Отслеживание прогресса загрузки файлов с помощью сессий

PHP может отслеживать прогресс загрузки отдельных файлов при включенной опции session.upload_progress.enabled. Данная информация не особенно полезна для запроса, непосредственно закачивающего файл, однако, в течение данной загрузки приложение может посылать POST-запросы на отдельную страницу (например, с помощью XHR) для проверки статуса.

Прогресс закачки будет доступен в суперглобальной переменной $_SESSION в процессе закачки, а также при отправке POST-запросом переменной с именем равным значению опции session.upload_progress.name. Как только PHP обнаружит такой POST-запрос, он создаст массив в $_SESSION, ключом которого будет конкатенация значений опций session.upload_progress.prefix и session.upload_progress.name. Ключ обычно можно получить прочитав эти опции, т.е.:

<?php
$key 
ini_get("session.upload_progress.prefix") . $_POST[ini_get("session.upload_progress.name")];
var_dump($_SESSION[$key]);
?>

Также возможно отменить загружаемый в данный момент файл, установив ключ $_SESSION[$key]["cancel_upload"] в значение TRUE. При загрузке нескольких файлов за один раз, это действие отменит только текущий загружаемый файл и все следующие за ним, но не удалит уже успешно загруженные к этому времени файлы. Если закачка была отменена этим способом, то элемент с ключом error в массиве $_FILES будет установлен в UPLOAD_ERR_EXTENSION.

Опции session.upload_progress.freq и session.upload_progress.min_freq контролируют частоту обновления информации о прогрессе загрузки. При разумных значениях этих двух настроек, накладные расходы данной функции практически неощутимы.

Пример #1 Пример

Пример структуры массива прогресса загрузки.

<form action="upload.php" method="POST" enctype="multipart/form-data">
 <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
 <input type="file" name="file1" />
 <input type="file" name="file2" />
 <input type="submit" />
</form>

Данные в сессии будут выглядеть примерно так:

<?php
$_SESSION
["upload_progress_123"] = array(
 
"start_time" => 1234567890,   // Время начала запроса
 
"content_length" => 57343257// Длина содержимого POST
 
"bytes_processed" => 453489,  // Количество полученных и обработанных байт
 
"done" => false,              // true при завершении обработки POST, успешно или нет
 
"files" => array(
  
=> array(
   
"field_name" => "file1",       // Имя поля <input/>
   // Следующие 3 элемента аналогичны соответствующим элементам массива $_FILES
   
"name" => "foo.avi",
   
"tmp_name" => "/tmp/phpxxxxxx",
   
"error" => 0,
   
"done" => true,                // True, если обработчик POST закончил обработку данного файла
   
"start_time" => 1234567890,    // Время начала обработки этого файла
   
"bytes_processed" => 57343250// Число полученных и обработанных байт этого файла
  
),
  
// И еще один файл, загрузка которого еще не закончена в том же запросе
  
=> array(
   
"field_name" => "file2",
   
"name" => "bar.avi",
   
"tmp_name" => NULL,
   
"error" => 0,
   
"done" => false,
   
"start_time" => 1234567899,
   
"bytes_processed" => 54554,
  ),
 )
);

Внимание

Для успешной работы данной функции необходимо отключить буферизацию запроса web-сервером. Иначе PHP увидит загрузку файла только когда загрузка полностью завершится. Серверы, такие как например Nginx, буферизуют большие запросы.

Коментарии

For PHP >= 5.2 there is http://pecl.php.net/package/uploadprogress
2012-03-02 10:35:23
http://php5.kiev.ua/manual/ru/session.upload-progress.html
Автор:
Note, this feature doesn't work, when your webserver is runnig PHP via FastCGI. There will be no progress informations in the session array.
Unfortunately PHP gets the data only after the upload is completed and can't show any progress.

