Pers.narod.ru. PHP. Разбиваем вывод PHP на страницы |
На большинстве сайтов нужно выдавать пользователю полученные из базы данные небольшими "порциями" по 10, 20 или ещё сколько-то записей. Чаще всего при этом внизу или вверху страницы доступно меню, позволяющее перейти к другой странице:
Когда страниц много, переходить между ними становится не очень удобно, а меню перехода разрастается и занимает всё больше места, как, например, в этой гостевой на Narod.Ru:
Давайте кратко обсудим, как в коде на PHP делать разбиение на страницы, и напишем соответствующую "универсальную" функцию.
Во-первых, нам понадобится ряд переменных, управляющих отображением данных. Я обычно обхожусь примерно таким набором:
$sort - способ сортировки записей; если предумсотрены прямая и обратная сортировка, может понадобиться еще и переменная, управляющая режимом сортировки;
$start - начиная с какой записи отображать;
$limit - по сколько записей отображать; удобно, если специально назначенное значение этой переменной (например, -1) говорит о том, что надо отобразить все записи.
Где хранить все эти переменные? В 5-й (да и 4-й) версиях PHP уже не стоит объявлять глобальных переменных. Передавать все данные через URL запроса - тоже можно, хотя это неудобно и создает длинные неудобочитаемые адреса:
http://мойсайт.ru/index.php?id=8&sort=date&start=0&limit=5
Кроме того, при таком подходе придется "таскать" все эти переменные из скрипта в скрипт, добавляя в каждый файл обработку соответствующих параметров (кстати, о компактной обработке параметров, переданных через GET или POST, написано в этой статье).
В качестве альтернативы можно хранить все переменные, отвечающие за настройки вывода, в созданной браузером сессии. Для этого достаточно первой строчкой каждого скрипта указать вызов функции, запускающей сессию:
session_start ();
Второй строкой можно всегда указывать подключение файла functions.php
с функциями проекта:
require_once ("functions.php");
Этот файл, в свою очередь, может подключать другие библиотеки, например, файл конфигурации проекта и бибилиотеку для работы с базой данных:
require_once ("config.php"); require_once ("db.php"); ...
Несложный пример библиотеки db.php
описан, например, в этой статье, а про поддержку сессий говорится в этой.
Сделав простейшие файлы, отвечающие за переключение режимов вывода (скажем, вот файл sort.php
, позволяющий последовательно переключать переменную сессии $sort между значениями date, rating и title):
<? session_start(); require_once ("functions.php"); if ($_SESSION['sort']=='date') $_SESSION['sort']='rating'; else if ($_SESSION['sort']=='rating') $_SESSION['sort']='title'; else $_SESSION['sort']='date'; if (isset ($_SERVER['HTTP_REFERER'])) { header('Location: '.$_SERVER['HTTP_REFERER']); } else { header('Location: index.php'); } ?>
и поставив ссылки на эти файлы где-нибудь в единой для всего портала "шапке" страниц:
<p>Сортировать по: <a href="sort.php"><?print ($_SESSION['sort']=='date'? 'рейтингу':($_SESSION['sort']=='rating'?'заголовку':'дате')); ?></a> Выводить по: <a href="limits.php?limit=10">10</a> <a href="limits.php?limit=50">50</a> <a href="limits.php?limit=-1">все</a>
мы можем теперь переключать режимы вывода с любой страницы сайта, не передавая никаких лишних переменных скриптам. Здесь предполагается, что названия режимов сортировки совпадают с именами полей в таблице БД, то есть, в таблице имеются поля с именами title, date и rating, по которым её можно сортировать.
Дать переменным сессии начальные значения можно в любом коде, выполняемом один раз, скажем, так:
if (empty($_SESSION['sort'])) $_SESSION['sort']='date'; if (empty($_SESSION['start'])) $_SESSION['start']='0'; if (empty($_SESSION['limit'])) $_SESSION['limit']='10';
Дело за малым - получив из базы данных список страниц, отвечающих запросу, сформировать меню для их вывода.
В качестве примера предположим, что данные хранятся в таблице с именем notes, тогда SQL-запрос и его обработка могут иметь следующий вид:
$sql='select * from notes order by '.$_SESSION['sort'].' desc'; if ($_SESSION['limit']!=-1) $sql.=' limit '.$_SESSION['start'].','.$_SESSION['limit']; $result = dbquery($sql); if ($result and dbrows($result)) { while ($page = dbfetcha($result)) { /* Разбор и вывод очередной статьи. Поле базы с именем text будет доступно как $page['text'] и т.д. */ } if ($_SESSION['limit']>-1) { $count = dbfetch(dbquery("select count(*) from notes")); if ($count[0]>$_SESSION['limit']) { print '<p align=center>'; navigation_string ($count[0],$_SESSION['sort'], $_SESSION['start'],$_SESSION['limit']); print "</p>\n"; } } } else { /* Обработка ситуации, когда не удалось получить ни одной статьи */ }
Здесь для простоты всегда делается сортировка по убыванию (desc), а число записей в базе получается отдельным запросом select count(*) from notes
, в жизни того и другого легко избежать. Функция navigation_string
, тело которой помещено в файл функций functions.php
, выполнит всю работу:
function navigation_string ($count,$sort,$start,$limit) { if ($count>$limit) { $show=false; for ($s=0; $s<$count; $s+=$limit) { $from=$s+1; $to=$from+$limit-1; if ($to>$count) $to=$count; if ($from==$to) $diap="$from"; else $diap="$from-$to"; if ( (abs($s-$start)<2*$limit) or ($s<2*$limit) or ($s>=$count-2*$limit) ) { if ($s!=$start) print " [<a href=\"start.php?start=$s\">$diap</a>]"; else print " [$diap]"; $show=true; } else { if ($show) { print " ..."; $show=false; } } } //Если не нужна ссылка для вывода всех страниц - закомментарить строку ниже print " [<a href=\"limits.php?limit=-1\">все</a>]"; } }
Здесь для изменения настройки разбиения на порции вызывается скрипт start.php
:
<? session_start(); require_once ("functions.php"); $params = array('start'); require_once ("params.php"); if ($start<0) $start=0; $_SESSION['start']=$start; if (isset ($_SERVER['HTTP_REFERER'])) { header('Location: '.$_SERVER['HTTP_REFERER']); } else { header('Location: index.php'); } ?>
а для изменения лимита может быть вызыван аналигичный скрипт limits.php
:
<? session_start(); require_once ("functions.php"); $params = array('limit'); require_once ("params.php"); if ($limit<-1) $limit=-1; else if ($limit>100) $limit=100; $_SESSION['limit']=$limit; $_SESSION['start']=0; //При изменении лимита начинаем всегда с 0 if (isset ($_SERVER['HTTP_REFERER'])) { header('Location: '.$_SERVER['HTTP_REFERER']); } else { header('Location: index.php'); }?>
Оба последних скрипта используют общий для всего сайта обработчик параметров с именем params.php
:
<? while (list($num,$var) = each($params)) { if (!empty($_POST[$var])) $$var = trim(htmlspecialchars(magic($_POST[$var]))); else if (!empty($_GET[$var])) $$var = trim(htmlspecialchars(magic($_GET[$var]))); else $$var = ''; } ?>
Функция magic
, служащая для корректной обработки кавычек, включена в файл функций functions.php
:
function magic($path){ if( ini_get('magic_quotes_sybase')=='1'){ $path=str_replace('""','"',$path); $path=str_replace("''","'",$path); } else { if(@get_magic_quotes_gpc()=='1'){ $path=str_replace('\\"','"',$path); $path=str_replace("\\'","'",$path); $path=str_replace("\\\\","\\",$path); } } return $path; }
Описанный пример предполагает, что подключение к базе данных с именем test
, находящейся на локальном хосте, описано в файле db.php
:
$mysql=mysql_connect("localhost", "root", "root"); //хост, логин, пароль mysql_select_db("test"); //имя базы данных
и эта база имеет таблицу с именем notes
и следующей структурой:
id int PRIMARY KEY auto_increment, date bigint, title varchar(255), rating int, anons text
Файл, позволяющий создать таблицу, находится в архиве под именем !sql!.sql
, а подробная инструкция о настройке и выполнении скриптов на локальном сервере под Windows XP доступна в этой статье.
Работающий пример, содержащий все рассмотренные функции и файлы, можно скачать по ссылке ниже. Разумеется, с ним есть смысл работать, когда таблица notes
наполнена данными.
После создания таблицы в базе с именем test
запрос вносит туда 60 записей.
Скачать пример (7 Кб)
Для небольшого числа статей функция navigation_string
выдаст примерно вот такое меню:
Если статей становится много, функция гибко уберет лишние ссылки:
гостевая; E-mail |