I got Undefined index: reading recursively an array - php

I'm going to be crazy, I can't understand what is the problem.
I have this array:
array(2) {
[0]=>
array(4) {
["id"]=>
string(1) "1"
["parent_id"]=>
NULL
["name"]=>
string(7) "Events"
["children"]=>
array(2) {
[0]=>
array(3) {
["id"]=>
string(1) "2"
["parent_id"]=>
string(1) "1"
["name"]=>
string(9) "Concerts"
}
}
}
[1]=>
array(4) {
["id"]=>
string(1) "4"
["parent_id"]=>
NULL
["name"]=>
string(7) "Music"
["children"]=>
array(3) {
[0]=>
array(3) {
["id"]=>
string(1) "5"
["parent_id"]=>
string(1) "4"
["name"]=>
string(4) "Rock"
}
}
}
}
and I try to print with this recursive function:
public function printTree($tree) {
$result = "";
if(!is_null($tree) && count($tree) > 0) {
$result .= '<ul>';
foreach($tree as $node) {
$result .= '<li>Cat: '.$node['name'];
$subtree = array($node['children']);
$this->printTree($subtree);
$result .= '</li>';
}
$result .= '</ul>';
}
return $result;
}
I get an "Undefined index: name" error.
Do I need to declare name? how?
Is the array with incorrect syntax?
If I comment the recursive call
$subtree = array($node['children']);
$this->printTree($subtree);,
then $node['name'] isn't undefined and the code works, but of course with only with one level of depth.
SOLVED: (Thanks all guys!)
public function printTree($tree) {
$result = "";
if(is_array($tree) && count($tree) > 0) {
$result .= '<ul>';
foreach($tree as $node) {
$result .= '<li>Cat: '.$node['name'];
if (isset($node['children'])) {
$result .= $this->printTree($node['children']);
}
$result .= '</li>';
}
$result .= '</ul>';
}
return $result;
}

You are pushing $node['children'] into an additional array. That way you are not dealing with the subarray of this node (which has a name later on), but you have another layer of array.
Skip this array layer, remove it.
Also note that !is_null() isn't really a nice check if you then want to use that variable as an array. Check for is_array() instead, because strings and other scalar values will return count>0 as well - they return 1. Only NULL returns count=0.

You will have to append the results returned by the consecutive calls to printTree() for child nodes to the $result.
$result .= $this->printTree($node['children']);
:)

First of all, you want to enclose the $subtree-stuff into an if-condition checking for the existence of the key 'children', because as it is now, you have created an infinite loop of recursive calls to printTree(), but you only want to do this, if the key 'children' exists.
Second, I guess you want to add $result .= in front of $this->printTree($subtree);, otherwise the return value will simply be discarded.
Third, don't do $subtree = array($node['children']);. $node['children'] already is an array, so this adds another level to the array, which makes the recursion break.
So, the final function should look something like this:
public function printTree($tree) {
$result = '';
if(!is_null($tree) && count($tree) > 0) {
$result .= '<ul>';
foreach($tree as $node) {
$result .= '<li>Cat: '.$node['name'];
if (isset($node['children'])) {
$subtree = $node['children'];
$result .= $this->printTree($subtree);
}
$result .= '</li>';
}
$result .= '</ul>';
}
return $result;
}
Edit: Whoops, was too slow there, the others also found the three problems here :)

Related

Function $_POST return value from array parameter

