TRASH-NEWS file_put_contentsに排他ロック機能をつけてみた(PHP)

順路
  1. ホーム
  2. 2008年
  3. 01月
  4. 13日
  5. この記事 [現在地]
Search?
お知らせ
社会人近況 (2008/09/07 0:00)
配属されてからこの方、ほぼ毎日終電での帰宅が続いているうえに毎週泊まりがけの出張が入っているため、1週間に1回か2回更新できればマシといった状況です。実はまだTRASH-NEWSは概要ページもリンクコーナーもろくに作っていないような有様なんですけれども、気づけばそろそろ1周年+すでに50万ヒット。……なんだこのえもいわれぬグダグダ感は……。とりあえずヴェスペリア堪能してから考えますね。
1 2 3

file_put_contentsに排他ロック機能をつけてみた(PHP)

関連ページ
  1. PHP
  2. 自作関数
TRASH-NEWSは
I've Soundをこよなく愛するサイトです
初出時刻
2008年01月13日 00時52分 投稿
最終更新時刻
2008年02月21日 13時22分 改訂
  • この記事をはてブする
  • Yahoo!ブックマークに登録

最近カウンターの数字がリセットされることが多く、そのたびに過去ログから手動復旧する手間に追われています。リセットの原因は……おそらくカウンターの数値ファイルの破損。同じ瞬間(たぶん数マイクロ秒間)に複数のアクセスがあって同じ瞬間にカウンターの数値ファイルが書き換えられたシチュエーション……において壊れたのでしょう。

通常のwebプログラムならファイルのデータを書き換える際には『排他ロック』を働かせファイルを保護するためこのようなことはあまりおこりません(排他ロックとはファイルを書き換えている作業をしている間はそのファイルにアクセスできないよう保護するという機能です)。

しかし僕の場合は既存のカウンタープログラムが重ったるいのに辟易して自作のものを利用しているため『排他ロック』を利用することを忘れがちになります。今使っているサーバーがPHP5に対応しているため安易にfile_put_contentsという関数を利用しているのが主たる要因。perlだったりPHP4以下だったりの言語ではファイルにデータを書き込む際長々と関数を書いていかなければならなかったのを、これ1つの関数のみで行えるという、夢のような関数です。

しかしこのfile_put_contents、デフォルトの状態では排他ロックを利用する設定になっておらず結構危険。カウンターのように毎秒何回ものアクセスが起こりうるプログラムに使うには危険が多すぎます。まぁ僕のいま使っているカウンターはお手軽版にもほどがあるよ、と。

PHPの公式マニュアルによるとfile_put_contentsでは排他ロックをできないことがわかったので、自作するほかありません。排他ロックを働かせる関数flockを使うにはファイルポインタを利用した関数でそろえなければならないのでfile_get_contentsも使えません。そこでfile_get_contentsとfile_put_contentsの両方をセットで使うことを想定した関数を作りました。

my_file_get_contents と my_file_put_contents 、それらを利用したカウンター作例
// ファイルを読み込んで内容とファイルポインタリソースを返す関数 function my_file_get_contents($FileName,$GetFlag="r+"){ if($fp = @fopen($FileName,$GetFlag)){ set_file_buffer($fp,0); flock($fp,LOCK_EX); rewind($fp); return array(fgets($fp,1024),$fp); }else{ return FALSE; } } // 排他ロックをかけながらファイルにデータを書き込む関数 function my_file_put_contents($fp,$PutData){ rewind($fp); fputs($fp,$PutData); flock($fp,LOCK_UN); fclose($fp); return TRUE; } // 排他ロックが処理中ずっとかかっているので安心なカウンターの作例 function UltraEasyCounter(){ list($TotalCount,$fp) = my_file_get_contents([カウンタのファイル]); $TotalCount++; if(my_file_put_contents($fp,$TotalCount)){ return $TotalCount; }else{ return 0; } } /* 実際は加算処理の前にCookieでアクセス重複を判別したりだとか アクセスログのデータベースを照会したりだとか、 いろいろやるべきことはありますが原理上これでカウンターが完成しています。 */

