Главная страница «Первого сентября»Главная страница журнала «Информатика»Содержание №18/2008


Педагогический университет

Основы web-программирования для школьного "сайтостроительства". Лекция 2.

Пример задачи автоматизации: доска объявлений школьного сайта

И снова здравствуйте! Сегодня нам предстоит весьма насыщенное занятие, в котором в отличие от первого кода будет больше, чем слов. Надеюсь, в результате изучения первой лекции вы добились главного на данный момент — установили Denwer и заставили его работать на тех простых примерах, которые были рассмотрены.

Содержательная тема второй лекции — доска объявлений школьного сайта. Выбрал я ее потому, что, пожалуй, трудно придумать задачу более типичную. Если сайт “живой”, то наличие на нем объявлений — насущная необходимость. Ведь это самый простой и надежный способ оперативно известить о чем-то педагогов, учеников, родителей.

С другой стороны, именно объявления на сайте часто становятся настоящей головной болью веб-мастера. Мало удовольствия, когда тебя “дергают” то между уроками, то рано утром, то поздно вечером, то даже в выходные для того, чтобы “повесить” на сайт очередное объявление, что-то поменять, исправить, дополнить и т.д. Куда как правильнее один раз напрячься, немного попрограммировать и научить кого-то другого (например, секретаря школы) размещать объявления на сайте. Один из способов сделать это мы сегодня рассмотрим.

Сразу оговорюсь — способ точно не лучший, не слишком удобный, не оптимальный, не современный. Зато очень быстрый в реализации. Несколько минут — и все готово. А что касается других (лучших) вариантов, то о них мы поговорим, когда займемся рассмотрением баз данных.

Учебный план

№ газеты

ЛЕКЦИЯ

17/2008

Лекция 1. “Пролетая над миром web-программирования”. Границы возможностей статического HTML. Два мира, две системы: программирование на стороне клиента и программирование на стороне сервера. Идем от реальности: текущие предложения хостинг-провайдеров. Инструментарий: пакет Denwer, установка. Первая программа на PHP “Здравствуй, мир web-программирования”.

18/2008

Лекция 2. Пример задачи автоматизации: доска объявлений школьного сайта. SSI, основные возможности и директивы. SSI-версия школьной доски объявлений. PHP-версия доски объявлений. Совершенству нет предела: выводим все объявления из каталога, помечаем важные. Передача параметров в программы на PHP. Обзор синтаксиса PHP: типы данных, операции, основные алгоритмические конструкции.

19/2008

Лекция 3. Обработка форм на стороне сервера. Формы и элементы управления HTML: однострочное и многострочное поля ввода, флажки, радиокнопки, списки. Методы GET и POST, кодирование URL. Обзор синтаксиса PHP: функции, массивы.

20/2008

Лекция 4. Усовершенствованная доска объявлений с разделом администратора. Обзор синтаксиса PHP: файлы. Законченный мини-проект: административный интерфейс для доски объявлений на файловом “движке”.

Контрольная работа № 1. Разработка теста с обработкой результатов тестирования на стороне сервера.

21/2008

Лекция 5. Введение в использование баз данных в задачах web-программирования. Зачем нужна СУБД? Теория реляционных баз данных: основные термины. SELECT — “главная команда” SQL. Что такое MySQL? Взаимодействие с сервером MySQL из программ на PHP.

22/2008

Лекция 6. База данных “Страница школьного журнала”: от проектирования до визуализации. Практическое применение базы данных для автоматизации школьного сайта и школьной жизни.

Контрольная работа № 2. Доработка базы данных “Страница школьного журнала”.

23/2008

Лекция 7. “На троих”. Задействуем трех основных “игроков”: MySQL+PHP+Javascript. Проверка данных форм на стороне клиента перед отправкой на сервер.

24/2008

Лекция 8. Рисование средствами PHP. Генерирование графических данных “на лету”. Построение графиков и диаграмм. Графическая визуализация данных школьного журнала.

Итоговая работа

Back in SSI

“Many, many years ago…” С этих слов начинается бесчисленное количество английских сказок и исторических произведений. С них же мы начнем краткий рассказ об одной из самых “древних” технологий, имеющей отношение к web-программированию, — технологии SSI. Это сокращение от Server Side Includes — включения на стороне сервера.

Ключевая идея SSI вам фактически уже знакома, если при изучении предыдущей лекции вы поняли ключевую идею PHP. Заключается она в следующем: HTML-файл может содержать некоторые фрагменты (директивы), которые обрабатываются на стороне сервера, а браузеру отправляется результат их обработки. Все точно так же, как и с PHP, только для обработки директив SSI ничего дополнительного (как для PHP — интерпретатор PHP) не требуется, всю работу выполняет сам web-сервер (напомню, в нашем случае — Apache).

