Variable out of scope when entering a while loop in php - php

I have a problem when trying to populate an array in php. It seems that once I enter a while loop with a mysql_fetch_assoc method I cannot populate my array. I've included the code below.
$params = $_REQUEST['params'];
$arr["status"]="ok";
$projects=array();
$files=array();
$titles=array();
$query = 'SELECT p.id as pid, f.fname as name, f.title FROM proj p INNER JOIN pic f ON f.projid=p.id WHERE p.catid=\'' . $params['category'] . '\' ORDER BY p.ordr, f.ordr';
require("../php/connect.php");
//select all projects from chosen category and pics from selected projects
$proj_result = mysql_query($query) or die ("Select failed");
//populate from rows
while($row = mysql_fetch_assoc($proj_result)){
$projects[]=$row["pid"];
$files[]=$row["name"];
$titles[]=$row["title"];
}
$arr["projects"]=$projects;
$arr["files"]=$files;
$arr["titles"]=$titles;
echo json_encode($arr);
The result: {"status":"ok","projects":[],"files":[],"titles":[]}
Thank You.

A while loop doesn't create a new scope, as you can see here: http://codepad.org/H1U3wXZD
About the code itself, here's a few suggestions:
0) I would consider having a database abstraction layer (PDO would be good enough).
1) Learn how to use JOIN's. It looks like you could fetch all the necessary information with a single query, something like:
SELECT p.id, p.proj, c.id, c.fname, c.title
FROM proj p
INNER JOIN pic c ON c.projid=p.id
WHERE catid='<your category>'
ORDER BY p.ordr, c.ordr
2) You should separate the code that gets data from the db from the code that constructs the HTML (?). Perhaps you could put that in another method. Something like:
if ($cmd == 'catSelect') {
$data = getData($params['category']);
foreach ($data as $value) {
// process data here
}
}
3) I take it you are using the generated JSON to send it via AJAX to a client. In that case, I would totally cut the fat (eg: generated markup) and send only essentials (picture id, title, fname and whatever else is essential) and generate the code on the client side. This will make your page load faster and save you and your visitors bandwidth.

my jquery/ajax client side script was not sending in category properly and therefore was no selecting any rows.
The above code will work.

Within the loop try something like this :
while($row = mysql_fetch_assoc($proj_result)){
$projects[]=$row["pid"];
$files[]=$row["name"];
$titles[]=$row["title"];
echo $row["pid"]." -- ".$row["name"]." -- ".$row["title"]."\n";
}
Do you get anything? Once you have tried it we will take it from there. My guess is that you aren't getting any data from MySQL.

Related

Get MySQL data and store it to a PHP array based on the data array returned by another MySQL select operation

