
こんにちは。タクマ™ [@suwaru_blog] です。
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」の最新記事