6

Assuming www.mydomain.com?param1=example as an example.

What is the best way to store a second parameter that is a list of key value pairs? At the minute I use &param2=key|value,key|value. I separate the key from the value using a vertical line, and the pairing with a comma, everything after the equals is encoded using encodeURIComponent(). This works fine.

However, the user has control of the value... And as sensible human beings we all know that the first thing the user will probably do is stick a vertical bar or a comma as one of the values breaking my parameter parser. Is there a better way to do this? I've seen PHP users talking about storing associated arrays in urls but I'm looking for a pure javascript solution.

Jon Wells
  • 4,191
  • 9
  • 40
  • 69

4 Answers4

7

PHP (and other server-side languages) support passing arrays in the query string.

www.mydomain.com?param1=example&param2[key1]=value1&param2[key2]=value2

PHP will parse the GET string as such:

array(2) {
  ["param1"]=>
  string(7) "example"
  ["param2"]=>
  array(2) {
    ["key1"]=>
    string(6) "value1"
    ["key2"]=>
    string(6) "value2"
  }
}

If you don't pass keys, it will be become a numeric array:

www.mydomain.com?param1=example&param2[]=value1&param2[]=value2

Will be parsed as:

array(2) {
  ["param1"]=>
  string(7) "example"
  ["param2"]=>
  array(2) {
    [0]=>
    string(6) "value1"
    [1]=>
    string(6) "value2"
  }
}

UPDATE: You can also parse the query string in JavaScript.

Here is a simple jQuery plugin I made:

$.parseQuery = function(str) {
    var ret = {};
    $.each(str.split("&"), function() {
        var data = this.split('='),
            name = decodeURIComponent(data.shift()),
            val = decodeURIComponent(data.join("=")).replace('+', ' '),
            nameVal = name.match(/(.*)\[(.*)\]/);

        if (nameVal === null) {
            ret[name] = val;
        }
        else {
            name = nameVal[1];
            nameVal = nameVal[2];
            if (!ret[name]) {
                ret[name] = nameVal ? {} : [];
            }
            if ($.isPlainObject(ret[name])) {
                ret[name][nameVal] = val;
            }
            else if($.isArray(ret[name])){
                ret[name].push(val);
            }
        }
    });
    return ret;
};

Then you can do: $.parseQuery('param1=example&param2[]=value1&param2[]=value2');.

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • is this possible to do this with just Javascript? To parse the get string in this way? The parameters are only used to query local data. I effectively just use parameters to allow the user to bookmark filtered data – Jon Wells Aug 30 '12 at 10:14
  • @CrimsonChin: Yes it is. `window.location.search` contains the get string. You can then parse it in JavaScript. You can use this method I wrote: https://gist.github.com/3528917 :-) (Note: `window.location.search` contains the `?`, you you'll need to call it like: `$.parseQuery(window.location.search.substring(1))`). – gen_Eric Aug 30 '12 at 13:50
  • I don't have access to the query string - I think its a JQM thing, because of the # tag. That being said, I can split the window.location.href to get the query string and your github code works excellently. Could I suggest putting the code in your answer? I think its very valuable to the question/answer. Its your code, so the choice is yours. Thanks either way – Jon Wells Aug 31 '12 at 08:15
0

A possible solution would be to escape the pipe and commas in the user input before posting them to your url.

That means sanitising the user input values and replacing | and , with something that doesn't break your code or just stripping them altogether.

Ohad
  • 1,719
  • 1
  • 16
  • 20
  • Problem is the values are query parameters and they need to match the data they are querying – Jon Wells Aug 29 '12 at 14:33
  • You will need to have some kind of encoding/decoding on the way. Keep in mind ampersands will also break your array. – Ohad Aug 29 '12 at 14:35
0

To prevent casual tampering, you could add a checksum and base-64 encode your values then encodeURIComponent() the resulting string. (See How can you encode to Base64 using Javascript? and A JavaScript CRC32.)

Of course, this won't prevent someone who's really determined from messing with your values, but it will slow down people who just like to twiddle URLs.

Community
  • 1
  • 1
JamieSee
  • 12,696
  • 2
  • 31
  • 47
-1

When I think of serializing a list of key-value pairs, I immediately think of using a query-string.

For basics (JSON used to show deserialization):

foo=bar&foo=baz&fizz=buzz&alpha&beta=

is essentially:

{
    foo: [
        'bar',
        'baz'
    ],
    fizz: 'buzz',
    alpha: null,
    beta: ''
}

But special characters have to be escaped:

foo=bar%26baz

is essentially:

{
    foo: 'bar&baz'
}

What this means is that you can pass a query-string as a value in another query-string:

foo=bar%3Dbaz%26fizz%3Dbuzz

is essentially:

{
    foo: 'bar=baz&fizz=buzz'
}

And foo can be parsed to produce:

{
    bar: baz,
    fizz: buzz
}

That all being said, it's very easy to make mistakes while encoding/decoding, and as soon as you start double-encoding and double-decoding you're guaranteed to run into issues. If you can, use a single query string to contain all the necessary data, and don't embed a query-string within a query-string.

zzzzBov
  • 174,988
  • 54
  • 320
  • 367