Загрузка файла HTTP: мониторинг процесса загрузки

Я нахожусь в ситуации, когда мне нужно реализовать загрузку больших файлов (до 4 ГБ) с веб-сервера: Apache 2.4.4 по протоколу HTTP. Я пробовал несколько подходов, но лучшим решением оказалось использование модуля X-SendFile.

Поскольку я предлагаю индикатор выполнения для загрузки файлов, мне потребуется такая же функция для загрузки файлов. Итак, вот мои вопросы:

  • Есть ли способ, включая обходной путь, для отслеживания хода загрузки файлов?
  • Есть ли способ, включая обходной путь, рассчитать скорость передачи файлов?
  • Есть ли лучший способ обеспечить эффективную загрузку файлов с веб-сервера, чем использование модуля X-Sendfile?

Есть ли лучший вариант загрузки файла в целом, который позволил бы мне отслеживать процесс загрузки файла? Это может быть клиентское (JavaScript) или серверное решение (PHP). Есть ли какой-либо конкретный веб-сервер, который позволяет это?

В настоящее время я использую:

  • Апач 2.4.4
  • Убунту

Много раз спасибо.


person Bunkai.Satori    schedule 22.10.2013    source источник
comment
Вы можете использовать cURL в php. stackoverflow.com/questions/13958303/   -  person posit labs    schedule 25.10.2013
comment
Можете ли вы передать файл с вашего сервера в потоковом режиме или вы загружаете один файл?   -  person web_bod    schedule 25.10.2013
comment
@web_bod, многие файлы будут загружены с сервера. Другими словами, загрузка и выгрузка файлов будет основным функционалом сервера. Поскольку я контролирую сервер, я могу выбрать любую форму загрузки файла. Я пытался загрузить через PHP, но это привело к ограничениям на размер файла и количество загружаемых файлов. Поэтому я попробовал X-SendFile, который выглядит хорошо. Однако, если потоковая передача — это путь, я с радостью подделаю X-SendFile.   -  person Bunkai.Satori    schedule 25.10.2013
comment
@positlabs, cURL тоже выглядит интересно. Спасибо за этот совет. Поскольку я мало что знаю о cURL, я собираюсь его изучить. Надеюсь, cURL не препятствует скачиванию файла или количеству одновременных загрузок.   -  person Bunkai.Satori    schedule 25.10.2013
comment
На выходных я набросаю для вас кое-что. PHP — ваш любимый язык?   -  person web_bod    schedule 25.10.2013
comment
@web_bod, это очень мило с твоей стороны. Да, PHP — мой предпочтительный серверный язык. На стороне клиента ничего особенного только: HTML 5, JavaScript. Конечно, я бы не хотел, чтобы клиенты устанавливали что-то особенное вроде java или flash из-за скачивания файлов. Сервер должен иметь возможность обрабатывать несколько файлов и нескольких пользователей без ограничения размера файла, так как у меня могут быть файлы размером в несколько ГБ. Заранее большое спасибо. Пожалуйста, не забывай меня. :-)   -  person Bunkai.Satori    schedule 25.10.2013
comment
@web_bod: есть еще кое-что. файлы на серверах находятся в своих конкретных каталогах, вдали от каталога веб-обслуживания. Сейчас я изучаю cURL, но я не уверен, может ли cURL получить доступ к файлам, хранящимся где-то еще, кроме веб-каталога, на сервере.   -  person Bunkai.Satori    schedule 25.10.2013
comment
@positlabs, я протестировал cURL. Он имеет даже информацию о прогресс-баре. Проблема с cURL заключается в том, что, когда требуется загрузить большой файл, при загрузке файла происходит большая задержка, прежде чем загрузка действительно произойдет. Я не знаю, чем это вызвано. Но представьте, вы нажимаете на ссылку, чтобы получить файл, и теперь вам нужно подождать несколько минут, прежде чем начнется загрузка. Но это был хороший совет +1   -  person Bunkai.Satori    schedule 31.10.2013


Ответы (4)


2 идеи (не проверено):

Во-первых:

Вместо размещения обычных ссылок на файлы (которые вы хотите скачать) на вашей странице разместите ссылки типа .../dowanload.php, которые могут выглядеть примерно так:

<?php

    // download.php file
    session_start(); // if needed

    $filename = $_GET['filename']);

    header( 'Content-type: text/plain' ); // use any MIME you want here
    header( 'Content-Disposition: attachment; filename="' . htmlspecialchars($filename) . '"' );
    header( 'Pragma: no-cache' );

    // of course add some error handling

    $filename = 'c:/php/php.ini';

    $handle = fopen($filename, 'rb');

    // do not use file_get_contents as you've said files are up to 4GB - so read in chunks
    while($chunk = fread($handle, 1000)) // chunk size may depend on your filesize
    {
        echo $chunk;
        flush();
        // write progress info to the DB, or session variable in order to update progress bar
    }

    fclose($handle);
?>