В принципе web-сервер можно настроить таким образом, чтобы он искал и при необходимости обрабатывал директивы SSI в любом HTML-файле. Но так делают крайне редко, поскольку это сильно замедляет работу. Типичный вариант, который в настройках Denwer установлен “по умолчанию”, заключается в том, что директивы SSI обрабатываются в файлах с расширением shtml.

Итак, давайте поставим эксперимент. Прежде всего в каталоге home (помните, о чем речь? Мы много экспериментировали с этим в первой лекции) создайте каталог myschool. Это будет основной каталог для примеров этого занятия. В нем создайте каталог www, а в нем — ssi. Запустите Denwer.

Теперь поместите в каталог ssi два файла:

Файл ssidemo.shtml

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=windows-1251">

<title>Тестируем SSI</title>

</head>

<body>

<h1>Тестируем SSI</h1>

<!--#include file="include.htm" -->

</body>

</html>

Файл include.htm

Меня только что вставили в другой документ.

Откройте файл ssidemo.shtml в браузере. (Помните, какой путь надо записать в URL? Постарайтесь понять это самостоятельно. И только если совсем ничего не получится, “подсмотрите” на рис. 1.)

4-0.gif (18027 bytes)

Рис. 1. Результат обработки shtml-файла

Ключевой момент: директива SSI

<!--#include file="include.htm" -->

была выполнена web-сервером, и на ее место был вставлен текст из файла include.htm. Директива <!--#include … --> — самая употребительная директива SSI. Ради нее мы и знакомимся с данной технологией. Да и вообще, директив в SSI не так много. Все они имеют вид

<!--#директива [параметры] -->

Директивы SSI не случайно имеют вид комментариев HTML. Это сделано для того, чтобы предотвратить их вывод на экран в случае, если web-сервер не умеет интерпретировать SSI или не настроен соответствующим образом. Мы легко можем смоделировать соответствующую ситуацию, изменив расширение файла с shtml на htm. (Напомню, что директивы SSI интерпретируются только в файлах с расширением shtml — так настроен Denwer.) Результат эксперимента с переименованием показан на рис. 2.

5-0.gif (18073 bytes)

Рис. 2. Web-сервер не обработал директиву и вернул ее браузеру AS IS. А тот воспринял ее просто, как комментарий

Как можно использовать технологию SSI на пользу дела? Фактически мы это уже продемонстрировали. Даже в эпоху расцвета SSI самой используемой директивой была include, а типичным ее применением — создание “каркасов” (шаблонов) сайтов. Рассмотрим, например, типичный макет школьного сайта (внимание! Наполнение этого макета — это, конечно, шутка, — мне просто требовалось как-то наполнить шаблон текстом).

5-1.gif (45847 bytes)

Рис. 3. Макет “школьного” сайта

На макете, показанном на рис. 3, легко выделить ряд независимых содержательных блоков. Например, к таковым можно уверенно отнести левое навигационное меню, центральный блок (в него я поместил замечательную притчу Э.Дийкстры о первом программисте. Если кто не читал — очень рекомендую, я для этого специально привел текст файла welcome.htm), блок объявлений и все остальное. Остальное — это каркас, включающий три эти блока.

Понятно, что все блоки можно разместить и в одном html-файле. Но это не слишком удобно. Почему? Посмотрим на те же объявления. Если сайт “живой”, их приходится добавлять часто. А это значит, что каждый раз надо “залезать” внутрь довольно большого файла, искать в нем место под очередное объявление и аккуратно его туда вставлять. Учитывая, что основной каркас страницы представляет собой таблицу, а блок объявлений — отдельная таблица (как и навигационное меню), запутаться в трех (или более) “соснах” (таблицах) не так сложно. Вот тут и приходит на помощь SSI. Куда как проще разместить блоки, составляющие эту страницу, в отдельных файлах и собрать их вместе посредством директивы include.

Я реализовал это следующим образом. Страница, показанная на рис. 3, состоит из четырех файлов: index.shtml (основной каркас), lmenu.htm (левое навигационное меню), welcome.htm (центральный блок) и notices.htm (блок объявлений). Наверное, это избыточно, но я все же не пожалею места и приведу здесь содержимое всех четырех файлов (можно было бы, конечно, ограничиться только файлом index.shtml, но я хорошо знаю, как иногда раздражают слова “легко видеть”, когда ты только начинаешь и тебе совсем даже не легко).

Файл index.shtml

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=windows-1251">

<title>Наша школа № 1123581321</title>

</head>

<body>

<table width="100%" cellpadding="5">

<tr bgcolor="#DDEEDD">

