in reply to PHP through PERL

You can always use CGI.pm to upload files but I've been working on a CGI.pm alternative for file uploading. Below are the two subs that do the job... and code showing how to use them. Maybe I'll make this a module sometime soon -- much, much faster then CGI.pm.

Note - The below needs CRLF support to make it pretty much bug free.

#!/usr/bin/perl use strict; BEGIN { unshift @INC, $1 if $0 =~ m!(.*)[/\\]!; } eval { my $in = process_buffer(); print "Content-Type: text/html\n\n"; print q~<form method="post" action="" enctype="multipart/form-data +"><input type="file" name="file"><br><input type="submit" value="Uplo +ad"></form>~; if ($in->{file}) { (my $fn = $in->{file}) =~ s!^.*(\\|\/)!!; # get actual filenam +e open FH, ">$fn"; binmode FH; print FH $::multipart_data{$in->{file}}; close FH; print "<p>File $in->{file} Uploaded!"; } }; print "content-type: text/html\n\n$@" if $@; # process_buffer: Read the form data. sub process_buffer { binmode STDIN; binmode STDOUT; binmode STDERR; my $buffer; if ($ENV{'REQUEST_METHOD'} =~ /^(GET|HEAD)$/) { $buffer = $ENV{'QUERY_STRING'}; } elsif ($ENV{'REQUEST_METHOD'} eq 'POST') { if ((my $received = read(STDIN, $buffer, $ENV{'CONTENT_LENGTH' +})) != $ENV{'CONTENT_LENGTH'}) { die "Short read: wanted $ENV{'CONTENT_LENGTH'}, but unfort +unately got $received"; } if ($ENV{'CONTENT_TYPE'} =~ m|^multipart/form-data|) { # Begin + multipart my ($boundary) = $ENV{'CONTENT_TYPE'} =~ /boundary=\"?([^\ +";,]+)\"?/; die "Couldn't find boundary. This is usually caused by a b +ug server-side." unless $boundary; $boundary = "--$boundary"; my @buffer = (); for my $i (grep /^\s*Content-Disposition:/i, split /$bound +ary/, $buffer) { my @data = split("\r\n\r\n", substr($i, 0, length($i) +- 2)); my $headers = shift @data; my %header; while ($headers =~ /([-\w!\#$%&\'*+.^_\`|{}~]+):"?(.+) +"?/xmgo) { my ($name, $value) = ($1, $2); $name =~ s/\b(\w)/\u$1/g; $header{$name} = $value; } my ($key) = $header{'Content-Disposition'} =~ / name=" +?([^\";]*)"?/; my $value = join "\r\n\r\n", @data; # POSSIBLE BUG ALERT: Netscape does not escape quotati +on marks in file names? my ($filename) = $header{'Content-Disposition'} =~ / f +ilename="?([^\"]*)"?/; #$filename =~ s!\\!/!g; $filename =~ s~[^\w\d \-_:/\\\.]~~g; if ($filename) { $::multipart_data{$filename} = $value; push @buffer, "$key=$filename"; } else { push @buffer, "$key=$value"; } } $buffer = join ';', @buffer; } # End multipart } else { die "Unknown request method used: $ENV{'REQUEST_METHOD'}"; } return format_buffer($buffer); } # format_buffer: Converts a standard buffer into a hash. # Syntax: format_buffer('key=value&key2=value2'); sub format_buffer { my $buffer = shift; my $temp; for my $pair ( split /[&;]/, $buffer ) { my ($name, $value) = split /=/, $pair; $name =~ tr/+/ /; $name =~ s/%([a-fA-F0-9]{2})/pack("c", hex($1))/eg; $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9]{2})/pack("c", hex($1))/eg; if (exists $temp->{$name}) { if (ref $temp->{$name}) { push @{ $temp->{$name} }, $value; } else { $temp->{$name} = [$temp->{$name}, $value]; } } else { $temp->{$name} = $value; } } return $temp; }

UPDATE: You can get the above code in .txt format here!