I am creating an iOS application and I am facing a difficulty with the web service portion, which is written in PHP. What I am trying to achieve is, sending push notification to the devices. I have completed that part. However, I need a mechanism to differentiate between notifications that has been delivered successfully to the phone and that haven't. I use a feedback web-service for this purpose and It is also working. have a MySQL table with the following structure. Based on the status bit of each notification, I collect all the notifications corresponding to each device token, and make it into an array and send it to the device. Here is where I am facing difficulty.
I have two tables.
This table stores the notification ID, device token and status of the notification. By looking at this table, my script can determine whether the notification has been delivered to the particular device or not. My script collects all the notification IDs that has been undelivered to a particular device ID and uses the following apps_notif table to fetch the undelivered notifications. The table structure is as below.
My PHP/MySQL script is as follows.
$fecthnotif=mysqli_query($mysqli,"SELECT notif_id FROM notif_status WHERE notif_status=0 AND dev_token='$device_token'") or die(mysqli_error($mysqli));
$d2=array();
while($row = mysqli_fetch_assoc($fecthnotif)) {
$d2[]=$row;
$json = json_encode($d2);
$arr = json_decode( $json,true);
By this time, I get an array of undelivered notifications as JSON. The result is as follows.
[{"notif_id":"124"},{"notif_id":"129"}]
Now, I loop though the results as follows.
foreach($arr as $item) { //foreach element in $arr
$uses= $item['notif_id']; }
What I am trying to achieve is to take each notif_id from the above result, fetch allthe notification data from the apss-Notif table, make it a single JSON object and return that payload to the app.So that JSON should have all the notification data of all the notifications that were undelivered at the first place.
Inside the foreach loop, I wrote a query loop to store all the pending notifications to array, but it isnt working.
$d=array();
foreach($arr as $item) { //foreach element in $arr
$uses= $item['notif_id']; //etc
//echo $uses;
$sendnotif=mysqli_query($mysqli,"SELECT * FROM apps_notif WHERE notif_id='$uses'") or die(mysqli_error($mysqli));
while($row = mysqli_fetch_assoc($sendnotif)) {
$d[]=$row;
$i++;
}
}
Edit: Basically, what I am trying to achieve is to return rows from the apps_notif table that match the criteria, notif_status=0 (from table notif_status) and dev_token="qwerty" (from apps_notif table)
I can see that two rows are eligible.
Hope it helps
SELECT b.*
FROM notif_status a
INNER JOIN apps_notif b ON a.notif_id = b.notif_id
WHERE notif_status = 0
AND dev_token = '$device_token';
using sub queries,
SELECT *
FROM app_notify
WHERE notify_id IN (SELECT notif_id
FROM notif_status
WHERE notif_status = 0
AND dev_token = '$device_token') ;
See in your table. In table 1 you have notify_id but in table 2 you have date having kind of similar values. Hence if u match table1 notifyId and table2 notifyId you will not get the desired output. First check the proper criteria how the table should be designed.
You can try below PHP code to get the details from 2 table and make JSON object. Not tested query as i don't have respective DB tables.
$query = "SELECT a.* from apps_notif a JOIN notif_status b ON b.notif_id = a.notif_id WHERE b.notif_status=0 AND b.dev_token='$device_token'";
$res = mysqli_query($mysqli,$query);
$d = array();
while ($row = mysqli_fetch_assoc($res)) {
$d[] = $row;
}
$json = json_encode($d);
Hope this helps you.

Is it bad to put a Query inside an while loop?

I built a Query inside an While loop to get the status from my users. Is there any problem by doing that?
I would like to do it in a different way.
My code.
$output = array();
while($row = mysqli_fetch_assoc($result))
{
if ($row['user_id'] != $id)
{
$checkstatus= mysqli_query($con,"SELECT session_id, status FROM frei_session WHERE session_id = '".$row['user_id']."' ");
$status = mysqli_fetch_row($checkstatus);
if(!$status[0]){
$row['status'] = 0;
}
$output[] = $row;
}
}
$json = json_encode(array("contacts" => $output ));
print($json);
Thank you.
It will blow up your code and can result in very bad performance, escpecially when your main query is returning a lot of rows. A SQL-Server can connect different tables much more efficient by using Joins. For me it seems like a good scenario to use them here. Especially the LEFT-JOIN can be usefull to load a session. It will return NULL for the requested fields when there is no session connected with the current user.
But because I don't even know your main query or much less the use behind your code, you've to decide whether a user without a session makes sense in your case. If not, use a EQUAL-JOIN instead. Then your query wouldn't return any data if no session exists.
An example how can such a JOIN can look when you've two tables USER and SESSION:
SELECT user.username, user.email,
session.status AS session_status
FROM user, session
WHERE user.userid = 123
AND session.session_id = user.user_id
I don't see any problem with having a query like yours inside the while loop. It would become problematic if the query was inefficient (imagine if the query would return 10 lines and you would only use/need 1), but you are targeting your user in the where clause, so it's OK.

Joining 2 statements to pull data from different tables

I have this code:
<?php
$data = mysql_query("SELECT * FROM repin WHERE new_pin_id LIKE ".$pinDetails->id) or die(mysql_error());
while($info = mysql_fetch_array( $data ))
{
Print "".$info['from_pin_id'].",".$info['new_pin_id']."";
}
?>
Obtained thanks to this article: Check field for identical number
I'm trying to use the detail I pulled: ".$info['from_pin_id']." to get data from another table. I'm looking for the best way to do this.
I thought about making it a variable and then running a second statement within the same <?php?> which would look something like this:
Print "".$info['from_pin_id'].",".$info['new_pin_id']."";
}
$newdata = "".$info['from_pin_id']."";
// new statement here.
?>
But 1. it won't work and 2. it looks messy.
What is the best way to achieve it?
FYI, what I need to do is use ".$info['from_pin_id']." to match a field in another table where the data is the same ID, then pull more info based on the match.
Use the following query:
"SELECT *
FROM repin r
LEFT JOIN otherTable o
ON o.someColumn = r.from_pin_id
WHERE r.new_pin_id LIKE '".$pinDetails->id."'"
Also, the argument to LIKE must be a string; you need to put quotes around it.

