Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1712 jp_milcent 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 dot alberton at quipo dot it>
33
 * @author     Richard Heyes <richard@phpguru.org>
34
 * @copyright  2003-2006 Lorenzo Alberton, Richard Heyes
35
 * @license    http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
36
 * @version    CVS: $Id$
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 = !empty($_SERVER['HTTPS']) ? 'https://' : 'http://';
46
    define('CURRENT_FILENAME', '');
47
    define('CURRENT_PATHNAME', $http.$_SERVER['HTTP_HOST'].str_replace('\\', '/', $_SERVER['PHP_SELF']));
48
} else {
49
    define('CURRENT_FILENAME', preg_replace('/(.*)\?.*/', '\\1', basename($_SERVER['PHP_SELF'])));
50
    define('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 dot alberton at quipo dot it>
69
 * @author     Richard Heyes <richard@phpguru.org>
70
 * @copyright  2003-2005 Lorenzo Alberton, Richard Heyes
71
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
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        = CURRENT_PATHNAME;
125
 
126
    /**
127
     * @var string file name
128
     * @access private
129
     */
130
    var $_fileName    = 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"
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     = '&lt;&lt; Back';
245
 
246
    /**
247
     * @var string image/text to use as "next" link
248
     * @access private
249
     */
250
    var $_nextImg     = 'Next &gt;&gt;';
251
 
252
    /**
253
     * @var string link separator
254
     * @access private
255
     */
256
    var $_separator   = '';
257
 
258
    /**
259
     * @var integer number of spaces before separator
260
     * @access private
261
     */
262
    var $_spacesBeforeSeparator = 0;
263
 
264
    /**
265
     * @var integer number of spaces after separator
266
     * @access private
267
     */
268
    var $_spacesAfterSeparator  = 1;
269
 
270
    /**
271
     * @var string CSS class name for current page link
272
     * @access private
273
     */
274
    var $_curPageLinkClassName  = '';
275
 
276
    /**
277
     * @var string Text before current page link
278
     * @access private
279
     */
280
    var $_curPageSpanPre        = '';
281
 
282
    /**
283
     * @var string Text after current page link
284
     * @access private
285
     */
286
    var $_curPageSpanPost       = '';
287
 
288
    /**
289
     * @var string Text before first page link
290
     * @access private
291
     */
292
    var $_firstPagePre  = '[';
293
 
294
    /**
295
     * @var string Text to be used for first page link
296
     * @access private
297
     */
298
    var $_firstPageText = '';
299
 
300
    /**
301
     * @var string Text after first page link
302
     * @access private
303
     */
304
    var $_firstPagePost = ']';
305
 
306
    /**
307
     * @var string Text before last page link
308
     * @access private
309
     */
310
    var $_lastPagePre   = '[';
311
 
312
    /**
313
     * @var string Text to be used for last page link
314
     * @access private
315
     */
316
    var $_lastPageText  = '';
317
 
318
    /**
319
     * @var string Text after last page link
320
     * @access private
321
     */
322
    var $_lastPagePost  = ']';
323
 
324
    /**
325
     * @var string Will contain the HTML code for the spaces
326
     * @access private
327
     */
328
    var $_spacesBefore  = '';
329
 
330
    /**
331
     * @var string Will contain the HTML code for the spaces
332
     * @access private
333
     */
334
    var $_spacesAfter   = '';
335
 
336
    /**
337
     * @var string $_firstLinkTitle
338
     * @access private
339
     */
340
    var $_firstLinkTitle = 'first page';
341
 
342
    /**
343
     * @var string $_nextLinkTitle
344
     * @access private
345
     */
346
    var $_nextLinkTitle = 'next page';
347
 
348
    /**
349
     * @var string $_prevLinkTitle
350
     * @access private
351
     */
352
    var $_prevLinkTitle = 'previous page';
353
 
354
    /**
355
     * @var string $_lastLinkTitle
356
     * @access private
357
     */
358
    var $_lastLinkTitle = 'last page';
359
 
360
    /**
361
     * @var string Text to be used for the 'show all' option in the select box
362
     * @access private
363
     */
364
    var $_showAllText   = '';
365
 
366
    /**
367
     * @var array data to be paged
368
     * @access private
369
     */
370
    var $_itemData      = null;
371
 
372
    /**
373
     * @var boolean If TRUE and there's only one page, links aren't shown
374
     * @access private
375
     */
376
    var $_clearIfVoid   = true;
377
 
378
    /**
379
     * @var boolean Use session for storing the number of items per page
380
     * @access private
381
     */
382
    var $_useSessions   = false;
383
 
384
    /**
385
     * @var boolean Close the session when finished reading/writing data
386
     * @access private
387
     */
388
    var $_closeSession  = false;
389
 
390
    /**
391
     * @var string name of the session var for number of items per page
392
     * @access private
393
     */
394
    var $_sessionVar    = 'setPerPage';
395
 
396
    /**
397
     * Pear error mode (when raiseError is called)
398
     * (see PEAR doc)
399
     *
400
     * @var int $_pearErrorMode
401
     * @access private
402
     */
403
    var $_pearErrorMode = null;
404
 
405
    // }}}
406
    // {{{ public vars
407
 
408
    /**
409
     * @var string Complete set of links
410
     * @access public
411
     */
412
    var $links = '';
413
 
414
    /**
415
     * @var string Complete set of link tags
416
     * @access public
417
     */
418
    var $linkTags = '';
419
 
420
    /**
421
     * @var array Array with a key => value pair representing
422
     *            page# => bool value (true if key==currentPageNumber).
423
     *            can be used for extreme customization.
424
     * @access public
425
     */
426
    var $range = array();
427
 
428
    /**
429
     * @var array list of available options (safety check)
430
     * @access private
431
     */
432
    var $_allowed_options = array(
433
        'totalItems',
434
        'perPage',
435
        'delta',
436
        'linkClass',
437
        'path',
438
        'fileName',
439
        'fixFileName',
440
        'append',
441
        'httpMethod',
442
        'formID',
443
        'importQuery',
444
        'urlVar',
445
        'altFirst',
446
        'altPrev',
447
        'altNext',
448
        'altLast',
449
        'altPage',
450
        'prevImg',
451
        'nextImg',
452
        'expanded',
453
        'accesskey',
454
        'attributes',
455
        'onclick',
456
        'separator',
457
        'spacesBeforeSeparator',
458
        'spacesAfterSeparator',
459
        'curPageLinkClassName',
460
        'curPageSpanPre',
461
        'curPageSpanPost',
462
        'firstPagePre',
463
        'firstPageText',
464
        'firstPagePost',
465
        'lastPagePre',
466
        'lastPageText',
467
        'lastPagePost',
468
        'firstLinkTitle',
469
        'nextLinkTitle',
470
        'prevLinkTitle',
471
        'lastLinkTitle',
472
        'showAllText',
473
        'itemData',
474
        'clearIfVoid',
475
        'useSessions',
476
        'closeSession',
477
        'sessionVar',
478
        'pearErrorMode',
479
        'extraVars',
480
        'excludeVars',
481
        'currentPage',
482
    );
483
 
484
    // }}}
485
    // {{{ build()
486
 
487
    /**
488
     * Generate or refresh the links and paged data after a call to setOptions()
489
     *
490
     * @access public
491
     */
492
    function build()
493
    {
494
        //reset
495
        $this->_pageData = array();
496
        $this->links = '';
497
 
498
        $this->_generatePageData();
499
        $this->_setFirstLastText();
500
 
501
        if ($this->_totalPages > (2 * $this->_delta + 1)) {
502
            $this->links .= $this->_printFirstPage();
503
        }
504
 
505
        $this->links .= $this->_getBackLink();
506
        $this->links .= $this->_getPageLinks();
507
        $this->links .= $this->_getNextLink();
508
 
509
        $this->linkTags .= $this->_getFirstLinkTag();
510
        $this->linkTags .= $this->_getPrevLinkTag();
511
        $this->linkTags .= $this->_getNextLinkTag();
512
        $this->linkTags .= $this->_getLastLinkTag();
513
 
514
        if ($this->_totalPages > (2 * $this->_delta + 1)) {
515
            $this->links .= $this->_printLastPage();
516
        }
517
    }
518
 
519
    // }}}
520
    // {{{ getPageData()
521
 
522
    /**
523
     * Returns an array of current pages data
524
     *
525
     * @param $pageID Desired page ID (optional)
526
     * @return array Page data
527
     * @access public
528
     */
529
    function getPageData($pageID = null)
530
    {
531
        $pageID = empty($pageID) ? $this->_currentPage : $pageID;
532
 
533
        if (!isset($this->_pageData)) {
534
            $this->_generatePageData();
535
        }
536
        if (!empty($this->_pageData[$pageID])) {
537
            return $this->_pageData[$pageID];
538
        }
539
        return array();
540
    }
541
 
542
    // }}}
543
    // {{{ getPageIdByOffset()
544
 
545
    /**
546
     * Returns pageID for given offset
547
     *
548
     * @param $index Offset to get pageID for
549
     * @return int PageID for given offset
550
     */
551
    function getPageIdByOffset($index)
552
    {
553
        $msg = '<b>PEAR::Pager Error:</b>'
554
              .' function "getPageIdByOffset()" not implemented.';
555
        return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
556
    }
557
 
558
    // }}}
559
    // {{{ getOffsetByPageId()
560
 
561
    /**
562
     * Returns offsets for given pageID. Eg, if you
563
     * pass it pageID one and your perPage limit is 10
564
     * it will return (1, 10). PageID of 2 would
565
     * give you (11, 20).
566
     *
567
     * @param integer PageID to get offsets for
568
     * @return array  First and last offsets
569
     * @access public
570
     */
571
    function getOffsetByPageId($pageid = null)
572
    {
573
        $pageid = isset($pageid) ? $pageid : $this->_currentPage;
574
        if (!isset($this->_pageData)) {
575
            $this->_generatePageData();
576
        }
577
 
578
        if (isset($this->_pageData[$pageid]) || is_null($this->_itemData)) {
579
            return array(
580
                        max(($this->_perPage * ($pageid - 1)) + 1, 1),
581
                        min($this->_totalItems, $this->_perPage * $pageid)
582
                   );
583
        } else {
584
            return array(0, 0);
585
        }
586
    }
587
 
588
    // }}}
589
    // {{{ getPageRangeByPageId()
590
 
591
    /**
592
     * @param integer PageID to get offsets for
593
     * @return array  First and last offsets
594
     */
595
    function getPageRangeByPageId($pageID)
596
    {
597
        $msg = '<b>PEAR::Pager Error:</b>'
598
              .' function "getPageRangeByPageId()" not implemented.';
599
        return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
600
    }
601
 
602
    // }}}
603
    // {{{ getLinks()
604
 
605
    /**
606
     * Returns back/next/first/last and page links,
607
     * both as ordered and associative array.
608
     *
609
     * NB: in original PEAR::Pager this method accepted two parameters,
610
     * $back_html and $next_html. Now the only parameter accepted is
611
     * an integer ($pageID), since the html text for prev/next links can
612
     * be set in the factory. If a second parameter is provided, then
613
     * the method act as it previously did. This hack was done to mantain
614
     * backward compatibility only.
615
     *
616
     * @param integer $pageID Optional pageID. If specified, links
617
     *                for that page are provided instead of current one.  [ADDED IN NEW PAGER VERSION]
618
     * @param  string $next_html HTML to put inside the next link [deprecated: use the factory instead]
619
     * @return array back/next/first/last and page links
620
     */
621
    function getLinks($pageID=null, $next_html='')
622
    {
623
        $msg = '<b>PEAR::Pager Error:</b>'
624
              .' function "getLinks()" not implemented.';
625
        return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
626
    }
627
 
628
    // }}}
629
    // {{{ getCurrentPageID()
630
 
631
    /**
632
     * Returns ID of current page
633
     *
634
     * @return integer ID of current page
635
     */
636
    function getCurrentPageID()
637
    {
638
        return $this->_currentPage;
639
    }
640
 
641
    // }}}
642
    // {{{ getNextPageID()
643
 
644
    /**
645
     * Returns next page ID. If current page is last page
646
	 * this function returns FALSE
647
	 *
648
	 * @return mixed Next page ID
649
     */
650
	function getNextPageID()
651
	{
652
		return ($this->getCurrentPageID() == $this->numPages() ? false : $this->getCurrentPageID() + 1);
653
	}
654
 
655
	// }}}
656
    // {{{ getPreviousPageID()
657
 
658
    /**
659
     * Returns previous page ID. If current page is first page
660
	 * this function returns FALSE
661
	 *
662
	 * @return mixed Previous pages' ID
663
     */
664
	function getPreviousPageID()
665
	{
666
		return $this->isFirstPage() ? false : $this->getCurrentPageID() - 1;
667
	}
668
 
669
    // }}}
670
    // {{{ numItems()
671
 
672
    /**
673
     * Returns number of items
674
     *
675
     * @return int Number of items
676
     */
677
    function numItems()
678
    {
679
        return $this->_totalItems;
680
    }
681
 
682
    // }}}
683
    // {{{ numPages()
684
 
685
    /**
686
     * Returns number of pages
687
     *
688
     * @return int Number of pages
689
     */
690
    function numPages()
691
    {
692
        return (int)$this->_totalPages;
693
    }
694
 
695
    // }}}
696
    // {{{ isFirstPage()
697
 
698
    /**
699
     * Returns whether current page is first page
700
     *
701
     * @return bool First page or not
702
     */
703
    function isFirstPage()
704
    {
705
        return ($this->_currentPage < 2);
706
    }
707
 
708
    // }}}
709
    // {{{ isLastPage()
710
 
711
    /**
712
     * Returns whether current page is last page
713
     *
714
     * @return bool Last page or not
715
     */
716
    function isLastPage()
717
    {
718
        return ($this->_currentPage == $this->_totalPages);
719
    }
720
 
721
    // }}}
722
    // {{{ isLastPageComplete()
723
 
724
    /**
725
     * Returns whether last page is complete
726
     *
727
     * @return bool Last age complete or not
728
     */
729
    function isLastPageComplete()
730
    {
731
        return !($this->_totalItems % $this->_perPage);
732
    }
733
 
734
    // }}}
735
    // {{{ _generatePageData()
736
 
737
    /**
738
     * Calculates all page data
739
     * @access private
740
     */
741
    function _generatePageData()
742
    {
743
        // Been supplied an array of data?
744
        if (!is_null($this->_itemData)) {
745
            $this->_totalItems = count($this->_itemData);
746
        }
747
        $this->_totalPages = ceil((float)$this->_totalItems / (float)$this->_perPage);
748
        $i = 1;
749
        if (!empty($this->_itemData)) {
750
            foreach ($this->_itemData as $key => $value) {
751
                $this->_pageData[$i][$key] = $value;
752
                if (count($this->_pageData[$i]) >= $this->_perPage) {
753
                    $i++;
754
                }
755
            }
756
        } else {
757
            $this->_pageData = array();
758
        }
759
 
760
        //prevent URL modification
761
        $this->_currentPage = min($this->_currentPage, $this->_totalPages);
762
    }
763
 
764
    // }}}
765
    // {{{ _renderLink()
766
 
767
    /**
768
     * Renders a link using the appropriate method
769
     *
770
     * @param altText Alternative text for this link (title property)
771
     * @param linkText Text contained by this link
772
     * @return string The link in string form
773
     * @access private
774
     */
775
    function _renderLink($altText, $linkText)
776
    {
777
        if ($this->_httpMethod == 'GET') {
778
            if ($this->_append) {
779
                $href = '?' . $this->_http_build_query_wrapper($this->_linkData);
780
            } else {
781
                $href = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_fileName);
782
            }
783
            $onclick = '';
784
            if (array_key_exists($this->_urlVar, $this->_linkData)) {
785
                $onclick = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_onclick);
786
            }
787
            return sprintf('<a href="%s"%s%s%s%s title="%s">%s</a>',
788
                           htmlentities($this->_url . $href),
789
                           empty($this->_classString) ? '' : ' '.$this->_classString,
790
                           empty($this->_attributes)  ? '' : ' '.$this->_attributes,
791
                           empty($this->_accesskey)   ? '' : ' accesskey="'.$this->_linkData[$this->_urlVar].'"',
792
                           empty($onclick)            ? '' : ' onclick="'.$onclick.'"',
793
                           $altText,
794
                           $linkText
795
            );
796
        } elseif ($this->_httpMethod == 'POST') {
797
            return sprintf("<a href='javascript:void(0)' onclick='%s'%s%s%s title='%s'>%s</a>",
798
                           $this->_generateFormOnClick($this->_url, $this->_linkData),
799
                           empty($this->_classString) ? '' : ' '.$this->_classString,
800
                           empty($this->_attributes)  ? '' : ' '.$this->_attributes,
801
                           empty($this->_accesskey)   ? '' : ' accesskey=\''.$this->_linkData[$this->_urlVar].'\'',
802
                           $altText,
803
                           $linkText
804
            );
805
        }
806
        return '';
807
    }
