Pagination in PHP

This first pagination technique simply splits the results from a database up and displays links to all the pages.

$page = (int) $_GET['page'];
if ($page < 1) $page = 1;

The number of the page currently being used is input via a query string. The page number is checked to make sure that it is greater than one otherwise it is set to one.


The code above starts a connection to a database that we will query for the data.

$resultsPerPage = 10;
$startResults = ($page - 1) * $resultsPerPage;
$numberOfRows = mysql_num_rows(mysql_query('SELECT title FROM table'));
$totalPages = ceil($numberOfRows / $resultsPerPage);

The first variable holds the number of results to display per page, and the second calculates which results to start from. The total number of rows is calculated and the number of pages is calculated by rounded up the division of the number of rows and the results per page.

$query = mysql_query("SELECT title FROM table LIMIT $startResults, $resultsPerPage");
while ($output = mysql_fetch_assoc($query))
   echo $output['title'].'<br />';

The data from the database is printed to the user with the variables calculated before to select a subset of the results.

echo '<a href="?page=1">First</a>&nbsp';
if($page > 1)
   echo '<a href="?page='.($page - 1).'">Back</a>&nbsp';

Two links are printed first, one to link to the first page, and one link is set if the user is not on the first page i.e. a back button.

for($i = 1; $i <= $totalPages; $i++)
   if($i == $page)
      echo '<strong>'.$i.'</strong>&nbsp';
      echo '<a href="?page='.$i.'">'.$i.'</a>&nbsp';

This loop goes through all the pages and creates links to them all. The current page is output in bold type.

if ($page < $totalPages)
   echo '<a href="?page='.($page + 1).'">Next</a>&nbsp;';
echo '<a href="?page='.$totalPages.'">Last</a>';

Finally two more links are output. If the user is not at the last page then a next link is printed, and a link that points to the final page is also printed.

Grouping links

If there are lots of pages to display then printing them all at once might not be a good idea, so in this part of the tutorial we will limit the number of links on the page and make them alter depending on which page the user is currently at. The first part of the code is identical to the first pagination technique.

$halfPages = floor($numberOfPages / 2);
$range = array('start' => 1, 'end' => $totalPages);
$isEven = ($numberOfPages % 2 == 0);
$atRangeEnd = $totalPages - $halfPages;

These variables are used to define the new range of links to display to the user. The $range variable specifies the range of links to display and this will be updated later to ensure that only a subset of links are shown.

if($isEven) $atRangeEnd++;
if($totalPages > $numberOfPages)
   if($page <= $halfPages)
      $range['end'] = $numberOfPages;

The first check is to see if the number of pages to display is even and if it is, it updates the $atRangeEnd variable. The second check is that the total number of pages is greater than the user specified one because if this was false then we simply need to display all the results. There are now three options we have to consider. When the subset of links is displayed we will keep the current page in the middle of the other links, to do this we need to know if the current page is at the start of the links, at the end of the links or somewhere in the middle. This first case checks to see if the current page is at the start of the links because if this is true then we do not need to display anymore pages to the left (i.e. the first link to display is the first page and the last link to display is the programmer specified number of pages to display).

elseif ($page >= $atRangeEnd)
   $range['start'] = $totalPages - $numberOfPages + 1;

This checks to see if the current page is at the end of the set of links and if it is then we do not need to display anymore links as we have reached the end, we therefore keep the end of the range as the total number of links and set the start of the links to the the total number minus the number of links to display.

   $range['start'] = $page - $halfPages;
   $range['end'] = $page + $halfPages;
   if($isEven) $range['end']--;

Finally if we are in the middle of the links then we simply need to display some links to the left and some to the right, the number of links was defiend by the programmer in an earlier variable so we need to add/subtract this number of links from the current page.

NB: If the variable $numberOfPages is an even number then we have to alter the range because there is not middle value e.g. if we want to display 4 links then if the current page is in the middle then we need to display one to the left and two to the right or visa versa.
if($page > 1)
   echo '<a href="?page='.($page - 1).'">&laquo;</a>&nbsp';

for ($i = $range['start']; $i <= $range['end']; $i++)
   if($i == $page)
      echo '<strong>'.$i.'</strong>&nbsp;';
      echo '<a href="?page='.$i.'">'.$i.'</a>&nbsp;';

if ($page < $totalPages)
   echo '<a href="?page='.($page + 1).'">&raquo;</a>&nbsp;';

Finally we need to display the links. We will display two arrows on each side of the links as forward and backward arrows (providing that the user is not at the start/end of the links). Using the range array we created eariler the links are output to the user using a loop.

Producing a menu

These pagination techniques can be used with option boxes to produce pull down menus that allow the user to select results from a form.

<?php if($_POST['select']) header('Location: '.basename($_SERVER['PHP_SELF']).$_POST['select']); ?>

As a backup for the JavaScript, this code checks to see if the form has been submitted. If it has then the page is redirected to show the correct subset of links.

function changeurl(id)
   var newurl = id.options[id.selectedIndex].value;
   window.location.href = newurl;

This function turns the option box into a menu by changing the page when the user has made a selection.

echo 'Viewing results <form name="form1" id="form1" method="post" action="">
      <select name="select" id="select" onchange="changeurl(this)">';
for($i = 1; $i < $totalPages; $i++)
   $startResults2 = (($i - 1) * $resultsPerPage);
   echo '<option value="?page='.$i.'"'.(($i == $page) ? ' selected="selected"' : '').'>
        '.($startResults2 + 1).' to '.($startResults2 + $resultsPerPage).'</option>';
echo '<option value="?page='.$totalPages.'"'.(($totalPages == $page) ? ' selected="selected"' : '').'>
     '.((($totalPages - 1) * $resultsPerPage) + 1).' to '.$numberOfRows.'</option>';
echo '</select><input type="submit" name="submit" id="submit" value="Submit" /></form>';
echo ' of '.$numberOfRows.' Results';

This section of the code prints the form and loops over the number of pages and enters them into the option box. The last item is printed separately because it might not contain a full set of links (for example the set of links {1 – 10, 11 – 15} does not have 10 links in the last element because there are not a multiple of 10 elements in the database).


GitHub repository