ファイルの入出力
前回、ハローワールドを画面出力しました。今回は、ファイルへの入出力をしていきたいと思います。
fopen
ファイルやURLを開くことが出来ます。成功した場合、返値$fp にはファイルポインタが帰ります。
$fp = fopen('ファイル名 or URL','モード');
r : 読み込み
w : 上書き、ファイルが無い時は作成
a : 追記、ファイルが無い時は作成
x : 書き込み、ファイルが有る時はエラー
c : 上書き、ファイルが無い時は作成
⇨wはロックする前にファイルサイズを0にします。flock()を使う場合はcを使いロックを取得してからftruncate() を使う。上記モードに「+」を付けて読み書き出来るモードが有ります。
r+ , w+ , a+ , x+ , c+
便利ですが、処理が長くなる場合はファイルを開いている時間が長くなってしまうので別々に処理した方が良い事も有ります。
ファイルの読み込み
前回のDocker環境を作っている人は、pubディレクトリにdataディレクトリを作ってその中に「test.txt」を作って2,3行適当に書き込んで下さい。
・cgidocker/pub/data/test.txt
1行目です。 2行目です。 3行目です。
VScodeのターミナルで
cd ~/code/cgidocker sudo chmod 766 pub/data/test.txt
エラー処理が無い場合
<?php if (!$fp = fopen("../data/test.txt", "r")) { echo "読み込みerror"; } else { while ($line = fgets($fp)) { echo "$line<br />"; } } fclose($fp); ?>
エラー処理が有る場合
fopen()関数などを使う場合は「try-catch」を使う必要が有ります。
<?php ini_set("display_errors", 1); set_error_handler( function ($errno, $errstr, $errfile, $errline) { throw new ErrorException( $errstr, 0, $errno, $errfile, $errline ); } ); $fp = null; try{ $fname = "../data/test.txt"; $fp = fopen($fname, "r"); if (!$fp) { echo "読み込み2error"; } else { while ($line = fgets($fp)) { echo "$line<br />"; } fclose($fp); } }catch(Exception $ex){ echo "読み込み1error"; if (!is_null($fp)) { fclose($fp); } return false; } ?>
2行目は画面へエラー表示をする設定をしてます。
ini_set("display_errors", 1);
php.ini内では非表示設定をして不要なエラーを表示しないようにします。
display_errors = Off
3行目~ fopen()関数はエラーでは無く警告(Warning)を発生させます。
PHPでは、Warningでtry-catch出来ないのでset_error_handlerでエラーを発生させてcatchするようにしています。
set_error_handler( function ($errno, $errstr, $errfile, $errline){ throw new ErrorException( $errstr, 0, $errno, $errfile, $errline ); } );
try{}の中身は$fpにnullを設定して$fnameにファイルのパスを設定しています。
相対パスになっていますが絶対パスでもOKです。
fopen()関数のrモード読み込み専用で開いています。
失敗するとfalseが帰るのでif文で!$fpとしてエラーを表示しています。
ファイルが開けた場合は、else{}内でfgets()とwhile()関数をを使って1行ずつ取り出して処理して必ず最後はfclose()関数で閉じる様にします。
$fp = null; try{ $fname = "../data/test.txt"; $fp = fopen($fname, "r"); if (!$fp) { echo "読み込み2error"; } else { while ($line = fgets($fp)) { echo "$line<br />"; } fclose($fp); } }
ファイルの書き込み
エラー処理が無い場合
<?php $fname = "../data/test.txt"; $fex = file_exists($fname); $fp = fopen($fname, "w"); fwrite($fp, "ハロー\nワールド!"); fclose($fp); if(!$fex){ chmod($fname, 0766); } ?>
エラー処理が有る場合
ini_set(),set_error_handler()は、読み込みと同様で
file_exists()でファイルの存在確認
fopen()をcモード書き込み専用でサイズを0にしないモードを使い
flock()のLOCK_EXを使ってロックして
ロックが成功した時にftruncate($fp, 0)でファイルサイズを0にしています。
fwrite()で書き込みをして
fflush()でメモリからファイルへ書き出して
flock()の LOCK_UNを使ってロックを解放しています。
ロックを解放してからfclose()でファイルをクローズします。
元々ファイルが存在してなかった時だけchmod()で0766を指定しています。(0を忘れないように)
<?php ini_set("display_errors", 1); set_error_handler(function ($errno, $errstr, $errfile, $errline) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); }); $fp = null; $fname = "../data/test.txt"; $fex = file_exists($fname); try{ $fp = fopen($fname, "c"); if(!$fp){ echo "書き込み2error"; }else{ if(flock($fp, LOCK_EX)){ ftruncate($fp, 0); fwrite($fp, "ハロー\nワールド!"); fflush($fp); flock($fp, LOCK_UN); }else{ echo "ファイルを取得できません!"; } fclose($fp); $fp = null; if(!$fex){ chmod($fname, 0766); } } }catch (Exception $ex) { echo "読み込み1error"; if (!is_null($fp)) { fclose($fp); } return false; }
ini_set()文は運用時にはコメントアウトするか削除してエラーを表示しないようにします。
flock()する時は、fflush()してから LOCK_UNでロック解放します。
chmod()は、コマンドラインでは「chmod 766」と3桁で指定しますがコード内からだと「chmod($fname, 0766)」で4桁で指定します。