We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you two Citrix podcasts. Learn about 2020 trends and get answers to your biggest Citrix questions!Listen Now


robust upload file without CGI.pm

Traltixx asked
Medium Priority
Last Modified: 2013-12-25
Im trying to make a perl-CGI upload script without the CGI.pm module. I know its easier but I want to understand several things. First my upload.html has several fields (and a file input box) and submits via ENCTYPE="multipart/form-data", so when my CGI grabs it all (from POST) via STDIN, I get some strings like:

Content-Disposition: form-data; name="email_address"

Content-Disposition: form-data; name="Submit"

Submit Form

I was wondering if anyone has a quick way to parse this? Maybe turn it into hashes or something? Also in this is the binary content of the file I uploaded, so Im also trying to not only get field values, but also upload a file (without the CGI module).
Watch Question

Most Valuable Expert 2014
Top Expert 2015

could you use CGI::Minimal;
Top Expert 2006

Can you show the code you use that produced the output you posted?


well, I cant use the CGI module at all, so no, I cant use CGI::Minimal.
And code that produced that?
The perl snippet is:
print "\n\nStandard Input:\n";
if ($ENV{'REQUEST_METHOD'}  eq "POST") {
      read(STDIN, $in, $ENV{'CONTENT_LENGTH'});
      print $in;
and the HTML snippet is something like:

<FORM ACTION="upload.cgi" METHOD="post" ENCTYPE="multipart/form-data">
  File to Upload: <INPUT TYPE="file" NAME="filex">
      Your Email Address: <INPUT TYPE="text" NAME="email_address">
        <INPUT TYPE="submit" NAME="Submit" VALUE="Submit Form">

Most Valuable Expert 2014
Top Expert 2015

the CGI::Minimal module is not the CGI module


it isnt? is there an example of how to use/upload files with this?


OK, i've had a look and it seems that CGI::minimal is a whole module alltogether. I suppose I should change my question to, not using CGI.pm or any downloaded modules (because i cant download them).
Is there another way of doing this?
Thanks alot again!
you have to parse the HTTP header *and* the POST data line by line yourself.
From the header you need to get the value of the Content-Type and extract the boundary string.
Then you need to parse the POST data and search the boundary  string followed by a
  Content-Disposition: form-data; name="whatever"
wher "whatever" is your variable name from the HTML form.
While parsing you need to count the bytes of the data you ignore, the remaining ones 'til the value of the Content-Length *or* #til next boundary string is your file's data.

Simple, isn't it?
You better go with a redy-to-use module. Or go and get one and steal the code from there, if you like the hard way ;-)
Top Expert 2007

Why can't you download them?  Is this a homework/assignment question?


I cant download them because its a personal restraint (i.e. im trying to understand CGI more by relying less on modules and doing everything standalone).
That is why i was wondering if anyone knew a quick way of parsing the POST data bymyself since if I did it, i would have missed some things due to the nature of my test cases.
Anyway, it seems that there is a more minimal module than CGI::minimal, namely cgi-lib.pl ( http://cgi-lib.berkeley.edu/#intro )
thanks for the info anyway for cgi::minimal
Top Expert 2007

cgi-lib is a not a particularly good example to study as it is so out of date and doesn't conform to all the latest standards.  It was good in its day when there wasn't any other choice.

If you really want to learn more about CGI, I'd suggest studying the CGI spec


and studying the code of CGI::Minimal or CGI (admittedly, it's not particularly easy code to read as it uses many tricks to be as efficient and broad based as possible)
Top Expert 2006
I'm going to wash my hands after posting this. This is a crude way of parsing the from data into a hash:

my %IN = read_parse();

sub read_parse {

   my $buffer;
   if ($ENV{'REQUEST_METHOD'} eq 'GET') {
      $buffer = $ENV{'QUERY_STRING'};
   elsif ($ENV{'REQUEST_METHOD'} eq 'POST') {
      read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
   else {die "Invalid request method";}

  my @pairs = split(/&/, $buffer);
   foreach (@pairs) {
      my($name, $value) = split(/=/, $_);
      $value =~ tr/+/ /;
      $value =~ s/%([a-fA-F0-9]{2})/pack("c", hex($1))/eg;
      if (defined($IN{$name})){$IN{$name} .= "\0";}
      $IN{$name} .= $value;
   return %IN;

the above is not recommended but it might give you some insight.

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts


yes, cgi-lib.pl is rather out of date, but it seems to be fine.
Also thanks for the snippet (although it doesnt work really well with uploading file but i found what i was looking for).
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.


Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.