package Parse_Form_Data; use strict; use warnings; use Exporter qw( import ); our @EXPORT_OK = qw( parse_form_data ); sub parse_form_data { my %form_data; # split query string into name-value pairs and store each pair # in @parameters array, splitting on the ampersand as the delimiter my @parameters = split /&/, $ENV{ QUERY_STRING }; # if the request happens to be a POST, also read the content of the # request from STDIN. If number of bytes read does not equal number of # bytes we expect in CONTENT_LENGTH, throw error. if ( $ENV{ REQUEST_METHOD } eq 'POST' ) { my $query; read( STDIN, $query, $ENV{ CONTENT_LENGTH } ) == $ENV{ CONTENT_LENGTH } or die "Could not read POST request payload."; push @parameters => split /&/, $query; } # loop through parameters to split them into $name and $value foreach my $name_value ( @parameters ) { my ( $name, $value ) = split /=/, $name_value; # decode URL-encoded characters # replace each plus sign with a space $name =~ tr/+/ /; # could also be $name =~ s/\+/ / g; # scan for a percentage sign followed by two hexadecimal digits and # use Perl's chr function to convert the hexadecimal value into a # character $name =~ s/%([\da-f][\da-f])/chr( hex($1) )/egi; # possible that a parameter can be passed without an equal sign or a # value. Set to empty string to avoid warnings $value = "" unless defined $value; # see comments above for $name $value =~ tr/+/ /; $value =~ s/%([\da-f][\da-f])/chr( hex($1) )/egi; # if the form has elements that share the same name, or if there is # a scrolling box that supports multiple values, then it is possible # for us to receive multiple values for the same name. # to address this, store the multiple values as a single text string # that is delimited by a colon if ( exists $form_data{$name} ) { $form_data{$name} .= ":$value"; } else { $form_data{$name} = $value; } } return %form_data; }