1. 程式人生 > >PHP強化之10 - CSV檔案處理

PHP強化之10 - CSV檔案處理

一、生成CSV檔案

1、主要函式:

fputcsv—將行格式化為 CSV 並寫入檔案指標

int fputcsv ( resource $handle , array $fields [, string $delimiter = ',' [, string $enclosure = '"' ]] )

1)函式說明:

fputcsv() 將一行(用 fields 陣列傳遞)格式化為 CSV 格式並寫入由 handle 指定的檔案。

2)引數:

  • handle 檔案指標必須是有效的,必須指向由fopen()或fsockopen()成功開啟的檔案(並還未由fclose()關閉)。
  • fields 值的一個數組。
  • delimiter 可選的delimiter引數設定欄位分界符(只允許一個字元)。
  • enclosure 可選的enclosure引數設定欄位欄位環繞符(只允許一個字元)。

3)返回值:

返回寫入字串的長度, 或者在失敗時返回false。

2、示例code:

//test data
$list = array (
    array('name', 'data', 'number', 'price'),
    array('iphone X', '2018/3/21', 123 ,8888),
    array('imax pro', '2018/3/23',20,12000),   
    array('Letv', '2018/3/27',99,1100),
);
$fp = fopen('./file.csv', 'w') or die('Can\'t open file.');
// fwrite($fp,chr(0xEF).chr(0xBB).chr(0xBF)); //解決出現中文編碼的問題
foreach ($list as $fields) {
    if (fputcsv($fp, $fields) === false) {
        die('Can\'t write line.');
    }
}
fclose($fp) or die('Can\'t close file.');

如下為生成的CSV檔案:

3、問題:

1)中文編碼問題

//Windows下使用BOM來標記文字檔案的編碼方式
fwrite($fp,chr(0xEF).chr(0xBB).chr(0xBF));

二、輸出CSV資料

要輸出CSV格式的資料而不是寫入檔案,可以使用特殊的輸出流php://output。

要把SCV格式的資料放入一個pb字串,而不是輸出或寫至一個檔案,可以結合輸出緩衝區使用,具體程式碼如下:

$list = array (
    array('name', 'data', 'number', 'price'),
    array('iphone X', '2018/3/21', 123 ,8888),
    array('imax pro', '2018/3/23',20,12000),   
    array('Letv', '2018/3/27',99,1100),
);

ob_start();
$fp = fopen('php://output','w') or die('Can\'t open php://output');
foreach ($list as $fields) {
    if (fputcsv($fp, $fields) === false) {
        die('Can\'t write CSV line.');
    }
}
fclose($fp) or die('Can\'t close php://output');
$output = ob_get_contents();
ob_end_clean();
//echo $output;

三、解析CSV檔案

1、主要函式

如果CSV資料在一個檔案中(或可以通過一個URL得到),用fopen()開啟檔案,並使用fgetcsv()讀入資料。

fgetcsv—從檔案指標中讀入一行並解析 CSV 欄位。

array fgetcsv ( resource $handle [, int $length = 0 [, string $delimiter = ',' [, string $enclosure = '"' [, string $escape = '\\' ]]]] )

1)函式說明:

和 fgets() 類似,只除了 fgetcsv() 解析讀入的行並找出 CSV 格式的欄位然後返回一個包含這些欄位的陣列。

2)引數:

  • handle 一個由 fopen()、popen() 或 fsockopen() 產生的有效檔案指標。
  • length 必須大於 CVS 檔案內最長的一行。在 PHP 5 中該引數是可選的。如果忽略(在 PHP 5.0.4 以後的版本中設為 0)該引數的話,那麼長度就沒有限制,不過可能會影響執行效率。
  • delimiter 設定欄位分界符(只允許一個字元)。
  • enclosure 設定欄位環繞符(只允許一個字元)。
  • escape 設定轉義字元(只允許一個字元),預設是一個反斜槓。

3)返回值:返回包含讀取欄位的索引陣列。

2、示例程式碼如下:

$fp = fopen('./file.csv','r') or die('Can\'t open file');
print '<table>';
while($csv_line = fgetcsv($fp)) {
    print '<tr>';
    for($i = 0, $j = count($csv_line); $i < $j; $i++){
    print '<td>'.htmlentities($csv_line[$i]).'</td>';//將字元轉換為 HTML 轉義字元
}
print '</tr>';
}
print '</table>';
fclose($fp) or die('Can\'t close file');

3、注意

預設地,fgetcsv()會讀入一整行資料。如果平均行長度超過8192位元組,還可以明確指定行的長度而不是讓PHP來確定,這樣一來,你的程式可以執行得更快。為此要為fgetcsv()提供第二個引數,這是比CSV檔案中最大行長度更大的一個值(不要忘記統計行尾空白符)。如果傳入長度為0,PHP應付採用預設行為。

可以向fgetcsv()傳入可選的第三個引數,這個作為分隔符來取代逗號(,)。不過,使用CSV的目的是為了很容易地交換表格資料,而使用一個不同的分隔符可能對此會有些影響。

不要試圖繞過fgetcsv(),而只想讀入一行再使用explode()按逗號進行解析。CSV比這要複雜,它可以處理包含特殊符號的欄位值,如欄位值中可能包含直接量逗號,不能把這些逗號看作是欄位分隔符。使用fgetcsv()可以避免這樣一些微妙的錯誤。

四、下載CSV檔案

結合使用header()函式來改變php程式輸出的內容型別,並使用fputcsv()函式完成資料格式轉化,從而可以將CSV檔案傳送到瀏覽器。

示例程式碼如下:

$list = array (
    array('name', 'data', 'number', 'price'),
    array('iphone X', '2018/3/21', 123 ,8888),
    array('imax pro', '2018/3/23',20,12000), 
    array('Letv', '2018/3/27',99,1100),
);
$fp = fopen('php://output','w') or die('Can\'t open php://output');
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="save.csv"');
foreach ($list as $fields) {
    if (fputcsv($fp, $fields) === false) {
        die('Can\'t write CSV line.');
    }
}
fclose($fp) or die('Can\'t close php://output');