![]() |
|
![]() |
||
![]() |
![]() |
![]() |
![]() |
![]() |
CGI File Uploadingby Brent MichalskiAug. 14, 1998 Ever since Netscape
introduced file uploading via their Web browser back in version 2.0, many
people have been struggling to figure out just how to implement this feature
on their servers. Have no fear, uploading files is not difficult if you
let the CGI.pm
module do the dirty work for you.
File uploading introductionWhen Netscape Navigator version 2.0 came out, Netscape threw a useful feature into their implementation of the HTML input tag -- they added support for TYPE=FILE. Microsoft caught up with file uploading in version 3.02 if you apply a patch; versions 3.03 and higher have file upload support built in.Lately I have noticed a lot of newsgroup postings asking how to enable file uploads through a Web interface. This tells me that either people aren't using the resources available on the Internet to find the information that will help them, or that they haven't found any information that explains it well enough for them to understand it. I can't solve the first problem, but I hope to eliminate the second. Why use your browser instead of FTP?I know that most of us programmer/system administrator types occasionally make jokes about our users. However, we must remember that it is our job to make their computer use as easy and productive as possible. It is their job to do their best at whatever it is that they do. Not all of our users are going to be as computer literate as we are, so we must accept that fact and get on with our job of making their jobs easier.Face it, the fewer programs we have to teach our users to use, the easier our lives are. Instead of teaching our users to use FTP to upload files and place them in their proper directory with the proper passwords, etc., why don't we allow them to do their file transfers through their Web browsers? Most users are familiar with a Web browser and by doing the uploads through the browser, we can restrict where they can put the files. Diving inThis week's program shows the code to accept a file submitted by the user's browser. The code can accept text or graphic files and includes a subroutine to ensure that a filename was submitted. All of these features are packed into just 27 lines of Perl! Here is the form. Let's jump right into the code.1: #!/usr/local/bin/perl 2: use CGI qw/:standard/; 3: $CGI::POST_MAX=1024 * 25; # max 25K posts 4: $file_name = param('file_name'); 5: $file_type = param('file_type'); 6: &Print_Error if($file_name eq ""); 7: &Print_Results; 8: sub Print_Results{ 9: if($file_type eq "text"){ 10: print header(); 11: print start_html('File Upload Test'); 12: print "<PRE><B>File Name:</B> $file_name\n"; 13: print "<B>File Contents:</B>\n"; 14: while(<$file_name>) { print $_; } 15: print "</PRE>"; 16: print end_html; 17: } else { 18: print header('image/gif'); 19: while(read($file_name,$data,1024)) { print $data; } 20: } # End of if..else 21: } # End of subroutine. 22: sub Print_Error { 23: print "Content-type: text/html\n\n"; 24: print "<p>Field 'File Name' must be filled in for 25: this script to work properly.</p>\n" ; 26: exit 0; 27: } Line-by-line explanationLine 1: Tells the program where to find Perl on the Web server. This line will vary depending on where Perl is installed on your server so you need to make any necessary changes. On a UNIX server, this line is required. If you are running this program on an NT server, this line is not required but won't hurt anything if included.Line 2: Loads the CGI.pm module into the program. The argument in the qw/:standard/ imports the standard function definitions into our program. These definitions are part of the CGI.pm module. Line 3: Sets the maximum amount of data we allow for file uploads. Normally you would set this much higher, but we don't want any really large files taking up our bandwidth. This feature was added in version 2.37 and higher of CGI.pm. Lines 4-5: Read the input sent from the file_name and file_type variables on the calling Web page and store them in their respective variables. Line 6: Calls our error subroutine, Print_Error, if $file_name contains no data. This would occur if the user forgot to choose a file to upload or if the user is using a Web browser that does not support TYPE=FILE in the INPUT tag. Line 7: Calls our Print_Results subroutine. This subroutine sends the contents of the uploaded file back to the browser. Line 8: This is the beginning of our Print_Results subroutine. Line 9: Checks to see if the $file_type variable is equal to text. If it is, it continues into the code block. If it is not, it goes to the else statement on Line 17. Line 10: Calls a subroutine in CGI.pm that prints out the HTTP header information so the Web server knows what kind of data is being sent. This is the equivalent of print "Content-type: text/html\n\n";. Line 11: Calls a subroutine in CGI.pm that prints the beginning HTML code and gives the out page a title. Line 12: Prints some HTML that begins our <PRE> block and displays the file name in bold. Line 13: Prints some HTML that displays File Contents in bold. Line 14: A while loop through the entire file, line-by-line, printing each line. Line 15: Prints some HTML to end our <PRE> block. Line 16: Calls a subroutine in CGI.pm that ends our HTML. This subroutine does a: print "</BODY></HTML>";. Line 17: The else part of our if..else statement. If the if was NOT true, then we proceed to the else. If we get here, then the file must be a graphics file type. Line 18: Prints out our HTTP header to tell the server that we are sending data of MIME type image/gif. Note that this file type will work on both GIF and JPG images. Line 19: OK, this is probably the most difficult part of the program. This line does basically the same thing as the while loop started in Line 14, except this time, we are dealing with binary data so looping through each line of the file wouldn't work well. Let's break this line down further so you can better understand what is happening. while ( begins a while loop that continues as long as there is data to read.Line 20: The end of the if..else block. Line 21: The end of the Print_Results subroutine. Line 22: Begins the Print_Error subroutine. Line 23: Prints out the HTTP header. This does the exact same thing as Line 10, but I didn't use the CGI.pm subroutine this time to show what it looks like if you do it manually. Lines 24-25: Print the error message to the user. I broke the print statement up onto two lines to make it look better in the example. Line 26: Exits the program and returns a status of 0 to Perl. Line 27: The end of our Print_Error subroutine. NotesIf you are on an NT system, you may need to add a few lines of code to get your system to handle binary data better. The CGI.pm site has some tips for using it on non-UNIX platforms.When the file is uploaded onto your Web server, it is stored in a temporary location and deleted as soon as the program stops execution. If you want to keep the file and store it somewhere useable on the system, you need to do it manually. It is very simple to do. Here is what you could add to our above program to save a text file to the /home/brent directory on your server. (If you have a /home/brent directory) Line 13.5 open (MYFILE,">/home/brent/$file_name") || die $!; Line 14 while(<$file_name>){ print MYFILE $_; } Line 14.5 close(MYFILE);Notice that we only had to add 2 extra lines, and modify Line 14 slightly. You would do the same thing for a binary file, except you use the read function as in Line 19 of our program. Please remember that users can also upload programs or scripts -- so be security concious! Do not allow users to upload files into whatever directory they want, or into directories with execute permissions. File uploading is a powerful feature of the Web; make sure you take the appropriate security cautions. If you are on an intranet, you may be able to be a little more flexible. On the Internet you will need to be much more careful. One final note. If you are uploading large files, the user will only see the "hourglass" until the entire file is sent. CGI.pm does not provide any feedback to the user and you cannot send anything back until the file has been saved onto the server. The only way for you to provide feedback to the user while the file is uploading in our example would be to modify CGI.pm which you probably would not want to do. You may wish to warn your users that there may be a long wait before they see any response from the server if they are uploading large files. Wrapping it upI told you at the start of this article that file uploading wasn't hard if you let CGI.pm do the work for you, and now you have seen a working example in less than 30 lines of Perl. You could actually implement a file-upload application in about 10 lines of Perl if you omit the error subroutine.The ability to upload files through the Web browser means we can create powerful Web applications that can accept files on the server. I wrote a document management system where all document check-in/out was handled through the Web browser. This also allowed me to collect information about the file(s) being uploaded and by doing this, I am able to track information on each of the documents on my server. With a little modification, you could easily provide your users with a simple way to upload their home pages to your server or upload anything else they may need to. By the way, next week (August 17-20, 1998) is O'Reilly's Perl Conference 2.0 in San Jose. It is a great opportunity to meet other Perl programmers and learn from some of the leading names in the Perl community. I hope to see you there!
Source Code for CGI File
Uploading
|
|
|
Web Techniques and Web Design and Development copyright © 1995-99 Miller Freeman, Inc. ALL RIGHTS RESERVED |