今日はファイル操作。
目次
テキストファイルへの書き込み
まずはコードから。
コード
入力フォーム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!doctype html> <html> <head> <meta charset="utf-8"> <title>ファイル書き込み</title> </head> <body> <h3>書き込み</h3> <form action="file_write.php" method="POST"> <div> <label for="name">名前:</label> <input type="text" name="name" size="50" maxlength="50"> </div> <div> <label for="message">メッセージ:</label> <input type="text" name="message" size="100" maxlength="255"> </div> <input type="submit" value="送信"> </form> </body> </html> |
書き込み用PHP
1 2 3 4 5 6 7 |
<?php $file = fopen('message.dat', 'ab'); fwrite($file, date('Y年 m月 d日 H:i:s')."\t"); fwrite($file, $_POST['name']."\t"); fwrite($file, $_POST['message']."\n"); fclose($file); header('Location: http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/input_data.html'); |
fopen
ファイルまたは URL をオープンする。
第一引数:ファイル名かURL
第二引数:第一引数へのアクセス形式。
aは書き込み専用。末尾に追記する形で書き込まれる。ファイルが存在しない場合は新規で作成する。
bはバイナリモード。マニュアルで「互換性維持のために、fopen() でファイルをオープンする際は 常に ‘b’ フラグを指定することが強く推奨されます。」とあるので、特段の事情が無い限りbをつける。
fwrite(またはfputs)
ファイルへの書き込み処理を行う。
exit=dieと同じようにfwriteもfputsも同じ。マニュアルでfputsの項目がfwriteの項目へのリンクをしているのでこちらを使ってみた。
第一引数:fopenを使って作成したファイルシステムポインタリソース。ファイルのどの位置?というところまで読み込んでいる。
第二引数:書き込みたい文字列。今回は入力値と日時を書き込んでいる。
fclose
引数が指しているファイルを閉じる。
fopenなどの関数によって正常にオープンされたファイルに限る。
header
生の HTTP ヘッダを送信する
Locationは特別なヘッダでリダイレクトステータスコードを返すため、これを使って入力フォームへリダイレクト(自動転送)している。
今回のphpファイルには出力するものが何もないため利用している。
headerは全ての出力の前にコールしなければならない。
今回はheaderの前にページに何か出力しているわけでは無いので7行目だが問題ない。
$_SERVER
サーバー情報および実行時の環境情報を有するスーパーグローバル変数。
HTTP_HOSTでサーバのホスト名、dirnameにPHP_SELF(現在実行中のファイル名)を引数として渡すことで親ディレクトリのパスを返している。
今回はホスト名/フォルダ名/ファイル名を渡すことでURLの表示を実現している。
実行結果
4人前入力してみた。
2014年 02月 06日 11:46:30 名前 メッセージ 2014年 02月 06日 11:58:33 我々は 宇宙人だ 2014年 02月 06日 12:35:49 @名無しさん m9(^Д^)プギャー 2014年 02月 06日 12:36:52 @名無しさん 4げと
ロック機能の追加
複数ユーザーの同時アクセスが起きるとファイル更新に不具合が起きる場合がある。
先ほどのフォームに
一人目
名前:地球人 メッセージ:間違いない
二人目
名前:宇宙人 メッセージ:んなわきゃない
と入れて同時送信したとする。
するとファイルに
2014年 02月 06日 12:57:37 地球人 2014年 02月 06日 12:57:38 宇宙人 間違いない んなわきゃない
と混ざって書き込まれてしまうことがある。
※今回はsleepを使って同時送信状態を再現している。
flock
ファイルロックを行う。
第一引数:fopen()で開いたファイルシステムポインタリソース。
第二引数:ロックの種類。今回は排他的ロック(書き込み禁止)とする LOCK_EXと(共有または排他的)ロックを開放するLOCK_UNを使う。
その他に共有ロック(読み込み中の書き込み禁止)のLOCK_SHがある。
コード
1 2 3 4 5 6 7 8 9 |
<?php $file = fopen('message.dat', 'ab'); flock($file, LOCK_EX); fwrite($file, date('Y年 m月 d日 H:i:s')."\t"); fwrite($file, $_POST['name']."\t"); fwrite($file, $_POST['message']."\n"); flock($file, LOCK_UN); fclose($file); header('Location: http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/input_data.html'); |
ファイルを読み込む
ファイルの読み込んでリスト化したページを作ります。
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?php $file = @fopen('message.dat', 'rb') or exit('ファイルが開けませんでした'); flock($file, LOCK_SH); print('<dl>'); while ($row = fgetcsv($file, 1024, "\t")): $cnt += 1; ?> <dt><?php print($cnt.'. '.e($row[1])); ?> (<?php print(e($row[0])); ?>)</dt> <dd>メッセージ:<?php print(e($row[2])); ?></dd> <hr /> <?php endwhile; print('</dl>'); flock($file, LOCK_UN); fclose($file); ?> |
エラー制御演算子
警告やエラーの表示を抑制するための演算子。
今回はfopenの前についている@がそれに当たる。
ファイルが開けなかったら自前の警告文をexitで発行している。
fgetcsv
ファイルポインタから行を取得し、CSVフィールドを処理する。
第一引数:fopen()等で正常に開かれたファイルポインタ
第二引数:最大文字長。ファイル内で最も長い行よりも大きい必要がある。
そのため、ある程度入力値は制御しなければならない。加えてこの引数は省略すれば最大長の制限は無くなるが若干動作が遅くなるらしい。
第三引数:区切り文字(1文字のみ)
csvを名乗っているがカンマ区切りの処理しか出来ない訳では無い。
今回はタブ区切りのファイルを処理している。
似た関数でfgets()があるがこちらは1行分(改行文字を検出した瞬間終了する)の取得となる。ただし区切りを解釈しないのでデータを分割して使いたい場合は自分で分解する必要がある。
今日のひとこと探ってたけどイマイチ勘が鈍ってるのか見つけられなかった・・・明日頑張ろう・・・
コメント
No Trackbacks.