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

Guys,

I have requirement where user need to select Circle and Technology on HTML page and then should click Upload button.Once user will click Upload button,Upload CGI will be called where user will get option to upload the file on server. Now whatever the file user uploads that has to be renamed after combining Circle and Technology value received from HTML page.I am struggling to fetch Circle and Technology value in Upload script. Pls really need your suggestion here.

HTML Code

<!DOCTYPE html> <html> <head> <title>MAINTENANCE PAGE</title> </head> <body> <form name = f1 action="https://10.XXX.XXX.X:16311/ibm/console/webtop/ +cgi-bin/download_csv.cgi" method = "POST"> <p style="margin-left:10em;font-size:40px">MAINTENANCE PAGE</p> <br> <p style="margin-left:16.5em;font-size:20px">Circle:<select name="Circ +le" > <option value="Gabon">Gabon</option> <option value="Tanzania">Tanzania</option> </select> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs +p;&nbsp;&nbsp; Technology : <select name="Techno" > <option value="Core">Core</option> <option value="RAN">RAN</option> </select> </p> <br> <input type="submit" style="margin-left:30.5em" value="Download" onc +lick="this.form.target='_blank';return true;"> &nbsp;&nbsp;&nbsp; <input type="submit" value="Upload" onclick="f1.action='https://10.XXX +.XXX.X:16311/ibm/console/webtop/cgi-bin/Maintenance_Framework.cgi'; +return true;"> </form> </body> </html>

UPLOAD CGI SCRIPT

#!/usr/bin/perl use CGI qw(:standard); use CGI::Carp qw( fatalsToBrowser ); use File::Basename; use Exporter qw(import); our @EXPORT = qw(copyToTarget); $newfilename=''; sub xyz() { local ($buffer, @pairs, $pair, $name, $value, %FORM); $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } $Circle = $FORM{Circle}; $Techno = $FORM{Techno}; $newfilename = $Circle.'abc'.$Techno.'.csv'; print ("Content-type: text/html\n\n"); print <<_ABC_; <p>$newfilename</p> _ABC_ } sub print_page() { # xyz(); print ("Content-type: text/html\n\n"); print <<__HTML__; <form name=f1 style="margin:20px 0" action="Maintenance_Framew +ork.cgi" method="post" enctype="multipart/form-data"> <p> <h3 align='center'> Maintenance File Upload </h3> <br> <p>File to Upload: <input type="file" name="filecsv" /></p> <p><input type="submit" name="Submit" value="Upload"></p>&nbsp +&nbsp&nbsp </body> </html> </form> __HTML__ } sub main() { #xyz(); $CGI::POST_MAX = 1024 * 5000; my $safe_filename_characters = "a-zA-Z0-9_.-"; my $upload_dir = "/opt/IBM/Maintenance/tmp"; my $query = new CGI; print_page(); my $filename = $query->param("filecsv"); if ( !$filename ) { exit; } my ( $name, $path, $extension ) = fileparse ( $filename, '.csv +' ); $filename = $name . $extension; $filename =~ tr/ /_/; $filename =~ s/[^$safe_filename_characters]//g; if ( $filename =~ /^([$safe_filename_characters]+)$/ ) { $filename = $1; } else { die "Filename contains invalid characters"; } my $upload_filehandle = $query->upload("filecsv"); open ( UPLOADFILE, ">$upload_dir/$filename" ) or die "$!"; binmode UPLOADFILE; while ( <$upload_filehandle> ) { print UPLOADFILE; } close UPLOADFILE; print <<END_HTML; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/ +xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang= +"en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=ut +f-8" /> <title>Thanks!</title> <style type="text/css"> img {border: none;} </style> </head> <body> <p>Thanks for uploading your file!</p> </body> </html> END_HTML } main();

