Как я могу выводить CSV UTF-8 в PHP, который Excel будет читать правильно?

У меня есть очень простая вещь, которая просто выводит некоторые вещи в формате CSV, но это должен быть UTF-8. Я открываю этот файл в TextEdit или TextMate или Dreamweaver, и он правильно отображает символы UTF-8, но если я его открываю в Excel, он делает это глупое дело. Вот что я получил во главе моего документа:

header("content-type:application/csv;charset=UTF-8"); header("Content-Disposition:attachment;filename=\"CHS.csv\""); 

Кажется, что все это имеет желаемый эффект, за исключением того, что Excel (Mac, 2008) не хочет импортировать его должным образом. В Excel нет никаких опций для «открытия как UTF-8» или чего-то еще, поэтому … Я немного раздражаюсь.

Кажется, я не могу найти каких-либо ясных решений в этом месте, несмотря на то, что у многих людей такая же проблема. То, что я вижу больше всего, это включить спецификацию, но я не могу точно понять, как это сделать. Как вы можете видеть выше, я просто echo эти данные, я не пишу никаких файлов. Я могу это сделать, если мне это нужно, я просто не потому, что на данный момент это не похоже на необходимость. Любая помощь?

Обновление: я пробовал эхо BOM как echo pack("CCC", 0xef, 0xbb, 0xbf); который я просто вытащил с сайта, который пытался обнаружить спецификацию. Но Excel просто добавляет эти три символа в первую ячейку при импорте и все еще испортит специальные символы.

Чтобы процитировать инженера по поддержке Microsoft ,

Excel для Mac в настоящее время не поддерживает UTF-8

Обновление, 2017 : Это относится ко всем версиям Microsoft Excel для Mac до Office 2016 . Более новые версии (из Office 365) теперь поддерживают UTF-8.

Чтобы вывести содержимое UTF-8, которое Excel как в Windows, так и в OS X сможет успешно прочитать, вам нужно будет сделать две вещи:

  1. Убедитесь, что вы конвертируете текст UTF-8 в UTF-16LE

     mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8'); 
  2. Убедитесь, что вы добавили символ порядка байтов UTF-16LE

     chr(255) . chr(254) 

Следующая проблема, которая появляется только с Excel в OS X (но не в Windows), будет при просмотре CSV-файла с запятыми, значения Excel будут отображать строки только с одной строкой и всем текстом вместе с запятыми в первой строке.

Способ избежать этого – использовать вкладки в качестве разделенного значения.

Я использовал эту функцию из комментариев PHP (используя вкладки «\ t» вместо запятых), и она отлично работала на OS X и Windows Excel.

Обратите внимание, что для исправления проблемы с пустым столбцом в конце строки мне пришлось изменить строку кода, которая гласит:

  $field_cnt = count($fields); 

в

  $field_cnt = count($fields)-1; 

Как показывают некоторые другие комментарии на этой странице, другие приложения для электронных таблиц, такие как OpenOffice Calc, собственные номера Apple и электронная таблица Google Doc, не имеют проблем с UTF-8 файлами с запятыми.

См. Таблицу в этом вопросе, для чего работает и не работает для файлов CSV Unicode в Excel


В качестве примечания я мог бы добавить, что если вы используете Composer , вам следует взглянуть на добавление League\Csv к вашим требованиям. League\Csv есть действительно хороший API для создания файлов CSV .

Чтобы использовать League\Csv с помощью этого метода создания файлов CSV, ознакомьтесь с этим примером.

У меня такая же (или аналогичная) проблема.

В моем случае, если я добавлю спецификацию на вывод, она будет работать:

 header('Content-Encoding: UTF-8'); header('Content-type: text/csv; charset=UTF-8'); header('Content-Disposition: attachment; filename=Customers_Export.csv'); echo "\xEF\xBB\xBF"; // UTF-8 BOM 

Я считаю, что это довольно уродливый взлом, но он работал для меня, по крайней мере, для Excel 2007 Windows. Не уверен, что это сработает на Mac.

