Selling cookie info to third-parties is a classic example of you can make money without doing evil.
RSS

CGI's UPLOAD_HOOK

2008/02/02 filed under /perl

Many a time, I see people asking and messing with CGI uploads and progress bars.

First of all, I believe an upload progress bar is the responsibility of the browser (client) and not of the server. The client knows the file size it is uploading and how many bytes it sent over the wire. Regardless, progress bars are fairly nice, especially with large(r) files. So let's see how we can implement one.

Perl is very well suited to show you the upload progress (I believe it's more tricky with PHP), due to the UPLOAD_HOOK facility of CGI

The documentation isn't too extensive, so let's just look at an example. First of all, you'd need to understand what needs to be done. After someone hits the upload button, we need to query the server over and over, to get the upload status. Javascript kicks in here.

To display the bar, I simply use an existing script, for a) it looks better than anything I'd ever create and b) it works :)

Bram.us 's jsProgressBarHandler is the one I chose for this example.

Ok, so now first take a look at the hook subroutine. First you'd have to create an instance of the CGI object like this:

my $q = CGI->new(\&hook);

The hook subroutine isn't too fancy either. I use File::Slurp to write the percentage to a file that we can query later.

sub hook {
   my ($filename, $buffer, $bytes_read, $data) = @_;
   my $perc = sprint("%i", (($bytes_read / $ENV{CONTENT_LENGTH}) * 100));
   write_file("/tmp/$ENV{REMOTE_ADDR}", {overwrite => 1}, "$perc");
}

That's all it takes.

Now, on the frontend, we simple query this file over and over, like this:

   function doUpload() {
      $('progress').show();
      var intervalID = window.setInterval('doProgress()', 1000);
   }

   function doProgress() {
      var d = new Date;
      new Ajax.Request('progress.cgi?time='+d.getMinutes()+
                       '_'+d.getSeconds(), {
         method:'get',
         onSuccess: function(transport){
            myJsProgressBarHandler.setPercentage('progress', 
                                                 transport.responseText);
         }
      });
   }

The function doUpload shows the progress bar and calls doProgress every second. Since Internet Explorer seems to think that caching the Ajax.Request is a smart thing to do, I simply post the minutes and seconds to the script aswell.

And progress.cgi isn't so fancy either:

#!/usr/bin/perl

use strict;
use File::Slurp;

print "Content-type: text/plain\n\n";
my $perc = read_file("/tmp/$ENV{REMOTE_ADDR}");
print $perc;

This works rather well on my machine(s) and it's really simple, as you can see. The only downside is that when two people sharing the same IP address start uploading at the same time, they'll probably get the wrong information. But hey, who cares? ;-)

Posted by: B10m | permanent link | comments (4)
return-member