
こんにちは。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」の最新記事