Replies are listed 'Best First'.
Re: Need to use data passed from FORM from HTML page to CGI upload script.
by poj (Abbot) on Jul 26, 2019 at 12:04 UTC

    Why not select the file on the html page ?

    <!DOCTYPE html> <html> <head> <title>MAINTENANCE PAGE</title> </head> <body> <form action="Maintenance_Framework.cgi" method = "post" enctype="mult +ipart/form-data"> <p>MAINTENANCE PAGE<br/> Circle: <select name="Circle" > <option value="Gabon">Gabon</option> <option value="Tanzania">Tanzania</option> </select> Technology : <select name="Techno" > <option value="Core">Core</option> <option value="RAN">RAN</option> </select> </p> <br> File to Upload: <input type="file" name="filecsv"/> <input type="submit" value="Upload"/> </form> </body> </html>
    #!/usr/lib/perl # Maintenance_Framework.cgi use strict; use warnings; use CGI; use CGI::Carp 'fatalsToBrowser'; # debug only $CGI::POST_MAX = 1024 * 5000; my $upload_dir = '/opt/IBM/Maintenance/tmp'; my $q = new CGI; my $Circle = $q->param('Circle'); my $Techno = $q->param('Techno'); my $newfilename = $Circle.'abc'.$Techno.'.csv'; my $upload_filehandle = $q->upload("filecsv"); open OUT, '>',"$upload_dir/$newfilename" or die "$!"; binmode OUT; while ( <$upload_filehandle> ) { print OUT; } close OUT; print $q->header; print << "HTM"; <html> <head><title>Maintenance Page</title></head> <body> <p>Thanks for uploading your file as $newfilename</p> </body></html> HTM
    poj
      Thanks for the comment. What you suggested is absolutely correct but not as per the requirement. I need to provide another button "Download" on the HTML page wherein if user click this button , Circle_Techno.csv should get download(Basically I am calling another download cgi script here for its execution). My bad .. I forgot to write about it in the original post.

        You can combine upload and download into one script by using an action parameter on the buttons. For example

        <!DOCTYPE html> <html> <head> <title>MAINTENANCE PAGE</title> </head> <body> <form action="Maintenance_Framework.cgi" method = "post" enctype="mult +ipart/form-data"> <h3>MAINTENANCE PAGE</h3> <p> Circle: <select name="Circle" > <option value="Gabon">Gabon</option> <option value="Tanzania">Tanzania</option> </select> Technology : <select name="Techno" > <option value="Core">Core</option> <option value="RAN">RAN</option> </select> <input type="submit" name="action" value="Download"/></p> File to Upload: <input type="file" name="filecsv"/> <input type="submit" name="action" value="Upload"/> </form> </body> </html>

        Add security features as appropriate to your use case.

        poj
Re: Need to use data passed from FORM from HTML page to CGI upload script.
by hippo (Archbishop) on Jul 26, 2019 at 10:18 UTC
    I am struggling to fetch Circle and Technology value in Upload script.

    One blocker at least is that print_page() doesn't refer to either of those params in any way, so it's no wonder that you can't retrieve them in the subsequent handler.

    I'm glad to see that nothing calls xyz() because that looks really horrible.

    Best of luck with this. I recommend a good read of the Basic Debugging Checklist which will stand you in good stead.

      Thanks for the update. But when I am using xyz() in the print_page(),upload function fails even if I retrieve the parameters. Code I pasted is generic one which doesn't include all the permutation & combination what I tried. If you have any suggestion where to use xyz() and still upload option works,I am open to try that. Thanks.

        Is your question really just "How can a handler with CGI.pm retrieve both file and non-file params in one run"? Because that's an easy one to demonstrate and means we can ignore the rest of what you have there.

