Adjusting last iteration in a foreach loop in PHP - php

I have a question and answer forum. A user may browse responses to questions and promote them if they wish. The code below outputs the different users that have promoted a given question - the users are in the array '$promoters' that is returned from the line $promoters = Promotion::find_all_promotions_for_response($response->response_id); . The foreach loop then goes through each and outputs them, styles by the css class "promoter list". Problem is this.....if I have one promoter I just want their name outputed (no problem with this). But if I have many I want to put a comma between each name and then none after the last name in the foreach loop. Straightforward problem but I failed to achieve this....I tried to add a count($promoters) line in an elseif condition so that if the array $promoters has more than one value, then it outputs the users fullname and then a comma, but of course the last name also has a comma after it which is wrong. How do you indentify the last iteration in a foreach loop and ask it to do something different with this.....
Many thanks guys...
<?php
$promoters = Promotion::find_all_promotions_for_response($response->response_id);
if(!empty($promoters)){
echo "<span class=\"promoted_by\">Promoted by </span>";
foreach($promoters as $promoter){
echo "<span class=\"promoter_list\">" . User::full_name($promoter->user_id) . ", </span>";
}
} else {
echo "";
};
?>

<?php
$promoters = Promotion::find_all_promotions_for_response($response->response_id);
if(!empty($promoters)){
echo "<span class=\"promoted_by\">Promoted by </span>";
foreach($promoters as $idx=>$promoter){
echo "<span class=\"promoter_list\">" . User::full_name($promoter->user_id);
if($idx < count($promoters) - 1) {
echo ", ";
}
echo "</span>";
}
} else {
echo "";
}
?>
UPDATE:
This is another way to do it using implode as suggested by #deceze:
<?php
$promoters = Promotion::find_all_promotions_for_response($response->response_id);
if(!empty($promoters)){
echo "<span class=\"promoted_by\">Promoted by </span>";
$htmlParts = array();
foreach($promoters as $idx=>$promoter){
$htmlParts[] = "<span class=\"promoter_list\">" . User::full_name($promoter->user_id);
}
echo implode(', </span>', $htmlParts) . '</span>';
} else {
echo "";
}
?>

Related

PHP and MYSQLI with LIKE array: does not echo all content correctly

