Perl CGI: How to asynchronously upload multiple files

Date March 14th, 2016 Author Vitaly Agapov

If you pass by then just pass by.

Alexey Ivanov «Dormitory-on-Blood»

async

This is a quite frequently used control in the modern web UIs. The user just selects file or files as usual but then he has no need to submit the form and wait for the page to reload. The files are uploaded immediately by Ajax and the result can be seen immediately too.

jQuery makes this task trivial from the frontend point of view but the server side is not so clear. Especially if you use Perl. So I will try eliminate the lack of information with this small post.

Let’s start with the frontend anyway. We’ll assume that we have such an object in our html:

<form action="#" enctype="multipart/form-data" method="post" id="form_file_upload">
   <label for="file_upload">Load from file:</label>
   <input type="file" name="file_upload" id="file_upload" multiple>
</form>

And we also have such a JS:

$(document).ready(function(){
  $('input[type=file]').on('change', uploadFiles);
});
function uploadFiles(event) {
  files = event.target.files;
  event.stopPropagation(); // Stop stuff happening
  event.preventDefault();  // Totally stop stuff happening
  // Create a formdata object and add the files
  var data = new FormData();
  $.each(files, function(key, value) {
     data.append(key, value);
  });
  $.ajax({
     url: '/cgi-bin/upload.pl',
     type: 'POST',
     data: data,
     cache: false,
     dataType: 'json',
     processData: false,
     contentType: false,
     success: function(data, textStatus, jqXHR) {
        if(typeof data.error === 'undefined') {
            handleParsedResults(data.data);
        }
        else {
            console.log('ERRORS: ' + data.error);
        }
     },
     error: function(jqXHR, textStatus, errorThrown) {
        console.log('ERROR: ' + textStatus);
     }
  });
}

Of course this snippet is for case when backend returns some JSON. In any other case the code will we slightly different.

This was just an introduction. Let’s see what should be in upload.pl script.

#!/usr/bin/perl
use JSON;
use CGI;
my $cgi=new CGI();
print "\n";
my $fileCount = 0;
# Iterate over uploaded files
foreach my $tmpfile (keys %{$cgi->{".tmpfiles"}}) {
   # Define the original filename
   my $filename = $cgi->{".tmpfiles"}->{$tmpfile}->{'info'}->{'Content-Disposition'};
   if ( $filename =~ /filename=\"(.+?)\"/ ) {
      $filename = $1;
   } else {
      $filename = "tmpfile$fileCount";
   }
   # Define the full path to the temporary saved file
   my $cgitmpfile=$cgi->{".tmpfiles"}->{$tmpfile}->{'name'}->as_string();

   # Here we can do the magic with all the files.
   # We know the current path to TMP file ($cgitmpfile)
   # And the original name of the file ($filename)
   # So we can move it to some folder we'd like to save it in or just parse it
}
my $result;
$result{data} = "some result text";
$result{error} = $error if ( $error );
print to_json( \%result );
exit;

This is kind of skeleton for any application. I will be glad if it is useful for somebody.

Tags: ,
Category: Perl, Web-dev | No comments »

Comments

Leave a comment

 Comment Form