Первый сайт на PHP

Всего три файла - и гостевая книгаА можно даже два



Рисунок 9.2. Всего три файла - и гостевая книга. А можно даже два


Содержимое же файла niz.php (см. Рисунок 9.2) может быть таким (пояснения относятся к коду под ними):

<?php

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

$dirct="gb";

Ну а далее следует уже знакомый вам сценарий "Папкопотрошилки" , применяемый к этой самой папке с отзывами. Вот практически точно такой же, как и в "Папкопотрошилке", код, записывающий в массив $а[] имена всех файлов, в имени которых содержится указанный выше индекс книги:

$hdl=opendir($dirct) ;

while ($file = readdir($hdl))

if (strstr($file, $nom)!=False)

$a[]=$file;

closedir($hdl);

Примечание:

Функция strstr ищет в своем первом аргументе строку, указанную вторым аргументом, и возвращает True, если ее там находит.



Теперь отсортируем полученный массив. Для этого сначала узнаем количество сообщений книги:

$l=sizeof($a);

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

if ($l!=0)

{

rsort($a);

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

Ну и, наконец, вставим все файлы с сообщениями в страницу с гостевой книгой с помощью оператора include, перебрав последовательно элементы массива с именами этих файлов конструкцией foreach:

foreach ($a as $value)


{

include ("$dirct/$value");

echo ("<br>(разделитель сообщений)");

Как уже говорилось, foreach считывает в указанную в его параметрах переменную - в данном случае $value - все элементы массива - в данном случае $а - по очереди, выполняя каждый раз указанный после него в фигурных скобках код, в котором указанная переменная может использоваться. Поскольку в массиве первыми идут элементы с именами файлов с наиболее новыми сообщениями, то и на странице эти сообщения появятся сверху.

Комментарий:

Оператор foreach будет работать только в РНР 4.0 и выше. Если вы можете использовать лишь РНРЗ, то вместо него можно использовать цикл for, указав в его параметрах величину массива $1:

for ($k = 1; $k < $1; $k++) {

Для удобства можно записать значение очередного элемента массива в переменную: $value=$a[$k] ;

Все - код вывода имеющихся сообщений завершен!

}>

Теперь осталось разместить на странице форму для добавления нового сообщения. В ее заголовке укажем имя файла, в котором будет размещен код добавления нового отзыва - допустим, это otziv.php:

<form method="post" action="otziv.php">

Чтобы обойтись одним файлом-обработчиком новых отзывов, передадим ему в скрытом поле формы индекс гостевой книги - чтобы обработчик знал, к какой книге относится переданное ему сообщение. Для удобства назовем его так же, как и переменную, содержащую индекс - nom.

<input name="nom" type="hidden" value="<?php echo $nom; ?>">

Комментарий:

Скрытое поле (типа hidden) не отображается в браузере, однако передается вместе с формой.

Ну и - непосредственно поле ввода сообщения, уже, ясное дело, не скрытое:

<textarea name="otziv" cols="60" rows="10" wrap="virtual"></textarea>

И вездесущая кнопка отправки формы:

<input name="submit" type="submit" value="Добавить отзыв"></form>

Теперь осталось сделать программу-обработчик новых отзывов. Как это ни удивительно, но она уместится всего в пять строк. Разместить ее надо в том файле, имя которого указано в заголовке формы для ввода сообщения - в нашем случае это otziv.php (см. Рисунок 9.2).



<?php

Укажем сценарию имя папки с отзывами:

$dirct="gb";

В принципе, можно было бы это имя и передать через форму с помощью скрытого поля - типа hidden. А можно было бы и вообще не запоминать в переменную - указывать в сценарии в нужных местах само имя папки (т. е. "gb" в нашем случае) - и дело с концом. Просто так несколько нагляднее, да и в случае необходимости изменить это имя проделать данную операцию будет достаточно лишь в этом месте.

Сгенерируем имя для нового файла с сообщением - просто соединим вместе индекс гостевой книги и временную метку Unix, полученную функцией time():

$otznam=$nom.time();

Как вы помните, при передаче сценарию РНР информации через форму значения ее полей записываются в переменные, имена которых соответствуют значениям параметров пате этих полей, поэтому индекс гостевой книги, переданный через поле формы с именем пот, и оказался в переменной Snom.

Теперь создадим новый файл со сгенерированным именем и откроем его для записи - все это делается одной командой - f open с параметром w+.

Примечание:

Для того чтобы из программы на РНР считать содержимое какого-либо файла или записать в него данные, этот файл нужно сначала открыть - командой fopen (так уж устроен РНР). При этом открытому файлу присваивается некое "внутреннее имя" - так называемый дескриптор, и именно его возвращает функция fopen. Первый параметр fopen - имя файла (вместе с относительным или абсолютным путем к нему), второй — способ открытия файла.

В зависимости от второго параметра функции fopen файл может быть открыт по-разному - для чтения, для записи, с очисткой содержимого или без таковой. Возможные параметры fopen такие:

• r - открыть файл только для чтения и приготовиться читать его с начала.;

• r+ - открыть файл для чтения и для записи и приготовиться работать с ним с его начала;

• w - открыть файл только для записи, предварительно удалив из него все содержимое, причем если файл с указанным именем не существует, то создается новый файл с таким именем;



• w+ - открыть файл как для записи, так и для возможного последующего чтения, предварительно удалив из него все содержимое, причем если файл с указанным именем не существует, то создается новый файл с таким именем;

• а - открыть файл только для записи и приготовиться дописывать данные в его конец. Если файл с указанным именем не существует, то создается новый файл с таким именем;

• а+ - открыть файл для записи и для чтения и приготовиться дописывать данные в его конец. Если файл с указанным именем не существует, то создается новый файл с таким именем.

Открываемый файл может располагаться и на удаленном сервере - в этом случае он будет доступен только для чтения независимо от параметров открытия файла. Путь к файлу в таком случае следует указывать полностью - начиная с http://muftp://.

(В нашем случае можно также использовать параметр а+ - различие этих двух параметров, заключающееся в том, что fopen с параметром w+ очищает все содержимое открываемого файла, a fopen с параметром а+ нет, несущественно, так как файл все равно создается новый):

$hdl = fopen("$dirct/$otznam", "w+");

Проводить операции записи или чтения из файла средствами РНР можно только через дескриптор этого файла - некое "внутреннее имя", "поток вывода данных". Именно дескриптор, а не имя файла, придется указывать в функциях, совершающих эти действия. Дескриптор создается при открытии файла функцией fopen, которая его и возвращает -в данном случае он записывается в переменную Shdl.

Теперь запишем в открытый файл отзыв (находящийся в переменной Sotziv - именно такое имя имело поле ввода отзыва в форме для его ввода), предварительно убрав из него специальной командой, возможно, содержащиеся в нем тэги HTML и команды РНР - дабы обезопасить сайт от действий злоумышленников:

fwrite($hdl,strip_tags($otziv));

Примечание:

Команда fwrite (дескриптор файла, записываемая в файл строка) записывает указанную во втором параметре строку в файл, дескриптор которого указан в ее первом параметре.



То место в файле, с которого совершается чтение данных и в которое осуществляется запись, называется указателем файла. (Если файл представить как тетрадь, то указатель - это открытая страница, вернее, номер открытой страницы.) При открытии файла командой fopen с параметрами r, r+, w или w+ указатель файла ставится на его начало, а при открытии с параметром а или а + -в самый конец.

При записи в файл командой fwrite в том случае, если указатель находится не в конце файла, записываемые данные пишутся поверх имеющихся. Если же файл был открыт командой fopen с параметром а или a +, то вне зависимости от позиции указателя запись в файл идет в его конец, т. е. - после всех данных файла.

Функция strip tags (строка) вырезает из строки, указанной в ее параметрах, все тэги — т. е. "все в угловых скобках", как HTML, так и РНР, ASP и другие, возвращая эту строку с вырезанными тэгами. Если какие-либо тэги вырезать не следует, то их можно перечислить во втором параметре данной функции: команда

strip_tags (строка, ' <a><b><ixu> ') ;

вырежет из указанной в первом параметре строки все тэги, кроме <а>, <Ь>, </>, <и>, т. е. оставит посетителю возможность оформлять ими свой текст.

В результате злоумышленник не сможет разместить в гостевой книге ни HTML-текст, ни PHP-программу, а значит, не сможет ни испортить дизайн сайта, ни выполнить на нем какие-либо свои команды РНР.

Вместо полного удаления всех тэгов из отзыва можно провести конвертацию содержащихся в нем специальных символов - угловых скобок, кавычек, амперсандов - в их эквиваленты, просто отображающие эти символы на экране. Это делает команда htmlspecialchars:

fwrite($hdl, htmlspecialchars($otziv));

Примечание:

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



• & (амперсанд) заменяется на сочетание символов &атр;

• " ( двойная кавычка) заменяется на сочетание символов &quot ;

• < (меньше) заменяется на сочетание символов &11 /

• > (больше) заменяется на сочетание cимволов &gt ;

Сочетания символов "&атр;", "&quot;", "&lt;", "&gt;" отображаются в браузере как амперсанд, двойная кавычка, знаки "меньше" и "больше" соответственно.

В РНР третьей (начиная с подверсии 3.0.17) и четвертой (начиная с подверсии 4.0.3) версий в качестве второго аргумента можно также указать параметр ENTjQUOTES или ENTNOQUOTES. Если указан первый, то помимо вышеуказанных замен выполняется еще и замена символа ' (одинарной кавычки) на сочетание символов &#039;, а если указан второй - то никакие кавычки не заменяются.

В результате все тэги будут отображаться на экране точно так же, как при их вводе в поле ввода сообщения - т. е. не станут обрабатываться браузером или интерпретатором РНР.

Комментарий:

Любую информацию, запрашиваемую от посетителя и впоследствии выводимую на какую-либо страницу, весьма желательно перед выводом обработать какой-нибудь из этих функций, htmlspecialchars или strip_tags, - для обеспечения устойчивости сайта к взлому. Ибо даже в том случае, если вы на одной странице запрашиваете у посетителя e-mail, а на другой - его выводите на страницу, злоумышленник в поле ввода e-mail'a может поместить код на РНР, и тогда, будучи включенным в выведенную страницу без какой-либо обработки, этот код благополучно исполнится! А ведь в этом коде может быть что угодно - вплоть до команд удаления файлов. Поэтому не забывайте обрабатывать данными функциями все информацию, что была введена в элементы формы и будет отображаться на какой-либо странице.

Даже скрытые поля и выпадающие списки могут нести в себе угрозу безопасности сайта - если получаемая из них информация выводится на экран. Ничто не мешает злоумышленнику сделать локальную копию страницы с формой на своем жестком диске, прописать в качестве страницы-обработчика полный путь к ней - вместе с адресом сайта и изменить в форме содержимое любых полей, в том числе и скрытых, поместив туда PHP-код. Так что будьте бдительны!



Если Вы желаете, чтобы при отображении на странице сообщений сохранялась их разбивка отправителями на абзацы, то обработайте записываемое в файл сообщение командой nl2br для конвертации символов конца строки в тэги <br>, которые этот разрыв строки и означают:

fwrite($hdl,nl2br(strip_tags($otziv)));

или, если хотите, запишите все команды обработки записываемого сообщения в две строки:

$otziv=nl2br(strip_tags($otziv)); fwrite($hdl,$otziv);

Примечание:

Функция nl2bг (строка) вставляет перед каждым символом начала строки, встреченном в строке в ее параметре, тэг <br> -в РНР версии до 4.0.5, или <Ъг /> - в РНР более поздних версий. (Последний тэг совместим и с языком XML.)

Файл можно закрыть - и закончить сценарий.

fclose($hdl);

?>

Такой код будет работать в РНР версии 3. В РНР версии 4 и выше с этим кодом тоже проблем не будет, однако лишь в том случае, если в конфигурационном файле РНР установлена как on опция register_globals. Настройка данного файла - прерогатива администратора web-сервера (хотя по умолчанию данная опция включена). Если register_globals установить в off, то переменные формы по их именам в сценарии-обработчике доступны не будут.

Однако все переменные, передающиеся через форму, записываются еще и в специальный массив - с именем $HTTP_POST_VARS (если передача произведена методом post - т. е. в адресной строке значения передаваемых переменных не отображаются; вид передачи указывается в заголовке формы) или $HTTP_GET_VARS (если передача произведена методом get-с отображением в адресной строке передаваемых переменных). В РНР4 так происходит всегда, а в РНРЗ - только в том случае, если в конфигурационном файле РНР (настраиваемом администратором web-сервера) установлена как on опция track_vars. Элементы этих массивов названы именами этих переменных; так, переменная, указанная в поле с именем otziv формы, передающей введенные в нее значения методом POST сценарию в файле scen.php, будет доступна в этом сценарии в элементе массива $HTTP_POST_VARS['otziv'].



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

<?php

$dirct="gb";

$otznam=$HTTP_POST_VARS['nom'].time();

$hdl = fopen("$dirct/$otznam", "w+");

fwrite($hdl,nl2br(strip_tags($HTTP_POST_VARS['ot ziv1])));

fclose($hdl);

?>

Начиная с РНР версии 4.1, кроме массивов $HTTP_POST_VARS и $HTTP_GET_VARS, программе на РНР доступны идентичные им массивы $_POST и $_GET, так что в том случае, если на сервере, где должны быть размещены ваши сценарии, установлен РНР этой или более старшей версий, то вы можете использовать и такие имена.

Версию РНР вы можете узнать, включив в сценарий команду phpinf о ();. Она даст исчерпывающую информацию как по этому, так и по множеству других вопросов.


Содержание раздела