WebScript.Ru
C:\   главная  ::   о сайте  ::  каталог скриптов  ::  гнездо  ::  форум  ::   авторам  :: Новостройки ::   ХОСТИНГ  ::

|| разделы::
|| поиск по сайту::

|| реклама::
|| новости почтой::
Рассылки Subscribe.Ru ::



Новости сайта WebScript.Ru
Популярные статьи

Hot 5 Stories

|| рекомендуем::




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


Прислал: Felenka [ 24.05.2002 @ 12:05 ]
Раздел:: [ Статьи по PHP ]


Оглавление

Введение

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

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

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

  • Проблема, связанная с организацией внешнего вида (второстепенная проблема). В каждом проекте свой метод вывода информации. Это касается не только внешнего вида постраничных переходов (это может быть кнопка, которая переходит от страницы к странице с помощью метода POST; это может быть ссылка, которая формирует GET-овую строку запроса; и др.), но и способа хранения данных (кнопка или ссылка может формироваться динамически, "на лету"; это может быть шаблон, хранящийся в БД, и др.)

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

Цели и задачи

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

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

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

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

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

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

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

  • Страница - часть информации, выводимая на при постраничном просмотре, в соответствии с заданными параметрами деления информации на страницы.

  • Навигационная система или система постраничного вывода - это набор кнопок или ссылок, позволяющих пользователю осуществить постраничный просмотр (см. пример №1).

    Пример 1. Простейшая неграфическая навигационная система
    Первая страница Предыдущая страница 4 5 6 7 8 9 Следующая страница Последняя страница
  • Активная страница - страница, содержимое которой в данный момент просматривает пользователь. В примере №1 активной является седьмая (7) страница.

  • Навигационная ссылка - кнопка или ссылка (в зависимости от реализации), с помощью которой пользователь может "пролистать" на ту страницу, которая в данный момент не является активной. В примере №1 страницы 4-6, 8-9, "Первая страница", "Предыдущая страница", "Следующая страница", "Последняя страница" являются навигационными ссылками.

  • Строка в формате md5 - строка, содержащая параметры системы постраничного вывода, однако сформированная таким образом, чтобы внешне походить на md5-строки, генерируемые функцией md5(). См. пример №2.

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

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

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

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

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

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

