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

前回の続き

fputcsv、fwriteなどは大抵失敗したときにfalseを返すので
以下のようにfputcsvの度にfalse(失敗)を取得するようにする。
んでもって失敗した場合の処理をどうにかする。

以下ソース(何気に前回とコーディングスタイルが違うが気にしない)

<?php

// 省略

$success = false;
if (file_lock($file) {
	$res = true;
	$fp = @fopen($file ,'w');
	if ($fp) {
		foreach ($data as $row) {
			$res = $res && @fputcsv($fp, $row);
		}
		fclose($fp);
	} else {
		$res = false;	
	}
	file_unlock($file);
}

if (! $res) {
	// エラー処理
}

// 省略

?>

...このままだと失敗した場合を検知するけど、
fputcsvのループ最中で失敗してるとファイルが中途半端になって壊れてしまう。
あとでエラー処理をしてもすでに遅いじゃないか。

回避するのに思いついた方法は...
・「元ファイル名.tmp」で仮ファイルを作成
・仮ファイルにデータを書き込み
・エラーが無く終了していたら元ファイルを削除、仮ファイルを元ファイル名にリネーム
・エラーがあれば仮ファイルを削除
という方法

以下ソース

<?php

// 省略

$success = false;
if (file_lock($file) {
	$res = true;
	$tmp_file = $file . '.tmp';
	$fp = @fopen($tmp_file ,'w');
	if ($fp) {
		foreach ($data as $row) {
			$res = $res && @fputcsv($fp, $row);
		}
		fclose($fp);
		if ($res) {
			@unlink( $file );
			@rename( $tmp_file, $file );
		} else {
			@unlink( $tmp_file );
		}
	} else {
		$res = false;	
	}
	file_unlock($file);
}

if (! $res) {
	echo 'なんか失敗っぽいですよ';
}

// 省略

?>

...しかし
元ファイル削除やリネームで失敗したらどうなるんだろ...?
そもそも失敗するのか?
いやありえるか、世の中に絶対なんて無い!
失敗したらどうなるか?
元ファイルの削除失敗ならデータが更新されないだけなので大した問題では無い気がする。
問題はリネーム失敗の場合、仮ファイルだけが残り、元ファイルが無いまま....

だったらrenameを数回リトライする
何回?100回リトライしても駄目だったら?
駄目だったら諦める?

...いや、そこまで考えるなら最初っからDBを使うべきか。
またはアプリ側でバックアップ機能を付けるとかの方がいいか。
うむぅ。