Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Parsing form post (content)

by mp (Deacon)
on Aug 29, 2002 at 18:44 UTC ( [id://193851]=perlquestion: print w/replies, xml ) Need Help??

mp has asked for the wisdom of the Perl Monks concerning the following question:

I have looked on CPAN and here via Super Search and not found anything that fits the bill. Is there a CPAN module that given a content string (data sent via a form post) as a scalar variable will parse it and return a set of key, value pairs, properly unescaped? CGI.pm and Apache::Request.pm contain the code to do this, but is there anything standalone that doesn't require a full request object?

Example:
Given this input: a=7&b=1&text=Some+text+goes+here&required=Yes&submit=submit
Produce this data structure:

my $data = [ 'a' => 7, 'b' => 1, 'text' => 'Some text goes here', 'required' => 'Yes', 'submit' => 'submit', ];

The intended use is in a script that tests subroutines that are used inside of a mod_perl application. The subroutine under test expects pre-parsed post data in an array structure like that above. I'm using HTML::Form to extract and parse form data from an HTML page, then using it's $form->click method to click on various submit buttons on that page. $form->click returns an HTTP::Request object, from which I can extract the post data as a string (urlescaped and joined by ampersands), but I need to get that data properly parsed and unescaped to send it as input to the subroutine that I'm testing.

Replies are listed 'Best First'.
Re: Parsing form post (content)
by Zaxo (Archbishop) on Aug 29, 2002 at 19:02 UTC

    CGI will do this fine:

    use CGI qw(:standard); # import so no objects my $data = [Vars];

    Update: Some explanation. CGI's Vars() method returns a hash of field-value pairs in list context, which it gets from the arrayref brackets in the $data assignment. The hash gets flattened and $data becomes an arrayref as you wanted. Watch out for multivalued data, it comes in a packed format that you may have to predigest for your test application.

    After Compline,
    Zaxo

      Thank you for the quick response, that worked. Here's the code in context:
      sub test_submit { my ($html_content, $click, %values) = @_; my $base_url = 'http://test.com/'; ok(my @form_list = HTML::Form->parse($html_content, $base_url)); my $form = $form_list[0]; for (keys %values) { $form->value($_, $values{$_}); } my $request = $form->click($click); my $rcontent = $request->content; ######### BEGIN parse POST DATA ######### use CGI qw(:cgi-std); my $q = CGI->new($rcontent); my $data = [$q->Vars()]; ######### END parse POST DATA ######### use Data::Dumper; warn Dumper($data); }
Re: Parsing form post (content)
by fruiture (Curate) on Aug 29, 2002 at 19:18 UTC

    CGI.pm will do this, as the manpage points out.

    use CGI (); #no imports my $q = CGI->new( 'your=string;to=Parse&cgi=pm&will=do;it=correctly' ); # now all the stuff is in a CGI object as we know # and love it
    --
    http://fruiture.de
Re: Parsing form post (content)
by blokhead (Monsignor) on Aug 29, 2002 at 18:54 UTC
    This is stolen and modified from CGI.pm's ReadParse method: It'll work fine unless there are multiple query params with the same name.
    sub ReadParse { my $in = shift; @in = split(/&/,$in); foreach $i (0 .. $#in) { # Convert plus's to spaces $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/%(..)/pack("c",hex($1))/ge; $val =~ s/%(..)/pack("c",hex($1))/ge; # Associate key and value. \0 is the multiple separator $in{$key} = $val; } return \%in; } my $data = ReadParse('a=7&b=1&text=Some+text'); print $data->{text}, "\n"; # prints 'Some text'
    PS: you want those brackets in your question to be curlies, not square brackets. Otherwise you'll get an array ref, not a hash ref.

    PPS: You mentioned that CGI and Apache::Request modules both contained the functionality to do this. When that's the case, it's usually helpful (and a learning experience) to jump into the code for those modules and try to extract only the parts that you need. But then again, reinventing the wheel yourself is also a good learning experience too. ;) Take your pick!

    blokhead

      That code dosen't handle the semicolon as a seperator, and it dosen't work for multiple values on the same key either (it says it seperates them with \0 but it really dosen't) You're just lucky merlyn isn't on at the moment...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://193851]
Approved by talexb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (5)
As of 2024-04-18 05:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found