ファイルを読み込んで内容とファイルポインタリソースを返す関数『my_file_get_contents』という関数について説明します。第一引数に読み込むファイルの場所(URL)、第二引数に読み込みモードを指定します。つまりはfopenとまったく同じ書式です。マニュアルに沿って仕様を書くなら“resource my_file_get_contents ( string $filename , string $mode)”てなところでしょうか。ただし返り値は配列要素で、[0]が読み込まれたファイルの1行目の文字列(あくまでカウンタ用途なので)、[1]がファイルポインタのリソースとなっています。このあたりが自作関数ならではの汚い感じ。

set_file_buffer($fp,0)とrewind($fp)についてはおまじないの域を出ない気がしますが、実のところどうなんでしょうか。このあたりがC言語や機械いじりをやっていないツケというか。まぁさておき、このmy_file_get_contentsはfopenをfsockopen()に置き換えてstream_set_timeoutを併用すればそのまま外部サイトからのソース参照プログラムになるので思わぬところで便利になるかもしれません。重いファイルを読み込む場合にも1行1行読み出せるファイルポインタ系の関数は有効です。有効です、というかファイルにアクセスしている時点で負荷は変わらないのではと思いますが、コンピュータの深いところをまったく知らないので受け売りでしかモノを語れません。

さてそれでは排他ロックをかけながらファイルにデータを書き込む関数・『my_file_put_contents』という関数についても。第一引数に読み込むファイルポインタ情報、第二引数に書き込むデータを指定します。“int my_file_put_contents ( resource $handle , string $string)”といったかんじです。まぁそのままfputs(fwrite)関数ということですね。この関数内で行われている処理はすべてTRUEでなければいけないので4つの処理すべてで“失敗したらreturn FALSE”しなければならないのですが、まぁ、面倒なので。

さてこれを実際に動かしたところ、期待通り、きちんと動きました。目に見えて動作が遅くなったわけでもなし(試行を重ねてきちんと検証すべきなのか!?)、おそらくは排他ロックもできているのでもうファイルが壊れる心配もないでしょう……。

それにしてもこれだけニーズの高そうな排他ロックの機能がサポートされていないのはおかしい。もしくは既に有名な問題であってネット上で優れた勝手関数が公開されているのか。と、思い検索にかけてみました。しかしそれらしい関数はほとんど出てきません。ここで……ある可能性に気づき、別の検索語で検索してみます。

site:www.php.net "file_put_contents"

すると……驚愕の事実が判明しました。なんと問題視していた公式サポート関数・file_put_contentsに、既に排他ロック機能がついていました!

変更履歴

5.0.0 コンテキストがサポートされるようになりました。

5.1.0 LOCK_EX のサポートが追加され、 data パラメータにストリームリソースを指定することが可能になりました。

6.0.0 FILE_TEXT および FILE_BINARY がサポートされるようになりました。

とのこと。

要するに僕が見ていたマニュアルが旧い版のものだったため、その時点のfile_put_contentsでは排他ロック(LOCK_EX)の機能がサポートされていなかったと……。というかオンラインマニュアルなのに更新が3年前なんて、更新しないんならそんなもの置くなよ(PHPのマニュアルがネット上にうようよあることの弊害)!

というわけで、今回の長々とした関数は利用価値がほぼなくなりました。かわりにfile_put_contents($FileName,$PutData,LOCK_EX)とでも書けばこれ1行で大丈夫。世の中便利になりましたね!

ただPHP4を利用している人や何らかの事情でファイルポインタのリソースを使いたいという人にはまぁ有用であると思いますのでココに記事として残しておきますね。はームダ骨ムダ骨(だがそれがいい)。

サイト内検索
検索する
このサイトについて
  • サイト名 : TRASH-NEWS
  • 分類 : ニュースとネタのサイト
  • ジャンル : 井戸端からアレゲまで
  • もっと詳しく見る
最近の記事
12月21日の記事
  1. ディシディアFF同梱版PSP-3000ZWの画面が歪んで見えるレポート
12月05日の記事
  1. ニコニコ大会議2008冬へ行ってみた(フォトレポート)
11月30日の記事
  1. 取り急ぎ近況など
