PHPのfgetcsvやfputcsvでファイルを扱う時の排他処理

別にcsvに限った話ではないが、
以前から使っている(&修正し続けている)CSVファイルを扱う自作ライブラリで書き込み部分で未だ解決していないのがファイルの排他処理。
ググると色々情報が出るのだが、結局どの方法がベストなのかよくわからん。

この2点が特に...
・排他処理(ロック)
・書き込みが失敗した場合の処理

何も考えなければ書き込みは以下の様なソース

<?php
$file = "hoge.csv";
$data = array(
	array( "1", "hoge", "hogegege..." ),
	array( "2", "fuga", "gugagaga..." ),
	array( "3", "piyo", "piyoyoyo..." ),
);

$fp = fopen( $file, "w" );
foreach( $data as $row )
{
    fputcsv( $fp, $row );
}			
fclose( $fp );
?>

まずバッファの問題。
これはfopenの後に以下のようにしてバッファを0にすることで解決。
stream_set_write_buffer( $fp, 0 );
只、これも要るのかどうか....

そして何にせよロックしないとまずいのでflockを使うと、

<?php
$file = "hoge.csv";
$data = array(
	array( "1", "hoge", "hogegege..." ),
	array( "2", "fuga", "gugagaga..." ),
	array( "3", "piyo", "piyoyoyo..." ),
);

$fp = fopen( $file, "w" );
stream_set_write_buffer( $fp, 0 );// バッファをゼロにする
if( flock( $fp, LOCK_EX ) ) // 排他ロック
{
	foreach( $data as $row )
	{
	    fputcsv( $fp, $row );
	}
    flock( $fp, LOCK_UN );// ロックを解放
}		
fclose( $fp );
?>

これでいいのかなと思うのだが、flockマニュアルには以下の警告が
(番号は私が勝手に付けています)

(1)flock() は NFS 及び他の多くのネットワークファイルシステムでは動作しません。 詳細についてはオペレーティングシステムのドキュメントを確認ください。

(2)いくつかのオーペレーティングシステムでflock() はプロセスレベルで実装されています。ISAPIのようなマルチスレッド 型のサーバーAPIを使用している場合、同じサーバーインスタンスの並 列スレッドで実行されている他のPHPスクリプトに対してファイルを保 護する際に flock()を使用することはできません!

(3)
flock()はFATのような 旧式のファイルシステムではサポートされていないため、 そのような環境の場合は常にFALSEを返すことになります。 (これは特にWindows98ユーザーにとって常に真です)


(1)の様なNFSを通して操作することが実際にあるのか分からないが、どうもflock()はOSに依存するらしい。
(2)に該当するマルチスレッドというのは意外と多いみたい。
(3)FATはさすがに該当する機会が無い様な気がする。

以下のサイトや他のサイトを色々見ていると、
mkdirでロック用ディレクトリを作る方法がいいみたい。
という訳で、mikdirしたり、renameしたりしてる訳で...
どうやら「flock( $fp, LOCK_UN );」は要らないみたいだし...

その2へ続く


以下参考にしたページ

ファイル書き込みの排他制御

ファイルのロックに関する基礎知識

php flock LOCK_なんたらが効かない・できない・動作しない件(PHP)

flock考 - PHPの基礎体力掲示板

排他処理に stream_set_write_buffer は不要じゃね?

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

fopen関数

flock関数