0

I'm receiving a query string (from a terrible payment system whose name I do not wish to sully publicly) that contains un-encoded ampersands

name=joe+jones&company=abercrombie&fitch&other=no

parse_str can't handle this, and I don't know enough of regex to come up with my own scheme (though I did try). My hang up was look-ahead regex which I did not quite understand.

What I'm looking for:

Array
(
    [name] => joe jones
    [company] => abercrombie&fitch
    [other] => no
)

I thought about traipsing through the string, ampersand by ampersand, but that just seemed silly. Help?

4
  • Are the keys (name, company, etc.) predictable / fixed? Commented Nov 3, 2010 at 22:01
  • The keys are user generated and unpredictable :( Commented Nov 3, 2010 at 22:03
  • Then there is almost no way.... unless you can say an 'empty' value (if you parsed it as a valid query string) is 100% sure not going to happen (just loop through the result of parse_str & add the current key to the previous value if the value of the current key is an empty string. Commented Nov 3, 2010 at 22:07
  • This is a horrible horrible bug. If you have to work with a system that does this, and the developers aren't prepared to fix it, you should be making a lot of loud noises of complaint. Developers shouldn't be allowed to get away with that kind of bug. Commented Nov 3, 2010 at 22:29

2 Answers 2

3

How about this:

If two ampersands occur with no = between them, encode the first one. Then pass the result to the normal query string parser.

That should accomplish your task. This works because the pattern for a "normal" query string should always alternate equals signs and ampersands; thus two ampersands in a row means one of them should have been encoded, and as long as keys don't have ampersands in them, the last ampersand in a row is always the "real" ampersand preceding a new key.

You should be able to use the following regex to do the encoding:

$better_qs = preg_replace("/&(?=[^=]*&)/", "%26", $bad_qs);
Sign up to request clarification or add additional context in comments.

6 Comments

This looks marvelous but unfortunately will not work properly if the value has more than one ampersand in it (which is quite unlikely though).
It's close, if it could only be adapted to work with more than one ampersand.
Tatu - I adapted it to use a lookahead instead of an actual match on the second ampersand, which should allow it to work for any number of ampersands in a value.
@Amber, seems to be working now, great. Some proper RE mastery there :)
That's an impressive regex solution to a hideous problem.
|
0

You could also use the split() function to split the string by ampersands. After that, you could split again each element with the delimeter "="... something like that:

$myarray = split("&", $mystring);

foreach ($myarray as $element) {
  $keyvalue = split("=", $element);
  $resultarray[$keyvalue[0]] = $keyvalue[1];
}

print_r($resultarray);

Not tested! But you should get the idea.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.