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

Замечание: Этот функционал доступен с PHP 5.4.0.

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,
  ),
 )
);

Внимание

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

Предостережение

Информация о прогрессе загрузки записывается в сессию до того, как будет запущен какой либо скрипт. Поэтому изменение имени сессии с помощью ini_set() или session_name() выдаст сессию без информации о прогрессе загрузки.