Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

simple CGI::upload_hook() guide or example?

by thoughts (Initiate)
on Oct 12, 2005 at 16:11 UTC ( [id://499572]=perlquestion: print w/replies, xml ) Need Help??

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

I'm trying to use CGI::upload_hook() to implement a progress meter for file uploads. Using the code from CGI.pm's documentation doesn't work at all:

$q = CGI->new(); $q->upload_hook(\&hook); sub hook { my ($filename, $buffer, $bytes_read) = @_; print STDERR "Read $bytes_read bytes of $filename\n"; }

That's straight from the docs, except that I changed it to print to STDERR, and I removed "$data", which the docs randomly pass into upload_hook() but don't explain at all. The problem is that it doesn't do anything; nothing ever gets printed to STDERR, though the file gets completely uploaded.

I've been searching on Google for a couple hours and have found not a single working example of this feature of CGI.pm. The one that comes close is this other perlmonks thread Understanding CGI::upload_hook() ;. In it, the author asks basically my same question, and gets a reply from someone with a "working" example; however the example code doesn't run on either of the two servers I tried it on (both Linux/Apache without mod_perl), though it works on its author's homepage. But the example code isn't particularly simple, and all I'm interested in is the upload_hook portion; I don't want to try to debug the example package.

The example package calls the hook differently than the CGI.pm docs suggest:

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

When I try that in my code, I have only slightly more success: the hook does get called, but not until the file is almost completely finished uploading. It's a 2MB photo that takes about 60 seconds to upload on my connection, but the hook only get called during the last ~5 seconds -- during those 5 seconds, it gets called a few hundred times, starting with a $bytes_read value of zero, as if the entire upload didn't happen until those final 5 seconds. (I am monitoring the outgoing traffic on my workstation, so I know that isn't the case.)

What I'm looking for is a simple CGI script or function that shows upload_hook being used successfully. By simple, I mean not a module, not a full-blown package with XML config files and a database-backed caching system, etc. Just a few lines of code would be great.

I can post my full non-working example in a reply if that is helpful.

Replies are listed 'Best First'.
Re: simple CGI::upload_hook() guide or example?
by cees (Curate) on Oct 12, 2005 at 17:52 UTC

    OK, here is a completely stripped down version that just writes some data to a log file. This works fine on my machine

    #!/usr/bin/perl use strict; use warnings; use File::Slurp; use CGI qw(:standard); my $query = CGI->new(\&_hook, 'ID'); # Grab the uploaded file my $file = $query->param('uploaded_file'); print header, start_html(-title => 'A Simple Upload Meter Example'), h +1('Upload Complete'), end_html; # This is the upload_hook that gets called repeatedly by CGI.pm # during an upload. It gets called once for every 4K of data read in # by CGI.pm sub _hook { my ($filename, $buffer, $bytes_read, $umid) = @_; write_file( '/tmp/filename', {append => 1 }, "Uploading $filename +($umid) - $bytes_read\n" ) ; sleep 1; }

    And here is a simple HTML page that you can use to call it:

    <html> <body> <form method="post" action="example.cgi" enctype="multipart/fo +rm-data"> upload file: <input type="file" name="uploaded_file" /><br />< +input type="submit" tabindex="2" name=".submit" /> </body> </html>

    My gut instinct tells me that your test DID work, but your logfile was just buffering the output. To guarantee that it doesn't happen with this example, I am doing something very inefficient by opening and closing the log file on every call to the hook.

    Also, I should note that the CGI.pm docs are not very clear in how to use the upload hook. CGI.pm needs to know about the hook when it is first used, so you have to call CGI::upload_hook(\&hook,$data); before you do anything else. And if you use the OO interface like I do, you must pass the hook in at creation time.

      My gut instinct tells me that your test DID work, but your logfile was just buffering the output.

      This does appear to be the case. Even though I tried both of these in my hook:

      select(STDERR); $|=1; print STDERR "$byte_size\n";
      select((select(STDERR), $| = 1)[0]); print STDERR "$byte_size\n";

      ...STDERR refused to be unbuffered. Switching to a custom (plain old) logfile allowed it to work.

      To guarantee that it doesn't happen with this example, I am doing something very inefficient by opening and closing the log file on every call to the hook.

      But since the purpose of this is for some secondary process to be reading the log at the same time as it's being written, you'd at least have to release the filelock after every hook call, right?

      And if you use the OO interface like I do, you must pass the hook in at creation time.

      Good to know; I can't imagine how one is supposed to determine that (how did you?), given that the docs certainly don't say anything about it.

      Thanks for your help.

        ...STDERR refused to be unbuffered

        Well, you might be unbuffering your perl code, but Apache could still be buffering the output before it writes it to the error log...

        I can't imagine how one is supposed to determine that (how did you?), given that the docs certainly don't say anything about it.

        If I can't get something to work according to the docs, then I assume the docs are lying and check the source. Mind you the source of CGI.pm is not for the faint of heart ;). I meant to send in a doc patch to clarify this stuff, but never got around to it. If you can find the time, I am sure Lincoln would appreciate it.

        The upload hook seems to be one of those cool things that no one really uses. I guess that is why there is such a lack of info on the subject...

Re: simple CGI::upload_hook() guide or example?
by cees (Curate) on Oct 12, 2005 at 17:28 UTC

    It is hard to help with a coding problem without seeing the code. Also, you don't mention what types of errors you are getting with the example package you tried (that was my example app, so I might be able to help you out with it).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://499572]
Approved by Fang
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (2)
As of 2024-04-20 03:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found