foreach($_POST as $key => $value) not getting every $key

Reference (additional problem found to this question): http://www.experts-exchange.com/Software/Internet_Email/Web_Browsers/Q_28295433.html

I have a form which has several fields with the same name. It is posting the following data:
"...Diagnoses=HA&Diagnoses=Migraine&Diagnoses=TBI&Diagnoses=TMJ..."
I am using the following code in the php script which only appends the last Diagnoses field ("TMJ") to the string  $postData:
foreach($_POST as $key => $value) {
    $postData .= $key.'='.$value."\r\n";
}

Open in new window


I would like to continue using fields with the same name because I would like to append those fields together on one line like this:
foreach($_POST as $key => $value) 
{
    If ($key == $peviousKey)
	{
		echo "we are here<br>";
		$postData .= ", ".$value;
	}
	else
	{
		$postData .= "\r\n".$key.'='.$value;
	}
	$peviousKey = $key;
}

Open in new window

var_dump($_POST); displays only the last Diagnosis field ("TMJ") in the array.

I am thinking of renaming the duplicate fields to:
Diagnosis01
Diagnosis02
Diagnosis03
etc
and then use substr ($key, 0, -2) to compare with the $peviousKey and append the "duplicate" $keys together.

Any other ideas on how to handle this.?  TIA
LVL 39
thenelsonAsked:
Who is Participating?
 
Chris StanyonCommented:
There's absolutely no reason to rename your fields - this will create problems later on. Naming your fields as diagnoses[] is the same as naming them diagnoses[0], diagnoses[1], diagnoses[2] etc - it's just easier to leave them out and the browser take care of the indexes.

To get your code to work, just add an extra check in to see if the $value is an array

foreach($_POST as $key => $value):
	if (is_array($value)):
		$postData .= $key.'='.implode(',', $value)."\r\n";
	else:
		$postData .= $key.'='.$value."\r\n";	
	endif;
endforeach;

Open in new window

If the value is an array (such as diagnoses) it will join them all together with the implode function.
0
 
Chris StanyonCommented:
If you want to name form fields the same then you need to name them as an array.

<input type="text" name="diagnoses[]" />
<input type="text" name="diagnoses[]" />
<input type="text" name="diagnoses[]" />
<input type="text" name="diagnoses[]" />

Open in new window

Then your POST array will contain a key of diagnoses, that is an array:

foreach ($_POST['diagnoses'] as $diag):
    echo $diag;
endforeach;

Open in new window

0
 
Chris StanyonCommented:
As a follow on, if you want all the diagnoses in one string, then use the PHP implode function:

$diagnoses = implode(",", $_POST['diagnoses']);

Open in new window

That will give you string with each of the diagnoses, separated by a comma.
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
thenelsonAuthor Commented:
Chris,
Thanks for your response.

So as in your example, I could use name="diagnoses[]" for each field. I wouldn't need to use:
name="diagnoses[0]"; name="diagnoses[1]"; etc?

Would foreach($_POST as $key => $value) pick up each item in the subarray or would I have to include foreach ($_POST['diagnoses'] as $diag) also?

Using your suggestion, how would I build a string like this:
...
PreviousField=some text
Diagnoses=HA, Migraine, TMJ
PostField=some other text
...

I am thinking of renaming the duplicate fields to: "Diagnoses01,"; "Diagnoses02,"; etc. where the comma (or colon, semicolon, period, etc) at the end communicates the separator to use and then use this code to build my output:
foreach($_POST as $key => $value) 
{
    If (substr ($key, 0, -3) == $peviousKey)
	{
		$postData .= substr ($key, 0, -1).$value;
	}
	else
	{
		$postData .= "\r\n".$key.'='.$value;
	}
	$peviousKey = substr ($key, 0, -3);
}
//remove first "\r\n"
$postData = substr ($postData,2);

Open in new window

Do you see a problem with this?
0
 
thenelsonAuthor Commented:
>There's absolutely no reason to rename your fields
I am going to have to rename the Diagnoses fields to Diagnoses[]. Yes?

The code you suggested will work with multiple subarrays?  It will keep the different subarrays separate? For example:
<input type="text" name="diagnoses[]" />
<input type="text" name="diagnoses[]" />
<input type="text" name="diagnoses[]" />
<input type="text" name="diagnoses[]" />
<input type="text" name="symptom[]" />
<input type="text" name="symptom[]" />
<input type="text" name="surgery[]" />
<input type="text" name="surgery[]" />

Open in new window

>There's absolutely no reason to rename your fields - this will create problems later on.
I like your solution better than mine but out of curiosity, what problems could I expect later on. I realize I would need to be careful to avoid field names that are the same except the last three characters but anything other than that?

I didn't know that php had an alternate if:-endif;    foreach:-endforeach; syntax as opposed to using curly braces. Good to know.
0
 
Chris StanyonCommented:
OK. You're not renaming your fields - your just turning them into arrays by adding the square brackets - they'll still be called diagnoses, but instead of being a single value, it will be passed as an array.

