I seriously hope I'm wrong here, but it seems to me that PHP's default "handling" of multiple same-named form fields is... to ignore all bar the last one. That's not to say the values aren't still accessible for one to deal with via bespoke code, but... come on PHP. Really?
Here's a repro:
<?php
// formBasic.php
$colours = array("whero", "karaka", "kowhai", "kakariki", "kikorangi", "tawatawa", "mawhero");
$numbers = array("tahi","rua","toru","wha","rima","ono","whitu","waru","iwa","tekau");
?>
<form method="post" action="dumpPost.php">
Colours:<br>
<?php foreach($colours as $colour){ ?>
<input type="checkbox" name="colour" value="<?= $colour ?>"><?= $colour ?><br>
<?php } ?>
<hr>Number:<br>
<?php foreach($numbers as $number){ ?>
<input type="checkbox" name="number" value="<?= $number ?>"><?= $number ?><br>
<?php } ?>
<input type="submit" name="btnSubmit" value="Submit">
</form>
Here I have an array of colours and numbers, and make a series of checkboxes which one can - obviously - select zero or more of:
Or if we had
this.sameFormDieldsAsArray=true
set in Application.cfc, we'd get this:(which is how it always should have bloody been, but that's another story).
Anyway, with PHP we get this:
I'm using dBug to emulate
<cfdump>
with PHP here. Initially I thought this was a bug in dBug, but no... it's how the $_POST
variable works. In that, basically, it doesn't. This is a fundamental cock-up in PHP I reckon, because it simply is not representing the post data correctly.One can work around this in a coupla ways. The easiest is to name the HTML controls with array notation
name="colour[]"
. But I really think that's pollution. The mark-up shouldn't need to contend with the shortcomings of the back-end processing.The other way is to DIY the unpacking of the post data. This is incredibly jerry-built, but sits better with me than messing with the HTML. This is my proof-of-concept function which deals with it, resulting in the same things CFML would offer if
this.sameFormDieldsAsArray=true
// dumpPost.php
function unpackPost(){
$post = array();
foreach (explode('&', file_get_contents('php://input')) as $keyValuePair) {
list($key, $value) = explode('=', $keyValuePair);
if (!array_key_exists($key, $post)){
$post[$key] = $value;
continue;
}
if (is_array($post[$key])){
$post[$key][] = $value;
continue;
}
$temp = $post[$key];
$post[$key] = array($temp, $value);
}
return $post;
}
$post = unpackPost();
new dBug($post);
(I've linked to the stuff I needed to look-up in the docs, as they'd be new things I've mentioned on this blog).
Notes:
php://input
is where PHP sticks the raw post dataexplode()
converts a string to an array, using a substring as the delimiter. Kinda analogous tolistToArray()
, except the delimiter can be more than one character. So like a senisble implementation oflistToArray()
.
- Is the key is not already in the array, just add it in as a simple value;
- If it's already there, and its value is an array, then append the current key/value value to said array;
- lastly it's the case that previously (1) was fulfilled - so the key's value is currently the first simply value - but now we have a second value so we need to convert the key's value to an array, containing the initial first value and the new value.
And that outputs like this:
So that's fine.
But, really? Should we need to jump through hoops like this? Did the person writing the implementation of the code which populates
$_POST
not stop to think that... it doesn't work? At no point in PHP's history did anyone go "shit... better fix that?"Hopefully some PHP-savvy person will happen upon this and explain to me why I've got the wrong end of the stick. I did spend some time going "no... nonono... this can't be right?" whilst googling and stackoverflowing. Indeed the basis for the UDF above was gleaned from Stack Overflow (although I thought their implementation was a bit leaden, so changed it a bit).
Sigh.
Back to my studies...
--
Adam