Dagon: thanks for your sliding pagination bar code. I took it, applied my standard axxx-retentive coding conventions, and added a table version. Works great!
Note: if you enable (un-comment) the instrumentation code, you can watch it work.
<?php
// Script name: pageBar.php
// generates sliding pagination bar
// derived from very nice PHP script posted by Dagon 080418 (thanks!)
// @var int _GET["s"] => requested page number
// @var int _GET["c"] => # of line item (i.e., row) at top of requested pager
// This script is, I believe, strict PHP[4-5] code compliant (a highly desireable characteristic):
// 1. execution of this script will generate NO PHP warnings (which distract the amazing Zend engine); and
// 2. the HTML generated by this script will generate NO errors when checked with BBEdit (simply the BEST).
// This script may appear to some as overkill, but I have been programming since 1963 and learned early
// the value of taking the time to make your code as regular and readable as you possibly can:
// -- CONSTANTS are always full upper case
// -- caMel variable names rather than under_scored to distinguish from PHP constructs, e.g., ini_set
// -- the first letter of most variable names will indicate the "normal" type: i => int; a => array; s => string
// -- variables are explicitly initialized to avoid PHP warnings
// -- whenever a calculation may deliver a float to a non-float variable, explicitly type the delivered result, e.g., (int)
// -- GET (and POST) variable retrieval is always conditional to avoid PHP warnings
// -- conditional {braces} are ALWAYS on separate lines AND lined up vertically to make balancing visually easy
// -- for clarity, all operators have leading and trailing spaces,
// EXCEPT.concatenate.because ". =" doesn't work (so, for consistency, NEVER use spaces for the.operator)
// -- C++ style comments, with in-line preferred whenever possible
// -- leading tabs rather than spaces (marginally faster to parse) -- this one is controversial
// -- maintain separate and distinct tabbing sequences for PHP and HTML code snippets, and, except for embedded snippets,
// left align language shift constructs to make them easily identifiable (contrast, e.g., lines 1 and 142, and line 167)
// -- all HTML tags are balanced and full lower case per the W3C standard
// -- all HTML generated by this script has been "prettified" to make it easier to read/debug
// My coding conventions will not appeal to all, but opinions are rather like, uh, noses ... (almost) everyone has one.
// However, I have built, and daily maintain, 7 APACHE+PHP+MySQL websites, comprising tens of thousands of lines of
// PHP+MySQL+HTML code using these conventions. If anything, my standards are higher today than ever before,
// especially when it relates to site security: all of my site pages are generated dynamically, and, more importantly,
// visitor/guest/user access is controlled at both application AND page levels. My goal is not glitz but fast-as-possible
// download/rendering, which is just fine for my clients since my sites are working sites not consumer-oriented marketing hoses.
//
// icehose 080802
// OK, enough soap box, here's the beef ...
// here's a simple error logging function to facilitate debugging (aka, "instrumentation")
// @var string $sMessage => string to be written to error log
function logExc($sMessage)
{
$_sMsg = (string) date("j F Y, g:i a: ");
$_sMsg .= (string) $sMessage;
$_sMsg .= (string) "\n";
error_log($_sMsg, 3, "errors.log"); // change to direct output to your preferred log file location
} // end logExc
//---- start optional
// set php configuration variables to illustrate strict compliance
// strongly advisable during code development and debugging!
ini_set("track_errors", "1"); // error tracking
error_reporting(E_ALL); // enable error notices
//---- end optional
// script constants (could/should be in .cfg file)
$ROWCOUNT = 25; // # rows per page (set by you)
$RANGE = 10; // number of page numbers in pageBar (set by you)
// calculate local control constants (could/should be precalculated and stored as CONSTANTS in .cfg file)
//$iRangeMin = (int) ($RANGE % 2 == 0) ? ($RANGE / 2) - 1 : ($RANGE - 1) / 2; // Dagon's elegant original
//$iRangeMax = (int) ($RANGE % 2 == 0) ? $iRangeMin + 1 : $iRangeMin; // Dagon's elegant original
if ($RANGE % 2 == 0) // calculate modulo only once for both constants
{
$iRangeMin = (int) ($RANGE / 2) - 1;
$iRangeMax = $iRangeMin + 1;
}
else
{
$iRangeMin = (int) ($RANGE - 1) / 2;
$iRangeMax = $iRangeMin;
}
// GET working variables
$iPageNum = 1; // set default page number
if (!empty($_GET["s"])) // page number passed via GET
{
$iPageNum = $_GET["s"]; // get actual page number
}
$iCursor = 0; // set default page cursor
if (!empty($_GET["cursor"])) // cursor passed via GET
{
$iCursor = $_GET["cursor"]; // get actual cursor value
}
// Remember that databases, e.g., MySQL, have no concept of "page", so passing both page # AND cursor
// via your URL guarantees that you immediately have the page # info you need to generate the next pagination bar
// AND the LIMIT info you need to launch your next query (I prefer this to generating one from the other)
// set initial value(s)
// Note: here is where you set the actual size of the data set using, e.g., a MySQL query
// Change this value manually to see the effects this number has on the pagination bar
$iRows = 515; // total # of rows in data set
// calculate local control variables
$iPages = (int) ceil($iRows / $ROWCOUNT);
$iPageMin = $iPageNum - $iRangeMin;
$iPageMax = $iPageNum + $iRangeMax;
$iPageMin = ($iPageMin < 1) ? 1 : $iPageMin;
$iPageMax = ($iPageMax < ($iPageMin + $RANGE - 1)) ? $iPageMin + $RANGE - 1 : $iPageMax;
// create two different versions of pagination bar: <div>...</div> and <table>...</table>
$sPageButtons = ""; // set default (for strict correctness)
if ($iPages > 1 ) // we need to generate a pagination bar
{
if ($iPageMax > $iPages)
{
$iPageMin = ($iPageMin > 1) ? $iPages - $RANGE + 1 : 1;
$iPageMax = $iPages;
}
$iPageMin = ($iPageMin < 1) ? 1 : $iPageMin;
$s = 0; // initialize
$c = 0; // initialize
$p = 0; // initialize
if (($iPageNum > ($RANGE - $iRangeMin)) && ($iPages > $RANGE)) // generate left arrow button
{
$s = 1; // pro forma
// logExc("<: s = ".$s."; c = ".$c); // debugging instrumentation
$aPageButtons[++$p] = "<td><a href=\"pageBar.php?s=1&cursor=0\"><</a></td>\r";
$sPageButtons .= "\t\t<a href=\"pageBar.php?s=1&cursor=0\"><</a>\r";
}
if ($iPageNum > ($iRangeMin + 1)) // generate Prev button
{
$s = $iPageMin - 1;
$c = ($s - 1) * $ROWCOUNT;
// logExc("Prev: s = ".$s."; c = ".$c); // debugging instrumentation
$aPageButtons[++$p] = "<td><a href=\"pageBar.php?s=".$s."&cursor=".$c."\">Prev</a></td>\r";
$sPageButtons .= "\t\t<a href=\"pageBar.php?s=".$s."&cursor=".$c."\">Prev</a>\r";
}
for ($i = $iPageMin; $i <= $iPageMax; $i++) // generate numbered buttons
{
if ($i == $iPageNum)
{
$s = $i;
$c = ($s - 1) * $ROWCOUNT;
// logExc($s.": s = ".$s."; c = ".$c); // debugging instrumentation
$aPageButtons[++$p] = "<td><b>".$i."</b></td>\r";
$sPageButtons .= "\t\t<span><b>".$i."</b></span>\r";
}
else
{
$s = $i;
$c = ($s - 1) * $ROWCOUNT;
// logExc($s.": s = ".$s."; c = ".$c); // debugging instrumentation
$aPageButtons[++$p] = "<td><a href=\"pageBar.php?s=".$s."&cursor=".$c."\">".$i."</a></td>\r";
$sPageButtons .= "\t\t<a href=\"pageBar.php?s=".$s."&cursor=".$c."\">".$i."</a>\r";
}
}
if (($iPageNum < ($iPages - $iRangeMax)) && ($iPages > $RANGE)) // generate Next button
{
$s = $iPageMax + 1;
$c = ($s - 1) * $ROWCOUNT;
// logExc("Next: s = ".$s."; c = ".$c); // debugging instrumentation
$aPageButtons[++$p] = "<td><a href=\"pageBar.php?s=".$s."&cursor=".$c."\">Next</a></td>\r";
$sPageButtons .= "\t\t<a href=\"pageBar.php?s=".$s."&cursor=".$c."\">Next</a>\r";
}
if (($iPageNum < ($iPages - $iRangeMax)) && ($iPages > $RANGE) && ($s < $iPages)) // generate right arrow button
{
$s = $iPages;
$c = ($s - 1) * $ROWCOUNT;
// logExc(">: s = ".$s."; c = ".$c); // debugging instrumentation
$aPageButtons[++$p] = "<td><a href=\"pageBar.php?s=".$s."&cursor=".$c."\">></a></td>\r";
$sPageButtons .= "\t\t<a href=\"pageBar.php?s=".$s."&cursor=".$c."\">></a>\r";
}
$aPage["PAGINATION"] = "\t<div align=\"center\">\r".$sPageButtons."\t</div>\r"; // build <div>...</div> form
} // end generation of pagination bar
// send headers
HEADER("Expires: Sun, 15 Dec 2008 00:00:00 GMT");
HEADER("Cache-Control: no-store, no-cache, must-revalidate");
HEADER("Pragma: no-cache");
// start output to browser
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xHTML1/DTD/xHTML1-Transitional.dTD">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!--| VERSION 1.0 |-->
<head>
<meta http-equiv="Content-Type" content="text/HTML; charset=iso-8859-1" />
<title>Sliding Pagination Bar Demo</title>
</head>
<body>
<p align="center"><b><u>Sliding Pagination Bar Demo</u></b></p>
<?php
echo $aPage["PAGINATION"]; // display <div>...</div> form
// build/display <table>...</table> form
// Note: if your page is already in table format, you can delete the <table ...> and </table> lines
// leaving only the <tr> thru </tr> lines ... unless you need the align="center" table attribute
?>
<table align="center">
<tr>
<?php
foreach ($aPageButtons as $sPageButton)
{
if (!empty($sPageButton))
{
?>
<?php print $sPageButton ?>
<?php
}
}
// close output to browser
?>
</tr>
</table>
</body>
</html>