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

I need to add file upload capabilities to a CGI script, but am having problems. I know that normally the best way to go would be to use CGI.pm's upload function, however this is not an option, as this requires Fcntl, which uses Dynaloader, which I am unable to use on this system. I am, however, able to use most of the rest of CGI.pm's functions, such as getting params. I have also been able to work with files without needing Fcntl for other things like reading, writing and copying files on the server.

To prevent the script from failing on load, I have file upload disabled in CGI.pm (via the $DISABLE_UPLOADS flag).

The submit form is a basic form with a file element named sscfFile, which uses POST and enctype="multipart/form-data". The files that will be uploaded through this form are CSV files.

As far as the processing script, here is what I have. It is currently not working because the $query->param('sscfFile') line doesn't give any value, presumably because it is being ignored due to uploads being disabled. I believe that I also need to extract the file data to a buffer, since CGI isn't handling that in this case.

#!/usr/bin/perl -w use CGI(); my $query = new CGI; $upload_dir = "/tmp"; print "Content-type: text/html\n\n"; print "<html><head>\n"; print "<title>BFT File Upload</title></head>\n"; print "<body>\n"; print "Processing Uploaded File...<br />"; $sscfFile = $query->param('sscfFile') || ''; if ($sscfFile =~ /([\w .-]+)$/i) { #strip off path stuff $sscfFile = $1; } else { error("Could not generate filename $!"); } open (UPLOADFILE, ">$upload_dir/$sscfFile") || (error("Cannot open fil +e $upload_dir/$sscfFile $!")); binmode UPLOADFILE; while ($bytesread=read($sscfFile,$buffer,1024)) { $totalbytes += $bytesread; print UPLOADFILE $buffer; } close UPLOADFILE; print "</body></html>";

I looked around at the other threads on this site related to uploads, but they all seem to use CGI.pm for upload. I think what I need to do is manually extract the multipart form data into a buffer, and then use code similar to above to write it to a file. Does anyone have suggestions as to how I can go about this?

Replies are listed 'Best First'.
Re: File Upload without using CGI.pm upload function
by ikegami (Patriarch) on Jun 25, 2009 at 17:55 UTC
    Why don't you copy CGI (as CGI::NoDynaload or something) and remove or workaround the parts that need Fnctl. It should be much simpler to modify the box then trying to re-implement everything outside of the box.
Re: File Upload without using CGI.pm upload function
by trwww (Priest) on Jun 25, 2009 at 23:50 UTC

    Hello,

    You could use CGI::Simple. It is supposed to be a drop in replacement for the CGI module, but doesn't have all the dependency problems and loading complexities.

    regards,

      Thank you very much trwww! CGI::Simple worked perfectly without having to modify my old code or the module. As an added bonus, I am a seeing a very significant speed increase with CGI::Simple.

      I wouldn't have thought to look at the CGI::Simple module, so I'm really glad I asked here.
      Just a quick follow-up in case someone comes across a similar issue in the future:

      After further testing, I found that CGI::Simple actually didn't quite work for file uploads without modification. I initially did not enable uploads (turned off by default in CGI::Simple), so the upload function was not being called. New files were being created in the filesystem, but remained empty.

      CGI::Simple uses IO::File for file handles, which requires dynamic loading. I was able to remedy this by modifying the _save_tmpfile function to not require IO::File and instead use open() to create a temp file. File uploading now seems to work fine.