Вот как я это сделал (чтобы заставить браузер загружать файл csv):

 header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=file.csv'); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); echo "\xEF\xBB\xBF"; // UTF-8 BOM echo $csv_file_content; exit(); 

Единственное, что зафиксировало проблему кодирования UTF8 в превью CSV, когда вы нажимаете пробел на Mac .. но не в Excel Mac 2008 … не знаете, почему

Я только что затронул ту же проблему и придумал два решения.

  1. Используйте класс PHPExcel, как предлагается bpeterson76 .

    • С помощью этого класса создается наиболее широко совместимый файл, я смог создать файл из кодированных UTF-8 данных, которые отлично открылись в Excel 2008 Mac, Excel 2007 Windows и Google Docs.
    • Самая большая проблема с использованием PHPExcel заключается в том, что он медленный и использует много памяти, что не является проблемой для файлов с разумным размером, но если ваш файл Excel / CSV содержит сотни или тысячи строк, эта библиотека становится непригодной .
    • Вот PHP-метод, который будет принимать некоторые данные TSV и выводить файл Excel в браузер, обратите внимание, что он использует Excel5 Writer, что означает, что файл должен быть совместим со старыми версиями Excel, но у меня больше нет доступа к каким-либо, поэтому я не могу их протестировать.

       function excel_export($tsv_data, $filename) { $export_data = preg_split("/\n/", $tsv_data); foreach($export_data as &$row) { $row = preg_split("/\t/", $row); } include("includes/PHPExcel.php"); include('includes/PHPExcel/Writer/Excel5.php'); $objPHPExcel = new PHPExcel(); $objPHPExcel->setActiveSheetIndex(0); $sheet = $objPHPExcel->getActiveSheet(); $row = '1'; $col = "A"; foreach($export_data as $row_cells) { if(!is_array($row_cells)) { continue; } foreach($row_cells as $cell) { $sheet->setCellValue($col.$row, $cell); $col++; } $row += 1; $col = "A"; } $objWriter = new PHPExcel_Writer_Excel5($objPHPExcel); header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment;filename="'.$filename.'.xls"'); header('Cache-Control: max-age=0'); $objWriter->save('php://output'); exit; } в function excel_export($tsv_data, $filename) { $export_data = preg_split("/\n/", $tsv_data); foreach($export_data as &$row) { $row = preg_split("/\t/", $row); } include("includes/PHPExcel.php"); include('includes/PHPExcel/Writer/Excel5.php'); $objPHPExcel = new PHPExcel(); $objPHPExcel->setActiveSheetIndex(0); $sheet = $objPHPExcel->getActiveSheet(); $row = '1'; $col = "A"; foreach($export_data as $row_cells) { if(!is_array($row_cells)) { continue; } foreach($row_cells as $cell) { $sheet->setCellValue($col.$row, $cell); $col++; } $row += 1; $col = "A"; } $objWriter = new PHPExcel_Writer_Excel5($objPHPExcel); header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment;filename="'.$filename.'.xls"'); header('Cache-Control: max-age=0'); $objWriter->save('php://output'); exit; } в function excel_export($tsv_data, $filename) { $export_data = preg_split("/\n/", $tsv_data); foreach($export_data as &$row) { $row = preg_split("/\t/", $row); } include("includes/PHPExcel.php"); include('includes/PHPExcel/Writer/Excel5.php'); $objPHPExcel = new PHPExcel(); $objPHPExcel->setActiveSheetIndex(0); $sheet = $objPHPExcel->getActiveSheet(); $row = '1'; $col = "A"; foreach($export_data as $row_cells) { if(!is_array($row_cells)) { continue; } foreach($row_cells as $cell) { $sheet->setCellValue($col.$row, $cell); $col++; } $row += 1; $col = "A"; } $objWriter = new PHPExcel_Writer_Excel5($objPHPExcel); header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment;filename="'.$filename.'.xls"'); header('Cache-Control: max-age=0'); $objWriter->save('php://output'); exit; } 
  2. Из-за проблем с производительностью с PHPExcel мне также пришлось выяснить, как создать файл CSV или TSV, совместимый с UTF-8 и Excel.

    • Лучшее, что я мог придумать, – это файл, который был совместим с Excel 2008 Mac и компьютером Excel 2007, но не с документами Google, что достаточно для моего приложения.
    • Я нашел решение здесь , в частности, этот ответ , но вы также должны прочитать принятый ответ, поскольку он объясняет проблему.
    • Вот код PHP, который я использовал, обратите внимание, что я использую данные tsv (вкладки как разделители вместо запятых):

       header ( 'HTTP/1.1 200 OK' ); header ( 'Date: ' . date ( 'DM j G:i:s TY' ) ); header ( 'Last-Modified: ' . date ( 'DM j G:i:s TY' ) ); header ( 'Content-Type: application/vnd.ms-excel') ; header ( 'Content-Disposition: attachment;filename=export.csv' ); print chr(255) . chr(254) . mb_convert_encoding($tsv_data, 'UTF-16LE', 'UTF-8'); exit; 

Excel не поддерживает UTF-8. Вы должны кодировать текст UTF-8 в UCS-2LE.

 mb_convert_encoding($output, 'UCS-2LE', 'UTF-8'); 

У меня была такая же проблема, и она была решена, как показано ниже:

  header('Content-Encoding: UTF-8'); header('Content-Type: text/csv; charset=utf-8' ); header(sprintf( 'Content-Disposition: attachment; filename=my-csv-%s.csv', date( 'dmY-His' ) ) ); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); $df = fopen( 'php://output', 'w' ); //This line is important: fputs( $df, "\xEF\xBB\xBF" ); // UTF-8 BOM !!!!! foreach ( $rows as $row ) { fputcsv( $df, $row ); } fclose($df); exit(); 

