У меня есть каталог с файлами, которые нуждаются в обработке в пакете с PHP. Файлы копируются на сервер через FTP. Некоторые из файлов очень большие и требуют много времени для копирования. Как я могу определить в PHP, если файл все еще переносится (поэтому я могу пропустить обработку этого файла и обработать его в следующем запуске пакетного процесса)?
Возможность получить размер файла, подождать несколько минут и проверить, отличается ли размер файла. Это не является водонепроницаемым, потому что есть небольшой шанс, что передача просто застопорилась на несколько мгновений …
Один из самых безопасных способов сделать это – загрузить файлы с временным именем и переименовать их после завершения передачи. Программа должна пропускать файлы с временным именем (простое расширение работает очень хорошо.) Очевидно, для этого требуется, чтобы клиент (загрузчик) сотрудничал, поэтому он не идеален.
[Это также позволяет удалять неудачные (частичные) переводы по истечении заданного периода времени, если вам это нужно.]
Все, что основано на опросе размера файла, является ярким и небезопасным.
Другая схема (которая также требует сотрудничества от загрузчика) может включать сначала загрузку хэша и размера файла, а затем фактический файл. Это позволяет вам знать, когда это делается, и если это согласовано. (Существует много вариантов этой идеи.)
Что-то, что не требует сотрудничества от клиента, проверяет, открыт ли файл другим процессом или нет. (Как вы это делаете, зависит от ОС – я не знаю встроенного PHP, который делает это. lsof
и / или fuser
могут использоваться на разных платформах Unix-типа, для Windows для этого есть API.) Если другой процесс файл открыт, скорее всего, он еще не завершен.
Обратите внимание, что этот последний подход не может быть безупречным, если вы разрешаете перезапуск / возобновление загрузки или если ваше программное обеспечение FTP-сервера не сохраняет файл открытым в течение всей продолжительности передачи, поэтому YMMV.
Наш администратор сервера предложил ftpwho, который выводит файлы, которые в настоящий момент переносятся.
http://www.castaglia.org/proftpd/doc/ftpwho.html
Таким образом, решение состоит в анализе вывода ftpwho, чтобы увидеть, переносится ли файл в каталог.
Некоторые FTP-серверы позволяют запускать команды, когда происходит определенное событие. Поэтому, если ваш FTP-сервер разрешает это, вы можете создать простую схему сигнализации, чтобы ваше приложение узнало, что файл загружен более или менее успешно (более или менее потому, что вы не знаете, должен ли пользователь загружать файл полностью или по частям). Схема сигнализации может быть такой же простой, как создание файла «uploaded_file_name.ext.complete», и вы будете следить за существованием файлов с расширением «.complete».
Теперь вы можете проверить, можете ли вы открыть файл для записи. Большинство FTP-серверов не позволят вам делать это, если файл загружается.
Еще один подход, упомянутый Матом, – это использование системных методов для проверки того, открыт ли файл другим процессом.
Лучший способ проверить – попытаться получить эксклюзивную блокировку файла с помощью стаи. Процесс 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."); }
Это не очень хороший трюк, но это просто :-), то же самое можно делать с файлом
$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;