Nickolay.info. PHP. Разбиваем вывод PHP на страницы

На большинстве сайтов нужно выдавать пользователю полученные из базы данные небольшими "порциями" по 10, 20 или ещё сколько-то записей. Чаще всего при этом внизу или вверху страницы доступно меню, позволяющее перейти к другой странице:

Разбиение вывода на страницы в Яndex

Когда страниц много, переходить между ними становится не очень удобно, а меню перехода разрастается и занимает всё больше места, как, например, в этой гостевой на 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 выдаст примерно вот такое меню:

меню

Если статей становится много, функция гибко уберет лишние ссылки:

меню
меню

Рейтинг@Mail.ru

вверх гостевая; E-mail