Source for file Common.php
Documentation is available at Common.php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
* Contains the Pager_Common class
* LICENSE: Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @author Richard Heyes <richard@phpguru.org>
* @copyright 2003-2006 Lorenzo Alberton, Richard Heyes
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
* @version CVS: $Id: Common.php 12273 2007-05-03 14:49:21Z elixir_julian $
* @link http://pear.php.net/package/Pager
* Two constants used to guess the path- and file-name of the page
* when the user doesn't set any other value
define('CURRENT_FILENAME', '');
define('CURRENT_PATHNAME', 'http://'. $_SERVER['HTTP_HOST']. str_replace('\\', '/', api_get_self()));
define('CURRENT_FILENAME', preg_replace('/(.*)\?.*/', '\\1', basename(api_get_self())));
define('CURRENT_PATHNAME', str_replace('\\', '/', dirname(api_get_self())));
define('ERROR_PAGER_INVALID', - 2);
define('ERROR_PAGER_INVALID_PLACEHOLDER', - 3);
define('ERROR_PAGER_INVALID_USAGE', - 4);
define('ERROR_PAGER_NOT_IMPLEMENTED', - 5);
* Pager_Common - Common base class for [Sliding|Jumping] Window Pager
* Extend this class to write a custom paging class
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
* @author Richard Heyes <richard@phpguru.org>
* @copyright 2003-2005 Lorenzo Alberton, Richard Heyes
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @link http://pear.php.net/package/Pager
* @var integer number of items
* @var integer number of items per page
* @var integer number of page links for each window
* @var integer current page number
* @var integer total pages number
* @var string CSS class for links
* @var string wrapper for CSS class name
var $_path = CURRENT_PATHNAME;
* @var boolean If false, don't override the fileName option. Use at your own risk.
* @var boolean you have to use FALSE with mod_rewrite
* @var string specifies which HTTP method to use
* @var string specifies which HTML form to use
* @var boolean whether or not to import submitted data
* @var string name of the querystring var for pageID
* @var array data to pass through the link
* @var array additional URL vars
* @var array URL vars to ignore
* @var boolean TRUE => expanded mode (for Pager_Sliding)
* @var boolean TRUE => show accesskey attribute on <a> tags
* @var string extra attributes for the <a> tag
* @var string alt text for "first page" (use "%d" placeholder for page number)
* @var string alt text for "previous page"
* @var string alt text for "next page"
* @var string alt text for "last page" (use "%d" placeholder for page number)
* @var string alt text for "page"
* @var string image/text to use as "prev" link
* @var string image/text to use as "next" link
* @var string link separator
* @var integer number of spaces before separator
* @var integer number of spaces after separator
* @var string CSS class name for current page link
* @var string Text before current page link
* @var string Text after current page link
* @var string Text before first page link
* @var string Text to be used for first page link
* @var string Text after first page link
* @var string Text before last page link
* @var string Text to be used for last page link
* @var string Text after last page link
* @var string Will contain the HTML code for the spaces
* @var string Will contain the HTML code for the spaces
* @var string $_firstLinkTitle
* @var string $_nextLinkTitle
* @var string $_prevLinkTitle
* @var string $_lastLinkTitle
* @var string Text to be used for the 'show all' option in the select box
* @var array data to be paged
* @var boolean If TRUE and there's only one page, links aren't shown
* @var boolean Use session for storing the number of items per page
* @var boolean Close the session when finished reading/writing data
* @var string name of the session var for number of items per page
* Pear error mode (when raiseError is called)
* @var int $_pearErrorMode
* @var string Complete set of links
* @var string Complete set of link tags
* @var array Array with a key => value pair representing
* page# => bool value (true if key==currentPageNumber).
* can be used for extreme customization.
* @var array list of available options (safety check)
* Generate or refresh the links and paged data after a call to setOptions()
$msg = '<b>PEAR::Pager Error:</b>'
. ' function "build()" not implemented.';
* Returns an array of current pages data
* @param $pageID Desired page ID (optional)
* @return array Page data
if (!isset ($this->_pageData)) {
if (!empty($this->_pageData[$pageID])) {
return $this->_pageData[$pageID];
// {{{ getPageIdByOffset()
* Returns pageID for given offset
* @param $index Offset to get pageID for
* @return int PageID for given offset
$msg = '<b>PEAR::Pager Error:</b>'
. ' function "getPageIdByOffset()" not implemented.';
// {{{ getOffsetByPageId()
* Returns offsets for given pageID. Eg, if you
* pass it pageID one and your perPage limit is 10
* it will return (1, 10). PageID of 2 would
* @param integer PageID to get offsets for
* @return array First and last offsets
if (!isset ($this->_pageData)) {
// {{{ getPageRangeByPageId()
* @param integer PageID to get offsets for
* @return array First and last offsets
$msg = '<b>PEAR::Pager Error:</b>'
. ' function "getPageRangeByPageId()" not implemented.';
* Returns back/next/first/last and page links,
* both as ordered and associative array.
* NB: in original PEAR::Pager this method accepted two parameters,
* $back_html and $next_html. Now the only parameter accepted is
* an integer ($pageID), since the html text for prev/next links can
* be set in the factory. If a second parameter is provided, then
* the method act as it previously did. This hack was done to mantain
* backward compatibility only.
* @param integer $pageID Optional pageID. If specified, links
* for that page are provided instead of current one. [ADDED IN NEW PAGER VERSION]
* @param string $next_html HTML to put inside the next link [deprecated: use the factory instead]
* @return array back/next/first/last and page links
function getLinks($pageID= null, $next_html= '')
$msg = '<b>PEAR::Pager Error:</b>'
. ' function "getLinks()" not implemented.';
// {{{ getCurrentPageID()
* Returns ID of current page
* @return integer ID of current page
* Returns next page ID. If current page is last page
* this function returns FALSE
* @return mixed Next page ID
// {{{ getPreviousPageID()
* Returns previous page ID. If current page is first page
* this function returns FALSE
* @return mixed Previous pages' ID
* Returns number of items
* @return int Number of items
* Returns number of pages
* @return int Number of pages
* Returns whether current page is first page
* @return bool First page or not
* Returns whether current page is last page
* @return bool Last page or not
// {{{ isLastPageComplete()
* Returns whether last page is complete
* @return bool Last age complete or not
// {{{ _generatePageData()
* Calculates all page data
// Been supplied an array of data?
foreach ($this->_itemData as $key => $value) {
$this->_pageData[$i][$key] = $value;
$this->_pageData = array();
//prevent URL modification
* Renders a link using the appropriate method
* @param altText Alternative text for this link (title property)
* @param linkText Text contained by this link
* @return string The link in string form
return sprintf('<a href="%s"%s%s%s title="%s">%s</a>',
return sprintf("<a href='javascript:void(0)' onclick='%s'%s%s%s title='%s'>%s</a>",
// {{{ _generateFormOnClick()
* Mimics http_build_query() behavior in the way the data
* in $data will appear when it makes it back to the server.
* $arr = array('array' => array(array('hello', 'world'),
* 'things' => array('stuff', 'junk'));
* and _generateFormOnClick('foo.php', $arr)
* $_REQUEST['array'][0][0] === 'hello'
* $_REQUEST['array'][0][1] === 'world'
* $_REQUEST['array']['things'][0] === 'stuff'
* $_REQUEST['array']['things'][1] === 'junk'
* However, instead of generating a query string, it generates
* Javascript to create and submit a form.
* @param string $formAction where the form should be submitted
* @param array $data the associative array of names and values
* @return string A string of javascript that generates a form and submits it
// Check we have an array to work with
'_generateForm() Parameter 1 expected to be Array or Object. Incorrect value given.',
$str = 'var form = document.getElementById("'. $this->_formID. '"); var input = ""; ';
$str = 'var form = document.createElement("form"); var input = ""; ';
// We /shouldn't/ need to escape the URL ...
foreach ($data as $key => $val) {
$str .= 'document.getElementsByTagName("body")[0].appendChild(form);';
$str .= 'form.submit(); return false;';
// {{{ _generateFormOnClickHelper
* This is used by _generateFormOnClick().
* Recursively processes the arrays, objects, and literal values.
* @param data Data that should be rendered
* @param prev The name so far
* @return string A string of Javascript that creates form inputs
// foreach key/visible member
foreach ((array) $data as $key => $val) {
$tempKey = sprintf('%s[%s]', $prev, $key);
} else { // must be a literal value
// escape newlines and carriage returns
$search = array("\n", "\r");
$replace = array('\n', '\n');
// am I forgetting any dangerous whitespace?
// would a regex be faster?
// if it's already encoded, don't encode it again
$escapedData = htmlentities($escapedData, ENT_QUOTES, 'UTF-8');
$str .= 'input = document.createElement("input"); ';
$str .= 'input.type = "hidden"; ';
$str .= sprintf('input.name = "%s"; ', $prev);
$str .= sprintf('input.value = "%s"; ', $escapedData);
$str .= 'form.appendChild(input); ';
* Returns the correct link for the back/pages/next links
// {{{ _recursive_stripslashes()
// {{{ _recursive_urldecode()
$var = strtr($var, $trans_tbl);
* @param $url URL to use in the link [deprecated: use the factory instead]
* @param $link HTML to use as the link [deprecated: use the factory instead]
* @return string The link
//legacy settings... the preferred way to set an option
//now is passing it to the factory
* @param $url URL to use in the link [deprecated: use the factory instead]
$msg = '<b>PEAR::Pager Error:</b>'
. ' function "_getPageLinks()" not implemented.';
* @param $url URL to use in the link [deprecated: use the factory instead]
* @param $link HTML to use as the link [deprecated: use the factory instead]
* @return string The link
//legacy settings... the preferred way to set an option
//now is passing it to the factory
// {{{ _getFirstLinkTag()
return sprintf('<link rel="first" href="%s" title="%s" />'. "\n",
* Returns previous link tag
* @return string the link tag
return sprintf('<link rel="previous" href="%s" title="%s" />'. "\n",
* @return string the link tag
return sprintf('<link rel="next" href="%s" title="%s" />'. "\n",
* @return string the link tag
return sprintf('<link rel="last" href="%s" title="%s" />'. "\n",
* @return string the link tag url
// {{{ getPerPageSelectBox()
* Returns a string with a XHTML SELECT menu,
* useful for letting the user choose how many items per page should be
* displayed. If parameter useSessions is TRUE, this value is stored in
* a session var. The string isn't echoed right now so you can use it
* @param boolean $showAllData If true, perPage is set equal to totalItems.
* @param array (or string $optionText for BC reasons)
* - 'optionText': text to show in each option.
* Use '%d' where you want to see the number of pages selected.
* - 'attributes': (html attributes) Tag attributes or
* HTML attributes (id="foo" pairs), will be inserted in the
* @return string xhtml select box
function getPerPageSelectBox($start= 5, $end= 30, $step= 5, $showAllData= false, $extraParams= array())
require_once 'Pager/HtmlWidgets.php';
return $widget->getPerPageSelectBox($start, $end, $step, $showAllData, $extraParams);
// {{{ getPageSelectBox()
* Returns a string with a XHTML SELECT menu with the page numbers,
* useful as an alternative to the links
* @param array - 'optionText': text to show in each option.
* Use '%d' where you want to see the number of pages selected.
* - 'autoSubmit': if TRUE, add some js code to submit the
* form on the onChange event
* @param string $extraAttributes (html attributes) Tag attributes or
* HTML attributes (id="foo" pairs), will be inserted in the
* @return string xhtml select box
require_once 'Pager/HtmlWidgets.php';
return $widget->getPageSelectBox($params, $extraAttributes);
* @return string String with link to 1st page,
* or empty string if this is the 1st page.
* @return string String with link to last page,
* or empty string if this is the 1st page.
// {{{ _setFirstLastText()
* sets the private _firstPageText, _lastPageText variables
* based on whether they were set in the options
// {{{ _http_build_query_wrapper()
* This is a slightly modified version of the http_build_query() function;
* it heavily borrows code from PHP_Compat's http_build_query().
* The main change is the usage of htmlentities instead of urlencode,
* since it's too aggressive
* @author Stephan Schmidt <schst@php.net>
* @author Aidan Lister <aidan@php.net>
* @author Lorenzo Alberton <l dot alberton at quipo dot it>
$separator = ini_get('arg_separator.output');
if ($separator == '&') {
$separator = '&'; //the string is escaped by htmlentities anyway...
foreach ($data as $key => $val) {
//array_push($tmp, $key.'='.$val);
// If the value is an array, recursively parse it
// {{{ __http_build_query()
* @author Stephan Schmidt <schst@php.net>
* @author Aidan Lister <aidan@php.net>
$separator = ini_get('arg_separator.output');
if ($separator == '&') {
$separator = '&'; //the string is escaped by htmlentities anyway...
foreach ($array as $key => $value) {
//array_push($tmp, $this->__http_build_query($value, sprintf('%s[%s]', $name, $key)));
//array_push($tmp, sprintf('%s[%s]=%s', $name, htmlentities($key), htmlentities($value)));
//array_push($tmp, $this->__http_build_query(get_object_vars($value), sprintf('%s[%s]', $name, $key)));
* Check if a string is an encoded multibyte string
$hexchar = '&#[\dA-Fx]{2,};';
return preg_match("/^(\s|($hexchar))*$/Uims", $string) ? true : false;
* conditionally includes PEAR base class and raise an error
* @param string $msg Error message
* @param int $code Error code
* Set and sanitize options
* @param mixed $options An associative array of option names and
* @return integer error code (PAGER_OK on success)
foreach ($options as $key => $value) {
$this->{'_' . $key} = $value;
if (!isset ($options['httpMethod'])
&& !isset ($_GET[$this->_urlVar])
&& isset ($_POST[$this->_urlVar])
$this->_httpMethod = 'POST';
$this->_url = $this->_path;
if (isset ($_REQUEST[$this->_urlVar]) && empty($options['currentPage'])) {
* Return the current value of a given option
* @param string option name
* @return mixed option value
$msg = '<b>PEAR::Pager Error:</b>'
. ' invalid option: '. $name;
return $this->{'_' . $name};
* Return an array with all the current pager options
* @return array list of all the pager options
$options[$option] = $this->{'_' . $option};
* Return a textual error message for a PAGER error code
* @param int $code error code
* @return string error message
if (!isset ($errorMessages)) {
. ' $options[\'fileName\'] MUST contain the "%d" placeholder.',
return '<b>PEAR::Pager error:</b> '. (isset ($errorMessages[$code]) ?
|