7

PHP のコピー機能を使用すると、目的のファイルが既に存在する場合でも、目的のファイルが盲目的にコピーされます。既存のファイルがない場合にのみコピーを実行して、ファイルを安全にコピーするにはどうすればよいですか?

4

4 に答える 4

8

明らかな解決策は、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;
}
于 2008-10-22T18:03:09.897 に答える
3

あなた自身の質問に答えたと思います-コピーを実行する前に、宛先ファイルが存在することを確認してください。ファイルが存在する場合は、コピーをスキップします。

更新:あなたは本当にあなた自身の質問に答えたようです。競合状態について言及していますが、ファイルが既に存在することがわかった場合、どうすればそれを知ることができますか:

  • 既に存在するファイルは、実際にコピーしたいファイルです
  • ファイルをコピーしている他のプロセスがジョブを完了しました (ファイル データはすべてそこにあります)。
  • ファイルをコピーする他のプロセスは失敗しません(不完全なファイルを残すか、新しいファイルを削除します)

問題の解決策を設計するときは、これらの質問を考慮する必要があると思います。

于 2008-10-22T18:01:54.533 に答える
0

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 では機能しません。

于 2009-02-13T21:14:51.060 に答える