When the
session.upload_progress.enabled
INI option is enabled, PHP will be able to track the upload progress of
individual files being uploaded.
This information isn't particularly useful for the actual upload request
itself, but during the file upload an application can send a POST request
to a separate endpoint (via XHR for example) to check the
status.
The upload progress will be available in the $_SESSION
superglobal when an upload is in progress, and when POSTing a variable of
the same name as the
session.upload_progress.name
INI setting is set to.
When PHP detects such POST requests, it will populate an array in the
$_SESSION, where the index is a concatenated value of the
session.upload_progress.prefix
and
session.upload_progress.name
INI options.
The key is typically retrieved by reading these INI settings, i.e.
It is also possible to cancel the currently in-progress file
upload, by setting the $_SESSION[$key]["cancel_upload"] key to
true.
When uploading multiple files in the same request, this will only cancel the
currently in-progress file upload, and pending file uploads, but will not
remove successfully completed uploads.
When an upload is cancelled like this, the error key in
$_FILES array will be set to
UPLOAD_ERR_EXTENSION.
The
session.upload_progress.freq
and
session.upload_progress.min_freq
INI options control how frequent the upload progress information should be
recalculated.
With a reasonable amount for these two settings, the overhead of this
feature is almost non-existent.
Example #1 Example information
Example of the structure of the progress upload array.
The data stored in the session will look like this:
$_SESSION["upload_progress_123"] = array( "start_time" => 1234567890, // The request time "content_length" => 57343257, // POST content length "bytes_processed" => 453489, // Amount of bytes received and processed "done" => false, // true when the POST handler has finished, successfully or not "files" => array( 0 => array( "field_name" => "file1", // Name of the field // The following 3 elements equals those in $_FILES "name" => "foo.avi", "tmp_name" => "/tmp/phpxxxxxx", "error" => 0, "done" => true, // True when the POST handler has finished handling this file "start_time" => 1234567890, // When this file has started to be processed "bytes_processed" => 57343250, // Number of bytes received and processed for this file ), // An other file, not finished uploading, in the same request 1 => array( "field_name" => "file2", "name" => "bar.avi", "tmp_name" => NULL, "error" => 0, "done" => false, "start_time" => 1234567899, "bytes_processed" => 54554, ), ) );
Warning
The web server's request buffering has to be disabled for this to work
properly, else PHP may see the file upload only once fully uploaded. Servers
such as Nginx are known to buffer larger requests.
Caution
The upload progress information is written to the session before any scripts
are executed. Therefore changing the session name via ini_set()
or session_name() will give a session without the upload
progress information.
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.
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.
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.
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].
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.