206

我有一个非常简单的东西,它只是以 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,但我无法完全弄清楚如何做到这一点。正如你在上面看到的,我只是在echo输入这些数据,我没有写任何文件。如果需要,我可以这样做,我只是不是因为在这一点上似乎不需要它。有什么帮助吗?

更新:我尝试回显echo pack("CCC", 0xef, 0xbb, 0xbf);刚刚从试图检测 BOM 的站点中提取的 BOM。但是 Excel 只是在导入时将这三个字符附加到第一个单元格,并且仍然弄乱了特殊字符。

4

25 回答 25

314

我有相同(或类似)的问题。

就我而言,如果我将 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

我相信这是一个非常丑陋的 hack,但它对我有用,至少对 Excel 2007 Windows 来说是这样。不确定它是否可以在 Mac 上运行。

于 2010-12-14T14:24:34.047 回答
145

引用Microsoft 支持工程师的话,

Excel for Mac 目前不支持 UTF-8

2017 年更新: Office 2016之前的所有 Microsoft Excel for Mac 版本都是如此。较新的版本(来自 Office 365)现在支持 UTF-8。

为了输出 Windows 和 OS X 上的 Excel 都能成功读取的 UTF-8 内容,您需要做两件事:

  1. 确保将 UTF-8 CSV 文本转换为 UTF-16LE

    mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8');
    
  2. 确保将UTF-16LE 字节顺序标记添加到文件的开头

    chr(255) . chr(254)
    

仅在 OS X(而不是Windows)上的 Excel 中出现的下一个问题将是在查看具有逗号分隔值的 CSV 文件时,Excel 将仅呈现一行,并且所有文本与第一行中的逗号一起呈现。

避免这种情况的方法是使用制表符作为分隔值。

在 PHP 注释中使用了这个函数(使用制表符“\t”而不是逗号),它在 OS X 和 Windows Excel 上运行良好。

请注意,要解决以空列作为行尾的问题,我确实必须更改以下代码行:

    $field_cnt = count($fields);

    $field_cnt = count($fields)-1;

正如此页面上的其他一些评论所说,其他电子表格应用程序(如 OpenOffice Calc、Apple 自己的 Numbers 和 Google Doc 的电子表格)对带有逗号的 UTF-8 文件没有任何问题。

请参阅此问题中的表格,了解 Excel 中的 Unicode CSV 文件适用和无效的方法


作为旁注,我可能会补充一点,如果您使用的是Composer,您应该看看添加League\Csv到您的需求中。League\Csv一个非常好的 API 用于构建 CSV 文件

要使用League\Csv这种创建 CSV 文件的方法,请查看此示例

于 2013-05-27T04:14:33.313 回答
34

这是我的做法(即提示浏览器下载 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();

当您在 Mac 上按空格键时,它修复了 CSV 预览中的 UTF8 编码问题的唯一一件事。但在 Excel Mac 2008 中没有...不知道为什么

于 2011-09-29T17:36:12.467 回答
30

在我的情况下,以下工作非常好地使带有 UTF-8 字符的 CSV 文件在 Excel 中正确显示。

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

BOM标0xEF 0xBB 0xBF头将使 Excel 知道正确的编码。

于 2017-12-26T18:28:53.147 回答
23

我刚刚处理了同样的问题,并提出了两个解决方案。

  1. 按照 bpeterson76的建议使用PHPExcel类。

    • 使用此类生成最广泛兼容的文件,我能够从 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;
      
于 2011-01-21T19:00:20.203 回答
21

我遇到了同样的问题,并解决如下:

    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();
于 2015-12-18T16:31:30.347 回答
13

Excel 不支持 UTF-8。您必须将 UTF-8 文本编码为 UCS-2LE。

mb_convert_encoding($output, 'UCS-2LE', 'UTF-8');
于 2012-11-08T13:47:00.453 回答
8

要对此进行跟进:

看来问题出在 Mac 上的 Excel 上。这不是我生成文件的方式,因为即使从 Excel生成 CSV也会破坏它们。我保存为 CSV,然后重新导入,所有字符都搞砸了。

所以……似乎没有一个正确的答案。感谢所有的建议。

我想说,就我所读的所有内容而言,@Daniel Magliola 关于 BOM 的建议可能是其他计算机的最佳答案。但它仍然不能解决我的问题。

于 2011-01-11T16:56:44.633 回答
8

这适用于 Windows 和 Mac OS 的 excel。

修复 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;
}
于 2017-02-09T09:37:34.823 回答
7

