ファイルのロック
そふぃのPHP入門 >> PHP実践リファレンス >> ファイル操作 >> ファイルのロック

ファイルのロック

ファイルロックの限界

さんざんロックをしろと言ってきておいて何なんですが、「ファイルロック」という機能自体に覚えておいて欲しい限界点があります。この機能はOSに組み込まれてるファイルロックという機能をPHPから使わせてもらってるのです。つまり、使えるかどうかはOSに依存します。

と言ってもほとんどのUnix系OSには使えますし(使えないほうが珍しいです)、Windowsでも2000以降使えたはずです。Windows98では使えませんが、まさかちゃんとしたレンタルサーバがサーバ機に98使ってるって事もありえないと思うので(あったらどーしよぉ。。。)、ほぼ心配しなくても大丈夫、というレベルの話です。ローカルのテスト環境が98だよって人も別にあんまり困りません。OSで使えないからってファイルロック関数がエラーを出力するって訳ではないので書いておいても大丈夫です。そういう人は「同時アクセスをわざと発生させてファイルロックの頑丈さをテストする」とかの極端なテストは出来なくなるってだけです。自分のローカル環境で出来ないからってそうゆうテストを本番のサーバでしちゃいけません(念のため)。

但し、サーバによってはファイルロック機能は使えない、とか正しく動作しないかもしれない、と明言されている場合もあります。ここら辺は各自の環境によって違ってくるでしょうからご自分で調べて頂くとして、じゃあファイルロックが使えなかった場合はどうするんだ、というのはさらに深く排他制御に突っ込む羽目になるのでここでは触れません。排他制御についてはネット上に参考になる情報がたくさんありますので調べるのはそんなに難しくはないと思います。

ファイルをロックする―flock関数

PHPでファイルロック機能を利用するためにはflock()関数を使います。flock()関数だけで「排他ロック」も「共有ロック」もできますし、「ロックの破棄」もflock()関数を利用する事になります。

参考関数

  • flock() ---- ファイルをロックする

書式

  • bool flock( resource handle , int operation [, int wouldblock ] )

ロックの成功か失敗によってTRUE/FALSEが返されますので、とりあえずflock()を書いてみて、使えるOSならTRUEが返って来ますし、使えなければFALSEが返って来ます。この返り値で使用しているサーバがファイルロックを使えるかどうかを判断してみるのも手です。ただ・・・「正常に動かないかもしれない」なんて曖昧な表現をしているサーバでは「一応動くがあてにしないでくれ」って意味あいでしょうから、これで調べてTRUEでも期待できないんでしょうね。その辺の細かい環境まではご自分で調べて下さい。

第1引数にはfopen()で取得してあるファイルポインタを指定します。ファイル名で直接指定はできないのでファイルを開いてからロックをかける必要があるって事です。

第2引数はファイルロックの種類を指定します。これはさっき言った「共有ロック」「排他ロック」などの事です。指定方法は以下の通りです。

flock()関数でのロック指定方法
ロックの種類 定数値 数値 説明
共有ロック LOCK_SH 1 書き込みのみ禁止
排他ロック LOCK_EX 2 読み書き両方禁止
ロックの破棄 LOCK_UN 3 ロックを破棄する
ノンブロックモード LOCK_NB 4 ロック中、flock()関数でブロックモードとしない

この値は現在では定数値でも数値でも指定可能ですが、PHP4.0.1以下のバージョンでは数値の方しか使えません。現在は定数値で指定している方が多いようなので、定数値が使えるバージョンならそっちを指定しておくのをお勧めします。

補足ですが、ここで使えるロック用の定数はPHPに標準で組み込まれている定数です。つまりdefine()で自分で定義しなくてもいつでも(PHP4.0.1以降なら)使えるって事です。

ロックの破棄は文字通りかけたロックを外す訳ですが、実際はfclose()の段階で自動的に行われます。通常、ロック破棄はfclose()の寸前に書かれる(処理される)のが好ましいので、そういった場合はあまり明示的に書かれる事はありません。

第3引数は省略可能なオプション引数になってますが、ロックをブロックモードというモードにするかどうかというオプションです。今回はデフォルトの指定状態で良い(省略しておいて構わない)と思われますので説明しません。無意味に説明がややこしくなるので機会があったら説明します。

ロック機能付きカウンター

今回はずっとカウンターを例に出して来ましたし、ここらでファイルロック機能の付いたカウンターを作ってみます。と、言ってもこれまでのページで必要な事は説明してきましたので、サンプルを出すだけで解説は省きます。

ロック機能付カウンターサンプル

  1. <?php
  2. $filepath = 'counter/count.txt'; // ファイルへのパスを代入しておく
  3.  
  4. $fp = @fopen( $filepath, "r+" ); // ファイル開く 今回はr+が望ましい
  5. @flock($fp,LOCK_EX); // 排他ロックをかける
  6. $count = fgets( $fp, 10 ); // 9桁分値読み取り
  7. $count++; // カウントアップ
  8. rewind( $fp ); // ファイルポインタを先頭に戻す
  9. fputs( $fp, $count ); // 値書き込み
  10. flock($fp,LOCK_UN); // ロックの破棄。この位置なら書かなくてもいいがまぁ一応・・
  11. fclose( $fp ); // ファイル閉じる
  12. echo $count; // カウント値出力
  13. ?>

出力結果

7040

参考関数

  • fopen() ---- ファイルまたはURLを開く
  • flock() ---- ファイルをロックする
  • fgets() ---- ファイルから1行取得する
  • rewind() ---- ファイルポインタの位置を先頭に戻す
  • fputs() ---- fwrite()関数のエイリアス
  • fwrite() ---- ファイルをバイナリ・モードで書き込む
  • fclose() ---- ファイルポインタを閉じる

まぁ、書き方はいろいろありますのでこれだけじゃありません。今まで紹介した関数を使っていろいろ試してみて下さい。但し、ファイルを開くモード「r+」やロックの種類、ロックをかける位置などは変えるとロックの意味がないカウンターになりかねませんのでご注意を。