XML - Nodes with the same name showing only one time in PHP - 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>";

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.)

Moving empty values of an array to the last position

I'm pulling an array from an external API, And I've got some help with usort on here, And It pushes it to the bottom, and empty values are on top. I tried using unset but that just emptied out my entire realArrival values.
e.g.
$fromThis = array(
"realArrival": "",
"realArrival": "Confirm. 06:18",
"realArrival": "Confirm. 06:19"
);
Into:
$intoThis = array(
"realArrival": "Confirm. 06:18",
"realArrival": "Confirm. 06:19",
"realArrival": ""
);
Here is my code on how I tried to do it. I'm sure you are shaking your head at this but here it goes.
$url = 'http://apis.is/flight?language=en&type=arrivals';
$json = file_get_contents($url);
$results = json_decode($json, TRUE);
$results = $results['results'];
function cmp($a, $b) {
return strcmp($a['realArrival'], $b['realArrival']);
}
//Sort Time
usort($results, "compare_time");
function compare_time($a,$b) {
$splitA= count(explode(' ',$a['realArrival']));
$splitB= count(explode(' ',$a['realArrival']));
if($splitA==2 && $splitB==2)
{
$first_time = strtotime(explode(' ',$a['realArrival'])[1]);
$second_time = strtotime(explode(' ',$b['realArrival'])[1]);
if($first_time==$second_time)
{
return strcmp($b['realArrival'], $a['realArrival']);
}
return ($second_time < $first_time) ? 1: 0;
}
return strcmp($a['realArrival'], $b['realArrival']);
}
echo '<table class="highlight bordered responsive-table grey darken-2 col s6">';
echo "<tr>";
echo '<th>Date</th>';
echo '<th>Flight Number</th>';
echo '<th>Airline</th>';
echo '<th>From</th>';
echo '<th>Schedule. Time</th>';
echo '<th>Status</th>';
echo "</tr>";
foreach ($results as $item => $val) {
echo "<tr>";
echo '<td>'.$val['date'].'</td>';
echo '<td>'.$val['flightNumber'].'</td>';
echo '<td>'.$val['airline'].'</td>';
echo '<td>'.$val['from'].'</td>';
echo '<td>'.$val['plannedArrival'].'</td>';
// HERE I TRIED TO TARGET THE EMPTY VALUES
if ($val === "") {
unset($results[$item]);
$results[] = $val;
echo '<td style="font-weight: bold;">'.$val['realArrival'].'</td>';
}
echo '</tr>';
}
I know this might seem clunky, but you could always just do something like...
$items_with_real_arrivals = array();
$items_without_real_arrivals = array();
foreach ($results as $item => $val) {
if ($item[‘realArrival’] === "") { $items_without_real_arrivals.push($item); }
else $items_with_real_arrivals.push($item);
}
$reordered_items = array();
for ($i=0; $i<count($items_with_real_arrivals); $i++) {
$reordered_items.push($item);
}
for ($i=0; $i<count($items_without_real_arrivals); $i++) {
$reordered_items.push($item);
}
foreach ($reordered_items as $item => $val) {
echo "<tr>";
echo ' <td>'.$val['date'].'</td>';
echo ' <td>'.$val['flightNumber'].'</td>';
echo ' <td>'.$val['airline'].'</td>';
echo ' <td>'.$val['from'].'</td>';
echo ' <td>'.$val['plannedArrival'].'</td>';
echo ' <td style="font-weight:bold;">' . $val['realArrival'].'</td>';
echo '</tr>';
}

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?

php foreach error handling in function

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().

Categories