Parse form submission data from query string / jQuery.serialize() containing duplicate keys without losing values

3.7k views Asked by At

I am trying to figure out how I can handle possible duplicate array keys.

I have this form with a select dropdown which can select multiple options (more than 1). And I am using jQuery.serialize() to serialize the form on submit.

The serialized string for a multi-select element would look like so:

select=1&select=2&select=3 // assuming I selected first 3 options.

Now in the PHP side, I have the following code to handle the "saving" part into a database.

$form_data = $_POST['form_items'];

$form_data = str_replace('&','####',$form_data);
$form_data = urldecode($form_data);
$arr = array();
foreach (explode('####', $form_data) as $part) {
    list($key, $value) = explode('=', $part, 2);
    $arr[$key] = $value;
}

This all works for the rest of the form elements, but when it comes to the select element, it only picks the last selected key/value pair. So my array now looks like this:

Array ( [select_element] => 3)

What I need, is for it to look like:

Array ( [select_element] => '1,2,3')

So I guess what I am asking is based on my code, how can I check if a key already exists and if it does, append to the $value.

6

There are 6 answers

0
AudioBubble On BEST ANSWER

Ok, I was able to resolve this issue by using the following code:

    if (array_key_exists($key, $arr)) {
        $arr[$key] = $arr[$key].','.$value;
    } else { 
        $arr[$key] = $value;
    }

So now the loop looks like this:

foreach (explode('####', $form_data) as $part) {
    list($key, $value) = explode('=', $part, 2);

    if (array_key_exists($key, $arr)) {
        $arr[$key] = $arr[$key].','.$value;
    } else { 
        $arr[$key] = $value;
    }
}

This will essentially string up the value together separated by a comma which can then be exploded out into an array later.

6
Milad Naseri On

You should change your client-side code to send the augmented value: array.join(","); and use that in your PHP side. Because when your data reaches your script, the other values have already been lost.

3
rabusmar On

If you can modify the client-side code, I would rather change the name of the select to select[], that way it will be parsed as an array in your server script.

0
animuson On

You can't have multiple keys with the same name... They're unique keys. What it's doing is setting select = 1, then select = 2, then select = 3 and you end up with your final value of 3.

If you want to allow multiple choices in your select menu, you should change the name of the element so that it submits that data as an array, rather than multiple strings:

<select name="select[]" multiple="multiple">

which should result in something like this instead:

select[]=1&select[]=2&select[]=3

and when PHP requests that data, it will already be an array:

$data = $_POST['select'];
echo print_r($data); // Array(1, 2, 3)
0
Jason Brumwell On

This should give you the solution you require

$form_data = str_replace('&','####',$form_data);
$form_data = urldecode($form_data);
$arr = array();

foreach (explode('####', $form_data) as $part) {
    list($key, $value) = explode('=', $part, 2);

    if (isset($arr[ $key ])) {
        $arr[$key] = ','.$value;
    } else {
        $arr[$key] = $value;
    }
}
2
Francis Avila On

PHP has its own way of encoding arrays into application/x-www-form-urlencoded strings.

PHP's deserialization of x-www-form-urlencoded is implemented by parse_str(). You can think of PHP as running these lines at the beginning of every request to populate $_GET and $_POST:

parse_str($_SERVER['QUERY_STRING'], $_GET);
parse_str(file_get_contents('php://input'), $_POST);

parse_str() creates arrays from the query string using a square-bracket syntax similar to its array syntax:

select[]=1&select[]=2&select[]=3&select[key]=value

This will be deserialized to:

array('1', '2', '3', 'key'=>'value');

Absent those square brackets, PHP will use the last value for a given key. See this question in the PHP and HTML FAQ.

If you can't control the POSTed interface (e.g., you're not able to add square-brackets to the form), you can parse the POST input yourself from php://input and either rewrite or ignore the $_POST variable.

(Note, however, that there is no workaround for multipart/form-data input, because php://input is not available in those cases. The select=1 and select=2 will be completely and irretrievably lost.)