1. 程式人生 > >php 網站點選生成csv檔案,解決亂碼問題

php 網站點選生成csv檔案,解決亂碼問題

2012-01-10

abloz.com

周海漢 2012.1.10

先上一首詩:

鋤禾日當午,春運訂票苦 。 95105,一撥一上午。 撥了一上午,車票還沒譜。 過年回不回,心裡很痛苦。 為何會這樣,只能問政府。             作者:白交易

慶賀多路出擊終於買到了2012春運火車票,雖然是硬坐票,多年未擠火車了,這次要甩開膀子幹了:)

php點選,從資料庫生成csv格式的檔案供下載,有兩個問題:

1.中文檔名,在不同的瀏覽器下可能出現亂碼

2.內容的亂碼問題

重要建議,對部署在linux上,採用utf8編碼的資料庫和php檔案,直接將內容轉為gbk,可以用mb_convert_encoding或者iconv,這樣省很多麻煩。不要轉為utf16le格式的csv,否則還是容易遇到問題。utf8格式的csv有嗎?沒有。所以在windows上的csv格式,只有用gbk內容最簡單。

有一個fputcsv函式,可以將array轉成以逗號分隔的內容。header()函式可以讓瀏覽器生成可以下載的csv檔案。

<span style="font-family: Courier New;">    function query_to_csv($query, $filename="", $attachment = true, $headers = true)
    {
     if( empty( $filename ) )
  {
   $filename = "abloz_com_".date("Ymd").".csv";
  }
     header('Cache-control: private');
       
   
        if($attachment) {
            // send response headers to the browser
      //判斷瀏覽器,輸出雙位元組檔名不亂碼
      $encoded_filename  = urlencode($filename);
         $encoded_filename  = str_replace("+","%20",$encoded_filename );
         
            $fp = fopen('php://output', 'w');
         $ua = $_SERVER["HTTP_USER_AGENT"];
      if (preg_match("/MSIE/", $ua)) {
          header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
      }
      else if (preg_match("/Firefox/", $ua)) {
          header('Content-Disposition: attachment; filename*="utf8''' . $filename . '"');
      }
      else {
          header('Content-Disposition: attachment; filename="' . $filename . '"');
      }
      //if(function_exists('mb_convert_encoding')){
          //header('Content-type: text/csv; charset=UTF-16LE');
         header( 'Content-Type: text/csv' );
<span style="font-family: Courier New;">  } else {
            $fp = fopen($filename, 'w');
        }
        $result = mysql_query($query, $this->conn) or die( mysql_error( $this->conn ) );
       
        if($headers) {
            // output header row (if at least one row exists)
            $row = mysql_fetch_assoc($result);
            if($row) {
             $row = array_map("utf8togbk",array_keys($row));
                fputcsv($fp,$row );//,mb_convert_encoding(',',"UTF-16LE","UTF-8")
                // reset pointer back to beginning
                mysql_data_seek($result, 0);
            }
        }
       
        while($row = mysql_fetch_assoc($result)) {
         $row = array_map("utf8togbk",$row);
         
            fputcsv($fp, $row);//,mb_convert_encoding(',',"UTF-16LE","UTF-8")
        }
       
        fclose($fp);
    }
<span style="font-family: Courier New;">function utf8togbk($elem)
{
 return mb_convert_encoding($elem,"GBK","UTF-8");//"auto" = "ASCII,JIS,UTF-8,EUC-JP,SJIS".
}</span></span></span>

如果轉為utf16-le格式,還要寫bom,而且就算內容轉成功,fputcsv函式生成的分隔符“,”還是ansi的,開啟還是亂碼。除非自己寫一個直接生成csv格式的函式。

為了防止麻煩,就用utf8格式了。

對於下載時檔名亂碼問題,根據瀏覽器,提供不同的header,進行解決:

<span style="font-family: Courier New;">      //判斷瀏覽器,輸出雙位元組檔名不亂碼
      $encoded_filename  = urlencode($filename);
         $encoded_filename  = str_replace("+","%20",$encoded_filename );
         
            $fp = fopen('php://output', 'w');
         $ua = $_SERVER["HTTP_USER_AGENT"];
      if (preg_match("/MSIE/", $ua)) {
          header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
      }
      else if (preg_match("/Firefox/", $ua)) {
          header('Content-Disposition: attachment; filename*="utf8''' . $filename . '"');
      }
      else {
          header('Content-Disposition: attachment; filename="' . $filename . '"');
      }
</span>

對ie和firefox進行特殊處理。

query_to_csv是一個db類的成員函式,所以connection直接用了成員變數。如果是獨立函式,可以將conn做成全域性或引數傳入。

用法:

<span style="font-family: Courier New;">    require_once 'mydb_code.php';
    $db = new mydb();</span>




<span style="font-family: Courier New;">    $sql = "SELECT * FROM users";
    </span><span style="font-family: Courier New;">// output as a csv attachment
    $db->query_to_csv($sql, "周海漢.csv");</span>

如非註明轉載, 均為原創. 本站遵循知識共享CC協議,轉載請註明來源