PHP のコピー機能を使用すると、目的のファイルが既に存在する場合でも、目的のファイルが盲目的にコピーされます。既存のファイルがない場合にのみコピーを実行して、ファイルを安全にコピーするにはどうすればよいですか?
4 に答える
明らかな解決策は、file_existsを呼び出してファイルが存在するかどうかを確認することですが、これを行うと競合状態が発生する可能性があります。file_existsを呼び出してからcopyを呼び出すまでの間に、他のファイルが作成される可能性は常にあります。ファイルが存在するかどうかを確認する唯一の安全な方法は、fopenを使用することです。
fopenを呼び出すときは、モードを「x」に設定します。これは、ファイルが存在しない場合にのみ、ファイルを作成するようにfopenに指示します。存在する場合、fopenは失敗し、ファイルを作成できなかったことがわかります。成功すると、コピー先に安全にコピーできるファイルが作成されます。サンプルコードは次のとおりです。
// The PHP copy function blindly copies over existing files. We don't wish
// this to happen, so we have to perform the copy a bit differently. The
// only safe way to ensure we don't overwrite an existing file is to call
// fopen in create-only mode (mode 'x'). If it succeeds, the file did not
// exist before, and we've successfully created it, meaning we own the
// file. After that, we can safely copy over our own file.
$filename = 'sourcefile.txt'
$copyname = 'sourcefile_copy.txt'
if ($file = @fopen($copyname, 'x')) {
// We've successfully created a file, so it's ours. We'll close
// our handle.
if (!@fclose($file)) {
// There was some problem with our file handle.
return false;
}
// Now we copy over the file we created.
if (!@copy($filename, $copyname)) {
// The copy failed, even though we own the file, so we'll clean
// up by itrying to remove the file and report failure.
unlink($copyname);
return false;
}
return true;
}
あなた自身の質問に答えたと思います-コピーを実行する前に、宛先ファイルが存在することを確認してください。ファイルが存在する場合は、コピーをスキップします。
更新:あなたは本当にあなた自身の質問に答えたようです。競合状態について言及していますが、ファイルが既に存在することがわかった場合、どうすればそれを知ることができますか:
- 既に存在するファイルは、実際にコピーしたいファイルです
- ファイルをコピーしている他のプロセスがジョブを完了しました (ファイル データはすべてそこにあります)。
- ファイルをコピーする他のプロセスは失敗しません(不完全なファイルを残すか、新しいファイルを削除します)
問題の解決策を設計するときは、これらの質問を考慮する必要があると思います。
link()
の代わりに関数を使用してみてくださいcopy()
。
function safe_copy($src, $dest) {
if (link($src, $dest)) {
// Link succeeded, remove old name
unlink($filename);
return true;
} else {
// Link failed; filesystem has not been altered
return false;
}
}
残念ながら、これはWindows では機能しません。