Чтобы следить за этим:

Похоже, что проблема просто в Excel на Mac. Я не создаю файлы, потому что даже генерация CSV из Excel нарушает их. Я сохраняю CSV и реимпортирую, и все символы перепутаны.

Итак … на этот вопрос нет правильного ответа. Спасибо за все предложения.

Я бы сказал, что из всего, что я прочитал, предложение Даниила Маглиолы о спецификации, вероятно, будет лучшим ответом для другого компьютера. Но он все еще не решает мою проблему.

Файл CSV содержит запись байтового байта.

Или, как предложено и обходным путем, просто эхо его с телом HTTP

Добавить:

 fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF)); 

Или:

 fprintf($file, "\xEF\xBB\xBF"); 

Прежде чем писать любой контент в файл CSV.

Пример:

 <?php $file = fopen( "file.csv", "w"); fprintf( $file, "\xEF\xBB\xBF"); fputcsv( $file, ["english", 122, "বাংলা"]); fclose($file); 

Поскольку кодировка UTF8 не очень хорошо работает с Excel. Вы можете преобразовать данные в другой тип кодировки с помощью iconv() .

например

 iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $value), 

Когда я исследовал, и я обнаружил, что UTF-8 не работает хорошо на MAC и Windows, поэтому я попытался с Windows-1252, он хорошо подходит для обоих из них, но вы должны выбрать тип кодирования на ubuntu. Вот мой код $valueToWrite = mb_convert_encoding($value, 'Windows-1252');

 $response->headers->set('Content-Type', $mime . '; charset=Windows-1252'); $response->headers->set('Pragma', 'public'); $response->headers->set('Content-Endcoding','Windows-1252'); $response->headers->set('Cache-Control', 'maxage=1'); $response->headers->set('Content-Disposition', $dispositionHeader); echo "\xEF\xBB\xBF"; // UTF-8 BOM 

Как насчет только вывода для самого Excel? Это отличный класс, который позволяет создавать файлы XLS на стороне сервера. Я часто использую его для клиентов, которые не могут «выяснить» csv и до сих пор никогда не получали жалобы. Он также позволяет некоторое дополнительное форматирование (затенение, строки, расчеты и т. Д.), Которые csv никогда не будет делать.

