Solved

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

Posted on 2013-11-27
15
1,348 Views
Last Modified: 2013-11-27
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
0
Comment
Question by:thenelson
  • 7
  • 5
  • 3
15 Comments
 
LVL 42

Expert Comment

by:Chris Stanyon
Comment Utility
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
 
LVL 42

Expert Comment

by:Chris Stanyon
Comment Utility
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
 
LVL 39

Author Comment

by:thenelson
Comment Utility
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
 
LVL 42

Accepted Solution

by:
Chris Stanyon earned 500 total points
Comment Utility
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
 
LVL 39

Author Comment

by:thenelson
Comment Utility
>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
 
LVL 42

Expert Comment

by:Chris Stanyon
Comment Utility
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
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 39

Author Closing Comment

by:thenelson
Comment Utility
That works great!  Thanks!! I learned quite a few things.
0
 
LVL 39

Author Comment

by:thenelson
Comment Utility
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
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
Do you agree?
Let me put it this way: http://xkcd.com/292/
0
 
LVL 39

Author Comment

by:thenelson
Comment Utility
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
 
LVL 108

Expert Comment

by:Ray Paseur
Comment Utility
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
 
LVL 42

Expert Comment

by:Chris Stanyon
Comment Utility
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
 
LVL 39

Author Comment

by:thenelson
Comment Utility
yep, that's what I did.
Thanks again
0
 
LVL 39

Author Comment

by:thenelson
Comment Utility
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

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Use these top 10 tips to master the art of email signature design. Create an email signature design that will easily wow recipients, promote your brand and highlight your professionalism.
Although it can be difficult to imagine, someday your child will have a career of his or her own. He or she will likely start a family, buy a home and start having their own children. So, while being a kid is still extremely important, it’s also …
In this tutorial viewers will learn how to embed videos in a webpage using HTML5. Ensure your DOCTYPE declaration is set to HTML5: "<!DOCTYPE html>": Use the <video> tag to insert a video. Define the src as the URL of your video; this is similar to …
Any person in technology especially those working for big companies should at least know about the basics of web accessibility. Believe it or not there are even laws in place that require businesses to provide such means for the disabled and aging p…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now