I had this response from method post
array(7) {
["enable"]=>
array(2) {
[0]=>
string(2) "on"
[1]=>
string(2) "on"
}
["value"]=>
array(2) {
[0]=>
string(8) "R$ 10,00"
[1]=>
string(8) "R$ 10,00"
}
["zip_code"]=>
array(2) {
[0]=>
string(9) "57200-970"
[1]=>
string(9) "57200-990"
}
["address"]=>
array(2) {
[0]=>
string(28) "Avenida Floriano Peixoto"
[1]=>
string(33) "Povoado Tabuleiro dos Negros"
}
["neighborhood"]=>
array(2) {
[0]=>
string(6) "Centro"
[1]=>
string(4) "Bairro Vermelho"
}
["city"]=>
array(2) {
[0]=>
string(6) "Penedo"
[1]=>
string(6) "Penedo"
}
["state"]=>
array(2) {
[0]=>
string(2) "AL"
[1]=>
string(2) "AL"
}
}
I need first use the foreach to get the $_POST['active'] and get value from another arrays index
foreach (Request::post('enable') as $k => $v) {
print Request::post(array("zip_code", $k)) . "\n";
// I hope same result of $_POST['zip_code'][$k]
}
the real problem is my function
public static function post($key, $clean = false) {
$result = is_array($key) ? array_search($key, $_POST) : $_POST[$key];
if (!empty($result)) {
return ($clean) ? trim(strip_tags($result)) : $result;
}
return NULL;
}
if param key is an array get value from this key array
for example $_POST['a']['b']['c']
[EDIT]
I improve the function, thanks #mickmackusa
public static function post($key, $clean = false) {
$focus = $_POST;
if (is_array($key)) {
foreach ($key as $k) {
if (!isset($focus[$k])) {
return NULL;
}
$focus = $focus[$k];
if (!is_array($focus)) {
$result = $focus;
}
}
} else {
$result = empty($focus[$key]) ? NULL : $focus[$key];
}
return ($clean ? trim(strip_tags($result)) : $result);
}
I think line1 inside post() is fouling things up. Depending on $key's type, you are declaring $result's value as a key or a value. But then seemingly treating both possibilities as a value in the next condition and returning it.
public static function post($key, $clean=false) {
$result = is_array($key) ? array_search($key, $_POST) : $_POST[$key];
// if $key is an array, then $result is the key of the found value within $POST or FALSE if not found
// if $key is not an array, then $result is the value of $_POST[$key]
if (!empty($result)) {
return ($clean) ? trim(strip_tags($result)) : $result;
}
return NULL;
}
The !empty condition is checking for NOT falsey values in $result.
See all falsey values # empty() manual, including 0 which can be a totally legitimate index/key, and more.
Instead, I think you want to use:
public static function post($key,$clean=false){
$focus=$_POST;
foreach($key as $k){
if(!isset($focus[$k])){
return NULL;
}else{
$focus=$focus[$k];
if(!is_array($focus)){
$result=$focus;
}
}
}
return ($clean?trim(strip_tags($result)):$result);
}

PHP Arrays - Merge two arrays where a value is added together

I need some more help regarding PHP Arrays and the issue I am having. I have an array like this: -
array(2) {
[0]=>
array(2) {
[0]=>
array(2) {
["count"]=>
string(3) "100"
["id"]=>
int(46)
}
[1]=>
array(2) {
["count"]=>
string(3) "300"
["id"]=>
int(53)
}
}
[1]=>
array(1) {
[0]=>
array(2) {
["count"]=>
string(3) "200"
["id"]=>
int(46)
}
}
}
However, I would like it to look more like this as array: -
array(2) {
[0]=>
array(2) {
["count"]=>
string(3) "300" <--- This has been added from Array 1 and 2
["id"]=>
int(46)
}
[1]=>
array(2) {
["count"]=>
string(3) "300"
["id"]=>
int(53)
}
}
Basically if the same id is in both areas I want the count number to be added to each other but if it's not then it needs to just be left alone and included in the array.
I have used a number of array functions such as array_merge and array_push but I am running out of ideas of how this could work. I have also started working on a foreach with if statements but I just got myself completely confused. I just need a second pair of eyes to look at the issue and see howe it can be done.
Thanks again everyone.
Should work with something like this:
$idToCountArray = array(); //temporary array to store id => countSum
array_walk_recursive($inputArray, function($value,$key) { //walk each array in data structure
if(isset(value['id']) && isset($value['count'])) {
//we have found an entry with id and count:
if(!isset($idToCountArray[$value['id']])) {
//first count for id => create initial count
$idToCountArray[$value['id']] = intval($value['count']);
} else {
//n'th count for id => add count to sum
$idToCountArray[$value['id']] += intval($value['count']);
}
}
});
//build final structure:
$result = array();
foreach($idToCountArray as $id => $countSum) {
$result[] = array('id' => $id, 'count' => ''.$countSum);
}
Please note that I have not testet the code and there is probably a more elegant/performant solution.
You could use something like this:
$end_array = array();
function build_end_array($item, $key){
global $end_array;
if (is_array($item)){
if( isset($item["id"])){
if(isset($end_array[$item["id"]]))
$end_array[$item["id"]] = $end_array[$item["id"]] + $item["count"]*1;
else
$end_array[$item["id"]] = $item["count"]*1;
}
else {
array_walk($item, 'build_end_array');
}
}
}
array_walk($start_array, 'build_end_array');
Here is a fiddle.
Thank you ever so much everyone. I actually worked it by doing this: -
$fullArray = array_merge($live, $archive);
$array = array();
foreach($fullArray as $key=>$value) {
$id = $value['id'];
$array[$id][] = $value['count'];
}
$result = array();
foreach($array as $key=>$value) {
$result[] = array('id' => $key, 'count' => array_sum($value));
}
return $result;

Populate select with database entries the oo way

