views:

929

answers:

6

You all know the new generation of fancy, mostly Flash-based file uploaders like SWFUpload that can show a progress bar while uploading - a great improvement especially for shaky and low-bandwidth connections.

However, these uploaders all bring their own logic of how to handle uploads on the client side. I am looking for an unobtrusive way to "fancify" existing, classical file uploads, i.e. introducing a progress bar to normal file upload forms.

Due to the architecture of uploading files, this is most likely not possible without some tweaking on the client side.

I am looking for a solution that keeps the tweaking to an absolute minimum, e.g. a component that adds itself to the onsubmit event of a normal form, performs the file upload, displays a nice progress bar, puts the resulting temporary (server side) file path into the form, and submits it. On the server side, I just have to modify my script to use the file path provided by the flash uploader, instead of $_FILES and consorts, and think about security for a moment.

This is not exactly what all the Flash-based uploaders do: They can use data from a form, but they do not provide possibilities to submit the form as is, what is what I'm looking for. I am looking for a (probably) Flash based upload function taken a step further.

+1  A: 

Does the technique used in Uploadify (a jQuery plugin) meet your needs? Demo

artlung
Uploadify is great, but as far as I can tell the technique used would not integrate well with sending a complete form with all sorts of data, at least not without tweaking.
Pekka
+3  A: 

jquploader uses the info inside the form, such as the action attribute value as upload script. But i haven't updated it in a while and it lacks all the belts and whistles scripts like uploadify have (which is an excellent script btw). See if it could be a base for you to tweak.

pixeline
This looks exactly right. I will take a look whether I can use this as a base.
Pekka
If I understand it correctly, it's not quite what I need: I would like the solution to integrate fully with a classical, POST based form submission process. That is a tricky thing to achieve, I'm starting a bounty to see whether anything comes up.
Pekka
+4  A: 

If you use PHP 5.2 and up this file upload progress tutorial by IBM can help you.

This multiple file upload tutorial uses jQuery + AJAX Upload... It uses $_FILES on the server side and will transform a special <div> on the client side to make a <form>. I guess you could tweak it to fit your needs.

If tweaking the last one is too tricky, Uber-Uploader on SourceForge is another option.

There are dozens of open source project covering this topic. Unfortunately this is not something trivial to implement seamlessly (at least in the way you want - otherwise we would have saw this in the good old Netscape days already).

On the bright side, HTML5 will ease this as you can see in this demo and this one.

I hope this helps and good luck with you integration.

AlexV
BTW for the HTML5 demos you need an up-to-date browser (not IE) to test them. FF3, Chrome or Safari 4 should be OK.
AlexV
+3  A: 

We implemented this very simple by installing the PECL extension pecl-uploadprogress and added a simple AJAX callback to the forms:

Generate an upload key:

$upload_id = genUploadKey();
function genUploadKey ($length = 11) {
  $charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  for ($i=0; $i < $length; $i++)
    $key .= $charset[(mt_rand(0,(strlen($charset)-1)))];
  return $key;
}

Create an AJAX callback handler (eg. uploadprogress.php):

extract($_REQUEST);

// servlet that handles uploadprogress requests:
if ($upload_id) {
  $data = uploadprogress_get_info($upload_id);
  if (!$data)
    $data['error'] = 'upload id not found';
  else {
    $avg_kb = $data['speed_average'] / 1024;
    if ($avg_kb<100)
      $avg_kb = round($avg_kb,1);
    else if ($avg_kb<10)
      $avg_kb = round($avg_kb,2);
    else $avg_kb = round($avg_kb);

    // two custom server calculations added to return data object:
    $data['kb_average'] = $avg_kb;
    $data['kb_uploaded'] = round($data['bytes_uploaded'] /1024);
  }

  echo json_encode($data);
  exit;
}

// display on completion of upload:
if ($UPLOAD_IDENTIFIER) {
...

Download jQuery and the jQuery.uploadprogress libraries (which also includes the above snippet) and integrate with your form:

<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery.uploadprogress.0.3.js"></script>
<script type="text/javascript">
jQuery(function () {
    // apply uploadProgress plugin to form element
    // with debug mode and array of data fields to publish to readout:
    jQuery('#upload_form').uploadProgress({
        progressURL:'uploadprogress.php',
        displayFields : ['kb_uploaded','kb_average','est_sec'],
        start: function() {
            $('.upload-progress').show();
        },
    success: function() {
            $('.upload-progress').hide();
            jQuery(this).get(0).reset();
        }
    });
});
</script>

Add this to your upload form:

<input name="UPLOAD_IDENTIFIER" type="hidden" value="$upload_id" />

That should do the trick. This is extracted from our code base and may not work out-of-the-box. But it should tell you the idea.

hurikhan77
This looks the most promising, I'm accepting this one. Cheers!
Pekka
Glad to help. If my answer is too terse I'd be happy to revise it.
hurikhan77
A: 

How funny, I just saw Simon Willison blog about Plupload, which is a JavaScript library that I think does file upload progress bars (amongst other things).

It uses Flash, Silverlight, or whatever’s available, but I think abstracts all that away from you, so you’re still uploading with a regular HTML form.

Paul D. Waite
A: 

You'll have to check the size of the part of the file wich is allready on the Server, then get it on the Client per Ajax where you can paint the progress bar. (Remember to check the size of the hole Data before, to calculate the percantage ;-) )

Tokk
How do you propose to do that? Checking the size of the part that is already on the server?
Pekka