cgm225 Posted August 21, 2008 Share Posted August 21, 2008 I am new to OOP, and created a general pagination class to gather, calculate, etc, all the data I need to generate for several applications (blog, gallery, etc). It is working fine, but I wanted to get some feedback. What would you do differently? What could I improve on? Etc. Thank you all in advance! <?php class Pagination { //Declaring variables protected $paginationFor; protected $totalItems; protected $totalPages; protected $page; protected $defaultDisplayNumber; protected $numberDisplayed; public function __construct($paginationFor) { //Sets the paginationFor variable $this->paginationFor = $paginationFor; } public function setTotalItems($totalItems) { $this->totalItems = $totalItems; } public function getTotalItems() { return $this->totalItems; } public function setCurrentPageNumber($currentPage) { //Sets total number of pages (required for following line of code) $this->setTotalPages(); /* Resets page number to total number of pages if current page value is * greater than total pages */ $this->page = ($currentPage > $this->getTotalPages()) ? $this->getTotalPages() : $currentPage; /* Resets position values for the first and last items on a particular * page in case the page number value was changed by the above line */ $this->setFirstLastPosition(); } public function getCurrentPageNumber() { return $this->page; } public function setDefaultDisplayNumber($defaultDisplayNumber) { //Creates numberDisplayed array session variable if not already present if (!isset($_SESSION['numberDisplayed'])) { $_SESSION['numberDisplayed'] = array(); } /* If user has provided a new number to display from an HTML form, that * value will be added/updated in the numberDisplayed array session * variable. If no new value has been provided, then, if the key is * present, the existing session variable key/value pair will be used, * or a new pair will be created based on a provided default value */ if (isset($_POST['numberDisplayed'])) { $this->setNumberDisplayed($this->paginationFor, $_POST['numberDisplayed']); $this->setCurrentPageNumber($this->page); //Resets current page } elseif (!$this->getNumberDisplayed('notes')) { $this->setNumberDisplayed($this->paginationFor, $defaultDisplayNumber); } } public function setNumberDisplayed($paginationFor, $numberDisplayed) { //Checks that the $numberDisplayed variable only contains numbers $regex = '/[^0-9]++/'; //Only numbers allowed $this->numberDisplayed = preg_replace($regex, '', $numberDisplayed); //Adds key/value pair to session array $_SESSION['numberDisplayed'][$paginationFor] = $this->numberDisplayed; } public function getNumberDisplayed() { //Either returns the key's value or returns false if (empty($_SESSION['numberDisplayed'][$this->paginationFor])) { return false; } else { return $_SESSION['numberDisplayed'][$this->paginationFor]; } } public function setTotalPages() { /* Calculates total number of pages based on total items and number of * items displayed per page */ $this->totalPages = ceil($this->getTotalItems() / $this->getNumberDisplayed()); } public function getTotalPages() { return $this->totalPages; } public function setFirstLastPosition() { /* Calculates the numerical position of the first and last items on any * particular page */ $this->firstPageItemPosition = ($this->getCurrentPageNumber() * $this->getNumberDisplayed()) - $this->getNumberDisplayed(); $this->lastPageItemPosition = $this->firstPageItemPosition + $this->getNumberDisplayed(); } public function getFirstPageItemPosition() { return $this->firstPageItemPosition; } public function getLastPageItemPosition() { return $this->lastPageItemPosition; } } ?> Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/ Share on other sites More sharing options...
cgm225 Posted August 21, 2008 Author Share Posted August 21, 2008 bump Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-621948 Share on other sites More sharing options...
cgm225 Posted August 22, 2008 Author Share Posted August 22, 2008 bump Below is an updated version of the pagination class and an example of its implementation... Instantiation of pagination class in a controller helper class... class NotesActions extends ActionController { ...SNIP... public function doNotes() { ...SNIP... /* Instantiates new Notes class, then gathers all entries from the * database, places that data into an array, and then passes the object * to the registry */ $notes = new Notes($this->mysqli); $notes->findEntries(); $this->registry->set('notesObject', $notes); /* Instantiates new Pagination class, passes all the required data for * generating pagination, and then passes the object to the registry */ $pagination = new Pagination('notes'); $pagination->setTotalItems($notes->getDataCount()); $pagination->setDefaultDisplayNumber(4); $pagination->setCurrentPageNumber($this->page); $this->registry->set('paginationObject', $pagination); } } Example of implementation of the pagination object... <?php //Sets note and pagination objects from the registry $notes = $this->registry->get('notesObject'); $pagination = $this->registry->get('paginationObject'); //Ouputs HTML header and openning div echo "\t\t<div class=\"notesContainer\">\n"; echo "\t\t\t<h2 class=\"notes\">Notes:: More from me..</h2>\n"; echo "\t\t\tI use this area of my site to share random thoughts, experiences, etc.\n\t\t\t<br />\n\n"; //Ouputs navigation div echo "\t\t\t<div class=\"notesNavigationContainer\">\n"; echo "\t\t\t\t<div class=\"notesNavigationRight\">\n"; //If there are more pages beyond the current one, a "Next" link is provided if ($pagination->getTotalItems() > $pagination->getLastPageItemPosition()) { echo "\t\t\t\t\t<a href=\"http://" . $_SERVER['SERVER_NAME'] . '/notes/' . ($pagination->getCurrentPageNumber() + 1) . "\">Next</a>\n"; $addNextLink = true; } else { $addNextLink = false; } echo "\t\t\t\t</div>\n"; echo "\t\t\t\t<div class=\"notesNavigationLeft\">\n"; //If the user is beyond the first page, a "Previous" link is provided if ($pagination->getCurrentPageNumber() > 1) { echo "\t\t\t\t\t<a href=\"http://" . $_SERVER['SERVER_NAME'] . '/notes/' . ($pagination->getCurrentPageNumber() - 1) . "\">Previous</a>\n"; } else { echo "\t\t\t\t\t<span style=\"color:#ffffff;\">_</span>\n"; } echo "\t\t\t\t</div>\n"; echo "\t\t\t\t<div class=\"notesNavigationCenter\">\n\t\t\t\t\t"; //Calculating the starting pagination number $startingPaginationNumber = $pagination->getCurrentPageNumber() - 2; //If the user is on page four or beyond, a link to page one is provided if ($startingPaginationNumber <= 1) { $startingPaginationNumber = 1; } else { echo '<a href="http://' . $_SERVER['SERVER_NAME'] . '/notes/1" title="First Page">«</a> '; } //Calculating the ending pagination number $endingPaginationNumber = $pagination->getCurrentPageNumber() + 2; if ($endingPaginationNumber > $pagination->getTotalPages()) { $endingPaginationNumber = $pagination->getTotalPages(); } /* Navigation via a numerical index will be provided with links directly to the * two most adjacent pages on either side of the current page number, as well as * the additional links to the starting and ending pages, all such that the * output will resemble "<< 3 4 5 6 7 >>" where 5 is the current page */ for ($i = $startingPaginationNumber; $i <= $endingPaginationNumber; $i++) { if ($i == $pagination->getCurrentPageNumber()) { echo '<span style="font-weight:800;text-decoration:underline;">' . $i . '</span> '; } else { echo '<a href="http://' . $_SERVER['SERVER_NAME'] . "/notes/$i\">$i</a> "; } } /* If the user is three or more pages from the end, a link to the last page is * provided */ if ($endingPaginationNumber < $pagination->getTotalPages()) { echo '<a href="http://' . $_SERVER['SERVER_NAME'] . '/notes/' . $pagination->getTotalPages() . '" title="Last Page">»</a>'; } echo "\n\t\t\t\t</div>\n"; echo "\t\t\t</div>\n\n"; //Outputting entry data $noteData = $notes->getSlicedData($pagination->getFirstPageItemPosition(), $pagination->getDisplayNumber()); foreach($noteData as $note) { echo "\t\t\t<div class=\"noteContainer\">\n"; echo "\t\t\t\t<h2 class=\"notes\">" . $note['title'] . "</h2>\n"; echo "\t\t\t\t" . $note['date'] . " | <a href=\"http://" . $_SERVER['SERVER_NAME'] . '/notes/entry/' . $note['id'] . "\">Permalink</a>\n"; echo "\t\t\t\t<div class=\"noteBody\">\n\t\t\t\t\t" . stripslashes(str_replace("\n" , "\t\t\t\t\t<br />\n\t\t\t\t\t", $note['note'])) . "\n\t\t\t\t</div>"; echo "\n\t\t\t</div>\n"; } echo "\t\t</div>"; ?> <form method="post" action="<?php $_SERVER['PHP_SELF'] ?>" class="notesNumberDisplayed"> <div class="notesNumberDisplayed"> Display <select name="displayNumber" size="1" class="notesNumberDisplayed" onchange="form.submit()"> <option value="2" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 2) {echo "selected=\"selected\"";} ?>>2</option> <option value="4" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 4) {echo "selected=\"selected\"";} ?>>4</option> <option value="6" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 6) {echo "selected=\"selected\"";} ?>>6</option> <option value="8" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == <!-- s8) --><img src=\"{SMILIES_PATH}/icon_cool.gif\" alt=\"\" title=\"Cool\" /><!-- s8) --> {echo "selected=\"selected\"";} ?>>8</option> <option value="10" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 10) {echo "selected=\"selected\"";} ?>>10</option> <option value="20" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 20) {echo "selected=\"selected\"";} ?>>20</option> <option value="40" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 40) {echo "selected=\"selected\"";} ?>>40</option> </select> <?php if ($addNextLink) { echo "\n\t\t\t<a href=\"http://" . $_SERVER['SERVER_NAME'] . '/notes/' . ($pagination->getCurrentPageNumber() + 1) . "\">Next</a>\n"; } ?> <noscript><p class="no_style">JavaScript required to change the display number!</p></noscript> </div> </form> Pagination class (updated) <?php class Pagination { //Declaring variables protected $paginationFor; protected $totalItems; protected $totalPages; protected $currentPage; protected $defaultDisplayNumber; protected $displayNumber; public function __construct($paginationFor) { //Sets the paginationFor variable $this->paginationFor = $paginationFor; } public function setTotalItems($totalItems) { $this->totalItems = $totalItems; } public function getTotalItems() { return $this->totalItems; } public function setCurrentPageNumber($page) { //Sets total number of pages (required for following line of code) $this->setTotalPages(); /* Resets page number to total number of pages if current page value is * greater than total pages */ $this->currentPage = ($page > $this->getTotalPages()) ? $this->getTotalPages() : $page; /* Resets position values for the first and last items on a particular * page in case the page number value was changed by the above line */ $this->setFirstLastPosition(); } public function getCurrentPageNumber() { return $this->currentPage; } public function setDefaultDisplayNumber($defaultDisplayNumber) { //Sets default number of items displayed $this->defaultDisplayNumber = $defaultDisplayNumber; /* Creates displayNumber array session variable, if not already * present, containing the default number of items to display */ if (empty($_SESSION['displayNumber'][$this->paginationFor])) { $_SESSION['displayNumber'][$this->paginationFor] = $this->defaultDisplayNumber; } /* If user has provided a new number to display from an HTML form, that * value will be added/updated in the displayNumber array session * variable, followed by an update of the current page number. */ if (isset($_POST['displayNumber'])) { $this->setDisplayNumber($_POST['displayNumber']); $this->setCurrentPageNumber($this->currentPage); } } public function setDisplayNumber($displayNumber) { //Checks that the $displayNumber variable only contains numbers $regex = '/[^0-9]++/'; //Only numbers allowed $this->displayNumber = preg_replace($regex, '', $displayNumber); //Adds key/value pair to session array $_SESSION['displayNumber'][$this->paginationFor] = $this->displayNumber; } public function getDisplayNumber() { //Either returns the key's value or returns false if (empty($_SESSION['displayNumber'][$this->paginationFor])) { return false; } else { return $_SESSION['displayNumber'][$this->paginationFor]; } } public function setTotalPages() { /* Calculates total number of pages based on total items and number of * items displayed per page */ $this->totalPages = ceil($this->getTotalItems() / $this->getDisplayNumber()); } public function getTotalPages() { return $this->totalPages; } public function setFirstLastPosition() { /* Calculates the numerical position of the first and last items on any * particular page */ $this->firstPageItemPosition = ($this->getCurrentPageNumber() * $this->getDisplayNumber()) - $this->getDisplayNumber(); $this->lastPageItemPosition = $this->firstPageItemPosition + $this->getDisplayNumber(); } public function getFirstPageItemPosition() { return $this->firstPageItemPosition; } public function getLastPageItemPosition() { return $this->lastPageItemPosition; } } ?> Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-622661 Share on other sites More sharing options...
darkfreaks Posted August 22, 2008 Share Posted August 22, 2008 just a word of caution make sure you filter for Cross site Scripting i have seen pagination Vulnerable to this Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-622672 Share on other sites More sharing options...
cgm225 Posted August 22, 2008 Author Share Posted August 22, 2008 The only data I get from the user, in this case, is the (1) page number or (2) user selected number of items to display per page, both of which I filter/validate as follows... //Sets page variable $regex = '/[^0-9]++/'; //Only numbers allowed $this->page = isset($_GET['page']) ? preg_replace($regex, '', $_GET['page']) : 1; ...SNIP... //Checks that the $displayNumber variable only contains numbers $regex = '/[^0-9]++/'; //Only numbers allowed $this->displayNumber = preg_replace($regex, '', $displayNumber); Do you think that is an ok way to protect against XSS attacks? Also, any other feedback on the class or implementation? Regardless, thanks again! Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-622687 Share on other sites More sharing options...
darkfreaks Posted August 22, 2008 Share Posted August 22, 2008 if you have something like &page= that will stop from injecting words into it. strip_tags is a better way Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-622707 Share on other sites More sharing options...
corbin Posted August 22, 2008 Share Posted August 22, 2008 When even I'm expecting integers, I usually just type cast. <?php $number = (isset($_GET['number'])) ? (int) $_GT['number'] : 0; //you might actually want to put a conditional in the if block, but since the default is 0 anyway, and type casting returns a value of 0 if it's not castable (or it's 0), then it's the same in this situation. Or I use http://php.net/ctype_number In my opinion, you shouldn't need to be operating on the values outside of the class. For example: $startingPaginationNumber = $pagination->getCurrentPageNumber() - 2; I personally would try to avoid things like that, but I guess which ever way works. Wow I'm rambling and this post was entirely useless. Oh well. Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-622708 Share on other sites More sharing options...
cgm225 Posted August 22, 2008 Author Share Posted August 22, 2008 I wanted a lot of flexibility with the class, so I that is why there are not specific methods to generate starting and ending pagination numbers. For example, in this case, I wanted the output to look like: << 3 4 5 6 7 >> (with 5 being the current page number) Therefore, I am able to get that range of numbers based off the current page number +/- 2. However, in another case I might want to display all the page numbers like so... 1 2 3 4 5 6 7 8 (with 5 being the current page number) ...which I would do based on the current page number and total number of pages. Does that make sense? Or would you still use a method to achieve this? If so, what would it look like? Also, thank you for all the other feedback, I am working on integrating it now. Anything else I can work on? Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-622967 Share on other sites More sharing options...
corbin Posted August 22, 2008 Share Posted August 22, 2008 Oh ignore everything I said. I thought you were processing the numbers to use in later method calls. Didn't see that you were using them for outputting HTML. Guess I should read the code better next time x.x. Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-623336 Share on other sites More sharing options...
cgm225 Posted August 26, 2008 Author Share Posted August 26, 2008 Any other feedback about the class? Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-625556 Share on other sites More sharing options...
darkfreaks Posted August 30, 2008 Share Posted August 30, 2008 i ran your pagnation script through pixybox i got this Warning: Invalid path to PHP binary in config file: /opt/lampp/bin/php Syntax error line: 6 Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-629890 Share on other sites More sharing options...
jordanwb Posted August 31, 2008 Share Posted August 31, 2008 <?php $number = (isset($_GET['number'])) ? (int) $_GT['number'] : 0; //you might actually want to put a conditional in the if block, but since the default is 0 anyway, and type casting returns a value of 0 if it's not castable (or it's 0), then it's the same in this situation. Actually you code do this: $number = (int)$_GET['number']; And it would do the same thing. However if $_GET['number'] has a value of say "39hv40", $number will be 3940 Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-630443 Share on other sites More sharing options...
corbin Posted September 3, 2008 Share Posted September 3, 2008 That would also throw a notice if $_GET['number'] isn't set, hence the isset(). Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-632372 Share on other sites More sharing options...
jordanwb Posted September 3, 2008 Share Posted September 3, 2008 That would also throw a notice if $_GET['number'] isn't set, hence the isset(). It doesn't do that on my scripts. Is it because I don't set up error reporting to E_ALL? Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-632428 Share on other sites More sharing options...
corbin Posted September 3, 2008 Share Posted September 3, 2008 Any error reporting level not including E_NOTICE will not throw notices ;p. Edit: Bleh.... Removed something about type casting. Thoughts strings were always casted to 0 if not entirely numeric ;p. Apparently strings starting with numbers retain numbers. Link to comment https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/#findComment-632435 Share on other sites More sharing options...
Recommended Posts