PHP encode a partial set of MySQL data into JSON - php

I know how to encode all the data from an SQL query into JSON using PHP, but don't know How to encode a partial set.
In Android (the client), I send an HTTP request which goes something like this:
public interface DataAPI {
#GET("/top500")
public void getResult(#Query("start") int start, #Query("count") int count,
Callback<Top500> response);
}
As you can see, I am using start and count in Android code.
I have around 500 records in my table and I have successfully encoded all the data into JSON, using below PHP Script:
<?php
$con = mysqli_connect(HOST,USER,PASS,DB);
$sql = "select * from Persons";
$res = mysqli_query($con,$sql);
$result = array();
while($row = mysqli_fetch_array($res)){
array_push($result,
array(
'id'=>$row[0],
'name'=>$row[1]
));
}
echo json_encode(array("result"=>$result));
mysqli_close($con);
?>
JSON Result:
{"result": [{ ... }]}
But I need to encode mysql data 20 by 20 like this:
{"count": 20, "start": 0, "total": 500, "result": [{ ...}]}
What's missing is how to use the start and count parameters to get a partial set in order to get slices of the data.

You need to use LIMIT and OFFSET in your query. Applying some nasty logic in PHP is a bad solution. This is an operation that MySQL should do instead because you don't want to fetch all the rows if you don't need all of them.
If you run a query like this:
SELECT *
FROM Persons
ORDER BY Id
LIMIT 10 OFFSET 20
you will get a subset of the matching rows starting from the 20th and long 10 rows. You can then loop over the full results set.
Better to explicitly order by a field to ensure consistency across different pages.
You're final code (using PDO rather than mysqli):
$pdo = new PDO('mysql:dbname=db;host=127.0.0.1', $user, $password);
$count = $_GET['count'];
$start = $_GET['start'];
$stmt = $pdo->prepare('SELECT * FROM Persons ORDER BY Id LIMIT ? OFFSET ?');
$stmt->execute(array($count, $start));
$rows = $stmt->fetchAll();
foreach ($rows as $row) {
// your logic that was inside the while
}

Use below code.
$con = mysqli_connect(HOST,USER,PASS,DB);
$count = "select count(*) as total from Person"; //query to get row count of your table
$count_res = mysqli_query($con,$count);
$count_row = mysqli_fetch_array($count_res);
$total = $count_row['total']; // get total no of records
$start = YOUR_START_VALUE; // from which offset you want to get record
$end = YOUR_VALUE // how many record want to fetch
$sql = "select * from Persons limit $start, $end";
$res = mysqli_query($con,$sql);
$result = array();
while($row = mysqli_fetch_array($res)){
array_push($result,
array(
'id'=>$row[0],
'name'=>$row[1]
));
}
echo json_encode(array("count"=> $end, "start"=> $start, "total"=> $total,"result"=>$result));
mysqli_close($con);
?>

How about something like:
$start = 7;
$size = 3;
$count = 0;
while($row = mysqli_fetch_array($res)){
if($count>=$start && $count <$start+$size) {
array_push($result,array('id'=>$row[0],'name'=>$row[1]));
}
$count++;
}
The code should be self explanatory, but if you have any questions, feel free to comment.
Note: This is more of a PHP pseudo code, as I don't have an environment and haven't coded in PHP in a while.

I can think of 2 ways to solve this problem.
The first is using just MySQL:
SELECT SQL_CALC_FOUND_ROWS * FROM Persons LIMIT 0,20;
SELECT FOUND_ROWS();
With the first query you retrieve the batch of rows you want. With the second you get the total row count in the result set.
The second option is to use array_slice:
$total = count($result);
$batch = array_slice($result, 0, 20);
echo json_encode(array("total" => $total, "start" => 0, "count" => count($batch), "result"=>$batch));

Related

PHP mysql data not retrieving from last id