My database table
TABLE `dog_types` (
`dog_type_id` int(11)
`dog_type_name` varchar(64)
I would like to make the dog_type_name entries available in a select menu.
My attempt
Class Sell {
public static function getAllDogTypes()
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SELECT dog_type_name FROM dog_types";
$query = $database->prepare($sql);
$query->execute(array());
// fetchAll() is the PDO method that gets all result rows
return $query->fetchAll();
}
public static function viewSelect($name = "select") {
$html = "<select name='$name'>\n";
foreach ($query as $key => $val) {
$html .= "<option value='$key'>$val</option>\n";
}
$html .= "</select>\n";
return $html;
}
}
<?php echo Sell::viewSelect(); ?>
My output
<select>
Notice: Undefined variable: query
Warning: Invalid argument supplied for foreach()
</select>
The two functions work on their own. I just cannot figure out how to put them together.
As you already guessed I am super new to all of this and would highly appreciate any kind of help!
With noob's suggestions my code looks like this:
public static function getAllDogTypes()
{
$database = DatabaseFactory::getFactory()->getConnection();
$sql = "SELECT * FROM dog_types";
$query = $database->prepare($sql);
$query->execute(array());
// fetchAll() is the PDO method that gets all result rows
return $query->fetchAll();
}
public static function viewSelect($name = "select") {
$query=Sell::getAllDogTypes();
$html = "<select name='$name'>\n";
foreach ($query as $key => $val) {
$html .= "<option value='$key'>$val</option>\n";
}
$html .= "</select>\n";
return $html;
}
<?php echo Sell::viewSelect(); ?>
var_dump on query shows the database entries:
Dog_type: array(8) { [0]=> object(stdClass)#8 (2) { ["dog_type_id"]=> string(1) "1" ["dog_type_name"]=> string(13) "Affenpinscher" } [1]=> object(stdClass)#9 (2) { ["dog_type_id"]=> string(1) "2" ["dog_type_name"]=> string(12) "Afghan Hound" } [2]=> object(stdClass)#10 (2) { ["dog_type_id"]=> string(1) "3" ["dog_type_name"]=> string(4) "Aidi" } [3]=> object(stdClass)#11 (2) { ["dog_type_id"]=> string(1) "4" ["dog_type_name"]=> string(16) "Airedale Terrier" } [4]=> object(stdClass)#12 (2) { ["dog_type_id"]=> string(1) "5" ["dog_type_name"]=> string(6) "Akbash" } [5]=> object(stdClass)#13 (2) { ["dog_type_id"]=> string(1) "6" ["dog_type_name"]=> string(5) "Akita" } [6]=> object(stdClass)#14 (2) { ["dog_type_id"]=> string(1) "7" ["dog_type_name"]=> string(13) "Alano Espanol" } [7]=> object(stdClass)#15 (2) { ["dog_type_id"]=> string(1) "8" ["dog_type_name"]=> string(16) "Alaskan Klee Kai" } }
The error messages
Notice: Undefined variable: query
Catchable fatal error: Object of class stdClass could not be converted to string
add this line to at the beginning of second function:
$query=Sell::getAllDogTypes(); //get the value of $query from getAlldogTypes function which is present in this class.
$query returns array of objects, so you need a nested foreach loop
$html = "<select name='$name'>\n";
foreach ($query as $obj) {
foreach ($obj as $key=>$val)
$html .= "<option value='$key'>$val</option>\n";
}
}
$html .= "</select>\n";
return $html;
}
first of all change
public static function viewSelect($name = "select",$query="") {
$sql = "SELECT dog_type_id,dog_type_name FROM dog_types";
Because you should pass dog_type_id in options values.
First Call this
<?php $query=Self::getAllDogTypes(); ?>
Then call
<?php echo Self::viewSelect($query); ?>

create php array using simpleXMLobject

I'm trying to get this array ($resdata) with object(SimpleXMLElement) into a php array:
$resdata =
array(59) {
[0]=> ...
[10]=> object(SimpleXMLElement)#294 (28) {
["reservation_id"]=> string(7) "8210614"
["event_id"]=> string(6) "279215"
["space_reservation"]=> array(2) {
[0]=> object(SimpleXMLElement)#344 (9) {
["space_id"]=> string(4) "3760"
["space_name"]=> string(9) "205"
["formal_name"]=> string(33) "Center" }
[1]=> object(SimpleXMLElement)#350 (9) {
["space_id"]=> string(4) "3769"
["space_name"]=> string(9) "207"
["formal_name"]=> string(32) "Right" } } }
}
I've tried:
$res = (array)$resdata;
$reservation = $res['reservation'];
$result = array();
foreach ($reservation as $key => $value){
$res = array($value);
$spid = $res[0]->space_reservation->space_id;
echo $value->event_id."<br />";
echo $spid."<br />";
}
This only outputs the first space_id and I need to get all the space_ids within "space_reservation" array. Not all records will have multiple space_ids. Any help pointing me in the right direction is appreciated. Not sure if I should use xpath but I need to re-write my foreach statement regardless.
I was hoping to be able to literally convert all references to "object(SimpleXMLElement)#_ (#)" to "array(#)"
[10]=> array (28) {
["reservation_id"]=> string(7) "8210614"
["event_id"]=> string(6) "279215"
["space_reservation"]=> array(2) {
[0]=> array (9) {
["space_id"]=> string(4) "3760"
["space_name"]=> string(9) "205"
["formal_name"]=> string(33) "Center" }
[1]=> array (9) {
["space_id"]=> string(4) "3769"
["space_name"]=> string(9) "207"
["formal_name"]=> string(32) "Right" } } }
}
the function in my cakephp 1.3 controller is this:
$xml = simplexml_load_string($string);
$this->data['events']= $xml->children();
$resdata = $this->data['events'];
$this->set('resdata',$resdata);
I think this should do what you are looking for:
foreach ($resdata as $res) {
echo $res->event_id . '<br />';
foreach ($res->space_reservation as $reservation) {
echo $reservation->space_id . '<br />';
}
}
Googled it and found a general solution for any SimpleXMLElement to array conversion:
function xml2array($xml) {
$arr = array();
foreach ($xml as $element) {
$tag = $element->getName();
$e = get_object_vars($element);
if (!empty($e)) {
$arr[$tag] = $element instanceof SimpleXMLElement ? xml2array($element) : $e;
}
else {
$arr[$tag] = trim($element);
}
}
return $arr;
}

