|
Последняя модификация: 10.08.2014 г Страница загружена с адреса: http://webdesign.site3k.ru/conjuncture/append/d/price2.html Обработка баз данных сервером
Считывание данных в WEB-страницуCSV-Файлы получили настолько широкое распространение, что их поддержку включили даже в PHP. Так что, можно обрабатывать на сервере те же базы данных, что были предназначены для обработки браузером посетителя (см. «Обработка баз данных браузером посетителя»). Для обработки CSV-файлов в PHP введена функция: fgetcsv($FILE, LEN, DELIM) Эта функция читает одну строку из файла, заданного дескриптором $FILE, с максимальной длиной, заданной параметром LEN, разбивает ее по символу DELIM (параметр DELIM должен обязательно состоять из одного символа, в противном случае принимается во внимание только первый) на отдельные элементы, и возвращает их в массив. Таким образом, получивший значение, возвращаемое функцией fgetcsv, массив содержит 1 запись из базы данных, готовую к дальнейшей обработке и ее не приходится дополнительно делить на поля с помощью функций explode() или split(). После считывания строки, позиция в файле меняется, так, что при следующем считывании, функция прочтет следующую строку1. Функция возвращает false, если строки кончились. Пустые строки в файле не игнорируются, а возвращаются как список из одного элемента пустой строки. Используя функцию fgetcsv, напишем простой PHP-скрипт для считывания CSV-файла (по сути, самого обычного текстового файла, в котором элементы разделены неким, удобным для нас символом):
Фильтрация данныхДобившись отображения на странице данных из CSV-файла, можно добавить к ним фильтры. В начале создадим для них элементы управления:
Если на вашем сервере GET-переменные скриптам недоступны, вместо использования переменных $edit1, $edit2 и т. д., следует использовать массив GET-переменных. Например: $_GET['edit1'], $_GET['edit2'], $_GET['menu'].
Теперь можно усовершенствовать код PHP, чтобы он учитывал посылаемые ему фильтры. Вместо простого вывода на страницу, сразу за функцией LIST, добавим условия, при которых должен происходить вывод:
Код проверяет, не является ли переменная пустой (и тогда проверяет следующую строку), если она не пустая, равна ли она, после перекодировки (а все неанглийские символы кодируются при передаче параметров в HTTP-запросе) значению «Все», что так же, как и пустота переменной, означает переход к следующей строке, или может быть (опять же, после перекодировки, на всякий случай), равна марке из базы данных. При несовпадении ни одного из условий, строка из базы не выводится на страницу и начинается следующий цикл, с чтением следующей строки. Если одно из условий выполняется, начинается следующая проверка: не установлена ли переменная edit1, а если установлена, то не будет ли она меньше или ровна чем цена в базе. Если условие не выполняется, считывается следующая строка, если выполняется, начинается последняя проверка: задано ли ограничение по площади (edit2) и не соответствуют ли ему данные из базы. В конце концов, пройдя три уровня фильтров, данные выводятся на страницу. Если мы выберем фильтр, задав торговую марку, предел цены, минимум расчетной площади и нажмем на кнопку «Показать», отфильтрованные данные отобразятся в таблице, заголовок которой покажет их точное количество. Поле для ввода цены, благодаря конструкции value="<?=@$edit1 ?>", вставляющей на место <?=@$edit1 ?> результат работы PHP-кода (а он просто впишет туда значение переменной edit1, полученной до обновления данных) будет отображать максимальное значение цены, а поле для ввода площади, по аналогичной причине, будет отображать минимальную площадь Вот только список, почему-то, будет показывать «Все», несмотря на выбор конкретной торговой марки. Происходит это потому что, после посылки формы, страница перегружается, и все ее переменные устанавливаются в исходное состояние. Конструкция value="<?=@$edit1 ?>" позволяла сохранить значения полей ввода, принудительно назначая их новой версии страницы. Аналогично можно было бы поступить и с выпадающим списком, каждый раз переписывая его заново с помощью PHP, но это слишком громоздко. Удобней, на мой взгляд, сделать это, написав дополнительный JavaScript:
Конструкция, в целом не хитрая. Объявляется цикл по всему списку, так что, изменение списка не требует коррекции скрипта. Внутри цикла переменной «а» передается текст элемента списка и сравнивается со значением, выбранным ранее. Если совпало, пункт списка объявляется выбранным и цикл прекращается. Вот только Опера и Мазила с этим не работают... Оказалось, Опера и Мазила в innerHTML включают больше текста, чем требовалось. Опера считает своим долгом добавить в него завершающий пробел, даже если он и без того есть, а Мазила вообще, все подряд до следующего тега. Но «Hitachi» и «Hitachi » это разные вещи. И если Эксплорер автоматически отрезает завершающие пробелы, то другие браузеры нет. И никаких функций для этого не предусмотрено. Так что, сразу за a=frm.menu[i].innerHTML, следует добавить код, обрезающий все завершающие знаки табуляции, возврата каретки, новой строки и пробелы:
Теперь выбор данных работает в любом браузере2. Выполнить сортировку, как предлагалось в «Обработка баз данных браузером посетителя» нельзя, так как PHP не обладает функциями сортировки данных для простых текстовых файлов, но в большинстве случаев фильтров вполне достаточно. Окончательный вариант исходного кодаПоскольку вы никоим образом не сможете увидеть истинный код страницы напичканной PHP-скриптами, приведу его здесь:
А вот результат его выполнения: Смотреть. Браузеры без JavaScriptПоскольку подавление скриптов, благодаря Windows XP SP2 стало популярным, стоит отметить что, приведенный выше код будет работать и без JavaScript, только количество отобранных записей не будет отображаться и, текущее положение в выпадающем списке, при обновлении страницы установится в положение по умолчанию. Не самое лучшее поведение, которое можно было себе представить, но эти недостатки вполне терпимы. Но кто сказал, что их нужно терпеть? Делать совместимую страницу, так уж делать ее совместимой по полной программе! Но как добится сохнанения положения ввыпадающем списке без JavaScript? Неужели перед каждым пунктом писать кодпроверки на соответствие текущему положению и, в зависимости от результата, вписывать его то с "selected", то без? Ведь это громоздко и крайне неудобно, в случае необходимости редактировать меню? Но способ есть: Если меню хранить в отдельном файле, то, с случае обработки браузером, его можно включать в страницу по <!--#include virtual="этот_файл" --> (см. документацию по SSI-директивам). В PHP-варианте, этот файл можно открыть и добавить построчно, циклически проверяя каждую строку: не нужен ли ей атрибут "selected". Таким образом, при необходимости изменения списка (в данном случае, торговых марок), придется менять один этот файл, а не две страницы, его использующие. Реализация функции пометки, при хранении списка опций в отдельном файле очень проста и не зависит от их количества. Помещаем такой код, в том месте, где должен объявлятся список:
Теперь хорошо бы перевести на язык PHP и счетчик записей – элементарно:
Поскольку количество столбцов скрипт узнает только по окончании заполнения таблицы, CAPTION придется помещать перед ее закрытием. Это означает что, сумарную информацию мы получим под таблицей? О, нет. Это же CAPTION, она все равно отобразится на верху! Отстался один маленький скриптеныш – на кнопке возвращения к исходному состоянию, событие onClick. И его можно убрать, но только не везде кнопка без него будет работать. Но это можно пережить. Эту кнопку вообще можно выкинуть, а вместо нее, добавить на страницу еще одну форму:
Со скриптом, или с формой, нажатие кнопки «Снять фильтр» означает для браузера возврат к исходной странице, на которую не устанавливались ни какие фильтры, и он просто возьмет ее из кеша, что произойдет очень быстро. Более медленный, но более академический вариант – поместить в скрипт вторую кнопку типа SUBMIT, дав ей некое имя, напрмер «button2», а перед выводом формы, если эта кнопка нажата, очистить все переменные фильтров:
Получится вот такой исходный код:
А вот результат его выполнения: Смотреть. 1 Конечно, можно было бы, и это было бы более традиционно, считать базу в массив и, затем обрабатывать массив, но при величине прайса в сотню строк (позиций), выизрыш в скорости не будет заметен, а при больших размерах... Представим себе, что, в среднем, строка прайса имеет длинну 100 символов. Стало быть, прайс в сто строк имеет размер в 10 килобайт. Если на каждом из тысячи сайтов на сервере вашего провайдера открыто по десять таких прайсов или чего-то еще, в этом духе, сто мегабайт оперативной памяти тратятся только на такие массивы. А сколько еще на всякие переменные и процессы? А хватит ли памяти на сервере? Не стоит уповать на мощьности компьютеров – следует делать экономичные программы. Файлы до килобайта, конечно, лучше считать в массив, свыше ста килобайт, лучше использовать обращение к базам, имеющим ключевые поля, базы более мегабайта, лучше обрабатывать через SQL-запросы. А файлы среднего размера (каждый сам решит, что такое средний размер), следует обрабатывать либо по ключам, либо построчно. НО НЕ СЧИТЫВАТЬ ВЕСЬ ФАЙЛ В МАССИВ! Представьте, десять посетителей на каждом из тысячи сайтов, открывших мегабайтную базу в массив – когда это делаете вы в одиночку, на своем компьютере – это ерунда, но на сервере потребуется 10 ГИГАБАЙТ оперативной памяти! 2 Вместо frm.menu[i].innerHTML можно было применить frm.menu[i].innerText, но он не будет работать в Mozilla. Другой способ – frm.menu[i].text – будет работать везде и, более того, не потребует удаления лидирующих пробелов, однако для примера специально выбран более сложный способ, чтобы, заодно, продемонстрировать полезную функцию усечения строки.
|