views:

387

answers:

6

I am looking to have a list of arguments passed across in an a URL.

$url['key1']=1;
$url['key2']=2;
$url['key3']=3;
$url['key4']=4;
$url['key5']=5;
$url['key6']=6;
$url['key7']=7;

Please Note I am trying to pass this in the URL in 1 GET variable. I know this would be better done by ?key1=1&key2=2&key3=3...etc but for reasons that are too complicated to try and explain they can't be in this format.

Any suggestions how I can convert this array into something that can be passed as 1 get var in a URL string?

Thanks in advance.

+1  A: 

You could serialize them as key-value pairs when constructing the URL, putting the resultant serialized value in a single $_GET variable (e.g. data=sfsdfasdf98sdfasdf), then unserialize the $_GET["data"] variable. You'll need to use urlencode to make sure the resultant serialized values are URL-safe. Make sure you watch out for maximum URL lengths - 2083 characters in IE.

However, unless you really can't use key-value pairs in URLs (per your question), key1=foo&key2=bar... is definitely the way to go.

Dominic Rodger
You can use bzcompress() to save space as well. Also note that there may be security considerations to using serialize() that depend on what you use with the unserialize() data.
geocar
+3  A: 

You can use json_encode() or serialize()

$myUrl = 'http://www.example.com/?myKey=' . urlencode(json_encode($url));

or

$myUrl = 'http://www.example.com/?myKey=' . urlencode(serialize($url));

Using json_encode will usually give you a shorter string, but very old PHP version might not have the json_decode function available to decode it again.

The final way would be to create your own custom encoding... it could be as simple a pipe-separated values: key1|1|key2|2|key3|3
This would give you the best option for a short URL, but is the most work.

Greg
I had thought of that but the string becomes very long:serialized =:7:{s:4:"key1";i:1;s:4:"key2";i:2;s:4:"key3";i:3;s:4:"key4";i:4;s:4:"key5";i:5;s:4:"key6";i:6;s:4:"key7";i:7;}With url_enode:a%3A7%3A%7Bs%3A4%3A%22key1%22%3Bi%3A1%3Bs%3A4%3A%22key2%22%3Bi%3A2%3Bs%3A4%3A%22key3%22%3Bi%3A3%3Bs%3A4%3A%22key4%22%3Bi%3A4%3Bs%3A4%3A%22key5%22%3Bi%3A5%3Bs%3A4%3A%22key6%22%3Bi%3A6%3Bs%3A4%3A%22key7%22%3Bi%3A7%3B%7DWill the length be an issue?
Lizard
~200 characters is not really a problem... just very ugly. Try json instead
Greg
you have approx 2048 chars to work with although in theory there should be no limit: http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-an-url
seengee
@Greg - you don't say :)
karim79
{"key1":1,"key2":2,"key3":3,"key4":4,"key5":5,"key6":6,"key7":7}and %7B%22key1%22%3A1%2C%22key2%22%3A2%2C%22key3%22%3A3%2C%22key4%22%3A4%2C%22key5%22%3A5%2C%22key6%22%3A6%2C%22key7%22%3A7%7DBetter, just trying to do something a little bit more easy on the eye :(
Lizard
You can use bzcompress() if the string gets too long. A bigger problem is that there may be security problems associated with this method because the end-user can (then) directly create PHP objects of any type they like, with any value. Even if the farside simply "prints" the result, you've got an XSS attack vector.
geocar
A: 

If you don't mind dropping the key names, you can use

http://example.com?url[]=1&url[]=2&url[]=3

EDIT Keeping the key names:

http://example.com?values[]=1&values[]=2&values[]=3&keys[]=1&keys[]=2&keys[]=3

Then in your PHP script:

$url = array_combine($_GET['keys'], $_GET['values']);
soulmerge
Sorry I will need key names :(
Lizard
Ok, updated answer
soulmerge
+1  A: 

Try http_build_query:

$url['key1']=1;
$url['key2']=2;
$url['key3']=3;
$url['key4']=4;
$url['key5']=5;
$url['key6']=6;
$url['key7']=7;

echo http_build_query($url);
//echos key1=1&key2=2&key3=3&key...

What it does is converting an array into a query string using the keys and automatically takes care of url-encoding.

EDIT:

Just read your additional requirement that it should be just one variable. So nevermind this answer. If your problem was the proper encoding though you might want to give this another try.

Hope that helps.

André Hoffmann
You gave me an idea:echo $newurl = http_build_query($url,"","|");which could give me:?key1=1|key2=2|key3=3|key4=4|key5=5|key6=6|key7=7
Lizard
Isn't that what I said 5 minutes before? :|
Greg
@greg sorry! didnt see that!
Lizard
A: 

Could you solve your problem by saving the data as a HTML cookie? That way you don't have to modify the URL at all.

If you know the values in advance, you can set them from the server side when you send the user the page with your target link on it.

If you won't know the values until the user fills out a form it can still be done using JavascriptL When the user clicks the form submit you can set multiple cookies by making multiple javascript calls like: document.cookie = 'key1=test; expires=Mon, 7 Sept 2009 23:47:11 UTC; path=/'

The security model might give you some trouble if you are trying to pass this data from one domain to another though.

Al Crowley
The question still remains: how to go about encoding the data, even if you resolve where to actually put it.
geocar
+2  A: 

The recommendation to use serialize() is fine. If space is an issue, then use a combination of bzcompress() and serialize().

However, there's a security considering that hasn't been brought up, and that's that the end user (who can see and edit this url) could manipulate the data within it. You may think it's difficult, but most of the PHP-attacking worms in the wild do this to some degree or another.

If letting the user directly manipulate any of the keys or values (or replacing it with an integer, or an object, or anything else), then you should protect your script (and your users) from this attack.

A simple solution is to simply use a shared secret. It can be anything; just so long as it's unique and truly secret (perhaps you should randomly generate it at install-time). Let's say you have in your config file something like this:

define('SECRET', 'unoqetbioqtnioqrntbioqt');

Then, you can digitally sign the serialized data created with: $s=serialize($m) using $k=sha1($s.SECRET) and make the url value $k.$s

Then, before you unserialize() do this:

$v=substr($input,0,40);
$s=substr($input,40);
if ($v != sha1($s.SECRET)) { die("invalid input"); }
$m=unserialize($s);

This way, you know that $m is the same as the original value that you serialized.

If you like, you can use the following drop-in replacements:

define('SECRET','buh9tnb1094tib014'); // make sure you pick something else
function secureserialize($o) {
  $s=serialize($o);
  return sha1($s.SECRET).$s;
}
function secureunserialize($i) {
  $v=substr($i,0,40);$s=substr($i,40);
  if ($v!=sha1($s.SECRET)){die("invalid input");}
  return unserialize($s);
}
geocar