Pagination while using a GET variable - php

I have had a difficult time paginating the code below. I think it has to do with passing the GET variable $find on to the next page.
Anyway, how would I paginate the code below, so that the table below shows only 100 rows per page?
Thanks in advance,
John
<?php
ob_start();
session_start();
$find = strip_tags($_GET['find']);
$illegal = array("'", ".", "/", "\"", ";", "{", "}", "[", "]", "\\", "''", "'''", "''''", "'''''", "\\\\", "\\\\\\", "\\\\\\\\");
$find = str_replace($illegal, '', $find);
$find = trim ($find);
$find = strtolower($find);
$find = stripslashes($find);
$_SESSION['find'] = $find;
?>
<?
if ($searching =="yes")
{
if ($find == "")
{
session_write_close();
header("Location:http://www.site.com/index.php");
exit;
unset($_SESSION['find']);
}
mysql_connect("mysqlv10", "username", "password") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());
$find = mysql_real_escape_string($find);
$result=mysql_query("SHOW TABLES FROM database LIKE '$find'")
or die(mysql_error());
if(mysql_num_rows($result)>0){
while($table=mysql_fetch_row($result)){
print "<p class=\"topic\">$table[0]</p>\n";
$r=mysql_query("SELECT * , votes_up - votes_down AS effective_vote FROM `$table[0]` WHERE site != '' ORDER BY effective_vote DESC");
print "<table class=\"navbar\">\n";
while($row=mysql_fetch_array($r)){
$effective_vote = $row['votes_up'] - $row['votes_down'];
print "<tr>";
print "<td class='sitename'>".'<a type="amzn" category="products" class="links2">'.$row['site'].'</a>'."</td>";
print "<td class='votes'>".'<span class="votes_count" id="votes_count'.$row['id'].'">'.number_format($effective_vote).'</span>'."</td>";
print "<td class='ballot'>".'<span class="button" id="button'.$row['id'].'">'.''.vote.''.'</span>'."</td>";
}
print "</tr>\n";
}
print "</table>\n";
}
?>

