2008-10-22 18 views

Respuesta

8

La solución obvia sería llamar al file_exists para verificar si el archivo existe, pero hacerlo podría causar una condición de carrera. Siempre existe la posibilidad de que el otro archivo se creará entre cuando llame al file_exists y cuando llame al copy. La única manera segura de verificar si el archivo existe es usar fopen.

Cuando llame al fopen, establezca el modo en 'x'. Esto indica fopen para crear el archivo, pero solo si no existe. Si existe, fopen fallará, y sabrá que no pudo crear el archivo. Si tiene éxito, tendrá creado un archivo en el destino que puede copiar de forma segura. Código de la muestra es el siguiente:

// 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 ([email protected]($file)) { 
     // There was some problem with our file handle. 
     return false; 
    } 

    // Now we copy over the file we created. 
    if ([email protected]($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; 
} 
+0

Aún tiene una condición de carrera. Pero estás en el camino correcto: si el fopen tiene éxito, utiliza fwrite() para realizar la copia y desvincula el archivo de origen cuando se complete. –

3

Creo que respondió su propia pregunta: verifique que el archivo de destino exista antes de realizar la copia. Si el archivo existe, omita la copia.

Actualización: veo que realmente respondiste tu propia pregunta. Usted menciona las condiciones de carrera, pero si usted encuentra que el archivo ya existe, ¿cómo se sabe que:

  • el archivo que ya está allí es realmente la persona que desea copiar
  • el otro proceso de copiar el archivo ha completado su trabajo (los datos del archivo es todo lo que hay)
  • la otra copia el archivo de proceso no va a fallar (y dejar un archivo incompleto, o borrar el archivo nuevo)

Creo que se debería considerar estas preguntas al diseñar una solución a su problema.

0

Intente utilizar la función link() en lugar de 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; 
    } 
} 

Desafortunadamente, esto será no trabajo en Windows.

0

Una función de tejón de miel, que simplemente no se preocupa por las condiciones de carrera, pero funciona multiplataforma.

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