##############!/usr/bin/perl #This is the 'uploader.cgi' script. #####################################
require 'cgi-lib2.pl'; # Indicate if your server O/S is Unix/Linux or Windows NT # Set to "unix" if Unix or Linux; set to "nt" if Windows NT $serverOS = "unix"; # This parameter defines what character set you want the Web # browser to be set to when viewing your Html pages. # Default is "". Chinese GB = "gb2312". Chinese Big5 = "Big5". $charset = "us-ascii"; # Supervisor Password. $superpwd = "whatever"; # Full pathname of directory (parent) which is 1 level higher than # the "file upload" directory (directory storing the uploaded files). # This directory must be resided in a Html directory # Create this directory manually if it is not already existed. # Use chmod command to set this directory to writable, i.e. 0777. # The last "/" character is significant. #I have refered this $parent_dir to the password file/files,(but no he +lp). $parent_dir="/home/virtual/site71/fst/var/www/html/uploads/mp3/"; $return_url="http://www.mysite.net/"; @valid=('http://www.mysite.net/uploads/MP3Upload.html'); ################################################################### # Parse Form Contents &ReadParse; if ($ENV{'REQUEST_METHOD'} ne 'POST') { &error_not_a_command; } $| = 1; # Validate & execute command according to Action Type unless ( ($in{'action'} eq "uploadfile") || ($in{'action'} eq "listfilenames")) { &error_not_a_command; } if ($in{'action'} eq "uploadfile") {&uploadfile} if ($in{'action'} eq "listfilenames") {&listfilenames} exit; sub uploadfile { &check_url_referer; if ($in{'pwd'} ne $superpwd) { &error_password; } if (!$in{'sourcefile'}) { &error_uploadfile; } if (!$in{'filedirname'}) { &error_no_upload_directory; } if ($in{'filedirname'} =~ /[^a-z0-9A-Z]+/) { &error_invalid_directory_name; } if ($in{'maxfilesize'}) { $maxfilesize = $in{'maxfilesize'}; }<li> if ($ENV{'CONTENT_LENGTH'} > $maxfilesize) { &error_file_too_large; } $upload_dir = "$parent_dir$in{'filedirname'}"; if (opendir(DIR,"$upload_dir") != 1) { if (mkdir($upload_dir,0777) == 0) { &cannot_create_directory; } if ($serverOS =~ /^unix$/i) { `chmod 0777 $upload_dir`; } } $upload_dir = "$upload_dir/"; open(REAL,">$upload_dir$in{'destn_filename'}") || &error_open_file; if ($serverOS =~ /^nt$/i) { binmode(REAL); } print REAL $in{'sourcefile'}; close(REAL); if ($serverOS eq "unix") { `chmod 0777 $upload_dir$in{'destn_filename'}`; } &upload_ok; } sub listfilenames { &check_url_referer; if ($in{'pwd'} ne $superpwd) { &error_password; } if (!$in{'filedirname'}) { &error_no_upload_directory; } $list_dir = "$parent_dir$in{'filedirname'}"; if (opendir(DIR,"$list_dir") == 1) { @files = readdir(DIR); closedir(DIR); } else { &error_cannot_open_dir; } &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>Listin +g of Filenames</b></font></center><p>\n"; print "<b>The following filenames are found in directory \"$in{'fil +edirname'}\":<br>\n"; $count = 0; foreach $fitem (@files) { $fitem_pathname = "$list_dir" . "/" . "$fitem"; if (-e $fitem_pathname) { if (-d $fitem_pathname) {next;} $count++; print " $fitem<br>\n"; } } if ($count == 0) { print " Sorry, nothing found!!<br>\ +n"; } print "</b><p>\n"; &listfilenames_ok; } sub return { print "Location: $ENV{'DOCUMENT_URI'}\n\n"; } sub check_url_referer { $referral_cnt = @valid; if ($referral_cnt > 0) { foreach $referer (@valid) { if ($ENV{'HTTP_REFERER'} =~ /$referer/i) { $good_ref = "yes"; last; } } if ($good_ref ne "yes") { &go_away; } } } sub error_password { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>ERROR: + Invalid password</b></font></center>"; print "<p>You didn't supply a valid password. Please check and ente +r again.</p></body></html>\n"; exit; } sub error_not_a_command { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>ERROR: + Not a valid command</b></font></center>"; print "<p>You did not select a valid command. Please check and try +again.</p></body></html>\n"; exit; } sub go_away { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>ERROR: + Unauthorised Access</b></font></center>"; print "<p>Request denied. You are attempting to access our server u +sing an unauthorized form.</p></body></html>\n"; exit; } sub cannot_create_directory { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>ERROR: + Cannot create the upload directory</b></font></center>"; print "<p>Please check your input and try again. If the problem rep +eats, please contact your Webmaster.</p>\n"; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub error_invalid_directory_name { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>ERROR: + Invalid upload directory name</b></font></center>"; print "<p>Please check your input and try again. Directory name mus +t contain alphanumeric characters only.</p>\n"; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub set_content_type { if ($charset eq "") { print "content-type: text/html\n\n"; } else { print "content-type: text/html\; charset=$charset\n\n"; } } sub upload_ok { &set_content_type; print "<p><center><font size=+1 color=\"FF0000\"><b>File Upload Com +pleted</b></font></center>"; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub listfilenames_ok { print "<p><center><b>Total files listed = $count</b></center></p>\n +"; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub error_no_source_file { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>ERROR: + Source File Is Empty</b></font></center>"; print "<p>You must select a source file to be uploaded. Please try +again.</p>\n"; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub error_no_upload_directory { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>ERROR: + Upload directory name absent</b></font></center>"; print "<p>You did not enter an upload directory name. Please try ag +ain. Directory name must contain alphanumeric characters only.</p>\n" +; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub error_cannot_open_dir { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\"><b>ERROR: + Cannot open the directory</b></font></center>"; print "<p>Please supply a valid directory name and try again.</p>\n +"; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub error_file_too_large { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\">ERROR: Up +load file too large.</font></center>"; print "<p>Size of your upload file exceeds $maxfilesize bytes. Plea +se try again.</p>\n"; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub error_uploadfile { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\">ERROR: Up +load file not specified or empty.</font></center>"; print "<p>You did not provide a file to be uploaded or it is empty. + Please try again.</p>\n"; print "<p><center><b><a href=\"$return_url\">Back Home</a></b></cen +ter></p></body></html>\n"; exit; } sub error_open_file { &set_content_type; print "<html><body><center><font size=+1 color=\"FF0000\">ERROR: De +stination upload file cannot be opened.</font></center>"; print "<p>Please contact Webmaster.</p></body></html>\n"; exit; } #End of uploader.cgi ###################################################################### +################################################################# #Below is the accompanying 'cgi-lib2.pl' script. ################################################# $cgi_lib'version = sprintf("%d.%02d", q$Revision: 2.17 $ =~ /(\d+)\.(\ +d+)/); # Parameters affecting cgi-lib behavior # User-configurable parameters affecting file upload. $cgi_lib'maxdata = '5000000'; # maximum bytes to accept via POST + - 2^21 $cgi_lib'writefiles = '/home/virtual/site71/fst/var/www/html/uploads/m +p3/';# directory to which to write files, or # 0 if files should not be written #What does this mean?Prefix of file? #I know what it is on a phone number,but...? #Could it be anything, for assignment purposes? $cgi_lib'filepre = "audio"; # Prefix of file names, in directory ab +ove # Do not change the following parameters unless you have special reaso +ns $cgi_lib'bufsize = '8192'; # default buffer size when reading mul +tipart $cgi_lib'maxbound = '100'; # maximum boundary length to be encoun +terd $cgi_lib'headerout = '0'; # indicates whether the header has bee +n printed # ReadParse # Reads in GET or POST data, converts it to unescaped text, and puts # key/value pairs in %in, using "\0" to separate multiple selections # Returns >0 if there was input, 0 if there was no input # undef indicates some failure. # Now that cgi scripts can be put in the normal file space, it is usef +ul # to combine both the form and the script in one place. If no paramet +ers # are given (i.e., ReadParse returns FALSE), then a form could be outp +ut. # If a reference to a hash is given, then the data will be stored in t +hat # hash, but the data from $in and @in will become inaccessable. # If a variable-glob (e.g., *cgi_input) is the first parameter to Read +Parse, # information is stored there, rather than in $in, @in, and %in. # Second, third, and fourth parameters fill associative arrays analago +us to # %in with data relevant to file uploads. # If no method is given, the script will process both command-line arg +uments # of the form: name=value and any text that is in $ENV{'QUERY_STRING'} # This is intended to aid debugging and may be changed in future relea +ses sub ReadParse { local (*in) = shift if @_; # CGI input local (*incfn, # Client's filename (may not be provid +ed) *inct, # Client's content-type (may not be provid +ed) *insfn) = @_; # Server's filename (for spooled files) local ($len, $type, $meth, $errflag, $cmdflag, $perlwarn, $got, $nam +e); # Disable warnings as this code deliberately uses local and environm +ent # variables which are preset to undef (i.e., not explicitly initiali +zed) $perlwarn = $^W; $^W = 0; binmode(STDIN); # we need these for DOS-based systems binmode(STDOUT); # and they shouldn't hurt anything else binmode(STDERR); # Get several useful env variables $type = $ENV{'CONTENT_TYPE'}; $len = $ENV{'CONTENT_LENGTH'}; $meth = $ENV{'REQUEST_METHOD'}; # if ($len > $cgi_lib'maxdata) { # cnctek # &CgiDie("cgi-lib2.pl: Request to receive too much data: $len b +ytes\n"); # cnctek # } # cnctek if (!defined $meth || $meth eq '' || $meth eq 'GET' || $meth eq 'HEAD' || $type eq 'application/x-www-form-urlencoded') { local ($key, $val, $i); # Read in text if (!defined $meth || $meth eq '') { $in = $ENV{'QUERY_STRING'}; $cmdflag = 1; # also use command-line options } elsif($meth eq 'GET' || $meth eq 'HEAD') { $in = $ENV{'QUERY_STRING'}; } elsif ($meth eq 'POST') { if (($got = read(STDIN, $in, $len) != $len)) {$errflag="Short Read: wanted $len, got $got\n";}; } else { &CgiDie("cgi-lib2.pl: Unknown request method: $meth\n"); } @in = split(/[&;]/,$in); push(@in, @ARGV) if $cmdflag; # add command-line parameters foreach $i (0 .. $#in) { # Convert plus to space $in[$i] =~ s/\+/ /g; # Split into key and value. ($key, $val) = split(/=/,$in[$i],2); # splits on the first =. # Convert %XX from hex numbers to alphanumeric $key =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; $val =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; # Associate key and value $in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple +separator $in{$key} .= $val; } } elsif ($ENV{'CONTENT_TYPE'} =~ m#^multipart/form-data#) { # for efficiency, compile multipart code only if needed $errflag = !(eval <<'END_MULTIPART'); local ($buf, $boundary, $head, @heads, $cd, $ct, $fname, $ctype, $ +blen); local ($bpos, $lpos, $left, $amt, $fn, $ser); local ($bufsize, $maxbound, $writefiles) = ($cgi_lib'bufsize, $cgi_lib'maxbound, $cgi_lib'writefiles); # The following lines exist solely to eliminate spurious warning m +essages $buf = ''; ($boundary) = $type =~ /boundary="([^"]+)"/; #"; # find boundary ($boundary) = $type =~ /boundary=(\S+)/ unless $boundary; &CgiDie ("Boundary not provided: probably a bug in your server") unless $boundary; $boundary = "--" . $boundary; $blen = length ($boundary); if ($ENV{'REQUEST_METHOD'} ne 'POST') { &CgiDie("Invalid request method for multipart/form-data: $meth\ +n"); } if ($writefiles) { local($me); stat ($writefiles); $writefiles = "/tmp" unless -d _ && -w _; # ($me) = $0 =~ m#([^/]*)$#; $writefiles .= "/$cgi_lib'filepre"; } # read in the data and split into parts: # put headers in @in and data in %in # General algorithm: # There are two dividers: the border and the '\r\n\r\n' between # header and body. Iterate between searching for these # Retain a buffer of size(bufsize+maxbound); the latter part is # to ensure that dividers don't get lost by wrapping between two b +ufs # Look for a divider in the current batch. If not found, then # save all of bufsize, move the maxbound extra buffer to the front + of # the buffer, and read in a new bufsize bytes. If a divider is fo +und, # save everything up to the divider. Then empty the buffer of eve +rything # up to the end of the divider. Refill buffer to bufsize+maxbound # Note slightly odd organization. Code before BODY: really goes + with # code following HEAD:, but is put first to 'pre-fill' buffers. B +ODY: # is placed before HEAD: because we first need to discard any 'pre +face,' # which would be analagous to a body without a preceeding head. $left = $len; PART: # find each part of the multi-part while reading data while (1) { die $@ if $errflag; $amt = ($left > $bufsize+$maxbound-length($buf) ? $bufsize+$maxbound-length($buf): $left); $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $a +mt); die "Short Read: wanted $amt, got $got\n" if $errflag; $left -= $amt; $in{$name} .= "\0" if defined $in{$name}; $in{$name} .= $fn if $fn; $name=~/([-\w]+)/; # This allows $insfn{$name} to be untainted if (defined $1) { $insfn{$1} .= "\0" if defined $insfn{$1}; $insfn{$1} .= $fn if $fn; } BODY: while (($bpos = index($buf, $boundary)) == -1) { if ($left == 0 && $buf eq '') { foreach $value (values %insfn) { unlink(split("\0",$value)); } &CgiDie("cgi-lib2.pl: reached end of input while seeking boundar +y " . "of multipart. Format of CGI input is wrong.\n"); } die $@ if $errflag; if ($name) { # if no $name, then it's the prologue -- discard if ($fn) { print FILE substr($buf, 0, $bufsize); } else { $in{$name} .= substr($buf, 0, $bufsize); } } $buf = substr($buf, $bufsize); $amt = ($left > $bufsize ? $bufsize : $left); #$maxbound==leng +th($buf); $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != +$amt); die "Short Read: wanted $amt, got $got\n" if $errflag; $left -= $amt; } if (defined $name) { # if no $name, then it's the prologue -- d +iscard if ($fn) { print FILE substr($buf, 0, $bpos-2); } else { $in {$name} .= substr($buf, 0, $bpos-2); } # kill l +ast \r\n } close (FILE); last PART if substr($buf, $bpos + $blen, 2) eq "--"; substr($buf, 0, $bpos+$blen+2) = ''; $amt = ($left > $bufsize+$maxbound-length($buf) ? $bufsize+$maxbound-length($buf) : $left); $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $a +mt); die "Short Read: wanted $amt, got $got\n" if $errflag; $left -= $amt; undef $head; undef $fn; HEAD: while (($lpos = index($buf, "\r\n\r\n")) == -1) { if ($left == 0 && $buf eq '') { foreach $value (values %insfn) { unlink(split("\0",$value)); } &CgiDie("cgi-lib: reached end of input while seeking end of " . "headers. Format of CGI input is wrong.\n$buf"); } die $@ if $errflag; $head .= substr($buf, 0, $bufsize); $buf = substr($buf, $bufsize); $amt = ($left > $bufsize ? $bufsize : $left); #$maxbound==leng +th($buf); $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != +$amt); die "Short Read: wanted $amt, got $got\n" if $errflag; $left -= $amt; } $head .= substr($buf, 0, $lpos+2); push (@in, $head); @heads = split("\r\n", $head); ($cd) = grep (/^\s*Content-Disposition:/i, @heads); ($ct) = grep (/^\s*Content-Type:/i, @heads); ($name) = $cd =~ /\bname="([^"]+)"/i; #"; ($name) = $cd =~ /\bname=([^\s:;]+)/i unless defined $name; ($fname) = $cd =~ /\bfilename="([^"]*)"/i; #"; # filename can be + null-str ($fname) = $cd =~ /\bfilename=([^\s:;]+)/i unless defined $fname +; $incfn{$name} .= (defined $in{$name} ? "\0" : "") . (defined $fname ? $fname : ""); ($ctype) = $ct =~ /^\s*Content-type:\s*"([^"]+)"/i; #"; ($ctype) = $ct =~ /^\s*Content-Type:\s*([^\s:;]+)/i unless defin +ed $ctype; $inct{$name} .= (defined $in{$name} ? "\0" : "") . $ctype; if ($incfn{$name}) { # cnctek $source_filename = $incfn{$name}; # cnctek $source_filename =~ s/[:\\]/\//g; # cnctek $source_filename =~ s/.*\///g; # cnctek } # cnctek if ($writefiles && defined $fname) { $ser++; $fn = $writefiles . ".$$.$ser"; open (FILE, ">$fn") || &CgiDie("Couldn't open $fn\n"); binmode (FILE); # write files accurately } substr($buf, 0, $lpos+4) = ''; undef $fname; undef $ctype; } 1; END_MULTIPART if ($errflag) { local ($errmsg, $value); $errmsg = $@ || $errflag; foreach $value (values %insfn) { unlink(split("\0",$value)); } &CgiDie($errmsg); } else { if (!$in{'destn_filename'} || $in{'destn_filename'} =~ /^[ ]+$/) + { # cnctek if ($source_filename) { # cnctek $in{'destn_filename'} = $source_filename; # cnctek } # cnctek } # cnctek # everything's ok. } } else { &CgiDie("cgi-lib2.pl: Unknown Content-type: $ENV{'CONTENT_TYPE'}\n +"); } # no-ops to avoid warnings $insfn = $insfn; $incfn = $incfn; $inct = $inct; $^W = $perlwarn; return ($errflag ? undef : scalar(@in)); } # PrintHeader # Returns the magic line which tells WWW that we're an HTML document sub PrintHeader { return "Content-type: text/html\n\n"; }
# HtmlTop # Returns the <head> of a document and the beginning of the body # with the title and a body 'h1' header as specified by the parameter sub HtmlTop { local ($title) = @_; return <<END_OF_TEXT; <html> <head> <title>$title</title> </head> <body> <h3>$title</h3> END_OF_TEXT } # HtmlBot # Returns the </body>, </html> codes for the bottom of every HTML page sub HtmlBot { return "</body>\n</html>\n"; } # SplitParam # Splits a multi-valued parameter into a list of the constituent param +eters sub SplitParam { local ($param) = @_; local (@params) = split ("\0", $param); return (wantarray ? @params : $params[0]); } # MethGet # Return true if this cgi call was using the GET request, false otherw +ise sub MethGet { return (defined $ENV{'REQUEST_METHOD'} && $ENV{'REQUEST_METHOD'} eq +"GET"); } # MethPost # Return true if this cgi call was using the POST request, false other +wise sub MethPost { return (defined $ENV{'REQUEST_METHOD'} && $ENV{'REQUEST_METHOD'} eq +"POST"); } # MyBaseUrl # Returns the base URL to the script (i.e., no extra path or query str +ing) sub MyBaseUrl { local ($ret, $perlwarn); $perlwarn = $^W; $^W = 0; $ret = 'http://' . $ENV{'SERVER_NAME'} . ($ENV{'SERVER_PORT'} != 80 ? ":$ENV{'SERVER_PORT'}" : '') . $ENV{'SCRIPT_NAME'}; $^W = $perlwarn; return $ret; } # MyFullUrl # Returns the full URL to the script (i.e., with extra path or query s +tring) sub MyFullUrl { local ($ret, $perlwarn); $perlwarn = $^W; $^W = 0; $ret = 'http://' . $ENV{'SERVER_NAME'} . ($ENV{'SERVER_PORT'} != 80 ? ":$ENV{'SERVER_PORT'}" : '') . $ENV{'SCRIPT_NAME'} . $ENV{'PATH_INFO'} . (length ($ENV{'QUERY_STRING'}) ? "?$ENV{'QUERY_STRING'}" : '' +); $^W = $perlwarn; return $ret; } # MyURL # Returns the base URL to the script (i.e., no extra path or query str +ing) # This is obsolete and will be removed in later versions sub MyURL { return &MyBaseUrl; } # CgiError # Prints out an error message which which containes appropriate header +s, # markup, etcetera. # Parameters: # If no parameters, gives a generic error message # Otherwise, the first parameter will be the title and the rest will # be given as different paragraphs of the body sub CgiError { local (@msg) = @_; local ($i,$name); if (!@msg) { $name = &MyFullUrl; @msg = ("Error: script $name encountered fatal error\n"); }; if (!$cgi_lib'headerout) { #') print &PrintHeader; print "<html>\n<head>\n<title>$msg[0]</title>\n</head>\n<body>\n"; } print "<h1>$msg[0]</h1>\n"; foreach $i (1 .. $#msg) { print "<p>$msg[$i]</p>\n"; } $cgi_lib'headerout++; } # CgiDie # Identical to CgiError, but also quits with the passed error message. sub CgiDie { local (@msg) = @_; &CgiError (@msg); die @msg; } # PrintVariables # Nicely formats variables. Three calling options: # A non-null associative array - prints the items in that array # A type-glob - prints the items in the associated assoc array # nothing - defaults to use %in # Typical use: &PrintVariables() sub PrintVariables { local (*in) = @_ if @_ == 1; local (%in) = @_ if @_ > 1; local ($out, $key, $output); $output = "\n<dl compact>\n"; foreach $key (sort keys(%in)) { foreach (split("\0", $in{$key})) { ($out = $_) =~ s/\n/<br>\n/g; $output .= "<dt><b>$key</b>\n <dd>:<i>$out</i>:<br>\n"; } } $output .= "</dl>\n"; return $output; } # PrintEnv # Nicely formats all environment variables and returns HTML string sub PrintEnv { &PrintVariables(*ENV); } # The following lines exist only to avoid warning messages $cgi_lib'writefiles = $cgi_lib'writefiles; $cgi_lib'bufsize = $cgi_lib'bufsize ; $cgi_lib'maxbound = $cgi_lib'maxbound; $cgi_lib'version = $cgi_lib'version; $cgi_lib'filepre = $cgi_lib'filepre; 1; #return true #####
Edit kudra, 2002-09-13 Replaced pre tags with code tags, added READMORE
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |