How do I echo each value of a foreach loop? - php

Not sure if the question title actually makes sense.
Anyway, what I'd like to do is be able to echo an individual value from a foreach loop.
Here's my code:
$headlines = array('primary_headline' => $_POST['primary_headline'], 'secondary_headline' => $_POST['secondary_headline'], 'primary_subline' => $_POST['primary_subline'], 'secondary_subtext' => $_POST['secondary_subtext']);
$city_name = "Dallas";
$ref_name = "Facebook";
$searches = array('$city_name', '$ref_name');
$replacements = array($city_name, $ref_name);
if(isset($headlines)) {
foreach($headlines as $headline) {
$headline = str_replace($searches, $replacements, $headline);
echo($headline['primary_headline']); // I thought this would do the trick
}
}
I thought that this would've echoed my city is Dallas when my city is $city_name was posted, unfortunately, this isn't the case and it merely echoes msps, which is the first letter of each input value:
<input name="primary_headline" type="text" value="my city is $city_name" />
<input name="secondary_headline" type="text" value="secondary headline" />
<input name="primary_subline" type="text" value="primary subline" />
<input name="secondary_subtext" type="text" value="secondary subline" />
<input type="submit" value="submit" />
If anyone could point me in the right direction, it would be very much appreciated!! :)

$searches = array('$city_name', '$ref_name');
The single quotes are making $searches literally contain the word $city_name, not the VALUE of $city_name. You don't need quotes while assigning variables:
$searches = array($city_name, $ref_name);
unless, of course, you're doing some kind of templating system and trying to do variable interpolation without eval().

Change
echo($headline['primary_headline']); // I thought this would do the trick
To
echo($headline) . PHP_EOL; // I thought this would do the trick
When you are using foreach you do not need to specify an index to the element, because foreach will handle iterating for you, so when you dereference something inside the loop, you are asking for a character from the string. Here you get the first character because 'primary_headline' is being interpreted as a 0.

$headlines = array('primary_headline' => $_POST['primary_headline'], 'secondary_headline' => $_POST['secondary_headline'], 'primary_subline' => $_POST['primary_subline'], 'secondary_subtext' => $_POST['secondary_subtext']);
This creates an array with key=>value pairs, not a multidimensional array. Looping through this array in a foreach loop will return only the values, i.e. $_POST['primary_headline'] for the first iteration, $_POST['secondary_headline'] for the second iteration, etc. This is why you're unable to access $headline['primary_headline'].
If you want to access "my city is Dallas" per your example, simply echo $headlines['primary_headline'].
If you want to echo each value:
foreach($headlines as $headline) {
echo $headline . PHP_EOL;
}

For good measure figured I should close this question with an answer (I've already placed it in the comments section as I couldn't add an answer).
The ampersand (&) must be used in order to assign a reference to the original array $headlines instead of copying it's valuables, thus updating it with any values created within the foreach() loop.
So, my code is now;
$headlines = array('primary_headline' => $_POST['primary_headline'], 'secondary_headline' => $_POST['secondary_headline'], 'primary_subline' => $_POST['primary_subline'], 'secondary_subtext' => $_POST['secondary_subtext']);
$city_name = "Dallas";
$ref_name = "Facebook";
$searches = array('$city_name', '$ref_name');
$replacements = array($city_name, $ref_name);
if(isset($headlines)) {
foreach($headlines as &$headline) {
$headline = str_replace($searches, $replacements, $headline);
}
echo ($headlines['primary_headline']) // This now has the value of $_POST['primary_headline'] along with the str_replace() function assigned to $headline
}

Related

Using form inputs in PHP to populate nested objects

I am trying to process the submitted results for a form, containing data for a number of employees. The form inputs have names like "employees[1]_firstName" which needs to map to the PHP variable $companydata->employees[1]->firstName
When populating the $_POST array, PHP sees square brackets, and tries to make a multi-dimensional array, but gets it wrong (ignoring everything after the opening bracket)
This replicates $_POST but without the corrupted array keys: Note that I've taken out a foreach loop to simplify the question.
$post_data = explode('&', file_get_contents("php://input"));
// Result: $post_data = array('employees%5B1%5D_firstName=Timothy'
list($key, $value) = explode('=', $post_data[0]);
$key = urldecode($key);
$value = urldecode($value);
// Result: $key = 'employees[1]_firstName', $value = 'Timothy'
However things go wrong when I try to use variable variables:
$post_key_parts = explode('_', $key);
// Result: $post_key_parts = array([0] => 'employees[1]', [1] => 'firstName')
$Companydata->$post_key_parts[0]->$post_key_parts[1] = $value;
// Expected result: Element [0] in array $employees => 'Timothy'
The actual result is a variable with square brackets in its name '$employees[0]',
and no change to the $employees array. Putting curly brackets round the {$post_key_parts[0]} doesn't help.
I am trying to find a flexible solution that will also work for names of different lengths eg: employees[0]_address_lines[2] or employees[0]_addresses[1]_postcode
I'm happy to avoid the sin of variable variables, but I can't think of an elegant way to do it with regexes or something like that.
I would suggest you change the inputs' names. To make use of the built-in features of PHP. [] creates an array for you, use arrays then, as you are intended to use them.
I had the same problem and came up with this:
//HTML part
<input name="employee_firstName[]">
<input name="employee_address[]">
//PHP part
<?php
$info = array("firstName", "address")
foreach ($info as $i) {
foreach ($_POST["employee_".$i] as $k => $v) {
$companydata->employees[$k]->$i = $v;
}
}
?>
NOTE I don't think you can do this for things like employees[0]_address_lines[2]. Or maybe try employees[0][address_line][] and use it as an array, but I'm not sure that works.

Creating an array from textarea

I am trying to put some data into Amazon's simpledb. I need to enter multiple values for an attribute (comma separated), but as I have the script now it's entering all the values as one attribute. I think I need to create an array from the comma separated values in the textarea, but I don't know how to do that. Heck, I don't really know how to ask this question correctly. :)
Here's the code.
<?php require_once('./simpledb/config.inc.php'); ?>
<html>
<body>
<h1>Input Cities</h1>
<?php
$domain = "states";
if (!empty($_POST["state"])) { // if a value is passed from the key input field save it
$state = $_POST["state"];
} else {
$state = "";
}
$state = stripslashes($state); // remove PHP escaping
if (!empty($_POST["cities"])) { // if a value is passed from the key input field save it
$cities = $_POST["cities"];
} else {
$cities = "";
}
//$cities = stripslashes($cities); // remove PHP escaping
?>
<FORM ACTION="addcities.php" METHOD=post>
<label>State (Caps)</label><br>
<input type=text name="state" size=10 value="<?php echo $state; ?>"><br>
<label>Cities ('' & comma seperated)</label><br>
<textarea name="cities" cols=60><?php echo($cities); ?></textarea><br>
<INPUT TYPE=submit VALUE="Add Cities">
<?php
if (!class_exists('SimpleDB')) require_once('./simpledb/sdb.php');
$sdb = new SimpleDB(awsAccessKey, awsSecretKey); // create connection
$item_name = $state;
//$input_cities = array("value" => array($cities));
echo "<p>putAttributes() item $item_name<br>";
//$putAttributesRequest["make"] = array("value" => "Acura"); // Example add an attribute
$putAttributesRequest['City'] = array("value" => array("Blue","Red")); // Add multiple values
The previous line is the manual way of adding your multiple values into the attribute. I tried doing the following, which gets the value of the text area, but as I mentioned earlier it just creates one value that's comma seperated vs. multiple values.
$putAttributesRequest['City'] = $input_cities; // Add multiple values
The following is just the rest of the code.
$rest = $sdb->putAttributes($domain,$item_name,$putAttributesRequest);
if ($rest) {
echo("Item $item_name created");
echo("RequestId: ".$sdb->RequestId."<br>");
echo("BoxUsage: ".$sdb->BoxUsage." = " . SimpleDB::displayUsage($sdb->BoxUsage)<br>");
} else {
echo("Item $item_name FAILED<br>");
echo("ErrorCode: ".$sdb->ErrorCode."<p>");
}
?>
Use php explode function
For example:
$cities = explode(",", $_POST['cities']);
This will only work if your data is formatted like so:
New York,Las Vegas,Sydney,Melbourne,London
Change the first part of the explode function to match the formatting of your text area.
You can then do something like:
foreach ($cities as $key => $val){
echo trim($val) . '<br />';
}
Put your SimpleDB stuff inside the foreach loop above and use $val where you want to use the city name.
This will loop through the array and do the SimpleDB stuff on each city.
Explode the string on the commas.
$citiesArray = explode(",", $cities);
You'll then want to trim each of the cities to make sure there's not additional white space before or after the city name.
call_user_func_array("trim", $cities);
There is one more Request Parameters in PUT - Replace. Although its default value is false, please specify it as a false. If Replace is false the value will be added as a multi-value to that attribute and if it is true then it will replace the older value.
Also you need to add single pair of 'Attribute Name and Attribute value' each time in PUT request. i.e if you need multvalue V1 & V2 of Attribute A then in you request it would be like this -
https://sdb.amazonaws.com/
?Action=PutAttributes
&Attribute.1.Name=A
&Attribute.1.Value=V1
&Attribute.2.Name=A
&Attribute.2.Value=V2
&Attribute.3.Replace=false
&AWSAccessKeyId=[valid access key id]
&DomainName=MyDomain
&ItemName=Item123
&SignatureVersion=2
&SignatureMethod=HmacSHA256
&Timestamp=2010-01-25T15%3A03%3A05-07%3A00
&Version=2009-04-15
&Signature=[valid signature]

Cleaning up array elements from a form

I have a form that uses inputs to create and array. The inputs are not all required but at least one is.
<form method="post" action="process.php">
<input type="text" name="MAC[]" maxlength="12" />
<input type="text" name="MAC[]" maxlength="12" />
<input type="text" name="MAC[]" maxlength="12" />
<input type="text" name="MAC[]" maxlength="12" />
<input class="submitbg" type="submit" value="Register" name="submit"/>
</form>
Now on process.php I want to loop through the array remove two types of special characters : ; then make all upper case, and verify there are only 12 characters and then serialize the arrray.
$my_array = $_POST['MAC'];
foreach ($my_array as $val){
$val = strtoupper($val);
$val = str_replace(";","",$val);
$val = str_replace(":","",$val);
$val = trim($val);
if (strlen($val) != 12)){
$valid = false;
$error = "Your MAC address is not 12 characters long";
}
}
$mac_addresses = serialize($my_array);
// if valid is not false do something with the cleaned up array.
The questions:
Will my foreach loop save the updated values back into the array?
How to check to make sure there is at least one array value?
I am just not sure if my foreach loop updates and resaves the values each time
If you want to save the values you should change your loop so that it looks something like this:
foreach ($my_array as $idx => $val) {
...
$my_array[$idx] = $val;
}
Of course you could also save the proper value to a separate clean array which you will then use further on in your application.
I also have to check to make sure there is at least one entry.
In theory you do not have to check whether the array contains elements to use the array in a foreach. The thing you need to check though is whether the variable contains an array. Suppose the MAC[] field wasn't submitted to the server you would first get a warning (it might also be an error nowadays) because you are looking up some non-existent index in the array. Secondly you would get an error on your foreach as it works on arrays (or anything that is Traversable). You could fix this with the following check:
if (!empty($_POST['MAC'])) {
$my_array = $_POST['MAC'];
if (!is_array($my_array)) {
// throw some error.
}
}
Of course you would want to do this validation of your input in a more structured way by providing a validation framework which you can provide validation rules and some input and the validation framework will then handle the validation and most importantly the error messages for you.
Actually could also change the last if-statement to read:
if (!is_array($my_array) && !($my_array instanceof Traversable))
That is if you want to be sure $my_array contains something you can traverse over with foreach. The nasty bit is that the built-in array() isn't Traversable, nasty although understandable.
What's the question?
you can do str_replace(array(';',':'),'',$val);
It's usually better to trim before doing other processing on the same variable due to the overhead involved in processing data you will eventually cut
Consider using break on errors, if you halt execution on one error.
You're not really doing any updates to $my_array.
Consider doing:
foreach($my_array as &$val)
You pass by reference so all updates to $val happen to the actual array. Or:
foreach($my_array as $key=>$val){
$my_array[$key]=trim($my_array[$key]);
You can also try to create a new array for your sanitized data and then over-write your old array. It all depends on needs.
I'm also not understanding your question /problem.
But, looking at your code, you might get the feeling that in the end nothing has happened to your POSTed vars.
You're right! :-)
Your cleaned up array at the end of the script is exactly the original array.
You might want to achieve something like this: The clean array will contain cleaned values, if they consist of 12 characters.
$my_array = $_POST['MAC'];
$my_clean_array = $_POST['MAC'];
foreach ($my_array as $val) {
$val = strtoupper($val);
$val = str_replace(";","",$val);
$val = str_replace(":","",$val);
$val = trim($val);
if (strlen($val) != 12)) {
$valid = false;
$error = "Your MAC address is not 12 characters long";
}
else {
$my_clean_array[] = $val;
}
}
$mac_addresses = serialize($my_clean_array);
To check to see if you have at least one you should be able to use if(count($my_array) > 1)

Combine arrays in PHP

Trying to learn arrays in PHP. Snippets posted for brevity.
HTML form here:
<p>What are your favorite type of cookies?</p>
<input type="checkbox" name="cookies[]" value="Oreos" />Oreos<br />
<input type="checkbox" name="cookies[]" value="Chocolate chip" />Chocolate chip<br />
<input type="checkbox" name="cookies[]" value="Sugar" />Sugar<br />
<input type="checkbox" name="cookies[]" value="Vanilla Mocha" />Vanilla Mocha<br />
<p>What are your favorite type of drinks?</p>
<input type="checkbox" name="drinks[]" value="Soda" />Soda<br />
<input type="checkbox" name="drinks[]" value="Wine" />Wine<br />
<input type="checkbox" name="drinks[]" value="Milk" />Milk<br />
<input type="checkbox" name="drinks[]" value="Water" />Water<br />
PHP page here:
foreach ($drinks as $d) {
echo "Your favorite drink(s) are: " . $d . "<br />";
}
foreach ($cookies as $cookie) {
echo "Your favorite cookies are: " . $cookie . "<br />";
}
$experimentalArray = array($cookie => $d);
foreach ($experimentalArray as $key => $value) {
echo "Cookie - " . $key . " Drink - " . $value . "<br /><br />";
}
Both cookies and drinks are multi-choice questions, so you can select more than one answer.
However, the experimentalArray only shows the last answer chosen in both drink and cookie question.
For example, I choose Oreos and Chocolate Chip in cookies, and Soda and Wine in drinks.
The answer comes out as: "Cookie - Chocolate chip Drink - Wine"
Why is it not displaying all values?
Edited for a multi-dimensional script
<?php
$drinks = $_POST['drinks'];
$cookies = $_POST['cookies'];
$combinedArray = array( 'Cookies' => $cookies, 'Drinks' => $drinks);
foreach($combinedArray as $snackType => $snack) {
print "<h2>$snackType</h2>";
foreach ($snack as $number => $snackChosen) {
print " $number is $snackChosen<br />";
}
}
?>
Ok, so tried to do a multi-dimensional array script instead since the previous script wasn't going to obtain all the values as per the HTML form.
This script works (was ripped off from a book and modified for this code here), however, $number value starts at 0. How do I modify that so that it starts at 1 instead?
Also, is this proper form for doing multi-dimensional array? Could it have been rewritten in a better way?
And again, thank you for all responses. Even if I don't quite understand them! :) So, thank you for your patience as well.
No idea which php tutorial you are using, but stop using it, it's probably horribly outdated!
You'll have to use the $_POST / $_GET / $_REQUEST (contains POST, GET and - depending on the config - Cookie values) arrays. register_globals is deprecated and a potential security hole if enabled.
For example, use $drinks = isset($_POST['drinks']) ? $_POST['drinks'] : array(); to get your $drinks array. Same for the $cookies one.
About your array issue. It looks like you want the keys from the drinks array and the values from hte cookies array. If yes, have a look at array_combine(). Note that it requires both arrays to have the same amount of elements though so feeding it with user-generated arrays where the length can vary is not a very good idea.
Fyi, $experimentalArray = array($cookie => $d); maps the last element from $cookies to the last element of $drinks because PHP has no block scope and thus $cookie and $d still point to the last array elements you got in your foreach loops.
There are a few problems here.
When you iterate with foreach and you would like to perform actions for each element, the code need to be between the foreach's brakets.
There is always a chance that the user will select a different number of cookies than drinks, which would cause problems because one food item wouldn't have a pair.
The solution that I propose is the array_combine() function to pair cookies with drinks after padding each of the arrays to the same length:
<?php
//$cookies = array_pad( $cookies , count( $drinks ), '(none)' ); Doesn't work, thanks for pointing this out #Phoenix
$drinks = array_pad( $drinks, count( $cookies ), '(none)' ); //If more cookies than drinks, add (none) drinks to account for extra cookies
$combined = array_combine( $cookies, $drinks ); //Combine arrays and cookies
?>
Of course this may seem a little complicated so let me explain. Let's say the user choses Sugar and Chocolate Chip Cookies with Milk and Water. These obviously aren't the tastiest choices, but they are the most optimal in this case. Since there are an equal number of cookies as there are drinks, PHP will simply pair up the choices with the array_combine() function. This function accepts an array of keys (cookies) and values ($drinks) and combines them into one. Ex.
array_combine( array( 'one', 'two' ), array( 1, 2 ) ) == array( 'one' => 1, 'two' => 2 );
We run into problems when the user chooses an unequal number of favorite snacks. This is when the first two lines come into play. The first line will add (none) to the cookie array for each extra drink. Ex.
array_pad( array( 'one' ), 2, '(none)' ) == array( 'one', '(none)' );
The next line does the same, but instead equals the drinks with the cookies (in the case there are more cookies selected than drinks).
Let me know if you need more examples.
What about the previous two? Do they work appropriately? I believe that the problem is here:
$experimentalArray = array($cookie => $d);
Which should be
$experimentalArray = array($cookies => $drinks);
I don't think I've ever made an array in that fashion though, not sure if the values of $cookies will automatically be the keys of $drinks.
If not, a method of generating such an array would be something like:
if(count($drinks) >= count($cookies))
{
$count = count($drinks);
}
else
{
$count = count($cookies);
}
for($i=1;$i<=$count;$i++)
{
if(isset($drinks[$i]) && isset($cookies[$i]))
{
$experimentalArray[$cookies[$i]] = $drinks[$i];
}
else if(isset($drinks[$i]) && !isset($cookies[$i]))
{
$experimentalArray['None' . $i] = $drinks[$i];
}
else
{
$experimentalArray[$cookies[$i]] = 'None' . $i;
}
}
Or something like that, which accounts for if there are fewer of one type chosen than the other.
This script works (was ripped off from a book and modified for this code here), however, $number value starts at 0. How do I modify that so that it starts at 1 instead?
PHP always starts the Count at 0.
You can read more about that at:
http://php.net/manual/de/language.types.array.php

confusion receiving an string value with functions list() and split()

buy.php
<form action="cart.php">
<input style="width:10px; margin-left:9px; " name="price[]" type="checkbox" value="' . $variety['price']. '_'. $variety['variety'] '_'. $product['name']. '" />
</form>
I am sending the input form above to cart.php inthere I receive it like:
list($aDoor, $variety,$productname) = split('_', $_POST['price']);
$aDoor = array();
$variety = array();
$productname= // $productname is a string how can I set it up here?
foreach ($_POST['price'] as $p)
{
list($a, $b,$c) = explode('_', $p);
$aDoor[] = $a;
$variety[] = $b;
$productname =$c; // and I have put it equal to the variable $c here
}
The only problem above is receiving the index $product['name'] coming from the form in buy.php
In cart.php I have set it up to be received by $productname but as you can see this is an string not a array how can I set it up when it is an string in with the functions list() and split() it confuses me.
Ok. There's a few things wrong with your script.
1) You've not specified a method on your form tag, so by default the data will be submitted as a 'GET'. You're using $_POST in your script, so those values will be blank and the foreach loop will fail as $_POST['price'] doesn't exist.
2) You're naming the checkbox as "price[]". The [] tells PHP that there will be multiple values submitted with this same name, so that $_GET['price'] will be an array. Your first few lines of code will then fail, as split works on strings, not arrays. You'll end up with the following values assigned
$aDoor = "Array"
$variety = NULL;
$productname = NULL;
PHP attempts to convert your $GET['price'] array to a string, but this defaults to just coming back as the string 'Array', and there's no "" values in there, so the rest of the list() variables having nothing to be assigned to them, so they become null.
3) Split's been deprecated and will be removed in PHP 6, so use explode() instead (as you do just a few lines later)
4) You then immediately trash those values by assigning empty arrays for $aDoor and $variety, so in effect the split line was useless
The foreach loop looks fine, though you'll want to assign to a $productname array, instead of a string, so use $productname[] = $c;
5) I would, however, not store the data you're explode()ing in three seperate arrays. It would make more sense to
store it like this:
$products = array();
foreach($_POST['price'] as $p) {
list($a, $b, $c) = explode('_', $p);
$products[] = array('aDoor' => $a, 'variety' => $b, 'productname' => $c);
}
This way you don't have to pass around 3 arrays (or make them 'global') in any functions that use this data, you can pass just a single variable (ie: updateInventory($products[7]); )
5) If this shopping cart script was released into the wild, it could be a gaping security hole on the server. What would stop someone from constructing their own price by passing in something like "$0.00_fire engine red-ferrari" as the price field? I've always wanted a free Ferrari, and round-tripping pricing data through the user's browser is a nice way to get it. Never, ever, trust a client to NOT hack up critical data, such as its price.
$productname = '';
If you don't specify the method attribute of the form, the default is GET. In your script you are using POST, try putting POST method to your form:
<form action="cart.php" method="post">
Secondly, even if $productname is a string but you can convert it to array (like you have done for other vars) by suffixing it with [], so your code becomes:
$aDoor = array();
$variety = array();
$productname = array();
foreach ($_POST['price'] as $p)
{
list($a,$b,$c) = explode('_', $p);
$aDoor[] = $a;
$variety[] = $b;
$productname[] = $c;
}
Now these three arrays contains your data.

Categories