808
 
809
    // }}}
810
    // {{{ _generateFormOnClick()
811
 
812
    /**
813
     * Mimics http_build_query() behavior in the way the data
814
     * in $data will appear when it makes it back to the server.
815
     *  For example:
816
     * $arr =  array('array' => array(array('hello', 'world'),
817
     *                                'things' => array('stuff', 'junk'));
818
     * http_build_query($arr)
819
     * and _generateFormOnClick('foo.php', $arr)
820
     * will yield
821
     * $_REQUEST['array'][0][0] === 'hello'
822
     * $_REQUEST['array'][0][1] === 'world'
823
     * $_REQUEST['array']['things'][0] === 'stuff'
824
     * $_REQUEST['array']['things'][1] === 'junk'
825
     *
826
     * However, instead of  generating a query string, it generates
827
     * Javascript to create and submit a form.
828
     *
829
     * @param string $formAction where the form should be submitted
830
     * @param array  $data the associative array of names and values
831
     * @return string A string of javascript that generates a form and submits it
832
     * @access private
833
     */
834
    function _generateFormOnClick($formAction, $data)
835
    {
836
        // Check we have an array to work with
837
        if (!is_array($data)) {
838
            trigger_error(
839
                '_generateForm() Parameter 1 expected to be Array or Object. Incorrect value given.',
840
                E_USER_WARNING
841
            );
842
            return false;
843
        }
844
 
845
        if (!empty($this->_formID)) {
846
            $str = 'var form = document.getElementById("'.$this->_formID.'"); var input = ""; ';
847
        } else {
848
            $str = 'var form = document.createElement("form"); var input = ""; ';
849
        }
850
 
851
        // We /shouldn't/ need to escape the URL ...
852
        $str .= sprintf('form.action = "%s"; ', htmlentities($formAction));
853
        $str .= sprintf('form.method = "%s"; ', $this->_httpMethod);
854
        foreach ($data as $key => $val) {
855
            $str .= $this->_generateFormOnClickHelper($val, $key);
856
        }
857
 
858
        if (empty($this->_formID)) {
859
            $str .= 'document.getElementsByTagName("body")[0].appendChild(form);';
860
        }
861
 
862
        $str .= 'form.submit(); return false;';
863
        return $str;
864
    }