I have come this far and seem to be stuck on this trivial output issue, apologies in advance.
The $getexhibitions is an array and works when only this aspect of code is running. I have then added $results based on a LIKE keyword link that is intended to be an array within the array.
My problem is that the output is supposed to show $getexhibitions->title with the list of each $results->sponsor underneath. Java then creates a drop down with specific sponsor information. This will then repeat for the preceeding 8 years as so.
As you can see the code is getting stuck and i feel as though this may be a div or { problem or it may be more with the array code. Thanks in advance.
http://tenmoregirls.com/tenmoregirls/sponsors.php
<?php
$current_url = base64_encode($url="http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
$query_getexhibitions = $mysqli->query("SELECT * FROM exhibitions ORDER BY year DESC");
if ($query_getexhibitions) {
while($getexhibitions = $query_getexhibitions->fetch_object()) {
echo "<a>$getexhibitions->year | $getexhibitions->title</a>", "<br />";
$sponsorlink = $getexhibitions->year;
$result = $mysqli->query("SELECT * FROM sponsors WHERE (`year` LIKE '%".$sponsorlink."%')");
if ($result) {
while($results = $result->fetch_object()) {
echo "<a href = \"javascript:void(0)\" class=\"subheading\" onclick = \"document.getElementById($results->id).style.display='block'\" >$results->sponsor</a>", "<br />";
echo "<div id=\"$results->id\" style=\"display: none;\">
<img src=\"exhibitstyles/links/close.png\" alt=\"close\" width=\"20\"/><br />";
echo '<img src="sponsorimages/'.$results->logo.'">';
echo $results->summary, "<br />";
echo "$results->website", "<br /><br /><br />";
} "</div>"; } "</div>";
}} exit(); ?>
It's probably not a problem with PHP and MYSQLI, but just with a wrong closing div tag, which is outside the loop. There is also one additional closing tag that don't seem to refer to anything. Try to move </div> tag inside the loop and delete the other one.
Edit:
You were also missing echo command before "</div>"; tag, because you used ; on the end of the previous line. You also can't use , between multiple echo parameters. . is a concatenation operator for strings in php. Whereas . is a concatenation operator for strings, echo construction also allows the usage of , between arguments. My bad.
Try this:
while($getexhibitions = $query_getexhibitions->fetch_object()) {
echo "<a>$getexhibitions->year | $getexhibitions->title</a><br />";
$sponsorlink = $getexhibitions->year;
$result = $mysqli->query("SELECT * FROM sponsors WHERE (`year` LIKE '%".$sponsorlink."%')");
if ($result) {
while($results = $result->fetch_object()) {
echo "<a href = \"javascript:void(0)\" class=\"subheading\" onclick = \"document.getElementById($results->id).style.display='block'\" >$results->sponsor</a><br />";
echo "<div id=\"$results->id\" style=\"display: none;\">
<img src=\"exhibitstyles/links/close.png\" alt=\"close\" width=\"20\"/><br />";
echo '<img src="sponsorimages/'.$results->logo.'">';
echo $results->summary . "<br />";
echo "$results->website<br /><br /><br />";
echo "</div>";
}
}
}

Separate MySQL results into Divs using while loop

Just beginning PHP to bear with me.
Results I'm trying to achiever:
I have a table of YouTube URL's and MetaData.
Trying to build this:
<div class="slide">
<iframe></iframe>
<iframe></iframe>
</div>
<div class="slide">
<iframe></iframe>
<iframe></iframe>
</div>
Two videos per slide, then I'm going to paginate through results using Deck.js.
I suspect I'm going about this completely the wrong way, not that experienced at programmin g logic;
while($data = mysql_fetch_array($result)) {
for ($counter = 1; $counter<=2; $counter++) {
echo "<div class=\"slide\">";
echo "<h3>" . $data['VIDEO_TITLE'] . "</h3>";
echo "<iframe width=\"560\" height=\"315\" src=\"" . $data['VIDEO_URL'] . "\" frameborder=\"0\" allowfullscreen></iframe>";
/* If Video 1, increment counter for 2nd video */
if ($counter == 1) {
$counter++;
}
/* If Video 2, close div and reset counter */
else if ($counter == 2) {
echo "</div>";
$counter = 1;
}
/* If error break out */
else {
echo "</div>";
break;
}
}
}
Basically trying to nest loops to keep track of how many videos per div and start a new one when a div has two.
I've tried a few different ways, this being the latest. Results in:
<div class="slide">
<iframe></iframe>
<div class="slide>
<iframe></iframe>
Hit the blank wall now, not sure what to try next. Willing to use/learn any method to accomplish the results, just not sure where to go at this point.
Cheers.
You could remove the second loop all together using the % operator (modulus). The idea is that a % b === 0 then the number a was evenly divisible by b. Using this, you can easily check for even or odd or every Nth row.
$k = 1;
echo "<div class=\"slide\">";
while($data = mysql_fetch_array($result)) { // you should really change to mysqli or PDO
if($k % 3 === 0){
echo "</div>";
echo "<div class=\"slide\">";
}
echo "<h3>" . $data['VIDEO_TITLE'] . "</h3>";
echo "<iframe width=\"560\" height=\"315\" src=\"" . $data['VIDEO_URL'] . "\" frameborder=\"0\" allowfullscreen></iframe>";
$k++;
}
echo "</div>";
Put the echo <div> before the for loop (still inside the while loop) and the </div> after the for loop
In your while loop you're retrieving just one row, but then you're iterating over it twice with a nested loop. Do away with the inner loop and just use a flip-flop variable to track left and right. I think this will do what you want:
$left=true; // track whether we're emitting HTML for left or right video
while($data = mysql_fetch_array($result)) {
if ($left) {
echo "<div class=\"slide\">";
echo "<h3>" . $data['VIDEO_TITLE'] . "</h3>";
}
echo "<iframe width=\"560\" height=\"315\" src=\"" . $data['VIDEO_URL'] . "\" frameborder=\"0\" allowfullscreen></iframe>";
if (!$left) {
echo "</div>";
}
$left = !$left; // invert $left to indicate we're emitting the right iFrame
}
// end of loop. If we had an odd number of
// videos, tidy up the HTML
if (!$left) {
echo "</div>";
}
PHPFiddle
<?php
$x = 10;
$counter = 0;
while($x > 0)
{
if($counter != 0 && $counter % 2 == 0)
{
echo "ENDOFSLIDE</br>";
}
if($counter == 0 || $counter % 2 == 0)
{
echo "SLIDE</br>";
}
echo "iframe => $x </br>";
$x--;
$counter++;
}
echo "ENDOFSLIDE";
?>
It won't work because the for loop is inside the fetch loop for the SQL data. The second iteration of the for loop does not have a new SQL row. A better solution would be to capture the common column that identifies the two videos (the title) and generate a new div whenever that value changes. Try something like this, which will work for any number of SQL rows with the same title. This will also give proper results if the SQL query returns no rows and will handle the potential of a title with only one URL - which could get ugly if you merely flip-flop and end up with URLs on the wrong title. Of course, as in your current solution, your SQL query must ORDER BY VIDEO_TITLE so the rows are adjacent. I didn't run it, but should be close.
$lastTitle = "";
$n = 0; //count SQL rows processed
while($data = mysql_fetch_array($result)) {
// See if the title changed from last
if( $data['VIDEO_TITLE'] != $lastTitle ) {
// if we processed any rows, must end the current div before starting a new one
if( $n > 0 )
echo "</div>";
echo "<div class=\"slide\">";
echo "<h3>" . $data['VIDEO_TITLE'] . "</h3>";
//save the title as last title
$lastTitle = $data['VIDEO_TITLE'];
}
$n++; //count the SQL row
echo "<iframe width=\"560\" height=\"315\" src=\"" . $data['VIDEO_URL'] . "\" frameborder=\"0\" allowfullscreen></iframe>";
}
if( $n > 0 )
echo "</div>";

How to speedup by code?

is there a way to speed up my code? It takes about 15 seconds to load ... I don't really see a way to reduce my code... I just thought about inserting the values into database, so the user does not have to load new info every time.. but the thing is that my cron only allows 1 load per hour ... by loading new info on every load it gives me fresh information..
$q1=mysql_query("SELECT * FROM isara");
while($r1=mysql_fetch_array($q1)){
$named=$r1['name'];
$idd=$r1['id'];
$descd=$r1['desc'];
$online=check_online($named);
$char = new Character($r1['name'],$r1['id'],$r1['desc']);
if($online == "online"){
$char->rank = $i++;
}
else{
$char->rank = 0;
}
$arr[] = $char;
}
?>
<br />
<h2 style="color:green">Online enemies</h2>
<?php
foreach ($arr as $char) {
if($char->rank>=1){
echo "<a style=\"color:green\" href=\"http://www.tibia.com/community/?subtopic=characters&name=$char->name\">";
echo $char->name." ";
echo "</a>";
echo level($char->name)."<b> ";
echo vocation($char->name)."</b> (<i>";
echo $char->desc." </i>)<br />";
}
}
?>
<br />
<h2 style="color:red">Offline enemies</h2>
<?php
foreach ($arr as $char) {
if($char->rank==0){
echo "<a style=\"color:red\" href=\"http://www.tibia.com/community/?subtopic=characters&name=$char->name\">";
echo $char->name." ";
echo "</a>";
echo level($char->name)."<b> ";
echo vocation($char->name)."</b> (<i>";
echo $char->desc." </i>)<br />";
}
}
?>
As I wrote in the comment, fetch the page once instead of once for every name in the database.
Pseudo code for my comment:
users = <get users from database>
webpage = <get webpage contents>
for (user in users)
<check if user exists in webpage>
As mentioned in the comments you're calling a webpage for each entry in your database, assuming that's about 2 seconds per call it's going to slow you down a lot.
Why don't you call the page once and pass the contents of it into the check_online() function as a parameter so your code would look something like this which will speed it up by quite a few magnitudes:
$content=file_get_contents("http://www.tibia.com/community/?subtopic=worlds&worl‌​d=Isara",0);
$q1=mysql_query("SELECT * FROM isara");
while($r1=mysql_fetch_array($q1)){
$named=$r1['name'];
$idd=$r1['id'];
$descd=$r1['desc'];
$online=check_online($named,$content);
$char = new Character($r1['name'],$r1['id'],$r1['desc']);
if($online == "online"){
$char->rank = $i++;
}
else{
$char->rank = 0;
}
$arr[] = $char;
}
?>
<br />
<h2 style="color:green">Online enemies</h2>
<?php
foreach ($arr as $char) {
if($char->rank>=1){
echo "<a style=\"color:green\" href=\"http://www.tibia.com/community/?subtopic=characters&name=$char->name\">";
echo $char->name." ";
echo "</a>";
echo level($char->name)."<b> ";
echo vocation($char->name)."</b> (<i>";
echo $char->desc." </i>)<br />";
}
}
?>
<br />
<h2 style="color:red">Offline enemies</h2>
<?php
foreach ($arr as $char) {
if($char->rank==0){
echo "<a style=\"color:red\" href=\"http://www.tibia.com/community/?subtopic=characters&name=$char->name\">";
echo $char->name." ";
echo "</a>";
echo level($char->name)."<b> ";
echo vocation($char->name)."</b> (<i>";
echo $char->desc." </i>)<br />";
}
}
?>
and your check_online() function would look something like this:
function check_online($name,$content){
$count=substr_count($name, " ");
if($count > 0){ $ex=explode(" ",$name); $namez=$ex[1]; $nameused=$namez; }
else{ $nameused=$name; }
if(preg_match("/$nameused/",$content)){ $status="online"; }
else{ $status="offline"; }
return $status;
}
You can also do the following to make it faster
Stop using select * which is very bad on innodb
Put better indexes on your database to make the recordset return faster
Install PHP 5.4 as it's faster especially as you're creating a new object in each iteration
Use a byte code accelerator/cache such as xdebug
you should avoid using distinct (*) keyword in your SQL Query
for more information read this http://blog.sqlauthority.com/category/sql-coding-standards/page/2/

Foreach loop echo

The last foreach loop doesn't seem to echo the list I want, it doesn't print anything. How can I fix this? I know it's getting quite complicated but any help would be appreciated.
$allTroopsList = array();
$allMissionsList = array();
while ($mytroops = $alltroops->fetch_assoc())
{
$allTroopsList []= $mytroops;
}
while ($mymissions = $allmissions->fetch_assoc())
{
$allMissionsList []= $mymissions;
}
while($userintroop = $allUsersintroops->fetch_assoc())
{
if($userintroop['userid'] == $_SESSION['userid'])
{
echo "<ul class='troop'>";
echo "<li>" . $userintroop['troopid']. " </li>";
foreach($allTroopsList as $mytroops)
{
if($userintroop['troopid'] == $mytroops['troopid'])
{
echo "<li> Troop description: " . $mytroops['description']. " </li>";
foreach($allMissionsList as $mymissions)
{
if($mytroops['missionid'] == $mymissions['missionid'])
{
echo "<li> Missionname: " . $mymissions['missionname']. " </li>";
echo "<br/>";
echo "</ul>";
}
}
}
}
}
}
foreach($allUsers as $myotherusers)
{
if($userintroop['userid'] == $myotherusers['userid'])
{
echo "<li> other users: " . $myotherusers['username']. " </li>";
echo "<br/>";
}
}
This line:
while($userintroop = $allUsersintroops->fetch_assoc())
is fetching results from a database, right? That'd mean at some point you run out of rows to fetch, and $userintroop will become a boolean FALSE.
Then later on you try to do
if($userintroop['userid'] == $myotherusers['userid'])
which is wrong on two levels - $userintroop will NOT be an array at this point, so it could never have a ['userid'] parameter. And since it's the result of a failed fetch operation, never could have any value OTHER than a FALSE.
So that last loop does execute, but will never produce anything since the conditions for producing output are literally impossible to meet.

While inside while php

We're trying to put a while inside a while loop.
The first while is run through and the results are displayed in a list (139, 140, 141).
The list for the second while only displays one value (1ste troop).
These are the results:
139
1ste troop
140
141
So it seems that the second while is only executed once.
What can I do to fix this?
echo "<ul>";
while($user = $allUsersintroops->fetch_assoc())
{
if($user['userid'] == $_SESSION['userid'])
{
echo "<li>" . $user['troopid']. " </li>";
while ($mytroops = $alltroops->fetch_assoc())
{
if($user['troopid'] == $mytroops['troopid'])
{
echo "<li>" . $mytroops['description']. " </li>";
}
}
}
}
echo "</ul>";
The inner loop stops once fetch_assoc returns false... but that indicates the end of all found results and it doesn't have any rows left for the next iteration.
You should collect all the rows from $alltroops into an array once, then iterate over that:
echo "<ul>";
$allTroopsList = array();
while ($mytroops = $alltroops->fetch_assoc()) {
$allTroopsList []= $mytroops;
}
while($user = $allUsersintroops->fetch_assoc()) {
if($user['userid'] == $_SESSION['userid']) {
echo "<li>" . $user['troopid']. " </li>";
foreach($allTroopsList as $mytroops) {
if($user['troopid'] == $mytroops['troopid']) {
echo "<li>" . $mytroops['description']. " </li>";
}
}
}
}
echo "</ul>";
Additionally, you should consider adding some filtering to your $allUsersintroops query, because you are only using a part of the the returned rows, which means the rest of the rows are sent from the DB to your code for no reason, wasting time and bandwidth.

Categories