PHP Array not accessible

Basically, i'm trying to get users data from a database using a class i found, it's parsing all data inside an array as shown here from the following function :
public function Get($field = NULL) {
if ($field == NULL)
{
$data = array();
while ($row = mysql_fetch_array($this->last_query))
{
$data[] = $row;
}
}
else
{
$row = mysql_fetch_array($this->last_query);
$data = $row[$field];
}
return $data;
}
Here's the PHP code i'm using to get the call this function
if($_SERVER['REQUEST_METHOD'] == 'POST'){
if($_SESSION['csrfToken'] == $_POST['csrfToken']) {
$email = $_POST['email'];
$password = $Security->Salt($Security->secParam($_POST['password']));
$DB->Query("SELECT * FROM `table` WHERE `email` = '$email' AND `password` = '$password'");
if($DB->num_rows() > 0) {
$results = $DB->Get();
} else {
echo "Account not found";
}
}
}
If i do a var_dump on $results it shows the following
array(1) {
[0]=> array(8) {
[0]=> string(1) "1" ["id"]=> string(1) "1"
[1]=> string(35) "email#email.com" ["email"]=> string(35) "email#email.com"
[2]=> string(32) "4f14dfef1efe0de64e2b176eac6051cd" ["password"]=> string(32) "4f14dfef1efe0de64e2b176eac6051cd"
[3]=> string(1) "1" ["status"]=> string(1) "1"
}
}
how can i access this data ? I've tried calling it by doing the following
$email = $results['email'];
echo $email;
But it's not displaying anything ?
Even though there's only one result in this instance (I guess?) the array supports multiple.
So find the first result, then take the email from that:
echo $results[0]['email'];
// ^^^^^^^^^^^
// first result
You need to tracking how arrays works. First you have array(1) and then into array another vars such as "email" or 1.
array(1) { <---- THIS IS ARRAY OCCURED FOR FIRST "0" ARRAY.
What's about
this
\/
echo $results[0]["email"]; ?
if($_SERVER['REQUEST_METHOD'] == 'POST' && $_SESSION['csrfToken'] == $_POST['csrfToken']) {
$password = $Security->Salt($Security->secParam($_POST['password']));
$password = $DB->quoteStr($password);
$email = $DB->quoteStr($_POST['email']);
$DB->Query("SELECT * FROM `table` WHERE `email` = $email AND `password` = $password");
return $DB->GetRow();
}
public function GetRow() {
return mysql_fetch_array($this->last_query);
}
public function quoteStr($str) {
return "'".mysql_real_escape_string($str)."'";
}
Marin Sagovac question is the answer.
To break it down a little more, your var_dump output shows that $results is a nested array. The first part of the output:
array(1) {
[0]=>
shows that $results consists of an array containing 1 element, at index 0, since that's where PHP starts indexing. This is the $results[0] part of Marin's response.
The element 0 of the $results array consists of an array with 8 elements.
[0]=>array(8) {
[0]=> string(1) "1" ["id"]=> string(1) "1"
[1]=> string(35) "email#email.com" ["email"]=> string(35) "email#email.com"
Even though there are only 4 actual results, index 1-4, each one exists twice so that they can either be accessed by index or by its key. Arrays that can be accessed by a unique key, as opposed to an index, are known as associative arrays.
So, in this case, either will return the same value:
echo $results[0]["email"];
echo $results[0][1];
The print_r function would also work, instead of var_dump.

Categories