Пример 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;
    
    где
    • $part_1 - "маскирующая" часть 1, полученная на шаге 1;
    • $curindex - номер текущей страницы;
    • $part_2 - "разделяющая" часть 2, полученная на шаге 2;
    • $total - общее число элементов
    • $part_3 - "разделяющая" часть 3, полученная на шаге 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() принимает следующие параметры (более подробно - см. описание функции на сайте //www.php.net):

    • $res - результирующая строка, полученная на шаге 4;
    • GENERAL_LENGTH - длина строки, которая будет сравниваться с длиной строки $res; если длина строки $res меньше, чем GENERAL_LENGTH, то наша строка $res будет дополнена в соответствии с последующими двумя параметрами до длины GENERAL_LENGTH;
    • md5(uniqid(mt_rand())) - случайным образом сгенерированная строка в формате md5, которая будет использоваться до "дополнения" нашей строки $res до длины GENERAL_LENGTH;
    • STR_PAD_RIGHT - означает, что "дополняющая" строка будет добавляться к нашей строке $res справа.

  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() (более подробно - см. описание функции на сайте //www.php.net):

    preg_split('/[^0-9]/si', $str, 3, PREG_SPLIT_NO_EMPTY)
    
    где
    • '/[^0-9]/si' - образец, позволяющий выделить из строки $str те ее части, которые состоят только из цифр; например, если
            $str = 'cf16b2bcf12fd72dc05154e87749d940'
      то результатом выполнения функции
            preg_split('/[^0-9]/si', $str)
      будет массив значений:

      • 16
      • 2
      • 12
      • 72
      • 05154
      • 87749
      • 940

    • $str - заданная строка в формате md5;

    • 3 - специальный параметр функции preg_split(), которая говорит, что нужно анализировать только первых три (3) совпадения в заданной строке $str;например, если
            $str = 'cf16b2bcf12fd72dc05154e87749d940'
      то результатом выполнения функции
            preg_split('/[^0-9]/si', $str, 3)
      будет массив значений:

      • 16
      • 2
      • cf12fd72dc05154e87749d940

    • 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. 

 




 :::::  bers пишет 11.11.2002 @ 15:37 
еще не дочитал до конца, но подход к написанию статьи мне очень понравился. побольше бы таких авторов
 :::::  Andrew пишет 21.11.2002 @ 16:58 
Объясните мне такому дураку плиз в чем преимущества того что мы все параметры замаскировали в виде хэша??? не проще ли написать search/?all=10&Current=2 ???
 :::::   пишет 21.11.2002 @ 18:48 
Полный бред. Andrew прав на 99%
 :::::  Victor пишет 27.11.2002 @ 17:01 
Допустим, текст на куски можно разделить вообще абстрактной строкой вида "!"№;%:?" ( или аналогичной, которая вряд ли встретится в тексте ). После этого получить полное количество страниц и текст каждой можно так:

$pages = explode("!"№;%:?", $text);

Получить количество страниц так:
$numPages = count($pages) - 1; // или sizeof, что по некоторым оценкам быстрее http://php.spb.ru/php/speed.html

И еще предусмотреть проверку таких вещей, как размер последней страницы - там может оказаться только символ перехода на новую строку, номер текущей страницы не больше количество страниц.

 :::::  Victor пишет 27.11.2002 @ 17:03 
В предыдущем сообщении случайно в строке попалась двойная кавычка - это опечатка.
 :::::  Yury Zaytsev пишет 30.11.2002 @ 20:57 
Совершенно непонятно какое отношение имеет

- Упрощение передачи параметров постраничного вывода в навигационных ссылках.
- Возможность использовать несколько систем постраничного вывода одновременно.
- "и всё такое" (c)

К формированию строки "а-ля md5" и зачем это вообще делать? Только загружать сервер _бесполезными_ и _ненужными_ вычислениями и свою голову бесполезной писаниной...

Да и вообще, зачем передавать скрипту все параметры в одной "замаскированной" строке? Если это из соображений безопасности (?), то почему бы просто не ползоваться проверками при register_globals=off?
 :::::  silverwind пишет 17.01.2003 @ 10:51 
Однако интересно. Немного, правда, запутано. Но все же интересно. Спасибо.

2 Юрий Зайцев: упрощение -- представь гипотетически ситуацию верстки страницы в две равноценные колонки с разным содержимым и при этом с постраничным (читай лимитированым) выводом в каждой, а давай больше -- еще и в две строки! Так вот сколько параметров тебе уже надо передавать скрипту и как их различать?.. совмещение -- пример выше, твои функции уже должны возится с кучей переменных;

2 Андрей: проще... )) но не везде, смотри пример выше, такое не встречается (?) согласен, но пример!
 :::::  qik пишет 07.02.2003 @ 21:26 
об`ясните мне plz как этот скрипт использовать ??? я чета не втыкаю =(
 :::::  Felenka пишет 04.03.2003 @ 17:07 
Ух... Сколько отзывов! :) Всем спасибо :))
Прошу прощения за "запоздалость" ответов - редко заглядываю :)

2Andrew
>в чем преимущества того что мы все параметры замаскировали в виде хэша???
>не проще ли написать search/?all=10&Current=2 ???

проще, когда параметров всего 2, а если еще нужно учитывать сколько навигационных ссылок показывать, сколько элементов на странице?

Нюансов может быть множество, приведу в качестве примера те, с которыми чаще встречаюсь, чем с другими:
случай 1) при пролистывании результатов поиска добавляются еще дополнительные параметры: с одной стороны, хорошим тоном было бы передавать результаты через GET, чтобы Вася смог показать Пете тот классный футбольный мяч, который он нашел на 18 странице среди 1000 предоставленных товаров в интернет-магазине. Однако, GET ведь не резиновый, верно? использование нескольких параметров внутри одной строки упрощает эту задачу

случай 2) давай представим, что функции "пролистывания" написал твой коллега - а ты всего лишь пользуешься уже готовой библиотекой. Сколько имен переменных нужно держать тебе в голове, чтобы они не "перекрывались" с переменными, используемыми при пролистывании?


2Victor
>Допустим, текст на куски можно разделить вообще абстрактной строкой вида
>"!"№;%:?" ( или аналогичной, которая вряд ли встретится в тексте ).

Я не очень поняла... Предполагается, что текст для постраничного вывода у нас есть целиком? тогда да, конечно... Однако, я рассматриваю более часто встречающуюся ситуацию, когда данные выбираются из БД и содержимое каждой страницы формируется динамически в зависимости от того, какая навигационная ссылка активна.

2qik
Скрипт непосредственно использовать вряд ли получится :) Он представлен как фундамент для библиотеки, которую разработчик сможет разработать, используя предложенный метод. Если тема будет интересна, то я продолжу серию статей, в которых эта библиотека будет описана более подробно

 :::::  Mark пишет 06.03.2003 @ 18:36 
Помоему слишком уж раздули тему над столь простой задачей. Тоесть "hello world на 100 страниц".
 :::::  WestSoft пишет 27.06.2003 @ 19:07 
Обмениваться скриптами!Сюда!Пишите мне на мыло!
 :::::  MIS_525 пишет 02.08.2003 @ 17:55 
Felenka, mojete li vi mne prislat samii prostoi rabotaushi primer napisanni po primeru vashei stati? ya ne uverena chto u menia vsio poluchitsa...
zaranee spasibo...
s uvajeniem NINO
 :::::  Design & Programming from ADC пишет 18.10.2003 @ 17:29 
MIS_525
Люди на транслит не отвечают.

 :::::  Cord пишет 12.02.2007 @ 19:12 
Интересный подход к оформлению статьи. По поводу содержания - хм, необычная идея. :)
Имя:
Email:
URL

Введите сумму двух чисел девять и шесть (девять+шесть=?)
Запомнить мою информацию

* Html запрещен* Ваш E-mail опубликован не будет.

Copyright © 2000-2001 WebScript.Ru nas@webscript.ru
Design © 2001 by Parallax Design Studio (aka Spectator.ru)
Все торговые марки и авторские права на эту страницу принадлежат их соответствующим владельцам.
Сгенерировано за: 0.0377951