<td width="200"

><a href="/"><img src="logo.gif" alt="Логотип школы"

width="180" height="100" border="0"></a></td>

<td>

<h1>Средняя школа №&nbsp;1123581321 имени Л. Фибоначчи</h1>

<p><b>Адрес:</b> 121165, г. Пиза, ул. Короля Фридриха II, д. 24.

<b>Тел.:</b> 03. <b>Факс:</b> 02. <b>E-mail:</b>

<a href="mailto:leonardo@nikogo.net">leonardo@nikogo.net</a>

</td>

</tr>

<tr>

<td bgcolor="#DDDDEE" valign="top" width="200">

<!--#include file="lmenu.htm" -->

<!--#config timefmt="%D %r" -->

<hr>Последний раз этот документ был изменен

<i><!--#flastmod file="index.shtml" --></i>

<p>Знаете ли вы, каким браузером пользуетесь? А я знаю:

<i><!--#echo var="HTTP_USER_AGENT" --></i>

</td>

<td valign="top">

<table width="30%" align="right" bgcolor="#EEEEEE" vspace="5"

hspace="5" cellpadding="5">

<tr><th bgcolor="#AAAAAA">Объявления администрации</th></tr>

<tr>

<td>

<!--#include file="notices.htm" -->

</td>

</tr>

</table>

<h2>Добро пожаловать на сайт нашей школы!</h2>

<!--#include file="welcome.htm" -->

</td>

</tr>

</table>

</body>

</html>

Файл lmenu.htm

<table width="100%" border="1">

<tr>

<td><a href="#">Педагогический коллектив</a></td>

</tr>

<tr>

<td><a href="#">Администрация</a></td>

</tr>

<tr>

<td><a href="#">Расписание уроков</a></td>

</tr>

<tr>

<td><a href="#">Кружки и факультативы</a></td>

</tr>

</table>

Файл welcome.htm

<p>В незапамятные времена была организована железнодорожная компания. Один из ее руководителей (вероятно, коммерческий директор) обнаружил, что можно сэкономить много денег, если снабжать туалетом не каждый железнодорожный вагон, а лишь половину из них. Так и решено было сделать.

<p>Однако вскоре после начала пассажирских перевозок начались неприятности с туалетами. Причина их была крайне проста: хотя компания была только что создана, неразберихи уже хватало, и о распоряжении коммерческого директора ничего не знали на сортировочных станциях, где все вагоны считали одинаковыми. В результате в некоторых поездах туалетов почти совсем не было.

<p>Чтобы исправить положение, каждый вагон снабдили надписью, говорящей, есть ли в нем туалет, и сцепщикам было велено составлять поезда так, чтобы около половины вагонов имели туалеты. Хотя это и осложнило работу сцепщиков, вскоре они с гордостью сообщили, что тщательно выполняют новую инструкцию.

<p>Тем не менее неприятности с туалетами продолжались. Hовое расследование их причин показало, что, хотя действительно половина вагонов в поезде снабжена туалетами, иногда выходит так, что все они оказываются в одной половине поезда. Чтобы спасти дело, были выпущены инструкции, предписывающие чередовать вагоны с туалетами и без них. Это добавило работы сцепщикам, однако, поворчав, они и с этим справились.

<p>Hо проблема на этом не кончилась. Поскольку туалеты располагаются в одном из концов вагона, расстояние между двумя соседними туалетами в поезде могло достигать трех длин вагонов, и для пассажиров с детьми - особенно если коридоры были заставлены багажом - это было слишком далеко. Тогда вагоны с туалетами были снабжены стрелкой, и были изданы новые инструкции, предписывающие, чтобы все стрелки были направлены в одну сторону. Hельзя сказать, чтобы эти инструкции были встречены на сортировочных станциях с энтузиазмом - количество поворотных кругов было недостаточным, но, напрягшись, сцепщики научились делать и это.

<p>Теперь, когда все туалеты находились на равных расстояниях, компания была уверена в успехе, однако пассажиры продолжали беспокоиться: хотя до ближайшего туалета было не больше одного вагона, но не было ясно, с какой стороны он находится. Чтобы решить и эту проблему, внутри вагонов были нарисованы стрелки с надписью "ТУАЛЕТ", сделавшие необходимым правильно ориентировать и вагоны без туалетов.