I'm developing one API in php to display data on android app from my database using JSON.
In my app I want to display 20 records first, after display again 20 records once user scroll to top.
I'm requesting the last id of the record from app to show next 20 records from last id.
Here is my code
<?php
$last_movie = 0;
$genre = $_REQUEST['genre'];
$last_movie = $_REQUEST['lastid'];
require_once("connect.php");
$myArray = array();
if($last_movie == 0)
{
$result = $conn->query("SELECT * FROM my_movies WHERE genre = '$genre' ORDER BY year DESC LIMIT 20");
}
else
{
$result = $conn->query("SELECT * FROM my_movies WHERE genre = '$genre' ORDER BY year LIMIT ".$last_movie.",20");
}
if ($result) {
while($row = $result->fetch_array(MYSQL_ASSOC)) {
$myArray[] = $row;
}
echo json_encode($myArray);
}
$result->close();
$conn->close();
?>
I'm getting values in some genres, but sometimes it show empty JSON.
I tried with this url
http://freemodedapk.com/bobmovies/by_genre.php?genre=Action
its working , whenever I try from last id
http://freemodedapk.com/bobmovies/by_genre.php?genre=Action&lastid=4714
It returns empty JSON. I have values in database.
But some genres working fine
http://freemodedapk.com/bobmovies/by_genre.php?genre=Drama
http://freemodedapk.com/bobmovies/by_genre.php?genre=Drama&lastid=865
I have total 4858 records in the database with all genres.
Anybody can help me to fix empty JSON problems in some of genres ?
Your main issue is in the wrong LIMIT usage: when you utilize 2 parameters for LIMIT keyword, the first one is for OFFSET value (not for IDs), the second one is to limit your result.
In short words: you should use LIMIT 0,20 to get the first 20 results, LIMIT 20,20 to show next 20 results and so on.
Also, your code is insecure - you have SQL injection. Try to not post direct urls on your sites with the source code which includes injection because some bad guys may drop your database or do some other harmful things.
Sample code is listed below (minor changes may be required):
<?php
require_once('connect.php');
$response = [];
$items_per_page = 20;
$page = (int) (($_REQUEST['page'] - 1) * $items_per_page);
$genre = $conn->escape_string($genre); # replace escape_string with proper method if necessary
$result = $conn->query("SELECT * FROM my_movies WHERE genre = '$genre' ORDER BY year DESC LIMIT $page,$items_per_page");
if ($result)
{
$response = $conn->fetch_all($result, MYSQLI_ASSOC); # replace fetch_all with proper method if necessary
}
echo json_encode($response);
$result->close();
$conn->close();
if you want to get last ID to ASC then use to
SELECT * FROM my_movies WHERE genre = '$genre' id<".$last_movie." ORDER BY year LIMIT 0,20
or if you want to get for pagination then your OFFSET value wrong,
you should be use LIMIT 0,20 to get the first 20 results, LIMIT 20,20 to next 20 , LIMIT 40,20
please check your SQL injection
look like Code
require_once('connect.php');
$result = [];
$limit = 20;
$pageNumber = (int) (($_REQUEST['pageNumber'] - 1) * $limit);
$genre = $conn->escape_string($genre);
$getDta = $conn->query("SELECT id,title,stream,trailer,directors,actors,quality,year,genre,length,translation,rating,description,poster FROM my_movies WHERE genre = '".$genre."' ORDER BY year DESC LIMIT $pageNumber,$limit");
if ($result)
$result =$conn->fetch_all($result, MYSQLI_ASSOC);
echo json_encode($result);
$result->close();
$conn->close();

Placing single column database values into an array then calling them in another query

I'm having trouble with pulling database information from 'rownum' column and putting it into an array and then using that array information for my next query that randomly selects one line of the array and then displays it.
<?php
// Connect to database
include 'DB.php';
$con = mysqli_connect($host,$user,$pass);
$dbs = mysqli_select_db($databaseName, $con);
// Select Rownum to get numbers and only where there is no value in seen.
$firstquery = "SELECT rownum FROM num_image WHERE seen=''";
// If there are results store them here
$result = mysqli_query($firstquery) or die ("no query");
// Put the results taken from the table into array so it displays as: array(56, 44, 78, ...) etc...
$result_array = array();
while($row = mysqli_fetch_assoc($result))
{
$result_array[] = $row;
}
// Select the data I require
$query = mysqli_query("SELECT number, association, image_file, skeleton, sound, colour, comments FROM num_image WHERE rownum='$row' LIMIT 1;");
$test = mysqli_query("UPDATE num_image SET Seen='yes' WHERE rownum='$row';");
// Fetch Results of Query, Ignore test.
$arrayss = mysqli_fetch_row($query);
// Echo Results as a Json
echo json_encode($arrayss);
?>
I'm not sure what I have done wrong? Does the array have to be echoed and then my $query line calls that instead?
Updated code - Solved my problem
Thanks for tips guys, it helped me wrap my head around it and came up with a working solution.
<?php
// Connect to database
include 'DB.php';
$con = mysqli_connect($host,$user,$pass);
$dbs = mysqli_select_db($databaseName, $con);
// Select Rownum to get numbers and only where there is no value in seen.
$firstquery = "SELECT rownum FROM num_image WHERE seen=''";
// If there are results store them here
$result = mysqli_query($firstquery) or die ("no query");
// Put the results taken from the table into array so it displays as: array(56, 44, 78, ...) etc...
$result_array = array();
while($row = mysqli_fetch_assoc($result))
{
$result_array[] = $row;
}
for ($i = 0; $i < count($result_array); $i++) {
$all_rownums[] = implode(',', $result_array[$i]);
}
//pick a random point in the array
$random = mt_rand(0,count($all_rownums)-1);
//store the random question
$question = $all_rownums[$random];
// Select the data I require
$query = mysqli_query("SELECT number, association, image_file, skeleton, sound, colour, comments FROM num_image WHERE rownum='$question' LIMIT 1;");
$test = mysqli_query("UPDATE num_image SET Seen='yes' WHERE rownum='$question';");
// Fetch Results of Query, Ignore test.
$arrayss = mysqli_fetch_row($query);
// Echo Results as a Json
echo json_encode($arrayss);
?>
This part is what helped me solve it:
for ($i = 0; $i < count($result_array); $i++) {
$all_rownums[] = implode(',', $result_array[$i]);
}
Happy Dance

