※このサンプルの解説は、「CGI(Perl)の解説」をすべて読み終えてる方を前提としています。
■ ファイル書き込みの排他制御
ファイル書き込み時の排他制御は今まで完全ではないと思ってました。
それは、Perlの命令で「ファイルが存在するかどうか」という処理と「無ければ新規ファイルを作成する」という2つの処理を1命令で行うことができないからです。
「CGI(Perl)の解説」−「14.ファイルの読み書き」で解説した「flock()」関数で可能ですが、Windows環境では使用できないという問題があります。
そこで、いろいろ調べてみますと、ディレクトリ(フォルダ)作成の命令を使うとどうやら可能なのでサンプルを作ってみようと思います。
- 【 解 説 】
-
まず、今回もグラフィックカウンタの処理を例に取ります。
カウンタの書き込み処理が次のようになっています。
$filnam = "gcntsf.cgi"; open(FP,">$filnam"); print FP "$totalc"; close(FP);この処理の前に、このカウンタファイルを使用してもいいかをディレクトリ(フォルダ)が存在するかどうかで判断させます。
ディレクトリ(フォルダ)を作成する命令の「mkdir()」関数は、そのディレクトリ(フォルダ)が存在しなければそのディレクトリ(フォルダ)を作成して正常に終了します。
そのディレクトリ(フォルダ)が存在すれば、エラーを返します。例えば、「lock」という名前のディレクトリ(フォルダ)をパーミッション(属性)「755」で作成する場合は次のように記述します。
mkdir("lock", 0755);※..「0755」の頭「0」は8進数の記述方式ですが、パーミッション(属性)の表記法と同じになりますのでこの方法を使うと解かりやすいと思います。
そして、エラーが発生すれば、何秒か待って、再度作成するようにします。
この時、何秒か待つという命令はPerlの「sleep()」関数を使います。
例えば、5秒待ちたい場合は、単純に次のように記述できます。
sleep(5);ですから、ディレクトリ(フォルダ)が作成できるまで1秒単位に5回繰り返す処理は「while{}」関数を使い次のように記述できます。
$tcnt0 = 0; while(!mkdir("lock", 0755)){ if (++$tcnt0 > 5){ print "ファイルがロックできません<br>\n"; exit(); } sleep(1); }また、処理が終わったら先ほど作成したディレクトリ(フォルダ)を削除しておかないと2度と書き込みができなくなります。
ディレクトリ(フォルダ)の削除は「rmdir()」関数を使い、次のように記述できます。
rmdir("lock");
では、上記の方法でこの前の「グラフィック型のアクセスカウンタ」を変更してみます。
- 【記述サンプル】
- #!/usr/bin/perl $filnam = "gcntsf.cgi"; open(FP,"<$filnam"); $totalc = <FP>; close(FP); $totalc++; $tcnt0 = 0; while(!mkdir("lock", 0755)){ if (++$tcnt0 > 5){ print "ファイルがロックできません<br>\n"; exit(); } sleep(1); } $filnam = "gcntsf.cgi"; open(FP,">$filnam"); print FP "$totalc"; close(FP); rmdir("lock"); $totalc = sprintf("%06d", $totalc); $ketat = length($totalc); for $i (0..$ketat-1){ $suji = substr($totalc, $i, 1); print "<img src='$suji.gif'>"; }
- ◆実行結果について
-
上記のサンプルを「flock.cgi」という名前で保存して実行してみてください。
(注意)
サーバーでテストする場合は、「flock.cgi」を設置するフォルダのパーミッション(属性)を「777」
、もしくは「666」
にして下さい。実行結果はこちらをクリックしてください。
なお、実行結果については、各々のサーバーの環境、ユーザーの環境にによって内容は変わってきます。