865
 
866
    // }}}
867
    // {{{ _generateFormOnClickHelper
868
 
869
    /**
870
     * This is used by _generateFormOnClick().
871
     * Recursively processes the arrays, objects, and literal values.
872
     *
873
     * @param data Data that should be rendered
874
     * @param prev The name so far
875
     * @return string A string of Javascript that creates form inputs
876
     *                representing the data
877
     * @access private
878
     */
879
    function _generateFormOnClickHelper($data, $prev = '')
880
    {
881
        $str = '';
882
        if (is_array($data) || is_object($data)) {
883
            // foreach key/visible member
884
            foreach ((array)$data as $key => $val) {
885
                // append [$key] to prev
886
                $tempKey = sprintf('%s[%s]', $prev, $key);
887
                $str .= $this->_generateFormOnClickHelper($val, $tempKey);
888
            }
889
        } else {  // must be a literal value
890
            // escape newlines and carriage returns
891
            $search  = array("\n", "\r");
892
            $replace = array('\n', '\n');
893
            $escapedData = str_replace($search, $replace, $data);
894
            // am I forgetting any dangerous whitespace?
895
            // would a regex be faster?
896
            // if it's already encoded, don't encode it again
897
            if (!$this->_isEncoded($escapedData)) {
898
                $escapedData = urlencode($escapedData);
899
            }
900
            $escapedData = htmlentities($escapedData, ENT_QUOTES, 'UTF-8');
901
 
902
            $str .= 'input = document.createElement("input"); ';
903
            $str .= 'input.type = "hidden"; ';
904
            $str .= sprintf('input.name = "%s"; ', $prev);
905
            $str .= sprintf('input.value = "%s"; ', $escapedData);
906
            $str .= 'form.appendChild(input); ';
907
        }
908
        return $str;
909
    }
