<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress/2.3.3" -->
<rss version="0.92">
<channel>
	<title>MT312 &#187; $fpが権限を握るflockによるファイルロック</title>
	<link>http://www.mt312.com</link>
	<description></description>
	<lastBuildDate>Sun, 13 Jul 2008 21:49:58 +0000</lastBuildDate>
	<docs>http://backend.userland.com/rss092</docs>
	<language>ja</language>
	
	<item>
		<title>$fpが権限を握るflockによるファイルロック</title>
		<description>果たして、この記事が役に立つか疑問ですが、私の様にポカをする人がいないとも限りませんし、忘備録的に書いてみます。

先日カウンターのログが頻繁に壊れると指摘があり、原因が分からず2日程考えていた時、ふと疑問が。テストしてみると、全くロックできていない。実はこう書いていました。
[php]
function lock() {
  $fp = fopen('./lock', 'w');
  return $fp && flock($fp, LOCK_EX);
}
if(!lock()) {
  // ロック失敗で終了
}
// ログ保存
$fp = fopen(LOG_FILE, 'wb');
fwrite($fp, $lines);
fclose($fp);
[/php]
自分では正しいと思っていたんですけど、実はlock()はtrueしか返さず、後にロックが外れます。どうなっているかと言うと、lcok()と同時にロックされ真が返りますが、$fpがローカル変数で既に用済みな為、ロックが外れてしまうのです。flockによるファイルロックは$fpが生きている必要があります。つまり、以下でもロックが外れます。
[php]
$fp = fopen('./lock', 'w');
flock($fp, LOCK_EX);
unset($fp);
[/php]
よって、こう書いて解決。
関数にしなきゃいいだけの話。
[php]
// ファイル生成可能で空にするコストがないaを指定
$l_fp = fopen('./lock', 'a+');
$locked = $l_fp && flock($l_fp, LOCK_EX);
if(!$locked) {
  // ロック失敗で終了
}
// ログ保存
$fp = fopen(LOG_FILE, 'wb');
fwrite($fp, $lines);
fclose($fp);
[/php]
上の例と違い、ログファイルを追記モードで扱う場合はロックファイルを用意する必要はありません。また、追記モードで書込モードの様に空にしてから書き込む事もできます。
[php]
// ファイルがなければ生成
$fp = fopen(LOG_FILE, 'a+b');
// ロックしてファイルを空にする
$prepared ...</description>
		<link>http://www.mt312.com/php/44/</link>
			</item>
</channel>
</rss>