вы можете конвертировать CSV String с iconv . например:

 $csvString = "Möckmühl;in Möckmühl ist die Hölle los\n"; file_put_contents('path/newTest.csv',iconv("UTF-8", "ISO-8859-1//TRANSLIT",$csvString) ); 

Вы должны использовать кодировку «Windows-1252».

 header('Content-Encoding: Windows-1252'); header('Content-type: text/csv; charset=Windows-1252'); header("Content-Disposition: attachment; filename={$filename}"); 

Возможно, вам нужно преобразовать ваши строки:

 private function convertToWindowsCharset($string) { $encoding = mb_detect_encoding($string); return iconv($encoding, "Windows-1252", $string); } 

Для меня ни одно из вышеприведенных решений не работало. Ниже приводится то, что я сделал для решения проблемы: измените значение с помощью этой функции в PHP-коде:

 $value = utf8_encode($value); 

Этот вывод правильно отображается на листе excel.

Это отлично работает как для Windows, так и для Mac OS.

// Исправлены проблемы в excel, которые не отображают символы, содержащие диакритические знаки, кириллические буквы, греческую букву и символы валюты.

 function writeCSV($fileprefix, $headings, $data) { //Use tab as field separator $newTab = "\t"; $newLine = "\n"; $fputcsv = count($headings) ? '"'. implode('"'.$newTab.'"', $headings).'"'.$newLine : ''; // Loop over the * to export if (! empty($data)) { foreach($data as $item) { $fputcsv .= '"'. implode('"'.$newTab.'"', $item).'"'.$newLine; } } //Convert CSV to UTF-16 $encoded_csv = mb_convert_encoding($fputcsv, 'UTF-16LE', 'UTF-8'); // Output CSV-specific headers header('Set-Cookie: fileDownload=true; path=/'); //This cookie is needed in order to trigger the success window. header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Cache-Control: private",false); header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=\"$filename.csv\";" ); header("Content-Transfer-Encoding: binary"); header('Content-Length: '. strlen($encoded_csv)); echo chr(255) . chr(254) . $encoded_csv; //php array convert to csv/excel exit; } 

У меня была такая же проблема, когда у меня была программа Excel VBA, которая импортировала данные. Поскольку CSV – это простой текстовый формат, я работал над этим, программно открывая данные в простом редакторе файлов, например wordpad, и повторно сохраняя его как текст в формате Unicode или копируя его в буфер обмена оттуда и вставляя его в Excel. Если excel автоматически не анализирует CSV в ячейках, это легко исправить, используя встроенную функцию «Текст в столбцы».

Проблема возникает, когда вы сохраняете ее как .txt-файл, и они открываются, что в excel с запятой в качестве разделителя?

Проблема может быть не в кодировке вообще, возможно, просто, что файл не является идеальным CSV в соответствии с стандартами excel.

Эта почта довольно старая, но после нескольких часов попыток я хочу поделиться своим решением … возможно, это помогает кому-то, кто имеет дело с Excel, Mac и CSV, и спотыкается об этой угрозе. Я генерирую csv динамически как вывод из базы данных с пользователями Excel. (UTF-8 с спецификацией)

Я пробовал много iconv'ов, но не мог получить немецкие умлауты, работающие в Mac Excel 2004. Одно из решений: PHPExcel. Это здорово, но для моего проекта слишком много. Что для меня работает – это создать файл csv и преобразовать этот файл csv в xls с помощью этого PHPsnippet: csv2xls . результат xls работает с excel german umlauts (ä, ö, Ü, …).

Я просто попробовал эти заголовки и получил Excel 2013 на ПК с Windows 7, чтобы правильно импортировать CSV-файл со специальными символами. Значок байтового заказа (BOM) был последним ключом, который заставлял его работать.


     header ('Content-Encoding: UTF-8');
     header ('Content-type: text / csv; charset = UTF-8');
     header («Content-disposition: attachment; filename = filename.csv»);
     header («Pragma: public»);
     заголовок («Истекает: 0»);
     echo "\ xEF \ xBB \ xBF";  // UTF-8 BOM

Вы можете добавить 3 байта в файл перед экспортом, он работает для меня. Прежде чем делать эту систему, работайте только в Windows и HP -UX, но не удалось в Linux.

 FileOutputStream fStream = new FileOutputStream( f ); final byte[] bom = new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF }; OutputStreamWriter writer = new OutputStreamWriter( fStream, "UTF8" ); fStream.write( bom ); 

