【发布时间】:2008-10-22 18:00:53
【问题描述】:
当您使用 PHP copy 函数时,该操作会盲目地复制目标文件,即使它已经存在。如何安全地复制文件,仅在没有现有文件的情况下执行复制?
【问题讨论】:
当您使用 PHP copy 函数时,该操作会盲目地复制目标文件,即使它已经存在。如何安全地复制文件,仅在没有现有文件的情况下执行复制?
【问题讨论】:
显而易见的解决方案是调用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;
}
【讨论】:
我认为您回答了自己的问题 - 在执行复制之前检查以确保目标文件存在。如果文件存在,则跳过副本。
更新:我看到你确实回答了你自己的问题。您提到了竞争条件,但如果您确实发现该文件已经存在,您怎么知道:
我认为在为您的问题设计解决方案时应该考虑这些问题。
【讨论】:
一个蜜獾函数,它不关心竞争条件,但可以跨平台工作。
function safeCopy($src, $dest) {
if (is_file($dest) === true) {
// if the destination file already exists, it will NOT be overwritten.
return false;
}
if (copy($src, $dest) === false) {
echo "Failed to copy $src... Permissions correct?\n";
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 上运行。
【讨论】: