2011-08-30 14 views
25

Tengo un directorio con archivos que necesitan procesarse en un lote con PHP. Los archivos se copian en el servidor a través de FTP. Algunos de los archivos son muy grandes y tardan mucho tiempo en copiarse. ¿Cómo puedo determinar en PHP si aún se está transfiriendo un archivo (para poder omitir el procesamiento en ese archivo y procesarlo en la siguiente ejecución del proceso por lotes)?Cómo determinar si un archivo todavía se está transfiriendo a través de ftp

Una posibilidad es obtener el tamaño del archivo, espere unos momentos y verifique si el tamaño del archivo es diferente. Esto no es impermeable porque hay una pequeña posibilidad de que la transferencia se haya detenido por unos momentos ...

+1

Hmm, interesante cuestión de hecho! +1 –

+0

Puede usar [ftp_nb_put] (http://nl3.php.net/manual/en/function.ftp-nb-put.php), ver ejemplo con while-loop en el documento. –

+1

cheque por Linux usando exec como 'lsof | grep filename ' –

Respuesta

5

Nuestro administrador de servidor sugirió ftpwho, que genera qué archivos se transfieren actualmente.

http://www.castaglia.org/proftpd/doc/ftpwho.html

Así que la solución es analizar la salida de ftpwho para ver si un archivo en el directorio está siendo transferido.

9

Una de las formas más seguras de hacerlo es subir los archivos con un nombre temporal y cambiarles el nombre una vez la transferencia ha terminado. Su programa debe omitir archivos con el nombre temporal (una simple extensión funciona bien). Obviamente, esto requiere que el cliente (cargador) coopere, por lo que no es ideal.

[Esto también le permite borrar las transferencias fallidas (parciales) después de un período de tiempo determinado si necesita eso.]

Cualquier cosa basado en el sondeo del tamaño del archivo es subido de tono e inseguro.

Otro esquema (que también requiere la cooperación del cargador) puede implicar cargar primero el hash y el tamaño del archivo, luego el archivo real. Eso le permite saber cuándo se realiza la transferencia y si es coherente. (Hay muchas variantes en torno a esta idea.)

Algo que no requiere cooperación del cliente es comprobar si el archivo está abierto por otro proceso o no. (Cómo lo hace es dependiente del sistema operativo - No sé de un PHP incorporado que hace esto. lsof y/o fuser se puede utilizar en una variedad de plataformas de tipo Unix, Windows tiene API para esto.) Si otro proceso tiene el archivo abierto, es probable que aún no esté completo.

Tenga en cuenta que este último enfoque puede no ser infalible si permite reiniciar/reanudar cargas, o si el software del servidor FTP no mantiene el archivo abierto durante toda la transferencia, entonces YMMV.

+1

La transferencia la lleva a cabo un usuario a través de ftp y no está iniciada por php. No quiero que el usuario tenga que cambiar el nombre del archivo cuando se haya transferido – murze

+1

Edité mi respuesta de una manera que no requiere nada del cliente. No es infalible. (No creo que nada sea con un FTP simple.) – Mat

+1

Tenga en cuenta: 'lsof' y' fuser' deben ejecutarse como 'root' para informarle sobre otros usuarios. Además, si su archivo está en un NFS fs, no le dirán nada si el archivo está siendo escrito desde otra máquina distinta a la que está ejecutando el comando 'lsof' o' fuser'. –

4

Algunos servidores FTP permiten ejecutar comandos cuando se produce determinado evento. Entonces, si su servidor FTP lo permite, puede crear un esquema de señalización simple para que su aplicación sepa que el archivo se ha cargado con más o menos éxito (más o menos es porque no sabe si el usuario tenía la intención de cargar el archivo) completamente o en partes). El esquema de señalización puede ser tan simple como la creación del archivo "uploaded_file_name.ext.complete", y usted controlará la existencia de archivos con la extensión ".complete".

Ahora puede verificar si puede abrir el archivo para escribir. La mayoría de los servidores FTP no te permitirán hacer esto si el archivo se está cargando.

Otro enfoque mencionado por Mat es el uso de técnicas específicas del sistema para verificar si el archivo está abierto por otro proceso.

2

La mejor forma de comprobarlo sería intentar obtener un bloqueo exclusivo en el archivo que utiliza el rebaño. El proceso sftp/ftp utilizará las bibliotecas fopen.

// try and get exclusive lock on file 
$fp = fopen($pathname, "r+"); 

if (flock($fp, LOCK_EX)) { // acquire an exclusive lock 
    flock($fp, LOCK_UN); // release the lock 
fclose($fp); 
} 
else { 
    error_log("Failed to get exclusive lock on $pathname. File may be still uploading."); 
} 
+0

Esto desencadena la instrucción else para la mayoría de los archivos, aunque no se estén cargando. – Rapti

+0

El servidor FTP no bloquea la transferencia de archivos. Por lo tanto, esta prueba es incorrecta. – artoodetoo

+0

me parece a mí ... si no puedes obtener un candado ... el archivo aún se está cargando ... parece ser lo que está buscando ... voto favorable. –

0

No es realmente un truco, pero es :-) simple, el mismo u puede hacer con filemtime

$result = false; 
$tryies = 5; 
if (file_exists($filepath)) { 
    for ($i=0; $i < $tryies; $i++) { 
     sleep(1); 
     $filesize[] = filesize($filepath); 
    } 
    $filesize = array_unique($filesize); 
    if (count($filesize) == 1) { 
     $result = true; 
    } else { 
     $result = false; 
    } 
} 

return $result; 
Cuestiones relacionadas