home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / Pager / Common.php next >
Encoding:
PHP Script  |  2008-07-02  |  48.8 KB  |  1,669 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5.  * Contains the Pager_Common class
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE: Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. The name of the author may not be used to endorse or promote products
  17.  *    derived from this software without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
  20.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
  23.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * @category  HTML
  31.  * @package   Pager
  32.  * @author    Lorenzo Alberton <l.alberton@quipo.it>
  33.  * @author    Richard Heyes <richard@phpguru.org>
  34.  * @copyright 2003-2007 Lorenzo Alberton, Richard Heyes
  35.  * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
  36.  * @version   CVS: $Id: Common.php,v 1.78 2008/03/26 22:23:49 quipo Exp $
  37.  * @link      http://pear.php.net/package/Pager
  38.  */
  39.  
  40. /**
  41.  * Two constants used to guess the path- and file-name of the page
  42.  * when the user doesn't set any other value
  43.  */
  44. if (substr($_SERVER['PHP_SELF'], -1) == '/') {
  45.     $http = (isset($_SERVER['HTTPS']) && ('on' == strtolower($_SERVER['HTTPS']))) ? 'https://' : 'http://';
  46.     define('PAGER_CURRENT_FILENAME', '');
  47.     define('PAGER_CURRENT_PATHNAME', $http.$_SERVER['HTTP_HOST'].str_replace('\\', '/', $_SERVER['PHP_SELF']));
  48. } else {
  49.     define('PAGER_CURRENT_FILENAME', preg_replace('/(.*)\?.*/', '\\1', basename($_SERVER['PHP_SELF'])));
  50.     define('PAGER_CURRENT_PATHNAME', str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])));
  51. }
  52. /**
  53.  * Error codes
  54.  */
  55. define('PAGER_OK',                         0);
  56. define('ERROR_PAGER',                     -1);
  57. define('ERROR_PAGER_INVALID',             -2);
  58. define('ERROR_PAGER_INVALID_PLACEHOLDER', -3);
  59. define('ERROR_PAGER_INVALID_USAGE',       -4);
  60. define('ERROR_PAGER_NOT_IMPLEMENTED',     -5);
  61.  
  62. /**
  63.  * Pager_Common - Common base class for [Sliding|Jumping] Window Pager
  64.  * Extend this class to write a custom paging class
  65.  *
  66.  * @category  HTML
  67.  * @package   Pager
  68.  * @author    Lorenzo Alberton <l.alberton@quipo.it>
  69.  * @author    Richard Heyes <richard@phpguru.org>
  70.  * @copyright 2003-2007 Lorenzo Alberton, Richard Heyes
  71.  * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
  72.  * @link      http://pear.php.net/package/Pager
  73.  */
  74. class Pager_Common
  75. {
  76.     // {{{ class vars
  77.  
  78.     /**
  79.      * @var integer number of items
  80.      * @access private
  81.      */
  82.     var $_totalItems;
  83.  
  84.     /**
  85.      * @var integer number of items per page
  86.      * @access private
  87.      */
  88.     var $_perPage     = 10;
  89.  
  90.     /**
  91.      * @var integer number of page links for each window
  92.      * @access private
  93.      */
  94.     var $_delta       = 10;
  95.  
  96.     /**
  97.      * @var integer current page number
  98.      * @access private
  99.      */
  100.     var $_currentPage = 1;
  101.  
  102.     /**
  103.      * @var integer total pages number
  104.      * @access private
  105.      */
  106.     var $_totalPages  = 1;
  107.  
  108.     /**
  109.      * @var string CSS class for links
  110.      * @access private
  111.      */
  112.     var $_linkClass   = '';
  113.  
  114.     /**
  115.      * @var string wrapper for CSS class name
  116.      * @access private
  117.      */
  118.     var $_classString = '';
  119.  
  120.     /**
  121.      * @var string path name
  122.      * @access private
  123.      */
  124.     var $_path        = PAGER_CURRENT_PATHNAME;
  125.  
  126.     /**
  127.      * @var string file name
  128.      * @access private
  129.      */
  130.     var $_fileName    = PAGER_CURRENT_FILENAME;
  131.  
  132.     /**
  133.      * @var boolean If false, don't override the fileName option. Use at your own risk.
  134.      * @access private
  135.      */
  136.     var $_fixFileName = true;
  137.  
  138.     /**
  139.      * @var boolean you have to use FALSE with mod_rewrite
  140.      * @access private
  141.      */
  142.     var $_append      = true;
  143.  
  144.     /**
  145.      * @var string specifies which HTTP method to use
  146.      * @access private
  147.      */
  148.     var $_httpMethod  = 'GET';
  149.  
  150.     /**
  151.      * @var string specifies which HTML form to use
  152.      * @access private
  153.      */
  154.     var $_formID      = '';
  155.  
  156.     /**
  157.      * @var boolean whether or not to import submitted data
  158.      * @access private
  159.      */
  160.     var $_importQuery = true;
  161.  
  162.     /**
  163.      * @var string name of the querystring var for pageID
  164.      * @access private
  165.      */
  166.     var $_urlVar      = 'pageID';
  167.  
  168.     /**
  169.      * @var array data to pass through the link
  170.      * @access private
  171.      */
  172.     var $_linkData    = array();
  173.  
  174.     /**
  175.      * @var array additional URL vars
  176.      * @access private
  177.      */
  178.     var $_extraVars   = array();
  179.  
  180.     /**
  181.      * @var array URL vars to ignore
  182.      * @access private
  183.      */
  184.     var $_excludeVars = array();
  185.  
  186.     /**
  187.      * @var boolean TRUE => expanded mode (for Pager_Sliding)
  188.      * @access private
  189.      */
  190.     var $_expanded    = true;
  191.  
  192.     /**
  193.      * @var boolean TRUE => show accesskey attribute on <a> tags
  194.      * @access private
  195.      */
  196.     var $_accesskey   = false;
  197.  
  198.     /**
  199.      * @var string extra attributes for the <a> tag
  200.      * @access private
  201.      */
  202.     var $_attributes  = '';
  203.  
  204.     /**
  205.      * @var string onclick
  206.      * @access private
  207.      */
  208.     var $_onclick = '';
  209.  
  210.     /**
  211.      * @var string alt text for "first page" (use "%d" placeholder for page number)
  212.      * @access private
  213.      */
  214.     var $_altFirst     = 'first page';
  215.  
  216.     /**
  217.      * @var string alt text for "previous page"
  218.      * @access private
  219.      */
  220.     var $_altPrev     = 'previous page';
  221.  
  222.     /**
  223.      * @var string alt text for "next page"
  224.      * @access private
  225.      */
  226.     var $_altNext     = 'next page';
  227.  
  228.     /**
  229.      * @var string alt text for "last page" (use "%d" placeholder for page number)
  230.      * @access private
  231.      */
  232.     var $_altLast     = 'last page';
  233.  
  234.     /**
  235.      * @var string alt text for "page" (use optional "%d" placeholder for page number)
  236.      * @access private
  237.      */
  238.     var $_altPage     = 'page';
  239.  
  240.     /**
  241.      * @var string image/text to use as "prev" link
  242.      * @access private
  243.      */
  244.     var $_prevImg     = '<< Back';
  245.  
  246.     /**
  247.      * image/text to use as "prev" link when no prev link is needed  (e.g. on the first page)
  248.      * NULL deactivates it
  249.      *
  250.      * @var string
  251.      * @access private
  252.      */
  253.     var $_prevImgEmpty = null;
  254.  
  255.     /**
  256.      * @var string image/text to use as "next" link
  257.      * @access private
  258.      */
  259.     var $_nextImg     = 'Next >>';
  260.  
  261.     /**
  262.      * image/text to use as "next" link when
  263.      * no next link is needed (e.g. on the last page)
  264.      * NULL deactivates it
  265.      *
  266.      * @var string
  267.      * @access private
  268.      */
  269.     var $_nextImgEmpty = null;
  270.  
  271.     /**
  272.      * @var string link separator
  273.      * @access private
  274.      */
  275.     var $_separator   = '';
  276.  
  277.     /**
  278.      * @var integer number of spaces before separator
  279.      * @access private
  280.      */
  281.     var $_spacesBeforeSeparator = 0;
  282.  
  283.     /**
  284.      * @var integer number of spaces after separator
  285.      * @access private
  286.      */
  287.     var $_spacesAfterSeparator  = 1;
  288.  
  289.     /**
  290.      * @var string CSS class name for current page link
  291.      * @access private
  292.      */
  293.     var $_curPageLinkClassName  = '';
  294.  
  295.     /**
  296.      * @var string Text before current page link
  297.      * @access private
  298.      */
  299.     var $_curPageSpanPre        = '';
  300.  
  301.     /**
  302.      * @var string Text after current page link
  303.      * @access private
  304.      */
  305.     var $_curPageSpanPost       = '';
  306.  
  307.     /**
  308.      * @var string Text before first page link
  309.      * @access private
  310.      */
  311.     var $_firstPagePre  = '[';
  312.  
  313.     /**
  314.      * @var string Text to be used for first page link
  315.      * @access private
  316.      */
  317.     var $_firstPageText = '';
  318.  
  319.     /**
  320.      * @var string Text after first page link
  321.      * @access private
  322.      */
  323.     var $_firstPagePost = ']';
  324.  
  325.     /**
  326.      * @var string Text before last page link
  327.      * @access private
  328.      */
  329.     var $_lastPagePre   = '[';
  330.  
  331.     /**
  332.      * @var string Text to be used for last page link
  333.      * @access private
  334.      */
  335.     var $_lastPageText  = '';
  336.  
  337.     /**
  338.      * @var string Text after last page link
  339.      * @access private
  340.      */
  341.     var $_lastPagePost  = ']';
  342.  
  343.     /**
  344.      * @var string Will contain the HTML code for the spaces
  345.      * @access private
  346.      */
  347.     var $_spacesBefore  = '';
  348.  
  349.     /**
  350.      * @var string Will contain the HTML code for the spaces
  351.      * @access private
  352.      */
  353.     var $_spacesAfter   = '';
  354.  
  355.     /**
  356.      * @var string $_firstLinkTitle
  357.      * @access private
  358.      */
  359.     var $_firstLinkTitle = 'first page';
  360.  
  361.     /**
  362.      * @var string $_nextLinkTitle
  363.      * @access private
  364.      */
  365.     var $_nextLinkTitle = 'next page';
  366.  
  367.     /**
  368.      * @var string $_prevLinkTitle
  369.      * @access private
  370.      */
  371.     var $_prevLinkTitle = 'previous page';
  372.  
  373.     /**
  374.      * @var string $_lastLinkTitle
  375.      * @access private
  376.      */
  377.     var $_lastLinkTitle = 'last page';
  378.  
  379.     /**
  380.      * @var string Text to be used for the 'show all' option in the select box
  381.      * @access private
  382.      */
  383.     var $_showAllText   = '';
  384.  
  385.     /**
  386.      * @var array data to be paged
  387.      * @access private
  388.      */
  389.     var $_itemData      = null;
  390.  
  391.     /**
  392.      * @var boolean If TRUE and there's only one page, links aren't shown
  393.      * @access private
  394.      */
  395.     var $_clearIfVoid   = true;
  396.  
  397.     /**
  398.      * @var boolean Use session for storing the number of items per page
  399.      * @access private
  400.      */
  401.     var $_useSessions   = false;
  402.  
  403.     /**
  404.      * @var boolean Close the session when finished reading/writing data
  405.      * @access private
  406.      */
  407.     var $_closeSession  = false;
  408.  
  409.     /**
  410.      * @var string name of the session var for number of items per page
  411.      * @access private
  412.      */
  413.     var $_sessionVar    = 'setPerPage';
  414.  
  415.     /**
  416.      * Pear error mode (when raiseError is called)
  417.      * (see PEAR doc)
  418.      *
  419.      * @var integer $_pearErrorMode
  420.      * @access private
  421.      */
  422.     var $_pearErrorMode = null;
  423.  
  424.     // }}}
  425.     // {{{ public vars
  426.  
  427.     /**
  428.      * @var string Complete set of links
  429.      * @access public
  430.      */
  431.     var $links = '';
  432.  
  433.     /**
  434.      * @var string Complete set of link tags
  435.      * @access public
  436.      */
  437.     var $linkTags = '';
  438.  
  439.     /**
  440.      * @var array Complete set of raw link tags
  441.      * @access public
  442.      */
  443.     var $linkTagsRaw = array();
  444.  
  445.     /**
  446.      * @var array Array with a key => value pair representing
  447.      *            page# => bool value (true if key==currentPageNumber).
  448.      *            can be used for extreme customization.
  449.      * @access public
  450.      */
  451.     var $range = array();
  452.  
  453.     /**
  454.      * @var array list of available options (safety check)
  455.      * @access private
  456.      */
  457.     var $_allowed_options = array(
  458.         'totalItems',
  459.         'perPage',
  460.         'delta',
  461.         'linkClass',
  462.         'path',
  463.         'fileName',
  464.         'fixFileName',
  465.         'append',
  466.         'httpMethod',
  467.         'formID',
  468.         'importQuery',
  469.         'urlVar',
  470.         'altFirst',
  471.         'altPrev',
  472.         'altNext',
  473.         'altLast',
  474.         'altPage',
  475.         'prevImg',
  476.         'prevImgEmpty',
  477.         'nextImg',
  478.         'nextImgEmpty',
  479.         'expanded',
  480.         'accesskey',
  481.         'attributes',
  482.         'onclick',
  483.         'separator',
  484.         'spacesBeforeSeparator',
  485.         'spacesAfterSeparator',
  486.         'curPageLinkClassName',
  487.         'curPageSpanPre',
  488.         'curPageSpanPost',
  489.         'firstPagePre',
  490.         'firstPageText',
  491.         'firstPagePost',
  492.         'lastPagePre',
  493.         'lastPageText',
  494.         'lastPagePost',
  495.         'firstLinkTitle',
  496.         'nextLinkTitle',
  497.         'prevLinkTitle',
  498.         'lastLinkTitle',
  499.         'showAllText',
  500.         'itemData',
  501.         'clearIfVoid',
  502.         'useSessions',
  503.         'closeSession',
  504.         'sessionVar',
  505.         'pearErrorMode',
  506.         'extraVars',
  507.         'excludeVars',
  508.         'currentPage',
  509.     );
  510.  
  511.     // }}}
  512.     // {{{ build()
  513.  
  514.     /**
  515.      * Generate or refresh the links and paged data after a call to setOptions()
  516.      *
  517.      * @return void
  518.      * @access public
  519.      */
  520.     function build()
  521.     {
  522.         //reset
  523.         $this->_pageData   = array();
  524.         $this->links       = '';
  525.         $this->linkTags    = '';
  526.         $this->linkTagsRaw = array();
  527.  
  528.         $this->_generatePageData();
  529.         $this->_setFirstLastText();
  530.  
  531.         if ($this->_totalPages > (2 * $this->_delta + 1)) {
  532.             $this->links .= $this->_printFirstPage();
  533.         }
  534.  
  535.         $this->links .= $this->_getBackLink();
  536.         $this->links .= $this->_getPageLinks();
  537.         $this->links .= $this->_getNextLink();
  538.  
  539.         $this->linkTags .= $this->_getFirstLinkTag();
  540.         $this->linkTags .= $this->_getPrevLinkTag();
  541.         $this->linkTags .= $this->_getNextLinkTag();
  542.         $this->linkTags .= $this->_getLastLinkTag();
  543.         
  544.         $this->linkTagsRaw['first'] = $this->_getFirstLinkTag(true);
  545.         $this->linkTagsRaw['prev']  = $this->_getPrevLinkTag(true);
  546.         $this->linkTagsRaw['next']  = $this->_getNextLinkTag(true);
  547.         $this->linkTagsRaw['last']  = $this->_getLastLinkTag(true);
  548.  
  549.         if ($this->_totalPages > (2 * $this->_delta + 1)) {
  550.             $this->links .= $this->_printLastPage();
  551.         }
  552.     }
  553.  
  554.     // }}}
  555.     // {{{ getPageData()
  556.  
  557.     /**
  558.      * Returns an array of current pages data
  559.      *
  560.      * @param integer $pageID Desired page ID (optional)
  561.      *
  562.      * @return array Page data
  563.      * @access public
  564.      */
  565.     function getPageData($pageID = null)
  566.     {
  567.         $pageID = empty($pageID) ? $this->_currentPage : $pageID;
  568.  
  569.         if (!isset($this->_pageData)) {
  570.             $this->_generatePageData();
  571.         }
  572.         if (!empty($this->_pageData[$pageID])) {
  573.             return $this->_pageData[$pageID];
  574.         }
  575.         return array();
  576.     }
  577.  
  578.     // }}}
  579.     // {{{ getPageIdByOffset()
  580.  
  581.     /**
  582.      * Returns pageID for given offset
  583.      *
  584.      * @param integer $index Offset to get pageID for
  585.      *
  586.      * @return integer PageID for given offset
  587.      * @access public
  588.      */
  589.     function getPageIdByOffset($index)
  590.     {
  591.         $msg = 'function "getPageIdByOffset()" not implemented.';
  592.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  593.     }
  594.  
  595.     // }}}
  596.     // {{{ getOffsetByPageId()
  597.  
  598.     /**
  599.      * Returns offsets for given pageID. Eg, if you
  600.      * pass it pageID one and your perPage limit is 10
  601.      * it will return (1, 10). PageID of 2 would
  602.      * give you (11, 20).
  603.      *
  604.      * @param integer $pageID PageID to get offsets for
  605.      *
  606.      * @return array  First and last offsets
  607.      * @access public
  608.      */
  609.     function getOffsetByPageId($pageID = null)
  610.     {
  611.         $pageID = isset($pageID) ? $pageID : $this->_currentPage;
  612.         if (!isset($this->_pageData)) {
  613.             $this->_generatePageData();
  614.         }
  615.  
  616.         if (isset($this->_pageData[$pageID]) || is_null($this->_itemData)) {
  617.             return array(
  618.                         max(($this->_perPage * ($pageID - 1)) + 1, 1),
  619.                         min($this->_totalItems, $this->_perPage * $pageID)
  620.                    );
  621.         }
  622.         return array(0, 0);
  623.     }
  624.  
  625.     // }}}
  626.     // {{{ getPageRangeByPageId()
  627.  
  628.     /**
  629.      * Given a PageId, it returns the limits of the range of pages displayed.
  630.      *
  631.      * @param integer $pageID PageID to get offsets for
  632.      *
  633.      * @return array First and last offsets
  634.      * @access public
  635.      */
  636.     function getPageRangeByPageId($pageID = null)
  637.     {
  638.         $msg = 'function "getPageRangeByPageId()" not implemented.';
  639.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  640.     }
  641.  
  642.     // }}}
  643.     // {{{ getLinks()
  644.  
  645.     /**
  646.      * Returns back/next/first/last and page links,
  647.      * both as ordered and associative array.
  648.      *
  649.      * NB: in original PEAR::Pager this method accepted two parameters,
  650.      * $back_html and $next_html. Now the only parameter accepted is
  651.      * an integer ($pageID), since the html text for prev/next links can
  652.      * be set in the factory. If a second parameter is provided, then
  653.      * the method act as it previously did. This hack was done to mantain
  654.      * backward compatibility only.
  655.      *
  656.      * @param integer $pageID    Optional pageID. If specified, links for that
  657.      *                           page are provided instead of current one.
  658.      *                           [ADDED IN NEW PAGER VERSION]
  659.      * @param string  $next_html HTML to put inside the next link
  660.      *                           [deprecated: use the factory instead]
  661.      *
  662.      * @return array back/next/first/last and page links
  663.      * @access public
  664.      */
  665.     function getLinks($pageID=null, $next_html='')
  666.     {
  667.         $msg = 'function "getLinks()" not implemented.';
  668.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  669.     }
  670.  
  671.     // }}}
  672.     // {{{ getCurrentPageID()
  673.  
  674.     /**
  675.      * Returns ID of current page
  676.      *
  677.      * @return integer ID of current page
  678.      * @access public
  679.      */
  680.     function getCurrentPageID()
  681.     {
  682.         return $this->_currentPage;
  683.     }
  684.  
  685.     // }}}
  686.     // {{{ getNextPageID()
  687.  
  688.     /**
  689.      * Returns next page ID. If current page is last page
  690.      * this function returns FALSE
  691.      *
  692.      * @return mixed Next page ID or false
  693.      * @access public
  694.      */
  695.     function getNextPageID()
  696.     {
  697.         return ($this->getCurrentPageID() == $this->numPages() ? false : $this->getCurrentPageID() + 1);
  698.     }
  699.  
  700.     // }}}
  701.     // {{{ getPreviousPageID()
  702.  
  703.     /**
  704.      * Returns previous page ID. If current page is first page
  705.      * this function returns FALSE
  706.      *
  707.      * @return mixed Previous page ID or false
  708.      * @access public
  709.      */
  710.     function getPreviousPageID()
  711.     {
  712.         return $this->isFirstPage() ? false : $this->getCurrentPageID() - 1;
  713.     }
  714.  
  715.     // }}}
  716.     // {{{ numItems()
  717.  
  718.     /**
  719.      * Returns number of items
  720.      *
  721.      * @return integer Number of items
  722.      * @access public
  723.      */
  724.     function numItems()
  725.     {
  726.         return $this->_totalItems;
  727.     }
  728.  
  729.     // }}}
  730.     // {{{ numPages()
  731.  
  732.     /**
  733.      * Returns number of pages
  734.      *
  735.      * @return integer Number of pages
  736.      * @access public
  737.      */
  738.     function numPages()
  739.     {
  740.         return (int)$this->_totalPages;
  741.     }
  742.  
  743.     // }}}
  744.     // {{{ isFirstPage()
  745.  
  746.     /**
  747.      * Returns whether current page is first page
  748.      *
  749.      * @return bool First page or not
  750.      * @access public
  751.      */
  752.     function isFirstPage()
  753.     {
  754.         return ($this->_currentPage < 2);
  755.     }
  756.  
  757.     // }}}
  758.     // {{{ isLastPage()
  759.  
  760.     /**
  761.      * Returns whether current page is last page
  762.      *
  763.      * @return bool Last page or not
  764.      * @access public
  765.      */
  766.     function isLastPage()
  767.     {
  768.         return ($this->_currentPage == $this->_totalPages);
  769.     }
  770.  
  771.     // }}}
  772.     // {{{ isLastPageComplete()
  773.  
  774.     /**
  775.      * Returns whether last page is complete
  776.      *
  777.      * @return bool Last age complete or not
  778.      * @access public
  779.      */
  780.     function isLastPageComplete()
  781.     {
  782.         return !($this->_totalItems % $this->_perPage);
  783.     }
  784.  
  785.     // }}}
  786.     // {{{ _generatePageData()
  787.  
  788.     /**
  789.      * Calculates all page data
  790.      *
  791.      * @return void
  792.      * @access private
  793.      */
  794.     function _generatePageData()
  795.     {
  796.         // Been supplied an array of data?
  797.         if (!is_null($this->_itemData)) {
  798.             $this->_totalItems = count($this->_itemData);
  799.         }
  800.         $this->_totalPages = ceil((float)$this->_totalItems / (float)$this->_perPage);
  801.         $i = 1;
  802.         if (!empty($this->_itemData)) {
  803.             foreach ($this->_itemData as $key => $value) {
  804.                 $this->_pageData[$i][$key] = $value;
  805.                 if (count($this->_pageData[$i]) >= $this->_perPage) {
  806.                     $i++;
  807.                 }
  808.             }
  809.         } else {
  810.             $this->_pageData = array();
  811.         }
  812.  
  813.         //prevent URL modification
  814.         $this->_currentPage = min($this->_currentPage, $this->_totalPages);
  815.     }
  816.  
  817.     // }}}
  818.     // {{{ _renderLink()
  819.  
  820.     /**
  821.      * Renders a link using the appropriate method
  822.      *
  823.      * @param string $altText  Alternative text for this link (title property)
  824.      * @param string $linkText Text contained by this link
  825.      *
  826.      * @return string The link in string form
  827.      * @access private
  828.      */
  829.     function _renderLink($altText, $linkText)
  830.     {
  831.         if ($this->_httpMethod == 'GET') {
  832.             if ($this->_append) {
  833.                 $href = '?' . $this->_http_build_query_wrapper($this->_linkData);
  834.             } else {
  835.                 $href = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_fileName);
  836.             }
  837.             $onclick = '';
  838.             if (array_key_exists($this->_urlVar, $this->_linkData)) {
  839.                 $onclick = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_onclick);
  840.             }
  841.             return sprintf('<a href="%s"%s%s%s%s title="%s">%s</a>',
  842.                            htmlentities($this->_url . $href, ENT_COMPAT, 'UTF-8'),
  843.                            empty($this->_classString) ? '' : ' '.$this->_classString,
  844.                            empty($this->_attributes)  ? '' : ' '.$this->_attributes,
  845.                            empty($this->_accesskey)   ? '' : ' accesskey="'.$this->_linkData[$this->_urlVar].'"',
  846.                            empty($onclick)            ? '' : ' onclick="'.$onclick.'"',
  847.                            $altText,
  848.                            $linkText
  849.             );
  850.         } elseif ($this->_httpMethod == 'POST') {
  851.             $href = $this->_url;
  852.             if (!empty($_GET)) {
  853.                 $href .= '?' . $this->_http_build_query_wrapper($_GET);
  854.             }
  855.             return sprintf("<a href='javascript:void(0)' onclick='%s'%s%s%s title='%s'>%s</a>",
  856.                            $this->_generateFormOnClick($href, $this->_linkData),
  857.                            empty($this->_classString) ? '' : ' '.$this->_classString,
  858.                            empty($this->_attributes)  ? '' : ' '.$this->_attributes,
  859.                            empty($this->_accesskey)   ? '' : ' accesskey=\''.$this->_linkData[$this->_urlVar].'\'',
  860.                            $altText,
  861.                            $linkText
  862.             );
  863.         }
  864.         return '';
  865.     }
  866.  
  867.     // }}}
  868.     // {{{ _generateFormOnClick()
  869.  
  870.     /**
  871.      * Mimics http_build_query() behavior in the way the data
  872.      * in $data will appear when it makes it back to the server.
  873.      *  For example:
  874.      * $arr =  array('array' => array(array('hello', 'world'),
  875.      *                                'things' => array('stuff', 'junk'));
  876.      * http_build_query($arr)
  877.      * and _generateFormOnClick('foo.php', $arr)
  878.      * will yield
  879.      * $_REQUEST['array'][0][0] === 'hello'
  880.      * $_REQUEST['array'][0][1] === 'world'
  881.      * $_REQUEST['array']['things'][0] === 'stuff'
  882.      * $_REQUEST['array']['things'][1] === 'junk'
  883.      *
  884.      * However, instead of  generating a query string, it generates
  885.      * Javascript to create and submit a form.
  886.      *
  887.      * @param string $formAction where the form should be submitted
  888.      * @param array  $data       the associative array of names and values
  889.      *
  890.      * @return string A string of javascript that generates a form and submits it
  891.      * @access private
  892.      */
  893.     function _generateFormOnClick($formAction, $data)
  894.     {
  895.         // Check we have an array to work with
  896.         if (!is_array($data)) {
  897.             trigger_error(
  898.                 '_generateForm() Parameter 1 expected to be Array or Object. Incorrect value given.',
  899.                 E_USER_WARNING
  900.             );
  901.             return false;
  902.         }
  903.  
  904.         if (!empty($this->_formID)) {
  905.             $str = 'var form = document.getElementById("'.$this->_formID.'"); var input = ""; ';
  906.         } else {
  907.             $str = 'var form = document.createElement("form"); var input = ""; ';
  908.         }
  909.  
  910.         // We /shouldn't/ need to escape the URL ...
  911.         $str .= sprintf('form.action = "%s"; ', htmlentities($formAction, ENT_COMPAT, 'UTF-8'));
  912.         $str .= sprintf('form.method = "%s"; ', $this->_httpMethod);
  913.         foreach ($data as $key => $val) {
  914.             $str .= $this->_generateFormOnClickHelper($val, $key);
  915.         }
  916.  
  917.         if (empty($this->_formID)) {
  918.             $str .= 'document.getElementsByTagName("body")[0].appendChild(form);';
  919.         }
  920.  
  921.         $str .= 'form.submit(); return false;';
  922.         return $str;
  923.     }
  924.  
  925.     // }}}
  926.     // {{{ _generateFormOnClickHelper
  927.  
  928.     /**
  929.      * This is used by _generateFormOnClick().
  930.      * Recursively processes the arrays, objects, and literal values.
  931.      *
  932.      * @param mixed  $data Data that should be rendered
  933.      * @param string $prev The name so far
  934.      *
  935.      * @return string A string of Javascript that creates form inputs
  936.      *                representing the data
  937.      * @access private
  938.      */
  939.     function _generateFormOnClickHelper($data, $prev = '')
  940.     {
  941.         $str = '';
  942.         if (is_array($data) || is_object($data)) {
  943.             // foreach key/visible member
  944.             foreach ((array)$data as $key => $val) {
  945.                 // append [$key] to prev
  946.                 $tempKey = sprintf('%s[%s]', $prev, $key);
  947.                 $str .= $this->_generateFormOnClickHelper($val, $tempKey);
  948.             }
  949.         } else {  // must be a literal value
  950.             // escape newlines and carriage returns
  951.             $search  = array("\n", "\r");
  952.             $replace = array('\n', '\n');
  953.             $escapedData = str_replace($search, $replace, $data);
  954.             // am I forgetting any dangerous whitespace?
  955.             // would a regex be faster?
  956.             // if it's already encoded, don't encode it again
  957.             if (!$this->_isEncoded($escapedData)) {
  958.                 $escapedData = urlencode($escapedData);
  959.             }
  960.             $escapedData = htmlentities($escapedData, ENT_QUOTES, 'UTF-8');
  961.  
  962.             $str .= 'input = document.createElement("input"); ';
  963.             $str .= 'input.type = "hidden"; ';
  964.             $str .= sprintf('input.name = "%s"; ', $prev);
  965.             $str .= sprintf('input.value = "%s"; ', $escapedData);
  966.             $str .= 'form.appendChild(input); ';
  967.         }
  968.         return $str;
  969.     }
  970.  
  971.     // }}}
  972.     // {{{ _getLinksData()
  973.  
  974.     /**
  975.      * Returns the correct link for the back/pages/next links
  976.      *
  977.      * @return array Data
  978.      * @access private
  979.      */
  980.     function _getLinksData()
  981.     {
  982.         $qs = array();
  983.         if ($this->_importQuery) {
  984.             if ($this->_httpMethod == 'POST') {
  985.                 $qs = $_POST;
  986.             } elseif ($this->_httpMethod == 'GET') {
  987.                 $qs = $_GET;
  988.             }
  989.         }
  990.         foreach ($this->_excludeVars as $exclude) {
  991.             if (array_key_exists($exclude, $qs)) {
  992.                 unset($qs[$exclude]);
  993.             }
  994.         }
  995.         if (count($this->_extraVars)) {
  996.             $this->_recursive_urldecode($this->_extraVars);
  997.             $qs = array_merge($qs, $this->_extraVars);
  998.         }
  999.         if (count($qs) && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
  1000.             $this->_recursive_stripslashes($qs);
  1001.         }
  1002.         return $qs;
  1003.     }
  1004.  
  1005.     // }}}
  1006.     // {{{ _recursive_stripslashes()
  1007.  
  1008.     /**
  1009.      * Helper method
  1010.      *
  1011.      * @param string|array &$var variable to clean
  1012.      *
  1013.      * @return void
  1014.      * @access private
  1015.      */
  1016.     function _recursive_stripslashes(&$var)
  1017.     {
  1018.         if (is_array($var)) {
  1019.             foreach (array_keys($var) as $k) {
  1020.                 $this->_recursive_stripslashes($var[$k]);
  1021.             }
  1022.         } else {
  1023.             $var = stripslashes($var);
  1024.         }
  1025.     }
  1026.  
  1027.     // }}}
  1028.     // {{{ _recursive_urldecode()
  1029.  
  1030.     /**
  1031.      * Helper method
  1032.      *
  1033.      * @param string|array &$var variable to decode
  1034.      *
  1035.      * @return void
  1036.      * @access private
  1037.      */
  1038.     function _recursive_urldecode(&$var)
  1039.     {
  1040.         if (is_array($var)) {
  1041.             foreach (array_keys($var) as $k) {
  1042.                 $this->_recursive_urldecode($var[$k]);
  1043.             }
  1044.         } else {
  1045.             $trans_tbl = array_flip(get_html_translation_table(HTML_ENTITIES));
  1046.             $var = strtr($var, $trans_tbl);
  1047.         }
  1048.     }
  1049.  
  1050.     // }}}
  1051.     // {{{ _getBackLink()
  1052.  
  1053.     /**
  1054.      * Returns back link
  1055.      *
  1056.      * @param string $url  URL to use in the link  [deprecated: use the factory instead]
  1057.      * @param string $link HTML to use as the link [deprecated: use the factory instead]
  1058.      *
  1059.      * @return string The link
  1060.      * @access private
  1061.      */
  1062.     function _getBackLink($url='', $link='')
  1063.     {
  1064.         //legacy settings... the preferred way to set an option
  1065.         //now is passing it to the factory
  1066.         if (!empty($url)) {
  1067.             $this->_path = $url;
  1068.         }
  1069.         if (!empty($link)) {
  1070.             $this->_prevImg = $link;
  1071.         }
  1072.         $back = '';
  1073.         if ($this->_currentPage > 1) {
  1074.             $this->_linkData[$this->_urlVar] = $this->getPreviousPageID();
  1075.             $back = $this->_renderLink($this->_altPrev, $this->_prevImg)
  1076.                   . $this->_spacesBefore . $this->_spacesAfter;
  1077.         } else if ($this->_prevImgEmpty !== null) {
  1078.             $back = $this->_prevImgEmpty
  1079.                   . $this->_spacesBefore . $this->_spacesAfter;
  1080.         }
  1081.         return $back;
  1082.     }
  1083.  
  1084.     // }}}
  1085.     // {{{ _getPageLinks()
  1086.  
  1087.     /**
  1088.      * Returns pages link
  1089.      *
  1090.      * @param string $url URL to use in the link [deprecated: use the factory instead]
  1091.      *
  1092.      * @return string Links
  1093.      * @access private
  1094.      */
  1095.     function _getPageLinks($url='')
  1096.     {
  1097.         $msg = 'function "_getPageLinks()" not implemented.';
  1098.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  1099.     }
  1100.  
  1101.     // }}}
  1102.     // {{{ _getNextLink()
  1103.  
  1104.     /**
  1105.      * Returns next link
  1106.      *
  1107.      * @param string $url  URL to use in the link  [deprecated: use the factory instead]
  1108.      * @param string $link HTML to use as the link [deprecated: use the factory instead]
  1109.      *
  1110.      * @return string The link
  1111.      * @access private
  1112.      */
  1113.     function _getNextLink($url='', $link='')
  1114.     {
  1115.         //legacy settings... the preferred way to set an option
  1116.         //now is passing it to the factory
  1117.         if (!empty($url)) {
  1118.             $this->_path = $url;
  1119.         }
  1120.         if (!empty($link)) {
  1121.             $this->_nextImg = $link;
  1122.         }
  1123.         $next = '';
  1124.         if ($this->_currentPage < $this->_totalPages) {
  1125.             $this->_linkData[$this->_urlVar] = $this->getNextPageID();
  1126.             $next = $this->_spacesAfter
  1127.                   . $this->_renderLink($this->_altNext, $this->_nextImg)
  1128.                   . $this->_spacesBefore . $this->_spacesAfter;
  1129.         } else if ($this->_nextImgEmpty !== null) {
  1130.             $next = $this->_spacesAfter
  1131.                   . $this->_nextImgEmpty
  1132.                   . $this->_spacesBefore . $this->_spacesAfter;
  1133.         }
  1134.         return $next;
  1135.     }
  1136.  
  1137.     // }}}
  1138.     // {{{ _getFirstLinkTag()
  1139.  
  1140.     /**
  1141.      * Returns first link tag
  1142.      *
  1143.      * @param bool $raw should tag returned as array
  1144.      *
  1145.      * @return mixed string with html link tag or separated as array
  1146.      * @access private
  1147.      */
  1148.     function _getFirstLinkTag($raw = false)
  1149.     {
  1150.         if ($this->isFirstPage() || ($this->_httpMethod != 'GET')) {
  1151.             return $raw ? array() : '';
  1152.         }
  1153.         if ($raw) {
  1154.             return array(
  1155.                 'url'   => $this->_getLinkTagUrl(1),
  1156.                 'title' => $this->_firstLinkTitle
  1157.             );
  1158.         }
  1159.         return sprintf('<link rel="first" href="%s" title="%s" />'."\n",
  1160.             $this->_getLinkTagUrl(1),
  1161.             $this->_firstLinkTitle
  1162.         );
  1163.     }
  1164.  
  1165.     // }}}
  1166.     // {{{ _getPrevLinkTag()
  1167.  
  1168.     /**
  1169.      * Returns previous link tag
  1170.      *
  1171.      * @param bool $raw should tag returned as array
  1172.      *
  1173.      * @return mixed string with html link tag or separated as array
  1174.      * @access private
  1175.      */
  1176.     function _getPrevLinkTag($raw = false)
  1177.     {
  1178.         if ($this->isFirstPage() || ($this->_httpMethod != 'GET')) {
  1179.             return $raw ? array() : '';
  1180.         }
  1181.         if ($raw) {
  1182.             return array(
  1183.                 'url'   => $this->_getLinkTagUrl($this->getPreviousPageID()),
  1184.                 'title' => $this->_prevLinkTitle
  1185.             );
  1186.         }
  1187.         return sprintf('<link rel="previous" href="%s" title="%s" />'."\n",
  1188.             $this->_getLinkTagUrl($this->getPreviousPageID()),
  1189.             $this->_prevLinkTitle
  1190.         );
  1191.     }
  1192.  
  1193.     // }}}
  1194.     // {{{ _getNextLinkTag()
  1195.  
  1196.     /**
  1197.      * Returns next link tag
  1198.      *
  1199.      * @param bool $raw should tag returned as array
  1200.      *
  1201.      * @return mixed string with html link tag or separated as array
  1202.      * @access private
  1203.      */
  1204.     function _getNextLinkTag($raw = false)
  1205.     {
  1206.         if ($this->isLastPage() || ($this->_httpMethod != 'GET')) {
  1207.             return $raw ? array() : '';
  1208.         }
  1209.         if ($raw) {
  1210.             return array(
  1211.                 'url'   => $this->_getLinkTagUrl($this->getNextPageID()),
  1212.                 'title' => $this->_nextLinkTitle
  1213.             );
  1214.         }
  1215.         return sprintf('<link rel="next" href="%s" title="%s" />'."\n",
  1216.             $this->_getLinkTagUrl($this->getNextPageID()),
  1217.             $this->_nextLinkTitle
  1218.         );
  1219.     }
  1220.  
  1221.     // }}}
  1222.     // {{{ _getLastLinkTag()
  1223.  
  1224.     /**
  1225.      * Returns last link tag
  1226.      *
  1227.      * @param bool $raw should tag returned as array
  1228.      *
  1229.      * @return mixed string with html link tag or separated as array
  1230.      * @access private
  1231.      */
  1232.     function _getLastLinkTag($raw = false)
  1233.     {
  1234.         if ($this->isLastPage() || ($this->_httpMethod != 'GET')) {
  1235.             return $raw ? array() : '';
  1236.         }
  1237.         if ($raw) {
  1238.             return array(
  1239.                 'url'   => $this->_getLinkTagUrl($this->_totalPages),
  1240.                 'title' => $this->_lastLinkTitle
  1241.             );
  1242.         }
  1243.         return sprintf('<link rel="last" href="%s" title="%s" />'."\n",
  1244.             $this->_getLinkTagUrl($this->_totalPages),
  1245.             $this->_lastLinkTitle
  1246.         );
  1247.     }
  1248.  
  1249.     // }}}
  1250.     // {{{ _getLinkTagUrl()
  1251.  
  1252.     /**
  1253.      * Helper method
  1254.      *
  1255.      * @param integer $pageID page ID
  1256.      *
  1257.      * @return string the link tag url
  1258.      * @access private
  1259.      */
  1260.     function _getLinkTagUrl($pageID)
  1261.     {
  1262.         $this->_linkData[$this->_urlVar] = $pageID;
  1263.         if ($this->_append) {
  1264.             $href = '?' . $this->_http_build_query_wrapper($this->_linkData);
  1265.         } else {
  1266.             $href = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_fileName);
  1267.         }
  1268.         return htmlentities($this->_url . $href, ENT_COMPAT, 'UTF-8');
  1269.     }
  1270.  
  1271.     // }}}
  1272.     // {{{ getPerPageSelectBox()
  1273.  
  1274.     /**
  1275.      * Returns a string with a XHTML SELECT menu,
  1276.      * useful for letting the user choose how many items per page should be
  1277.      * displayed. If parameter useSessions is TRUE, this value is stored in
  1278.      * a session var. The string isn't echoed right now so you can use it
  1279.      * with template engines.
  1280.      *
  1281.      * @param integer $start       starting value for the select menu
  1282.      * @param integer $end         ending value for the select menu
  1283.      * @param integer $step        step between values in the select menu
  1284.      * @param boolean $showAllData If true, perPage is set equal to totalItems.
  1285.      * @param array   $extraParams (or string $optionText for BC reasons)
  1286.      *                - 'optionText': text to show in each option.
  1287.      *                  Use '%d' where you want to see the number of pages selected.
  1288.      *                - 'attributes': (html attributes) Tag attributes or
  1289.      *                  HTML attributes (id="foo" pairs), will be inserted in the
  1290.      *                  <select> tag
  1291.      *
  1292.      * @return string xhtml select box
  1293.      * @access public
  1294.      */
  1295.     function getPerPageSelectBox($start=5, $end=30, $step=5, $showAllData=false, $extraParams=array())
  1296.     {
  1297.         include_once 'Pager/HtmlWidgets.php';
  1298.         $widget =& new Pager_HtmlWidgets($this);
  1299.         return $widget->getPerPageSelectBox($start, $end, $step, $showAllData, $extraParams);
  1300.     }
  1301.  
  1302.     // }}}
  1303.     // {{{ getPageSelectBox()
  1304.  
  1305.     /**
  1306.      * Returns a string with a XHTML SELECT menu with the page numbers,
  1307.      * useful as an alternative to the links
  1308.      *
  1309.      * @param array  $params          - 'optionText': text to show in each option.
  1310.      *                                  Use '%d' where you want to see the number
  1311.      *                                  of pages selected.
  1312.      *                                - 'autoSubmit': if TRUE, add some js code
  1313.      *                                  to submit the form on the onChange event
  1314.      * @param string $extraAttributes (html attributes) Tag attributes or
  1315.      *                                HTML attributes (id="foo" pairs), will be
  1316.      *                                inserted in the <select> tag
  1317.      *
  1318.      * @return string xhtml select box
  1319.      * @access public
  1320.      */
  1321.     function getPageSelectBox($params = array(), $extraAttributes = '')
  1322.     {
  1323.         include_once 'Pager/HtmlWidgets.php';
  1324.         $widget =& new Pager_HtmlWidgets($this);
  1325.         return $widget->getPageSelectBox($params, $extraAttributes);
  1326.     }
  1327.  
  1328.     // }}}
  1329.     // {{{ _printFirstPage()
  1330.  
  1331.     /**
  1332.      * Print [1]
  1333.      *
  1334.      * @return string String with link to 1st page,
  1335.      *                or empty string if this is the 1st page.
  1336.      * @access private
  1337.      */
  1338.     function _printFirstPage()
  1339.     {
  1340.         if ($this->isFirstPage()) {
  1341.             return '';
  1342.         }
  1343.         $this->_linkData[$this->_urlVar] = 1;
  1344.         return $this->_renderLink(
  1345.                 str_replace('%d', 1, $this->_altFirst),
  1346.                 $this->_firstPagePre . $this->_firstPageText . $this->_firstPagePost
  1347.         ) . $this->_spacesBefore . $this->_spacesAfter;
  1348.     }
  1349.  
  1350.     // }}}
  1351.     // {{{ _printLastPage()
  1352.  
  1353.     /**
  1354.      * Print [numPages()]
  1355.      *
  1356.      * @return string String with link to last page,
  1357.      *                or empty string if this is the 1st page.
  1358.      * @access private
  1359.      */
  1360.     function _printLastPage()
  1361.     {
  1362.         if ($this->isLastPage()) {
  1363.             return '';
  1364.         }
  1365.         $this->_linkData[$this->_urlVar] = $this->_totalPages;
  1366.         return $this->_renderLink(
  1367.                 str_replace('%d', $this->_totalPages, $this->_altLast),
  1368.                 $this->_lastPagePre . $this->_lastPageText . $this->_lastPagePost
  1369.         );
  1370.     }
  1371.  
  1372.     // }}}
  1373.     // {{{ _setFirstLastText()
  1374.  
  1375.     /**
  1376.      * sets the private _firstPageText, _lastPageText variables
  1377.      * based on whether they were set in the options
  1378.      *
  1379.      * @return void
  1380.      * @access private
  1381.      */
  1382.     function _setFirstLastText()
  1383.     {
  1384.         if ($this->_firstPageText == '') {
  1385.             $this->_firstPageText = '1';
  1386.         }
  1387.         if ($this->_lastPageText == '') {
  1388.             $this->_lastPageText = $this->_totalPages;
  1389.         }
  1390.     }
  1391.  
  1392.     // }}}
  1393.     // {{{ _http_build_query_wrapper()
  1394.  
  1395.     /**
  1396.      * This is a slightly modified version of the http_build_query() function;
  1397.      * it heavily borrows code from PHP_Compat's http_build_query().
  1398.      * The main change is the usage of htmlentities instead of urlencode,
  1399.      * since it's too aggressive
  1400.      *
  1401.      * @param array $data array of querystring values
  1402.      *
  1403.      * @return string
  1404.      * @access private
  1405.      */
  1406.     function _http_build_query_wrapper($data)
  1407.     {
  1408.         $data = (array)$data;
  1409.         if (empty($data)) {
  1410.             return '';
  1411.         }
  1412.         $separator = ini_get('arg_separator.output');
  1413.         if ($separator == '&') {
  1414.             $separator = '&'; //the string is escaped by htmlentities anyway...
  1415.         }
  1416.         $tmp = array ();
  1417.         foreach ($data as $key => $val) {
  1418.             if (is_scalar($val)) {
  1419.                 //array_push($tmp, $key.'='.$val);
  1420.                 $val = urlencode($val);
  1421.                 array_push($tmp, $key .'='. str_replace('%2F', '/', $val));
  1422.                 continue;
  1423.             }
  1424.             // If the value is an array, recursively parse it
  1425.             if (is_array($val)) {
  1426.                 array_push($tmp, $this->__http_build_query($val, urlencode($key)));
  1427.                 continue;
  1428.             }
  1429.         }
  1430.         return implode($separator, $tmp);
  1431.     }
  1432.  
  1433.     // }}}
  1434.     // {{{ __http_build_query()
  1435.  
  1436.     /**
  1437.      * Helper function
  1438.      *
  1439.      * @param array  $array array of querystring values
  1440.      * @param string $name  key
  1441.      *
  1442.      * @return string
  1443.      * @access private
  1444.      */
  1445.     function __http_build_query($array, $name)
  1446.     {
  1447.         $tmp = array ();
  1448.         $separator = ini_get('arg_separator.output');
  1449.         if ($separator == '&') {
  1450.             $separator = '&'; //the string is escaped by htmlentities anyway...
  1451.         }
  1452.         foreach ($array as $key => $value) {
  1453.             if (is_array($value)) {
  1454.                 //array_push($tmp, $this->__http_build_query($value, sprintf('%s[%s]', $name, $key)));
  1455.                 array_push($tmp, $this->__http_build_query($value, $name.'%5B'.$key.'%5D'));
  1456.             } elseif (is_scalar($value)) {
  1457.                 //array_push($tmp, sprintf('%s[%s]=%s', $name, htmlentities($key), htmlentities($value)));
  1458.                 array_push($tmp, $name.'%5B'.urlencode($key).'%5D='.urlencode($value));
  1459.             } elseif (is_object($value)) {
  1460.                 //array_push($tmp, $this->__http_build_query(get_object_vars($value), sprintf('%s[%s]', $name, $key)));
  1461.                 array_push($tmp, $this->__http_build_query(get_object_vars($value), $name.'%5B'.$key.'%5D'));
  1462.             }
  1463.         }
  1464.         return implode($separator, $tmp);
  1465.     }
  1466.  
  1467.     // }}}
  1468.     // {{{ _isEncoded()
  1469.  
  1470.     /**
  1471.      * Helper function
  1472.      * Check if a string is an encoded multibyte string
  1473.      *
  1474.      * @param string $string string to check
  1475.      *
  1476.      * @return boolean
  1477.      * @access private
  1478.      */
  1479.  
  1480.     function _isEncoded($string)
  1481.     {
  1482.         $hexchar = '&#[\dA-Fx]{2,};';
  1483.         return preg_match("/^(\s|($hexchar))*$/Uims", $string) ? true : false;
  1484.     }
  1485.  
  1486.     // }}}
  1487.     // {{{ raiseError()
  1488.  
  1489.     /**
  1490.      * conditionally includes PEAR base class and raise an error
  1491.      *
  1492.      * @param string  $msg  Error message
  1493.      * @param integer $code Error code
  1494.      *
  1495.      * @return PEAR_Error
  1496.      * @access private
  1497.      */
  1498.     function raiseError($msg, $code)
  1499.     {
  1500.         include_once 'PEAR.php';
  1501.         if (empty($this->_pearErrorMode)) {
  1502.             $this->_pearErrorMode = PEAR_ERROR_RETURN;
  1503.         }
  1504.         return PEAR::raiseError($msg, $code, $this->_pearErrorMode);
  1505.     }
  1506.  
  1507.     // }}}
  1508.     // {{{ setOptions()
  1509.  
  1510.     /**
  1511.      * Set and sanitize options
  1512.      *
  1513.      * @param mixed $options An associative array of option names and their values
  1514.      *
  1515.      * @return integer error code (PAGER_OK on success)
  1516.      * @access public
  1517.      */
  1518.     function setOptions($options)
  1519.     {
  1520.         foreach ($options as $key => $value) {
  1521.             if (in_array($key, $this->_allowed_options) && (!is_null($value))) {
  1522.                 $this->{'_' . $key} = $value;
  1523.             }
  1524.         }
  1525.  
  1526.         //autodetect http method
  1527.         if (!isset($options['httpMethod'])
  1528.             && !isset($_GET[$this->_urlVar])
  1529.             && isset($_POST[$this->_urlVar])
  1530.         ) {
  1531.             $this->_httpMethod = 'POST';
  1532.         } else {
  1533.             $this->_httpMethod = strtoupper($this->_httpMethod);
  1534.         }
  1535.  
  1536.         $this->_fileName = ltrim($this->_fileName, '/');  //strip leading slash
  1537.         $this->_path     = rtrim($this->_path, '/');      //strip trailing slash
  1538.  
  1539.         if ($this->_append) {
  1540.             if ($this->_fixFileName) {
  1541.                 $this->_fileName = PAGER_CURRENT_FILENAME; //avoid possible user error;
  1542.             }
  1543.             $this->_url = $this->_path.(!empty($this->_path) ? '/' : '').$this->_fileName;
  1544.         } else {
  1545.             $this->_url = $this->_path;
  1546.             if (0 != strncasecmp($this->_fileName, 'javascript', 10)) {
  1547.                 $this->_url .= (!empty($this->_path) ? '/' : '');
  1548.             }
  1549.             if (false === strpos($this->_fileName, '%d')) {
  1550.                 trigger_error($this->errorMessage(ERROR_PAGER_INVALID_USAGE), E_USER_WARNING);
  1551.             }
  1552.         }
  1553.         if (false === strpos($this->_altPage, '%d')) {
  1554.             //by default, append page number at the end
  1555.             $this->_altPage .= ' %d';
  1556.         }
  1557.  
  1558.         $this->_classString = '';
  1559.         if (strlen($this->_linkClass)) {
  1560.             $this->_classString = 'class="'.$this->_linkClass.'"';
  1561.         }
  1562.  
  1563.         if (strlen($this->_curPageLinkClassName)) {
  1564.             $this->_curPageSpanPre  .= '<span class="'.$this->_curPageLinkClassName.'">';
  1565.             $this->_curPageSpanPost = '</span>' . $this->_curPageSpanPost;
  1566.         }
  1567.  
  1568.         $this->_perPage = max($this->_perPage, 1); //avoid possible user errors
  1569.  
  1570.         if ($this->_useSessions && !isset($_SESSION)) {
  1571.             session_start();
  1572.         }
  1573.         if (!empty($_REQUEST[$this->_sessionVar])) {
  1574.             $this->_perPage = max(1, (int)$_REQUEST[$this->_sessionVar]);
  1575.             if ($this->_useSessions) {
  1576.                 $_SESSION[$this->_sessionVar] = $this->_perPage;
  1577.             }
  1578.         }
  1579.  
  1580.         if (!empty($_SESSION[$this->_sessionVar]) && $this->_useSessions) {
  1581.              $this->_perPage = $_SESSION[$this->_sessionVar];
  1582.         }
  1583.  
  1584.         if ($this->_closeSession) {
  1585.             session_write_close();
  1586.         }
  1587.  
  1588.         $this->_spacesBefore = str_repeat(' ', $this->_spacesBeforeSeparator);
  1589.         $this->_spacesAfter  = str_repeat(' ', $this->_spacesAfterSeparator);
  1590.  
  1591.         if (isset($_REQUEST[$this->_urlVar]) && empty($options['currentPage'])) {
  1592.             $this->_currentPage = (int)$_REQUEST[$this->_urlVar];
  1593.         }
  1594.         $this->_currentPage = max($this->_currentPage, 1);
  1595.         $this->_linkData = $this->_getLinksData();
  1596.  
  1597.         return PAGER_OK;
  1598.     }
  1599.  
  1600.     // }}}
  1601.     // {{{ getOption()
  1602.  
  1603.     /**
  1604.      * Return the current value of a given option
  1605.      *
  1606.      * @param string $name option name
  1607.      *
  1608.      * @return mixed option value
  1609.      * @access public
  1610.      */
  1611.     function getOption($name)
  1612.     {
  1613.         if (!in_array($name, $this->_allowed_options)) {
  1614.             $msg = 'invalid option: '.$name;
  1615.             return $this->raiseError($msg, ERROR_PAGER_INVALID);
  1616.         }
  1617.         return $this->{'_' . $name};
  1618.     }
  1619.  
  1620.     // }}}
  1621.     // {{{ getOptions()
  1622.  
  1623.     /**
  1624.      * Return an array with all the current pager options
  1625.      *
  1626.      * @return array list of all the pager options
  1627.      * @access public
  1628.      */
  1629.     function getOptions()
  1630.     {
  1631.         $options = array();
  1632.         foreach ($this->_allowed_options as $option) {
  1633.             $options[$option] = $this->{'_' . $option};
  1634.         }
  1635.         return $options;
  1636.     }
  1637.  
  1638.     // }}}
  1639.     // {{{ errorMessage()
  1640.  
  1641.     /**
  1642.      * Return a textual error message for a PAGER error code
  1643.      *
  1644.      * @param integer $code error code
  1645.      *
  1646.      * @return string error message
  1647.      * @access public
  1648.      */
  1649.     function errorMessage($code)
  1650.     {
  1651.         static $errorMessages;
  1652.         if (!isset($errorMessages)) {
  1653.             $errorMessages = array(
  1654.                 ERROR_PAGER                     => 'unknown error',
  1655.                 ERROR_PAGER_INVALID             => 'invalid',
  1656.                 ERROR_PAGER_INVALID_PLACEHOLDER => 'invalid format - use "%d" as placeholder.',
  1657.                 ERROR_PAGER_INVALID_USAGE       => 'if $options[\'append\'] is set to false, '
  1658.                                                   .' $options[\'fileName\'] MUST contain the "%d" placeholder.',
  1659.                 ERROR_PAGER_NOT_IMPLEMENTED     => 'not implemented'
  1660.             );
  1661.         }
  1662.  
  1663.         return (isset($errorMessages[$code]) ?
  1664.             $errorMessages[$code] : $errorMessages[ERROR_PAGER]);
  1665.     }
  1666.  
  1667.     // }}}
  1668. }
  1669. ?>