910
 
911
    // }}}
912
    // {{{ _getLinksData()
913
 
914
    /**
915
     * Returns the correct link for the back/pages/next links
916
     *
917
     * @return array Data
918
     * @access private
919
     */
920
    function _getLinksData()
921
    {
922
        $qs = array();
923
        if ($this->_importQuery) {
924
            if ($this->_httpMethod == 'POST') {
925
                $qs = $_POST;
926
            } elseif ($this->_httpMethod == 'GET') {
927
                $qs = $_GET;
928
            }
929
        }
930
        foreach ($this->_excludeVars as $exclude) {
931
            if (array_key_exists($exclude, $qs)) {
932
                unset($qs[$exclude]);
933
            }
934
        }
935
        if (count($this->_extraVars)){
936
            $this->_recursive_urldecode($this->_extraVars);
937
            $qs = array_merge($qs, $this->_extraVars);
938
        }
939
        if (count($qs) && get_magic_quotes_gpc()){
940
            $this->_recursive_stripslashes($qs);
941
        }
942
        return $qs;
943
    }
944
 
945
    // }}}
946
    // {{{ _recursive_stripslashes()
947
 
948
    /**
949
     * Helper method
950
     * @param mixed $var
951
     * @access private
952
     */
953
    function _recursive_stripslashes(&$var)
