php foreach error handling in function - php

I have a function which performs a foreach loop on an array from a database.
see foreach ($teamarray AS $key => $value){$teamgo .= $value[1]." ".$value[2]."<br/>";
Problem is, sometimes there may be no data set, which throws an error when the loop hits that field.
How can i catch/suppress this error?
function GetUnsubmitted($coach){
$push .= "<div id=unsubmitted><h2>Check which event/teams you want to process and click submit</h2>";
$push .= "<form action=\"submit.php\" method=POST>";
$result = mysql_query("SELECT * FROM `ptable` WHERE coach = '$_SESSION[username]' AND status = '1' ORDER BY status ASC") or trigger_error(mysql_error());
while($row = mysql_fetch_array($result)){
foreach($row AS $key => $value) { $row[$key] = stripslashes($value); }
$id = $row['id'];
$teampre = $row['team'];
$eventpre = $row['event'];
$statuspre = $row['status'];
$eventarray = DecodeEvent($eventpre);
$event = $eventarray[0];
$cat = $eventarray[1];
$subcat = $eventarray[2];
$division = $eventarray[3];
$type = $eventarray[4];
$teamarray = DecodeTeam($teampre);
$price = GetPrice($type, "nat");
$teamcount = count($teamarray);
$total = $price * $teamcount;
$teamgo = "";
foreach ($teamarray AS $key => $value){
$teamgo .= $value[1]." ".$value[2]."<br/>";
if($statuspre == "1"){
$statuscolor = "#FFCC99";
$statusmsg = "unsubmitted <a href=delsub.php?id=$id onClick=\"return confirm('Are you sure you want to delete this submission?');\"><img src=images/del.png border=0 />";
} elseif($statuspre == "2"){
$statuscolor = "#FFCC66";
$statusmsg = "awaiting confirmation";
} elseif($statuspre == "3"){
$statuscolor = "#66CC66";
$statusmsg = "confirmed";
}
}
$push .= "<div id=submission><div id=event style=\"background-color:$statuscolor;\"><h1>$event</h1><span id=status>$statusmsg</span></div><div id=subinfo><span id=dropdown><img src=images/expand.png border=0></span><h2>$cat >> $subcat >> $division >> $type</h2> <div id=team style=\"display:none;\">$teamgo<br />$price - $total<div id=controls></div></div></div></div>";
$pid .= $id;
$rtotal .= "$total,";
}
$stotal = explode(",", $rtotal);
$gtotal = array_sum($stotal);
$push .= "<div style=\"text-align:right;\"><div id=total>Total - <em>$gtotal</em></div><br><input type=image src=images/paynow.png alt=\"Pay Now\"></form> <a href=submit2.php?$pid&$pidarray><img src=images/mailfax.png width=138px height=41px border=0></a></div></div>";
return $push;
}
If possible id like it to say "no team selected" and stop.

You can write so:
foreach ((array)$teamarray as $key => $value) {
$teamgo .= $value[1] . " " . $value[2] . "<br/>";
//...
}
foreach expects array. So the really correct way is to ensure that you deal with array before try to iterate, like this:
if (is_array($teamarray) && count($teamarray)) {
foreach ((array)$teamarray as $key => $value) {
$teamgo .= $value[1] . " " . $value[2] . "<br/>";
//...
}
}
You also can check is_iterable since PHP 7.1.

if ($array) {
foreach ($array as $k => $v) {
...
}
} else {
echo 'No team selected';
// exit from loop
}
Your exit from loop will be a "return", or a "break n" (n is the levels to break for) or continue... it depends on your logic.

if ($value !== null && count($value) >= 3) {
$teamgo .= $value[1] . $value[2]
}

<insert puzzled smiley here>
foreach($row AS $key => $value) {
if ($value) {
$row[$key] = stripslashes($value);
}
}
And:
foreach ($teamarray AS $key => $value){
if ($value && sizeof($value) > 2) {
$teamgo .= $value[1] . $value[2]
}
}
Is this it?

Just do a test if $teamarray actually is an array:
if (is_array($teamarray)) {
foreach ($teamarray as $key => $value) {
// …
}
}

Or you could do:
$teamarray = isset($teamarray) ? $teamarray : array();
Just prior to the loop in a nice tidy line, and it would ensure that you have the variable set to an empty array which would cause it to skip the foreach().

Related

I'm trying to convert an array to XML but I am failing to get it 100% correct

I need to output the response from the database in XML. So far I have gotten it to output this:
The outermost tag needs to match the name of the action query, it'll either be <courses> or <students>.
Here is my code:
<?php
require_once('./database.php');
if (isset($_GET['format'])) {
$format = filter_var($_GET['format']);
}
if (isset($_GET['action'])) {
$action = filter_var($_GET['action'], FILTER_SANITIZE_STRING);
$tableName = "sk_$action";
}
$query = "SELECT * FROM $tableName";
if (isset($_GET['course'])) {
$course = filter_input(INPUT_GET, 'course');
$query .= " WHERE courseID = :course";
}
function arrayToXml($arr, $i = 1, $flag = false)
{
$sp = "";
for ($j = 0; $j <= $i; $j++) {
$sp .= " ";
}
foreach ($arr as $key => $val) {
echo "$sp<" . $key . ">";
if ($i == 1) echo "\n";
if (is_array($val)) {
if (!$flag) {
echo "\n";
}
arrayToXml($val, $i + 5);
echo "$sp</" . $key . ">\n";
} else {
echo "$val" . "</" . $key . ">\n";
}
}
}
$statement = $db->prepare($query);
$statement->bindValue(':course', $course);
$statement->execute();
$response = $statement->fetchAll(PDO::FETCH_ASSOC);
$statement->closeCursor();
if ($format == 'json') {
echo json_encode($response);
}
if ($format == 'xml') {
arrayToXml($response, 1, true);
}
I'm pretty new to PHP and have never worked with XML. All help is appreciated. Thanks.
function arrayToXml($arr, $collectionTag, $singleTag) {
$collection = new SimpleXMLElement("<$collectionTag/>");
foreach ($arr as $row) {
$element = $root->addChild($singleTag);
foreach ($row as $tag => $value) {
$element->addChild($tag, $value);
}
}
return $collection;
}
$courses = arrayToXml($response, 'courses', 'course');
echo $courses->asXML();
Tested with PHP 7.1.23. Output:
<?xml version="1.0"?>
<courses>
<course><courseID>cs601</courseID><courseName>Web Application Development</courseName></course>
<course><courseId>cs602</courseId><courseName>Server-Side Application Development</courseName></course>
<course><courseId>cs701</courseId><courseName>Rich Internet Application Development</courseName></course>
</courses>
(I added newlines because by default it doesn't add any.)

XML - Nodes with the same name showing only one time in PHP

I have a little problem with decoding my xml with php:
I have an xml file with details about movies, what I need to do is to take the nodes torrents->torrent->quality and show the result in my php script. Right now I have a part of the code, it shows me only the first quality that it finds.
(For example: I have the movie "Poltergeist" that is in 720p and 1080p, but in my script it will only show the 720p and skip the 1080p)
Screenshot website:
Screenshot xml:
<link rel="stylesheet" type="text/css" href="css/style.css">
<?php
$xml = simplexml_load_file("https://yts.to/api/v2/list_movies.xml?limit=10");
$titolo = array();
$locandina = array();
$anno = array();
$durata = array();
$genere = array();
$qualita = array();
$i = 0;
foreach ($xml->data->movies->movie as $element) {
foreach ($element->children() as $key => $val) {
$chiave = $key;
$valore = $val;
if ($key == "title") {
$titolo[] = $val;
}
if ($key == "medium_cover_image") {
$locandina[] = $val;
}
if ($key == "year") {
$anno[] = $val;
}
if ($key == "runtime") {
$durata[] = $val;
}
if ($key == "genres") {
for($g = 0; $g < count($xml->data->movies->movie[$i]->genres->genre); $g++) {
$genere[$i][] = $xml->data->movies->movie[$i]->genres->genre[$g];
}
}
$qualdef = $xml->data->movies->movie->torrents->torrent;
foreach ($qualdef as $element) {
foreach ($element->children() as $key => $val) {
if ($key == "quality") {
$qualita[] = $val;
}
}
}
}
$i++;
}
for ($i = 0; $i < count($titolo); $i++) {
echo "<div class=totbox>";
if (isset($locandina[$i])) {
echo "<div class=box><img src=" . $locandina[$i] . "></div>";
}
echo "<div class=text><b>" . $titolo[$i] . "</b> - " . $anno[$i] . "</div>";
foreach ($genere[$i] as $genResult) {
echo "<div class=text><b>" . $genResult . "</b></div>";
}
echo "<div class=text><b> Qualita':" . $qualita[$i] . "</b></div>";
echo "<div class=text><b> Durata:" . $durata[$i] . "</b></div>";
echo "</div>";
}
?>
What am I doing wrong?
It seems like you are collecting data without any problem but when you are displaying you go by the index of $titolo so you don't go through every element of $qualita array.
So just try this:
echo "<div class=text><b> Qualita':" . implode(', ',$qualita) . "</b></div>";

XML: Show two child nodes with the same name in php

I have a problem with showing my xml into a php page. I have an xml that looks like this (obviously its only a part of it because it really to long to post it all).
It all goes well until it cames to the "genre", I have two values for it and I don't know how to show them at the same time.
<movie>
<id>4441</id>
<title>Rudderless</title>
<title_long>Rudderless (2014)</title_long>
<year>2014</year>
<rating>7.5</rating>
<runtime>105</runtime>
<genres>
<genre>Comedy</genre>
<genre>Drama</genre>
</genres>
</movie>
(an important thing to notice is that not every movie will have two genre, sometimes there is only one and sometime two or three)
This is my code right now
$genere = array();
foreach ($xml->data->movies->movie->genres as $row) {
foreach ($row->children() as $key => $val) {
if ($key == "genre") {
$genere[] = $val;
}
}
}
//and then I'll print
for ($i = 0; $i < 20 ; $i++) {
echo "<div class=text><b>" . $genere[$i] . "</b></div>";
}
When I'm doing this it will print only for the first item of the array, and the others just give me a "Notice: Undefined offset: 1 in /path/ on line 53"
I've tried to follow some guides but it was a failure
What am I doing wrong?
/--Edit--/
<?php
$xml = simplexml_load_file("https://yts.to/api/v2/list_movies.xml")
$titolo = array();
$locandina = array();
$anno = array();
$durata = array();
$genere = array();
foreach ($xml->data->movies->movie as $element)
{
foreach($element->children() as $key => $val)
{
$chiave = $key;
$valore = $val;
if ($key == "title")
{
$titolo[] = $val ;
}
if ($key == "medium_cover_image")
{
$locandina[] = $val ;
}
if ($key == "year")
{
$anno[] = $val ;
}
if ($key == "runtime")
{
$durata[] = $val;
}
}
}
foreach ($xml->data->movies->movie->genres as $row)
{
foreach($row->children() as $key => $val)
{
if ($key == "genre")
{
$genere[] = $val;
}
}
}
var_dump($genere);
for ($i=0 ; $i<20 ; $i++)
{
echo "<div class=totbox>";
echo "<div class=box><img src=" . $locandina[$i] . "></div>";
echo "<div class=text><b>" . $titolo[$i] . "</b> - " . $anno[$i] . "</div>";
echo "<div class=text><b>" . $genere[$i] . "</b></div>";
echo "<div class=text><b> Durata:" . $durata[$i] . "</b></div>";
echo "</div>";
}
?>
UPDATED - Code fixed. Please, try now.
<?php
$xml = simplexml_load_file("https://yts.to/api/v2/list_movies.xml")
$titolo = array();
$locandina = array();
$anno = array();
$durata = array();
$genere = array();
$i = 0;
foreach ($xml->data->movies->movie as $element) {
foreach ($element->children() as $key => $val) {
$chiave = $key;
$valore = $val;
if ($key == "title") {
$titolo[] = $val;
}
if ($key == "medium_cover_image") {
$locandina[] = $val;
}
if ($key == "year") {
$anno[] = $val;
}
if ($key == "runtime") {
$durata[] = $val;
}
if ($key == "genres") {
for($g = 0; $g < count($xml->data->movies->movie[$i]->genres->genre); $g++) {
$genere[$i][] = $xml->data->movies->movie[$i]->genres->genre[$g];
}
}
}
$i++;
}
for ($i = 0; $i < count($titolo); $i++) {
echo "<div class=totbox>";
if (isset($locandina[$i])) {
echo "<div class=box><img src=" . $locandina[$i] . "></div>";
}
echo "<div class=text><b>" . $titolo[$i] . "</b> - " . $anno[$i] . "</div>";
foreach ($genere[$i] as $genResult) {
echo "<div class=text><b>" . $genResult . "</b></div>";
}
echo "<div class=text><b> Durata:" . $durata[$i] . "</b></div>";
echo "</div>";
}
I hope this helps!
Look on my code, based on yours. PHP file:
<?php
$xml = new SimpleXMLElement(file_get_contents('test.xml'));
$genere = array();
foreach ($xml->genres as $row) {
foreach ($row->children() as $key => $val) {
if ($key == "genre") {
$genere[] = $val;
}
}
}
//and then I'll print
foreach ($genere as $genre) {
echo "<div class=text><b>" . $genre . "</b></div>";
}
XML file:
<movie>
<id>4441</id>
<title>Rudderless</title>
<title_long>Rudderless (2014)</title_long>
<year>2014</year>
<rating>7.5</rating>
<runtime>105</runtime>
<genres>
<genre>Comedy</genre>
<genre>Drama</genre>
</genres>
</movie>
Its work fine, test it.
Based on your full xml file, look on this:
<genres>
<genre>Horror</genre>
</genres>
You have only one genre on first position, so its work fine. You need to loop on movie tag first, not genres. So put your genre tag inside movie foreach.
Like:
foreach($element->children() as $key => $val)
{
if ($key == "genres")
{
// your loop, based on $val variable!
}

how can I add items from an array as a class

I am new at php, so please be kind.
I am building a script that gets the number of facebook likes from facebook pages.
Then it sorts them, I have found a way to add the page's profile picture using css, however the only class I am able to add is a url. how can I give each thumbnail it's own class, which I can then apply the css to?
here is my code:
function array_sort($array, $on, $order=SORT_ASC)
{
$new_array = array();
$sortable_array = array();
if (count($array) > 0) {
foreach ($array as $k => $v) {
if (is_array($v)) {
foreach ($v as $k2 => $v2) {
if ($k2 == $on) {
$sortable_array[$k] = $v2;
}
}
} else {
$sortable_array[$k] = $v;
}
}
switch ($order) {
case SORT_ASC:
asort($sortable_array);
break;
case SORT_DESC:
arsort($sortable_array);
break;
}
foreach ($sortable_array as $k => $v) {
$new_array[$k] = $array[$k];
}
}
return $new_array;
}
function getLikes($arr){
$urls = "";
// Add urls to check for likes
for($i = 0;$i < count($arr);$i++) {
if($urls != "") $urls .= ",https://www.facebook.com/";
$urls .= $arr[$i];
}
// Retreive info from Facebook
$xml = simplexml_load_file("http://api.facebook.com/restserver.php?method=links.getStats&urls=https://www.facebook.com/" . $urls);
$likes = array();
// Loop through the result and populate an array with the likes
for ($i = 0;$i < count($arr);$i++) {
$url = $xml->link_stat[$i]->url;
$counts = (int)$xml->link_stat[$i]->like_count;
$likes[] = array('likes' => $counts,'url' => $url);number_format(1000, 0, '.', ',');
}
return $likes;
}
$array = array("kylieminogue","SiaMusic","iggyazalea");
$likes = getLikes($array);
$likes = array_sort($likes, 'likes', SORT_DESC);
foreach ($likes as $key => $val) {
$final = number_format($val['likes'], 0, '.', ',');
echo "<li class='facebook'><div class='fb-page'><div class='rank'>" . $key . "</div>" . "<div class='thumb " . $val['url'] . "'><div class='link'>" . $val['url'] . "</div></div>" . "<div class='likes'>" . $final . "</div></div></li><br />";
}
If you do this in getLikes(), inside the second loop:
$likes[] = array(
'likes' => $counts,
'url' => $url,
// create a hopefully unique class name
'class' => strtolower($arr[$i]) . '-' . $i
);
// After this you call number_format without receiving its value, why?
Then in the HTML you change
"<div class='thumb " . $val['url'] . "
for
"<div class='thumb " . $val['class'] . "
Is this what you mean?

automatically generate update form with array

$resultUpdate = Nemesis::select("*", $table, "id = '{$id}'");
if (!$resultUpdate) {
self::show_error(QUERY_ERROR);
} elseif ($resultUpdate->num_rows > 0) {
$out .= '<div class="form-desc">' . $formDesc . '</div>';
} else {
self::show_error(QUERY_EMPTY);
}
$array = array_values($array);
print_r($array);
$out .= '<form action="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&table=' . $table . '" method="post" class="form-horizontal" ' . $formAppend . '>';
while ($row = $resultUpdate->fetch_assoc()) {
foreach ($row as $fieldname => $value) {
if (in_array($fieldname, $array)) {
$out .= generateInputField($fieldname, $value);
}
}
foreach ($row as $fieldname => $value) {
if (in_array($fieldname, $array)) {
$out .= generateTextarea($fieldname, $value, $cke);
}
}
foreach ($row as $fieldname => $value) {
if (in_array($fieldname, $array)) {
$out .= generateImgField($fieldname, $value);
}
}
}
$arr = array("last_modified"=>"input", "published"=>"input", "content"=>"textarea");
echo $automate->createArrayForm('projects', 'update', 'Some form desc', '178514825', $arr, true);
Right now all fields are outputting in every foreach when only inputs should output in the generateInputField section for example. I know this is because I need to check if the fieldtype (input, textarea) key matches with one of the values marked as input or textarea for values of the $fieldname. But I am not sure how.
I am pretty sure I have to filter the array so only values with input go into a separate array like arrayInput in which I can use as the second argument in in_array.
If I understand you and your code correctly...
This code
while ($row = $resultUpdate->fetch_assoc()) {
foreach ($row as $fieldname => $value) {
if (in_array($fieldname, $array)) {
will always return true for all your rows thats why you are getting your current output.
Instead you should be doing this:
while ($row = $resultUpdate->fetch_assoc()) {
foreach ($row as $fieldname => $value) {
if ($fieldname == 'input') {
$out .= generateInputField($fieldname, $value);
} elseif($fieldname == 'textarea') {
$out .= generateTextarea($fieldname, $value, $cke);
} elseif ($fieldname == 'img') {
$out .= generateImgField($fieldname, $value);
}
else{ $out = $out;}
}
}
With alot of help from stackers...
/**
* Create Form With Array
*
* Creates a form based on an array. If $do == update, we match fieldnames with values
*
* #param string $table name of database table
* #param string $do whether the form is an insert or update
* #param string $formDesc form description to be echoed
* #param array $array associative array of type (keys), and fieldnames (values)
* #param bool $markFields whether or not to add headers for inputs, textareas .etc during insert
* #param bool $formBrackets whether or not to prepend and append form brackets
* #return $out html form
*
*/
public function createArrayForm($table, $do, $formDesc = '', $id, $array, $markFields = false, $formBrackets = true) {
if (!isset($table) && !isset($do)) {
self::show_error('One or more parameters are missing in ' . __FUNCTION__);
} elseif ($table == 'update' && !isset($id)) {
self::show_error('For this form to be built, and ID must be set. Missing parameter `ID` in ' . __FUNCTION__);
}
if (!is_array($array)) {
self::show_error('For this form to be built, an array must be given. Missing parameter `array` in ' . __FUNCTION__);
}
$result = array();
// create two dimensional array to preserve keys that
// otherwise would be lost with array_flip
foreach($array as $k => $v) {
if (array_key_exists($v, $result)) {
$result[$v][] = $k;
} else {
$result[$v] = array($k);
}
}
// make sure we do not have any duplicates
$result = super_unique($result);
// we just need the array_values for matching with in_array
// however we do not want to run array_values on null
// so we check to see if the $result is a valid array first
// if not, we just output a blank array so in_array doesn't complain
$arrayInput = is_array($result['input']) ? array_values($result['input']) : array();
$arrayTextarea = is_array($result['textarea']) ? array_values($result['textarea']) : array();
$arrayImages = is_array($result['images']) ? array_values($result['images']) : array();
$out = $formBrackets == true ? '<form action="' . $_SERVER['PHP_SELF'] . '?id=' . $id . '&table=' . $table . '" method="post" class="form-horizontal" ' . $formAppend . '>' : NULL;
if($do == 'insert') {
$out .= isset($formDesc) ? '<div class="form-desc">' . $formDesc . '</div>' : NULL;
$out .= $markFields && in_array('input', $array) ? '<h3>Input Fields</h3>' : NULL;
foreach ($arrayInput as $fieldname) {
$out .= generateInputField($fieldname);
}
$out .= $markFields && in_array('textarea', $array) ? '<h3>Content Fields</h3>' : NULL;
foreach ($arrayTextarea as $fieldname) {
$out .= generateTextarea($fieldname, $cke);
}
$out .= $markFields && in_array('image', $array) ? '<h3>Images Fields</h3>' : NULL;
foreach ($arrayImages as $fieldname) {
$out .= generateImgField($fieldname);
}
} elseif ($do == 'update') {
$resultUpdate = Nemesis::select("*", $table, "id = '{$id}'");
if (!$resultUpdate) {
self::show_error(QUERY_ERROR);
} elseif ($resultUpdate->num_rows > 0) {
$out .= isset($formDesc) ? '<div class="form-desc">' . $formDesc . '</div>' : NULL;
} else {
self::show_error(QUERY_EMPTY);
}
while ($row = $resultUpdate->fetch_assoc()) {
foreach ($row as $fieldname => $value) {
if (in_array($fieldname, $arrayInput)) {
$out .= generateInputField($fieldname, $value);
}
}
foreach ($row as $fieldname => $value) {
if (in_array($fieldname, $arrayTextarea)) {
$out .= generateTextarea($fieldname, $value, $cke);
}
}
foreach ($row as $fieldname => $value) {
if (in_array($fieldname, $arrayImages)) {
$out .= generateImgField($fieldname, $value);
}
}
}
} else {
self::show_error('Missing array or `do` argument in function ' . __FUNCTION__);
}
$out .= form_hidden('user_data', '1');
$out .= form_hidden('id', $do == 'update' ? $id : self::generateID());
$out .= $formBrackets == true ? form_close() : NULL;
return $out;
}
Usage:
$arr = array("last_modified"=>"input", "published"=>"input", "project_content"=>"textarea", "project_content"=>"textarea");
echo $automate->createArrayForm('projects', 'insert', 'Some form desc', '123', $arr, true);
echo $automate->createArrayForm('projects', 'update', 'Some form desc', '178514825', $arr, true);

Categories