how to fetch query from mySql using first three alphabet of a word

I am making an android app to save data into mySql using php.Now after making table and save the data i want to fetch the data.But i want to fetch the data using first three or four letter .How can i do this plz help me.
my php code is.
<?php
require "loginConnect.php";
$bookname = $_GET['bookname'];
$sql = "SELECT * FROM novels WHERE bookname LIKE '$bookname%'";
$r = mysqli_query($con,$sql);
$result = array();
$row = mysqli_fetch_array($r);
array_push($result,array(
"id"=>$row['id'],
"photo"=>$row['photo'],
"bookname"=>$row['bookname'],
"phoneNumber"=>$row['phoneNumber'],
"price"=>$row['price'],
"discription"=>$row['discription'],
"address"=>$row['address'],
"publicationName"=>$row['publicationName']
));
echo json_encode(array('result'=>$result));
mysqli_close($con);
?>
Use PHP substr() and MySQL LIKE
substr($bookname, 0, 4) will give you first four characters.
And like '$bookname%' will give you all records having bookname starting from these four characters.
$bookname = substr($bookname, 0, 3);
$sql = "SELECT * FROM novels WHERE bookname LIKE '$bookname%'";
You can use substr function to get first 3/4 characters of a word. Like this,
$characters = substr($bookname, 0, 4);
And use LIKE in SQL query to find results based on characters you got.
$sql = "SELECT * FROM novels WHERE bookname LIKE '$characters%'";
So your script will look like this.
<?php
require "loginConnect.php";
$bookname = $_GET['bookname'];
$characters = substr($bookname, 0, 4);
$sql = "SELECT * FROM novels WHERE bookname LIKE '$characters%'";
$r = mysqli_query($con,$sql);
$result = array();
$row = mysqli_fetch_array($r);
array_push($result,array(
"id"=>$row['id'],
"photo"=>$row['photo'],
"bookname"=>$row['bookname'],
"phoneNumber"=>$row['phoneNumber'],
"price"=>$row['price'],
"discription"=>$row['discription'],
"address"=>$row['address'],
"publicationName"=>$row['publicationName']
));
echo json_encode(array('result'=>$result));
mysqli_close($con);
?>

PHP PDO - incremental for loop that fetches the next array row with each loop