I hope this informations helps.
2012-06-20 00:32:42
http://php5.kiev.ua/manual/ru/session.upload-progress.html
it should be noted that the hidden element come before the file element otherwise you wont get any updates.
2012-08-10 09:12:08
http://php5.kiev.ua/manual/ru/session.upload-progress.html
Автор:
If you're seeing
"PHP Warning:  Unknown: The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in Unknown on line 0",
then a misplaced input could be the cause. It's worth mentioning again that the hidden element MUST be before the file elements.
2012-09-03 08:11:16
http://php5.kiev.ua/manual/ru/session.upload-progress.html
Автор:
dont't forget, that the session has to be initialized before the form is generated, otherwise the mentioned example above won't work.
2013-05-02 11:01:37
http://php5.kiev.ua/manual/ru/session.upload-progress.html
Автор:
While the example in the documentation is accurate, the description is a bit off. To clarify:

PHP will populate an array in the $_SESSION, where the index is a concatenated value of the session.upload_progress.prefix and the VALUE of the POSTed session.upload_progress.name variable.
2013-06-12 18:34:47
http://php5.kiev.ua/manual/ru/session.upload-progress.html
Note that if you run that code and you print out the content of $_SESSSION[$key] you get an empty array due that session.upload_progress.cleanup is on by default and it  cleans the progress information as soon as all POST data has been read.

Set it to Off or 0 to see the content of $_SESSION[$key].
2013-09-29 21:47:02
http://php5.kiev.ua/manual/ru/session.upload-progress.html
If you have upload progress enabled in your php.ini, and you have 

<form enctype="multipart/form-data" ...
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" ...

in your form, but you DON'T specify an input with 'type="file"', you may lose your session ID. I am using PHP 5.5 and I lose my session ID on the second loading of such a page. To prevent this, you can use a dummy input as follows:

<form enctype="multipart/form-data" ... >
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" ... />
    <input type="file"' name="dummy" style="display="none;" ... />
2014-10-03 10:22:09
http://php5.kiev.ua/manual/ru/session.upload-progress.html
Автор:
It seems like if you send a form with the field like :

<?php echo '<input type="hidden" name="'.ini_get('session.upload_progress.name') .'" value="123" />'?>

without any field type "file", the server respons will be an 500 error.
2014-10-21 01:07:54
http://php5.kiev.ua/manual/ru/session.upload-progress.html
Автор:
ATTENTION:

Put the upload progress session name input field BEFORE your file field in the form :

  <form action="upload.php" method="POST" enctype="multipart/form-data">
  <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
  <input type="file" name="file1" />
  <input type="file" name="file2" />
  <input type="submit" />
  </form>

If you make it after your file field, you'll waste a lot of time figuring why (just like me ...)

The following form will make you crazy and waste really a lot of time:

<form action="upload.php" method="POST" enctype="multipart/form-data">
 <input type="file" name="file1" />
 <input type="file" name="file2" />
 <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
 <input type="submit" />
</form>

DON'T do this!
2015-04-04 10:18:46
http://php5.kiev.ua/manual/ru/session.upload-progress.html
session.upload_progress updates completely ignore custom session handlers set via  session_set_save_handler()
2015-04-28 21:36:27
http://php5.kiev.ua/manual/ru/session.upload-progress.html
There were two gotchas that got me with implementing this.

The first - if you use session_name() to change the name of sessions, this will not work. I discovered this by looking at phpinfo() and seeing that is saw a different session name.

At least in Apache, a better way to set the session is in your apache config use

php_value session.name "your custom name"

It goes within the Directory directive, might work in .htaccess - I don't know.

-=-

Secondly - in apache, don't use mod_mpm_prefork.so

That was the problem I had, that's the default in CentOS 7.

The problem is it causes Apache to wait with any additional requests until the upload is finished.

Commenting that module out and using mod_mpm_worker.so instead fixed that problem, and the progress meter worked.
2016-07-21 02:49:02
http://php5.kiev.ua/manual/ru/session.upload-progress.html

    Поддержать сайт на родительском проекте КГБ