将使用Mozilla Thunderbird创建的CSV文件中的多字节字符导入PHP

将使用Mozilla Thunderbird创建的CSV文件中的多字节字符导入PHP,php,drupal,csv,thunderbird,Php,Drupal,Csv,Thunderbird,我正在尝试将CSV文件导入到用Drupal构建的PHP应用程序中。我在导入从Mozilla Thunderbird导出的CSV文件时遇到了一个奇怪的情况(我正在导出联系人的通讯簿)。如果I使用Windows版本的Thunderbird导出,则任何多字节字符都不会呈现在屏幕上,并在将提取内容的内容转储到屏幕时显示为缺少的字符。但是,如果使用使用Linux版本的Thunderbird创建的相同文件,则不存在此问题。在这种情况下,一切都很完美 为了测试这一点,我在Linux和Windows7上安装了相

我正在尝试将CSV文件导入到用Drupal构建的PHP应用程序中。我在导入从Mozilla Thunderbird导出的CSV文件时遇到了一个奇怪的情况(我正在导出联系人的通讯簿)。如果I使用Windows版本的Thunderbird导出,则任何多字节字符都不会呈现在屏幕上,并在将提取内容的内容转储到屏幕时显示为缺少的字符。但是,如果使用使用Linux版本的Thunderbird创建的相同文件,则不存在此问题。在这种情况下,一切都很完美

为了测试这一点,我在Linux和Windows7上安装了相同版本的Thunderbird。然后我创建同一个单一用户(姓氏:张, 姓名:利) 在通讯簿中,然后将通讯簿导出为CSV文件。如上所述,linux CSV文件可以成功导入,但Windows one无法成功导入

如果我在linux中使用
文件--mime myfilename.csv
检查这两个文件,将得到以下输出:

LinuxTB14.csv:text/plain;字符集=utf-8

WinTB14.csv:text/plain;字符集=iso-8859-1

因此,windows文件,即使它包含汉字,也被编码为iso-8859-1。在发现这一点后,我假设这是一个编码问题,我只需要告诉PHP将有问题的内容编码为UTF-8

问题是PHP似乎以另一种我无法理解的方式检测编码

//设置正确的区域设置以避免多字节字符出现任何问题。
$original_local_value=setlocale(LC_CTYPE,0);
如果($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()是一个drupal函数,它将参数的内容打印到屏幕上。
dsm(mb_检测_编码($data[0]);
dsm($data[0]);
}
如果我包含上面的代码,它显示了CSV文件每行中第一个值的编码和内容,那么我将在屏幕上呈现以下内容:

用于由Thunderbird在windows中创建的CSV

ASCII码

名字

UTF-8

用于Thunderbird在Linux中创建的CSV

ASCII码

名字

UTF-8

正如您所见,PHP报告两个文件的编码相同,即使Windows文件中的汉字没有打印到屏幕上

有人知道这里发生了什么吗

编辑

如果我在记事本中打开Windows CSV文件并另存为..UTF-8格式,则文件将正确导入。因此,这显然是一个编码问题。如果文件编码尚未设置为UTF-8,我已添加以下代码来转换文件编码

$file\u contents=file\u get\u contents($file->uri);
$file_encoding=mb_detect_encoding($file_contents,'UTF-8,ISO-8859-1,WINDOWS-1252');
如果($file_encoding!=='UTF-8'){
$file\u contents=iconv($file\u编码,'UTF-8',$file\u contents);
$handle=fopen($file->uri,'w');
fwrite($handle,$file\u contents);
fclose($handle);
}
这部分地解决了问题。字符出现了,但它们是乱码的(例如。张 显示为ÕÅ)。我检查了浏览器的页面编码和页面标题,两者都设置为UTF-8,因此这不是浏览器问题


有什么想法吗?

对于这个问题,我提出的唯一解决方案是不首先尝试检测和转换上传文件的编码。经过大量研究,似乎确实不存在可靠的编码检测。这样做有太大的出错空间

最安全的选择是确保上传的文件以UTF-8编码,因为可以可靠地检测到UTF-8编码

$file\u content=file\u get\u contents($file->uri);
//创建检测UTF-8编码的正则表达式模式。
$regex='%^(?:
[\x09\x0A\x0D\x20-\x7E]#ASCII
|[\xC2-\xDF][\x80-\xBF]#非超长2字节
|\xE0[\xA0-\xBF][\x80-\xBF]#不包括超长
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}直三字节
|\xED[\x80-\x9F][\x80-\xBF]#不包括代理
|\xF0[\x90-\xBF][\x80-\xBF]{2}平面1-3
|[\xF1-\xF3][\x80-\xBF]{3}平面4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2}平面16
)*$%xs';
如果(!preg_match($regex,$file_content)){
//UTF-8编码无效,因此请标记错误。
}

对于这个问题,我提出的唯一解决方案是不首先尝试检测和转换上传文件的编码。经过大量研究,似乎确实不存在可靠的编码检测。这样做的错误空间太大了

最安全的选择是确保上传的文件以UTF-8编码,因为可以可靠地检测到UTF-8编码

$file\u content=file\u get\u contents($file->uri);
//创建检测UTF-8编码的正则表达式模式。
$regex='%^(?:
[\x09\x0A\x0D\x20-\x7E]#ASCII
|[\xC2-\xDF][\x80-\xBF]#非超长2字节
|\xE0[\xA0-\xBF][\x80-\xBF]#不包括超长
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}直三字节
|\xED[\x80-\x9F][\x80-\xBF]#不包括代理
|\xF0[\x90-\xBF][\x80-\xBF]{2}平面1-3
|[\xF1-\xF3][\x80-\xBF]{3}平面4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2}平面16
)*$%xs';
如果(!preg_match($regex,$file_content)){
//UTF-8编码无效,因此请标记错误。
}

在Windows文本编辑器中打开CSV文件时,尝试使用UTF-8编码重新保存该文件?仅尝试sav