954
    {
955
        if (is_array($var)) {
956
            foreach (array_keys($var) as $k) {
957
                $this->_recursive_stripslashes($var[$k]);
958
            }
959
        } else {
960
            $var = stripslashes($var);
961
        }
962
    }
963
 
964
    // }}}
965
    // {{{ _recursive_urldecode()
966
 
967
    /**
968
     * Helper method
969
     * @param mixed $var
970
     * @access private
971
     */
972
    function _recursive_urldecode(&$var)
973
    {
974
        if (is_array($var)) {
975
            foreach (array_keys($var) as $k) {
976
                $this->_recursive_urldecode($var[$k]);
977
            }
978
        } else {
979
            $trans_tbl = array_flip(get_html_translation_table(HTML_ENTITIES));
980
            $var = strtr($var, $trans_tbl);
981
        }
982
    }
983
 
984
    // }}}
985
    // {{{ _getBackLink()
986
 
987
    /**
988
     * Returns back link
989
     *
990
     * @param $url  URL to use in the link  [deprecated: use the factory instead]
991
     * @param $link HTML to use as the link [deprecated: use the factory instead]
992
     * @return string The link
993
     * @access private
994
     */
995
    function _getBackLink($url='', $link='')
996
    {
997
        //legacy settings... the preferred way to set an option
998
        //now is passing it to the factory
999
        if (!empty($url)) {
1000
            $this->_path = $url;
1001
        }
1002
        if (!empty($link)) {
1003
            $this->_prevImg = $link;
1004
        }
1005
        $back = '';
1006
        if ($this->_currentPage > 1) {
1007
            $this->_linkData[$this->_urlVar] = $this->getPreviousPageID();
1008
            $back = $this->_renderLink($this->_altPrev, $this->_prevImg)
1009
                  . $this->_spacesBefore . $this->_spacesAfter;
1010
        }
1011
        return $back;
1012
    }
1013
 
1014
    // }}}
1015
    // {{{ _getPageLinks()
1016
 
1017
    /**
1018
     * Returns pages link
1019
     *
1020
     * @param $url  URL to use in the link [deprecated: use the factory instead]
1021
     * @return string Links
1022
     * @access private
1023
     */
1024
    function _getPageLinks($url='')
1025
    {
1026
        $msg = '<b>PEAR::Pager Error:</b>'
1027
              .' function "_getPageLinks()" not implemented.';
1028
        return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
1029
    }
1030
 
1031
    // }}}
1032
    // {{{ _getNextLink()
1033
 
1034
    /**
1035
     * Returns next link
1036
     *
1037
     * @param $url  URL to use in the link  [deprecated: use the factory instead]
1038
     * @param $link HTML to use as the link [deprecated: use the factory instead]
1039
     * @return string The link
1040
     * @access private
1041
     */
1042
    function _getNextLink($url='', $link='')
1043
    {
1044
        //legacy settings... the preferred way to set an option
1045
        //now is passing it to the factory
1046
        if (!empty($url)) {
1047
            $this->_path = $url;
1048
        }
1049
        if (!empty($link)) {
1050
            $this->_nextImg = $link;
1051
        }
1052
        $next = '';
1053
        if ($this->_currentPage < $this->_totalPages) {
1054
            $this->_linkData[$this->_urlVar] = $this->getNextPageID();
1055
            $next = $this->_spacesAfter
1056
                  . $this->_renderLink($this->_altNext, $this->_nextImg)
1057
                  . $this->_spacesBefore . $this->_spacesAfter;
1058
        }
1059
        return $next;
1060
    }
1061
 
1062
    // }}}
1063
    // {{{ _getFirstLinkTag()
1064
 
1065
    /**
1066
     * @return string
1067
     * @access private
1068
     */
1069
    function _getFirstLinkTag()
1070
    {
1071
        if ($this->isFirstPage() || ($this->_httpMethod != 'GET')) {
1072
            return '';
1073
        }
1074
        return sprintf('<link rel="first" href="%s" title="%s" />'."\n",
1075
            $this->_getLinkTagUrl(1),
1076
            $this->_firstLinkTitle
1077
        );
1078
    }
1079
 
1080
    // }}}
1081
    // {{{ _getPrevLinkTag()
1082
 
1083
    /**
1084
     * Returns previous link tag
1085
     *
1086
     * @return string the link tag
1087
     * @access private
1088
     */
1089
    function _getPrevLinkTag()
1090
    {
1091
        if ($this->isFirstPage() || ($this->_httpMethod != 'GET')) {
1092
            return '';
1093
        }
1094
        return sprintf('<link rel="previous" href="%s" title="%s" />'."\n",
1095
            $this->_getLinkTagUrl($this->getPreviousPageID()),
1096
            $this->_prevLinkTitle
1097
        );
1098
    }
1099
 
1100
    // }}}
1101
    // {{{ _getNextLinkTag()
1102
 
1103
    /**
1104
     * Returns next link tag
1105
     *
1106
     * @return string the link tag
1107
     * @access private
1108
     */