You have to use LIMIT in your query to tell the database how many rows you want and where to start from.
Pass along a parameter that tells the script that you want another chunk of the results and not just the first batch.
So for the link you can pass along the page parameter:
example.com/results.php?page=2
Where page= will tell the script what page you want to return.
Then you'll want to LIMIT the number of rows returned each time so that you have consistent paging.
$results_cnt = 100; //--rows you want per page of results
Now in your script you'll check to see if the page variable has been set. If not, default the start row to return from the first. But as you want to return different pages/sets of results, a little math is needed in order to start at the proper row.
if(isset($_GET["page"]) //--see if the variable is even there
{
$page_num = (int)$_GET["page"]; //--forcing it to always be an integer
$start_row = $results_cnt * ($page_num - 1);
/* --
what happens:
($results_cnt currently at 100)
on page one (page=1), start at row 0
math: 100 * (1 - 1) = 0
on page two (page=2), start at row 100
math: 100 * (2 - 1) = 100
on page three (page=3), start at row 200
math: 100 * (3 - 1) = 200
etc.
*/
}
else
$start_row = 0;
Now, having set the correct starting row, adjust the SQL query to use the variables like so:
$r = mysql_query("SELECT *, votes_up - votes_down AS effective_vote
FROM `$table[0]`
WHERE site != ''
ORDER BY effective_vote DESC
LIMIT $start_row, $results_cnt");
Every time you hit the page it will be checking to see if $_GET["page"] is there. If not, then display from the first row. If it is, do the maths and work out how many rows to pass over and show the next page of.

you need to use
LIMIT (<pagenumber*amount of records you want to display>,< amount of records you want to display >)
in your SQL statement

Related

Pagination, wrong amount of results on first page

I'm making news website, and I have mysql db with field "time" like 1533074400
Everything is ok if I just print results from query, but if I want to print only news older than today, I get in result only 2 instead of 5 news on first page. Remaining 3 are on the second page.
The problem is with query, if I receive let's say I have in my database 10 results and only 7 of them are past news, so when I filter them descending by
if ($today > news_date)
I get 2 news on first page (the remaining 3 are invisible future news, blocked by code above) and the rest 5 news on second page. So my question is, what to do to get it properly: 5 news on first page and remaining 2 on second page?
$results_per_page = 5;
if (!isset($_GET['page'])) {
$page = 1;}
else {
$page = $_GET['page'];
}
$this_page_first_result = ($page-1)*$results_per_page;
$sql='SELECT * FROM news ORDER BY time DESC LIMIT ' . $this_page_first_result . ',' . $results_per_page;
$result = mysqli_query($con, $sql);
$number_of_results = mysqli_num_rows($result);
$today = strtotime("now");
while($row = mysqli_fetch_array($result))
{
$news_date = $row[1];
if ($today > $news_date) {
echo HTML;
}
}
$number_of_pages = ceil($number_of_results/$results_per_page);
for ($page=1;$page<=$number_of_pages;$page++) {
echo '' . $page . ' ';
}
Try this:
$sql='SELECT * FROM news WHERE time < '.time().' ORDER BY time DESC LIMIT ' . $this_page_first_result . ',' . $results_per_page;
//Note: time() is an equivalent to strtotime("now")
If you're doing pagination in MySQL you should also do your filtering inside MySQL.
[Edit: Additional explanation] If you paginate in MySQL and then filter in PHP you'll have weird instances like this crop up because MySQL doesn't know where you're intending to actually start from. In this particular example if you have a lot of future-dated items you could actually end up with several blank pages of results pages before you start to see entries.
[Edit edit:] Also, if you do this, you'll no longer need the if check in your PHP loop as MySQL will have already done that.

PHP Limit rows returned by MySQL and do something if last row returned

I didn't know exactly how to word this question but by do something I mean that I would like to hide or not show my "next" button that is shown below. I have a script that pulls all the images from MySQL and prints them to my page by 30 images per page and the next 30 will create a new page that is activated by my back/next buttons. My "back" button has a if statement if $startrow isn't >= 0 than it won't show but I would like the same concept with my next button when the last row in my database is shown and it hides my next button.
I was thinking if you can detect the first empty row or the last row of the database and if so hide the next button. Otherwise it keeps adding 30 to $startrow when nothing is shown on screen.
I found a script helping me with this here but it didn't tell me how to hide the next button.
<?php
$startrow = $_GET['startrow'];
if (!isset($_GET['startrow']) or !is_numeric($_GET['startrow'])) {
$startrow = 0;
} else {
$startrow = (int)$_GET['startrow'];
}
?>
<?php
$db = mysqli_connect("localhost", "root", "", "media");
$uploaded = mysqli_query($db, "SELECT * FROM images LIMIT $startrow, 30");
while ($row = mysqli_fetch_array($uploaded)) {
echo "<div class='img_container'>";
echo "<li><img class='img_box' src='uploads/images/".$row['image_title']."' ></li>";
echo "</div>";
}
$prev = $startrow - 30;
if ($prev >= 0) {
echo '<div class="prevRow">Back</div>';
}
echo '<div class="nextRow">Next</div>';
?>
You could try something like
$num_rows = 30; // rows on a page
$db = mysqli_connect("localhost", "root", "", "media");
// get total possible rows
$res = mysqli_query($db, "SELECT count(id) FROM images");
$row = $res->fetch_row();
$total_rows = $row[0];
$res->close();
$uploaded = mysqli_query($db, "SELECT * FROM images LIMIT $startrow, $num_rows");
while ($row = mysqli_fetch_array($uploaded)) {
. . .
}
$prev = $startrow - $num_rows;
if ($prev >= 0) {
echo '<div class="prevRow">Back</div>';
}
if ( $startrow+$num_rows < $total_rows ) {
echo '<div class="nextRow">Next</div>';
}
Potentially a little faster than the answer from #RiggsFolly, you can modify your existing query to count the rows.
SELECT SQL_CALC_FOUND ROWS * FROM images LIMIT $startrow, 30
Then, after the query returns, you run a second query to get the answer:
SELECT FOUND_ROWS()
The FOUND_ROWS() function returns the number of rows the previous query would have returned, without LIMIT (or an offset).
This is probably not as fast as your original query would be in isolation, but should be slightly faster than SELECT COUNT(...) ... followed by your original query. With small data sets, though, any differences will likely be below measurable limits.
See also https://dev.mysql.com/doc/refman/5.7/en/information-functions.html
You can also combine these things into a stored procedure that accepts items per page and page number, and returns all of the records along with metadata items such as the total number of pages.

How do I get the first and last results from a query?

I am creating a pagination script and I need to get the first and last results in the database query so that I can determine what results appear when the user clicks a page to go to. This is the code that I have at the minute:
// my database connection is opened
// this gets all of the entries in the database
$q = mysql_query("SELECT * FROM my_table ORDER BY id ASC");
$count = mysql_num_rows($q);
// this is how many results I want to display
$max = 2;
// this determines how many pages there will be
$pages = round($count/$max,0);
// this is where I think my script goes wrong
// I want to get the last result of the first page
// or the first result of the previous page
// so the query can start where the last query left off
// I've tried a few different things to get this script to work
// but I think that I need to get the first or last result of the previous page
// but I don't know how to.
$get = $_GET['p'];
$pn = $_GET['pn'];
$pq = mysql_query("SELECT * FROM my_table ORDER BY id ASC LIMIT $max OFFSET $get");
// my query results appear
if(!$pn) {
$pn = 1;
}
echo "</table><br />
Page $pn of $pages<br />";
for($p = 1;$p<=$pages;$p++) {
echo "<a href='javascript:void(0);' onclick='nextPage($max, $p);' title='Page $p'>Page $p</a> ";
}
I think you have few problems there, but I try to tackle them for you. First, as comments say above, you are using code that it vulnerable to SQL injection. Take care of that - you might want to use PDO, which is as easy use as MySQL extension, and will save you from many trouble (like injection).
But to your code, lets go through it:
You should ask DB to get count of the rows, not using mysql function, it's far more effective, so use SELECT count(*) FROM mytable.
For $pages use ceil() as you want all rows to be printed, if you have $max 5 and have 11 rows, round will make $pages 2, where you actually want 3 (last page just contains that last 11th row)
in LIMIT you want to LIMIT row_count OFFSET offset. You can calculate offset from page number, so: $max = row_count but $offset = ($max * $page) - $max. In your code if $get is directly the page, it means you get $get'th row (Not sure though what happens in your JS nextpage. Bare in mind that not all use JavaScript.)
I have prepared simple example here which uses PDO, maybe that gives you idea how simple it's use PDO.
The selecting rows shows example how to put parameters in SQL, it would be perfectly safe in this case state, 'SELECT * FROM pseudorows LIMIT '.$start.','.$max by I wanted to make an example how easy it is (and then safe):
// DB config
$DB_NAME = 'test';
$DB_USER = 'test';
$DB_PASSWD = 'test';
// make connection
try {
$DB_CONN = new PDO("mysql:host=localhost;dbname=".$DB_NAME, $DB_USER, $DB_PASSWD);
$DB_CONN->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die($e);
}
// lets say user param 'p' is page, we cast it int, just to be safe
$page = (int) (isset($_GET['p'])?$_GET['p']:1);
// max rows in page
$max = 20;
// first select count of all rows in the table
$stmt = $DB_CONN->prepare('SELECT count(*) FROM pseudorows');
$stmt->execute();
if($value = $stmt->fetch()) {
// now we know how many pages we must print in pagination
// it's $value/$max = pages
$pages = ceil($value[0]/$max);
// now let's print this page results, we are on $page page
// we start from position max_rows_in_page * page_we_are_in - max_rows_in_page
// (as first page is 1 not 0, and rows in DB start from 0 when LIMITing)
$start = ($page * $max) - $max;
$stmt = $DB_CONN->prepare('SELECT * FROM pseudorows LIMIT :start,:max');
$stmt->bindParam(':start',$start,PDO::PARAM_INT);
$stmt->bindParam(':max', $max,PDO::PARAM_INT);
$stmt->execute();
// simply just print rows
echo '<table>';
while($row = $stmt->fetch()) {
echo '<tr><td>#'.$row['id'].'</td><td>'.$row['title'].'</td></tr>';
}
echo '</table>';
// let's show pagination
for($i=1;$i<=$pages;$i++) {
echo '[ '.$i.' ]';
}
}
mysql_fetch_array returns an associative array
Which means you can use reset and end to get the first and last results:
$pqa = mysql_fetch_array($pq);
$first = reset($pqa);
$last = end($pqa);
I don't see how you plan to use the actual results, just page numbers should be sufficient for pagination.
Still, hope it helps. And yes, upgrade to mysqli, so your code doesn't get obsolete.

How to php pagination of results obtained from this database

I am a beginner in php.
I visualize in my html page the results obtained with this php code, and now I want to paginate the results and limit your search to 6 items per page. How can I get this? My php code is as follows:
<?php
$k = $_GET['k'];
$terms = explode(" ", $k);
$query = "SELECT * FROM table_name WHERE ";
$i = 0;
foreach ($terms as $each){
$i++;
if ($i == 1)
$query .= "keywords LIKE '%$each%' ";
else
$query .= "OR keywords LIKE '%$each%' ";
}
// connect
mysql_connect("hostname","databaseUser","databasePassword");
mysql_select_db("databaseName");
$query = mysql_query($query);
$numrows = mysql_num_rows($query);
echo "<p><strong>Totale: {$numrows} risultati trovati</strong></p></br>";
if ($numrows > 0){
while ($row = mysql_fetch_assoc($query)){
$id = $row['id'];
$title = $row['title'];
$description = $row['description'];
$keywords = $row['keywords'];
$link = $row['link'];
$date = $row['date'];
$caption = $row['caption'];
echo "<h4><a href='$link'>$title</a></h4>";
echo "<em>$description</em></br></br>";
echo "$caption</br>";
echo "$link</br></br>";
echo "<em>$date</em></br></br>";
}
}
else
echo "NO result found for \"<p><strong>$k</strong></p>\"";
// disconnect
mysql_close();
?>
Pagination is a problem that most of us have tried to solve over the years.
You can build your own library to do this but you'll almost definitely be re-inventing the wheel and might not spot/handle some of the special cases.
If you're using a framework I'd suggest using the built in paginator, if not you could look at using something like http://pear.php.net/package/Pager which is a PEAR package.
You need to add a page variable into your code. The easiest way to to this is via $_GET, just like you grabbed keywords, so your url should look something like this:
foo.php?k=keywords%20here&p=1
Where p is the current page number.
Then you just need to add a limit to your search results so that you only grab 6, and the correct 6 at that. Something like this:
$query .= ' LIMIT '.(6*($pageNum - 1)).' 6';
This statement tells SQL to start at the first entry for the given page, and grab 6 results. We subtract 1 from the page number so that page 1 starts at entry 0 instead of entry 6.
The result of this code:
page | statement | Rows Grabbed
---------------------------------
1 | LIMIT 0 6 | 1-6
2 | LIMIT 6 6 | 7-12
3 | LIMIT 12 6 | 13-18
---------------------------------
and so on...
You might need to check that $_GET['p'] is an integer before you put it in $pageNum, so that you don't run into runtime issues trying to multiply a string by 6.
If you ever want to change the results per page, simply replace the 6's in that statement with the desired number of results per page, e.g.
$query .= ' LIMIT '.($numResults*($pageNum - 1)).' '.$numResults;
That way you can set your desired number of results with another variable, say $_GET['n'] or something similar, and have even better control.
EDIT:
You should probably add error checking:
$pageNum = (is_numeric($_GET['p']) ? intval($_GET['p']) : 1);
which says if GET[p] is numeric, set pageNum to the integer value of GET[p]. Otherwise, set pageNum to 1.
Also, You have a few errors in the way that you put variables into strings. There are two ways to join a variable into a string, you can either use double quotes and curly braces, like so:
$string = "this string has {$variable} in it";
Or you can concatenate with periods, using either single or double quotes likes so:
$string = 'this string has ' . $variable . " in it";
You have this problem in your foreach loop when you append the query, and also further down where you output your results.

PHP/MySQL Count() Issue

I am trying to create a class registration system for a client that utilizes PHP and MySQL. I have the database and table all set up and that part works just fine, however, the client has requested that upon registration, if there are 3 or fewer students enrolled to warn that the class may not run.
I'm trying to use the count() function as well as passing a dynamic variable from a cookie, set from the registration PHP script. However, I've hit a roadblock. I can't seem to get the count() function to actually count the rows. My select statement is below. Any help would be greatly appreciated.
$class = $_COOKIE["class"];
$min_check = "SELECT class_list, COUNT(class_list) as count
FROM T_Student WHERE class_list = '$class'
GROUP BY class_list
HAVING count < 20";
$result = mysql_query($min_check);
$count = mysql_num_rows($result);
if ($count < 4)
{
echo "IF THERE ARE 3 OR FEWER PEOPLE SIGNED UP FOR THIS CLASS, IT MAY NOT RUN.\n";
echo "THERE ARE CURRENTLY " . $count . " PEOPLE SIGNED UP.\n";
}
else if ($count > 4)
{
echo "There are currently " . $count . " people signed up for this class.";
}
?>
Your SQL query is returning a list of the class_list values, along with a count of each specific instance, where there are less than 20 people registered.
$count = mysql_num_rows($result);
...is getting the number of records returned in the resultset, not the alias count value, which is why you aren't seeing the output you expect. You need to read into your resultset to get the value:
while ($row = mysql_fetch_assoc($result)) {
$count = $row['count'];
if($count < 4) { ... }
}
The count that you want is returned in the row of the query. the mysql_num_rows will count the rows returned, which is not what you want. Use this instead.
$result = mysql_query($min_check);
$count = mysql_fetch_row($result);
$count = $count[0];
On a first glance, the HAVING count < 20 is unnecessary.
You use the MySQL-count-function, but never retrieve it's value!? Use:
$firstRow = mysql_fetch_row($result);
$count = $firstRow[1]; // 1 indicates the second column (0 being the first)
I don't recommend using known MySQL identifiers like count. It's confusing.
$class = mysql_real_escape_string($_COOKIE["class"]);
$min_check = "SELECT class_list, COUNT(class_list) as mycount
FROM T_Student WHERE class_list = '$class'
GROUP BY class_list
HAVING mycount < 20";
Don't forget to escape the contents of that cookie!
The error is that count is a reserved word. You need to either surround it in backticks `count` or even better, use a different moniker. It's not an error per se, but it's just too confusing.
Next up, you are not actually retrieving the mycount result from the database. I suggest using code something like this:
$result = mysql_query($min_check);
while( $row = mysql_fetch_assoc($result) ) {
$people_count = $row['mycount'];
if ($people_count < 4) { echo "this" }
else { echo "that" }
}

Categories