Perl Processing File Uploads

The browser displays t his field as a t ext input box int o which t he user can ent er t he nam e m anually. I t also present s a Browse but t on for select ing t he file via t he st andard file-brow sing syst em dialog. When t he user chooses a file and subm it s t he form , t he browser encodes t he file cont ent s for inclusion int o t he result ing POST request . At t hat point , t he web server receives t he request and invokes your script t o process it . The specifics vary for part icular API s, but file uploads generally work like t his: • The file will already have been uploaded and st ored in a t em porary direct ory by t he t im e your upload- handling script begins execut ing. All your script has t o do is read it . The t em porary file will be available t o your script eit her as an open file descript or or t he t em porary filenam e, or perhaps bot h. The size of t he file can be obt ained t hrough t he file descript or. The API m ay also m ake available ot her inform at ion about t he file, such as it s MI ME t ype. But not e t hat som e browsers m ay not send a MI ME value. • Uploaded files are delet ed aut om at ically by t he web server when your script t erm inat es. I f you want a files cont ent s t o persist beyond t he end of your script s execut ion, youll have t o save it t o a m ore perm anent locat ion for exam ple, in a dat abase or som ewhere else in t he filesyst em . I f you save it in t he filesyst em , t he direct ory where you st ore it m ust be accessible t o t he web server. • The API m ay allow you t o cont rol t he locat ion of t he t em porary file direct ory or t he m axim um size of uploaded files. Changing t he direct ory t o one t hat is accessible only t o your web server m ay im prove securit y a bit against local exploit s by ot her users wit h login account s on t he server host . This sect ion discusses how t o creat e form s t hat include a file upload field. I t also dem onst rat es how t o handle uploads using a Perl script , post _im age.pl. The script is som ewhat sim ilar t o t he st ore_im age.pl script for loading im ages from t he com m and line Recipe 17.7 . post _im age.pl differs in t hat it allows you t o st ore im ages over t he Web by uploading t hem , and it st ores im ages only in MySQL, whereas st ore_im age.pl st ores t hem in bot h MySQL and t he filesyst em . This sect ion also discusses how t o obt ain file upload inform at ion using PHP and Pyt hon. I t does not repeat t he ent ire im age-post ing scenario shown for Perl, but t he recipes dist ribut ion cont ains equivalent im plem ent at ions of post _im age.pl for PHP and Pyt hon.

18.9.4 Perl

You can specify m ult ipart encoding for a form several ways using t he CGI .pm m odule. The following st at em ent s are all equivalent : print start_form -action = url , -enctype = multipartform-data; print start_form -action = url , -enctype = MULTIPART ; print start_multipart_form -action = url ; The first st at em ent specifies t he encoding t ype lit erally. The second uses t he CGI .pm MULTIPART funct ion, which is easier t han t rying t o rem em ber t he lit eral encoding value. The t hird st at em ent is easiest of all, because start_multipart_form supplies t he enctype param et er aut om at ically. Like start_form , start_multipart_form uses a default request m et hod of POST , so you need not include a method argum ent . Heres a sim ple form t hat includes a t ext field for assigning a nam e t o an im age, a file field for select ing t he im age file, and a subm it but t on: print start_multipart_form -action = url , Image name:, br , textfield -name =image_name, -size = 60, br , Image file:, br , filefield -name =upload_file, -size = 60, br , br , submit -name = choice, -value = Submit, end_form ; When t he user subm it s an uploaded file, begin processing it by ext ract ing t he param et er value for t he file field: file = param upload_file; The value for a file upload param et er is special in CGI .pm because you can use it t wo ways. You can t reat it as an open file handle t o read t he files cont ent s, or pass it t o uploadInfo t o obt ain a reference t o a hash t hat provides inform at ion about t he file such as it s MI ME t ype. The following list ing shows how post _im age.pl present s t he form and processes a subm it t ed form . When first invoked, post _im age.pl generat es a form wit h an upload field. For t he init ial invocat ion, no file will have been uploaded, so t he script does not hing else. I f t he user subm it t ed an im age file, t he script get s t he im age nam e, reads t he file cont ent s, det erm ines it s MI ME t ype, and st ores a new record in t he image t able. For illust rat ive purposes, post _im age.pl also displays all t he inform at ion t hat t he uploadInfo funct ion m akes available about t he uploaded file. usrbinperl -w post_image.pl - allow user to upload image files via POST requests use strict; use lib qwusrlocalapachelibperl; use CGI qw:standard escapeHTML; use Cookbook; print header , start_html -title = Post Image, -bgcolor = white; Use multipart encoding because the form contains a file upload field print start_multipart_form -action = url , Image name:, br , textfield -name =image_name, -size = 60, br , Image file:, br , filefield -name =upload_file, -size = 60, br , br , submit -name = choice, -value = Submit, end_form ; Get a handle to the image file and the name to assign to the image my image_file = param upload_file; my image_name = param image_name; Must have either no parameters in which case that script was just invoked for the first time or both parameters in which case the form was filled in. If only one was filled in, the user did not fill in the form completely. my param_count = 0; ++param_count if defined image_file image_file ne ; ++param_count if defined image_name image_name ne ; if param_count == 0 initial invocation { print p No file was uploaded.; } elsif param_count == 1 incomplete form { print p Please fill in BOTH fields and resubmit the form.; } else a file was uploaded { my size, data; If an image file was uploaded, print some information about it, then save it in the database. Get reference to hash containing information about file and display the information in key=x, value=y format my info_ref = uploadInfo image_file; print p Information about uploaded file:; foreach my key sort keys {info_ref} { printf p key= . escapeHTML key . , value= . escapeHTML info_ref-{key}; } size = stat image_file[7]; get file size from file handle print p File size: . size; binmode image_file; helpful for binary data if sysread image_file, data, size = size { print p File contents could not be read.; } else { print p File contents were read without error.; Get MIME type, use generic default if not present my mime_type = info_ref-{Content-Type}; mime_type = applicationoctet-stream unless defined mime_type; Save image in database table. Use REPLACE to kick out any old image with same name. my dbh = Cookbook::connect ; dbh-do REPLACE INTO image name,type,data VALUES?,?,?, undef, image_name, mime_type, data; dbh-disconnect ; } } print end_html ; exit 0;

18.9.5 PHP