I have an Ajax call to create an image gallery. There is a combo box to set the number of images per page, and pagination to navigate through the pages. It's working fine, except that if a person is on the last page, and they increase the number of images per page, it reloads to the current page number. This is a problem because there are now less pages and so the page is blank. In other words, you end up on page 7 of 5 for instance.
I reckon the problem is in the PHP as that is where the number of pages is calculated. I've thought out an if statement to deal with this:
if ($page > $no_of_paginations) {
$page = $no_of_paginations;
}
However, I don't know where to place this. The reason being, $page needs to be defined before the mysql_query, but $no_of_paginations is defined after the query.
Any thoughts on how I can make this functional?
I'll post the pertinent code below:
<?php
$page = 0;
if(isset($_GET['page'])){
$page = (int) $_GET['page'];
}
$cur_page = $page;
$page -= 1;
if((int) $_GET['imgs'] > 0){
$per_page = (int) $_GET['imgs'];
} else {
$per_page = 16;
}
$start = $per_page * $page;
include"db.php";
$query_pag_data = "SELECT `imgURL`,`imgTitle` FROM `images` ".
"ORDER BY `imgDate` DESC LIMIT $start, $per_page";
$result_pag_data = mysql_query($query_pag_data) or die('MySql Error' . mysql_error());
echo "<ul class='new_arrivals_gallery'>";
while($row = mysql_fetch_assoc($result_pag_data)) {
echo "<li><a target='_blank' href='new_arrivals_img/".$row['imgURL']."' class='gallery' title='".$row['imgTitle']."'><img src='new_arrivals_img/thumbnails/".$row['imgURL']."'></a></li>";
}
echo "</ul>";
/* --------------------------------------------- */
$query_pag_num = "SELECT COUNT(*) AS count FROM images";
$result_pag_num = mysql_query($query_pag_num);
$row = mysql_fetch_array($result_pag_num);
$count = $row['count'];
$no_of_paginations = ceil($count / $per_page);
?>
Thanks for your help!
As you are currently doing it, there would be no problem with moving the last section to above the main query.
A better way to find the total records with MySQL is to use the SQL_CALC_FOUND_ROWS keyword on your main query (so here it is SELECT SQL_CALC_FOUND_ROWS imgURL, imgTitle FROM images WHERE etc) then you can query SELECT FOUND_ROWS() and just get the number of records found in the last query. As well as being faster and more efficient, this avoids a race condition when records are added between the two queries.
However, in this case you should probably just do the two current queries in the reverse order as your only other option is to check at the end and repeat if necessary.
You should use query:
$query_pag_data = "SELECT SQL_CALC_FOUND_ROWS `imgURL`,`imgTitle` FROM `images` ".
"ORDER BY `imgDate` DESC LIMIT $start, $per_page";
And instead of
$query_pag_num = "SELECT COUNT(*) AS count FROM images";
use
$query_pag_num = "SELECT FOUND_ROWS()";
If you do the "SELECT COUNT(*) ..." query earlier in the script (at least before the other query), you will have $no_of_paginations earlier, and can use it to clamp $page to the correct range.
Sometimes you just have to bite the bullet and do a query twice. Accept the user-provided "I want page X" value, and try to get that particular page. If it ends up being past the end of the available data, you can either say "hey, wait... that ain't right" and abort, or redo the loop and default to the last available page.
while(true) {
$sql = "select sql_calc_found_rows .... limit $X,$Y";
$result = mysql_query($sql) or die(mysql_error());
$sql = "select found_rows();"; // retrieve the sql_calc_found_rows_value
$res2 = mysql_query($sql);
$row = mysql_fetch_array($res2);
$total_rows = $row[0];
if ($total_rows < $requested_row) {
... redo the loop and request last possible page ...
} else {
break;
}
}
details on found_rows() function here.
Related
I have a php pagination script that I found online ( http://papermashup.com/easy-php-pagination/), and it works fine and i want to modify it to better suit my needs and update it a little bit. The problem i am having is that whilst it gives the number of results found, using
echo $total_pages.' Results';
It will not return a zero if there are no results it just simply has no value.
Here is the code that counts the number of results.
$query = "SELECT COUNT(*) as num FROM $tableName";
$total_pages = mysql_fetch_array(mysql_query($query));
$total_pages = $total_pages[num];
I have tried to add an if statement so that if the results are 0 i can say sorry no matches found, but i can not get the value to display if there are no results.
I have tried to echo COUNT as a row along with num but no matter what i do, i can not seem to get it to display 0 results.
Extending on your code:
$query = "SELECT COUNT(*) as num FROM {$tableName}";
$total_pages = mysql_fetch_array(mysql_query($query));
$total_pages = $total_pages['num'];
if (!empty($total_pages)) {
echo $total_pages . " Results found.";
} else {
echo "Sorry! No results found.";
}
You can achieve this by using the function mysql_num_rows();
$result_set = mysql_query($query);
$count = mysql_num_rows($result_set);
p.s. please try to use mysqli rather than simple mysql as its deprecated now.
Try it.
$query = mysql_query("SELECT * FROM $tableName");
$num = mysql_num_rows($query);
if($num > 0)
{
echo "Total records = ".$num;
}
else
{
echo "Sorry no record found";
}
I have a simple form to search a table for the search term entered into that form.
$query = $_GET['term'];
$min_length = 1;
if(strlen($query) >= $min_length){
$query = htmlspecialchars($query);
$query = mysqli_real_escape_string($link, $query);
}
Here the variable 'query' is the search query posted from the form.
The query for the database looks like this
$sql = mysqli_query($link, "SELECT * FROM products WHERE `name` LIKE '%".$query."%' OR
`brand` LIKE '%".$query."%'
OR `description` LIKE '%".$query."%' OR `spec` LIKE '%".$query."%'
OR `category` LIKE '%".$query."%' OR `subcategory` LIKE '%".$query."%' AND status = 1
ORDER BY id DESC LIMIT $offset, $rowsperpage") OR die(mysqli_error($link));
So this works ok if I dont paginate results, but I need to paginate them.
I think I need to get this line of code to send the variable '$query' to each paginated page.
echo " <a href='{$_SERVER['PHP_SELF']}?$query¤tpage=$x'>$x</a> ";
'$x' is just the variable for the current page
My form is now set to method="get"
EDIT: Sorted (I think)
I had everything wrapped in a
if(isset( $_GET['submit'] ) ){
}
So it appears to me that when I went to any other page but the first page (the first time) that submit from my search form wasn't being posted again obviously, so there were no results to get.
When I took that 'if' out the pagination works. But is it ok not to have it?
You need to forward term parameter and current page index. Also you must add
offset $x*$pagesize
limit $pagesize
to your query...
A few thoughts here:
Before even getting into the pagination aspects, just by looking at your query, I would suggest you look at using a MySQL natural language full text search (http://dev.mysql.com/doc/refman/5.5/en/fulltext-natural-language.html). that would make your query something like this:
SELECT * FROM products
WHERE
MATCH (name, brand, description, spec, category, subcategory)
AGAINST :query
AND STATUS = 1
This requires a FULLTEXT index across the fields used in the search. This requires use of MyISAM engine for the table.
An interesting thing to note about using the full text search in the where clause like this is that it will return rows in order of "relevance". So, for example, a record that has a number of matches across DB columns for you search term will have higher relevance than a record with a single match. In most search uses cases like yours, this is desired behavior, and your current query does nothing at all to provide this sort of functionality.
Now on to pagination.
You would likely need to pass some additional parameters to indicate page. So say your parameters are like this:
// you should provide some validation for these parameters, but I am not showing that
$query = $_GET['term'];
$page = $_GET['page'];
You would also somewhere in your code have some value set to determine rows per page to be shown. This could even be in the form of a parameter as well if you want to let the user select number of rows per page.
$rows_per_page = $_GET['pagerows'];
// or simply something like $rows_per_page = 10;
Calculation of values to use in the LIMIT clause is trivial. I am assuming $page is 1-based (i.e. first page has value of 1)
$offset = ($page - 1) * $rows_per_page;
Putting it together with the query above you get:
SELECT * FROM products
WHERE
MATCH (name, brand, description, spec, category, subcategory)
AGAINST :query
AND STATUS = 1
LIMIT :offset, :pagerows
Note I am just using named parameter syntax in the queries. You should consider using prepared statements for these queries.
So that is is the simple use case. Now what if you want to show the user some indication as to the number of pages associated with the search result? This means that you need to understand how many rows the query would return if there was no LIMIT clause. There are a couple of ways of doing this. You could simply run the same query without the LIMIT first and get the number of rows from that query. This may be appropriate for cases where you were not accepting user input to filter the result set and the user could arrive in the pagination view on any arbitrary page number.
That does not seem to be the use cases realted to a search, so I will give you another option which may best suite the search query use case. That is the use of SQL_CALC_FOUND_ROWS keyword in conjunction with FOUND_ROWS() functions. Here is how it works.
You simply add SQL_CALC_FOUND_ROWS into you SELECT query like this:
SELECT SQL_CALC_FOUND_ROWS * FROM products
WHERE
MATCH (name, brand, description, spec, category, subcategory)
AGAINST :query
AND STATUS = 1
LIMIT :offset, :pagerows
Your query will return the paginated result as expected, but using the same DB connection, you can then make a follow-up query to get the number of "found rows" (i.e. rows in result set before applying LIMIT from the last query). That query is very simple:
SELECT FOUND_ROWS()
So here is how this may look from a coding perspective:
$sql = <<<EOT
SELECT SQL_CALC_FOUND_ROWS * FROM products
WHERE
MATCH (name, brand, description, spec, category, subcategory)
AGAINST :query
AND STATUS = 1
LIMIT :offset, :pagerows
EOT;
// perform query here
// work with your result set
while ($row = /* your row fetch logic here */) {
// do something with row
}
// now query DB again to get found rows
// you must use same DB connection used for initial query
// and you must not perform any queries between your initial
// SELECT and this query to get row count
$row_sql = 'SELECT FOUND_ROWS()';
// execute your query and read the value from the result
// lets assume you set this to a variable named $total_rows
// now simply determine number of available page by simple math and rounding
$page_count = ceil($total_rows / $rows_per_page);
Please try something like this:
pagination.php
<?php
function getPagingQuery($sql, $itemPerPage = 10)
{
if (isset($_GET['page']) && (int)$_GET['page'] > 0) {
$page = (int)$_GET['page'];
} else {
$page = 1;
}
// start fetching from this row number
$offset = ($page - 1) * $itemPerPage;
return $sql . " LIMIT $offset, $itemPerPage";
}
function getPagingLink($sql, $itemPerPage = 10,$strGet)
{
$result = mysql_query($sql) or die(mysql_error());
$pagingLink = '';
$totalResults = mysql_numrows($result);
$totalPages = ceil($totalResults / $itemPerPage);
// how many link pages to show
$numLinks = 10;
// create the paging links only if we have more than one page of results
if ($totalPages > 1) {
$self = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] ;
if (isset($_GET['page']) && (int)$_GET['page'] > 0) {
$pageNumber = (int)$_GET['page'];
} else {
$pageNumber = 1;
}
// print 'previous' link only if we're not
// on page one
if ($pageNumber > 1) {
$page = $pageNumber - 1;
if ($page > 1) {
$prev = " [Prev] ";
} else {
$prev = " [Prev] ";
}
$first = " [First] ";
} else {
$prev = ''; // we're on page one, don't show 'previous' link
$first = ''; // nor 'first page' link
}
// print 'next' link only if we're not
// on the last page
if ($pageNumber < $totalPages) {
$page = $pageNumber + 1;
$next = " [Next] ";
$last = " [Last] ";
} else {
$next = ''; // we're on the last page, don't show 'next' link
$last = ''; // nor 'last page' link
}
$start = $pageNumber - ($pageNumber % $numLinks) + 1;
$end = $start + $numLinks - 1;
$end = min($totalPages, $end);
$pagingLink = array();
for($page = $start; $page <= $end; $page++) {
if ($page == $pageNumber) {
$pagingLink[] = " $page "; // no need to create a link to current page
} else {
if ($page == 1) {
$pagingLink[] = " $page ";
} else {
$pagingLink[] = " $page ";
}
}
}
$pagingLink = implode(' | ', $pagingLink);
// return the page navigation link
$pagingLink = $first . $prev . $pagingLink . $next . $last;
}
return $pagingLink;
}
?>
product_search.php
$query = $_GET['term'];
$select = "SELECT * FROM products WHERE `name` LIKE '%".$query."%' ";
$strget="term=".$query;
$rowsPerPage =10;
$result= mysql_query(getPagingQuery($sel_products, $rowsPerPage, $strget)) or die(mysql_error());
$pagingLink = getPagingLink($sel_products, $rowsPerPage, $strget);
$num_rows = mysql_numrows($result);
if($num_rows > 0) {
while($array_in= mysql_fetch_array($result))
{
$product_id = $array_in['id'];
$product_name = $array_in['name'];
}
echo $pagingLink;
}
else
{
echo "No Results To Display";
}
I hope it should work.
How to add pagination in this code?
I want to limited data in one page and I want in bottom as:
1 2 3 4 5 6 8 9 10
If I click on page 2 then my more results show on that page.
How can I do like that ?
<?php
//connect to database
mysql_connect('localhost','root','pasword');
mysql_select_db('root');
/* Get the letter user clicked on and assign it a variable called $sort */
$sort = $_REQUEST['letter'];
/* Let's check if variable $sort is empty. If it is we will create a query to display all customers alphabetically ordered by last name. */
if($sort == ""){
$qry= "SELECT * FROM tree ORDER BY keywords ASC " ;
}else{
/* if varible $sort is not empty we will create a query that sorts out the customers by their last name, and order the selected records ascendingly. */
$qry = "SELECT * FROM tree WHERE keywords LIKE '$sort%' ORDER BY keywords ASC" ;
}
/* Notice the use of '%' wilde card in the above query "LIKE '$sort%'". */
//next step is to execute the query.
$execute = mysql_query($qry) or die(mysql_error());
/* Before we display results let's create our alphabetical navigation. The easiest way to create the navigation is to use character codes and run them through the "for" loop. */
echo "<p>" ;
for ($i = 65; $i < 91; $i++) {
printf('%s | ',
$PHP_SELF, chr($i), chr($i));
}
echo "</p>" ;
/* now we are ready to display the results. Since out tbl_customers table has only three fileds we will display the results in a paragraphs. In the real world you may need to display the results in a table.
To display the results we will use "do while" loop to fetch the results. If no customers are found we will display an error message. */
if(mysql_num_rows($execute)>0){
do{
echo "<p>" .$result['id']. " " .$result['keywords']. " " .$result['meaning']. "</p>" ;
}while($result = mysql_fetch_assoc($execute));
}else{
echo "<p>No customer found.</p>" ;
}
?>
First select no of datas to generate page numbers by total_number of rows by no of pages per page
mysql_num_rows($execute);
use limit command to limit the data like this
$qry= "SELECT * FROM tree ORDER BY keywords ASC limit 0,10 " ;
then for every page number increment the limit index
You can use the below code
$page = $_GET['page'];
if ($page < 1)
{
$page = 1;
}
$conc=mysql_connect('localhost','root','');
mysql_select_db('employer',$conc);
$resultsPerPage = 5;
$startResults = ($page - 1) * $resultsPerPage;
$query = mysql_query('SELECT * FROM employee ') or die(mysql_error());
$numberOfRows=mysql_num_rows($query);
$totalPages = ceil($numberOfRows / $resultsPerPage);
$query = mysql_query("SELECT * FROM employee LIMIT $startResults,$resultsPerPage");
while ($output = mysql_fetch_assoc($query))
{
$result[]=$output;
}
for($i = 1; $i <= $totalPages; $i++)
{
if($i == $page)
echo '<strong>'.$i.'</strong> ';
else
echo ''.$i.' ';
}
$page = intval(abs($_GET['page'])); // get security ONE
if(mysql_num_rows($sql)) // get page number to empty location index.php
{
header('Location: index.php');
}
I don't know how to make the search through another table. how should i do that?
the table name is comments and i want to search for all the post stored in the column name kom
Another thing is that i cant get the pagination start working...
I started the pagination within an else statment because i only need it when i get more than 1 result.
I can get the page links showing and limit the search posting showing but when i click on one off the links i cant get to the next page
Heres the code
<?php
$search = $_POST["search"];
$field = $_POST["field"];
if($_POST["submit"] && $search)
{
echo "<div id='result'>";
echo "<h2>Resultat</h2>";
$search = strtoupper($search);
$search = strip_tags($search);
$search = trim($search);
$query = "SELECT * FROM blogTable WHERE title LIKE '%$search%'
UNION
SELECT * FROM blogTable WHERE post LIKE '%$search%'";
$result = mysql_query($query, $conn) or die(mysql_error());
$matches = mysql_num_rows($result);
if($matches == 0)
//code if serch didnt result any results
else if($matches == 1)
//code if the matches only 1
else
{
$per_page = 4;
$pages = ceil($matches / $per_page);
$page = (isset($_GET['page'])) ? (int)$_GET['page']: 1;
$start = ($page - 1) * $per_page;
$query2 = "SELECT * FROM blogTable WHERE title LIKE '%$search%'
UNION
SELECT * FROM blogTable WHERE post LIKE '%$search%' LIMIT $start, $per_page";
$result2 = mysql_query($query2, $conn) or die(mysql_error());
echo "<font size='-1'>Sökningen $search gav $matches resultat</font><br/>";
while ($r2 = mysql_fetch_array($result2))
{
$id = $r["id"];
$title = $r["title"];
$post = $r["post"];
$time = $r["time"];
echo "<br/><strong><a href='comment.php?id=$id'>$title</a></strong><br/>";
echo "<font size='-1'>".substr($post, 0, 60)."</font><br/>";
echo "<font size='-1'>".substr($post, 60, 70)."</font><br/>";
echo "<font size='-3'>$time</font><br/>";
}
//theese are showin but cannot click of any of them
if($pages >= 1 && $page <= $pages)
{
for($nr = 1; $nr <= $pages; $nr++)
{
if($nr == $page)
echo "<a href='?page=".$nr."' style='font-size:20px;'>$nr</a>";
else
echo "<a href='?page=".$nr."' style='font-size:15px;'>$nr</a> ";
}
}
}
}
?>
Is there a specific reason you are using a UNION?
If not, you can change:
$query = "SELECT * FROM blogTable WHERE title LIKE '%$search%'
UNION
SELECT * FROM blogTable WHERE post LIKE '%$search%'";
to:
$query = "SELECT * FROM blogTable WHERE (title LIKE '%$search%') OR (post LIKE '%$search%')";
Anyway, I would never execute the same query twice, just get the first x results if no start parameter was given (for example a page number in the query string) and calculate the start point when a start parameter was given.
And if you want the total, use a COUNT(*) query or change your query:
$query = "SELECT SQL_CALC_FOUND_ROWS * FROM blogTable WHERE (title LIKE '%$search%') OR (post LIKE '%$search%')";
One thing that catches the eye is that the code you show is vulnerable to SQL injection.
Get rid of the strip_tags() (if it's for security, in which case it's useless) and do a mysql_real_escape_string() on every value you use in the search queries, or check whether the value is actually a number when using int columns.
Another thing is that the <font> tag is outmoded. The cool CSS way of styling text is having an external CSS stylesheet, and defining in it something like
span.small { font-size: 12px; color: green }
and then using it in the HTML like so:
<span class="small">Text goes here</span>
that said, this probably belongs on CodeReview.SE....
First, I always recommend to use GET method and not POST method for searches and filters, next, maybe this pagination php class can help you.
I am trying to create multiple pages from my query. If I have 100 results, and I want 10 results per page, I would like there to be ten pages created, with each page showing a different query. This is how my query is set up:
$sql ="SELECT * FROM Post WHERE (active ='1') ORDER BY PostID DESC ";
$result = mysql_query($sql,$db);
$numrows = mysql_num_rows($result);
while(($post = mysql_fetch_assoc($result))) {
$posts[] = $post;
}
<?php
if (!$numrows){ echo $errormessage;}
else{
foreach($posts as $post): ?>
echo stripslashes($post['text']);
<?php endforeach; }?>
This pulls each "post" from the database and puts displays them all out.
I would like to do something like this:
$results = mysql_num_rows($result);
$numpages = 10/$results; //gives the number of pages
while($numpages<$results)
{
//run code from above\\
}
What is the best way to do this with the method that I use? I appreciate your opinions because I'm at one of those stages where I'm lost in my own logic. Thank You!
Most pagination examples fail to meet real life requirements. A custom query string, for example.
So, here is a complete yet concise example:
<?
per_page=10;
// Let's put FROM and WHERE parts of the query into variable
$from_where="FROM Post WHERE active ='1'";
// and get total number of records
$sql = "SELECT count(*) ".$from_where;
$res = mysql_query($sql) or trigger_error(mysql_error()." in ".$sql);
$row = mysql_fetch_row($res);
$total_rows = $row[0];
//let's get page number from the query string
if (isset($_GET['page'])) $CUR_PAGE = intval($_GET['page']); else $CUR_PAGE=1;
//and calculate $start variable for the LIMIT clause
$start = abs(($CUR_PAGE-1)*$per_page);
//Let's query database for the actual data
$sql = "SELECT * $from_where ORDER BY PostID DESC LIMIT $start,$per_page";
$res = mysql_query($sql) or trigger_error(mysql_error()." in ".$sql);
// and fill an array
while ($row=mysql_fetch_array($res)) $DATA[++$start]=$row;
//now let's form new query string without page variable
$uri = strtok($_SERVER['REQUEST_URI'],"?")."?";
$tmpget = $_GET;
unset($tmpget['page']);
if ($tmpget) {
$uri .= http_build_query($tmpget)."&";
}
//now we're getting total pages number and fill an array of links
$num_pages=ceil($total_rows/$per_page);
for($i=1;$i<=$num_pages;$i++) $PAGES[$i]=$uri.'page='.$i;
//and, finally, starting output in the template.
?>
Found rows: <b><?=$total_rows?></b><br><br>
<? foreach ($DATA as $i => $row): ?>
<?=$i?>. <?=$row['title']?><br>
<? endforeach ?>
<br>
Pages:
<? foreach ($PAGES as $i => $link): ?>
<? if ($i == $CUR_PAGE): ?>
<b><?=$i?></b>
<? else: ?>
<?=$i?>
<? endif ?>
<? endforeach ?>
It would be hideous to extract all data from the database and manage it from PHP. It would kill the RAM, and the network.
Use the LIMIT clause for paging.
First, you need to see the total number of records. Use
$query = 'SELECT count(1) as cnt FROM Post WHERE active =1';
then,
$result = mysql_query($query, $db);
$row = mysql_fetch_assoc($result);
$count = $row['cnt'];
$pages = ceil($count/10.0); //used to display page links. It's the total number of pages.
$page = 3; //get it from somewhere else, it's the page number.
Then extract the data
$query = 'SELECT count(1) as cnt FROM Post WHERE active =1 LIMIT '.$page*10.', 10';
$result = mysql_query($query, $db);
while($row = mysql_fetch_assoc($result))
{
//display your row
}
Then output the data.
I'm using that similar code to do that:
$data = mysql_query("SELECT * FROM `table`");
$total_data = mysql_num_rows($data);
$step = 30;
$from = $_GET['p'];
$data = mysql_query("SELECT * FROM `table` LIMIT '.$from.','.$step.'"
That code get total rows
and that for creating links:
$p=1;
for ($j = 0 ; $j <= $total_data+$step; $j+=$step)
{
echo ' '.$p.' ';
$p++;
} ?>
You can also read about : pagination