Как скопировать файл в PHP без перезаписи существующего файла? - PullRequest
6 голосов
/ 22 октября 2008

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

Ответы [ 4 ]

8 голосов
/ 22 октября 2008

Очевидным решением было бы вызвать 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;
}
3 голосов
/ 22 октября 2008

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

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

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

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

0 голосов
/ 26 марта 2014

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

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;   
}
0 голосов
/ 14 февраля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...