Как скопировать файл на PHP без перезаписи существующего файла?

Когда вы используете функцию копирования PHP, операция слепо копирует файл назначения, даже если он уже существует. Как вы копируете файл безопасно, только выполняете копию, если нет существующего файла?

Очевидным решением было бы вызвать file_exists, чтобы проверить, существует ли файл, но это может привести к состоянию гонки. Всегда существует вероятность того, что другой файл будет создан между ними при вызове file_exists и при вызове копии . Единственный безопасный способ проверить, существует ли файл, – использовать 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.

Функция медового барсука, которая просто не заботится о гоночных условиях, но работает кросс-платформенно.

 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; }