関数とファイルロック

関数 

何度も使う処理は関数としてまとめておいて、必用なときに呼び出して使うと便利です。

関数を定義するにはfunctionを使います。 
function 関数名(引数){処理}

PHPでは関数の中で使われる変数は関数内だけで有効なローカル変数になります。外部の変数を使うには、引数として関数に渡すか、グローバル変数として呼び出す必要があります。グローバル変数はglobal $変数;となります。

function.php
<html>
<head>
<title>function.php</title>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
</head>
<body>

<?php
$a="A";$b="B";$c="C";
print test($a,"D");

function test($d,$e){

print "b=$b<br />";
global $c;
print "c=$c<br />";
print "d=$d<br />";
print "e=$e<br /><br />";
return "$c$d$e";

}
?>
</body>
</html>
実行結果
b=
c=C
d=A
e=D

CAD

print test($a,"D");では、関数test()を実行しその結果が出力されます。returnが返される結果です。
test内の$bは中身が宣言されていないので空になります。
test内の$cはグローバル宣言されているので、元の$cの中身が格納されています。
test内の$dは引数として渡された$aの中身が格納されています。
test内の$eは引数として渡された"D"が格納されています。

ファイルロック

インターネットでは、同じCGIが同時に実行されることがあります。この時、同時にファイルに書き込もうとしたときにファイルが壊れたり、内容がおかしくなることがあります。それを防ぐためにファイル処理は同時に行わせずに、順番に処理を行うようにする必要があります。

ロック処理の流れとしては、
1.ファイル処理が実行されていないか確認する
2.実行されていれば、それが終わるのを待つ。
3.実行されてなければ、実行されないようにロックする。
4.ファイル処理を行う。
5.実行が終わったら、ロックを解除する。

ここでは、簡単に利用できるディレクトリを使って解説します。
ロックされているかされていないかをディレクトリが存在するかしないかで判断します。
1.ディレクトリの存在を確認する。
2.ディレクトリが存在していれば、ディレクトリが消えるのを待つ。
3.ディレクトリが存在しなければ、ディレクトリを作成する。
4.ファイル処理を行う。
5.ディレクトリを削除する。

これだけだとディレクトリが存在している間ずっと待たされることになるので、指定時間待ってもディレクトリが消えない場合は、混雑しているものとしてエラーを返して処理を終了させます。
また、何らかのエラーにより処理の途中で止まってしまいディレクトリが削除されない時もありますので、指定時間よりも古ければ強制的に削除します。

lock.php

<html>
<head>
<title>lock test</title>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
</head>
<body>

<?php
$file= "lock.txt";

print "ロックします<br>\n";
lock($file);
$fh=fopen($file,"w");
fwrite($fh,"lock test");
fclose($fh);
unlock($file);
print "ロックを解除しました<br>\n";

function lock($file){

$lockdir= "lock/";
$lockfile= "$lockdir"."$file";

#再挑戦回数
$retry = 3;

# 30秒以上古いロックは削除する
if (file_exists($lockfile)) {

$mtime = filemtime($lockfile);
if ($mtime < time() - 30) {

unlock($file);

}

}

# ロック用ディレクトリを作成する
while (!@mkdir($lockfile, 0755)) {

if ($retry-- <= 0) { print "<H3>只今混雑しています。</H3>";exit;}
sleep(1);

}

}

function unlock($file) {

$lockdir= "lock/";
$lockfile= "$lockdir"."$file";
# ロック用ディレクトリを削除する
if (file_exists($lockfile)) {rmdir($lockfile);}

}
?>
</body>
</html>

実行結果
ロックします
<作成する前にディレクトリが存在していれば【只今混雑しています。】と表示される>
<ディレクトリlock.txtが作成される>
<ファイルlock.txtに文字列【lock test】が書き込まれる>
<ディレクトリlock.txtを削除する>

ロックを解除しました

実行前に、実行するPHPのあるフォルダ(ディレクトリ)にフォルダ[lock]を作成してください。この[lock]フォルダの中にファイル名のディレクトリが作成されます。つまり、[lock]フォルダの中に、複数のファイル分のロックを作成する事ができます。

ロックを確認・作成するにはlock関数を作成し、それを呼び出します。ロックを解除するときはunlockを呼び出します。

$retryは既にロックされている場合は何回挑戦するか回数を指定します。あまり多いとサーバーに負荷がかかってしまいます。sleepは一時停止の秒数です。つまりこの場合は、1秒ごとに3回繰り返してもロックが解除されない場合は混雑中としてexitで処理を停止します。$retry--は$retry=$retry-1と同じ意味です。

file_existsはファイルやディレクトリが存在するかを確認します。if文を使うことにより、指定されたファイルやディレクトリが存在すれば処理を行うという意味になります。

filemtimeはファイルやディレクトリが作成された日時を返します。ここでは30秒よりも古い場合はunlockで解除するために使っています。通常であれば遅くても数秒でロックが解除されるはずなので、30秒も古い場合はエラーで停止したものと判断しています。

whileは条件が正しい間処理を繰り返します。while (!@mkdir($lockfile, 0755))はディレクトリが作成できない間繰り返すという意味です。作成できるときはmkdir($lockfile, 0755)を実行したのと同じです。

unlockではディレクトリが存在した場合は、rmdirでディレクトリを削除します。

ディレクトリを利用し、mkdirがロック開始、rmdirがロック解除という意味合いになっています。ディレクトリの代わりにsymlinkを使う方法などもあります。symlinkではディレクトリを作成・削除するよりも処理が早くなりますがサーバーが対応していなければ使うことができません。(symlinkはWindowsでは動作しません)

symlinkを使う場合は、while (!@mkdir($lockfile, 0755)) {をwhile (!symlink(".", $lockfile)) {に置き換え、rmdir($lockfile);をunlink($lockfile);に置き換えて使います。

アンケート

評価を選んで下さい

参考になった
理解できたが参考にはならなかった
理解できなかった

該当するものを選んで下さい

書かれていることが難しい
書かれていることが理解しやすい
内容が乏しい
内容が充実している

感想や意見があれば記入して下さい。
サイト作りの参考にさせていただきます。

このページのトップへ ▲