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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
7
0
13 879
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Думаю, вы ответили на свой вопрос - убедитесь, что целевой файл существует, прежде чем копировать. Если файл существует, пропустите копию.

Обновление: я вижу, вы действительно ответили на свой вопрос. Вы упоминаете условия гонки, но если вы обнаружите, что файл уже существует, как вы это узнаете:

  • файл, который уже есть, действительно тот, который вы хотите скопировать
  • другой процесс, копирующий файл, завершил свою работу (все данные файла есть)
  • другой процесс, копирующий файл, не потерпит неудачу (и оставит неполный файл или удалит новый файл)

Я думаю, вам следует учитывать эти вопросы при разработке решения вашей проблемы.

Ответ принят как подходящий

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

У вас все еще есть состояние гонки. Но вы на правильном пути - если fopen завершится успешно, используйте fwrite () для выполнения копирования и разорвите связь с исходным файлом по завершении.

Nathan Strong 25.10.2008 21:13

Попробуйте использовать функцию 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;   
}

Другие вопросы по теме