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

I'm trying to pass a data structure from one cgi script to another, but am having trouble. I'm using similar syntax:
my $tree = XMLin( foo.xml ); print $q->redirect('http://foo/cgi-bin/bar.cgi?TREE='.$tree);
in bar.cgi I'm using the following:
my $p = new CGI; my %in = map { $_ => $p->param($_) } $p->param; print header; print Dumper(%in);
I've also tried something simple like:
my $treeparam = param('TREE'); print Dumper($treeparam);
but no luck with either. I can't seem to access any of the the data in the hash it creates. Is there an easier way or am I missing something?

Replies are listed 'Best First'.
Re: How do I pass a data structure with CGI redirect
by dave_the_m (Monsignor) on May 12, 2004 at 01:32 UTC
    Any data you add to the redirect URL must be a simple string, not a Perl data structure. This string gets sent to the client browser, then then sends it back as part of the new request.

    You really need to store the data on the server in one form or another, and send some sort of index value in the redirect URL, which can be used to retrieve the data by the second CGI script.

Re: How do I pass a data structure with CGI redirect
by Errto (Vicar) on May 12, 2004 at 02:35 UTC

    If you want to pass the entire contents of an XML file in the query string, the file had better be small. As the above posters said, you need to pass it as a string (not a data structure) and you should URL-encode the contents of the file.

    Other possibilities include:

    • If the target CGI can also access the XML file, just pass the filename, not the contents
    • On the originating side, build the XML data into a hash. Then do something like this:
      my $params = join '&', map { "$_=" . uri_escape($hash{$_}) } keys %has +h; print q->redirect("http://foo/cgi-bin/bar.cgi?$params");
      Be aware, though, that this will require that your keys be valid URI parameter names.

Re: How do I pass a data structure with CGI redirect
by sgifford (Prior) on May 12, 2004 at 01:41 UTC
    As dave_the_m said, you can only pass a string through CGI. If you want to pass a more complex data structure, you can store it on the server, as he suggests, or you can convert it into a string, pass it as as a CGI parameter, then convert it back to your data structure. You could convert it to a string by making it into XML data, as you seem to be using, or with pack or sprintf. You may have to escape special characters in the string; URI::Escape has tools for doing this.
Re: How do I pass a data structure with CGI redirect
by beth (Scribe) on May 12, 2004 at 06:05 UTC

    I came across a similar issue recently. As tempting as it is to stuff all your data in the HTML, or in the query string, it's rarely the right approach - you add to your bandwidth and then have to parse it back out anyway.

    What I did was put the data in a database (I was using a database anyway, so the connection overhead was already there) and in the HTML just passed a unique id I could use to extract the data on the other end.

    If you're really attached to XML, you could dump your data structure to XML - there are several modules for this, XML::Dumper is one of many. Or check out Storable for a non-XML variation.

    I can't say without knowing your data whether a file or database would be better for your purposes - it all depends on what kind of data, and how much. (Which is faster for you? TIAS). If you write to a file, don't forget about locking.

Re: How do I pass a data structure with CGI redirect
by eserte (Deacon) on May 12, 2004 at 09:42 UTC
    I wonder what's the best approach if both scripts are not on the same machine and the passing data is too large to be sent via GET. My current approach is to redirect to an intermediate cgi script on the source machine, which still has access to the data. The intermediate script builds a post form with the data in it and uses an javascript onLoad handler to automatically send the form to the remote script. For browsers with disabled javascript there is still a submit button. It's ugly, but it seems to work...
      Instead of using Javascript you can use LWP to place the data on the remote CGI with a unique id, and then redirect the client to the remote script and pass the unique id to it. Instead of LWP you could also use SOAP, XML::RPC etc. This way it will work for all browsers.