<p>Hа сортировочных станциях новая инструкция вызвала шок: сделать требуемое вовремя было невозможно. В критический момент кто-то, чье имя сейчас невозможно установить, заметил следующее. Если мы сцепим вагон с туалетом и без оного так, чтобы туалет был посередине, и никогда их не будем расцеплять, то сортировочная станция будет иметь дело вместо N ориентированных объектов с N/2 объектами, которые можно во всех отношениях и со всех точек зрения считать симметричными. Это наблюдение решило проблему ценой двух уступок. Во-первых, поезда могли теперь состоять лишь из четного числа вагонов - недостающие вагоны могли быть оплачены за счет экономии от сокращения числа туалетов, и, во-вторых, туалеты были расположены на чуть-чуть неравных расстояниях. Hо кого беспокоит лишний метр?

<p>Хотя во времена, к которым относится наша история, человечество не знало ЭВМ, неизвестный, нашедший это решение, был первым в мире компетентным программистом.

<p>Я рассказывал эту историю разным людям. Программистам, как правило, она нравилась, а их начальники обычно сердились все больше и больше по мере ее развития. Hастоящие математики, однако, не могли понять, в чем соль.

<p align="right"><i>Эдсгер Дийкстра</i>

Файл notices.htm

<p><b>07/09/08</b>. Курить на территории школы следует только в строго отведенных местах и только на переменах.

<p><b>05/09/08</b>. Ездить по школьным лестницам на велосипедах категорически запрещается!

<p><b>05/09/08</b>. Кто вырыл во дворе школы ловушку для слонопотама? Немедленно закопайте!

