什么是CSV文件?
Comma Separator Value(逗號分隔值)是也。常常用來(lái)數據轉換的中間文件存在,比如:從Mysql中導出數據到CSV,導入CSV到SqlServer中。最近在用Epsilon的郵件服務(wù)做郵件營(yíng)銷(xiāo),Epsilon的web前端接受csv格式的郵件列表,于是乎在Linux下用PHP腳本從Mysql數據庫中將user表的數據按照條件導出成csv,以便導入到Epsilon的web前端發(fā)郵件,問(wèn)題出現了,使用utf-8編碼導出CSV文件,打開(kāi)后里邊的中文成了亂碼(Windows下CSV文件默認與Microsoft Excel關(guān)聯(lián)),用Notepad++或者Word打開(kāi)正常,不過(guò)排版很亂,看著(zhù)累呀。
百度一下,找到原因:BOM惹的禍,微軟惹的禍。
什么是BOM?Byte Order Mark(比特序標記)是也。
為了識別 Unicode 文件,Microsoft 建議所有的 Unicode 文件應該以 ZERO WIDTH NOBREAK SPACE字符開(kāi)頭。這作為一個(gè)"特征符"或"字節順序標記(byte-order mark,BOM)"來(lái)識別文件中使用的編碼和字節順序(big-endian或little-endian),具體的對應關(guān)系見(jiàn)下表。
BytesEncoding Form00 00 FE FFUTF-32, big-endianFF FE 00 00UTF-32, little-endianFE FFUTF-16, big-endianFF FEUTF-16, little-endianEF BB BFUTF-8
類(lèi)Unix系統中并沒(méi)有使用 BOM,因為它會(huì )破壞現有的 ASCII 文件的語(yǔ)法約定。
我的php源碼文件是用NotePad++生成的,在Centos下執行,格式為:以UTF-8無(wú)BOM格式編碼,因此要想導出Microsoft Excel可以正常顯示的UTF-8的CSV文件,需要顯式的輸出BOM(EF BB BF,上表的最后一種類(lèi)型),然后再輸出Mysql中的有效數據。編寫(xiě)如下函數:
<?php
/**
* @param $file_name string 要導出的文件名,比如:mail-list.csv
* @param $content string 要輸出的csv格式的數據,用逗號分隔各字段
* @return null
*/
function output_csv($file_name,$content)
{
$content = "\xEF\xBB\xBF".$content; //添加BOM
if( empty( $file_name ) )
{
$file_name = date("Ymd")."csv";
}
header( "Cache-Control: public" );
header( "Pragma: public" );
header( "Content-type: text/csv" ) ;
header( "Content-Dis; filename={$file_name}" ) ;
header( "Content-Length: ". strlen( $content ) );
echo $content;
exit;
}
?>
問(wèn)題解決。
PS1:output_csv函數使用前,確保php源碼是utf-8,并且無(wú)BOM,并且沒(méi)有輸出任何內容。
PS2:BOM實(shí)際上挺煩人,如果你的網(wǎng)頁(yè)(*.html)有BOM,在IE6.x下面打開(kāi)會(huì )發(fā)現一神奇的空行,Firefox下卻沒(méi)有,遇到過(guò)沒(méi)?
PS3:參考文章UTF-8,UTF-16,UTF-32,BOM
相關(guān)php圖書(shū):