1109
    function _getNextLinkTag()
1110
    {
1111
        if ($this->isLastPage() || ($this->_httpMethod != 'GET')) {
1112
            return '';
1113
        }
1114
        return sprintf('<link rel="next" href="%s" title="%s" />'."\n",
1115
            $this->_getLinkTagUrl($this->getNextPageID()),
1116
            $this->_nextLinkTitle
1117
        );
1118
    }
1119
 
1120
    // }}}
1121
    // {{{ _getLastLinkTag()
1122
 
1123
    /**
1124
     * @return string the link tag
1125
     * @access private
1126
     */
1127
    function _getLastLinkTag()
1128
    {
1129
        if ($this->isLastPage() || ($this->_httpMethod != 'GET')) {
1130
            return '';
1131
        }
1132
        return sprintf('<link rel="last" href="%s" title="%s" />'."\n",
1133
            $this->_getLinkTagUrl($this->_totalPages),
1134
            $this->_lastLinkTitle
1135
        );
1136
    }
1137
 
1138
    // }}}
1139
    // {{{ _getLinkTagUrl()
1140
 
1141
    /**
1142
     * Helper method
1143
     * @return string the link tag url
1144
     * @access private
1145
     */
1146
    function _getLinkTagUrl($pageID)
1147
    {
1148
        $this->_linkData[$this->_urlVar] = $pageID;
1149
        if ($this->_append) {
1150
            $href = '?' . $this->_http_build_query_wrapper($this->_linkData);
1151
        } else {
1152
            $href = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_fileName);
1153
        }
1154
        return htmlentities($this->_url . $href);
1155
    }
1156
 
1157
    // }}}
1158
    // {{{ getPerPageSelectBox()
1159
 
1160
    /**
1161
     * Returns a string with a XHTML SELECT menu,
1162
     * useful for letting the user choose how many items per page should be
1163
     * displayed. If parameter useSessions is TRUE, this value is stored in
1164
     * a session var. The string isn't echoed right now so you can use it
1165
     * with template engines.
1166
     *
1167
     * @param integer $start
1168
     * @param integer $end
1169
     * @param integer $step
1170
     * @param boolean $showAllData If true, perPage is set equal to totalItems.
1171
     * @param array   (or string $optionText for BC reasons)
1172
     *                - 'optionText': text to show in each option.
1173
     *                  Use '%d' where you want to see the number of pages selected.
1174
     *                - 'attributes': (html attributes) Tag attributes or
1175
     *                  HTML attributes (id="foo" pairs), will be inserted in the
1176
     *                  <select> tag
1177
     * @return string xhtml select box
1178
     * @access public
1179
     */
1180
    function getPerPageSelectBox($start=5, $end=30, $step=5, $showAllData=false, $extraParams=array())
1181
    {
1182
        require_once 'Pager/HtmlWidgets.php';
1183
        $widget =& new Pager_HtmlWidgets($this);
1184
        return $widget->getPerPageSelectBox($start, $end, $step, $showAllData, $extraParams);
1185
    }
1186
 
1187
    // }}}
1188
    // {{{ getPageSelectBox()
1189
 
1190
    /**
1191
     * Returns a string with a XHTML SELECT menu with the page numbers,
1192
     * useful as an alternative to the links
1193
     *
1194
     * @param array   - 'optionText': text to show in each option.
1195
     *                  Use '%d' where you want to see the number of pages selected.
1196
     *                - 'autoSubmit': if TRUE, add some js code to submit the
1197
     *                  form on the onChange event
1198
     * @param string   $extraAttributes (html attributes) Tag attributes or
1199
     *                  HTML attributes (id="foo" pairs), will be inserted in the
1200
     *                  <select> tag
1201
     * @return string xhtml select box
1202
     * @access public
1203
     */
1204
    function getPageSelectBox($params = array(), $extraAttributes = '')
1205
    {
1206
        require_once 'Pager/HtmlWidgets.php';
1207
        $widget =& new Pager_HtmlWidgets($this);
1208
        return $widget->getPageSelectBox($params, $extraAttributes);
1209
    }
1210
 
1211
    // }}}
1212
    // {{{ _printFirstPage()
1213
 
1214
    /**
1215
     * Print [1]
1216
     *
1217
     * @return string String with link to 1st page,
1218
     *                or empty string if this is the 1st page.
1219
     * @access private
1220
     */
1221
    function _printFirstPage()
1222
    {
1223
        if ($this->isFirstPage()) {
1224
            return '';
1225
        }
1226
        $this->_linkData[$this->_urlVar] = 1;
1227
        return $this->_renderLink(
1228
                str_replace('%d', 1, $this->_altFirst),
1229
                $this->_firstPagePre . $this->_firstPageText . $this->_firstPagePost
1230
        ) . $this->_spacesBefore . $this->_spacesAfter;
1231
    }
1232
 
1233
    // }}}
1234
    // {{{ _printLastPage()
1235
 
1236
    /**
1237
     * Print [numPages()]
1238
     *
1239
     * @return string String with link to last page,
1240
     *                or empty string if this is the 1st page.
1241
     * @access private
1242
     */
1243
    function _printLastPage()
1244
    {
1245
        if ($this->isLastPage()) {
1246
            return '';
1247
        }
1248
        $this->_linkData[$this->_urlVar] = $this->_totalPages;
1249
        return $this->_renderLink(
1250
                str_replace('%d', $this->_totalPages, $this->_altLast),
1251
                $this->_lastPagePre . $this->_lastPageText . $this->_lastPagePost
1252
        );
1253
    }
