Постраничная навигация на PHP
Часто при разработке и выводе контента появляется необходимость использования постраничной навигации. Кто-то скорее всего использует готовые решения от своего фреймворка. Кто-то, возможно, не заморачивается и лупит страницы просто циклом. У кого-то есть свои наработки в этом направлении. Вот я как раз и хочу поделиться своим решением данной задачи.
Существует множество вариаций расположения и отображения кнопок, лично я пришел к следующему решению, которое по моему мнению наиболее наглядно и удобно. Подходит как для 5 страниц так и для 5000.
Пример HTML кода
Не буду ходить вокруг да около, сразу приложу пример сформированного скриптом html кода:
Назад 1 . 4 5 6 7 8 9 10 . 17 Вперед
Логика построения
По настройкам параметров я остановлюсь чуть позже после приведения кода, сейчас опишу логику формирования самих номеров.
С кнопками «Назад» и «Вперед» думаю все понятно, к тому же их можно просто отключить, поэтому на них не буду заострять внимания.
Первый и последний номер страницы отображается всегда, своего рода кнопки «В начало» и «В конец».
Середина формируется уже по простому алгоритму. Отображается просматриваемая страница и по N страниц по бокам. На примере отображается по N=3 страницы. В принципе все просто и понятно, но особая хитрость используется при приближении к краям. Опишу на примерах:
Страница 1-3 (где 3 = N)
Отображаются первые N*2 страниц и последняя.
Отображается первая и дальше сформированная строка от 4-3=1 до 4+3=7. Первая страница зарезервирована поэтому формируются номера от 2 до 7.
Пожалуй во всех навигациях что я видел (включая хабр) строка была бы сформирована с пропуском, т.е. 1… 3 4 5 6 7 8 9… 17
Но ведь это не логично, отображать многоточие вместо одного числа. При построении второго многоточия выполняется аналогичная проверка.
Формирование окончания аналогично началу
Редиректы
Помимо этого из особенностей хочу выделить еще 2 момента, это проверка существования страницы и редирект на «правильный» адрес. Т.е. к примеру, тут же на хабре первая страница может быть доступна сразу по 2м адресам:
habrahabr.ru/sandbox/page1
habrahabr.ru/sandbox
Скрипт не дает зайти на адрес page/1/ и выполняет редирект на «чистый» адрес
Так же если указан слишком большой номер страницы будет выполнен редирект на последнюю существующую. К примеру были удалены материалы или изменено количество записей на страницу. Не могу правда однозначно сказать полезно ли это будет с точки зрения СЕО, но для пользователей мне кажется так будет удобнее.
PHP код и его использование
class PaginateNavigationBuilder < /** * Чистый URL по умолчанию * В адресе может быть указано место для размещения блока с номером страницы, тег * Пример: * /some_url.html * В итоге адрес будет: * /some_url.html * /some_url/page_2.html * Если тег не указан, то страницы будут дописываться в конец адреса * * @var string */ private $baseUrl = '/'; /** * Шаблон ссылки навигации * * @var string */ public $tpl = 'page//'; /** * Обертка кнопок * * @var string */ public $wrap = "baseUrl = $baseUrl; > /** * Строим навигации и формируем шаблон * * @param integer $limit количество записей на 1 страницу * @param integer $count_all общее количество всех записей * @param integer $currentPage номер просматриваемой страницы * @return mixed Сформированный шаблон навигации готовый к выводу */ public function build($limit, $count_all, $currentPage = 1) < if( $limit < 1 OR $count_all $count_pages ) < header( "HTTP/1.0 301 Moved Permanently" ); header( "Location: " . $this->getUrl( $count_pages ) ); die( "Redirect" ); > if( $currentPage == 1 AND $_SERVER['REQUEST_URI'] != $this->getUrl( $currentPage ) ) < header( "HTTP/1.0 301 Moved Permanently" ); header( "Location: " . $this->getUrl( $currentPage ) ); die( "Redirect" ); > $this->currentPage = intval( $currentPage ); if( $this->currentPage < 1 ) $this->currentPage = 1; $shift_start = max( $this->currentPage - $this->spread, 2 ); $shift_end = min( $this->currentPage + $this->spread, $count_pages-1 ); if( $shift_end < $this->spread*2 ) < $shift_end = min( $this->spread*2, $count_pages-1 ); > if( $shift_end == $count_pages - 1 AND $shift_start > 3 ) < $shift_start = max( 3, min( $count_pages - $this->spread*2 + 1, $shift_start ) ); > $list = $this->getItem( 1 ); if ($shift_start == 3) < $list .= $this->getItem( 2 ); > elseif ( $shift_start > 3 ) < $list .= $this->separator; > for( $i = $shift_start; $i getItem( $i ); > $last_page = $count_pages - 1; if( $shift_end == $last_page-1 )< $list .= $this->getItem( $last_page ); > elseif( $shift_end < $last_page ) < $list .= $this->separator; > $list .= $this->getItem( $count_pages ); if( $this->nextPrev ) < $list = $this->getItem( $this->currentPage > 1 ? $this->currentPage - 1 : 1, $this->prevTitle, true ) . $list . $this->getItem( $this->currentPage < $count_pages ? $this->currentPage + 1 : $count_pages, $this->nextTitle, true ); > return str_replace( "", $list, $this->wrap ); > /** * Формирование адреса * @param int $page_num номер страницы * @return string сформированный адрес */ private function getUrl( $page_num = 0 ) < $page = $page_num >1 ? str_replace( '', $page_num, $this->tpl ) : ''; if( stripos( $this->baseUrl, '' ) !== false )< return str_replace( '', $page, $this->baseUrl ); > else < return $this->baseUrl . $page; > > /** * Формирование кнопки/ссылки * @param int $page_num номер страницы * @param string $page_name если указано, будет выводиться текст вместо номера страницы * @param bool $noclass * @return - span блок с активной страницей или ссылку. */ private function getItem( $page_num, $page_name = '', $noclass = false ) < $page_name = $page_name ?: $page_num; $className = $noclass ? '' : $this->activeClass; if( $this->currentPage == $page_num ) < return "else < return "getUrl($page_num)>\"> "; > > >
Для наглядности, приведу пример построения навигации песочницы:
habrahabr.ru/sandbox/page12
$navi = new PaginateNavigationBuilder( "/sandbox/" ); $navi->tpl = "page/"; $navi->spread = 4; $template = $navi->build( $limit, $count_all, $page_num );
Или же если номер страницы прописан внутри URL:
example.com/some_url/1.html — первая страница
example.com/some_url/1-page2.html — вторая страница
$navi = new PaginateNavigationBuilder( "/some_url/1.html" ); $navi->tpl = "-page"; $template = $navi->build( $limit, $count_all, $page_num );
$limit — количество записей на страницу
$count_all — общее количество записей
$page_num — номер страницы на которой находится пользователь
На этом, пожалуй, всё. Буду рад любой конструктивной критике.
PS. Огромное спасибо всем отписавшимся, особенно тем кто ругает (и правильно делает).
Обещаю со всем ознакомиться, принять во внимание и исправиться.
Функции постраничного вывода в PHP
Здравствуйте уважаемые читатели, сегодня хотелось бы обсудит проблему постраничного вывода в PHP и привести возможные пути решения. В этой статье я приведу довольно уникальную функцию с точки зрения её возможностей.
Часто при создании динамических сайтов (отсутствуют страницы как таковые) на базе данных или на файлах возникает вопрос о постраничном выводе информации будь — то статьи, архив новостей или что нибудь другое содержащие довльно большое количество страниц.
Поэтому мы начинаем (если сами не сообразим или кто-нибудь не поможет) рыскать по Интернету в поисках нужного кода, но приличный постраничный вывод найти тяжело. Так что попробуем сделать сегодня что нибудь хорошее, а главное рабочее.
Ниже будет приведён код простейшей функции постраничного вывода, эту функцию можно использовать на небольших сайтах. Все комментарии будут приведены в самой функции, я думаю Вы разберётесь.
/*Простейшая функция постраничного вывода, назавём её просто PagePrint*/ function PagePrint($start, $count) < $HrefPage='';//----Создаём переменную которая будет содержать постраничный вывод $number=10;//----Количество записей на странице /*Подсчитываем количество страниц, где $count - общее количество записей, $number - количество записей на странице*/ $CountPage=(int)(($count+$number-1)/$number); /*Перебираем в цикле все страницы*/ for($link=1; $link ".$link."";//--Формируем ссылки endfor; return $HrefPage; >
Вы видите, что функция имеет два входных параметра $start — точка выборки из базы данных и $count — количество данных, в файле либо в базе данных. Эта функция самая простая, так что на неё мало надежды при использовании на крупных сайтах где много информации.
Рассмотрим более сложную функцию, но имеющую больше функциональности.
function PagePrint($variable) < global $beginPage, $endPage;//------Объявляем глобальные переменные, отвечающие за ссылку на первую и последнюю страницу $href='';//-----Перемменная содержащая в себе постраничный вывод $separator=' ';//-----Переменная задающая разделитель между ссылками, по умолчанию пробел $style='style="text-decoration:none" style="color:orange" style="font-weight:bold"';//-------Задаёт стиль текущей страницы $stylePage='style="text-decoration:none" style="color:blue" style="font-weight:bold"';//------Задаёт стиль ссылки на первую и последнюю страницу if(is_array($variable))://------Проверяем тип array #Перебираем массив и присваиваем $number - количество записей, $start - точка извлечения, $pageCount - количество записей, $andere - другие свойства ссылки, $class - стиль для ссылок, $showLink - количество ссылок на странице list($number, $start, $pageCount, $andere, $class, $showLink)=$variable; #Обрабатывам $start if(empty($start) && !is_int($start) && !is_numeric($start)) $start=0; else $start=$start; #Обрабатываем $number if(empty($number) && !is_int($number) && !is_numeric($number)) $number=10; else $number=$number; $page=(($start/10)+1);//-------Рассчитывавем номер страницы $count=ceil($pageCount/$number);//------Количество страниц #Вывод сслыки на первую и последнюю страницы if($count!==1) : $beginPage="перв";//--------Первая страница $endPage="посл";//-----Последняя страница else: FALSE; endif; if($pageCount==10): return False; else: #Постраничный вывод $begin=$page - intval($showLink/2);//------Определяет номер страницы с которой выводить for($j=0; $j$count) break;//-----Защита если количество $i>возможных записей if($i==$page) $href=$href." ".$i."";//------Вывод текущей страницы else $href=$href." ".$i." ";//------Вывод следующих страниц endfor; return $href; endif; endif; >
Входным параметром функции является массив из шести элементов:
$number — количество отображаемых сообщений на странице
$start — точка извлечения из базы данных, т.е номер сообщения с которого начинается зивлечение данных
$pageCount — общее количество записей, т.е сколько всего содержит база записей
$andere — другие параметры ссылки, будь то новые переменные или что-либо ещё
$class — данный параметр задаёт внешний вид ссылок, т.е ссылки на страницы
$showLink — количество ссылок на странице
Первый параметр может быть передан через метод @$_GET[‘number’], только в том случае, если Вы захотите чтобы пользователь мог изменять количество сообщений на странице.
Второй параметр обязательно передаётся в массив методом @$_GET[‘start’], так как параметр $start всё время меняется когда пользователь кликает по ссылке на страницу.
Если, Вы вдруг не захотите, передавать первый, третий, четвёртый, пятый элемент массива вместо них необходимо передать пустоту — », без пробела между кавычками.
Как Вы можете видеть функция сильно расширяет возможности при создании постраничного вывода. Теперь Вы можете разместить свой постраничный вывод на маленьком участке страницы, регулируя количество отображаемых ссылок параметром $showLink. Всё это удобно при создании галлерей, поиска по каталогу сайта или чего-нибудь ещё.
Ниже будут приведены примеры вызова функции:
PagePrint(», @$_GET[‘start’], 90, », », 10) — Всего записей в базе 90, постраничный вывод будет отображать по десять ссылок
PagePrint(@$_GET[‘number’], @$_GET[‘start’], 90, », », 10) — Всего записей в базе 90, постраничный вывод будет отображать по десять ссылок и есть возможность изменять количество отображаемых записей на странице
PagePrint(@$_GET[‘number’], @$_GET[‘start’], 90, ‘&category=1’, », 10) — Всего записей в базе 90, постраничный вывод будет отображать по десять ссылок, есть возможность изменять количество отображаемых записей на странице и ссылка передаёт дополнительную переменную category со значением 1
PagePrint(@$_GET[‘number’], @$_GET[‘start’], 90, ‘&category=1’, ‘style=»color:black»‘, 10) — Всего записей в базе 90, постраничный вывод будет отображать по десять ссылок, есть возможность изменять количество отображаемых записей на странице, ссылка передаёт дополнительную переменную category со значением 1 и ссылки на странице будут чёрного цвета.
Надеюсь приведённые ниже объяснения и комментарии внутри функции помогут разобраться Вам с принципом работы функции.