Re: Need to use data passed from FORM from HTML page to CGI upload script. (cgi101)
by Anonymous Monk on Jul 27, 2019 at 04:50 UTC

    Hi

    Remember Re: Need to print file contents on page (cgi101)?

    Why all the "()" in "sub name() {..." ?

    I fix for you

    #!/usr/bin/perl -- ## ## ## ## perltidy -olq -csc -csci=10 -cscl="sub : BEGIN END if while for " +-otr -opr -ce -nibc -i=4 -pt=0 "-nsak=*" ## #!/usr/bin/perl -- use CGI::Carp qw( fatalsToBrowser ); use strict; use warnings; use CGI (); main( @ARGV ); exit( 0 ); sub main { # return DebugCGI(); $CGI::POST_MAX = 1024 * 5000; my $upload_dir = 'goner'; my $query = CGI->new; my( $headers, $body ) = SaveUploadsTo( $query, $upload_dir ); print $headers, $body; } ## end sub main sub SaveUploadsTo { my( $query, $upload_dir ) = @_; return $query->header, PrintPage( $query ) if not $query->first_param( "filecsv" ); my $filename = WashFilename( $query->first_param( "filecsv" ) ); ## imaginary alternative # my( $filename, $error ) = WashFilename( $query->first_param( "fil +ecsv" ) ); # $error and return $query->header, ErrorPage( $query, $error ); my $tmpfilename = $query->tmpFileName( $query->first_param( "filec +sv" ) ); $tmpfilename or return $query->header, ErrorPage( $query, "No file uploaded" +); $filename = "$upload_dir/$filename"; require File::Copy; File::Copy::copy( $tmpfilename, $filename ) or die "Copy to ( $filename ) failed: (( $! ))(( $^E ))"; return $query->header, ThanksPage( $query ); } ## end sub SaveUploadsTo sub ErrorPage { my( $query, $message ) = @_; return qq{<!DOCTYPE html> <html lang="en"> <title> Error </title> <h1> $message </h1> } } ## end sub ErrorPage sub CGI::first_param { return my( $first ) = CGI::multi_param( @_ ); } sub DebugCGI { my( $cgi ) = @_; $cgi ||= CGI->new; binmode STDOUT, ':encoding(UTF-8)'; $cgi->charset( 'UTF-8' ); print $cgi->header( -charset => 'UTF-8' ); print $cgi->start_html, $cgi->b( rand time, ' ', scalar gmtime ), '<table border="1" width="%100"><tr><td>', $cgi->Dump, '</td>', '<td><div style="white-space: pre-wrap; overflow: scroll;">', $cgi->escapeHTML( DD( $cgi ) ), '</div></td></tr></table>', CGI->new( \%ENV )->Dump, $cgi->end_html; } ## end sub DebugCGI sub DD { require Data::Dumper; return scalar Data::Dumper->new( \@_ )->Indent( 1 )->Useqq( 1 )->D +ump; } sub WashFilename { use File::Basename; my $basename = basename( shift ); # untainted , only use a-z A-Z 0-9 and dot and dash $basename = join '', $basename =~ m/([\-.a-zA-Z0-9])/g; # basename is now, hop0efully, file.ext ## so to ensure uniqueness, we adulterate it :) my $id = $$ . '-' . time; my( $file, $ext ) = split /\./, $basename, 2; return join '.', grep defined, $file, $id, $ext; } ## end sub WashFilename sub ThanksPage { my( $query ) = @_; q{ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-s +trict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Thanks!</title> <style type="text/css"> img {border: none;} </style> </head> <body> <p>Thanks for uploading your file!</p> </body> </html> } } ## end sub ThanksPage sub MaintenancePage { q{<!DOCTYPE html> <html> <head> <title>MAINTENANCE PAGE</title> </head> <body> <form name = f1 action="https://10.XXX.XXX.X:16311/ibm/console/webtop/ +cgi-bin/download_csv.cgi" method = "POST"> <p style="margin-left:10em;font-size:40px">MAINTENANCE PAGE</p> <br> <p style="margin-left:16.5em;font-size:20px">Circle:<select name="Circ +le" > <option value="Gabon">Gabon</option> <option value="Tanzania">Tanzania</option> </select> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs +p;&nbsp;&nbsp; Technology : <select name="Techno" > <option value="Core">Core</option> <option value="RAN">RAN</option> </select> </p> <br> <input type="submit" style="margin-left:30.5em" value="Download" onc +lick="this.form.target='_blank';return true;"> &nbsp;&nbsp;&nbsp; <input type="submit" value="Upload" onclick="f1.action='https://10.XXX +.XXX.X:16311/ibm/console/webtop/cgi-bin/Maintenance_Framework.cgi'; +return true;"> </form> </body> </html> }; } ## end sub MaintenancePage sub PrintPage { my( $q ) = @_; <<'__HTML__'; <!DOCTYPE html> <form name=f1 style="margin:20px 0" action="Maintenance_Framew +ork.cgi" method="post" enctype="multipart/form-data"> <p> <h3 align='center'> Maintenance File Upload </h3> <br> <p>File to Upload: <input type="file" name="filecsv" /></p> <p><input type="submit" name="Submit" value="Upload"></p>&nbsp +&nbsp&nbsp </body> </html> </form> __HTML__ } ## end sub PrintPage

      Thanks for this script. Upload function is working absolutely fine but however Download button is not available on the page.There should be Download button which should download the requested file based on the Circle and Techno selection. part of your working code

      sub MaintenancePage { q{<!DOCTYPE html> <html> <head> <title>MAINTENANCE PAGE</title> </head> <body> <form name = f1 action="https://10.XXX.XXX.X:16311/ibm/console/webtop/ +cgi-bin/download_csv.cgi" method = "POST"> <p style="margin-left:10em;font-size:40px">MAINTENANCE PAGE</p> <br> <p style="margin-left:16.5em;font-size:20px">Circle:<select name="Circ +le" > <option value="Gabon">Gabon</option> <option value="Tanzania">Tanzania</option> </select> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs +p;&nbsp;&nbsp; Technology : <select name="Techno" > <option value="Core">Core</option> <option value="RAN">RAN</option> </select> </p> <br> <input type="submit" style="margin-left:30.5em" value="Download" onc +lick="this.form.target='_blank';return true;"> &nbsp;&nbsp;&nbsp; <input type="submit" value="Upload" onclick="f1.action='https://10.XXX +.XXX.X:16311/ibm/console/webtop/cgi-bin/Maintenance_Framework.cgi'; +return true;"> </form> </body> </html> }; } ## end sub MaintenancePage

      Download scipt

      #!/usr/bin/perl #use strict; #use warnings; use CGI 'header'; use CGI::Carp qw(fatalsToBrowser); local ($buffer, @pairs, $pair, $name, $value, %FORM); $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } $Circle = $FORM{Customer}; $Techno = $FORM{Techno}; $filename = $Circle.'_'.$Techno.'.csv'; my $files_location = "/opt/IBM/Maintenance/archive"; if (!$filename) { die "You must specify a file to download"; exit; } print header( -type => 'text/csv', -content_disposition => "attachment;filename=$filename", ); my $fileloc = "$files_location/$filename"; open my $fh, '<', $fileloc or Error('open', 'file', $!); print while <$fh>; close $fh or Error ('close', 'file' ); sub Error { die "@_"; }
        .. Download button is not available on the page

        It looks like is in the HTML

        <input type="submit" style="margin-left:30.5em" value="Download" onc lick="this.form.target='_blank';return true;">
        poj

        Hi,

        Its your code now :)

        Did you copy that %FORM stuff from use CGI or die; ? The lesson of that node is to use param()