Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

CGI : How to put an "&" into a GET-parameter

by CountZero (Bishop)
on Jan 27, 2003 at 22:49 UTC ( [id://230388]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Fellow Monks,

I have this bunch of Perl-scripts which together make a nice dynamic website.

Now, for various reasons I must place in a web-page an href-link to another script. This other script expects to receive a number of parameters through the GET-protocol, which I therefore encode into the URL put into the href.

Say that the href turns out to be href='script.pl?company=IBM&place=Brussels'. This works nice and fine: script.pl happily obtains both parameters (thanks to CGI.pm of course) and outputs another dynamic webpage.

Now it comes to pass that the name of the company is "Smith & Jones" and the href becomes href='script.pl?company=Smith & Jones&place=Brussels'.

All of a sudden, script.pl sees only "Smith " in the company -parameter and a third parameter "Jones" pops into being.

Obviously the "&" between "Smith" and "Jones" was seen to be a delimiter, rather than part of the company-parameter.

Vainly I tried to find a way to escape this "&": All to no avail, CGI.pm seems to unescape all "&"-entities prior to parsing the URL for the GET-parameters.

I looked through the CGI-docs but could not find a solution.

Does anyone has a suggestion how to sneak in an "&" into a GET-parameter?

Although I do not think it has anything to do with this problem, I mention that my scripts do not directly output HTML, but XML which get server-side transformed into HTML by XSLT.

CountZero

"If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Replies are listed 'Best First'.
•Re: CGI : How to put an "&" into a GET-parameter
by merlyn (Sage) on Jan 28, 2003 at 02:51 UTC
    ... href='script.pl?company=IBM&place=Brussels'. This works nice and fine
    No, that was always incorrect. Your browser was letting you get away with mis-encoded data, and now when you actually had text where it makes a difference, you got bit.

    Learn to construct your URLs using the proper encoding, and you would not have had to work on the edge cases.

    When converting from filenames or data to URLs, URI-encoding should be used. The URI module is good for that.

    When including a URL in HTML code, HTML-entity-encoding should be used. The HTML::Entities module is good for that.

    If you're not doing both to something that appears in HREF='...', you are putting out broken HTML. Yours was an example of this. Some of the other answers in this thread were good, but some were bad. {sigh} The amount of cargo cult around this problem is amazing.

    For gun = Smith & Wesson and drink = Jack Daniels, you'd use code like this:

    use URI; use HTML::Entities; my $u = URI->new("/my/cgi"); $u->query_form("gun" => "Smith & Wesson", drink => "Jack Daniels"); print '<A HREF="', encode_entities("$u"), '">', encode_entities("shoot with Smith & Wesson, and drink Jack Daniels") +, '</A>', "\n";
    which correctly prints:
    <A HREF="/my/cgi?gun=Smith+%26+Wesson&amp;drink=Jack+Daniels">shoot wi +th Smith &amp; Wesson, and drink Jack Daniels</A>

    Note that the HREF parameter contains examples of both URI and HTML escaping. This is necessary. This is the proper way. If anyone else tells you different, they've not read the RFCs or consulted the experts. (Such as the code that runs this site, which when I checked a moment ago, was still broken for HTML.)

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      Interesting; I knew entity encoding in attributes (such as href) was permitted, but I didn't know it was required.

      One minor additional suggestion: make that <a href...</a>. Uppercase tags were deprecated in HTML 4.0 and are invalid in XHTML (because XML is case-sensitive). Not that any actual browser cares, of course.

       --jonadab

      Such as the code that runs this site, which when I checked a moment ago, was still broken for HTML.

      Yes, I noticed that a few weeks back when I was working on upgrading [link] handling. I had always assumed that we were using CGI.pm to build links (since we use CGI.pm for quite a few other things).

      Another thing I noticed was that quite a few big sites, including Google don't handle ";" for separating CGI parameters, which was disappointing.

                      - tye
      You are right about the importance of URI and HTML encoding. For this reason, it is a good idea to use the semicolon as the parameter separator instead of the ampersand. Using a semicolon means that URL attributes don't need HTML entity encoding. The problem characters will be caught by the URI encoding. CGI.pm parses semicolons. It will use semicolons if the $USE_PARAM_SEMICOLONS is defined. Some homegrown CGI parsers might not handle them but people should avoid those in any case.
      <A HREF="/my/cgi?gun=Smith+%26+Wesson;drink=Jack+Daniels">
Re: CGI : How to put an "&" into a GET-parameter
by BazB (Priest) on Jan 27, 2003 at 23:03 UTC

    Use URI::Escape.

    Cheers

    BazB.


    If the information in this post is inaccurate, or just plain wrong, don't just downvote - please post explaining what's wrong.
    That way everyone learns.

Re: CGI : How to put an "&" into a GET-parameter
by Flame (Deacon) on Jan 27, 2003 at 22:59 UTC

    Replace the "&" with "%26". CGI.pm should be able to convert it back for you. In this case the best thing to do is try submitting it via a form and see what it comes out as... this was done by typing & in the yahoo search field and looking at the query string :)

    Good luck. :)





    My code doesn't have bugs, it just develops random features.

    Flame ~ Lead Programmer: GMS (DOWN) | GMS (DOWN)

      Note: Don't let anything try to escape already escaped text.



      My code doesn't have bugs, it just develops random features.

      Flame ~ Lead Programmer: GMS (DOWN) | GMS (DOWN)

