Creating an Upload function with a progress meter
Uploading custom files to the database is an integral part of Open-LIMS. However, due to technical restrictions, for a long time it was not possible to display any information regarding the progress of an upload. This can be very annoying for the user, especially if he wants to upload a lot of files at the same time: He is doomed to wait for all files to arrive on the server without knowing when this will happen or how many files have already been transferred. The reason is simple: PHP is not capable of tracking uploads. It just copies the files from the POST-header and returns a status message when it’s done, so there is no way of knowing how much of a file has been copied until the upload is finished.
Now you might say “but hey, I could just check the size of the partly-copied file on the server”. Yes, you can, but it’s a hard job. PHP stores the file in a temporary folder (which you cannot access from within PHP itself) with a random temporary filename (which makes it difficult to find the current file), so the only solution for this is an external Java or Perl script.
Fortunately, some smart people came up with an easier solution: A small PHP extension called uploadprogress (http://pecl.php.net/package/uploadprogress). All you have to do is to add a hidden input field with a unique ID at the very beginning of your upload form, so the extension can keep track of it:
<input type='hidden' id='UPLOAD_IDENTIFIER' name='UPLOAD_IDENTIFIER' value='[[UNIQUE_ID]]'/>
As soon as the form is submitted, the extension can then access the POST variable via the ID and give information about the upload progress of all the files in the form. A call to uploadprogress_get_info() will return an associative array containing information on how many files have already been uploaded, how many bytes of the POST header have been processed already and the total size of the POST header (which you can derive the overall percentage from), the current upload speed and even an estimation of how long the upload is still going to take:
$status = uploadprogress_get_info($_GET["unique_id"]); $total_uploads = $status['files_uploaded']; $percent = round($status['bytes_uploaded']/$status['bytes_total']*100); $time_left = $status["est_sec"]; $speed = number_format(($status["speed_average"] / 1024), 1, ",", ".");
This works very smoothly, but bears three problems. The most important one is that the status array does not contain any information about errors. If a file exists already, if it is too large or any other error occurs, the upload will simply be treated as complete. Further, the PHP extension might not be installed on the server system, so a fallback method is needed. And lastly, small files might get uploaded so rapidly that the upload is not recognized as started (and hence is not recognized as complete either).
There is one solution for all those problems: Writing a second function that does not check the progress, but returns an array of the status messages of the native PHP upload function. After repeatedly calling the uploadprogress-function until all uploads are marked as complete, we call the second function, and the returned array will contain information about errors, which can then be displayed.
If the extension is not installed, we just use this function to feed the progress bar. In this case, the percentage does display the already uploaded bytes correlating with the number of total bytes, but the number of completed downloads correlating with the number of total uploads. As files can differ in size significantly, this gives no accurate information on how long the upload process is going to take, but still provides some useful visual feedback to the user.
In the case of uploading so fast that the extension does not recognize an upload as finished, a simple timeout does the trick. If the timeout is reached, the script falls back to the second function mentioned above, which then detects all complete uploads.
By R. Quiring.