Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

I am trying to understand a particular piece of code ?? 2

Status
Not open for further replies.

garymgordon

Programmer
Apr 5, 2000
307
US
I am very confused (as I am new to Perl) on exactly how the following works.

Especially the part:

$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",
hex($1))/eg;

(What in the world is the % doing in there?? And what is pcak("C",hex($1))/eg; ???)


If you would, please explain .. line by line and then almost character by character - what this code snippet is doing.

Thanks.

Here it is:

sub get_form_data

{
# Get the input
read(STDIN, $buffer, $ENV{ 'CONTENT_LENGTH' } );

# Split the name-value pairs
@pairs = split (/&/, $buffer);
foreach $pair (@pairs)

{
($name, $value) = split(/=/, $pair);

$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",
hex($1))/eg;
$value =~ s/<!--(.|\n)*-->//g;
$FORM{$name} = $value;
}
}

Gary M. Gordon, LLC
webmaster@garymgordon.com
Certified Web Developer ::
Application Programmer
 
The % is just a character that it is matching for. What it is doing is looking for a % followed by two hex characters, and then converting that into a normal ascii character (i.e. %20 = space). Special characters in URLs are encoded as %xx, and they need to be converted back into ascii characters before you can use them. pack is a pretty complicated function and not easy to comprehend, but in this case it is taking a two-digit hex number and &quot;packing&quot; it into an ascii character.

The subroutine gets form data (from method=&quot;PUT&quot;), parses it, and stores it in the %FORM hash. If you had a URL like:
It would create the following:
$FORM{'name'} = &quot;Tracy Dryden&quot;;
$FORM{'age'} = &quot;45&quot;;

Here's what's happening in the subroutine:
Code:
sub get_form_data
{
read(STDIN, $buffer, $ENV{ 'CONTENT_LENGTH' } );
# For PUT, data is in STDIN, length of data is in
# environment var CONTENT_LENGTH.
# So, read CONTENT_LENGTH bytes from STDIN into $buffer
# $buffer = &quot;name=Tracy%20Dryden&age=45&quot;;

# Split the name-value pairs on the & sign, which is
# the parameter seperator, store pairs in the @pairs array
@pairs = split (/&/, $buffer);
# $pairs[0] = &quot;name=Tracy%20Dryden&quot;;
# $pairs[1] = &quot;age=45&quot;;

# process each name-value pair in @pairs
foreach $pair (@pairs)
{
   # $pair = &quot;name=Tracy%20Dryden&quot;;
   # split name-value pair on equal sign
   ($name, $value) = split(/=/, $pair);
   # $name = &quot;name&quot;;
   # $value = &quot;Tracy%20Dryden&quot;;

   # Translate '+' in value to space
   $value =~ tr/+/ /;
   # Replace '%xx' encoding with ascii character
   $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(&quot;C&quot;,hex($1))/eg;
   # Remove html comments and SSI code in params
   # This is done for security
   $value =~ s/<!--(.|\n)*-->//g;
   # Now: $value = &quot;Tracy Dryden&quot;;
   # Store value in %FORM hash, keyed by name
   $FORM{$name} = $value;
   # $FORM{'name'} = &quot;Tracy Dryden&quot;;
}
# It will do the same for &quot;age=45&quot;
# When complete:
# $FORM{'name'} = &quot;Tracy Dryden&quot;;
# $FORM{'age'} = &quot;45&quot;;
} # End of subroutine
Now, after calling the subroutine, you can access your form variables as:
Code:
$FORM{'varname'}
Maybe someone else can give a good tutorial on the pack command (it will be a LOOOOONG one). I understand it just enough to use if for simple things like this.
Meddle not in the affairs of dragons,
For you are crunchy, and good with mustard.
 
OOPS, that should say method=&quot;post&quot; not &quot;put&quot;! Note that the above subroutine ONLY works for method=&quot;post&quot;. To make it work for method=&quot;get&quot; as well you would need to change the first line as follows:
Code:
if ( $ENV{'REQUEST_METHOD'} eq &quot;GET&quot; ) {
   $buffer = $ENV{'QUERY_STRING');
} elsif ( $ENV{'REQUEST_METHOD'} eq &quot;POST&quot; ) {
   read(STDIN, $buffer, $ENV{ 'CONTENT_LENGTH' } );
} else {
   die &quot;Invalid form method&quot;;
}

Also note that if you have more than one form variable with the SAME NAME only ONE of the values will be stored!
To avoid this you could check for the existence of a form variable with the same name and concatenate the new value with the existing value, separated by some special character. For example:
Code:
# Null value ('\0' separates multiple values
if ( defined($FORM{$name}) ) {
   $FORM{$name} .= &quot;\0&quot; . $value;
} else {
   $FORM{$name} = $value;
}
Here's another efficiency tip: instead of doing the translate of + to space on each value, you can do it on the entire buffer string first. It shouldn't have any effect on the rest of the code.
Code:
$buffer =~ tr/+/ /;
Meddle not in the affairs of dragons,
For you are crunchy, and good with mustard.
 
Thank you!! Thank you!!

LOL I was wondering what PUT was. haha

Thanks for clarifying it.

GREAT JOB. You did a wonderful job at explaining everything.

THANKS AGAIN!!!!!

Gary
Gary M. Gordon, LLC
webmaster@garymgordon.com
Certified Web Developer ::
Application Programmer
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top