Include within a while loop

I'm sure my inability to solve this problem steams from a lack of knowledge of some aspect of php but I've been trying to solve it for a month now with no luck. Here is a simplified version of the problem.
In my database I have a members table, a childrens table (the children of each member), and a friend requests table (this contains the friend requests children send to each other).
What I'm attempting to do is display the children of a particular parent using the following while loop....
$query = "SELECT * From children " . <br>
"WHERE parent_member_id = $member_id"; <br>
$result = mysql_query($query) <br>
or die(mysql_error());<br>
$num_children = mysql_num_rows($result);<br>
echo $num_children;<br>
while($row = mysql_fetch_array($result)){<br>
$first_name = $row['first_name'];<br>
$child_id = $row['child_id'];<br>
<div>echo $first_name<br>
}
This while loop works perfectly and displays something like this...
1) Kenneth
2) Larry
What I'm attempting to do though is also display the number of friend requests each child has next to their name...like this
Kenneth (2)
Larry (5)
To do this I attempted the following modification to my original while loop...
$query = "SELECT * From children " .<br>
"WHERE parent_member_id = $member_id";<br>
$result = mysql_query($query) <br>
or die(mysql_error());<br>
$num_movies = mysql_num_rows($result);<br>
echo $num_movies;<br>
while($row = mysql_fetch_array($result)){<br>
$first_name = $row['first_name'];<br>
$child_id = $row['child_id'];<br>
echo $first_name; include('counting_friend_requests.php') ;
}
In this version the included script looks like this...
$query = "SELECT <br>children.age,children.child_id,children.functioning_level,children.gender,children.parent_member_id,children.photo, children.first_name,friend_requests.request_id " .
"FROM children, friend_requests " .
"WHERE children.child_id = friend_requests.friend_two " .
"AND friend_requests.friend_one = $child_id"; <br>
$result = mysql_query($query)<br>
or die(mysql_error());<br>
$count = mysql_num_rows($result);<br>
if ($count==0)<br>
{<br>
$color = "";<br>
}<br>
else<br>
{<br>
$color = "red";<br>
}<br>
echo span style='color:$color' ;<br>
echo $count;<br>
echo /span;<br>
Again this while loop begins to work but the included file causes the loop to stop after the first record is returned and produces the following output...
Kenneth (2)
So my question is, is there a way to display my desired results without interrupting
the while loop? I'd appreciate it if anyone could even point me in the right direction!!
Avoid performing sub queries in code like the plague, because it will drag your database engine down as the number of records increase; think <members> + 1 queries.
You can create the query like so to directly get the result you need (untested):
SELECT child_id, first_name, COUNT(friend_two) AS nr_of_requests
From children
LEFT JOIN friend_requests ON friend_one = child_id OR friend_two = child_id
WHERE parent_member_id = $member_id
GROUP BY child_id, first_name;
It joins the children table records with friend_requests based on either friend column; it then groups based on the child_id to make the count() work.
You don't need to include the php file everytime you loop. Try creating a Person class that has a method getFriendRequestCount(). This method can all the database. This also means you can create methods like getGriendRequests() which could return an array of the friend requests, names etc. Then you could use count($myPerson->getFriendRequests()) to get the number. Thousands of options!
A great place to start, http://php.net/manual/en/language.oop5.php
Another example of a simple class, http://edrackham.com/php/php-class-tutorial/
Eg.
include ('class.Person.php');
while(loop through members)
$p = new Person(member_id)
echo $p->getName()
echo $p->getFriendRequestCount()
foreach($p->getFriendRequests as $fr)
echo $fr['Name']
In your Person class you want to have a constructor that grabs the member from the database and saves it into a private variable. That variable can then be accessed by your functions to proform SQL queries on that member.
Just to clarify whats happening here.
"include" processing is done when the script is parsed. Essentially its just copying the text from the include file into the current file. After this is done the logic is then parsed.
You should keep any include statements separate from you main logic. In most cases the "include"d code will contain definitions for one or more functions. You can then call these functions from the main body of your program at the appropriate place.

