fputcsv の改行コードを CR+LF にするには
php5.1 から使える fputcsv という関数はとても便利。
例えば、こんな感じで、
<?php $data = array( array(1, '松田', '聖子', '2'), array(2, '川本', '真琴', '2'), array(3, 'つのだ ★', 'ひろ', '1'), ); $fp = fopen("php://output", "w"); foreach ($this->data as $line) { fputcsv($fp, $line); } ?>
とやると
1,松田,聖子,2 2,川本,真琴,2 3,"つのだ ★",ひろ,1
こんなふうになる。空白や改行などが入っていてもええ感じにやってくれる。詳しくはここ参照。
ただ、改行コードが OS に依存するので、サーバが Linux でクライアントが Windows とかだとちょっと困ったりする。
具体的には、お客さんから電話で、ダウンロードした csv を Windows のメモ帳で開いたら改行されてないんですぅ〜! ぷんぷくり〜ん(怒)って言われたるするってこと。
つまり、Linux だと改行コードが LF なので、改行を (CR+LF) で扱う Windows 様のメモ帳ちゃんではうまく改行されない、と。
なので、解決策を考えた。使ったのは
あたり。
簡単に言うと、ストリームの出力時にフィルタを登録できるので、行末の改行を強制的にCR+LFに変換するフィルタを通したらいいのでは、ってこと。
ついでに Windows なので、mb_convert_variable を使って、文字コードも cp932 に変換してます。
詳しくはコード見てください。
<?php class csv { function setData($data) { $this->data = $data; } function getCsv($is_ms = false) { $fp = fopen("php://output", "w"); if (true === $is_ms) { stream_filter_register("msLineEnding", "ms_line_ending_filter"); stream_filter_append($fp, "msLineEnding"); } foreach ($this->data as $line) { if (true === $is_ms) { mb_convert_variable('cp932', 'utf-8', $line); } fputcsv($fp, $line); } fclose($fp); } function getCsvMs() { $this->getCsv(true); } } class ms_line_ending_filter extends php_user_filter { function filter($in, $out, &$consumed, $closing) { while ($bucket = stream_bucket_make_writeable($in)) { $bucket->data = preg_replace("/\n$/", "", $bucket->data); $bucket->data = preg_replace("/\r$/", "", $bucket->data); $bucket->data = $bucket->data . "\r\n"; $consumed += $bucket->datalen; stream_bucket_append($out, $bucket); } return PSFS_PASS_ON; } } ?>
utf-8 + LF の時は
<?php $data = array( array(1, '松田', '聖子', '2'), array(2, '川本', '真琴', '2'), array(3, 'つのだ ★', 'ひろ', '1'), ); $csv = new csv(); $csv->setData($data); $csv->getCsv(); ?>
cp932 + CRLF の時は
<?php $data = array( array(1, '松田', '聖子', '2'), array(2, '川本', '真琴', '2'), array(3, 'つのだ ★', 'ひろ', '1'), ); $csv = new csv(); $csv->setData($data); $csv->getCsvMs(); ?>
では、また。