<p><b>03/09/08</b>. С завтрашнего дня прекращается продажа пива в школьном буфете. Навсегда :-(

<p><b>29/08/08</b>. Уважаемые родители учащихся 5-х классов! Родительские собрания состоятся 3 сентября в 18.00. Просьба иметь с собой определенные суммы.

<p><b>25/08/08</b>. Уважаемые коллеги! Педагогический совет состоится 28 августа в 10<sup>00</sup> в актовом зале.

В файл index.shtml я включил несколько новых директив SSI. В частности, директива

<!--#flastmod file="index.shtml" -->

выводит дату/время последней модификации файла, а директива

<!--#config timefmt="%D %r" -->

как раз устанавливает параметры вывода для flashmod.

Директива

<!--#echo var="HTTP_USER_AGENT" -->

выводит значения стандартных переменных SSI, среди которых есть переменная HTTP_USER_AGENT, посредством которой можно узнать версию браузера клиента.

Вот, собственно, и все. Больше я про SSI рассказывать не буду — очень жалко тратить на это время и место. Как?!
А подробности? А точный синтаксис директив? А бесчисленные параметры timefmt? А полный список переменных?

Дорогие коллеги! Если вас интересуют указанные подробности, вы легко (по первой ссылке на запрос SSI на любом поисковике) найдете их. Но, право, не стоит тратить на это время. SSI — технология, о которой следует знать (и “для общего развития”, и для того, чтобы разбираться с проектами, написанными много лет назад), но использовать сейчас SSI в новых проектах точно не стоит. Это то, что применялось many, many years ago…

Translate to PHP

Итак, вернемся к PHP. Прежде всего в доказательство своих слов о том, что все, что можно сделать на SSI, уж точно можно сделать на PHP, я перепишу на PHP код нашего примера. При этом я не буду воспроизводить чисто иллюстративные фрагменты с датой изменения файла и версией браузера, а займусь лишь основным каркасом страницы. Перед этим в каталоге myschool/www я создам папку php, а в ней — папку v1 (версия 1, сегодня таких версий у нас будет пять) и перепишу в эту папку файлы lmenu.htm, welcome.htm и notices.htm — они, разумеется, останутся без изменений. А вот файл index.shtml я заменю файлом index.php.

Файл index.php

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=windows-1251">

<title>Наша школа № 1123581321</title>

</head>

<body>

<table width="100%" cellpadding="5">

<tr bgcolor="#DDEEDD">

<td width="200"

><a href="./"><img src="logo.gif" alt="Логотип школы"

width="180" height="100" border="0"

></a></

td>

<td>

<h1>Средняя школа №&nbsp;1123581321 имени Л. Фибоначчи</h1>

<p><b>Адрес:</b> 121165, г. Пиза, ул. Короля Фридриха II, д. 24.

<b>Тел.:</b> 03. <b>Факс:</b> 02. <b>E-mail:</b>

<a href="mailto:leonardo@nikogo.net">leonardo@nikogo.net</a>

</td>

</tr>

<tr>

<td bgcolor="#DDDDEE" valign="top" width="200">

<?php include "lmenu.htm" ?>

</td>

<td valign="top">

<table width="30%" align="right" bgcolor="#EEEEEE" vspace="5"

hspace="5" cellpadding="5">

<tr><th bgcolor="#AAAAAA">Объявления администрации</th></tr>

<tr>

<td>

<?php include "notices.htm" ?>

</td>

</tr>

</table>

<h2>Добро пожаловать на сайт нашей школы!</h2>

<?php include "welcome.htm" ?>

</td>

</tr>

</table>

</body>

</html>

Сделайте это и убедитесь, что все работает.

Давайте теперь разберемся с главным вопросом: а зачем мы все это сделали? Ну, да, когда вместо одного большого файла появились “кирпичики”, работать стало удобнее. И все? Нет, не все! Самое главное то, что мы сделали первый шаг на пути к автоматизации нашего сайта. Давайте еще раз посмотрим на файл notices.htm. Ведь он совсем простой! Для разметки в нем используется всего пара тегов. И теперь размещать в нем новые объявления можно научить практически любого. При этом можно не бояться за саму главную страницу сайта. Максимум, что может случиться плохого, — блок объявлений будет выглядеть “коряво”. То есть вполне можно дать секретарю школы доступ к файлу notices.htm, объяснить, как он устроен, и забыть о “текучке”. Ваша помощь понадобится теперь лишь в нестандартных ситуациях (когда кто-то что-то испортит :).

Правда, здорово? А ведь это только начало!

Разделяй и властвуй!

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

Вот каталог. В нем в текстовых файлах лежат все объявления. Файлы объявлений нумеруются по порядку: в файле 1.txt находится первое объявление, в 2.txt — второе, в 3.txt — третье и т.д. Если нужно поместить на сайт новое объявление, просто создаем текстовый файл с очередным именем (номером) и записываем в него текст объявления. Дата будет проставлена автоматически.

Правда, здорово? Давайте реализуем это. Для этого создадим в каталоге myschool/www/php каталог v2. В нем создадим каталог notices. И уже в него “накидаем” объявления 1.txt, 2.txt, 3.txt и т.д.

Перепишем в v2 все файлы из каталога v1 и модифицируем файл index.php (модифицированный фрагмент выделен).

Файл index.php

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=windows-1251">

<title>Наша школа № 1123581321</title>

</head>

<body>

<table width="100%" cellpadding="5">

<tr bgcolor="#DDEEDD">

<td width="200"

><a href="./"><img src="logo.gif" alt="Логотип школы" width="180" height="100" border="0"

></a></

td>

<td>

<h1>Средняя школа №&nbsp;1123581321 имени Л. Фибоначчи</h1>

<p><b>Адрес:</b> 121165, г. Пиза, ул. Короля Фридриха II, д. 24.

<b>Тел.:</b> 03. <b>Факс:</b> 02. <b>E-mail:</b>

<a href="mailto:leonardo@nikogo.net">leonardo@nikogo.net</a>

</td>

</tr>

<tr>

<td bgcolor="#DDDDEE" valign="top" width="200">

<?php include "lmenu.htm" ?>

</td>

<td valign="top">

<table width="30%" align="right" bgcolor="#EEEEEE" vspace="5"

hspace="5" cellpadding="5">

<tr><th bgcolor="#AAAAAA">Объявления администрации</th></tr>

<tr>

<td>

<?php

//Придется сначала найти общее количество объявлений

$i=1;

while (file_exists("notices/$i.txt")) $i++;

$i--;

//Теперь выведем все объявления, начиная с последнего

while ($i>0) {

echo "<p><b>".date("j/m/Y", filemtime("notices/$i.txt"))."</b> ";

include "notices/$i.txt";

$i--;

}

?>

</td>

</tr>

</table>

<h2>Добро пожаловать на сайт нашей школы!</h2>

<?php include "welcome.htm" ?>

</td>

</tr>

</table>

</body>

</html>

Поясню, что именно делает выделенный код. Во-первых, поскольку объявления добавляются в конец, более свежие объявления имеют большие номера. На странице такие объявления разумно выводить выше — так принято. Поэтому первое, что мы делаем, — находим номер последнего объявления. Для этого мы в цикле перебираем все файлы вида N.txt, пока файл с таким именем существует (это определяет функция file_exists). Когда этот цикл закончится (а он закончится, поскольку объявлений ведь не бесконечно много), надо уменьшить счетчик на 1, и мы получим номер последнего объявления.

После этого еще один цикл выводит объявления, добавляя к ним дату последней модификации соответствующего файла.

Сложно? Много технических подробностей? Хочется узнать точный формат используемых функций? Честное слово, я бы рад всю эту информацию здесь привести, но тогда, боюсь, на каждую лекцию и номера не хватит. Поэтому настоятельно рекомендую: www.php.net. Это самый полный и авторитетный ресурс по PHP, содержащий, в частности, последнюю версию документации, большая часть из которой переведена на русский.

Миллионы нас!

Ну, миллионы не миллионы, но когда объявлений накопится даже несколько десятков, страница станет изрядно перегружена. Каков выход? Можно, например, “по умолчанию” выводить не все объявления, а несколько последних. Пять, десять — это уж как захотите.

Это удобный повод научиться передавать в скрипт на PHP параметры. Допустим, мы назовем соответствующий параметр limit и договоримся управлять им так: если нам требуется вывести N последних объявлений, зададим limit равным N (например, limit=5). Если нам надо вывести все объявления, зададим в качестве значения limit слово “no”. Если же limit не будет задан вовсе, то это значит то же, что и “no”.

Параметры в скрипты передаются посредством особого синтаксиса — они указываются после вопросительного знака после имени скрипта в строке URL. Вот так:

http://myschool/php/v3/index.php?limit=2

На рис. 5 на с. 11 показан результат этого запроса, который станет нашей целью.

11-0.gif (33289 bytes)

Рис. 4. Документация по функции file_exists

11-1.gif (54006 bytes)

Рис. 5. Показаны два последних объявления

Прежде чем приступить к очередной модификации скрипта, нам надо внести изменения в настройку Denwer. Ниже я поясню, почему здесь возникли такие сложности, а пока аккуратно проделайте следующее:

1. Остановите Denwer.

2. Перейдите в каталог /usr/local/php5.

3. Найдите файл php.ini.

4. Откройте его в любом текстовом редакторе.

5. Поиском найдите строчку register_globals = Off (подсказка: в нашем комплекте Denwer — это строка 401).

6. Исправьте Off на On.

7. Сохраните файл.

8. Запустите Denwer.

Теперь обещанные пояснения. Начиная с некоторого момента в PHP “по умолчанию” часто запрещают прямой доступ к параметрам URL. Формально говоря, это правильно, так как при неаккуратном программировании такой доступ является причиной уязвимости скрипта. Например, вы используете в скрипте переменную $ok, хранящую результат какой-то проверки, и забыли инициализировать ее значением 0. Кто-то (злобный хакер) может попробовать написать в строке URL ok=1 с тем, чтобы обмануть ваш скрипт, используя не инициализированную переменную. Я не думаю, что на данном этапе начального знакомства с PHP мне имеет смысл подробно углубляться в вопросы безопасности, тем более что подавляющее большинство хостингов как раз устанавливают register_globals в On, как мы это и сделали.

Теперь создайте каталог myschool/www/php/v3, перепишите в него все файлы из v2 и модифицируйте index.php.

Файл index.php

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=windows-1251">

<title>Наша школа № 1123581321</title>

</head>

<body>

<table width="100%" cellpadding="5">

<tr bgcolor="#DDEEDD">

<td width="200"

><a href="./"><img src="logo.gif" alt="Логотип школы" width="180" height="100" border="0"

></a></

td>

<td>

<h1>Средняя школа №&nbsp;1123581321 имени Л. Фибоначчи</h1>

<p><b>Адрес:</b> 121165, г. Пиза, ул. Короля Фридриха II, д. 24.

<b>Тел.:</b> 03. <b>Факс:</b> 02. <b>E-mail:</b>

<a href="mailto:leonardo@nikogo.net">leonardo@nikogo.net</a>

</td>

</tr>

<tr>

<td bgcolor="#DDDDEE" valign="top" width="200">

<?php include "lmenu.htm" ?>

</td>

<td valign="top">

<table width="30%" align="right" bgcolor="#EEEEEE"

vspace="5" hspace="5" cellpadding="5">

<tr><th bgcolor="#AAAAAA">Объявления администрации</th></tr>

<tr>

<td>

<?php

if (!isset($limit)) $limit="no";

if ($limit!="no") $limit=0+$limit;

//Придется сначала найти общее количество объявлений

$i=1;

while (file_exists("notices/$i.txt")) $i++;

$i--;$j=0;

//Теперь выведем $limit объявлений, начиная с последнего

while (($i>0)&&(($limit==="no")||($j<$limit))) {

echo "<p><b>".date("j/m/Y", filemtime("notices/$i.txt"))."</b> ";

include "notices/$i.txt";

$i--;$j++;

}

if ($i>0) echo "<p><a href=\"./index.php?limit=no\">Все объявления</a>";

?>

</td>

</tr>

</table>

<h2>Добро пожаловать на сайт нашей школы!</h2>

<?php include "welcome.htm" ?>

</td>

</tr>

</table>

</body>

</html>

Разберем выделенный фрагмент кода подробнее.

if (!isset($limit)) $limit="no";

Напомню, что если параметр limit не задан, то будут выведены все объявления (то есть это тот же случай, что limit=no). Функция isset как раз и проверяет, определена ли данная переменная. А знаком “!” в PHP (как и в C) обозначается операция отрицания. Итак, эта строка кода означает: если не определена переменная limit, присвоить ей значение “no”

if ($limit!="no") $limit=0+$limit;

В этой строке используется прием, который для PHP является стандартным, но неизменно вызывает удивление (справедливое) и иногда возмущение (тоже справедливое) у тех, кто привык программировать на других языках. Дело здесь вот в чем. Параметры, передаваемые из URL, являются строками. То есть если, допустим, мы передадим limit=5, то значением переменной $limit будет строка “5”. Простейший способ преобразовать на PHP строку в число — выполнить с ней любую арифметическую операцию. После такого преобразования переменная станет числовой (конечно, со значением 5)

$i--;$j=0;

while(($i>0)&&(($limit==="no")||($j<$limit)))
{

echo "<p><b>".

date("j/m/Y", filemtime("notices/$i.txt")).

"</b> ";

include "notices/$i.txt";

$i--;$j++;

}

В переменной $j мы считаем количество выведенных объявлений. Содержательно условие продолжения цикла while читается так: (пока остались объявления) И ((количество выводимых не ограничено) ИЛИ (требуемое количество еще не выведено))

if ($i>0)

echo "<p><a href=\"./index.php?limit=no\">Все

объявления</a>";

Эта строка выводит ссылку “Все объявления”, если были выведены не все. Это стандартный прием

Информация от учителей физкультуры: одна минута опоздания на урок —
один дополнительный километр кросса. Будьте здоровы!

Объявления бывают разные. Бывают обычные, бывают — важные. Например, я никому бы не советовал игнорировать объявление, вынесенное в заголовок этого раздела. Давайте научимся как-то помечать при выводе важные объявления. Например, красным цветом. Но сначала надо как-то помечать соответствующие файлы. Я предлагаю вариант, который (проверено) интуитивно ясен: после номера в имени файла объявления повышенной важности ставится восклицательный знак. То есть имя выглядит как-то так: 3!.txt.

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=windows-1251">

<title>Наша школа № 1123581321</title>

</head>

<body>

<table width="100%" cellpadding="5">

<tr bgcolor="#DDEEDD">

<td width="200"

><a href="./"><img src="logo.gif" alt="Логотип школы" width="180" height="100" border="0"

></a></

td>

<td>

<h1>Средняя школа №&nbsp;1123581321 имени Л. Фибоначчи</h1>

<p><b>Адрес:</b> 121165, г. Пиза, ул. Короля Фридриха II, д. 24.

<b>Тел.:</b> 03. <b>Факс:</b> 02. <b>E-mail:</b>

<a href="mailto:leonardo@nikogo.net">leonardo@nikogo.net</a>

</td>

</tr>

<tr>

<td bgcolor="#DDDDEE" valign="top" width="200">

<?php include "lmenu.htm" ?>

</td>

<td valign="top">

<table width="30%" align="right" bgcolor="#EEEEEE"

vspace="5" hspace="5" cellpadding="5">

<tr><th bgcolor="#AAAAAA">Объявления администрации</th></tr>

<tr>

<td>

<?php

if (!isset($limit)) $limit="no";

if ($limit!="no") $limit=0+$limit;

//Придется сначала найти общее количество объявлений

$i=1;

while (file_exists("notices/$i.txt")||file_exists("notices/$i!.txt")) $i++;

$i--;$j=0;

//Теперь выведем $limit объявлений, начиная с последнего

while (($i>0)&&(($limit==="no")||($j<$limit))) {

$font_left=$font_right="";

if (file_exists("notices/$i.txt")) $filename="notices/$i.txt";

else {

$filename="notices/$i!.txt";

$font_left="<font color=\"red\">";

$font_right="</font>";

}

echo "<p>$font_left<b>".date("j/m/Y", filemtime($filename)).".</b> ";

include $filename;

echo $font_right;

$i--;$j++;

}

if ($i>0) echo "<p><a href=\"./index.php?limit=no\">Все объявления</a>";

?>

</td>

</tr>

</table>

<h2>Добро пожаловать на сайт нашей школы!</h2>

<?php include "welcome.htm" ?>

</td>

</tr>

</table>

</body>

</html>

В выделенный фрагмент кода внесены следующие изменения:

while(file_exists("notices/$i.txt")||

file_exists("notices/$i!.txt")) $i++;

Теперь нам придется проверять не только файлы вида N.txt, но и файлы N!.txt

$font_left=$font_right="";

Инициализация двух строковых переменных, в которые мы при необходимости (если объявление важное) поместим теги font для выделения цветом

if (file_exists("notices/$i.txt"))

$filename="notices/$i.txt";

else {

$filename="notices/$i!.txt";

$font_left="<font color=\"red\">";

$font_right="</font>";

}

Если существует файл N.txt, то в переменной $filename запомним его имя, а переменные $font_left и $font_right останутся пустыми строками. В противном случае (если существует файл N!.txt) запомним это в переменной $filename, а в $font_left и $font_right поместим соответственно открывающий и закрыващий теги font

echo "<p>$font_left<b>".

date("j/m/Y", filemtime($filename)).

".</b> ";

include $filename;

echo $font_right;

Если объявление было обычным, то переменные $font_left и $font_right содержат пустые строки и их вывод ничему не помешает. Зато, если объявление было важным, то эти переменные обеспечат соответствующую html-разметку

Последний штрих

По ходу этой лекции мы часто упоминали о том, как удобно бывает работать, когда код разделен на небольшие фрагменты (с этого мы начинали и разговор о SSI). Однако, постепенно усложняя скрипт, мы в результате получили уже весьма громоздкий файл index.php. Теперь было бы правильно вынести из него полученный код и тоже разместить его в отдельном файле. Это удачный повод познакомиться с функциями на PHP. Итак, сделаем следующее: создадим файл mylib.php и поместим в него весь код, ответственный за вывод объявлений. Оформим этот код в виде функции shownotices с единственным параметром $limit.

Файл mylib.php

<?php

function shownotices($limit) {

// Инкапсулируем в этой функции все, что требуется для вывода объявлений

if (!isset($limit)) $limit="no";

if ($limit!="no") $limit=0+$limit;

//Придется сначала найти общее количество объявлений

$i=1;

while (file_exists("notices/$i.txt")||file_exists("notices/$i!.txt")) $i++;

$i--;$j=0;

//Теперь выведем $limit объявлений, начиная с последнего

while (($i>0)&&(($limit==="no")||($j<$limit))) {

$font_left=$font_right="";

if (file_exists("notices/$i.txt")) $filename="notices/$i.txt";

else {

$filename="notices/$i!.txt";

$font_left="<font color=\"red\">";

$font_right="</font>";

}

echo "<p>$font_left<b>".date("j/m/Y", filemtime($filename)).".</b> ";

include $filename;

echo $font_right;

$i--;$j++;

}

if ($i>0) echo "<p><a href=\"./index.php?limit=no\">Все объявления</a>";

}

?>

А в файле index.php оставим только вызов функции.

Файл index.php

<? include "mylib.php" ?>

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=windows-1251">

<title>Наша школа № 1123581321</title>

</head>

<body>

<table width="100%" cellpadding="5">

<tr bgcolor="#DDEEDD">

<td width="200"

><a href="./"><img src="logo.gif" alt="Логотип школы"

width="180" height="100" border="0"

></a></

td>

<td>

<h1>Средняя школа №&nbsp;1123581321 имени Л. Фибоначчи</h1>

<p><b>Адрес:</b> 121165, г. Пиза, ул. Короля Фридриха II, д. 24.

<b>Тел.:</b> 03. <b>Факс:</b> 02. <b>E-mail:</b>

<a href="mailto:leonardo@nikogo.net">leonardo@nikogo.net</a>

</td>

</tr>

<tr>

<td bgcolor="#DDDDEE" valign="top" width="200">

<?php include "lmenu.htm" ?>

</td>

<td valign="top">

<table width="30%" align="right" bgcolor="#EEEEEE" vspace="5" hspace="5" cellpadding="5">

<tr><th bgcolor="#AAAAAA">Объявления администрации</th></tr>

<tr>

<td>

<?php

shownotices($limit);

?>

</td>

</tr>

</table>

<h2>Добро пожаловать на сайт нашей школы!</h2>

<?php include "welcome.htm" ?>

</td>

</tr>

</table>

</body>

</html>

На этом мы закончили содержательную часть второй лекции.

Вопросы и задания

1. Обязательно отладьте все примеры, рассмотренные в этой лекции.

2. Используя документацию на сайте www.php.net (предпочтительно) или любой справочник по PHP, тщательно проработайте код всех примеров с тем, чтобы в нем не осталось для вас “темных пятен”. Разумеется, при этом вы не овладеете в полном объеме синтаксисом языка, но освоитесь в нем и в дальнейшем будете быстрее находить ответы на вопрос: а как в PHP кодируется это? Если с чем-то не получится разобраться — обязательно пишите (координаты для связи со мной имеются в первой лекции).

3. Справились с пунктом 2? Контрольный вопрос! :) А что это за странная проверка $limit=== "no"? Почему в ней три знака “=”? И чем три знака “=” отличаются от двух?

Се. Ль. Островский

TopList