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

if the file uploaded is too big post_max stops the upload and i'm able to output the error, but i have to use: exit; right after or the page just hangs and then eventually gives page cannot be displayed. Anyway... i want trap large uploads, output and error, but also maintain the form data the user entered. Here's the code: Sorry about the length, but i figured you'd want to see it all.
#!/usr/bin/perl use strict; use CGI; use Mail::Sendmail; use File::Basename; use MIME::Base64; use Time::Local; $CGI::POST_MAX = 1024 * 2000; # file upload max $CGI::DISABLE_UPLOADS = 0; # allow uploads #----------------------------------------------- #process printing services request form #----------------------------------------------- my $SERVER="http://".$ENV{'SERVER_NAME'}; my $form=$SERVER.$ENV{'SCRIPT_NAME'} || $SERVER.$ENV{'PATH_INFO'}; my $datapath=dirname $0; my $progname=basename $0; my $logo ='<img src="/images/logobw.gif" width=120 height=50 alt="" + border=0>'; my $listimg ='<img src="/images/list.gif" border=0 height=18 width= +18>'; my ($sec,$min,$hr,$day,$mon,$yr)=(localtime); my $date=sprintf("%04d-%02d-%02d %02d:%02d", $yr+1900, $mon+1, $day, $ +hr, $min); my $date_sub; my %in=(); my %str=(); my %check=(); my $typetext="text"; my $typetextarea="textarea"; my $closetextarea="<\/textarea>"; my $border=0; my $PREVIEWSTR; my $SENDSTR; my $FIXSTR; my $ATTACHSTR; my $ATTACHERR; my $submitstr; my $previewstr; my %mainbody; my $formid; my $formstr; my $date; my $error; my $debug=0; my $boundary = "====" . time() . "===="; #mail data delimiter my ($e, $ee, $f, $ff, $ef); my $MAILTO='bryson.connolly@ottawa.ca'; # printshop@ottawa.ca, Bonn +ie.Pritchard@ottawa.ca $MAILTO='bryson.connolly@ottawa.ca' if ($debug); my ($sec, $min, $hr, $day, $mon, $yr) = localtime(); my $today=sprintf("%04d%02d%02d %02d:%02d", $yr+1900, $mon+1, $day, $h +r, $min); #------------------ #read form input #------------------ my $query=new CGI; print "content-type: text/html\n\n"; if ($query->cgi_error()){ print $query->cgi_error(); print "<br>The file you're trying to upload is too large!"; exit; } my $action =$query->param('action'); my $lang =$query->param('lang'); my $id="print_bi"; my $tpl="$id.htm"; if ($lang ne "_fr") { $lang="_en"; $f="<!--"; $ff="-->"; $ef=$f; $PREVIEWSTR="Preview"; $SENDSTR="Submit to Printing Services"; $FIXSTR="Edit"; $ATTACHSTR="<font color=red>*</font> Document to be Printed <input type=file name=fileid size=6 +8 maxlength=120 class=button><br> Document to be Printed <input type=file name=ref1 size=68 maxl +ength=120 class=button> Document to be Printed <input type=file name=ref2 size=68 maxl +ength=120 class=button><br> Document to be Printed <input type=file name=ref3 size=68 maxl +ength=120 class=button>"; $ATTACHERR="Attachment is required"; } else { $e="<!--"; $ee="-->"; $ef=$ee; $PREVIEWSTR="Prévisualiser"; $SENDSTR="Soumettre au services d'imprimerie"; $FIXSTR="éditer"; $ATTACHSTR="<font color=red>*</font> Document Etre Imprim&eacute; <input type=file name=fileid +size=70 maxlength=120 class=button><br> Document Etre Imprim&eacute; <input type=file name=ref1 size=7 +0 maxlength=120 class=button><br> Document Etre Imprim&eacute; <input type=file name=ref2 size=7 +0 maxlength=120 class=button><br> Document Etre Imprim&eacute; <input type=file name=ref3 size=7 +0 maxlength=120 class=button>"; $ATTACHERR="Document est requis"; } $submitstr="<input type=submit name=action value=\"$SENDSTR\" > &nbsp; +"; $submitstr.="<input type=submit name=action value=\"$PREVIEWSTR\">"; #print "Content-type: text/html\n\n"; &getdata; if ( $action eq $PREVIEWSTR) { $typetext="hidden"; $typetextarea="input type=hidden"; $closetextarea=""; %str=%in; $listimg=""; $border=1; $date=$today; $submitstr= "<input type=submit name=action value=\"$SENDSTR\" > & +nbsp;"; $submitstr.="<input type=submit name=action value=\"$FIXSTR\">" ; } if ($action eq "$SENDSTR") { if ( $query->param("fileid") || $query->param("c_mailit") ) { $typetext="hidden"; $typetextarea="input type=hidden"; $closetextarea=""; %str=%in; $listimg=""; $border=1; $date=$today; $submitstr=""; $formid=&newformid; $formstr="Control #: <b><font size=5>$formid</font></b>"; $ATTACHSTR=""; &mailto; } $error="<font color=red><b>$ATTACHERR</b></font>"; } my $tmp=&readhtml("$datapath/$tpl"); $tmp=&addinc($tmp); print $tmp; exit; #return htmlfile from template sub readhtml { my $selectname; my $retfile; open (DATA, "@_") || print "@_ HTML file not found"; while (<DATA>) { #parse input data #input type must be specified #type specified right after <input #name must only contain "A-Za-z0-9_" s|<input type=text([^>]?name=)"?(\w+)"?(.*?>)|<input type=$typ +etext $1$2 value="$in{$2}" $3 <b><tt>$str{$2}</tt></b>|ig; s|<textarea([^>]?)name=(\w+)(.*?>)|<$typetextarea $1 name=$2 v +alue="$in{$2}"$3$in{$2}|ig; s|</textarea>|$closetextarea|ig; s|(<input type=radio)(.*)( name=)(\w+)( value=)(\w+)|$1$2$3$4$ +5$6 $check{$4.$6}|ig; s|(<input type=checkbox)(.*)( name=)(\w+)|$1$2$3$4 $check{$4}| +ig; s/(\$[\w{}]+)/$1/eeg; #now to do the selects if ( /<select name="?(\w+)"?/ig ) {$selectname=$1} s|(<option value="?)([\w\-\@\,\;\.]+)("?)(.*)| my $tmp; if ($check{$selectname.$2} ) { $tmp="$1$2$3 $check{$selectname.$2}$4"; } if ($typetext eq "text") { $tmp="$1$2$3 $check{$selectname.$2}$4"; } $tmp; |seig; s|<option>(.*)</option>| package temp; my $tmp; if (($check{$selectname.$1}) or ($typetext eq "text")) {$tmp="<option $check{$selectname.$1}>$1</option> " . $che +ck{$selectname.$1} . $typetext . "text"} $tmp; |sgeix; $retfile.=$_; } close (DATA); return $retfile; } sub addinc { #------------------------------ #add include file just like ssi #------------------------------ ($_)=@_; my $BASEDIR=$ENV{'DOCUMENT_ROOT'} || dirname (dirname ($datapath)) +; undef $/; #slurp whole file ignoring cr/lf s|<!--\#include\s*virtual="([\w\/\.]+)"--> | package temp; my $tmp; my $file = $1; if (!open(IN,$BASEDIR . "/$file")) { $tmp = "[ INCLUDE ERROR: Cannot include $BASEDIR $file fil +e ]"; } else { $tmp = <IN>; close(IN); $tmp; } |sgeix; $/="\n"; return $_ } sub getdata { #-------------- #load form data #-------------- foreach ($query->param) { $in{$_} = $query->param($_); if ($_=~/^c_/) { $check{$_}="CHECKED" } #checkbox if ($_=~/^r_/) { $check{$_.$in{$_}}="CHECKED" } #radi +o if ($_=~/^s_/) { $check{$_.$in{$_}}="SELECTED" } #Sel +ect $in{$_}=~s/"/&quot;/g; $in{$_}=~s/'/&rsquo;/g; $in{$_}=~s/\r\n/<br>/g || $in{$_}=~s/<br>/\r\n/g; } $debug++ if ($in{requestor} =~/debug/i); } sub mailto { #---------- #send email #---------- $date_sub = "date submitted: ".localtime(); $logo=""; $listimg=""; my $FROM="Forms\@ottawa.ca"; my $SUBJECT= $in{reqdate} . " " . $in{docwords} . " " . $in{doctitle +}; my $to=$MAILTO; my $cc=$in{email}; my $body=&readhtml("$datapath/$tpl"); $body=&doclean($body); $body.=&attachfile ("fileid"); #the attachments $body.=&attachfile ("ref1", "ref1_"); $body.=&attachfile ("ref2", "ref2_"); $body.=&attachfile ("ref3", "ref3_"); $body.="--$boundary--"; my %mail=(SMTP => 'appsmtp.ottawa.ca', To => $to, cc => $cc, From => $FROM, subject => $SUBJECT, 'content-type'=> "multipart/mixed; boundary=\"$boundary\"", body => "--$boundary\nContent-Type: text/html\n\n $body" + ); if (!sendmail(%mail) ) { print "$Mail::Sendmail::error;"; exit } print "This request was mailed to $to $cc <p>" if ($debug); $tpl="confirm$lang.htm"; return } sub newformid { #----------------------------------- #get next id number and increment it #----------------------------------- use File::CounterFile; $File::CounterFile::DEFAULT_DIR="$datapath"; my $c = File::CounterFile->new("counter.dat"); $c->inc; $c=sprintf("%06d", $c); $c = "e".$c; return $c; } sub doclean { #------------------------------------------------- #remove the hidden fields and submit/reset buttons #------------------------------------------------- ($_)=@_; undef $/; s|<input (type=hidden.*?)>|<skip $1>|imsg; s|<input type="+submit.*?>||imsg; s|<input type="+reset.*?>||imsg; $/="\n"; return $_; } sub attachfile { #---------------------------------------------------- #create attachment to a mail message of uploaded file #---------------------------------------------------- #$CGI::POST_MAX = 1024 * 5000; # 5MB file upload max #$CGI::DISABLE_UPLOADS = 0; # allow uploads # my ($uploadfile,$prename)=@_; my $tmp; my $ATTACHDIR="$datapath/working"; my $filehandle = $query->upload("$uploadfile"); my $fileid = $query->param("$uploadfile"); return if (!$filehandle) ; my @file = <$filehandle>; close ($filehandle); my $fid=$prename . basename($filehandle); open (OUTFILE,">$ATTACHDIR/$fid") || print "failed to open $ATTACH +DIR / $fid xx"; binmode OUTFILE; print OUTFILE @file; close OUTFILE; open(F, "$ATTACHDIR/$fid") or die("Cannot read $fid: $!"); undef $/; binmode F; $tmp = encode_base64(<F>); close F; $/="\n"; #if ($query->cgi_error()){ #my $error = $query->cgi_error(); #"The file you are uploading is too large! Files are limited to $C +GI::POST_MAX KB".$error; print "<b>...File $fileid uploaded</b><br>" if ($debug); return <<END_OF_BODY; --$boundary Content-Type: application/octet-stream; name="$fid" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="$fid" $tmp END_OF_BODY }

Edited by planetscape - added readmore tags

( keep:1 edit:23 reap:0 )

Replies are listed 'Best First'.
Re: $CGI::POST_MAX issue
by ikegami (Patriarch) on Nov 02, 2006 at 21:17 UTC

    param calls won't return return anything if POST_MAX is reached. I don't know if that's what's causing the problem, but it'll surely hamper your efforts to repopulate the form.

    The file upload is not sent to the web server any differently than other inputs (text fields, radio buttons, etc). If the POST body is bigger than POST_MAX, then it is not processed, discarding all inputs indiscriminately.

    Update: A workaround would be to input the generic data on one page, the upload the files from another page.

      thanks, maybe i'll put it in an iframe