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

У меня есть очень простая вещь, которая просто выводит некоторые вещи в формате 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 пользуюсь этими данными, я не пишу никаких файлов. Я могу сделать это, если мне нужно, просто нет, потому что на данный момент в этом нет необходимости. Любая помощь?

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

Ответы [ 30 ]

264 голосов
/ 14 декабря 2010

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

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

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.

126 голосов
/ 27 мая 2013

Цитировать инженер поддержки 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 с запятыми.

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


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

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

30 голосов
/ 29 сентября 2011

Вот как я это сделал (чтобы браузер мог загрузить файл 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 ... не знаю, почему

22 голосов
/ 21 января 2011

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

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

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

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

      header ( 'HTTP/1.1 200 OK' );
      header ( 'Date: ' . date ( 'D M j G:i:s T Y' ) );
      header ( 'Last-Modified: ' . date ( 'D M j G:i:s T Y' ) );
      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;
      
13 голосов
/ 18 декабря 2015

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

    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();
12 голосов
/ 08 ноября 2012

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

mb_convert_encoding($output, 'UCS-2LE', 'UTF-8');
8 голосов
/ 11 января 2011

Для продолжения:

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

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

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

7 голосов
/ 09 февраля 2017

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

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

function writeCSV($filename, $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;
}
7 голосов
/ 26 декабря 2017

В моем случае следующее очень хорошо работает, чтобы CSV-файл с символами UTF-8 правильно отображался в Excel.

$out = fopen('php://output', 'w');
fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF));
fputcsv($out, $some_csv_strings);

Заголовок 0xEF 0xBB 0xBF BOM сообщит Excel правильную кодировку.

6 голосов
/ 20 октября 2011

Файл CSV должен содержать метку порядка байтов.

Или, как предложено и обходной путь, просто введите его в тело HTTP

...