PHP: Новый тип навигационной системы при постраничном выводе

Оглавление

Введение

(Вернуться к оглавлению)

Практически каждый разработчик сталкивался с необходимостью постраничного вывода информации. Каким бы ни был проект, в нем всегда есть "что-то", что не помещается на одну страницу: авторские стихи в маленькой домашней страничке или архив новостей в информационном портале. И каждый раз, когда мы создаем механизм поиска "Первой страницы", "Следующей страницы", "Предыдущей страницы", мы занимаемся рутинной работой. Каждый раз, когда мы в очередной раз переделываем готовую функцию постраничного вывода под новый интерфейс, мы напрасно теряем время. Однако, как правило, попытки создать какую-то единую универсальную функцию постраничного вывода наталкивались на то, что постраничный вывод тесно связан с контекстом. Эту связь можно разделить по степени важности на два уровня:

Невозможно создать универсальную систему постраничного вывода (читай: независимую от контекста), если невозможно разделить постраничный вывод и контекст. Причем не заниматься этим "разделением" в каждом проекте, а сделать это один раз, создав универсальную систему, и затем просто использовать ее. Всё это приводит нас к следующему разделу:

Цели и задачи

(Вернуться к оглавлению)

Целью этой статьи является рассказать об общем методе решения основной проблемы. Это решение неполно, но оно оставлено таким намеренно, чтобы не ограничивать свободы творчества тех разработчиков, которые решат воспользоваться им. Второстепенная проблема практически не затронута, но если идея, реализованная в этой статье, вызовет интерес, то, естественно, мы еще вернемся к этому вопросу.

Однако, прежде, чем начинать обсуждение чего-либо, хотелось бы "сверить часы": объяснить значение терминов, используемых в этой статье, создать своеобразный терминологический словарь:

Словарь терминов

(Вернуться к оглавлению)

Термины в словаре введены в логическом порядке: если термин содержит другие термины, то эти термины были определены раньше.

Основная идея

(Вернуться к оглавлению)

Основная идея, изложенная в этой статье, проста: если очень сложно (практически невозможно) отделить контекст от параметров постраничного вывода, то нужно попробовать использовать другой внешний вид этих параметров при передаче их в навигационных ссылках. Как правило, все системы постраничного вывода обладают несколькими основными параметрами, а именно:

  1. Количество элементов
  2. Номер активной страницы
  3. Количество навигационных ссылок
  4. Количество элементов на активной странице
Для того, чтобы постраничный вывод был корректным, каждый из этих параметров должен быть целым неотрицательным числом. Именно этот факт натолкнул меня на идею: передавать все параметры постраничного вывода внутри одного, специально отформатированного, параметра. В этой статье мы будем рассматривать упрощенную систему постраничного вывода, в которой отслеживаются только два основных параметра:
  1. Количество элементов
  2. Номер активной страницы

Тому есть 2 причины: во-первых, наши рассуждения могут быть легко распространены на два других параметра; во-вторых, это не будет отвлекать нас в процессе рассуждений.

Теперь изложим нашу идею более подробно для системы постраничного вывода с двумя основными параметрами: поскольку оба параметра - количество элементов и номер активной страницы - являются целыми неотрицательными числами, наиболее оптимальные решением было бы передавать их в виде специально сформированной строки, например, abcd2as15ks2sdm3 (См. пример N2)

Пример 2. Общий вид специально отформатированной строки,
объединяющей оба основных параметра системы постраничного вывода
abcd 2 as 15 ks 2sdm3
"Маскирующая" часть 1 Номер активной страницы "Разделяющая" часть 2 Общее число элементов "Разделяющая" часть 3 "Маскирующая" часть 4
Необязательная часть. Мы сами определим, как она должна выглядеть. Целое число ≥ 0 Разделитель-"не цифра" (например, буквы латинского алфавита) Целое число ≥ 0 Разделитель-"не цифра" (например, буквы латинского алфавита) Необязательная часть. Мы сами определим, как она должна выглядеть.

Создание строки в формате md5

(Вернуться к оглавлению)

