2011-08-30 2 views
25

У меня есть каталог с файлами, которые нуждаются в обработке в пакете с PHP. Файлы копируются на сервер через FTP. Некоторые из файлов очень большие и требуют много времени для копирования. Как я могу определить в PHP, если файл все еще переносится (поэтому я могу пропустить обработку этого файла и обработать его в следующем запуске пакетного процесса)?Как определить, переносится ли файл по ftp

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

+1

Хм, интересный вопрос, на самом деле! +1 –

+0

Вы можете использовать [ftp_nb_put] (http://nl3.php.net/manual/en/function.ftp-nb-put.php), см. Пример с while-loop в документе. –

+1

check by linux с помощью exec как 'lsof | grep filename ' –

ответ

5

Наш сервер admin предложил ftpwho, который выводит файлы, которые в настоящий момент переносятся.

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

Таким образом, решение для разбора вывода ftpwho, чтобы увидеть, если файл в директории передается.

9

Один из самых безопасных способов сделать это - загрузить файлы с временным именем и переименовать их после передача завершена. Программа должна пропускать файлы с временным именем (простое расширение работает очень хорошо.) Очевидно, для этого требуется, чтобы клиент (загрузчик) сотрудничал, поэтому он не идеален.

[Это также позволяет удалять неудачные (частичные) переводы по истечению определенного периода времени, если вам нужно.]

Anything, основанного на опросе размер файла является колоритным и небезопасным.

Другая схема (которая также требует сотрудничества от загрузчика) может включать сначала загрузку хэша и размера файла, а затем фактический файл. Это позволяет вам знать, когда это делается, и если это согласовано. (Существует много вариантов этой идеи.)

Что-то, что не требует сотрудничества от клиента, проверяет, открыт ли файл другим процессом или нет. (Как вы это делаете, зависит от ОС). Я не знаю встроенного PHP, который делает это. lsof и/или fuser могут использоваться на разных платформах Unix, для Windows для этого есть API.) Если другой процесс имеет файл открыт, скорее всего, он еще не завершен.

Обратите внимание, что этот последний подход не может быть безупречным, если вы разрешаете перезапуск/возобновление загрузки или если ваше программное обеспечение FTP-сервера не сохраняет файл открытым в течение всей продолжительности передачи, поэтому YMMV.

+1

Передача выполняется пользователем через ftp и не инициируется php. Я не хочу, чтобы пользователь должен был переименовать файл, когда он был передан. – murze

+1

Отредактировал мой ответ одним способом, который от клиента ничего не требует. Это не безупречно. (Я не считаю, что что-то с простым FTP.) – Mat

+1

Обратите внимание: 'lsof' и' fuser' должны запускаться как 'root', чтобы рассказать вам о других пользователях. Кроме того, если ваш файл находится в файловой системе NFS, они не скажут вам, что файл записывается с другого компьютера, кроме того, на который вы запускаете команду 'lsof' или' fuser'. –

4

Некоторые FTP-серверы позволяют запускать команды при возникновении определенного события. Поэтому, если ваш FTP-сервер разрешает это, вы можете создать простую схему сигнализации, чтобы ваше приложение узнало, что файл загружен более или менее успешно (более или менее потому, что вы не знаете, должен ли пользователь загружать файл полностью или по частям). Схема сигнализации может быть такой же простой, как создание файла «uploaded_file_name.ext.complete», и вы будете следить за существованием файлов с расширением «.complete».

Теперь вы можете проверить, можете ли вы открыть файл для записи. Большинство FTP-серверов не позволят вам делать это, если файл загружается.

Еще один подход, упомянутый Матом, использует системные методы для проверки того, открыт ли файл другим процессом.

2

Лучший способ проверить, чтобы попытаться получить эксклюзивную блокировку файла, используя стая. Процесс sftp/ftp будет использовать библиотеки 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

Это вызывает инструкцию else для большинства файлов, даже если они не загружаются. – Rapti

+0

FTP-сервер не блокирует передачу файлов. Итак, этот тест неверен. – artoodetoo

+0

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

0

Это не действительно хороший трюк, но это просто :-), то же самое и может делать с 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; 
Смежные вопросы