Re: CGI : How to put an "&" into a GET-parameter
by valdez (Monsignor) on Jan 27, 2003 at 23:29 UTC

    You can build your query string using URI::Escape as suggested by BazB, but you can also do something like this:

    $a = CGI->new({'id'=>'A-001', 'song'=>'A song', 'performers'=> 'Ike & Tina Turner'}); print $a->query_string, "\n";

    Ciao, Valerio

    Update: merlyn's solution below is better

Re: CGI : How to put an "&" into a GET-parameter
by Jenda (Abbot) on Jan 28, 2003 at 00:40 UTC

    To add to the examples:

    use CGI::Enurl; $href = 'script.pl?' . enurl({ company => 'Smith & Jones', place => 'Brussels' }); If you happen to have Interpolation.pm (0.68) you may do this:<code> use CGI::Enurl; use Interpolation '?:@->$' => sub { '?'.enurl({@_})}; print qq{<a href="script.pl$?{company => 'Smith & Jones', place => 'Br +ussels'}">click here</a>\n};
    Jenda
Re: CGI : How to put an "&" into a GET-parameter
by CountZero (Bishop) on Jan 28, 2003 at 06:49 UTC

    Thank you all for your answers! I will go for the solution proposed by merlyn as this seems to be the most general one.

    I probably could just manage by replacing the "&" by its numeric enity representation, but surely soon some name will show up which breaks this again.

    Thanks again and ++ to all of you!

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: CGI : How to put an "&" into a GET-parameter
by Wysardry (Pilgrim) on Jan 28, 2003 at 01:13 UTC

    Do you still have this problem if you force the newstyle_urls pragma for CGI.pm?

    __________
    "Every program has at least one bug and can be shortened by at least one instruction -- from which, by induction, one can deduce that every program can be reduced to one instruction which doesn't work." -- (Author Unknown)

Re: CGI : How to put an "&" into a GET-parameter
by Mr. Muskrat (Canon) on Jan 27, 2003 at 23:01 UTC

      HTML encoding is different than URI encoding. Ampersand for HTML is &amp; or &#x26;. Ampersand for URIs using ASCII encoding is %26.


      Seeking Green geeks in Minnesota

      So use escape(), from CGI::Util. It comes with, and is also imported into CGI.pm. You can use it as a function, or as a class/object method:
      $escaped = CGI::escape($string); $escaped = CGI->escape($string); $escaped = $cgi->escape($string); # if $cgi is your CGI object
      No, he wants to put them in a URL, not on a HTML page. Upd.: doh.. I should refresh before replying.

      Makeshifts last the longest.

Re: CGI : How to put an "&" into a GET-parameter
by thatguy (Parson) on Jan 27, 2003 at 23:00 UTC
    Why not change the data before you send it?
    $data=~ s/&/&#38;/g;

    -phill

    Update: Brain bungling by me. Untested knee jerk answer that does not work. Go with Flame's answer for what I was trying to say.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (6)
As of 2024-04-25 15:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found