PHP 5.4 File Upload Progress and HTML5 Progress Bars

Developers who work with PHP applications that upload files commonly struggle with providing user feedback on the upload progress, usually using flash and javascript solutions like uploadify. In PHP 5.4 there is now integrated functionality to allow file upload progress to be passed back to the browser.

In this post I’ll describe the basic operation of this feature and describe a quick example of its use.

PHP 5.4 File Upload Progress Demo

How it Works

The upload progress functionality stores the current progress in a session variable which can then be queried as required to give the current progress, it requires the use of PHP native sessions. The $_SESSION key is set by the form name and a prefix defined in php.ini

An example of the data stored is shown below:

<?php $_SESSION["upload_progress_123"] = array(  "start_time" = 1234567890,
 "content_length" => 57343257,
 "bytes_processed" => 453489,
 "done" => false,
 "files" => array(
  0 => array(
   "field_name" => "file1",
   // The following 3 elements equals those in $_FILES
   "name" => "foo.avi",
   "tmp_name" => "/tmp/phpxxxxxx",
   "error" => 0,
   "done" => true,
   "start_time" => 1234567890,
   "bytes_processed" => 57343250,
  ),
  // 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,
  ),
 )
);

It is up to the developer how they wish to present this data to the user.

Setup

This functionality is included as standard in PHP 5.4 which can be simply installed from an ubuntu package as discussed in my previous post: http://chemicaloliver.net/internet/installing-php-5-4-in-ubuntu/

This feature should be enabled by default.

Example

Complete code can be found on github.

Upload Form

The upload form is standard html file upload form apart from an additional hidden value defining the progress name attribute so the upload can be identified in the session variables later:

<form id="upload" action="/progress/upload.php" method="POST" enctype="multipart/form-data">
 <input type="hidden" name="" value="upload" />

 <input id="file1" type="file" name="file1" />
 <input id="file2" type="file" name="file2" />

 <input class="btn primary" type="submit" value="Upload" /></form>

In my example I’ve used the jquery form plugin to make submitting the form using AJAX more simple.

Recieving Script

In this example the receiving script needs to do nothing except start a session, I added a var_dump for debugging initially:

<?php session_start(); var_dump($_SESSION); var_dump($_FILES); ??

Monitoring Progress

This is performed through a combination of javascript and PHP, the client polls a server page which echos the current progress as JSON:

Client:

The client uses an interval time to get the progress every 200ms and pass it to an HTML5 progress bar.

interval_id = setInterval(function() {
$.getJSON('/progress/progress.php', function(data){
    //if there is some progress then update
    if(data)
    {
        $('#progress').val(data.bytes_processed / data.content_length);
        $('#progress-txt').html('Uploading '+ Math.round((data.bytes_processed / data.content_length)*100) + '%');
    }

    //When there is no data the upload is complete
    else
    {
        $('#progress').val('1');
        $('#progress-txt').html('Complete');
        stopProgress();
    }
})
}, 200);

Server Side:

The server side just echos a json encoded version of the session variable:

<?php
session_start();
echo json_encode( $_SESSION['upload_progress_upload']);
?>

PHP 5.4 File Upload Progress and HTML5 Progress Bars

  1. Phil Sturgeon says:

    Very useful! I’ve bookmarked this for future use as every single time I’ve done this in the past I’ve needed to use some crazy fuck combination of Flash, Perl and goat sacrifice.

    Thank you :)

    • chemicaloliver says:

      Thanks, it’s not perfect but of the only constraint is using native sessions it sounds a whole lot better than all the usual methods, using Flash solutions with Codeigniter has caused me lots of headaches.

      In my job I build apps for print order management which always involves uploading large files so it’s an issue close to my heart!

  2. Peter says:

    Thanks for a great and very useful tutorial. This particular problem has caused me lots of headaces too. The only okay solution i’ve found besides this with APC, but then there are some compability issues(does not work with Suhosin installed for example).
    I will bookmark this for use in coming projects.
    Thank you again!

    • chemicaloliver says:

      That is possible if you set up a websocket server to poll the PHP session variable and feed it down a websocket, but that’s a lot of trouble unless you already have the web socket server in place in your app.

Leave a Reply