Итак, давайте подробней обсудим, как будет формироваться наша cтрока в формате md5. Конечно, можно использовать любой другой алгоритм ее формирования, и необязательна эта строка должна быть похожа на md5-строку. И, конечно же, наш способ приведен исключительно в качестве примера. Мы предлагаем формировать строку в формате md5 с учетом следующих условий:

  1. Будем использовать "маскирующую" часть 1 фиксированной длины в 5 символов; для этого сгенерируем с помощью функции md5() строку и будем использовать ее первые 5 символов:

    define('PART1_LENGTH', 5); //... srand(time()); $part_1 = substr(md5(uniqid(mt_rand())), 0, PART1_LENGTH);
  2. Будем использовать "разделяющую" часть 2 фиксированной длины в 3 символа, который будем случайным образом выбирать из заранее определенной строки $t_str:

    define('PART2_LENGTH', 3); //... srand(time()); $t_str = eregi_replace('[0-9]', '', md5(uniqid(mt_rand()))); $part_2 = substr($t_str, 0, PART2_LENGTH);
  3. Аналогично "разделяющей" части 2, найдем "разделяющую" часть 3:

    define('PART3_LENGTH', 2); //... srand(time()); $t_str = eregi_replace('[0-9]', '', md5(uniqid(mt_rand()))); $part_3 = substr($t_str, 0, PART3_LENGTH);
  4. Теперь совместим все части вместе. Получим результирующую строку вида: $res = $part_1.$curindex.$part_2.$total.$part_3; где

  5. Длина нашей строки $res, полученной на шаге 4, может быть меньше, чем 32 символа, и поэтому, поскольку мы создаем строку в формате md5, сгенерируем с помощью функции md5() еще одну, "дополняющую" строку и будем использовать ее для "дополнения" до 32-х символов нашей строки $res. Для этого воспользуемся функцией str_pad(): define('GENERAL_LENGTH', 32); //... srand(time()); $res = str_pad($res, GENERAL_LENGTH, md5(uniqid(mt_rand())), STR_PAD_RIGHT); где функция str_pad() принимает следующие параметры (более подробно - см. описание функции на сайте http://www.php.net):

  6. Оформим формирование строки в формате md5 в виде отдельной функции:

    define('PART1_LENGTH', 5); define('PART2_LENGTH', 3); define('PART3_LENGTH', 2); define('GENERAL_LENGTH', 32); //... function makeSecureParam($curindex, $total){ srand(time()); $part1 = substr(md5(uniqid(mt_rand())), 0, PART1_LENGTH); srand(time()); $t_str = eregi_replace('[0-9]', '', md5(uniqid(mt_rand()))); $part2 = substr($t_str, 0, PART2_LENGTH); srand(time()); $t_str = eregi_replace('[0-9]', '', md5(uniqid(mt_rand()))); $part3 = substr($t_str, 0, PART3_LENGTH); srand(time()); return str_pad($part1.$curindex.$part2.$total.$part3, GENERAL_LENGTH, md5(uniqid(mt_rand())), STR_PAD_RIGHT ); }

Итак, основная идея нами реализована : мы создали функцию, позволяющую "прятать" параметры системы постраничного вывода внутрь одной, специального вида строки. Какие преимущества нам это дает? Поскольку теперь наша система постраничного вывода характеризуется всего одним параметром, то это даст нам возможность встраивать систему постраничного вывода в контекст, а не наоборот, как это было раньше. Осталось только реализовать класс, который позволил бы принимать эту специального вида строку и преобразовывать ее в соответствующие параметры навигационной системы.

Описание класса

(Вернуться к оглавлению)

Мы создадим базовый класс, в котором присутствуют всего 2 функции: конструктор и инициализация основных параметров системы постраничного вывода по заранее данной строке специального формата.

Мы используем именно класс, хоть это и несколько замедлит выполнение скрипта, для того чтобы иметь возможность использовать несколько систем постраничного вывода одновременно (например, постраничный вывод новостей еженедельно и постраничный вывод новостей ежедневно внутри каждой выбранной недели) без каких-либо особых осложнений. Описание класса приведено ниже:

  1. Класс содержит две переменных: общее число элементов и номер активной страницы.

    class navigation{ var $curpage; /* active page number */ var $total; /* total items */ //... }
  2. Конструктор класса инициализирует "пустой" набор элементов (это предоставит возможность инициализировать экземпляр класса несколько раз):

    class navigation{ //... function navigation(){ $this->curpage = $this->total = 0; } }
  3. Прежде, чем анализировать заданную строку в формате md5, исключим из нее "маскирующую" часть 1:

    $str = substr($str, PART1_LENGTH);
  4. Проанализируем заданную строку в формате md5 с помощью функции preg_split() (более подробно - см. описание функции на сайте http://www.php.net): preg_split('/[^0-9]/si', $str, 3, PREG_SPLIT_NO_EMPTY) где

  5. Поскольку функция preg_split() возвращает в качестве результата массив значений, то наиболее удобно использовать функцию list() обработки результатов - запишем первое полученное число во временную переменную $curpage, а второе - во временную переменную $total (этот порядок определяется способом формирования строки в формате md5 с помощью функции "makeSecureParam"):

    @list($curpage, $total) = preg_split('/[^0-9]/si', $str, 3, PREG_SPLIT_NO_EMPTY);
  6. Чтобы исключить всевозможные "неожиданности", преобразуем полученные результаты к целым неотрицательным числам, а результат запишем в соответствующие переменные нашего класса:

    $this->curpage = abs(intval($curpage)); $this->total = abs(intval($total));
  7. Оформим анализ строки в формате md5 в виде функции init, которая позволит выделить из данной строки необходимые параметры навигационной системы: общее число элементов и номер активной страницы.

    define('PART1_LENGTH', 5); //... class navigation{ //... function init($str = ''){ $str = substr($str, PART1_LENGTH); if (!trim($str)){ $this->curpage = $this->total = 0; return; } @list($curpage, $total) = preg_split('/[^0-9]/si', $str, 3, PREG_SPLIT_NO_EMPTY); $this->curpage = abs(intval($curpage)); $this->total = abs(intval($total)); } }

Итоги

(Вернуться к оглавлению)

Статья может быть полезной любому человеку, знакомому с синтаксисом РНР и владеющему по крайней мере начальным опытом программирования на РНР. В этой статье нет готовых рецептов. В ней изложен метод решения, которым каждый может воспользоваться. Главной идеей является "сокрытие" всех параметров навигационной системой внутри одной строки специального формата (в приведенном примере используется формат "а-ля md5" :) ). Представлена функция, формирующая строку в формате md5, и базовый класс, позволяющий инициализировать параметры навигационной системы по заданной строке в формате md5. Преимущества данного метода:

Полностью работающий текст класса и функции, описанных в этой статье, можно скачать здесь: code.zip

 

 Copyright © 2002 by Felenka