暴言満載

ネット上でぐらい暴言吐かせて・・・

@ITのPHPの記事が突っ込みどころ満載

2007-03-10 00:45:22 | PHP
サンプルで理解! フォームデータの受け渡し
1ページ目
menu.phpは、排他処理を扱ったようですが、早速ひどいです。
「一般的なオンラインシステムでは同時処理に対するデータの矛盾が発生しないよう留意する必要があります。」と書いているので、単にファイルが壊れなければいいという考えではないみたいなのに。

(1)flockするまえにデータを読むな
(2)file_existsのあとでwモードでファイルを開くな
(3)set_file_bufferはOSのバッファリングは関係ない
(4)fcloseの前にflock解除するな

(1)について。ファイルにはあらかじめ 1000000004 と書いてあるとします。
ユーザー1が4行目でファイルを開く

ユーザー1が5行目で $order_no に 1000000005 を代入

ユーザー2が4行目でファイルを開く

ユーザー2が5行目で $order_no に 1000000005 を代入

ということで、ユーザー1とユーザー2の $order_no が一緒になってしまいました。

(1)を改善するとコードはこうなりますかね
$count_file="/tmp/count.dat";
if(file_exists($count_file)){
$file = fopen($count_file, "r+") or die("ファイルをオープンできませんでした");
set_file_buffer($file, 0);
flock($file, LOCK_EX);
$order_no = fgets($file) + 1;
}else{
$file = fopen($count_file, "w") or die("ファイルをオープンできませんでした");
flock($file, LOCK_EX);
$order_no = 1000000001;
}
rewind($file);
fputs($file, $order_no);
flock($file, LOCK_UN);
fclose($file);


(2)について。
file_exists と fopen の間はあいています。あいているということは、他のユーザーが割り込む可能性があるということです。
ユーザー1がfile_existsを調べる→ない

ユーザー2がfile_existsを調べる→ない

ユーザー1がfopen($count_file, "w")でファイルを開く(作成する)

ユーザー2がfopen($count_file, "w")でファイルを開く

ユーザー1の $order_no に1000000001を代入

ユーザー2の $order_no に1000000001を代入

file_existsで調べても、その直後に状況は変わってるかもしれないということです。改善策はいくつかあります。
その1
$count_file="/tmp/count.dat";
touch($count_file);
$file = fopen($count_file, "r+") or die("ファイルをオープンできませんでした");
set_file_buffer($file, 0);
flock($file, LOCK_EX);
$order_no = fgets($file);
if(empty($order_no)) $order_no = 1000000001;
else $order_no++;
rewind($file);
fputs($file, $order_no);
flock($file, LOCK_UN);
fclose($file);

その2
$count_file="/tmp/count.dat";
$file = fopen($count_file, "a+") or die("ファイルをオープンできませんでした");
set_file_buffer($file, 0);
flock($file, LOCK_EX);
$order_no = fgets($file);
if(empty($order_no)) $order_no = 1000000001;
else $order_no++;
ftruncate($file, 0);
fputs($file, $order_no);
flock($file, LOCK_UN);
fclose($file);


(3)について
「set_file_buffer("ファイルポインタ", 0)」で書き込みバッファを使用しないようにします。書き込みバッファはOSがメモリ上に用意する一時的な記憶領域です。ハードディスクなど物理的なファイルシステムに書き出す前に利用されます。
バッファを利用することで、書き込みパフォーマンスを上げることができる一方、極めて短時間ですが、バッファ上のデータとファイルシステム上のデータに差異が発生します。その差異が発生している瞬間に障害が起きた場合、データが消失する可能性があります。そのため、バッファを利用せずに直接ファイルシステムに書き込むようにします。

と書いてますが、set_file_bufferはOSのバッファではなくPHPの内部のバッファーを制御します。マニュアルを見れば分かることなのに。「その差異が発生している瞬間に障害が起きた場合、データが消失する可能性があります。」とのことですが、差異が発生していないときに障害が起こってもデータは消失するわけで(「障害」ってのが具体的になんなのかさっぱりわかりませんが)。
ようするに、set_file_bufferは不要です。ただし、(4)を守るなら。

(4)について。
fcloseの前にflock(ファイルポインタ, LOCK_UN) する人は実に多いのですが、これははっきりと間違いだと断言します。flockをfcloseの前に解除するということは、fcloseの前に他のプロセスが割り込む可能性が出るということです。ファイルへの書き込みは、fwriteとかfputsとかしてからfflushまたはfclose実行までのどこかで行われる、というのがファイル周りのI/Oの基本です。なので、fcloseもロックの範囲内に入れなければなりません。fcloseでflockが解除されるのはそういう理由があるのです。単に「ファイルが閉じられたらflockもなにもないだろう」ではないのです。ちなみに、バッファを無効にしてこの問題を回避と言うのは俺に言わせれば邪道です。

さて、2ページ目にはファイルの排他処理なんてレベルじゃない重大な問題があります。それも書こうかと思いましたが、今日は疲れたのでこの辺にします。

ジャンル:
ウェブログ
キーワード
ファイルシステム ファイルポインタ バッファー
コメント (1) |  トラックバック (0) |  この記事についてブログを書く
Messenger この記事をはてなブックマークに追加 mixiチェック シェア
« 思想の自由なんて... | トップ | NHKの論理は崩壊... »

コメント

コメント日が  古い順  |   新しい順
Unknown (Unknown)
2007-03-13 10:14:10
排他処理は誤解してる人が本当に多いですね

コメントを投稿

 ※ 
コメント利用規約に同意の上コメント投稿を行ってください。
※文字化け等の原因になりますので、顔文字の利用はお控えください。
下記数字4桁を入力し、投稿ボタンを押してください。この数字を読み取っていただくことで自動化されたプログラムによる投稿でないことを確認させていただいております。
数字4桁

トラックバック

この記事のトラックバック  Ping-URL
ブログ作成者から承認されるまでトラックバックは反映されません。

あわせて読む