我正在尝试将 CSV 文件导入到使用 Drupal 构建的 PHP 应用程序中。我在导入从Mozilla Thunderbird导出的CSV文件时遇到了一个奇怪的情况(我正在导出联系人的通讯录)。如果我使用 Windows 版本的 Thunderbird 导出,任何多字节字符都不会呈现到屏幕上,并且在将提取的内容的内容转储到屏幕时显示为缺失字符。但是,当使用使用 Linux 版本的 Thunderbird 创建的相同文件时,不存在此问题。在这种情况下,一切都完美无缺。
为了测试这一点,我在 Linux 和 Windows 7 上安装了相同版本的 Thunderbird。然后我在地址簿中创建了相同的单个用户(姓:张,名字:利),然后将地址簿导出为 CSV 文件。如上所述,linux CSV 文件可以成功导入,但 Windows 不能。
如果我在 linux 中检查这两个文件,使用file --mime myfilename.csv
is 得到以下输出:
LinuxTB14.csv:文本/纯文本;字符集=utf-8
WinTB14.csv:文本/纯文本;字符集=iso-8859-1
所以windows文件,即使它包含中文字符,也被编码为iso-8859-1。发现这一点后,我认为这是一个编码问题,我只需要告诉 PHP 将违规内容编码为 UTF-8。
问题是 PHP 似乎以另一种我无法理解的方式检测编码。
// Set correct locale to avoid any issues with multibyte characters.
$original_local_value = setlocale(LC_CTYPE, 0);
if ($original_local_value !== 'en_US.UTF-8') {
setlocale(LC_CTYPE, 'en_US.UTF-8');
}
$handle = fopen($file->uri, "r");
$cardinfo = array();
while (($data = fgetcsv($handle, 5000, ",")) !== FALSE) {
$cardinfo[] = $data;
// dsm() is a drupal function which prints the content of the argument to screen.
dsm(mb_detect_encoding($data[0]));
dsm($data[0]);
}
如果我包含上面的代码,它显示了 CSV 文件每一行中第一个值的编码和内容,我会在屏幕上显示以下内容:
对于 Thunderbird 在 windows 中创建的 CSV
ASCII
名
UTF-8
对于 Thunderbird 在 Linux 中创建的 CSV
ASCII
名
UTF-8
利</p>
如您所见,PHP 报告两个文件的编码相同,即使 Windows 文件中的中文字符没有打印到屏幕上。
有人知道这里可能发生什么吗?
编辑
如果我在记事本中打开 Windows CSV 文件并另存为.. UTF-8 格式,则文件将正确导入。所以这显然是一个编码问题。如果文件编码尚未设置为 UTF-8,我添加了以下代码来转换文件编码。
$file_contents = file_get_contents($file->uri);
$file_encoding = mb_detect_encoding($file_contents, 'UTF-8, ISO-8859-1, WINDOWS-1252');
if ($file_encoding !== 'UTF-8') {
$file_contents = iconv($file_encoding, 'UTF-8', $file_contents);
$handle = fopen($file->uri, 'w');
fwrite($handle, $file_contents);
fclose($handle);
}
这部分解决了问题。字符出现了,但它们是乱码(例如,张显示为 ÕÅ)。我检查了浏览器的页面编码和页面标题,两者都设置为 UTF-8,所以这不是浏览器问题。
有任何想法吗?