1254
 
1255
    // }}}
1256
    // {{{ _setFirstLastText()
1257
 
1258
    /**
1259
     * sets the private _firstPageText, _lastPageText variables
1260
     * based on whether they were set in the options
1261
     *
1262
     * @access private
1263
     */
1264
    function _setFirstLastText()
1265
    {
1266
        if ($this->_firstPageText == '') {
1267
            $this->_firstPageText = '1';
1268
        }
1269
        if ($this->_lastPageText == '') {
1270
            $this->_lastPageText = $this->_totalPages;
1271
        }
1272
    }
1273
 
1274
    // }}}
1275
    // {{{ _http_build_query_wrapper()
1276
 
1277
    /**
1278
     * This is a slightly modified version of the http_build_query() function;
1279
     * it heavily borrows code from PHP_Compat's http_build_query().
1280
     * The main change is the usage of htmlentities instead of urlencode,
1281
     * since it's too aggressive
1282
     *
1283
     * @author Stephan Schmidt <schst@php.net>
1284
     * @author Aidan Lister <aidan@php.net>
1285
     * @author Lorenzo Alberton <l dot alberton at quipo dot it>
1286
     * @param array $data
1287
     * @return string
1288
     * @access private
1289
     */
1290
    function _http_build_query_wrapper($data)
1291
    {
1292
        $data = (array)$data;
1293
        if (empty($data)) {
1294
            return '';
1295
        }
1296
        $separator = ini_get('arg_separator.output');
1297
        if ($separator == '&amp;') {
1298
            $separator = '&'; //the string is escaped by htmlentities anyway...
1299
        }
1300
        $tmp = array ();
1301
        foreach ($data as $key => $val) {
1302
            if (is_scalar($val)) {
1303
                //array_push($tmp, $key.'='.$val);
1304
                $val = urlencode($val);
1305
                array_push($tmp, $key .'='. str_replace('%2F', '/', $val));
1306
                continue;
1307
            }
1308
            // If the value is an array, recursively parse it
1309
            if (is_array($val)) {
1310
                array_push($tmp, $this->__http_build_query($val, htmlentities($key)));
1311
                continue;
1312
            }
1313
        }
1314
        return implode($separator, $tmp);
1315
    }
1316
 
1317
    // }}}
1318
    // {{{ __http_build_query()
1319
 
1320
    /**
1321
     * Helper function
1322
     * @author Stephan Schmidt <schst@php.net>
1323
     * @author Aidan Lister <aidan@php.net>
1324
     * @access private
1325
     */
1326
    function __http_build_query($array, $name)
1327
    {
1328
        $tmp = array ();
1329
        $separator = ini_get('arg_separator.output');
1330
        if ($separator == '&amp;') {
1331
            $separator = '&'; //the string is escaped by htmlentities anyway...
1332
        }
1333
        foreach ($array as $key => $value) {
1334
            if (is_array($value)) {
1335
                //array_push($tmp, $this->__http_build_query($value, sprintf('%s[%s]', $name, $key)));
1336
                array_push($tmp, $this->__http_build_query($value, $name.'%5B'.$key.'%5D'));
1337
            } elseif (is_scalar($value)) {
1338
                //array_push($tmp, sprintf('%s[%s]=%s', $name, htmlentities($key), htmlentities($value)));
1339
                array_push($tmp, $name.'%5B'.htmlentities($key).'%5D='.htmlentities($value));
1340
            } elseif (is_object($value)) {
1341
                //array_push($tmp, $this->__http_build_query(get_object_vars($value), sprintf('%s[%s]', $name, $key)));
1342
                array_push($tmp, $this->__http_build_query(get_object_vars($value), $name.'%5B'.$key.'%5D'));
1343
            }
1344
        }
1345
        return implode($separator, $tmp);
1346
    }
1347
 
1348
    // }}}
1349
    // {{{ _isEncoded()
1350
 
1351
    /**
1352
     * Helper function
1353
     * Check if a string is an encoded multibyte string
1354
     * @param string $string
1355
     * @return boolean
1356
     * @access private
1357
     */
1358
 
1359
    function _isEncoded($string)
1360
    {
1361
        $hexchar = '&#[\dA-Fx]{2,};';
1362
        return preg_match("/^(\s|($hexchar))*$/Uims", $string) ? true : false;
1363
    }
1364
 
1365
    // }}}
1366
    // {{{ raiseError()
1367
 
1368
    /**
1369
     * conditionally includes PEAR base class and raise an error
1370
     *
1371
     * @param string $msg  Error message
1372
     * @param int    $code Error code
1373
     * @access private
1374
     */
1375
    function raiseError($msg, $code)
1376
    {
1377
        include_once 'PEAR.php';
1378
        if (empty($this->_pearErrorMode)) {
1379
            $this->_pearErrorMode = PEAR_ERROR_RETURN;
1380
        }
1381
        return PEAR::raiseError($msg, $code, $this->_pearErrorMode);
1382
    }
1383
 
1384
    // }}}
1385
    // {{{ setOptions()
1386
 
1387
    /**
1388
     * Set and sanitize options
1389
     *
1390
     * @param mixed $options    An associative array of option names and
1391
     *                          their values.
1392
     * @return integer error code (PAGER_OK on success)
1393
     * @access public
1394
     */
1395
    function setOptions($options)
