Como determinar se um arquivo ainda está sendo transferido via ftp

Eu tenho um diretório com arquivos que precisam ser processados ​​em um lote com o PHP. Os arquivos são copiados no servidor via FTP. Alguns dos arquivos são muito grandes e demoram muito para copiar. Como posso determinar no PHP se um arquivo ainda está sendo transferido (então eu posso ignorar o processamento desse arquivo e processá-lo na próxima execução do processo em lote)?

A possibilidade é obter o tamanho do arquivo, aguarde alguns instantes e verifique se o tamanho do arquivo é diferente. Isso não é impermeável porque há poucas chances de que a transferência tenha sido interrompida por alguns instantes …

Uma das formas mais seguras de fazer isso é carregar os arquivos com um nome temporário e renomeá-los assim que a transferência for concluída. O seu programa deve ignorar os arquivos com o nome temporário (uma extensão simples funciona bem). Obviamente, isso exige que o cliente (uploader) coopere, por isso não é ideal.

[Isso também permite que você exclua as transferências falhas (parciais) após um determinado período de tempo, se você precisar disso.]

Qualquer coisa com base na pesquisa do tamanho do arquivo é razada e insegura.

Outro esquema (que também requer cooperação com o uploader) pode envolver o upload do arquivo hash e tamanho primeiro, depois o arquivo real. Isso permite que você conheça os dois quando a transferência for concluída, e se for consistente. (Existem muitas variantes em torno dessa idéia.)

Algo que não requer cooperação com o cliente é verificar se o arquivo está aberto por outro processo ou não. (Como você faz isso dependendo do SO – eu não sei de um arquivo PHP que faz isso. O lsof e / ou o fuser podem ser usados ​​em uma variedade de plataformas de tipo Unix, o Windows possui APIs para isso.) Se outro processo tiver O arquivo aberto, é provável que ainda não esteja completo.

Tenha em atenção que esta última abordagem pode não ser à prova de falsidade se você permitir reiniciar / retomar os carregamentos, ou se o seu software de servidor FTP não mantém o arquivo aberto durante todo o período da transferência, então, YMMV.

Nosso administrador do servidor sugeriu o ftpwho, que mostra quais arquivos são transferidos atualmente.

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

Portanto, a solução é analisar a saída do ftpwho para ver se um arquivo no diretório está sendo transferido.

Alguns servidores FTP permitem executar comandos quando ocorre determinado evento. Então, se o seu servidor de FTP permitir isso, você pode criar um esquema de sinalização simples para que seu aplicativo saiba que o arquivo foi carregado com mais ou menos sucesso (mais ou menos é porque você não sabe se o usuário pretendia carregar o arquivo completamente ou em partes). O esquema de sinalização pode ser tão simples como a criação do arquivo “uploaded_file_name.ext.complete” e você monitorará a existência de arquivos com extensão “.complete”.

Agora, você pode verificar se você pode abrir o arquivo para escrever. A maioria dos servidores de FTP não permitirá que você faça isso se o arquivo estiver sendo carregado.

Uma abordagem mais mencionada pela Mat é usar técnicas específicas do sistema para verificar se o arquivo é aberto por outro processo.

A melhor maneira de verificar seria tentar obter um bloqueio exclusivo no arquivo usando flock. O processo sftp / ftp estará usando as 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."); } 

Não é realmente um bom truque, mas é simples :-), o mesmo que você pode fazer com 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;