Tag Archives: pagination

Perfect Pagination with PHP

Okay, so this may not be “perfect” but it does exactly what I want it to do, so I thought I would share.

The following code takes a set of items and breaks them into pages. 10 pages are shown in the list at any given time and the current page is displayed in the middle of the list. Sample HTML code is shown below so you can see what it does.

<?php
  // sample MySQL database connection and query to get a dataset
  $dbConnection = mysql_connect("localhost", "usename", "password");
  mysql_select_db("foo", $dbConnection);
  $dbQuery = "SELECT t.table_id, t.data FROM table AS t ORDER BY t.table_id ASC";

  // set how many items to show per page
  $limit = 50;
  
  // count the total number of items that the query returns
  $dbCount = mysql_query($dbQuery, $dbConnection);
  $totalRows  = mysql_num_rows($dbCount);     

  // divide the total rows by the limit to get the page count
  $numOfPages = ceil($totalRows / $limit);
  
  // get the current page number
  $currentPage = $_GET['page'];
  
  // if $currentPage is undefined, not a number, or out of range, then we're on page one
  if (empty($currentPage) || !is_numeric($currentPage) || ($currentPage > $numOfPages)) {
    $page = 1;
  }
  else {
    $page = $currentPage;
  }
  
  // figure out where to start on each page
  $limitValue = ($page * $limit) - $limit;

  // apply limits to the query
  $dbQuery = $dbQuery . " LIMIT $limit_value, $limit";
  
  $dbResult = mysql_query($dbQuery, $dbConnection);

  // display pagination only if needed
  if ($totalRows > $limit) {
    print("<div class=\"pagination\">\n");

    if ($_SERVER["QUERY_STRING"]) {
      $existing_query = preg_replace("/[&]*page=[^&]+/i", "" , $_SERVER["QUERY_STRING"]);
      if ($existing_query != "") $existing_query = preg_replace("/^&/i", "" , $existing_query) . "&";
    }
    else {
      $existingQuery = "";
    }

    // display previous link if there is a previous page to go to
    if ($page != 1) {  
      $pagePrev = "   <div class=\"gotopage\"><a href=\"" . $_SERVER["PHP_SELF"] . "?" . $existingQuery . "page=" . ($page - 1) . "\">Previous</a></div>\n";
    }

    // display next link if there is a next page to go to
    if (($totalRows - ($limit * $page)) > 0) { 
      $pageNext = "   <div class=\"gotopage\"><a href=\"" . $_SERVER["PHP_SELF"] . "?" . $existingQuery . "page=" . ($page + 1) . "\">Next</a></div>\n";
    }

    // divide the total rows by the limit to get the page count
    $numOfPages = ceil($totalRows / $limit);

    if ($numOfPages > 10) {
      // make the current page in the "center" of the list when possible
      if ($page > 5) {
        if (($page - 5) > ($numOfPages - 9)) {
          $startNum = ($page - 5) - (($page - 5) - ($numOfPages - 9));
        }
        else {
          $startNum = $page - 5;
        }
        if ($startNum > 1) {
          $pageFirst = "    <div class=\"gotopage\"><a href=\"" . $_SERVER["PHP_SELF"] . "?" . $existingQuery . "page=" . 1 . "\">First</a></div>\n";
        }
      }
      else {
        $startNum = 1;
      }
      if ($page < ($numOfPages - 4)) {
        if (($page + 4) < 10)
          $endNum = ($page + 4) + (10 - ($page + 4));
        else {
          $endNum = $page + 4;
        }
        $pageLast = "   <div class=\"gotopage\"><a href=\"" . $_SERVER["PHP_SELF"] . "?" . $existingQuery . "page=" . $numOfPages . "\">Last</a></div>\n";
      }
      else {
        $endNum = $numOfPages;
      }
    }
    else {
      $startNum = 1;
      $endNum = $numOfPages;
    }

    // first page link
    print(" <div class=\"pagefirst\">\n");
    if ($pageFirst) print($pageFirst);
    print(" </div>\n");

    // previous page link
    print(" <div class=\"pageprev\">\n");
    if ($pagePrev) print($pagePrev);
    print(" </div>\n");

    // individual page links
    print(" <div class=\"pages\">\n");
    for ($i = $startNum; $i <= $endNum; $i++) { 
      if ($i == $page) { 
        print("   <div class=\"currentpage\">" . $i . "</div>\n");
      }
      else { 
        print("   <div class=\"gotopage\"><a href=\"" . $_SERVER["PHP_SELF"] . "?" . $existingQuery . "page=" . $i . "\">" . $i . "</a></div>\n");
      } 
    } 
    print(" </div>\n");

    // next page link
    print(" <div class=\"pagenext\">\n");
    if ($pageNext) print($pageNext);
    print(" </div>\n");

    // last page link
    print(" <div class=\"pagelast\">\n");
    if ($pageLast) print($pageLast);
    print(" </div>\n");

    print("</div> <!-- .pagination -->\n");
  }
?>

So what does all that do? Well, let’s assume we were on page 10 of our result set. This is the HTML that would be generated:

<div class="pagination">
  <div class="pagefirst">
    <div class="gotopage"><a href="index.php?page=1">First</a></div>
  </div>
  <div class="pageprev">
    <div class="gotopage"><a href="index.php?page=9">Previous</a></div>
  </div>
  <div class="pages">
    <div class="gotopage"><a href="index.php?page=5">5</a></div>
    <div class="gotopage"><a href="index.php?page=6">6</a></div>
    <div class="gotopage"><a href="index.php?page=7">7</a></div>
    <div class="gotopage"><a href="index.php?page=8">8</a></div>
    <div class="gotopage"><a href="index.php?page=9">9</a></div>
    <div class="currentpage">10</div>
    <div class="gotopage"><a href="index.php?page=11">11</a></div>
    <div class="gotopage"><a href="index.php?page=12">12</a></div>
    <div class="gotopage"><a href="index.php?page=13">13</a></div>
    <div class="gotopage"><a href="index.php?page=14">14</a></div>
  </div>
  <div class="pagenext">
    <div class="gotopage"><a href="index.php?page=11">Next</a></div>
  </div>
  <div class="pagelast">
    <div class="gotopage"><a href="index.php?page=38">Last</a></div>
  </div>
</div> <!-- .pagination -->

All of the additional DIV tags are so I have complete flexibility to style the page list any way I like.

And yes, this will support pages with other URL passed parameters, such as search results.