php mysql alternative to using same query again inside a loop [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to query a tree structure table in MySQL in a single query, to any depth?
I have an admin area I created that pulls data from the mysql database using php and display the results in a table. Basically it shows a parent category, then the first sub category below it, then the third level sub category/subject.
It works perfectly but as I am new to mysql and php I am sure that it the code needs to be improved in order to save db resources as while building the table I use 3 while loops and in each loop make a mysql query which I am sure is the wrong way to do it.
Can somebody offer me some assistance for the best way of doing this?
Here is the code:
$query = mysql_query("SELECT * FROM categories WHERE
parent_id is null
order by cat_id asc;", $hd)
or die ("Unable to run query");
while ($row = mysql_fetch_assoc($query)) {
echo '<tr style="font-weight:bold;color:green;"><td>'. $row ['cat_id'].'</td><td>'.$row['cat_name'].'</td><td>'.$row ['parent_id'].'</td><td>'.$row['active'].'</td><td>'.$row ['url'].'</td><td>'.$row['date_updated'].'</td></tr>' ;
$query2 = mysql_query("SELECT * FROM categories WHERE
(active = 'true' AND parent_id = ".$row ['cat_id'].")
order by cat_id asc;", $hd)
or die ("Unable to run query");
while ($row2 = mysql_fetch_assoc($query2)) {
echo '<tr style="font-weight:bold;"><td>'. $row2['cat_id'].'</td><td>'.$row2 ['cat_name'].'</td><td>'.$row2['parent_id'].'</td><td>'.$row2 ['active'].'</td><td>'.$row2['url'].'</td><td>'.$row2 ['date_updated'].'</td></tr>' ;
$query3 = mysql_query("SELECT * FROM categories WHERE
(active = 'true' AND parent_id = ".$row2 ['cat_id'].")
order by cat_id asc;", $hd)
or die ("Unable to run query");
while ($row3 = mysql_fetch_assoc($query3)) {
echo '<tr><td>'. $row3['cat_id'].'</td><td>'.$row3['cat_name'].'</td><td>'.$row3 ['parent_id'].'</td><td>'.$row3['active'].'</td><td>'.$row3 ['url'].'</td><td>'.$row3['date_updated'].'</td></tr>' ;
}
}
}
EDIT
Ok so I did a bit of research and this is where I am:
Probably for a small database my approach is fine.
For a bigger database using an array to store the data would probably mean I need to use a recursive approach which might use up too much memory. Would love to hear what people think, would it still be better than looping db queries in the nested while loops?
I found the following thread where there is an answer to do this without reccursion and with only one query. Not sure if I need to add a position column to my current design:
How to build unlimited level of menu through PHP and mysql
If I rebuild the design using the nested sets model instead of adjacency model then the mysql query would return the results in the required order however maintaining the nested sets design is above my head and I think would be overkill.
That's it. If anyone has any input on top of that please add to the conversation. There must be a winning approach as this kind of requirement must be needed for loads of web applications.
I would think you could do something like this:
SELECT * FROM categories
WHERE active = 'true'
ORDER BY parent_id, cat_id
This would give you all your categories ordered by parent_id, then by cat_id. You would then take the result set and build a multi-dimensional array from it. You could then loop through this array much as you currently do in order to output the categories.
While this is better from a DB access standpoint, it would also consume more memory as you need to keep this larger array in memory. So it really is a trade-off that you need to consider.
There is a lot to fix there, but I'll just address your question about reducing queries. I suggest getting rid of the WHERE clauses all together and use if statements within the while loop. Use external variables to hold all the results that match a particular condition, then echo them all at once after the loop. Something like this (I put a bunch of your stuff in variables for brevity)
//before loop
$firstInfoSet = '';
$secondInfoSet = '';
$thirdInfoSet = '';
//in while loop
if($parentID == NULL)
{
$firstInfoSet.= $yourFirstLineOfHtml;
}
if($active && $parentID == $catID) // good for query 2 and 3 as they are identical
{
$secondInfoSet.= $yourSecondLineOfHtml;
$thirdInfoSet.= $yourThirdLineOfHtml;
}
//after loop
echo $firstInfoSet . $secondInfoSet . $thirdInfoSet;
You can now make whatever kinds of groupings you want, easily modify them if need be, and put the results wherever you want.
--EDIT--
After better understanding the question...
$query = mysql_query("SELECT * FROM categories order by cat_id asc;", $hd);
$while ($row = mysql_fetch_assoc($query)){
if($row['parent_id'] == NULL){
//echo out your desired html from your first query
}
if($row['active'] && $row['parent_id']== $row['cat_id']){
//echo out your desired html from your 2nd and 3rd queries
}
}

Categories