In the sample HTML you've provided, your POST array will contains 3 keys - diagnoses, symptom, surgery and each of these keys will be an array containing the values.

When I say it will cause problems later on, there are a couple of things to bear in mind. The more complicated the code, the more likely there is for a typo. In your first post you mentioned calling your fields Diagnoses01, Diagnoses02 etc, and then in the post above you mention about the last 3 characters being the same - I'm guessing you meant the last 2 characters, but already inconsistency is creeping in.

The code you've posted assumes that all the diagnosis fields will be kept together, so you are relying on the $previousKey value to group them. What if you need to re-design your form and you need something like:

<input type="text" name="diagnoses[]" />
<input type="text" name="symptom[]" />
<input type="text" name="diagnoses[]" />
<input type="text" name="symptom[]" />
<input type="text" name="diagnoses[]" />
<input type="text" name="symptom[]" />

Your code won't work.

There are plenty of other examples of why you shouldn't do it your way, but it comes down to this: it's just not considered best-practice!

As for the alternative PHP control blocks - I find it easier to use these when you have lots of nested blocks - if statements inside of while loops inside of foreach loops etc - it's very easy to lose track of the brackets and your code ends up with 7 closing brackets and no indication of what they're closing!!
0
 
Ray PaseurCommented:
ChrisStanyon has given you excellent advice here.  

I would just like to add a security note.  Never iterate over the $_POST array (or any external data, for that matter).  Your script should know what elements are expected in the request and should only process those elements.  This is a security issue that goes to the heart of "accept only known good values."  Since the $_POST array is created by PHP from external data, it is by definition tainted.  Therefore you cannot know that it contains good or bad values until you filter the external data.  An example of why this matters is in AntiPHPractice Number 18.

See http://www.laprbass.com/RAY_temp_thenelson.php

<?php // RAY_temp_thenelson.php
error_reporting(E_ALL);


// DEMONSTRATE HOW TO HANDLE EXTERNAL FORM DATA
// SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28305093.html


// THESE ARE THE ACCEPTABLE COLORS
$colors = array
( 'red'
, 'green'
, 'blue'
)
;

// IF THERE IS A POST-METHOD REQUEST TO SET THE COLOR
if (!empty($_POST['color']))
{
    // CHECK THAT THE POST DATA MATCHES THE FORM DATA
    if (in_array($_POST['color'], $colors))
    {
        // NORMALIZE / FILTER THE EXTERNAL DATA HERE
        $color = strtolower($_POST['color']);
        $color = ucFirst($color);
        echo PHP_EOL . "THE COLOR IS $color";
    }
    else
    {
        trigger_error('SCRIPT UNDER ATTACK', E_USER_ERROR);
    }
}

// CREATE THE RADIO BUTTONS FOR THE COLORS
$radios = NULL;
foreach ($colors as $rgb)
{
    $radios .= '<input type="radio" name="color" value="' . $rgb . '" />' . "$rgb<br>";
}

// CREATE THE FORM USING HEREDOC SYNTAX
$form = <<<FORM
<form method="post">
$radios
<input type="submit" />
</form>
FORM;

echo $form;

Open in new window

Best regards, ~Ray
0
 
thenelsonAuthor Commented:
That works great!  Thanks!! I learned quite a few things.
0
 
thenelsonAuthor Commented:
Ray,

Thanks for your input.  I can see what you are saying: that anyone can post data to my php script and this could be dangerous. I can see how important this would be if the script acts on the data. In this case, the only thing I am doing is building a string and writing that to a text file which I then view. So I don't think anything bad would happen if someone sent me bogus data other than I would see garbage and not use it.

Do you agree?
0
 
Ray PaseurCommented:
Do you agree?
Let me put it this way: http://xkcd.com/292/
0
 
thenelsonAuthor Commented:
A followup:
Is there an easy way to not include empty array elements using
if (is_array($value)):
		$postData .= $key.'='.implode(', ', $value).".\r\n";

Open in new window


I am getting:
     1986, fusion, , , , , 1996, esi, , , , .
I would like to eliminate the multiple commas.
0
 
Ray PaseurCommented:
Sure, just replace contiguous commas with single commas.  Something like this.  You'll have to experiment with it some to get the regular expression exact for your work.

<?php 
$rgx = '#,,+#';
$dat = '1986, fusion,,,,,1996,esi,,,';
echo preg_replace($rgx, ',', $dat);

Open in new window

0
 
Chris StanyonCommented:
Sure - just run $value through array_filter();

if (is_array($value)):
    $value = array_filter($value);
    $postData .= $key . '=' . implode(', ', $value) . PHP_EOL;

Open in new window

You might also want to use the PHP_EOL constant instead of the \r\n - again, good practice :)
0
 
thenelsonAuthor Commented:
yep, that's what I did.
Thanks again
0
 
thenelsonAuthor Commented:
What I tried first was similar to Ray's suggestion. I used str_replace to remove the multiple commas. That worked.

Chris' suggestion works too and i believe is more elegant.

Thanks again.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.