Ganlron has asked for the wisdom of the Perl Monks concerning the following question:

2 Questions:

1) With CGI::Simple, is there a way to get a hook into the spooling process for File Uploads so that you can setup some sort of metering to determine how the upload is progressing? If not, I guess I could go back to just using CGI.pm and use a non-anonymous tmpFileName.

2) Is it possible to get the total size of the file being uploaded before the spooling process begins?

Thanks humbly in advance :)

Replies are listed 'Best First'.
Re: Upload Progress
by matija (Priest) on Apr 26, 2004 at 23:10 UTC
    I don't know if CGI::Simple offers it, but CGI has a method called upload_hook, which can be used for that purpose:
    $q = CGI->new(); $q->upload_hook(\&hook,$data); sub hook { my ($filename, $buffer, $bytes_read, $data) = @_; print "Read $bytes_read bytes of $filename\n"; }
    The size of the uploaded file may (or may not) be passed in the headers - call uploadInfo() to find out.
        But this can't be used to build a progress bar...

        Not within the same request, as was mentioned in the thread you linked to, but you can use it to build a pop-up based progress bar. See Apache::UploadMeter for a mod_perl implementation of a progress bar (it uses the upload hook in Apache::Request to do it).

        - Cees

Re: Upload Progress
by Errto (Vicar) on Apr 27, 2004 at 01:05 UTC
    Don't know how to do this in Perl CGI, but the general idea that I've seen implemented is this:
    1. When loading the form, generate some unique sequence number and include it in a hidden field of some sort
    2. When pressing Submit, have it call a client-side Javascript function that, before submitting the form, pops up another little window, pointing to a different CGI script and using this unique number as one of the parameters
    3. The upload script then begins processing, regularly storing its progress in some sort of session variable tied to the unique number
    4. The CGI feeding the popup checks the status and generates HTML simulating a progress bar, with an appropriate refresh interval
    5. Once the file is done, the CGI feeding the popup will detect this and in its HTML output include a line like <script>window.close()</script> or some such.
    It's kind of crude, and it definitely relies on client-side Javascript, but it works. Other posts in this thread have suggested how to track the progress of an upload on the server side (needed for step 3).

    Update: This solution will probably require mod_perl or something else that allows two scripts to share server-side information

Re: Upload Progress
by Anonymous Monk on Apr 27, 2004 at 05:21 UTC

    Most people don't seem to think of using -s on the filehandle provided by CGI::Simple (or CGI). The following script works just fine (ugly example, but it works). You will notice one problem with this however: it works for the reading, but the entire file has to be uploaded before processing can begin. As far as I know, this problem exists in every single upload and cannot be avoided. The code in the script won't even start executing until the client has passed the entire file upload contents.

    #!c:/perl/bin/perl -w $| = 1; use strict; use CGI::Simple qw(-upload); my $q = CGI::Simple->new(); if ( defined($q->param('fh_upload')) ) { my $fh = $q->upload( $q->param('fh_upload') ); my $size = -s($fh); print $q->header(), <<'END_HTML'; <html> <head> <title>Upload Example</title> </head> <body> END_HTML my ($uploaded, $buffer); while ( my $bytes = read($fh, $buffer, 1024) ) { $uploaded += $bytes; print int($uploaded / $size * 100), "%<br />\n"; select( undef, undef, undef, 0.02); } print "</body></html>"; } else { print $q->header(); print <<"END_HTML"; <html> <head> <title>Upload Example</title> </head> <body> <form action="${\($ENV{'REQUEST_URI'})}" method="post" enctype +="multipart/form-data"> File to Upload: <input type="file" name="fh_upload" size=" +30" /> <input type="submit" value="upload file" /> </form> </body> </html> END_HTML }
Re: Upload Progress
by zentara (Cardinal) on Apr 27, 2004 at 12:07 UTC
    I don't recommend it, but I did get something working, based on the Mega-Uploader php uploader script. I hacked it to run with Perl on linux, and I just helped a fellow in Germany get it to run on WindowsXP.

    It uses javascript to create a popup, then it spawns 2 cgi programs, one to upload, and one to monitor the -s of the upload and send information back to the javascript popup.

    You can test it here . Files are available there too.

    I also have a simpler javascript upload indicator there for your use. It gives a simple animation until the upload completes.


    I'm not really a human, but I play one on earth. flash japh
      This is/was similar to what I was thinking of doing. Basically spawning a second script in a new window that would monitor the size progress of the temporary spooling file. I just wish I could determine what the even rough size of the file to be uploaded is, prior to it being spooled. :(

      Thanks for the suggestions though :)
        I just wish I could determine what the even rough size of the file to be uploaded is, prior to it being spooled

        Just look for the Content-Length header in the incoming request headers.

        - Cees