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 );」は要らないみたいだし...
以下参考にしたページ
php flock LOCK_なんたらが効かない・できない・動作しない件(PHP)