10月05日の記事
  1. テイルズオブヴェスペリアの感想 【戦闘編】
09月22日の記事
  1. テイルズオブヴェスペリアの感想 【ストーリー・キャラクター編】
09月11日の記事
  1. Xbox360がタイムリープぶーとべんち専用ハードになる日も近い
09月06日の記事
  1. ラタトスクのためにWiiを買い、ヴェスペリアのためにXbox360を買い
08月31日の記事
  1. Quad+GeForce 9600GTの新PCでタイムリープぶーとべんちしてみた
08月28日の記事
  1. 初音ミクの星間飛行や振り付けランカちゃんなど最近見たニコニコ動画
08月25日の記事
  1. 初音ミクと小林オニキスさんの新曲『ORCA』がまたも素晴らしい
日刊人気記事ランキング
2009年01月06日のぶん
1
Windows XP SP3インストールで不具合が起きることが発覚
50
2
ディシディアFF同梱版PSP-3000ZWの画面が歪んで見えるレポート
34
3
XP SP3における不具合報告と32bitOSでのメモリのRAMDisk化の話
24
4
テイルズオブヴェスペリアの感想 【ストーリー・キャラクター編】
20
5
Windows XPのSP3は思いのほかスゴいらしい
18
6
FFT-A2のクリア後レビューと感想(ネタバレなし)
16
7
画像解析系ジェネレータ・BannerCodeBattler2(仮)着手開始
16
8
NewsWeekによる『世界が尊敬する日本人100人』に植松伸夫氏
14
9
うみねこのなく頃に体験版はマンガ版を読んでからのプレイがオススメ
14
10
PSP版スターオーシャン2、新キャラにやはりウェルチ
13

2009年01月07日 0時更新

人気記事ランキング

カテゴリ(折畳表示)
ニュース・ネタ
サブカテゴリを開く
俺研究舎
サブカテゴリを開く
お知らせ
サブカテゴリを開く
特集・企画
サブカテゴリを開く
管理人近況
サブカテゴリを開く
カスタムアーキテクチャ
1回めのようこそ!
ゲストさん
  • 文字の大きさ : 12px
  • フォント : MS Pゴシック
  • レイアウト : 3段組
  • カスタムする
カレンダー
2008年1月
«  12月 - 02月  »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
管理人について
管理人 : 八満かシアン
理系になり損ねた文系人間(シアンのほう)
今頃たぶん聴いている曲
小さなてのひら by riya
月別アーカイブ
2008年
2007年
最近記事に掲載した画像
画面四隅が歪んだり虹色になるPSP-3000 ZW
画面四隅が歪んだり虹色になるPSP-3000 ZW
ニコニコ大会議2008冬のプレミアムチケットが当たったので行ってみた
ニコニコ大会議2008冬のプレミアムチケットが当たったので行ってみた
ニコニコ大会議2008冬フォトレポート・ひろゆきの胸像、額には肉
ニコニコ大会議2008冬フォトレポート・ひろゆきの胸像、額には肉
ニコニコ大会議2008冬フォトレポート・ニコニコ、Google=YouTubeと和解か
ニコニコ大会議2008冬フォトレポート・ニコニコ、Google=YouTubeと和解か
ニコニコ大会議2008冬フォトレポート・イチローさんパネェっすwww
ニコニコ大会議2008冬フォトレポート・イチローさんパネェっすwww
画像に関するリンク
ユーティリティ
RSSフィード
ソーシャルブックマーク
  • iGoogle
  • はてなアンテナにTRASH-NEWSを追加する TRASH-NEWSのはてなブックマーク数 この記事を含むはてなブックマーク
サイトプロフィール
Powered by
  • Movable Type 4.1 + [XHTML + CSS + JavaScript] + PHP
  • TRASH-NEWS / Hachiman_Cian 2007-
このページについて
題名
file_put_contentsに排他ロック機能をつけてみた(PHP)
内容
  • 最近カウンターの数字がリセットされることが多く、そのたびに過去ログから手動復旧す
TRASH-NEWS ロゴ
TRASH-NEWS ロゴ
TRASH-NEWS : http://www.trash-news.net/