こんにちは。iQeda [@iQeeeda] です。
stream_get_contents()
で CSV ファイルの中身を取り出そうとしても空文字…結論は「ストリームのモードをちゃんと見ろ」でした。
問題のソースコード
適当ですが、以下のソースコードがあったとします。
サーバ上で CSV ファイル生成して Windows 向けに文字コードも設定するって感じです。
$f = fopen($filepath, 'w');
if ($f) {
// CSV のヘッダー作成
$header = array(
"ユーザID",
"登録日時"
);
fputcsv($f, $header);
foreach ($data as $d) {
// CSV のボディ作成
$result = array(
$d->user_id,
date('Y/n/j G:i', strtotime($d->created_at))
);
fputcsv($f, $result);
}
// バッファ先頭に戻ってコンテンツ取得する
rewind($f);
// ...つもりがなぜかここで空文字しか取得できない!
$buffer = str_replace("\n", "\r\n", stream_get_contents($f));
// 文字コード SJIS でエンコード
$sjis = mb_convert_encoding($buffer, 'sjis-win', 'UTF-8');
fclose($f);
$f = fopen($filepath, 'w');
// エンコードデータで上書き
fwrite($f, $sjis);
fclose($f);
// 空っぽの CSV ファイルができあがる...\(^o^)/
}
これだと空っぽの CSV ファイルができあがり。
$buffer = str_replace("\n", "\r\n", stream_get_contents($f));
上記の stream_get_contents($f)
で空文字が返っていることが判明しました。
原因はストリームの mode
その原因は $f = fopen($filepath, 'w');
にありました。
mode 'w'
ではファイルストリームの中身を取り出すことができません。
$f = fopen($filepath, 'w+b');
にすると取り出せました。
fopen() のドキュメントを読んでみた
ちゃんと PHP 公式ドキュメントに書かれていました。
モード w は「書き出しのみ」。
ファイル中身を置換したり、文字コードを設定するときには「読み込み」も必要。
モード w ではダメなのですね。
w
書き出しのみでオープンします。ファイルポインタをファイルの先頭に置き、 ファイルサイズをゼロにします。ファイルが存在しない場合には、 作成を試みます。
w+
読み込み/書き出し用でオープンします。 ファイルポインタをファイルの先頭に置き、 ファイルサイズをゼロにします。 ファイルが存在しない場合には、作成を試みます。
b
Windows上では、\nを\r\nに透過的に変換する text-mode変換フラグ(‘t’)が提供されます。 それに対し、’b’を使って強制的にバイナリモードにすることもできます。 その場合データの変換はされません。 このフラグを使用するには、’b’ または ‘t’を mode引数の最後に追加してください。
デフォルトの変換モードは SAPI と使用している PHP のバージョンによって異なります。 したがって、互換性の意味から、常に適切なフラグを指定することが推奨されます。 plain-text ファイルを使用する場合には ‘t’ モードを指定すべきであり、 改行に \n を使用すると、 メモ帳のようなアプリケーションで読めることを期待できます。 それ以外のケースでは ‘b’ を使うべきです。
バイナリファイルを扱っている際に ‘b’ フラグを指定しなかった場合、 画像ファイルが壊れたり、\r\n キャラクタがおかしくなる等の問題を抱えてしまうでしょう。
まとめ
単なる書き込みモードのストリームでstream_get_contents()
を使った場合、
エラーが起きるわけでもなく、空文字が返ってくる。
その場合はストリームのモードを確認すること。
お仕事ください!
僕が代表を務める 株式会社 EeeeG では Web 制作・システム開発・マーケティング相談を行っています。 なにかお困りごとがあれば、Twitter DM や Web サイトからお気軽にご相談ください。
カテゴリ「Develop」の最新記事