Таким образом, вы можете следить за процессом загрузки. Тем временем вы можете записывать информацию о ходе выполнения в переменную БД/сессии и обновлять статус чтения индикатора выполнения из переменной БД/сеанса, используя AJAX, конечно, опрашивая скрипт, который считывает информацию о ходе выполнения.

Это очень упрощено, но я думаю, что это может работать так, как вы хотите.

Второе:

В Apache 2.4 встроен язык Lua:

Бьюсь об заклад, вы можете попробовать написать обработчик LUA Apache, который будет отслеживать вашу загрузку - отправлять ход выполнения в БД и обновлять индикатор выполнения, используя PHP/AJAX, получая информацию о ходе выполнения из БД.

Аналогично - есть модули для perl и даже python (но не для win)

person Artur    schedule 28.10.2013
comment
Странные URL-адреса можно скрыть с помощью mod_rewrite. Внешний мир не должен знать о скрипте download.php. - person Palec; 29.10.2013
comment
Вместо mod_lua вы можете использовать mod_perl, который не находится в экспериментальном состоянии. - person Palec; 29.10.2013
comment
используя БД для хранения обновлений прогресса? теперь я понимаю, почему node.js становится популярным... я имею в виду, по крайней мере, предложить APC... - person dandavis; 30.10.2013
comment
@dandavis: Конечно, с APC все будет в порядке, но в новейшем PHP его уже нет (Opcache должен разрешить подобное). Node.js — это то, о чем мне нужно больше читать — просто слышать об этом — не более того. Спасибо - person Artur; 30.10.2013
comment
@Артур, привет и спасибо за ваш отзыв. Честно говоря, мне это кажется слишком сложным и, возможно, излишним для того, что мне нужно. Для меня работала комбинация fopen(), fread(), print() при отслеживании хода загрузки с помощью запросов AJAX. - person Bunkai.Satori; 31.10.2013
comment
@ Артур, привет, могу я связаться с тобой по поводу твоего ответа, пожалуйста. Похоже, что невозможно запустить php-скрипт мониторинга загрузки во время загрузки. Пожалуйста, смотрите мой пост здесь: stackoverflow.com/questions/21506560/. У вас есть идеи для решения? Заранее спасибо. - person Bunkai.Satori; 02.02.2014

Я вижу основную проблему в том, что: В решении php+apache буферизация вывода может быть размещена в нескольких местах:

Браузер ‹= 1 => Apache ‹= 2 => обработчик PHP ‹= 3 => процесс интерпретатора PHP

Вам нужно контролировать первый буфер. Но напрямую из PHP нельзя.

Возможные решения:

1) Вы можете написать собственный мини-демон, основной функцией которого будет только отправка файлов и запуск его, например, на порту, отличном от 80, 8880. И обрабатывать загрузку файлов и мониторить выходной буфер оттуда. Ваш выходной буфер будет только один, и вы можете им управлять:

Браузер ‹= 1 => Процесс интерпретатора PHP

2) Также вы можете взять mod_lua и управлять выходными буферами прямо из апача.

3) Также вы можете взять nginx и управлять буферами вывода nginx с помощью встроенного perl (это стабильно)

4) Попробуйте использовать Встроенный веб-сервер PHP и управлять буфер вывода php напрямую. Не могу ничего сказать о стабильности, извините. Но вы можете попробовать. ;)

Я думаю, что nginx+php+встроенный perl более стабильное и мощное решение. Но вы можете выбрать и, возможно, использовать другое решение, не указанное в этом списке. Я буду следить за этой темой и с интересом жду вашего окончательного решения.

person dododo    schedule 29.10.2013

Чтение и запись в базу данных через короткие промежутки времени убивает производительность.

Я бы предложил использовать сеансы (увеличивая значение отправленных данных в цикле), с которыми вы можете безопасно отключиться совсем другим файлом php, вы можете возвращать данные в виде JSON, который может использоваться функцией/плагином javascript.

person jamek    schedule 30.10.2013
comment
отличная идея. У меня было то же самое. Однако я столкнулся с неожиданной проблемой: пока работает основной скрипт загрузки PHP, скрипт мониторинга PHP не запускается вызовами AJAX. Я застрял с этим в течение длительного времени и тестировать его. Но сценарии мониторинга AJAX, по-видимому, запускаются только тогда, когда в данный момент нет другого запущенного PHP-скрипта. см. мой другой пост - person Bunkai.Satori; 30.10.2013
comment
Я пробовал много подходов, и у всех была какая-то проблема. Подход с использованием fopen() fread() print() работает лучше всего для меня и не дает ограничений на размер файла. Поэтому я отмечаю этот ответ как полезный, как принятый ответ и награждаю его своей наградой. - person Bunkai.Satori; 31.10.2013

Если вы используете версию php >= 5.4, это может помочь вам http://www.php.net/manual/en/session.upload-progress.php

person kryoz    schedule 31.10.2013
comment
привет и спасибо за совет. Я знаю об этом, и на самом деле я это реализовал. Единственная проблема в том, что, хотя он хорошо работает для загрузки, он не работает для загрузки. Поэтому ищу альтернативное решение. - person Bunkai.Satori; 31.10.2013