CSV 文件必须包含字节顺序标记。

或者按照建议和解决方法,只需使用 HTTP 正文回显它

于 2011-10-20T08:56:43.220 回答
6

添加:

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);
于 2016-03-15T06:25:59.247 回答
5

mb_convert_encoding不需要使用转换已经 utf-8 编码的文本。只需在原始内容前面添加三个字符:

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

对我来说,这解决了 csv 文件中特殊字符的问题。

于 2014-09-16T12:13:56.970 回答
4

由于 UTF8 编码不能很好地与 Excel 配合使用。您可以使用 将数据转换为另一种编码类型iconv()

例如

iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $value),
于 2012-11-19T19:30:56.600 回答
3
**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;
}
于 2018-03-27T13:42:49.737 回答
2

您可以使用iconv转换您的 CSV 字符串。例如:

$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) );
于 2012-05-14T13:53:39.927 回答
2

正如我所调查的那样,我发现 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
于 2017-04-17T02:52:05.303 回答
1

您必须使用编码“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);
}
于 2013-04-10T08:41:20.580 回答
1

您可以在导出之前将 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 来解释数据

为 Excel 生成 CSV 文件,如何在值内添加换行符

于 2013-10-23T07:50:16.980 回答
1

我在 Mac 上,就我而言,我只需要指定分隔符"sep=;\n"并使用 UTF-16LE 对文件进行编码,如下所示:

$data = "sep=;\n" .mb_convert_encoding($data, 'UTF-16LE', 'UTF-8');
于 2016-07-18T22:45:29.380 回答
1

对我来说,上述解决方案均无效。以下是我为解决问题所做的工作:在 PHP 代码中使用此函数修改值:

$value = utf8_encode($value);

此输出值在 excel 表中正确输出。

于 2016-12-07T08:55:13.247 回答
0

当我有一个导入数据的 Excel VBA 例程时,我遇到了同样的问题。由于 CSV 是纯文本格式,因此我通过编程方式在写字板等简单文件编辑器中打开数据,然后将其重新保存为 unicode 文本,或者从那里将其复制到剪贴板并将其粘贴到 Excel 中来解决这个问题。如果 excel 没有自动将 CSV 解析为单元格,则可以使用内置的“文本到列”功能轻松解决此问题。

于 2010-12-03T18:52:22.153 回答
0

当您将其保存为 .txt 文件并使用逗号作为分隔符在 excel 中打开该文件时,问题是否仍然存在?

问题可能根本不是编码,它可能只是根据 excel 标准该文件不是完美的 CSV。

于 2010-12-03T18:58:51.750 回答
0

我刚刚尝试了这些标题,并在 Windows 7 PC 上安装了 Excel 2013 以正确导入带有特殊字符的 CSV 文件。字节顺序标记 (BOM) 是使它工作的最后一个关键。

    header('内容编码:UTF-8');
    header('内容类型: text/csv; charset=UTF-8');
    header("内容配置:附件;文件名=文件名.csv");
    header("Pragma: public");
    header("过期时间:0");
    回声“\xEF\xBB\xBF”;// UTF-8 物料清单

于 2013-07-17T17:45:11.080 回答
0

Mac Excel 2008 的简单解决方案:我为此苦苦挣扎了很多次,但这是我的简单解决方法:在 Textwrangler 中打开 .csv 文件,它应该正确打开你的 UTF-8 字符。现在在底部状态栏中将文件格式从“Unicode (UTF-8)”更改为“Western (ISO Latin 1)”并保存文件。现在转到您的 Mac Excel 2008 并选择 File > Import > Select csv > Find your file > 在 File origin 中选择“Windows (ANSI)”,瞧,UTF-8 字符显示正确。至少对我有用...

于 2015-08-11T06:41:15.600 回答
0

我使用它并且它有效

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;
于 2016-03-27T16:47:50.997 回答