Введите UTF-8 BOM (3 байта, шестнадцатеричный EF BB BF) в начале файла. В противном случае Excel будет интерпретировать данные в соответствии с кодировкой по умолчанию вашего языка (например, cp1252) вместо utf-8

Создание CSV-файла для Excel, как иметь новую строку внутри значения

В противном случае вы можете:

 header("Content-type: application/x-download"); header("Content-Transfer-Encoding: binary"); header("Content-disposition: attachment; filename=".$fileName.""); header("Cache-control: private"); echo utf8_decode($output); 

Преобразование уже закодированного utf-8 текста с использованием mb_convert_encoding не требуется. Просто добавьте три символа перед исходным контентом:

 $newContent = chr(239) . chr(187) . chr(191) . $originalContent 

Для меня это решило проблему специальных символов в файлах csv.

EASY для Mac Excel 2008: я много раз боролся с этим soo, но здесь было мое легкое решение: откройте CSV-файл в Textwrangler, который должен правильно открыть ваши символы UTF-8. Теперь в нижней строке состояния измените формат файла с «Unicode (UTF-8)» на «Western (ISO Latin 1)» и сохраните файл. Теперь перейдите в свой Mac Excel 2008 и выберите «Файл»> «Импорт»> «Выбрать csv»> «Найти свой файл»> «Происхождение файла» выберите «Windows (ANSI)» и отобразите символы UTF-8 правильно. По крайней мере, это для меня …

Я использую это, и он работает

 header('Content-Description: File Transfer'); header('Content-Type: text/csv; charset=UTF-16LE'); header('Content-Disposition: attachment; filename=file.csv'); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); // output headers so that the file is downloaded rather than displayed // create a file pointer connected to the output stream $output = fopen('php://output', 'w'); fputs( $output, "\xEF\xBB\xBF" ); // output the column headings fputcsv($output, array('Thông tin khách hàng đăng ký')); // fetch the data $setutf8 = "SET NAMES utf8"; $q = $conn->query($setutf8); $setutf8c = "SET character_set_results = 'utf8', character_set_client = 'utf8', character_set_connection = 'utf8', character_set_database = 'utf8', character_set_server = 'utf8'"; $qc = $conn->query($setutf8c); $setutf9 = "SET CHARACTER SET utf8"; $q1 = $conn->query($setutf9); $setutf7 = "SET COLLATION_CONNECTION = 'utf8_general_ci'"; $q2 = $conn->query($setutf7); $sql = "SELECT id, name, email FROM myguests"; $rows = $conn->query($sql); $arr1= array(); if ($rows->num_rows > 0) { // output data of each row while($row = $rows->fetch_assoc()) { $rcontent = " Name: " . $row["name"]. " - Email: " . $row["email"]; $arr1[]["title"] = $rcontent; } } else { echo "0 results"; } $conn->close(); // loop over the rows, outputting them foreach($arr1 as $result1): fputcsv($output, $result1); endforeach; 

Я нахожусь на Mac, в моем случае мне просто нужно было указать разделитель с "sep=;\n" и закодировать файл в UTF-16LE следующим образом:

 $data = "sep=;\n" .mb_convert_encoding($data, 'UTF-16LE', 'UTF-8'); 

#output UTF-8 CSV в PHP, который Excel будет читать правильно.

 //Use tab as field separator $sep = "\t"; $eol = "\n"; $fputcsv = count($headings) ? '"'. implode('"'.$sep.'"', $headings).'"'.$eol : ''; 
 //convert UTF-8 file without BOM to UTF-16LE for excel on mac $fileUtf8String = file_get_contents("file.ext"); file_put_contents("file.ext", "\xFF\xFE" . mb_convert_encoding($fileUtf8String, "UTF-16LE", "UTF-8"));