1396
    {
1397
        foreach ($options as $key => $value) {
1398
            if (in_array($key, $this->_allowed_options) && (!is_null($value))) {
1399
                $this->{'_' . $key} = $value;
1400
            }
1401
        }
1402
 
1403
        //autodetect http method
1404
        if (!isset($options['httpMethod'])
1405
            && !isset($_GET[$this->_urlVar])
1406
            && isset($_POST[$this->_urlVar])
1407
        ) {
1408
            $this->_httpMethod = 'POST';
1409
        } else {
1410
            $this->_httpMethod = strtoupper($this->_httpMethod);
1411
        }
1412
 
1413
        $this->_fileName = ltrim($this->_fileName, '/');  //strip leading slash
1414
        $this->_path     = rtrim($this->_path, '/');      //strip trailing slash
1415
 
1416
        if ($this->_append) {
1417
            if ($this->_fixFileName) {
1418
                $this->_fileName = CURRENT_FILENAME; //avoid possible user error;
1419
            }
1420
            $this->_url = $this->_path.'/'.$this->_fileName;
1421
        } else {
1422
            $this->_url = $this->_path;
1423
            if (strncasecmp($this->_fileName, 'javascript', 10) != 0) {
1424
                $this->_url .= '/';
1425
            }
1426
            if (strpos($this->_fileName, '%d') === false) {
1427
                trigger_error($this->errorMessage(ERROR_PAGER_INVALID_USAGE), E_USER_WARNING);
1428
            }
1429
        }
1430
 
1431
        $this->_classString = '';
1432
        if (strlen($this->_linkClass)) {
1433
            $this->_classString = 'class="'.$this->_linkClass.'"';
1434
        }
1435
 
1436
        if (strlen($this->_curPageLinkClassName)) {
1437
            $this->_curPageSpanPre  = '<span class="'.$this->_curPageLinkClassName.'">';
1438
            $this->_curPageSpanPost = '</span>';
1439
        }
1440
 
1441
        $this->_perPage = max($this->_perPage, 1); //avoid possible user errors
1442
 
1443
        if ($this->_useSessions && !isset($_SESSION)) {
1444
            session_start();
1445
        }
1446
        if (!empty($_REQUEST[$this->_sessionVar])) {
1447
            $this->_perPage = max(1, (int)$_REQUEST[$this->_sessionVar]);
1448
            if ($this->_useSessions) {
1449
                $_SESSION[$this->_sessionVar] = $this->_perPage;
1450
            }
1451
        }
1452
 
1453
        if (!empty($_SESSION[$this->_sessionVar])) {
1454
             $this->_perPage = $_SESSION[$this->_sessionVar];
1455
        }
1456
 
1457
        if ($this->_closeSession) {
1458
            session_write_close();
1459
        }
1460
 
1461
        $this->_spacesBefore = str_repeat('&nbsp;', $this->_spacesBeforeSeparator);
1462
        $this->_spacesAfter  = str_repeat('&nbsp;', $this->_spacesAfterSeparator);
1463
 
1464
        if (isset($_REQUEST[$this->_urlVar]) && empty($options['currentPage'])) {
1465
            $this->_currentPage = (int)$_REQUEST[$this->_urlVar];
1466
        }
1467
        $this->_currentPage = max($this->_currentPage, 1);
1468
        $this->_linkData = $this->_getLinksData();
1469
 
1470
        return PAGER_OK;
1471
    }
1472
 
1473
    // }}}
1474
    // {{{ getOption()
1475
 
1476
    /**
1477
     * Return the current value of a given option
1478
     *
1479
     * @param string option name
1480
     * @return mixed option value
1481
     */
1482
    function getOption($name)
1483
    {
1484
        if (!in_array($name, $this->_allowed_options)) {
1485
            $msg = '<b>PEAR::Pager Error:</b>'
1486
                  .' invalid option: '.$name;
1487
            return $this->raiseError($msg, ERROR_PAGER_INVALID);
1488
        }
1489
        return $this->{'_' . $name};
1490
    }
1491
 
1492
    // }}}
1493
    // {{{ getOptions()
1494
 
1495
    /**
1496
     * Return an array with all the current pager options
1497
     *
1498
     * @return array list of all the pager options
1499
     */
1500
    function getOptions()
1501
    {
1502
        $options = array();
1503
        foreach ($this->_allowed_options as $option) {
1504
            $options[$option] = $this->{'_' . $option};
1505
        }
1506
        return $options;
1507
    }
1508
 
1509
    // }}}
1510
    // {{{ errorMessage()
1511
 
1512
    /**
1513
     * Return a textual error message for a PAGER error code
1514
     *
1515
     * @param   int     $code error code
1516
     * @return  string  error message
1517
     * @access public
1518
     */
1519
    function errorMessage($code)
1520
    {
1521
        static $errorMessages;
1522
        if (!isset($errorMessages)) {
1523
            $errorMessages = array(
1524
                ERROR_PAGER                     => 'unknown error',
1525
                ERROR_PAGER_INVALID             => 'invalid',
1526
                ERROR_PAGER_INVALID_PLACEHOLDER => 'invalid format - use "%d" as placeholder.',
1527
                ERROR_PAGER_INVALID_USAGE       => 'if $options[\'append\'] is set to false, '
1528
                                                  .' $options[\'fileName\'] MUST contain the "%d" placeholder.',
1529
                ERROR_PAGER_NOT_IMPLEMENTED     => 'not implemented'
1530
            );
1531
        }
1532
 
1533
        return '<b>PEAR::Pager error:</b> '. (isset($errorMessages[$code]) ?
1534
            $errorMessages[$code] : $errorMessages[ERROR_PAGER]);
1535
    }
1536
 
1537
    // }}}
1538
}
1539
?>