如何在PHP中输出一个Excel可以正确读取的UTF-8格式的CSV文件?

225

我有一个非常简单的东西,只是以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”这些数据,我没有写任何文件。如果需要,我可以这样做,只是因为目前似乎没有必要。有帮助吗?

更新:我尝试将 BOM 作为 echo pack("CCC", 0xef, 0xbb, 0xbf); 传递,这仅仅是从一个试图检测 BOM 的网站上获取的。但是,当它导入时,Excel只是将这三个字符附加到第一个单元格,并仍然会弄乱特殊字符。


2
Excel没有提供调整输入文件字符集的选项吗?你确定100%吗?我手边没有副本,所以无法尝试,但我想象中一定有一个下拉框。 - Pekka
这是在 Mac 上的 Excel - 它似乎比 PC 上的 Excel 有更多限制。在“打开”对话框中根本没有下拉菜单,只能选择要打开的文件类型。我已经到处找了,如果它存在的话,那就很难发现。我可以说有 98% 的把握。 - Ben Saufley
微软办公套件还是开源办公套件? - ajreal
微软在这方面更好,我找不到任何方法让OpenOffice检测字符集,甚至是BOM。真可惜。 - Ciantic
BOM对于Mac版的Microsoft Excel 2008也没有影响。 - Ben Saufley
26个回答

0
Mac Excel 2008 的简单解决方案: 我曾经为此苦苦挣扎,但这是我的简单解决方法: 在 Textwrangler 中打开 .csv 文件,它应该能正确打开您的 UTF-8 字符。现在在底部状态栏中将文件格式从“Unicode(UTF-8)”更改为“Western(ISO Latin 1)”,然后保存文件。 现在转到您的 Mac Excel 2008 并选择“文件”>“导入”>“选择 csv”>“查找您的文件”>在“文件来源”中选择“Windows(ANSI)”,然后您的 UTF-8 字符将正确显示。至少对我来说是这样...

0

我刚试过这些头文件,成功地让Windows 7上的Excel 2013正确导入了带有特殊字符的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


是的,这在 Windows 版本的 Excel 中是正确的,但正如我在答案中解释的那样,在 OS X 版本的 Excel 上不起作用。 - Tim Groeneveld

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

我已经尝试过了!但它已经被编码为Unicode文本...将其保存为Unicode文本不会改变任何内容。我该如何将其保存为纯文本,而不会错误地解释所有特殊字符? - Ben Saufley
我认为Alain所说的“保存为Unicode文本”,可能是指“UTF-16LE”。Windows经常(可悲地)错误地使用“Unicode”来指代带有BOM的UTF-16LE或UTF-16LE。记事本的文件->保存对话框以这种方式使用“Unicode”。 - Thanatos

0

如果您将其保存为 .txt 文件,然后使用逗号作为分隔符在 Excel 中打开,问题是否仍然存在?

问题可能根本不是编码问题,而只是该文件不符合 Excel 标准的完美 CSV。


据我所知,CSV格式没问题。我可以在TextEdit中制作“完美”的CSV,没有问题,甚至可以将txt重命名为csv,因此它不会缺少任何秘密 - CSV只是文本文件。此外,在Excel中,所有格式都是完美的,只是特殊字符会破坏格式。但以防万一,我尝试了你的建议,可悲的是它产生了相同的问题。 - Ben Saufley
来自“他们到底在想什么”部门的消息:请注意,根据微软的说法,正确的字段分隔符取决于语言环境。在某些语言环境中,“逗号分隔”的文件可能需要使用分号进行分隔 - 除了建议使用OpenOffice之外,您无能为力。 - djn
这真的很疯狂 - 不幸的是,我没有问题正确地分隔字段。我只是在处理这些特殊字符时遇到了麻烦。 - Ben Saufley

0
这对我来说是有效的工作。
$df = fopen("File.csv", "w");
// NO header('Content-Encoding: UTF-8'); // don't do this
header("Content-type: text/csv charset=UTF-8");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Location: Path/File.csv');
header('Content-Transfer-Encoding: binary');
header("Pragma: no-cache");
header("Expires: 0");
fputs($df, $bom = ( chr(0xEF) . chr(0xBB) . chr(0xBF) ));

Content-Encoding 头部不接受文本编码值,例如 "UTF-8"。 https://dev59.com/uGQn5IYBdhLWcg3wCjX0#17155003 - Cheeso

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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接