Как я могу вывести 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" или что-то еще, так что ... я немного раздражен.

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

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

30 ответов


цитата инженер службы поддержки Microsoft,

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

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

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

  1. убедитесь, что вы конвертируете UTF-8 text в 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);

to

    $field_cnt = count($fields)-1;

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

посмотреть таблица в этом вопросе для чего работает и не работает для CSV-файлов Unicode в Excel


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

использовать League\Csv С помощью этого метода создания CSV-файлов проверьте


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

в моем случае, если я добавляю BOM к выходу, он работает:

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 preview, когда вы нажмете пробел на Mac.. но не в Excel 2008 для Mac... не знаю почему!--2-->


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

  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;   
      }
      
  2. из-за проблем с эффективностью PHPExcel мне также пришлось выяснить, как создать совместимый с UTF-8 и Excel CSV или TSV-файл.

    • лучшее, что я мог придумать, это файл, совместимый с Excel 2008 Mac и Excel 2007 PC, но не 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;
      

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. Это не так, как я генерирую файлы, потому что даже генерируя CSVs из Excel ломает их. Я сохраняю как CSV и реимпорт, и все символы перепутаны.

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

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


файл CSV musst включает Знак порядка байтов.

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


это отлично работает в 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;
}

с кодировкой utf8 не дружат с Excel. Вы можете преобразовать данные в другой тип кодировки, используя iconv().

например

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

добавить:

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);

Как я исследовал , и я обнаружил, что 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

в моем случае следующие работы очень приятно сделать 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 заголовок спецификации позволит Excel знать правильную кодировку.


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


вы можете преобразовать строку CSV с помощью 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);
}

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

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

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

$value = utf8_encode($value);

это выходные значения правильно на листе excel.


**This is 100% works fine in excel for both Windows7,8,10 and also All Mac OS.**
//Fix issues in excel that are not displaying characters containing diacritics, cyrillic letters, Greek letter and currency symbols.

function generateCSVFile($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;
}

У меня была такая же проблема, когда у меня была процедура Excel VBA, которая импортировала данные. Поскольку CSV-это текстовый формат, я работал над этим, программно открывая данные в простом редакторе файлов, таком как wordpad, и повторно сохраняя их как текст unicode или копируя их в буфер обмена оттуда и вставляя их в Excel. Если excel автоматически не анализирует CSV в ячейки, это легко исправить с помощью встроенной функции "текст в Столбцы".


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

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


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

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


Я просто попробовал эти заголовки и получил 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");
    header("Expires: 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 байта, hex 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-файлах.


простое решение для Mac Excel 2008: Я боролся с этим Су много раз, но вот мое легкое решение: Откройте .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;

#выведите CSV UTF-8 в 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"));