I'm in the process of updating my old mysql database techniques to prepared pdo statements. I'm all good with while loops while($row = $result->fetch()) however how would I do the following with PDO prepared statements?
$sql = "SELECT * FROM table WHERE id=".$id;
$result = mysql_query($sql) or die(mysql_error());
$loop_count = mysql_num_rows($result);
for($row=0;$row<7 && $loop_count-->0;$row++)
{
// Get next row
$loop_row = mysql_fetch_array($result);
echo $loop_row['field'];
}
I've tried this but with no joy:
$result = $conn->prepare("SELECT * FROM table WHERE id= ?");
$result->execute(array($id));
$loop_count = $result->rowCount();
for($row=0;$row<7 && $loop_count-->0;$row++)
{
// Get next row
$loop_row = $result->fetch();
echo $loop_row['field'];
}
Thanks!
UPDATE: The reason for using a for loop instead of a while loop is the ability to paginate the results, otherwise I would just put LIMIT 7 on the end of the SQL query.
To properly count rows with PDO you have to do this -
$result = $conn->prepare("SELECT * FROM table WHERE id= ?");
$result->execute(array($id));
$rows = $result->fetch(PDO::FETCH_NUM);
echo $rows[0];
But you would be better off using LIMIT in your query if all you want to do is get a static number of results.
In addition you're making your loop overly complex, there is no need to test for a range in the for condition just set the static number unless you're doing something weird, like possibly pagination.
You can try it this way:
$result = $conn->prepare("SELECT * FROM table WHERE id= ?");
$result->execute(array($id));
$loop_rows = $result->fetchAll();
$loop_count = count($loop_rows);
for($row=0;$row<7 && $loop_count-->0;$row++)
{
// Get next row
echo $loop_rows[$row]['field'];
}
As requested by the OP, here's an example of PDO prepared statements using LIMIT and OFFSET for pagination purposes. Please note i prefer to use bindValue() rather than passing parameters to execute(), but this is personal preference.
$pagesize = 7; //put this into a configuration file
$pagenumber = 3; // NOTE: ZERO BASED. First page is nr. 0.
//You get this from the $_REQUEST (aka: GET or POST)
$result = $conn->prepare("SELECT *
FROM table
WHERE id= :id
LIMIT :pagesize
OFFSET :offset");
$result->bindValue(':id', $id);
$result->bindValue(':pagesize', $pagesize);
$result->bindValue(':offset', $pagesize * $pagenumber);
$result->execute();
$rows = $result->fetchAll(PDO::FETCH_ASSOC);
This gives you the complete resultset of rows, limited to your required page. You need another query to calculate the total number of rows, of course.
What you could try is:
//Get your page number for example 2
$pagenum = 2;
//Calculate the offset
$offset = 7 * $pagenum;
//Create array
$data = array();
$result = $conn->prepare("SELECT * FROM table WHERE id= ? LIMIT 7 OFFSET ?");
$result->bind_param("ii", $id,$offset);
$result->execute();
$resultSet = $result->get_result();
while ($item = $resultSet->fetch_assoc())
{
$data[] = $item;
}
$result->close();
//echo resultSet you want
var_dump($data);

PHP nested problems while querying

I am working on a project. I need to query a DB and write the result to a csv file. The result is going to be over 15,000 entries, (thats what the user wants). I am breaking up the results using the LIMIT because if I don't the DB will time out. I divide the query in what I call total_pages. Here is my code.
The big for loop, loops 19 times. The problems is that the code will go through the nested loop one time ( only 500 entries) then It does not go back in. I tried using null on the $results but no luck. Please help.
// using this for my LIMIT
$start_from = 0;
$sql = "select * from someplace where gender = '".$gender."'";
$rs_result = mysql_query($sql);
$total_records = mysql_num_rows($rs_result);
$total_pages = ceil($total_records / 500);
// open a file
//write x in file
file = fopen("./DataFile/gdownload.csv","w");
//write header to the file
$x = "Last Name,First Name,Primary_Name, ........ etc...... \n";
fwrite($file, $x);
for($count = 0; $count <= $total_pages; $count++)
{
$query = "SELECT *
FROM ptable
JOIN person_name ON ptable.Primary_Name = person_name.Primary_Name
WHERE gender = '$gender'
ORDER BY person_name.Lname ASC
LIMIT ".$start_from.", 500";
$result = mysql_query($query) or die(mysql_error());
$num_row = mysql_num_rows($result);
//print tables in rows
while($row = mysql_fetch_array($result))
{
$x="";
$x=$x.$row['Lname'].",";
$x=$x.$row['Fname'].",";
$x=$x.$row['Primary_Name'].",";
$x=$x.$row['asdf#'].",";
$x=$x.$row['qwer'].",";
$x=$x.$row['hjkl'].",";
$x=$x.$row['bnm,'].",";
$x=$x.$row['yui'].",";
$x=$x.$row['aaa'].",";
.....
fwrite($file, $x);
}// end nested while
$start_from+=500;
}// end for loop
fclose($file);
It could be a problem with your LIMIT condition. What you have seems OK to me but the fact that the rows are only being written on the first pass through makes me think $result is empty after the first pass.
Try changing
LIMIT ".$start_from.", 500";
to
LIMIT 500 OFFSET ".$start_from;
Also make sure the query actually returns more than 500 results.
On a different note, it's odd that the request would timeout on just 15,000 records.

Categories