Учебники профессионалов ЭЛЕКТРОННЫЕ
УЧЕБНИКИ
ПРОФЕССИОНАЛОВ
PHP
  • Введение
  • Глава 1. Немного о Web-программировании
  • Глава 2. PHP: История. Места. Источники.
  • Глава 3. PHP: Основы
  • Глава 4. PHP: Выборочная загрузка
  • Глава 5. PHP: Простейший интернет-магазин
  • Глава 6. PHP: Папкопотрошилка
  • Глава 7. PHP: Закачка файлов
  • Глава 8. PHP: Авторизация доступа
  • Глава 9. PHP: Гостевая книга
  • Глава 10. PHP: Система оценки материалов
  • Глава 11. PHP: Файловый менеджер
  • Глава 12. PHP: Полезные мелочи
  • Глава 13. PHP: Способы передачи данных между отдельными страницами
  • Заключение
  • Приложение 1. Преврати свой сайт в портал
  • Приложение 2. Используй то, что под рукою - и не ищи всегда другое
  • Приложение 3. На сайте - как в "Винде"


WWW.UCHPRO.RU - Учебники профессионалов

УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 1. НЕМНОГО О WEB-ПРОГРАММИРОВАНИИ

  • Несколько терминов
  • Немного о Web-программировании


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

НЕСКОЛЬКО ТЕРМИНОВ

Web-программирование - разработка любых программных продуктов, предназначенных для работы на сайтах World Wide Web. Строго говоря, даже разработка web-страниц на чистом HTML является web-программированием, ведь при просмотре страницы браузер фактически исполняет код HTML, форматируя текст согласно инструкциям этого языка. В настоящее время под web-программированием понимают создание CGI-приложений и использование на web-странице технологий JavaScript и VBScript для достижений сложных эффектов.
Web-сервер - программа, запущенная на узле сети Интернет и выдающая посетителям этого узла web-страницы по запросам. Также web-сервером часто называется узел, на котором эта программа запущена, или даже компьютер, являющийся таким узлом.
CGI (сокращение от Common Gateway Interface) - технология, позволяющая запускать на web-сервере программы, имеющие возможность получать данные от посетителей сайтов, поддерживаемых этим web-сервером, и в свою очередь выдавать им обработанные данные в виде web-страниц или других файлов. Для использования технологии CGI программа web-сервер должна удовлетворять определенным критериям - "поддерживать CGI". Если программа, запускаемая на web-сервере, представлена не двоичным кодом (т. е. скомпилированным файлом), а текстовым, то для ее выполнения требуется программа-интерпретатор того языка, на котором написана эта программа. Такой интерпретатор включается в состав web-сервера и вызывается им при необходимости заняться выполнением программного кода.
CGI-сценарий (CGI-скрипт) - программа (в текстовом виде), предназначенная для исполнения на web-сервере. Для создания CGI-скриптов можно использовать любой язык программирования -важно лишь, чтобы на том web-сервере, где предполагается эту программу запускать, имелся интерпретатор этого языка.
Препроцессор - программа, работающая совместно с web-сервером, которая просматривает все или некоторые файлы, выдаваемые web-сервером посетителям, и выполняет над ними определенные действия в зависимости от содержащихся в этих файлах инструкций. РНР является именно препроцессором, что, собственно, и видно из его названия.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

НЕМНОГО О WEB-ПРОГРАММИРОВАНИИ

Все языки программирования, используемые при разработке web-сайтов, можно разделить на две большие группы.
К первой относятся те из них, код которых выполняется на компьютере посетителя сайта, т. е. в браузере, запущенном на компьютере пользователя. Это известные всем JavaScript и VBScript. Программы на этих языках встраиваются в код web-страниц или выносятся в отдельный файл, обращение к которому осуществляется из web-страницы (в этом случае браузер все равно обрабатывает такие «вынесенные» программы таким же образом, как если бы они были встроены в код страницы).
Во вторую группу включаются те языки, программы на которых выполняются на том компьютере, где расположен web-сервер. Эта группа более обширна - дело в том, что в принципе на web-сервере могут исполняться программы на любом языке, даже командных .bat-файлов MS-DOS, важно лишь, чтобы на нем была установлена программа-интерпретатор этого языка, удовлетворяющая стандарту CGI, которому также должен удовлетворять сам web-сервер.
РНР относится ко второй группе - программа на РНР исполняется на web-сервере. Однако от других CGI-языков РНР сильно отличается в лучшую сторону прежде всего своей простотой. При создании программы на РНР нет необходимости учитывать все те многочисленные мелочи, которые отравляют жизнь программистам на Perl или C++, - не надо заботиться о правах доступа к файлам сценария, не надо прописывать точные пути к различным модулям, нет необходимости следить за отсутствием в файле скрипта недопустимых символов. Синтаксис языка РНР допускает его легкое освоение как начинающим программистом, так и тем, кто уже использовал ранее какой-либо язык программирования. Можно целиком и полностью сосредоточиться на решаемой задаче и не думать о мелочах. Именно это и делает РНР подходящим выбором для web-дизайнера, который, начав его использовать, может вообще забыть о каких-либо других CGI-языках. (Впрочем, если исходить из механизма действия, то РНР более правильно называть не "CGI-языком", а препроцессором - что, собственно, отражено даже в его названии. В то время как CGI-приложение просто выдает некие данные в браузер посетителя, препроцессор просматривает все или некоторые файлы, выдаваемые web-сервером посетителю, и ищет в них определенные команды, которые и выполняет. Именно такой способ работы и позволяет указывать код программ на РНР непосредственно в тексте web-страниц.)
Одним из наиболее заметных достоинств РНР является возможность без особых затруднений работать с серверами баз данных. Ранее, до появления этого языка, задание, выражающееся словами "приделать базу данных к web-странице", было довольно трудным и малодоступным для начинающих web-дизайнеров. Приходилось либо самостоятельно разрабатывать хитроумные скрипты, взаимодействующие как с программой управления базой данных, так и с web-страницами сайта, либо закупать их у фирм-разработчиков. С помощью же РНР использование базы данных на сайте стало едва ли не элементарным. Для работы с подавляющим большинством типов баз данных в РНР есть встроенные функции, поэтому теперь достаточно лишь установить на web-сервере программу работы с базой данных (наиболее часто используется бесплатная MySQL - http://www.mysql.com) и включить в текст PHP-сценария команды работы с нею (их список приведен в описании языка вместе с примерами использования).
Возможности РНР можно весьма серьезно расширить с помощью дополнительных модулей, содержащих различные функции. Эти модули при необходимости размещаются на web-сервере, на котором установлен PHP-интерпретатор. Большое количество готовых модулей можно загрузить с адреса http://www.php.net, там же в разделе документации приведено и полное их описание. (В том web-сервере с установленным РНР, который распространяется с сайта http://php.spb.ru, никаких дополнительных модулей нет для уменьшения размера дистрибутива.) Например, модуль Zlib позволяет работать из программы на РНР с архивами в формате Gzip, а модуль libswf - с Flash-презентациями, создавая и редактируя их прямо из программы на РНР.

Рис. 1.1. Вся информация о сервере и интерпретаторе - одной командой phpinfo()


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 10. РНР: СИСТЕМА ОЦЕНКИ МАТЕРИАЛОВ

  • РНР: система оценки материалов
  • Файл niz.php
  • Файл otziv.php
  • Текст сценария


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

PHP: СИСТЕМА ОЦЕНКИ МАТЕРИАЛОВ

В этой главе будет разобран сценарий, позволяющий посетителям выставлять оценки размещенным на сайте материалам. Ранее не использованных команд в нем почти нет, так что просто следите за логикой программы.
Сначала подумаем. Что должен делать код выставления оценки? Ну вначале, наверное, принимать от посетителя значение оценки (скажем, из формы с элементами <select. . .>. . .<option>. . ..). Однако, если эта оценка является первой за всю историю существования статьи, то необходимо записать ее в файл. Если же ранее статья уже была оценена, то следует считать имеющееся значение из файла и вычислить среднее арифметическое всех оценок, включая только что добавленную. В самом деле, нам ведь нужна именно средняя оценка, не так ли? А затем это новое значение средней оценки необходимо в тот же файл и записать.
Среднюю оценку можно посчитать по очевидной формуле

(средний балл*количество оценок)+новодобавленная оценка /
количество оценок + 1

Кроме того, среднюю оценку желательно показать и посетителю. Простая вставка файла с оценкой в страницу со статьей с помощью команды include не является изящным решением, так как значение средней оценки может быть выражено и довольно длинной десятичной дробью. Следовательно, оценку желательно округлить хотя бы до сотых, а лучше - до десятых.
Далее. Что должно произойти, когда посетитель выставит статье оценку? Первое, что приходит в голову - это отправить его назад на статью, которую он оценивал. Ведь направляли же мы в сценарии в прошлой главе посетителя назад в гостевую книгу после отправки им в.нее сообщения? Однако посетитель уже ведь прочитал статью, - зачем ему ее выводить снова, тратя его время в Сети, а, значит, и деньги. Куда как лучше после выставления оценки отправлять посетителя на специальную страницу с благодарностью о выполненном им действии и каталогом статей или разделов сайта.
Желательна также и реализация "защиты от накруток", т. е. нельзя давать одному и тому же посетителю возможность голосовать несколько раз. Для этого можно использовать cookie, т. е. помечать с помощью cookie браузер посетителя при выставлении им оценки и впоследствии позволять выставлять оценку только при отсутствии такого cookie.

Комментарий:
Cookie - это файл в специальном формате, который присылается сервером браузеру посетителя сайта, расположенном на этом сервере. Браузер, если он поддерживает cookie (и эта поддержка в нем не отключена), помещает его в особое место и впоследствии отправляет назад на сервер при поступлении от него запроса. Иными словами, cookie позволяет серверу хранить свою информацию на компьютерах посетителей и считывать ее оттуда при необходимости. Подробнее о cookie читайте в гл. 8.

Бесспорно, использование cookie - не очень надежная подобная защита. Ничего не мешает посетителю удалять cookie перед каждой новой попыткой выставления оценки или использовать разные браузеры, да и на общедоступных компьютерах проголосовать можно будет лишь единожды независимо от числа их пользователей до тех пор, пока cookie не будет удален. Но хоть что-то...
Наверняка на сайте будет находиться немало статей, к которым стоит добавить форму выставления оценок. Для того чтобы не вставлять в каждый файл множество строк одинакового кода, стоит выполнить весь код выставления оценки в отдельном модуле и включать его с помощью команды include в статьи, оценка которых посетителями необходима.
Итак, код выставления оценок разместится в двух файлах, один из которых предназначен для вставки в страницы со статьями, а второй содержит в себе текст благодарности посетителю за оценку. Допустим, первый файл будет называться niz.php, а второй - otziv.php. Что ж, приступим к самому тексту кода.
В каждый файл со статьей, в то место, где должна располагаться форма для выбора оценки, следует вставить одну строчку кода:

<?php include ("niz.php"); ?>


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ФАЙЛ NIZ.PHP

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

<?php

Файлы со значениями среднего балла и количества оценок будут храниться в папке с именем cnt. Запишем для удобства ее имя в переменную:

$dirct="cnt";

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

$nom=substr(basename($PHP_SELF), 0, -4);

...а сами файлы назовем на основе этого имени, получив имя файла с количеством оценок прибавлением к нему окончания "kol", а имя файла со средним баллом - окончания "est" (рис. 10.1):

$kolvooc="$nom"."kol"; $ocenka="$nom"."est";

Рис. 10.1. Файлы системы оценивания.
Слева - статьи, файлы со сценариями и папка с файлами оценок, справа -содержимое этой папки

Теперь выведем сведения об уже выставленных оценках.

echo ("Оценок этой статье - ");

Если файл со сведениями о количестве оценок существует (он создается при первом оценивании)...

if (file_exists("$dirct/$kolvooc")==True)
{

...то вставим его значение в документ.

include ("$dirct/$kolvooc");

Если же такового файла нет, т. е. документ ни разу не оценивался...

}
else
{

...выведем значение "0".

echo ( " 0 " ) ;
}

Если файл со средним баллом существует...

if (file_exists("$dirct/$ocenka")==True)
{

...то надо вывести его значение.

echo (". Средний балл - ");

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

$hdl в fopen("$dirct/$ocenka", "r+");

...и считаем в переменную Ssred все содержимое этого файла.

$sred = fread($hdl, filesize("$dirct/$ocenka"));

Примечание:
Функция fread (дескриптор файла, длина считываемого фрагмента) считывает из открытого файла, для которого получен указанный в ее первом параметре дескриптор, столько байт, сколько указано в ее втором параметре (чтение начинается с местонахождения так называемого указателя файла — отметки, показывающей текущее место работы с файлом; указатель двигается при чтении или записи в файл, а также при использовании команды fseek).
Функция filesize (полный путь к файлу) возвращает размер указанного в ее параметре файла в байтах.

Файл можно закрыть...

fclose($hdl);

...а переменную $sred - округлить до десятых

$sred=round ($sred, 1);

Примечание:
Функция round (число, количество разрядов) округляет дробное число в ее первом параметре до количества разрядов, указанного в ее втором параметре. Скажем, round (число, 1) округлит число до десятых, round (число, 2) - до сотых и т. д.

В РНР до четвертой версии функция round могла округлять числа только до целых, поэтому в том случае, если вы располагаете только такой версией РНР, то команда округления до десятых должна выглядеть как

$sred=(round ($sred*10))/10; ...и вывести на страницу.
echo ("$sred.");
}

Имя cookie, в котором будет находиться информация о том, голосовал ли посетитель за данную статью или нет, тоже будет образовываться из имени файла статьи. Запишем это имя в переменную $haveestim...

$haveestim=$nom."haveest";

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

if ($$haveestim=="")

Обратите внимание на имя проверяемой переменной - это имя само является значением переменной Shaveestim (подобную конструкцию допускают правила РНР, подробнее смотрите в гл. 3).

Рис. 10.2. Содержимое cookie - пометки о состоявшемся голосовании

Поскольку значения cookies доступны и через массив $HTTP_COOKIE_VARS[], то проверить наличие cookie можно и на основе анализа значений этого массива:

if ($HTTP_COOKIE_VARS[$haveestim]=="")

или в РНР версии 4.1 и выше

if ($_COOKIE[$haveestim]==" ")

Комментарий:
Помните, что доступность данных cookie зависит от настроек в файле php.ini (рис.10.3) - если в файле php.ini установлен в on параметр register_globals, то содержимое cookie доступно в сценарии в переменной с тем же именем, что и cookie, а если ephp.ini установлен в on параметр trackjvars, то содержимое cookie доступно в сценарии в одноименном с этим cookie элементе массива SHTTPCOOKIEVARSfJ (с РНР 4.1 -и $_СООК1Е[]).

Использовать массивы $HTTP_COOKIE_VARS[] и $_СООК1Е[] лучше с точки зрения безопасности. Если в сценарии используются одноименные cookie переменные, а не элементы этих массивов, то в том случае, если cookie не установлен, злоумышленник все равно может передать сценарию значение такой переменной, попросту указав его в адресной строке браузера. В указанные же массивы попадают исключительно полученные с cookie данные. Однако в рассматриваемом в данной главе сценарии это несущественно. 118

Рис. 10.3. Файл php.ini. Вышеупомянутые настройки

Если cookie не установлен - т. е. посетитель ранее не голосовал за данную статью...

{

то выведем ему форму для голосования

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

Передадим в скрытом поле формы имя файла со статьей без расширения - для определения на основе него сценарием-обработчиком имен файлов со сведениями о количестве оценок и среднем балле, а также полное имя, вместе с путем, файла со статьей - для вывода ссылки "Назад" на странице со сценарием-обработчиком. В принципе можно было бы передавать через форму только полное имя файла со статьей, а "чистое" имя файла статьи определять в сценарии-обработчике точно так же, как и в сценарии из niz.php - на основе функции basename, но для сокращения длины кода в обработчике воспользуемся передачей его через форму.

<input name="nom" type="hidden" value="<?php echo $nom; ?>">
<input type=hidden name=nazad value=<?php echo ($PHP_SELF); ?>>

Выведем форму ввода оценки:
Поставьте оценку статье:

<SELECT NAME=ocen>
<OPTION VALUE=5>5 (Отлично)
«DPTION VALUE=4>4 (Хорошо)
<OPTION VALUE=3>3 (Удовлетворительно)
<OPTION VALUE=2>2 (Плохо)
<OPTION VALOE=1>1 (Очень плохо)
</SELECT>

В результате в сценарий-обработчик будет передана переменная Socen (и одноименные элементы массивов $HTTP_POST_VARS, $_POST при соответствующих версиях РНР и настройках в php.ini) со значением, равным параметру value выбранного пользователем пункта выпадающего списка.
Выведем кнопку отправки формы (рис. 10.4).

Рис. 10.4. Система оценивания в действии...

<input name="submit" type="submit" value="Послать оценку"></form>
<?php

А если посетитель уже голосовал за данную статью - т. е. cookie с соответствующим именем у него установлен...

}
else {

...то сообщим ему об этом (рис. 10.5).

echo ("Вы уже голосовали за эту статью!");

Рис. 10.5. ...но голосование уже состоялось

Вот и все.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ФАЙЛ OTZIV.PHP

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

<?php

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

$namecook=$nom."haveest";

...и весь дальнейший код выполним только в том случае, если такого cookie установлено не было.

if ($$namecook=="")

Примечание:
Вместо этой строки можно использовать строку
i f ($HTTP_COOKIE_VARS[$haveestim]=="") или в PHP версии 4.1 и выше — строку
if ($_COOKIE[$haveestim]=="") как уже указывалось выше.

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

Итак, если посетитель еще не голосовал за данную статью...

{

...установим cookie, говорящий, что такое голосование наконец совершилось. Время жизни cookie установим в месяц - пожалуй, хватит. (Пояснение по функции установки cookie смотрите в гл. 8).

SetCookie("$namecook","1",time()+2 592000);

Запишем в переменные имена директории с файлами оценок и самих этих файлов:

$dirct="cnt";
$kolvooc="$nom"."kol";
$ocenka="$nom"."est";

Если файлы оценок не существуют (т. е. выставляемая оценка - вообще первая по счету)...

if ((file_exists("$dirct/$kolvooc")!=True)||
(file_exists("$dirct/$name2")!=True)) {

...то запишем в файл со сведениями о количестве оценивших число 1 (так ведь и есть, не правда ли?)...

$hdll = fopen("$dirct/$kolvooc", "a+"); fwrite($hdll,l); fclose($hdll);

...а в файл со сведениями о среднем балле - выставленную посетителем оценку (она ведь и есть "среднее" от самой себя):

$hdl2 = fopen("$dirct/$ocenka", "a+");
fwrite($hdl2,$ocen);
fclose($hdl2);

Если же файлы со сведениями об оценке уже существуют...

else

...то считаем для начала содержимое файла с количеством оценок в переменную

kvo...
$hdll = fopen("$dirct/$kolvooc", "r+");
$kvo ¦ fread($hdll, filesize("cnt/$kolvooc"));

...а затем увеличим значение этой переменной на 1 - что и будет новым количеством оценок, с учетом последней выставленной:

$kvo++;

Теперь нам надо вернуть точку считывания (так называемый "указатель") в начало файла - для того, чтобы записать в файл новое значение количества оценок. Ведь в результате проведения операции чтения количества оценок из файла точка считывания - указатель - переместилась в его конец. Для совершения данной операции воспользуемся командой rewind:

rewind($hdll);

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

Запишем новое значение количества оценок в предназначенный для хранения этой величины файл...

fwrite($hdll,$kvo);

...и закроем его.

fclose($hdll);

Теперь разберемся со средним баллом. Откроем файл, где хранится его значение...

$hdl2 = fopen("$dirct/$ocenka", "r+");

...запишем это значение в переменную...

$sred= fread($hdl2, filesize("cnt/$ocenka"));

...и рассчитаем новую величину среднего балла - на основе его старого значения, а также информации о количестве оценок и новой оценки.

$sred=($sred*($kvo-l)+$ocen)/$kvo;

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

rewind($hdl2); fwrite($hdl2,$sred); fclose($hdl2);

Собственно, и все.
Можно выводить информацию посетителю об итоговом результате (рис. 10.6) или краткую благодарность.

echo ("Благодарим вас за оценку!");

Рис. 10.6. После успешного голосования

Рис.10.7. После попытки повторного голосования

Если же посетитель уже голосовал за данную статью...

}
else {

...то сообщим ему об этом (рис. 10.7) - и ничего делать не станем, echo ("Вы уже голосовали за эту статью!");

}
Сценарий закончен. ?>

Остальной текст страницы - на ваше усмотрение. Разместите на ней каталог разделов сайта, список статей или просто красиво оформите. Если же пожелаете поставить на ней ссылку на оцениваемую статью - то просто разместите в нужном месте выводящий эту ссылку код:

<?php echo ("<a href=$nazad>Ha3afl</a>"); ?>

Переменная Snazad была передана через форму, помните?

Комментарий:
В данном сценарии для упрощения восприятия значения переменных, передаваемых через форму, брались из одноименных переменных в сценарии-обработчике - так как на безопасность работы программы это здесь не влияет: даже если злоумышленник подставит значение переменной cookie в адресную строку, то он только потеряет возможность проголосовать, и ничего больше. Если вы желаете сделать код лучше соответствующим правилам РНР - замените их на одноименные элементы массива $HTTP_POST_VARS[] (в РНР версии до 4.1) или SPOSTfJ (в РНР версии 4.1 и старше).

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ТЕКСТ СЦЕНАРИЯ

Для большей наглядности ниже приводится текст сценария целиком, без разрывов.

Вставка в файлы со статьями:

<?php include ("niz.php"); ?>

Файл niz.php

<?php
$dirct="cnt";
$nom=substr(basename($PHP_SELF), 0, -4); $kolvooc="$nom"."kol"; $ocenka="$nom"."est"; echo ("Оценок этой статье - "); if (file_exists("$dirct/$kolvooc")==True) {
include ("$dirct/$kolvooc"); }
else {
echo (" 0") ; }
if (file_exists("$dirct/$ocenka")==True) {
echo (". Средний балл - "); $hdl = fopen("$dirct/$ocenka", "r+"); $sred = fread($hdl, filesize("$dirct/$ocenka")); fclose($hdl); $sred=round ($sred, 1); echo ("$sred."); }
$haveestim=$nom."haveest"; if ($$haveestim=="")
<form method="post" action="otziv.php">
<input name="nom" type="hidden" value="<?php echo $nom; ?>">
<input type=hidden name=nazad value=<?php echo ($PHP_SELF); ?>>
Поставьте оценку статье:
<SELECT NAME=ocen>
<OPTION VALUE=5>5 (Отлично)
<OPTION VALUE=4>4 (Хорошо)
<OPTION VALUE=3>3 (Удовлетворительно)
<OPTION VALUE=2>2 (Плохо)
<OPTION VALUE=1>1 (Очень плохо)
</SELECT>
<input name="submit" type="submit" value="Пocлaть оценку"></form>
<?php
}
else {
echo ("Вы уже голосовали за*эту статью!"); } ?>

Файл otziv.php

<?php
$namecook=$nom."haveest"; if ($$namecook=="") {
SetCookie("$namecook","1",time()+2592000);
$dirct="cnt";
$kolvooc="$nom"."kol";
$ocenka="$nom"."est";
if ((file_exists("$dirct/$kolvooc")!=True) ||(file_exists("$dirct/$name2")!=True))
{
$hdll = fopen("$dirct/$kolvooc", "a+");
fwrite($hdll,1)j
128
fclose($hdll);
$hdl2 = fopen("$dirct/$ocenka", "a+");
fwrite($hdl2,$ocen);
fclose($hdl2);
else
$hdll = fopen("$dirct/$kolvooc", "r+");
$kvo = fread($hdll, filesize("cnt/$kolvooc"))
$kvo++;
rewind($hdll);
fwrite($hdll,$kvo); .
fclose($hdll);
$hdl2 = fopen("$dirct/$ocenka", "r+");
$sred= fread($hdl2, filesize("cnt/$ocenka"));
$sred=($sred*($kvo-l)+$ocen)/$kvo;
rewind($hdl2);
fwrite($hdl2,$sred);
fclose($hdl2);
echo ("Благодарим вас за оценку!"); else echo ("Вы уже голосовали за эту статью!");

Ниже в этом же файле:

<?php echo ("<a href=$nazad>Ha3afl</a>"); ?>


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 11. РНР: ФАЙЛОВЫЙ МЕНЕДЖЕР

  • РНР: файловый менеджер
  • Проектирование
  • Файл index.php
  • Файл zapros.рнр
  • Файл do.рнр
  • Текст сценария


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

PHP: ФАЙЛОВЫЙ МЕНЕДЖЕР

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПРОЕКТИРОВАНИЕ

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

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

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

Комментарий:
Функция перемещения файлов раскладывается на два этапа — их копирование в другую папку и удаление с исходного места. Рассматриваемый в этой главе файловый менеджер позволяет и копировать, и удалять файлы, так что переместить файлы сего помощью тоже возможно. При желании вы можете впоследствии дополнить его функцией перемещения, попросту совместив подпрограммы копирования и удаления файлов.

Как все это сделать?
Как посетителю выбрать вид действия над файлами? Можно, конечно, выделить для каждого указанного выше действия по отдельной web-странице, разместить на этих страницах соответствующие сценарии, при этом для их выполнения посетителю придется заходить на нужную страницу. Однако это весьма неудобно. Лучше дать посетителю возможность выбирать вид действия прямо на той же самой странице, где отображается список файлов.
Как осуществить такой выбор действия? Можно, конечно, создать группу единственного выбора, состоящую из нескольких radio buttons (она представляет собой группу кружков, отметить из которых можно только один - рис. 11.1, слева), а в сценарии выполнения действия определять, какой пункт был отмечен. Однако интереснее будет для выбора действия использовать кнопки типа submit (рис. 11.1, справа), нажатие которых вызовет переход на страницу-обработчик формы, содержащей эти кнопки. Посетитель, отметив файлы, просто нажмет нужную кнопку и будет ждать результата.

Рис. 11.1. Способы выбора действия. Лучше тот, что справа.

Комментарий:
Возникает вопрос: а как сценарий-обработчик различит, какая кнопка из четырех была нажата? Очень просто. Каждой кнопке необходимо присвоить имя и проверять в сценарии-обработчике значение переменной с этим именем. Кнопка - это часть формы, следовательно, для нее тоже создается переменная с тем же именем, а также элементы массивов $ HTTP_POST_VARS[имя кнопки] и в РНР версии 4.1 и старше - и $ POST [имя кнопки]. Обработка формы происходит так, что в ту переменную, имя которой совпадает с именем нажатой кнопки, будет помещено значение value этой кнопки (т. е. то, что было надписью на ней), переменные же остальных трех кнопок будут пустыми. На основании «пустоты» или «непустоты» соответствующих переменных и будем судить о том, какое действие выбрал посетитель.

Для того, чтобы посетитель имел возможность указать сценарию объекты действий - т. е. над какими файлами эти действия должны производиться - достаточно против каждого имени файла поставить checkbox (пункт, который можно отметить галочкой, см. на рис. 11.3-11.6), разместив все checkbox'bi в единой форме, а затем анализировать состояние checkbox`ов в программе-обработчике формы.
Итак, в первом файле нашего файлового менеджера должна располагаться форма, содержащая список файлов и папок в текущей директории (выводимый специальным сценарием, позволяющим также перемещаться по вложенным папкам) со спескЬох'ами возле каждого названия файла или папки, а в низу формы должны располагаться четыре кнопки типа submit с различными именами.
Но простого выбора действия недостаточно для начала его выполнения. Перед тем, как совершать работу, у посетителя необходимо еще выяснить:

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

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

  • основной, отображающий список файлов в директории, позволяющий также перемещаться по дереву папок, отмечать нужные и выбирать тип действия над ними. Назовем его index.php.
  • файл запросов, запрашивающий у посетителя информацию для совершения выбранного действия - место назначения копирования, новые имена для переименованных файлов, имя для новосозданной папки или выдающий запрос на подтверждение удаления. Назовем его zapros.php.
  • файл действия, собственно выполняющий выбранное действие, а после его выполнения - автоматически перенаправляющий посетителя на основной файл.

Графическую схему смотрите на рис. 11.2.

Рис. 11.2. Схема сценария файлового менеджера

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ФАЙЛ INDEX.PHP

Сценарий в этом файле отображает список файлов и предоставляет посетителю возможность выбрать файлы для совершения над ними действия и вид этого действия.
Сначала в сценарии производится вывод на страницу списка файлов и папок в текущей директории и предоставляется возможность открыть любой файл или перейти в другую папку.
Просканировать папку и вывести список файлов можно с помощью сценария наподобие "Папкопотрошилки", описанного в 6-й главе. Поскольку планируется использовать одну и ту же страницу для отображения содержимого как корневой, так и любой из вложенных папок, то сценарию на этой странице нужно знать, список файлов в какой конкретно папке ему отображать, а также как составить ссылки на эти файлы, с указанием какого пути -"чтобы из файлового менеджера их можно было просматривать.
Проще всего передавать сценарию информацию о том, список содержимого какой папки подлежит выводу на экран, через переменную в адресной строке - попросту указав в ней путь от корневой папки к текущей. Скажем, если корневая папка имеет название files, то она будет открываться по ссылке index.php?f old=f iles, а вложенная в нее папка folded - по ссылке index. php?f old= files /folder 1. (Как видно из текста ссылок, информация о пути к текущей папке будет доступна сценарию на странице из значения переменной Sfold, и именно значение этой переменной и будет подставляться в сценарии в качестве имени папки для сканирования.)
Например, на рис. 11.3 файловый менеджер отображает содержимое папки f iles/Folder2/Folder3. Обратите внимание на адресную строку браузера.

Рис. 11.3. Файловый менеджер в работе

Комментарий:
Нетрудно заметить, что подобная конструкция весьма уязвима для взлома. В самом деле, - если подставить вместо имени корневой папки - files — имя любой другой папки, находящейся на том же уровне, что и папка files, то сценарий "Патопотрошилки" тихо-спокойно выведет и ее содержимое, - чего, возможно, делать не следует, а оно для этого может быть совсем не предназначено! А если указать в пути вместо имени каталога символы /../ (двумя точками обозначается родительский каталог, одной - текущий), то посетитель сможет добраться и до корневой папки всего сайта, и фактически получит возможность удалять, переименовывать, просматривать все файлы на сайте-аккаунте, так как весь сайт будет в его распоряжении.
Изменить же адресную строку - задача совсем не сложная, просто наилегчайшая. Поэтому такое положение дел, понятно, не так
и безопасно... Следовательно, поэтому в сценарий вывода списка файлов следует добавить проверку содержимого переменной Sfold, в которой путь к текущей папке и передается. - Наверное, на первое время хватит двух условий: чтобы путь к текущей папке начинался с имени корневой папки, в которой содержатся доступные посетителю файлы, и чтобы в этом пути не было символов "..", т. е. - двух точек подряд (в нормальных именах файлов такового встречаться не должно).
Впрочем, если вы предоставляете кому бы то ни было право размещать файлы на вашем сайте, то тому, кто их размещает, не составит труда поместить на сайт файл с программой на РНР, производящей любые действия (хотя бы собственную версию файлового менеджера без упомянутых ограничений), и тем самым получить контроль над всем сайтом, - в том числе даже над корневой директорией. Так что описанные в этом комментарии приемы - это, скорее, "защита от дурака", от того, кто уже может изменить адресную строку, но еще не способен писать программы на РНР.

На странице со списком файлов в какой-либо директории должна быть также ссылка на список файлов в той папке, в которую текущая папка вложена. Проще всего получать такую ссылку на основании пути к текущей папке, попросту отсекая отдюлного пути ее имя.
Впрочем, все это вы увидите в сценарии. Красивому оформлению страницы со списком файлов времени уделять не будем, его вы сможете сделать самостоятельно. Также в начало сценария файлового менеджера и на каждую его страницу вы можете вставить скрипт авторизации, вроде того, который описан в гл. 8-й (только не забудьте, что помещать такой скрипт надо до какого-либо вывода в браузер, будь то команда echo, текст web-страницы или что-то другое.).
Итак, начинаем:

<htmlx?php

Укажем корневую папку аккаунта посетителя - т. е. ту, с файлами и папками в которой ему разрешено работать, и запишем ее имя в переменную для дальнейшего использования в сценарии. Пусть эта папка называется files.

$begin="files";

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

Теперь проверим:

  • определена ли вообще содержащая путь к отображаемой папке переменная $fold (т. е. присутствует ли она в адресной строке - ее там не будет, если к странице с файловым менеджером обратились по внешней ссылке, а не с этой же страницы по ссылке на какую-либо папку из списка файлов и папок);
  • не содержит ли она двух точек подряд - признака попытки взлома;
  • начинается ли наличествующий в ней путь с имени корневой папки аккаунта (помещенного строчкой выше в переменную Sbegin):
    if ((strpos($fold,$begin)!=0)| (strpos($fold,"..")!=False)||($fold==""))
    {

Примечание:
Функция strpos (строка - объект поиска, искомая комбинация символов) возвращает либо номер позиции, на которой в указанной в ее первом параметре строке находится указанная во втором параметре комбинация символов, либо False - если таковая не найдена вообще.
Чтобы различить возможные результаты работы функции "комбинация символов найдена в строке на позиции 0" и "комбинация символов в строке не найдена", можно использовать при сравнении сочетание трех знаков равенства — это означает проверку на "тождественность ":
if (strpos ("строка", "символы") ===0) {... будет верно, если "строка" начинается с "символов".
Можно также проверять результат на принадлежность к целым числам:
if (is_integer (strpos ("строка ", "символы")==false) {...
выполнится, только если в "строке" "символы" не найдены.

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

$dirct=$begin;
}
else
{

а если переменная Sfold "в порядке", то в переменную Sdirct поместим именно ее значение:

$dirct=$fold;
}

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

echo ("<form action=zapros.php?folder=$dirct method=post>");

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

if ($dirct!=$begin) {

для чего выделим из пути к текущей папке его часть с начала вплоть до последнего слэша - разделителя директорий; это и будет путь к родительской папке (скажем, если путь к текущей папке -f iles/folderl/papkal, то путь к родительской папке будет выглядеть как f iles/f olderl):

$back=substr ($dirct, 0, strrpos($dirct, "/"));

Примечание:
Команда substr (строка, начало выделения, длина выделения) предназначена для выделения из строки ее части. Строка (или переменная, ее содержащая) должна быть указана в первом параметре команды. Второй параметр - позиция, с которой начинается выделяемая часть (вернее, число символов, которые необходимо пропустить до начала выделения части строки), а третий -количество выделяемых символов.
Команда strrpos (строка, символ) выдает номер позиции последнего появления указанного в ее втором параметре символа в строке, указанной в ее первом параметре. В вышеприведенной строчке она используется для определения длины вырезаемого из полного пути фрагмента — до последнего слэша.

и выведем ссылку на родительскую папку, попросту передав полученный путь к ней через переменную $fold:

echo ("<a href=index.рbр?:?о1с1=$bаск>Корневая папка</а><br>");

Все это делается, естественно, лишь в том случае, если текущая папка - не корневая.
}
Теперь можно и сканировать текущую папку. Получаем список файлов в ней (пояснения смотрите в гл. 6 - в описании сценария "Папкопотрошилка"):

$hdl=opendir($dirct); while ($file = readdir($hdl)) {
if (($file!="..")&&($file!=".")) { $a[]=$file;
} }
closedir($hdl);

В том случае, если файлы в папке есть...

if (sizeof($a)>0) {

отсортируем массив с их именами по алфавиту. К сожалению, при этом имена папок окажутся перемешанными с именами файлов, но делать специальную функцию сортировки пока не будем: asort($a);
Теперь надо вывести на страницу имена файлов и папок, причем каждое имя должно быть ссылкой на соответствующий файл или папку, а перед именем должен стоять checkbox для возможности выбора соответствующих файлов и папок для совершения над ними действий.
С каждым именем файла или папки...
foreach ($a as $k) { поступим следующим образом.

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

Вначале запишем в переменную путь к данному файлу или папке -относительный от той директории, где находятся файлы самого файлового менеджера. Для этого просто прибавим имя данного файла или папки к пути к текущей директории:
$full=$dirct."/". $k; Теперь выведем checkbox:

echo ("<input name=fl[] value=$k type=checkbox>");

При передаче формы странице-обработчику будет передан массив $fl, состоящий из значений атрибутов value отмеченных checkbox'oe (только отмеченных - неотмеченные игнорируются). А в качестве значений атрибутов value мы указываем имена файлов. Так что сценарию-обработчику будет полностью ясно, с какими файлами ему работать - путь к текущей папке будет передан в переменной в ссылке на обработчик, указанной в заголовке формы, а имена файлов передадутся в массиве $fl.
Если очередной элемент массива с именами файлов в текущей директории является папкой...

if (is__dir ($full)==True)

Примечание:
Функция is_dir возвращает True, если указанный в ее параметре объект существует и является папкой.

то выведем ссылку на нее. Вернее, не на нее, а на этот же файл нашего файлового менеджера - index.php, передав ему в качестве пути к текущей папке - в значении переменной Sfold - записанный нами ранее в переменную Sfull полный путь к данной папке:

echo ("<a href=index.php?fold=$full><b>nariKa $k</bx/a>") ;

Ну и укажем в качестве текста ссылки название папки, пояснив, что эта ссылка ведет именно на папку (см. рис. 11.4).
В результате перехода по такой ссылке файлу index.php будет передан новый путь - путь к "открываемой" папке - и посетитель сможет увидеть список файлов в ней.
Если же очередной элемент массива с именами файлов в текущей директории - всего лишь файл...

}
else {

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

echo ("<a href=$full>$k</a>");
}

После вывода ссылки - либо на файл, либо на папку - выведем разделитель строк, чтобы список имен файлов и папок представлял из себя аккуратный столбик:
echo ("<br>");
и перейдем к следующему элементу с именами файлов в текущей директории.
}
Все эти действия производятся, если в текущей папке есть файлы. Ну а если файлов нет - то и делать ничего не надо.

} ?>

Теперь отобразим кнопки выбора действия над выделенными файлами. Их будет четыре - "Удалить", "Переименовать", "Копировать", "Создать папку" с именами "udal", "ren", "copy", "md" соответственно.

<br><input type=submit value="Удaлить" name=udal><br><input type=submit | value="nepeименовать" name=renxbrxinput type=submit value="Koпировать" name=copy><br><input type=submit value="Создать папку" name=md>

Собственно, сам текст сценария закончен...

< / f ormx /html>

хотя, бесспорно, внешний вид страницы с ним будет весьма аскетичным (рис. 11.4, 11.5). Но художественное оформление страницы - уже ваша прерогатива.

Рис. 11.4. Файловый менеджер. Главная страница. Курсор - на ссылке, ведущей на папку

Рис. 11.5. Файловый менеджер. Главная страница. Исходный код Рассмотрим следующие компоненты файлового менеджера.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ФАЙЛ ZAPROS.PHP

Сценарии этого файла запрашивают от посетителя дополнительную информацию для проведения действия. Начало сценария:

<html><?php

Сразу же выведем заголовок формы, общий для всех четырех вариантов запросов. В нем точно так же передадим выполняющему собственно действия сценарию на странице do.php имя текущей папки:

echo ("<form action=do.php?folder=$folder method=post>");

Бесспорно, можно было бы и не передавать имя текущей папки, а сообщать обработчику конкретные имена файлов, над которыми совершается действие, с полным путем к ним, однако так все-таки проще.

УДАЛЕНИЕ, ЗАПРОС ИНФОРМАЦИИ

Если на основной странице файлового менеджера - index.php - была нажата кнопка "Удалить", имя которой - "udal", то значение переменной $udal' в сценарии на странице-обработчике будет отличным от нуля (вернее, оно будет представлять собой значение атрибута value кнопки "Удалить" на основной странице -^собственно слово "Удалить"). Если была нажата какая-нибудь другая кнопка, то значение переменной $udal определено не будет. Поэтому для того, чтобы узнать, было ли посетителем выбрано в качестве желаемого действия удаление, проверим содержимое этой переменной:

if ($udal!="")

Выведем небольшое пояснение посетителю...

echo ("Удалить файлы?<bг>");

и список файлов, которые планируется удалить. Их список передан в форму в массиве $fl. В этот массив включены параметры value тех checkbox'oB, которые были отмечены посетителем на основной странице менеджера файлов перед тем, как нажать кнопку с названием действия (а в эти параметры, как вы наверняка помните, были помещены имена файлов и папок, отображавшихся на основной странице файлового менеджера - путь к ним передан через переменную Sfolder в адресной строке). Переберем все элементы массива $ f 1...

foreach ($fl as $i)
{

и выведем их значения - имена файлов, подлежащих удалению. Вместе с именем папки, в которой они расположены - его сценарий на этой странице получил через адресную строку.
Ну а для того, чтобы иметь возможность эти имена передать сценарию на следующей странице, выполняющему собственно действие,
Строго говоря, вместо имен переменных, равных именам элементов формы, обрабатываемой сценарием на этой странице, следовало бы использовать имена соответствующих элементов массивов SHTTP_POST_VARS[] и (в РНР начиная с версии 4.1) $_POST[]. Однако для более легкого понимания кода выбран первый вариант. При использовании настоящего сценария на практике вы можете сами заменить имена переменных на имена элементов упомянутых массивов.
рядом с каждым именем удаляемого файла поместим скрытое поле, в которое поместим это самое имя. Сценарию, выполняющему удаление, останется только совершить эту операцию над теми файлами, имена которых ему будут переданы.
Имя же папки, в которой эти файлы располагаются, передается сценарию - исполнителю действия через адресную строку, указанную в заголовке формы запроса информации - точно так же, как оно было передано данному сценарию, запрашивающему дополнительную информацию. Вы могли видеть этот заголовок несколькими абзацами выше.

Рис. 11.6. Удаление файлов и папок. Запрос подтверждения

Как и на первой странице, все эти скрытые поля сделаем массивом, для удобства - даже присвоим ему то же имя flf ]:

echo ("<input type=hidden name=fl[] value=$i>$i из папки $folder<br>");
}

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

echo ("<input type=submit value = \"Удалить" name=udal>");

В результате в том случае, если посетитель на основной странице отметит файлы и папки и нажмет кнопку "Удалить", то на странице запроса подтверждения (рис. 11.6) ему будет выдан список выбранных им файлов и предложено нажать одну из двух кнопок - "Удалить" или "Отмена" (код, выводящий последнюю, размещен в конце страницы -смотрите ниже).

КОПИРОВАНИЕ, ЗАПРОС ИНФОРМАЦИИ

Для того, чтобы произвести копирование файлов и папок из одной папки в другую, простого согласия пользователя на это действие мало. Нужно еще узнать, а в какую папку необходимо производить копирование.
А что нужно, чтобы это узнать? Необходимо выдать запрос на получение имени этой папки у пользователя. Можно, конечно, предоставить пользователю возможность просто ввести новый путь в поле ввода текста, как при использовании команды сору в командной строке MS-DOS. Но это представляется весьма неудобным. Лучше, наверное, вывести пользователю список всех имеющихся на его аккаунте папок, из которых он сможет выбрать нужную. Пометить имя каждой папки радиокнопкой (кружком из группы единственного выбора, см. рис. 11.1, 11.7) - и для выбора папки назначения копирования достаточно будет только ткнуть мышью в нужном месте).
Но как вывести список всех папок? Ведь они могут быть вложены друг в друга, так что простое сканирование корневой директории не поможет... А команд в нашем распоряжении для достижения данной цели не так и много. Считать список содержимого каталога, определить, является ли тот или иной элемент, содержащийся в каталоге, так же директорией, - вот, собственно, и все, что нам может предложить РНР.
И тут придет на помощь принцип рекурсии.
Под рекурсией понимается запуск программы из самой этой программы. Иными словами - вот программа запускается, исполняется, исполняется - а затем очередная команда представляет собой не что иное, как вызов этой самой программы! и вновь программа исполняется с начала, исполняется... и опять доходит до вызова самой программы, и опять исполняется с начала.
Разумеется, для того чтобы программа с рекурсией имела какой-то смысл, а не представляла из себя бесконечно повторяемые действия, на каком-то этапе данный процесс должен прерваться. Иными словами, запуск программы изнутри самой программы должен происходить не каждый раз при ее работе, а в зависимости от того, выполняется ли определенное условие. Естественно, рано или поздно в ходе работы программы условие должно перестать выполняться, и тогда рекурсия прервется - исходная программа изнутри нее самой запущена при невыполнении условия не будет.
Как же принцип рекурсии можно использовать для построения списка всех папок на аккаунте? А алгоритм построения этого списка при использовании рекурсии прост:

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

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

if ($copy!="")
{

Для удобства запишем в переменную название корневой папки аккаунта пользователя. Впоследствии мы будем ее неоднократно использовать в коде.

$begin="files";

Выводим запрос пользователю...

echo ("Объекты для копирования:<br>");

и, точно так же, как в блоке кода, посвященном удалению файлов, выводим список объектов, подлежащих копированию (сравните - код практически такой же):

foreach ($fl as $i)
{
echo ("<input type=hidden name=fl[] value=$i>$folder/$i<br>") ;

Еще один запрос...

echo ("<bг>Выберите папку для копирования :<br>") ;
и начинаем вывод дерева папок - вызываем функцию tree.
tree($begin);

РЕКУРСИВНАЯ ФУНКЦИЯ ВЫВОДА СПИСКА ДОСТУПНЫХ ДЛЯ КОПИРОВАНИЯ ПАПОК НА АККАУНТЕ

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

function tree($fId)

Поскольку в функции будут использоваться переменные еще и из других частей программы на странице, такие как Sfolder (путь к текущей папке) и массив $fl (список копируемых объектов; имена тех папок, что перечислены в нем, выводиться на страницу не будут, так как папку нельзя скопировать саму в себя или в свою же вложенную папку), то эти переменные необходимо объявить как глобальные в самой функции, указав их в ее начале после слова global:

global $folder; global $fl;

Комментарий:
Массив Sfl был передан сценарию запроса дополнительной информации с помощью формы на основной странице файлового менеджера — методом POST. Поэтому он также доступен через массив $HTTP_POST_VARS - как его элемент $HTTP_POST_VARS['fl'J (если в файле конфигурации РНР установлен в on параметр track_vars). Для использования этого массива в функции его надо также объявить глобальным - командой global $HTTP_POST_VARS;.

В РНР 4.1 версий и выше массив Sfl доступен и через массив $_POST. В отличие от $HTTPJPOST_VARS этот массив автоглобальный — т. е. для использования в функциях его элементов объявление самого массива в функциях производить не надо.
Если вы пожелаете заменить в рассматриваемой программе все вхождения переменной-массива Sfl на соответствующие им элементы массивов SHTTPPOSTVARS или SPOST, то помните, что последние нельзя для вставки их значений в строку указывать в тексте строки — для этого следует использовать оператор конкатенации (точку).
Начинаем сканировать папку, имя которой было передано в вызове функции, при помощи того же сценария, который мы уже неоднократно использовали, он разбирался еще в главе "Папкопотрошилка". При первом вызове функции ей передается имя корневой папки аккаунта, с нее функция и начинает свою работу.

$hdl=opendir($fld);
while ($file = readdir($hdl)) if ( ($file!=°.")&&($file!=".."))
Для удобства запишем полное имя - вместе с путем - очередного взятого из папки объекта в переменную $f llnm:
$fllnm=$fld."/".$file;

Если этот объект - тоже папка...

if (is_dir($fllnm)==True)

то выясним:

  • не является ли данная папка одновременно и объектом копирования? Если является - то, во-первых, в списке папок она появиться не должна - папку нельзя скопировать саму в себя, а, во-вторых, сканировать ее вложенные папки тоже незачем - копировать одну папку в другую, вложенную в нее, еще никому не удавалось;
  • не в этой ли самой папке находится копируемый файл? Если в этой же самой папке - то выводить ее имя бессмысленно: копирование файла на свое же место возможно, но никаких за собой последствий не влечет.

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

$по=0;
foreach ($fl as $i)
if ($fllnm==$folder."/".$i) $no=l;

Переменная $по примет значение 0, если совпадений не было, и 1, если были.

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

Итак - если очередная папка из сканируемой директории не является объектом копирования...

if ($no==0)

{ и эти объекты копирования расположены не в ней...

if ($fllnm!=$folder)

то ее имя можно вывести в качестве возможного пункта назначения копирования, снабдив его radio button - т. е. "кружком" для единственного выбора. (После отправки формы результат выбора окажется в переменной $rd в сценарии выполнения действия.)

echo ("<input name=rd type=radio value=$fllnm>$fllnm<br>");

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

То, что папка содержит копируемые файлы, является препятствием к выводу имени этой папки на экран как возможнего пункта назначения копирования. Но это отнюдь не значит, что в данной папке не должны сканироваться вложенные папки. Поэтому оператор i f определяет, не содержит ли рассматриваемая папка копируемых файлов, завершаем...

} и вот он - рекурсивный вызов функции tree:

tree ($fllnm);

Осталось закрыть все незавершенные операторы и циклы,

}
}
}
}

и "потрошимую" директорию.

closedir($hdl);

Функция вывода списка директорий,- пунктов назначения копирования завершена.
}
Работать она будет так. Изначально, как вы помните, функция вызывается с параметром Sbegin, именем корневой директории аккаунта. Функция сканирует эту директорию и, как только натыкается на вложенную папку, проверяет, можно ли ее сканировать, после чего, возможно, эта вложенная папка превращается в сканируемую. И опять: функция сканирует уже эту вложенную папку, и, если опять натыкается на папку, вложенную в эту вложенную папку, то начинает сканировать уже ее. И так продолжается до тех пор, пока функция не доберется до папки, где вложенных папок нет (согласитесь, что такая рано или поздно найдется). Дойдя до такой, функция возвращается на шаг назад и сканирует следующую вложенную папку. Если таковой не находит, то возврат идет дальше. Попробуйте себе все это представить - и сразу поймете, если еще не поняли.

Как уже было сказано, функция tree () должна находиться в коде перед блоком запроса дополнительной информации для копирования.

Рис. 11.7. Копирование. Запрос папки назначения

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

if ($begin!=$folder) {
echo ("<brxinput name=rd type=radio value=$begin>$begin<br>");

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

echo ("<input type=submit value=\"Скопировать\" name=copy>");

Все.

}

Если посетитель на основной странице файлового менеджера отметит файлы и выберет функцию копирования, то ему будет выдан список папок, в которые может быть произведено копирование (рис. 11.7). Выбрав любую из них, для запуска копирования останется лишь нажать соответствующую кнопку.

ПЕРЕИМЕНОВАНИЕ, ЗАПРОС ИНФОРМАЦИИ

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

if ($ren!="") { то выведем пояснение пользователю...
echo ("Переименовать файлы?<bг>");

и для каждого файла или папки, чье имя было отмечено в соответствующем checkbox'e на главной странице...

foreach ($fl as $i)
{

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

echo ("<input type=hidden name=afl[] value=$i>");

Выведем старое имя файла...

echo ("$i");

и текстовое поле для ввода нового имени. Для удобства поместим в это текстовое поле старое имя - если пользователю надо было его изменить совсем немного, то ему сделать это будет легче.

echo ("<input type=text size=30 name=rfl[] value=$ixbr>") ;

Такие поля выведем для каждого файла или папки, подлежащего переименованию.
}
И выведем кнопку, запускающую процесс переименования путем перехода на страницу со сценарием-обработчиком с передачей этому сценарию отличного от пустой строки значения переменной $rеn:

echo ("<input type=submit value=\"Переименовать\" name=ren>");

Блок запроса дополнительной информации по переименованию файлов или папок закончен.
}
В результате работы данного сценария (а это произойдет только в том случае, если на основной странице файлового менеджера была нажата кнопка "Переименовать") посетителю будет отображен список выбранных им для переименования файлов, для каждого из которых он сможет ввести новое имя (рис. 11.8)
После нажатия кнопки "Переименовать" на странице запроса дополнительной информации сценарию-исполнителю действия будут переданы два массива - $afl и $rfl - со старыми и новыми именами файлов и папок, причем их элементы, относящиеся к одному и тому же файлу или папке, будут иметь один и тот же порядковый номер.
Полные же пути к переименовываемым файлам и папкам сценарий сможет восстановить на основе значения переменной Sfolder, переданной ему в ссылке на страницу со сценарием-обработчиком, указанной в заголовке формы (см. ранее).

Рис. 11.8. Переименование. Запрос новых имен

СОЗДАНИЕ НОВОЙ ПАПКИ, ЗАПРОС ИНФОРМАЦИИ

Для создания новой папки нужно получить от пользователя всего одно слово - имя этой самой новой папки.
Если на основной странице файлового менеджера было выбрано действие "Создание папки"...

if ($md!="")

то выведем на страницу поле для его ввода (его содержимое передастся сценарию-обработчику в переменной Snewname):

echo ("Введите имя папки: <brxinput type=text size=30 name=newname>");

и кнопку, запускающую это самое создание:

echo ("<input type=submit value=\"Создать папку \ " name=md>");

Собственно, и все.

}
?>

Посетитель увидит поле ввода для имени новой папки (рис. 11.9)

Рис. 11.9. Создание новой папки. Поле ввода ее имени

КНОПКА ОТМЕНЫ

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

<brxinput type=submit value="OTMeHa" name=otmena>

Собственно, это и есть весь текст этой страницы:

</form></html>

Графическое оформление - уже на вкус сайтостроителя.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ФАЙЛ DO.PHP

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

<?php
$begin="files";

Целесообразность проверки содержимого переменной Sfolder на предмет возможности попытки взлома сайта может представиться сомнительной. Эта переменная передается посредством заголовка формы и в адресной строке не отображается, однако ничто не мешает злоумышленнику сохрацить страницу с формой запроса информации на свой жесткий диск, исправить ее содержимое и, заменив относительные ссылки на абсолютные, перейти с сохраненного варианта на страницу выполнения действия. Так что проверять переменную Sfolder на наличие в ней ссылки на родительский каталог (двух точек подряд), а также удостовериться, что путь, записанный в ней, начинается с имени корневой папки аккаунта, всё же необходимо. Если последнее неверно или в Sfolder можно найти две точки подряд, то дальнейшее выполнение кода прекращается:

If
((strpos($folder,$begin)!=0)||(strpos($folder,"..")
!=False))
158
exit; }

Примечание:
Команда exi t полностью прекращает выполнение кода и выведение текста на странице, на которой она расположена - как если бы именно на ней страница заканчивалась. Обратите внимание, что эта команда завершает не выполнение РНР-программы, а вывод страницы - т. е. HTML-код после завершающего тэга РНР-сценария, если таковой есть, выводиться также не будет.

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

УДАЛЕНИЕ, ВЫПОЛНЕНИЕ ДЕЙСТВИЯ

Для удаления файлов в РНР существует специальная команда - unlink.

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

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

function delfiles($fId)
$hdl=opendir($fld); while ($file = readdir($hdl)) {
if (($file!=".")&&($file!="..")) {
if (is_dir($fld."/".$file)==True) {
delfiles ($fId.»/".$file); rmdir ($fld."/".$file); }
else {
unlink ($fld."/".$file); } } }
closedir($hdl);
}

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

if ($udal!="")

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

foreach ($fl as $i)

проверим на то, не является ли он директорией.

if (is_dir($folder."/".$i)==True)
{

Если является, то удалим все файлы в этой директории - рекурсивной функцией delf iles...

delfiles ($folder."/".$i); а затем и саму, уже опустошенную директорию - командой rmdir.
rmdir ($folder."/".$i); } else

А если этот объект, подлежащий удалению, является обычным файлом...
то для него припасена уже упомянутая выше команда unlink: unlink ($folder."/".$i); }
И так поступим с каждым объектом, имя которого передано сценарию через массив $fl, а путь к нему - через переменную Sfolder в адресной строке.
} Собственно, и все (рис. 11.10).

Рис. 11.10. Удаление выполнено

КОПИРОВАНИЕ, ВЫПОЛНЕНИЕ ДЕЙСТВИЯ

С копированием будет посложнее. Напомню, что из сценария запроса дополнительной информации передан массив Sfl, состоящий из имен копируемых файлов и папок, и переменная $rd, содержащая имя с полным путем к той папке, в которую планируется осуществить копирование. Ну и, разумеется, путь к текущей папке, в которой изначально и находятся копируемые файлы - $folder.
Сначала напишем функцию копирования целой папки со всеми вложенными в нее папками на новое место. Эта функция, как и функции удаления папки и вывода списка всех папок на аккаунте, будет рекурсивной - т. е. с вызовом самой себя из своего кода. Алгоритм ее прост:

  1. 1. Создать в папке назначения папку с тем же именем, что и у копируемой.
  2. 2. Копировать из копируемой папки в новосозданную папку все ее содержимое.
  3. 3. Если очередной копируемый объект - папка, то перейти к пункту 1, приняв в качестве папки назначения - новосозданную папку, а в качестве копируемой папки - этот самый очередной копируемый объект, оказавшийся папкой.

Рано или поздно функция дойдет до папок, содержащих только файлы, которые и станут прерывать рекурсию.
Функция будет получать полное имя (вместе с путем) папки, в которой находится копируемая папка, имя этой самой копируемой папки, и имя (вместе с путем) папки назначения копирования (т. е. той, в которую будет производиться копирование).
function copyfold ($fld, $nm, $tgt)
Внутри функции эти данные будут доступны в переменных $fld, $nm, $tgt соответственно.
Сначала создадим в папке назначения копирования папку с таким же именем, что и имя копируемой папки. Естественно, если там таковой еще нет:

if (file_exists($tgt."/".$nm)!=True)
mkdir ($tgt."/".$nm, 0666);

Примечание:
Команда mkdir (имя новой папки вместе с путем к ней, параметры доступа) создает новую папку. Если создать папку невозможно (например, уже есть папка с таким именем), то выдается сообщение об ошибке.

Параметры доступа, или атрибуты файла или папки - это восьмеричное число, сообщающее web-серверу о том, что можно делать с файлом, которому эти параметры установлены. Например позволить его читать только другим сценариям на том же аккаунте, но не посетителям из Сети. Узнать о соответствии значений параметров доступа их восьмеричному представлению можно, например в FTP-клиенте CuteFTP, воспользовавшись его окном выставления атрибутов файла (рис.11.11), доступном через пункт "Chmod" меню правой кнопки мыши любого файла на сайте. "Owner permissions" - это раз решения для других программ на том же аккаунте, a "Public permissions" - для посетителей из Интернета. Вы можете разрешить или запретить три вида действий: чтение, запись и запуск на исполнение (последнее имеет смысл только для программ).

Рис. 11.11 . "Калькулятор параметров доступа" из CuteFTP

Теперь начнем копировать файлы из исходной папки в новосоздан-ную (используем старый добрый сценарий "папкопотрошилки"): исходная папка при этом - $f Id. " /" . $шп, а новосозданная -

$tgt."/".$nm.
$hdl=opendir($fld."/".$nm) ; while ($file = readdir($hdl)) { if (($file!=" . .")&&($file! = "."))

Если очередной объект из "потрошимой" папки $f Id. " / " . $nm -директория...

if (is_dir($fld."/".$nm."/".$file)==True) {

о применим рекурсию - вновь вызовем функцию с ору fold, только араметры ей уже передадим несколько другие:

copyfold($fld."/".$nm, $file, tgt."/".$nm);

Другими словами, в качестве имени копируемой папки - указываем мя очередного обьекта, найденного в "потрошимой" папке. Остальные передаваемые функции параметры представляют собой соответственно имя "родительской" папки для копируемой (это имя "потрошимой" папки), имя папки назначения (составлено из исходного имени апки назначения и имени копируемой папки, эта папка, кстати, как вы, наверное, помните, была создана командой mkdir в начале работы функции).
Если же очередной объект из "потрошимой" папки $f Id." /" . $nm является обычным файлом...

}
else
{

то просто скопируем его из исходной папки в папку назначения -и дело с концом.
copy ($fld."/".$nm."/".$file, $tgt."/".$nm."/".$file);

Примечание:
Функция copy (исходный файл, файл на месте назначения) копирует файл, полный путь к которому указан в первом параметре, в тот файл, полный путь к которому указан во втором параметре. Если копирование не удается, то функция выводит сообщение об ошибке (можно отключить, поместив символ @ перед командой) и возвращает false.
Если файл назначения уже существует, он будет перезаписан без вывода какого-либо подтверждения.

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

copy ("/files/data/filel.htm", "/files/last/'filel.htm");

В качестве имен файлов могут выступать содержащие их строковые переменные.
Работа функции завершена. Закроем открытые циклы и условные операторы...

}
} }

и открытую "потрошимую" директорию:

closedir($hdl); }

Текст этой функции следует поместить перед разделом кода, выполняющимся в том случае, если в качестве действия над выбранными файлами выбрано копирование. Код же этот следующий.

if ($copy!="")
{

Переберем все объекты, подлежащие копированию: foreach ($fl as $i)
{ Если очередной объект - папка...

if (is_dir($folder."/".$i)==True)

то запустим функцию копирования папки, разобранную выше, передав ей нужные параметры.

copyfold($folder, $i, $rd);

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

Однако исключение вложенных папок из списка возможных пунктов назначения на странице запроса дополнительной информации не гарантирует невозможности начала такого копирования! Злоумышленник может сохранить страницу файлового менеджера со списком пунктов назначения копирования на своем компьютере, а потом, исправив относительные ссылки на абсолютные, добавить в локальную копию страницы новый возможный пункт назначения копирования, т. е. имя папки, вложенной в копируемую папку, а затем, пометив именно эту папку, запустить копирование, тем самым навредив владельцу сайта, на котором расположен файловый менеджер.
Чтобы сделать такие действия невозможными, на странице выполнения действия можно проверять, не вложена ли папка назначения копирования в копируемую папку. Для этого проще всего сравнить полные имена этих папок. Если полное имя копируемой папки можно найти в начале полного имени папки назначения, то копирование выполнять нельзя. Для сравнения проще всего воспользоваться функцией strpos (справку по ней смотрите в начале этой главы):

if (!(strpos ($rd, $?older."/".$i)===0)) { copyfold($folder, $i, $rd);
}

Хотя, бесспорно, в данном сценарии такая "защита", скорее, является демонстрационной - если посетитель имеет возможность загружать на аккаунт любые файлы, то никто не помешает ему загрузить на него какую-нибудь вредоносную программу на РНР и выполнить ее.
Если же очередной объект - файл...

}
else {
то его скопируем.
copy ($folder."/".$i, $rd."/".$i);

Осталось закрыть фигурными скобками запущенные циклы и условные операторы.

} }
}

Процесс копирования завершен (рис. 11.12).

Рис. 11.12. Файлы скопированы

ПЕРЕИМЕНОВАНИЕ, ВЫПОЛНЕНИЕ ДЕЙСТВИЯ

В том случае, если посетитель выбрал в качестве требуемого действия переименование, то на странице запроса дополнительной информации ему пришлось ввести новые имена для тех файлов и папок, переименовать которые он пожелал. Сценарию же выполнения действия передалось два массива со старыми и новыми именами этих обьектов -$afl и $rfl соответственно.

if ($ren!="")
{

Переберем все элементы массива со старыми именами - $af 1. Поскольку для совершения собственно переименования для каждого элемента массива со старыми именами нам также потребуется элемент массива $rf 1 с новыми именами под тем же порядковым номером, то перебирать эти элементы будем подряд, по номерам - с помощью цикла for:

for ($i = 0; $i < sizeof($afl); $i++)

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

if (($rfl[$i]!="")&($rfl[$i]!=$afl[$i]))

то можно переименовывать. Однако посетитель вполне может в новом имени указать символы, которые недопустимы для имен файлов - от пробелов до слэшей. Возвращать посетителя на этап ввода имени с выведением ему сообщения о недопустимых символах не будем - просто заменим все такие символы на знаки подчеркивания: "_". Тем более что такую замену можно совершить специальной командой PHP - strtr:

(Количество знаков подчеркивания в третьем параметре функции равно количеству указанных во втором недопустимых символов.)

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

Если столь длинная фраза вас смутила, то можно сказать проще: во втором и в третьем параметрах функции приводятся строки, состоящие из определенных символов.
Функция просматривает строку в первом параметре символ за символом. Если очередной символ этой строки встречается и в строке во втором параметре, то функция:

1. Смотрит, какой символ стоит в строке в ее третьем параметре на том же самом месте от начала строки, что и встреченный символ в строке во втором параметре.
2. Заменяет в строке в первом параметре этот очередной символ на найденный в третьей строке. Например результатом выполнения функции

strtr ("Оабвапабаво", "ба", "ру")

будет строка

"Оурвупуруво"

Если строки во втором и третьем параметрах разной длины, то лишние символы в более длинной строке игнорируются.

Поскольку на всех местах в строке в третьем параметре этой функции стоит знак подчеркивания, то все недопустимые символы, указанные в строке в ее втором параметре, будут на него заменены.
И наконец, само переименование - командой rename:

rename ($folder."/".$af1[$i], $folder."/".$rfl[$i]) ;

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

Вот и все (рис. 11.13).
} } }

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

Рис. 11.13. Файлы переименованы

Рис. 11.14. Ошибка при переименовании - сообщение РНР

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

while (file_exists($folder."/".$rfl[$i])==True)
{
$rfl[$i] = "_".$rfl[$i];
}

Как нетрудно понять, он добавляет в начало нового имени файла знак "_", если файл с таким именем уже существует в той же папке, куда предполагается копировать файл. Если же и таковой файл - со знаком "_" в начале -уже в папке имеется, то к новому имени добавляется еще один такой символ, и так до тех пор, пока новое имя не станет уникальным.

СОЗДАНИЕ НОВОЙ ПАПКИ, ВЫПОЛНЕНИЕ ДЕЙСТВИЯ

Создание новой папки выполняет самый маленький фрагмент кода во всем сценарии. Даже меньше того, что выводил запрос имени для этой новой папки.

if ($md!="") {

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

$newname=strtr($newname, " []{},/\!@#$%л&*",

и создадим папку - командой mkdir, не забыв указать в ее параметрах полный путь к новой папке:

mkdir ($folder."/".$newname, 06 66);

Описание команды mkdir вы уже видели выше - в подразделе "Копирование, выполнение действия". Собственно, и все (рис. 11.15).

Рис. 11.15. Папка создана

ЗАВЕРШЕНИЕ ДЕЙСТВИЯ

Ну и по окончании выполнения действий перенаправим посетителя на основную страницу файлового менеджера - в ту же директорию, в которой он и находился, передав сценарию на основной странице путь к ней через переменную fold в адресной строке. Для этого воспользуемся командой Header, передающей браузеру заголовки.
Если на странице запроса дополнительной информации посетителем была нажата кнопка "Отмена", то ни один из вышеприведенных блоков исполнения действия выполнен не будет - ни одна из переменных Sudal, $copy, $ren, $md определена не будет. А эта команда выполнится - т. е. после нажатия кнопки "Отмена" на странице запроса дополнительной информации посетитель окажется на основной странице файлового менеджера.

Header ("Location: index.php?fold=$folder");

Примечание:
Заголовок - это данные, передаваемые браузеру до передачи самой web-страницы, сообщающие ему некоторые параметры передаваемого файла или определенные команды. Список всех возможных заголовков, которые обязаны поддерживать современные браузеры, можно найти в спецификациях протокола HTTP - они есть, например, на сайте http://www.w3.org. PHP-команда Header выполняет всего одно действие -она просто передает то, что указано в ее параметре, в браузер, запросивший страницу, на которой она находится, в качестве заголовка.
Заголовок "Location" осуществляет перенаправление браузера на страницу, указанную в его параметре.

Сценарий можно завершить - посетитель уже на другой странице...
В результате после того как посетитель на странице запроса дополнительной информации нажмет кнопку начала действия, после небольшой паузы (длящейся ровно столько времени, сколько надо web-серверу для совершения этого действия) он вновь окажется на главной странице файлового менеджера, а заказанное им действие будет выполнено.
Однако если в процессе выполнения сценария возникнет ошибка (скажем, новую папку создать не удастся, так как окажется, что папка с таким же именем уже существует, или возникла проблема при переименовании файла - см.рис.11.14), то на страницу будет выведено сообщение об ошибке, а команда Header не сработает - и тоже выдаст сообщение об ошибке (так как заголовок можно отправлять только до какого-либо вывода на страницу). Если вас это не устраивает - то можете либо предварять все команды символом "@" (он запрещает выводить сообщения об ошибках), либо снабдить страницу со сценариями выполнения действия в самом низу небольшим комментарием (с информацией вроде "Возникла ошибка, извините...") и ссылкой на главную страницу файлового менеджера.
Вот, собственно, и весь сценарий. Если желаете - можете его использовать в своих разработках. Или просто, просмотрев текст с комментариями, составить себе представление о том, как составлять программы на РНР.
Разумеется, сценарий можно улучшать. Первые два предложения по улучшению напрашиваются сразу - добавить в него возможность загрузки файлов и блок авторизации доступа. Код программ, реализующих эти предложения, уже рассматривался в предыдущих главах, так что вряд ли их реализация будет для вас сложной. (Не 174
забудьте разве что вставить код проверки содержимого авторизационных переменных на все страницы файлового менеджера, а не только на основную.) Можно также научить сценарий выдавать осмысленные сообщения об ошибках, если они возникнут, заставить его выдавать подтверждения, скажем, в случае существования в папке назначения копирования файлов и папок, одноименных копируемым - дабы предотвратить случайное их переписывание. Но это все остается уже на ваше усмотрение.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ТЕКСТ СЦЕНАРИЯ

Для лучшего восприятия информации данной главы далее приводится текст разобранного выше сценария без каких-либо комментариев.

Файл index.php

<html> <?php
$begin="files";
if ((strpos($fold,$begin)!=0)||(strpos($fold,"..")!=False) | | ($fold== ¦¦'¦)) {
$dirct=$begin; }
else {
$dirct=$fold; }
echo ("<form action=zapros.php?folder=$dirct method=post>");
if ($dirct!=$begin) {
$back=substr ($dirct, 0, strrpos($dirct, "/")); echo ("<br><bxa href=index.php?fold=$back>KopHeBaH папка</ах/Ь><br>") ;
}
$hdl=opendir($dirct); while ($file = readdir($hdl)) {
if (($file!="..")&&($file!=".")) { $a[]=$file;
} }
closedir($hdl);
175
if (sizeof($a)>0)
asort($a); foreach ($a as $k)
$full=$dirct."/". $k;
echo ("<input name=fl[] value=$k type=checkbox>") ;
if (is_dir($full)==True)
echo ("<a href=index.php?fold=$fullxb>rianKa $k</bx/a>") ;
else
echo ("<a href=$full>$k</a>"); echo ("<br>");
?><brxinput type=submit value= "Удалить " name=udalxbr><input type=submit value="Переименовать" name=renxbrxinput type=submit value="Копировать" name=copyxbrxinput type=submit value="Создать папку" name=md>
</form></html>

Файл zapros.php

<htmlx?php
echo ("<form action=do.php?folder=$folder method=post>"); if ($udal!="") {
echo ("Удалить файлы?<br>"); foreach ($fl as $i) {
echo ("<input type=hidden name=fl[] value=$i>$i из папки $folder<br>");
}
echo ("<input type=submit value=\"Удалить\" name=udal>"); }
function tree($fld) {
global $ folder; global $fl;
176
$hdl=opendir($fld); while ($file = readdir($hdl)) {
if (($file!=".")&&($file!="..")) {
$fllnm=$fld."/".$file; if (is_dir($fllnm)==True) {
$ПО=0;
foreach ($fl as $i) {
if ($fllnm==$folder."/".$i) {
$no=l; } }
if ($no==0) {
if ($fllnm!=$folder) {
echo ("<input name=rd type=radio value=$fllnm>$fllnm<br>");
}
tree ($fllnm); } } } V
closedir($hdl); }
if ($copy!="") {
$begin="files";
echo ("Куда копировать файлы?<br>"); foreach ($fl as $i) {
echo ("<input type=hidden name=fl[] value=$i>$folder/$i<br>");
}
echo ("<br>Выберите папку для копирования:<br>"); tree($begin); if ($begin!=$folder) {
echo ("<input name=rd type=radio value=$begin>$begin<br>");
177
}
echo ("<input type=submit value=\"Скопировать\" name=сору>"); }
if ($ren!="") {
echo ("Переименовать файлы?<Ьг>"); foreach ($fl as $i) {
echo ("<input type=hidden name=afl[] value=$i>"); echo ("$i");
echo ("<input type=text size=3 0 name=rfl[] value=$ixbr>") ;
}
echo ("<input type=submit value=\"Переименовать\" name=ren>");
}
if ($md!="") {
echo ("Введите имя папки:<brxinput type=text size=3 0 name=newnamexbr><input type=submit value=\"Создать папку\" name=md>");
} ?>
<brxinput type=submit value="OTMeHa" name=otx/form>
</html>

Файл do.php

<?php
$begin="files";
if ((strpos($folder,$begin)!=0)|| (strpos ($folder, ".. . ") !=False) ) {
exit; }
function delfiles($fId) {
$hdl=opendir($fld); while ($file = readdir($hdl)) { if ( ($file! = ".")&&($file!=".."))
{
if (is_dir($fld."/".$file)==True) { delfiles ($fId."/".$file);
rmdir ($fld."/".$file); }
else {
unlink ($fld."/".$file) ; } } }
closedir($hdl); }
if ($udal!="") {
foreach ($fl as $i) {
if (is_dir($folder."/".$i)==True) {
delfiles ($folder."/".$i) ; rmdir ($folder."/".$i); }
else {
unlink ($folder."/".$i); } } }
if ($ren!="") {
for ($i = 0; $i < sizeof ($afl); $i++) {
if (($rfl[$i] ! = -)&($rfl[$i] !=$afl[$i])& (strpos($afl[$i],"..")==False)) {
$rfl[$i]=strtr($rfl[$i], " []{},/\!@#$%л&*",
'.__________________________" ) I
rename ($folder."/".$af1[$i] , $folder."/".$rfl[$i]); }
} }
function copyfold ($rt, $fld, $tgt) {
if (file_exists($tgt."/".$fId)!=True) {
mkdir ($tgt."/".$fld, 0666); }
179
$hdl=opendir($rt.V".$fld); while ($file = readdir($hdl)) {
if (($file!="..")&&($file!=".")) {
if (is_dir($rt."/".$fld."/".$file)==True) {
copyfold($rt."/"-$fld, $file, $tgt."/".$fId); }
else {
copy ($rt."/".$fld."/".$file, $tgt."/".$fld."/".$file) ;
} } } closedir($hdl);
}
if ($copy!="") {
foreach ($fl as $i) {
if (is_dir($folder."/".$i)==True) {
if (!(strpos ($rd, $folder."/".$i)===0)) {
copyfold($folder, $i, $rd); } }
else { copy ($folder."/".$i, $rd."/".$i);
} } }
if ($md!="") { $newname=$folder."/".strtr($newname,
{},/\!@#$%л&*",
"____________________")
mkdir ($newname, 0666);
Header ("Location: index.php?fold=$folder")


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 12. РНР: ПОЛЕЗНЫЕ МЕЛОЧИ

  • РНР: полезные мелочи
  • Счетчик посещений
  • Партнерская программа


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

PHP: ПОЛЕЗНЫЕ МЕЛОЧИ

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

СЧЕТЧИК ПОСЕЩЕНИЙ

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

<?php

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

$dirct="foldcount"; $cnt="counter.php";

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

if (file_exists("$dirct/$cnt")==True) {

считаем число из файла и запишем его в переменную $sr. Ее мы потом выведем на страницу в качестве показателя числа посещений, а также, увеличив на 1, получим число посещений, включая данное.

$hdl = fopen("$dirct/$cnt", "r+");
$sr = fread($hdl, filesize("$dirct/$cnt"));
fclose($hdl);
$sr++;
}

Примечание:
Для того чтобы из программы на РНР считать содержимое какого-либо файла или записать в него данные, этот файл нужно сначала открыть - командой fopen (так уж устроен РНР). При этом открытому файлу присваивается некое "внутреннее имя"' - так называемый дескриптор, и именно его возвращает функция /open. Первый параметр /open - имя файла (вместе с относительным или абсолютным путем к нему), второй - способ открытия файла.
В зависимости от второго параметра функции fopen файл может быть открыт по-разному - для чтения, для записи, с очисткой содержимого или нет. Возможные параметры fopen такие:
• г - открыть файл только для чтения и приготовиться читать его с начала.
• г+ - открыть файл для чтения и для записи и приготовиться работать с ним с его начала.
• w - открыть файл только для записи, предварительно удалив из него все содержимое, причем если файл с указанным именем не существует, то создается новый файл с таким именем.
• w+ - открыть файл как для записи, так и для возможного последующего чтения, предварительно удалив из него все содержимое, причем если файл с указанным именем не существует, то создается новый файл с таким именем.
• а - открыть файл только для записи и приготовиться дописывать данные в его конец. Если файл с указанным именем не существует, то создается новый файл с таким именем.
• а+ - открыть файл для записи и для чтения и приготовиться дописывать данные в его конец. Если файл с указанным именем не существует, то создается новый файл с таким именем.
Открываемый файл может располагаться и на удаленном сервере - в этом случае oft будет доступен только для чтения независимо от параметров открытия файла. Путь к файлу в таком случае следует указывать полностью - начиная с http:// или ftp://.

Если же файла со счетчиком нет, т. е. посещений раньше не было...

else

Справедливости ради стоит сказать, что такая фраза не совсем корректна по сути, но для практической работы подобный взгляд вполне можно использовать. 182
Глава 12. PHP: полезные мелочи то просто присвоим переменной со сведениями о количестве посещений значение 1.

$sr=l;

Выведем на страницу данные о числе посетителей... echo ("Посетителей - $sr");
и, снова открыв файл счетчика, но теперь уже для записи и очистив все его содержимое (видите параметр "w+"?), запишем в него значение переменной со сведениями о количестве посещений:

$hdl2 = fopen("$dirct/$cnt", "w+");
fwrite($hdl2, $sr);
fclose($hdl2);

Вот, собственно, и все (рис. 12.1).

Рис. 12.1. Счетчик посещений - всего с десяток строчек

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

$cnt="counter.php";

следует вставить строку, определяющую имя текущего файла на основе значения переменной $PHP_SELF:

$cnt=substr(basename($PHP_SELF), 0, -4). "_cnt.php";

Этот код выделяет из адреса страницы ее имя (без расширения) и создает на его основе уникальное имя файла счетчика (просто добавляя в конец имени страницы комбинацию символов "_cnt .php").


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПАРТНЕРСКАЯ ПРОГРАММА

Если вы когда-нибудь посещали Интернет-магазины, то наверняка видели в некоторых из них раздел "Партнерская программа". Суть такой программы проста - это предложение web-мастерам различных сайтов размещать на их страницах ссылки на магазин, и в том случае, если совершивший покупку посетитель пришел именно по такой ссылке, то тот, кто разместил ссылку, получает определенный процент от денег, выплаченных посетителем за товар.
Если вы на своем сайте также осуществляете прием заказов на что-либо от посетителей (например, у вас есть простой Интернет-магазин вроде описанного в гл. 5), то организовать партнерскую программу вы сможете буквально четырьмя строками кода на РНР.
Через гиперссылку, ведущую на какую-нибудь web-страницу, можно передать программе на этой web-странице значения переменных. Для этого следует после адреса web-страницы, на которую ссылка ведет, поместить знак вопроса, имя переменной и ее значение после знака равенства - www. domen. ru?perem=znach (можно передать и несколько переменных, записывая их одну за другой и разделяя амперсандом - &:

www.domen.ru?pereml=znachl&perem2=znach2).

В результате в сценарии на странице окажется доступной переменная с соответствующими именем и значением.
Понятно, что для того чтобы иметь возможность выделять среди всего потока приходящих на сайт тех, кто пришел от партнеров, достаточно указывать в партнерской ссылке значение определенной переменной, естественно, уникальное для каждого партнёра. Например, что-то вроде www. domen. ru?partner=ivanov.
Если в сценарии на той странице, куда ведет такая ссылка, имеется команда отправки письма, то можно значение этой переменной включить в отправляемое письмо. Однако довольно трудно представить себе такую ситуацию, так как обычно команда mail обрабатывает данные, переданные на содержащую ее страницу из формы, расположенной на другой странице того же сайта. Поэтому возникает вопрос - как "отловить" переданную переменную - партнерский идентификатор на той странице, на которую приходят посетители от этого партнера, и потом включить ее в письмо-заказ на странице с командой отправки почты. При условии, разумеется, что до отправки заказа посетитель, возможно, обойдет еще множество других страниц сайта?
Самым простым, но достаточно действенным способом решения такой проблемы будет использование cookies (подробнее о cookies рассказано в гл. 8). На тех страницах сайта, на которые будут указывать размещаемые партнерами ссылки, следует разместить код:

<?php
if ($partner!="")
{ SetCookie("prtn",$partner, ""); }
?>

В результате в том случае, если в ссылке окажется переменная partner, в браузер посетителя будет отправлен cookie под названием prtn с ее значением. Помните, что установка cookie должна предшествовать любому выводу в выдаваемый документ - поэтому данный код должен стоять в самом начале документа, до каких-либо тэгов HTML.
Ну а в код той страницы, в которой составляется и отправляется письмо с заказом, достаточно включить переменную, сохраненную в cookie. Например, команда отправки почты из рассмотренного в гл. 5 примера будет выглядеть так:

mail ("mail@harchikov.ru", "Заказ на кассеты", "С адреса $email пришла заявка на приобретение $kolv кассет на общую сумму $summa рублей: $zak. Контактные данные заказчика: $cont, партнерский идентификатор - $HTTP_COOKIE_VARS['prtn']", "From: $email\nReply-To: $email\nContent-Type: text/plain; charset=windows-1251");
Вот и все. Если посетитель зашел на ваш сайт от партнера, то вы об этом узн

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 13. РНР: СПОСОБЫ ПЕРЕДАЧИ ДАННЫХ МЕЖДУ ОТДЕЛЬНЫМИ СТРАНИЦАМИ

  • Краткая справка
  • Переменные в адресной строке
  • Cookies
  • Сессии (возможно только в РНР версий 4.0 и выше)
  • Пользовательская форма
  • Установленные переменные (только для переменных авторизации - $PHP_AUTH_USER и $PHP_AUTH_PW)


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

КРАТКАЯ СПРАВКА

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПЕРЕМЕННЫЕ В АДРЕСНОЙ СТРОКЕ.

Переменные указываются за вопросительным знаком, поставленным после адреса страницы, и разделяются амперсандом:

http://www.domen.ru/page.php?perl=znachl&per2=znach2

В результате вызова страницы page.php домена http: //www.domen.ru сценариям на этой странице будут доступны указанные в адресной строке переменные perl (со значением znachl) и рег2 (со значением znachl).
Данный способ подходит тогда, когда на содержащей подобные ссылки странице значения переменных уже известны и их надо передать другому сценарию - тому, на страницу с которым по ссылке переход и произойдет. Однако имейте в виду, что какие-либо секретные данные так передавать нельзя - подделать адресную строку, вручную указав в ней другие значения переменных и тем самым передав сценарию-обработчику именно их, труда не составит.
Значения переменных можно передавать и дальше так же через адресную строку - для этого достаточно просто помещать их в тексты ссылок на той странице, сценарию на которой они передаются. Скажем, если на странице page.php находятся ссылки на страницы pagel.php, page2.php, и им также следует передать значения переменных perl и рег2, то эти значения следует добавить в эти ссылки, выведя их с помощью кода на РНР:

<а href=pagel.php?perl=<?php echo($perl); ?>&per2=<?php echo($per2); ?>>Ссылка</а>


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

COOKIES

Для передачи данных между страницами можно использовать cookies - файлы, пересылаемые web-сервером браузеру посетителя и сохраняемые им на компьютере посетителя. Все современные браузеры поддерживают cookie.
Установив cookie на одной из страниц сайта (подробнее о cookies рассказывалось в гл. 8), вы можете использовать записанные в него переменные на всех остальных страницах сайта (расположенные на том же Интернет-узле - т. е. с тем же доменным именем).
При установке cookie ему дается определенное имя. Впоследствии сценариям на всех страницах этого Интернет-узла браузер посетителя передает при заходе на них переменную, одноименную с этим cookie и содержащую записанные в cookie данные (если в файле php.ini установлен в on параметр register_globals). Кроме того, сценарии на РНР могут получать данные cookie из массива $HTTP_COOKIE_VARS [ 'имя cookie '],ав РНР версий 4.1 и выше - еще и из массива $_СООК1Е [' имя переменной' ] (если в файле php.ini установлен в on параметр track_vars).
Если сведения, передаваемые через cookie, нужно защитить от подделки (т. е., скажем, обеспечить их получение только из cookie и никоим образом не из адресной строки, куда значения одноименных с сохраненных в cookie переменных злоумышленник может подставить), то в сценарии, где используются переменные из cookies, следует их считывать только из упомянутых массивов, а не из одноименной cookie переменной. В указанные массивы попадают исключительно те данные, которые сохранены в cookies.
Одновременно можно устанавливать как один, так и несколько cookies.
Данный способ подойдет тогда, когда данные, введенные на одной странице, могут потребоваться на прямо не связанной с ней другой. Ограничения же связаны с особенностями cookie: количество информации в cookie не может превышать 4 килобайта, cookie может похитить с компьютера посетителя любой, кто за него сядет. Кроме того, некоторые пользователи Интернета отключают cookie при путешествиях по Сети, что не дает возможности использовать данный способ абсолютно для всех посетителей.
Помните, что отправка и чтение cookie должны производиться до какого бы то ни было вывода в документ.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

СЕССИИ (ВОЗМОЖНО ТОЛЬКО В РНР ВЕРСИЙ 4.0 И ВЫШЕ)

Как уже говорилось в гл. 8, передача информации между страницами возможна с помощью механизма работы с сессиями. Смысл его в том, что значения определенных переменных сохраняются в файле в папке временных файлов сервера, а посетителю отправляется в cookie уникальный идентификатор этого файла (или, если браузер посетителя cookie не принимает, идентификатор присоединяется ко всем ссылкам на сайте, ведущим на другие его страницы). Впоследствии при получении от посетителя идентификатора сессии (имя cookie, содержащего его, жестко определяется в настройках web-сервера) в том случае, если в папке временных файлов существует соответствующий этому идентификатору файл, этот файл считывается и значения всех переменных, указанные в нем, передаются сценариям на страницах сайта.
Открыв сессию командой session_start ()1 и зарегистрировав для сессии нужные переменные командой session_register (), можно в сценариях на других страницах сайта (после вызова той же команды session_start ()) работать с этими переменными, как если бы они были определены и установлены в этих же самых сценариях. (Подробнее о данных командах и особенностях их использования в зависимости от настроек файла php.ini читайте в Описании РНР.)
Кроме того, все эти переменные доступны как элементы массивов $HTTP_SESSION_VARS и (в РНР 4.1) $_SESSION (использовать эти массивы предпочтительнее, так как при этом отсутствует риск передачи значений переменных сценарию-обработчику путем указания их значений в адресной строке при неоткрытой сессии).
Подробнее о сессиях читайте в гл. 8.
' Если в php.ini установлен в on параметр session.auto start, то открывать сессию для ее использования не обязательно - достаточно лишь зарегистрировать нужные переменные командой sessionregister, чтобы они сохранялись в качестве сессионных.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПОЛЬЗОВАТЕЛЬСКАЯ ФОРМА

При нажатии кнопки типа submit в пользовательской форме данные, введенные в ее поля, передаются сценарию, расположенному на указанной в параметре action заголовка формы страницу. Они доступны в этом сценарии в переменных, одноименных с соответствующими элементами формы (если в файле php.ini установлен в on параметр reg-ister_globals), а также через массивы $HTTP_POST_VARS (если в файле php.ini установлен в on параметр track_vars) и $_POST (в РНР версий 4.1 и старше).
В форме также могут быть указаны скрытые поля - т. е. поля типа hidden. В эти поля посетитель не может вводить свою информацию, однако данные, указанные в их параметрах value, отправляются вместе с формой сценарию-обработчику.
Принцип передачи данных по страницам с помощью формы прост: один скрипт выводит на страницу в форму скрытые поля с нужными данными, а другой скрипт - обработчик формы - их использует. Недостаток этого способа ясен: данные скрытых полей можно узнать, просмотрев исходный код страницы с формой, так что защита от подделки и вообще мало-мальская конфиденциальность здесь отсутствует.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

УСТАНОВЛЕННЫЕ ПЕРЕМЕННЫЕ (ТОЛЬКО ДЛЯ ПЕРЕМЕННЫХ АВТОРИЗАЦИИ - $PHP_AUTH_USER И $PHP_AUTH_PW)

Две строчки введенной посетителем информации можно передать между страницами и с помощью авторизационных переменных -$PHP_AUTH_USER и $PHP_AUTH_PW. Будучи раз определенными, эти переменные сохраняют свое значение до закрытия того окна браузера, в котором они были введены, и всех окон, из этого окна открытых по ссылкам. Однако получить от посетителя те данные, которые планируется записать в эти переменные, можно только с помощью специального диалогового окна авторизации и только до начала вывода web-страницы, на которой эти данные запрашиваются.
Подробнее о работе с этими переменными читайте в гл. 8.
Так что, как видите, способов много. Выбирайте на вкус. Наиболее многообещающим представляется использование сессий, хотя и без данного механизма РНР предоставляет немало возможностей.
Ну а если требуется сохранять данные посетителя между его визитами, причем независимо от компьютера, на котором тот работает, - то
тут выходом будет запись данных в файл или базу данных. Запись данных в файл подробно рассматривалась в гл. 9 и 10, а технология работы с базами данных - уже тема отдельной книги, тем более что она различна для разных типов систем управления базами данных.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ЗАКЛЮЧЕНИЕ

История РНР - прекрасный пример того, как изобретение, действительно нужное людям, способно завоевать весь мир. Начавшись с небольшого приложения, созданного энтузиастом-любителем, РНР превратился в самый массовый и самый многофункциональный язык web-программирования. Простой синтаксис и логичная структура, отсутствие затрудняющих работу особенностей, модульность конструкции интерпретатора, легкость взаимодействия с базами данных - все это и сделало РНР таковым.
Освоить РНР может каждый. Наличие множества весьма информативных ресурсов Интернета и полнота официального описания языка делают этот процесс легким и быстрым. Для реализации довольно широкого круга задач вполне хватит даже простой модификации фрагментов кода, приводимых в справке к официальному описанию. А, как показано выше, РНР позволяет не только дать посетителям сайта новые возможности, но и серьезно облегчить труд создателя сайта, тем самым сэкономив больше времени, чем окажется затрачено на его освоение.
Поэтому вы никогда не пожалеете, что занялись изучением этого языка программирования.
Если вы читали эту книгу последовательно, от первой страницы до этой, то не торопитесь ее закрывать. В трех Приложениях, следующих за этой страницей, вы найдете информацию, которая наверняка вам пригодится при «сайтостроении». Ибо, к сожалению, сведения, приводимые в них, не так уж и широко известны.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

    ГЛАВА 2. РНР: ИСТОРИЯ. МЕСТА. ИСТОЧНИКИ

    • РНР: История. Места. Источники.
    • C чего начать?
    • Места
    • РНР в России


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

PHP: ИСТОРИЯ. МЕСТА. ИСТОЧНИКИ

В отличие от многих других языков программирования, РНР был создан не какой-либо корпорацией или гением-программистом, а обычным пользователем, Расмусом Лердорфом, в далеком 1994 году. Цель разработки языка была проста - сделать домашнюю страничку Расмуса более интерактивной, а значит, и более привлекательной для посетителей. Расмус разработал базовый синтаксис и написал первый интерпретатор своего языка, получившего название Personal Home Page Tools - т. е. РНР. Этот интерпретатор мог обрабатывать лишь несколько основных команд, однако начало было положено.
В 1995 году Расмус доработал интерпретатор РНР, соединив его с другой своей программой, умевшей обрабатывать HTML-формы (именовавшейся FI - от "Form Interpretator"), а также сделал так, что интерпретатор, получивший название PHP/FI Version 2, мог становиться частью web-сервера. Это новшество позволило программам на РНР исполняться очень быстро. Кроме того, в том же 1995 году интерпретатор РНР был дополнен возможностями1 обработки новых команд, в частности, команд для работы с серверами баз данных и автоматического создания gif-файлов (последнее, к примеру, может быть использовано для генерации кнопок-счетчиков посещений). PHP/FI был размещен в Сети для всеобщего использования, и началось его повсеместное распространение. К концу 1997 года РНР использовался более чем на пятидесяти тысячах сайтов.
Web-мастера быстро оценили достоинства нового языка web-программирования, такие как легкость освоения и богатство возможностей, и вскоре традиционные Perl и С стали сдавать свои позиции. Так как исходный код интерпретатора был открыт (а сам интерпретатор, понятно, бесплатен), то энтузиасты стали заниматься его доработкой, и летом 1998 года появился на свет РНРЗ - детище Зива Сураски и Энди Гутманса (Zeev Suraski and Andi Gutmans). РНРЗ был создан практически "с нуля", так как его авторы сочли код предыдущих версий недостаточно эффективным. Кроме того, РНРЗ стал весьма легко расширяемым продуктом. Любой, создавший на основе определенных стандартов модуль расширения РНР, позволяющий, скажем, работать с архивами какого-либо типа, мог этот модуль интегрировать с программными файлами РНР без каких-либо серьезных затрат времени и сил. Уже к концу 1999 года число сайтов, построенных на основе РНР, перевалило за миллион. Весьма важным достоинством РНР также являлось то, что программы, позволявшие обрабатывать команды РНР, были созданы практически для всех операционных систем, от Windows до Unix и Linux.
В 2000-м году вышла разработанная компанией Zend Technologies четвертая версия интерпретатора РНР, дополненная множеством новых функций. В настоящее время именно она является наиболее распространенной - РНР используется более чем на 20% сайтов Сети. Сейчас готовится уже пятая версия данного языка.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

С ЧЕГО НАЧАТЬ?

Основным источником сведений по РНР является официальный сайт его разработчиков - www.php.net (рис. 2.1). Именно на этом сайте представлены дистрибутивы различных версий РНР для различных платформ. Также на www.php.net размещаются руководства по РНР на разных языках, а, кроме того, - списки сайтов, посвященных программированию на РНР.

Рис. 2.1. Официальный сайт РНР

Однако тем, кто желает разработать сайт с применением РНР, возможно, лучше посетить прежде всего русский сайт "РНР по-русски" (рис.2.2), расположенный по адресу http://php.spb.ru, и загрузить с него два файла - полное описание РНР на русском языке (перевод руководства по РНР с сайта www.php.net) и web-сервер Apache с РНР-мо-дулем, сконфигурированным для немедленного использования. Оба файла подготовил и разместил в Сети ведущий этого сайта Дмитрий Бородин.

Рис.2.2. А это - русский сайт по РНР. Ясно, коротко, доступно

Первым делом установите на своем компьютере web-сервер Apache из загруженного файла (этот процесс подробно описан на сайте Дмитрия Бородина, в статье по адресу http://php.spb.ru/php/install_module.html) и освойте его использование. В последнем нет ничего сложного - достаточно внимательно прочитать статью Дмитрия и файлы Readme из дистрибутива. После этого вы сможете полноценно работать с программами на РНР на своем компьютере, не выходя в Интернет, например, тестировать разработанные с использованием РНР сайты. (Версия РНР на сайте Дмитрия на момент написания этого текста была 4.0.6, в руководстве же рассматривается третья версия языка. Однако подавляющее большинство функций в третьей и четвертой версиях языка одинаковые, заметные различия есть разве что в технологии использования некоторых глобальных переменных и в наличии в 4-й версии механизма сессий - об этом будет рассказано в последующих главах.)
Ну а затем приступайте к изучению языка. В нескольких следующих главах изложены самые основные его понятия и описаны базовые команды, с помощью которых можно создать неплохие РНР-программы. За остальной информацией обращайтесь к описанию языка, тем более что оно переведено на русский язык и снабжено массой примеров кода. Только помните, что в том дистрибутиве web-сервера, о котором говорилось выше, отсутствуют модули, расширяющие возможности РНР, так что некоторые разделы описания будут неактуальны. Впрочем, ничего не мешает вам загрузить нужные модули отдельно и установить их (на сайте http://php.spb.ru описано, как это сделать), однако первое время такая необходимость у вас вряд ли появится.
Русскую версию учебника по РНР для версий 4.0 и выше вы можете загрузить как с сайта разработчиков РНР, так и с некоторых русских сайтов, например, с ресурса Александра Пирамидина -http://pyramidin.narod.ru.
Готовый к использованию web-сервер вместе с интерпретатором РНР, а также системой управления базами данных MySQL вы также можете найти на сайте проекта "Денвер", расположенном по адресу http://dklab.ru/chicken/web (рис.2.3). В отличие от вышеупомянутого ресурса "РНР по-русски", ведущие проекта "Денвер" Дмитрий Котеров, Дмитрий Короленко, Игорь Светликов и Андрей Любченко регулярно обновляют свой проект, постоянно размещая на нем свежие версии web-сервера с набором компонентов. Однако установка "Денвера" более автоматизирована, нежели набора с сайта "РНР по-русски", и предусматривает значительно меньшую ее "управляемость".
"Денвер" можно порекомендовать тем, кто предпочитает автоматически получить на своем компьютере готовый к использованию web-сервер в целях изучения языка РНР и создания на нем программ, а "РНР по-русски" понравится тому, кто привык все, что ему надо, настраивать сам. Тем более что последнее будет весьма легко - достаточно внимательно прочитать комментарий Дмитрия с сайта и файлы Readme из дистрибутива.

Рис. 2.3. Проект "Денвер"

Для написания кода на РНР подходит любой текстовый редактор -от "Блокнота" до "Script Editor" из пакета Microsoft Office, здесь выбор зависит от вашего личного вкуса и желания.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

МЕСТА

РНР - язык программирования, выполняющийся на стороне web-сервера, поэтому выполнение его команд нагружает компьютер, на котором установлен интерпретатор этого языка. Вследствие этого на серверах бесплатного хостинга использование РНР обычно невозможно или сопровождается необходимостью установки рекламных банне-ров этого сервера. Однако практически на всех серверах платного хостинга проблем с использованием РНР не возникает, и при разработке сайта можно полноценно применять возможности этого языка.
В RuNet'e использовать РНР разрешается, например, на таких бесплатных серверах, как http://www.hl.ru, http://webservis.ru, http://wallst.ru, http://www.hut.ru, http://meridian.tomsk.ru, на иностранных - http://www.saxen.net и многих других. Однако, при выборе бесплатного хостинга для размещения сайта помните, что в подавляющем большинстве случаев вам придется в обязательном порядке размещать на своих страницах рекламные баннеры (за их показ на вашем сайте рекламодатели платят деньги компании, владеющей сервером хостинга. Эти деньги, собственно, и служат оплатой поддержки размещенных на этом сервере сайтов). Кроме того, весьма часто владельцы хостингов с поддержкой РНР и других CGI-языков запрещают размещать на сайтах, расположенных у них, файлы zip, rar, ехе, трЗ. Впрочем, последнее условие можно обойти, использовав для хранения таких файлов другой бесплатный сервер, - пусть и без поддержки РНР.
На рынке платного хостинга ситуация другая - сейчас уже трудно найти хостинг, где бы, наоборот, не предлагали использовать РНР. Тарифные планы, не предполагающие использование РНР, сохранились разве что у некоторых провайдеров услуг доступа в Интернет, параллельно предоставляющих и услугу размещения web-сайтов за отдельную плату. Так что для построения сайтов, использующих РНР, можно выбирать практически любой сервер платного хостинга, оценивая его по различным другим критериям (цена, надежность, скорость и т. д.). Достаточно трудно рекомендовать какую-либо определенную фирму, однако можете попробовать ValueHost (www.valuehost.ru), www.350mb.ru, www.net.ru и другие.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

РНР В РОССИИ

Основной русский ресурс по РНР - это, несомненно, сайт Дмитрия Бородина "РНР для всех" (http://php.spb.ru, зеркало -http://rusphp.chat.ru), о котором уже упоминалось выше. Его содержимого практически достаточно для начала работы и изучения основ РНР, поэтому его посещение весьма и весьма желательно.
Другим большим порталом, посвященным РНР, является "Клуб РНР-разработчиков" (http://www.phpclub.net). Там вы найдете множество примеров сценариев на РНР, сможете загрузить литературу на русском языке. Форум разработчиков на РНР (рис. 2.4), размещенный на этом сайте, даст вам возможность получить от профессионалов в web-программировании ответ на свой вопрос, принять участие в каком-либо обсуждении или пообщаться с коллегами в чате. Архив Форума содержит в себе ответы практически на все возможные вопросы по web-программированию на РНР. Также в "Клубе РНР-разработчиков" регулярно публикуются новости мира РНР-программирования, рассказывается о новых разработках в этой области, размещается информация о вакансиях web-дизайнеров и программистов на рынке труда.

Рис. 2.4. Клуб РНР. Спрашивайте и отвечайте

Подразделением "Клуба PHP-разработчиков" является сайт "РНР в деталях" (рис. 2.5) - http://detail.phpclub.net, на котором представлены готовые программы на РНР, а также немало интересных сведений по этому языку.
В Сети есть немало и других сайтов с информацией о РНР:

  • http://php.itsoft.ru,
  • http://virtual.bresttelecom.by/php,
  • http://www.providerz.ru/articles/php и другие.

Рис.2.5. PHP в деталях. Для тех, кому мало ответов в форумах


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 3. РНР: ОСНОВЫ

  • РНР: основы
  • Работа с формами


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

PHP: ОСНОВЫ

Синтаксис PHP довольно простой. Программы на РНР встраиваются в текст web-страницы так же, как и сценарии на JavaScript, VBScript, при помощи окаймляющих угловых скобок с вопросительными знаками и указанием языка:

<?php
...
текст программы
...
?>

Команды РНР обязательно разделяются символом точки с запятой - ";" (символ конца абзаца или конца строки не учитывается никак), после последней в программе команды его можно не ставить. Также символ ";'' не ставится после условных операторов (if, switch) и операторов цикла (for, while и других).
Пример программы на РНР - на рис. 3.1.

Рис. З.1. Программа на РНР (выделена жирным) в тексте web-страницы

Как и во всех языках программирования, в РНР есть возможность работать с переменными - некими объектами, имеющими имя и могущими принимать различные значения. Однако работа с переменными в РНР, пожалуй, самая легкая из всех возможных. Переменные не надо заранее объявлять (если не знаете, что это такое - то пока и не надо), разве что за исключением использования их в функциях. Для введения новой переменной достаточно просто присвоить ей какое-либо значение, а для помещения значения переменной в строку текста, имени файла или параметра команды, нужно просто написать ее имя в том месте, где должно быть ее значение. Чтобы РНР мог отличать переменные от строк или команд, имя переменной должно начинаться со знака доллара - ("$") и не должно содержать пробелов, знаков апострофа и некоторых других символов. При анализе программного кода интерпретатор РНР считает именем переменной все, что содержится между $ и ближайшим к нему символом, недопустимым в имени переменной.
В качестве имен переменных можно также использовать другие переменные - для этого другую переменную следует просто указать на месте имени первой: $$а.
Переменные в РНР могут быть четырех типов - число (целое и дробное), строка текста, массив и объект1. Интерпретатор РНР автоматически определяет тип переменной на основании анализа ее содержимого. Подробнее о типах данных вы можете узнать в руководстве по РНР (например, в том, что доступно с сайта "РНР по-русски"), там же рассказано и об особенностях работы с массивами (и вообще объяснено, что это такое, если вы еще не знаете).
Для включения числовой или строковой переменной в строку текста достаточно просто поместить переменную туда, где она должна стоять в этой строке. Например, в итоге выполнения кода $а="птица певчая"; $b="Дятел - $а"; переменной $b будет присвоено значение "Дятел - птица певчая".
Помните, что в РНР нельзя для сложения строковых переменных использовать символ "+" - он пригоден лишь для числовых выражений. Поэтому необходимо помещать переменные в строки или использовать команду конкатенации (точку): $с = $а. $b.

Есть еще два типа переменных - PDF-документ и PDF-инфо, но они применяются только при работе с файлами PDF (и при установленном модуле поддержки PDF).

Довольно часто используются сокращенные обозначения арифметических действий над переменными и действий по присваиванию им каких-либо значений. Например, команда $а+=3 означает, что переменную $а надо увеличить на 3, что и будет сделано, если она имеет числовой формат. Точно так же команда $а- = 3 уменьшает переменную $ а на 3, а команды $а*=2 и $а/=2 соответственно умножают и делят на два переменную $а. Команда $а.=" строка" эквивалентна команде $а="$а строка".
В РНР применяются также операции инкремента и декремента -т.е. изменения значения переменной на 1. Так, команды $а++ и $а-- соответственно увеличивают и уменьшают значение переменной $а на единицу. То же самое делают и команды ++$а, --$а, однако, в том случае, если подобная команда используется в выражении, они, в отличие от предыдущих, сначала изменяют значение переменной, а потом выдают его в выражение. Иными словами, если переменная $а равна 2, то после выполнения команды $b=$а++; ее значение достигнет 3, а $b будет установлена в 2. В то же время команда $b= + + $а; установит обе переменные в 3.
Массив - это совокупность под одним именем перенумерованных переменных. Имя каждой переменной в массиве состоит из имени этого массива и индекса переменной - нечто вроде номера переменной в массиве или ее имени в нем. Индекс переменной может быть цифровым или символьным - т. е. представлять собой либо номер переменной в массиве, либо ее имя в нем.
Например, вот массив с числовыми индексами (нумерация индексов начинается с нуля, а не единицы!):

$а[0]=100; $а[1]=101; $а[2]=102;

а вот с символьными:

$а['first']=100; $а['second']=101; $а['third']=102;

(Массив с числовыми индексами называется еще "скалярным", а с символьными - "ассоциативным".)
Зачем нужны массивы? А для того чтобы можно было к ним обращаться как к чему-то целому, тем самым получая возможность возможность совершать автоматические действия со всеми элементами массива или с частью этих элементов, не указывая имени каждого их элемента.
Иными словами - скажем, в какие-то переменные записали имена клиентов и теперь желаем вывести их. Как это сделать? Естественно, только перебрав все эти переменные, для чего нам понадобятся имена этих переменных, которые придется жестко задать в программе. А если заранее неизвестно, сколько будет клиентов, как тогда быть? Если же имена клиентов поместить в массив, то все их можно перебрать специальной командой, добавить же новое имя тоже нетрудно.
В РНР добавлять элементы в массив можно как явно указывая индекс элемента (например, $а [100] = "Андрей";), так и просто упоминая, в какой массив этот элемент добавляется - $а [ ] ="Андрей" ;. В последнем случае добавляемый элемент становится последним в массиве.
Ниже перечислены некоторые основные команды РНР, которых вполне хватит для реализации несложных проектов. Для более полного ознакомления с командами РНР можно изучить Руководство по этому языку, доступное, например, с адреса http://php.spb.ru, или другие публикации.
include "имя файла" - команда для включения содержимого одного файла в другой. Содержимое файла, имя которого указывается в команде, целиком и полностью вставляется на то место, где располагается эта команда, при этом все коды РНР, содержащиеся во вставляемом файле, исполняются так же, как если бы они были на месте этой команды. (Помните, что файл именно вставляется - т. е., например, пути к картинкам, которые должны присутствовать во вставляемом файле, следует указывать от местонахождения того файла, в котором находилась команда include.)
Если файл, включаемый в страницу при помощи команды include, отсутствует, то вместо него размещается уведомление об этом, а программа на РНР выполняется дальше. (При необходимости завершения обработки и выдачи web-страницы в случае отсутствия включаемого файла, вместо команды include следует использовать команду require.)
mail ("Кому", "Тема", "Текст сообщения", "Дополнительные заголовки") - отправка почтового сообщения. При выполнении данной команды на сервере в соответствии с указанными параметрами формируется электронное письмо и отправляется с помощью установленной на сервере почтовой программы. В качестве параметра "Кому" может выступать набор адресов, разделенных запятыми. "Дополнительные заголовки" могут быть любые (естественно, допустимые почтовыми протоколами!), разделяться они должны должны комбинацией символов /п, которая в РНР означает перевод строки. (Если среди "Дополнительных заголовков" не указано поле From, то оно заполняется по умолчанию почтовой программой web-сервера, например, именем "Unprivileged User".)
echo ("текст") - вывод на web-страницу какого-либо текста. Чтобы вывести на web-страницу значение какой-либо переменной, достаточно просто написать ее имя внутри выводимой строки: команда echo "это цифра $а" выведет в web-страницу текст "это цифра 1", если ранее переменной $а было присвоено значение, равное единице. В случае необходимости использовать в выводимой строке кавычки или иные специальные символы перед этими символами следует ставить символ " \".
if (условие) {...команды, которые должны выполняться, если условие верно...;} else {...команды, которые должны выполняться, если условие неверно...} -команда, позволяющая выполнить то или иное действие в зависимости от истинности верности или ложности того или иного условия. В фигурных скобках может располагаться несколько команд, разделенных точкой с запятой. В качестве условия может быть оператор сравнения "равно" - ("==") (именно два-знака равенства!), "больше" -(">"), "меньше" - ("<") и их комбинации, скажем, "< = " - ("меньше или равно"). Можно использовать и несколько условий, взяв каждое из них, а также все вместе в скобки и разделяя знаками "&&" - ("и") или "| |" -("или").
Для того чтобы выполнять различные команды в зависимости от условия, которое может принимать три или больше значений, следует использовать оператор switch (описание смотрите ниже) - аналог оператора case в VBA и некоторых других языках.
for (начальное значение счетчика, условие продолжения цикла, изменение счетчика на каждом цикле) { . . . команды. . . ;} - цикл, т. е. повторение указанных в нем команд столько раз, сколько позволит условие изменения счетчика цикла (т. с. переменной, специально выделенной для подсчета числа выполнений команд цикла). К примеру цикл for ($i = 1; $i <= 10; $i + +) {echo $i;} выводит в web-страницу числа с 1 до 10, так как в нем изначально устанавливается значение счетчика в 1 - ($i = l), каждый цикл его значение увеличивается на 1 - ($i ++), а продолжаться он будет до тех пор, пока значение счетчика не превысит 10 (т. е. пока $i< = 10).
while (условие) { . . .команды. . . } - цикл с условием. Команды в фигурных скобках выполняются до тех пор, пока выполняется условие в заголовке цикла. Для того чтобы цикл прервался, нужно, чтобы условие выполняться перестало - поэтому внутри цикла необходимо предусмотреть возможность влиять на это условие. Скажем, цикл while ($i<=10) { . . .команды. . . ; $i++; } будет выполняться до тех пор, пока значение переменной $i не превысит 10 -если изначально оно было равно 1, то цикл выполнится 10 раз.
Цикл do {. . .команды. . . } while (условие) работает так же, однако команды, указанные в фигурных скобках, будут выполнены по меньшей мере один раз - даже если условие выполняться не будет.
Прервать выполнение любого цикла можно оператором break -дальнейшее выполнение программы пойдет с команды, следующей после закрывающей фигурной скобки. Оператор же continue прерывает текущую стадию выполнения цикла, т. е. после этого оператора дальнейшее выполнение программы начнется с очередной проверки условия заголовка цикла.
switch (выражение) {case значение: ... команды...; break; case другое значение: ... команды...; break;}
- оператор выбора. При его работе содержимое, заключённое в фигурные скобки, просматривается сверху вниз. Как только будет найден оператор case со значением, совпадающим со значением выражения, РНР начнёт выполнять весь код, следующий за этим оператором case до последней фигурной скобки оператора switch или до первого оператора break, в зависимости от того, что появится раньше. (Обратите внимание, что если команду break не указать в конце кода, относящегося к одному варианту значения выражения в заголовке оператора switch, PHP будет выполнять код дальше - т. е. тот, который принадлежит уже следующему оператору case! Это - одно из отличий данного оператора от аналогичных в других языках программирования.)
В конце оператора switch можно указать оператор default. Код, стоящий после него, выполнится в том случае, если значение выражения в заголовке оператора не совпадет ни с одним из значений после операторов case.
foreach (переменная as массив) { . . .команды. .. ;} - поочередное считывание всех элементов массива. Foreach считывает в указанную в его параметрах переменную поочередно все элементы указанного в них же массива, выполняя каждый раз указанный в фигурных скобках код, в котором может использоваться указанная переменная. (Значения элементов массива этим оператором только считываются, их модификация при помощи команды f oreach невозможна.) Оператор f oreach может быть использован только в РНР версии 4.0 и выше.
Программа на РНР может прерываться кодом web-страницы - для этого достаточно вставить закрывающий тэг до этого кода и открывающий - после. Все, что находится между ними, будет выдаваться в браузер без какой-либо обработки, рассматриваясь как выводимое с помощью команды echo. Иными словами, код

<?php if ($a==l) { ?><р>Переменная а равна 1</p><?php> }?>

эквивалентен коду

<?php if ($a==l) {echo "<p> Переменная а равна
1</p>";}?>

однако, первый вариант меньше нагружает процессор компьютера, на котором расположен интерпретатор РНР.
Из сказанного также следует, что все программы на РНР, расположенные на одной web-странице, представляют собой одну большую программу, несмотря на то, что они разделяются блоками обычного текста страницы. Именно поэтому переменная, объявленная в расположенном в начале страницы коде, сохраняет свое значение не только до ее конца, но и во всех присоединяемых с помощью команды include файлах. Пример - на рис. 3.2.
В РНР можно создавать функции - подпрограммы, которые можно вызывать по своим именам, при необходимости передавая им определенную информацию. Необходимы они в том случае, когда один и тот же код нужно выполнять несколько раз для разных данных, особенно если требуемое количество выполнений заранее неизвестно. Создать функцию на РНР можно, вставив в программу инструкцию function имя (переменные, в которые записываются передаваемые параметры, и их тип) {...команды функции . . . }, а вызвать - простым указанием имени этой функции и параметров.

Рис. 3.2. Пример PHP-кода. Посмотрите внимательно на код и результат его
отображения. Обратите внимание, что переменная а, которой присвоено
значение еще в первом программном блоке левой страницы, сохранила его
не только в других ее блоках, но и в программе, расположенной во
включаемой с помощью команды include странице

Помните, что переменные, созданные в функции, по умолчанию имеют установленное значение только внутри функции. Кроме того, также по умолчанию переменные, объявленные вне функции, в ней самой никакого значения не имеют, а если надо, чтобы имели, то вначале функции их следует "подключить" командой global <пе-ременная>; - и лишь после этого они станут доступными в функции. Подробнее о функциях и о переменных в них читайте в руководстве по РНР, например, с того же сайта http://php.spb.ru.
Обычно web-сервер настраивается так, что на предмет наличия программ на РНР просматриваются файлы, имеющие расширение .php, .php3, .phtml, остальные же файлы передаются в браузер пользователя без поиска в них команд РНР. Делается так для более быстрой работы сервера, а также для обеспечения возможности установки на сервере разных интерпретаторов (например, SSI - Server Side Includes, технологии, в какой-то мере предшествовавшей РНР), так как тогда каждому из интерпретаторов назначаются свои расширения для обработки соответствующих файлов.
Так как РНР-код полностью исполняется на web-сервере, то в страницах, выдаваемых браузеру, он будет отсутствовать, и если кто заинтересуется вашим опытом программирования, то вам придется отправлять ему этот код по почте, так как при просмотре сайта каким-нибудь образом узнать исходный PHP-код его страниц нельзя.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

РАБОТА С ФОРМАМИ

Значения переменных можно передавать между различными страницами сайта - с помощью использования форм. Формой называется конструкция, состоящая из поименованных элементов особых типов, заключенных между HTML-тэгами <form...> n</form>. В качестве элементов формы могут выступать поля ввода текста, кнопки, выпадающие меню, переключатели, квадратики для отметки галочкой -checkbox'bi, а также картинки формата jpg или gif. Каждый элемент формы может иметь свое имя.
Наиболее важным свойством формы является то, что в ее заголовке в открывающем тэге <f orm...> можно указать адрес какого-либо файла. В этом случае при загрузке этого файла в программный код, если он будет там присутствовать, передадутся значения всех переменных, установленных в этой форме, в частности, значения всех элементов формы, как если бы эти значения были установлены в программе, расположенной в самом загружаемом файле. Таким образом можно передавать значения переменных между различными web-страницами, используя их в программном коде.
Во всех версиях РНР имена передаваемых переменных соответствуют тем именам, которые были даны элементам формы в их тэгах, а значения - соответственно значениям этих элементов (если в конфигурационном файле РНР - php.ini - параметр regis-ter_globals установлен в on.): для поля ввода текста - введенному тексту, для переключателя или checkbox'a - True при отмеченном и False при неотмеченном, для рисунка - координаты указателя мыши относительно верхнего левого угла изображения, для выпадающего меню (элемент <select пате="имя"><орtion value="textl">text</option>...</select>) - значение параметра value выбранного пункта option.
Кроме того, переменные, передаваемые через форму, помещаются в ассоциативные массивы $HTTP_POST_VARS и $HTTP_GET_VARS (если в конфигурагцюнном файле РНР - php.ini - параметр track_vars установлен в on) с именами элементов, соответствующими именам переменных (т. е. содержимое поля ввода текста <input type=text name=qwerty size=3 0> окажется в элементе $HTTP_POST_VARS['qwerty']). SHTTPPOSTVARS содержит переменные, переданные с помощью метода POST (метод указывается в заголовке формы), а $HTTP_GET_VARS - метода GET. Различие между методами состоит в том, что при передаче данных методом GET эти данные отображаются в адресной строке браузера, а при использовании метода POST - нет.
Начиная с РНР версии 4.1, передаваемые через форму переменные помещаются еще и в массивы SPOST и SGET. Отличие этих массивов от предыдущих состоит в том, что их переменные доступны еще и во всех функциях, расположенных в программе РНР, т. е. они являются глобальными.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 4. РНР: ВЫБОРОЧНАЯ ЗАГРУЗКА

В этой главе приведен пример простого PHP-сценария, используемого на реально существующем сайте.
Сайт www.harchikov.ru посвящен творчеству певца-барда Александра Харчикова. На сайте должны были быть представлены вышедшие альбомы певца в количестве 15 шт. и записи песен каждого альбома в МРЗ-формате. При создании сайта возникла необходимость обеспечить удобную навигацию. Общепринятый способ - ссылки на страницы с описанием каждого из альбомов и песнями из него - имел тот недостаток, что посетитель, желающий просмотреть не один альбом, а сразу несколько, был бы вынужден постоянно переходить со страницы на страницу, делая лишние усилия. Кроме того, в случае разрыва связи во время загрузки какого-либо файла посетитель, ушедший на другую страницу, был бы вынужден снова возвращаться на ту, с которой он этот файл загружать начал, тратя время на ее поиск. Недостаток другого варианта - размещения информации о всех альбомах на одной странице - ясен: размер этой страницы получ'ился бы очень большим, а интересная посетителю информация могла бы занимать лишь небольшую ее часть.
Поэтому было сделано так. На главной странице разместилась форма, а у каждого названия альбома - checkbox, внизу же страницы -кнопка перехода на список альбомов. Посетитель мог отметить заинтересовавшие его альбомы (рис.4.1), и после нажатия кнопки перехода PHP-сценарий выводил ему страницу с описаниями лишь тех альбомов, которые посетитель выбрал (рис.4.2).
Чтобы добиться такого результата, всем checkbox'aM заглавной страницы сайта были присвоены имена: <INPUT name=pan01 type=checkbox>. Все эти checkbox'bi находятся в большой форме, параметром action которой является имя файла с программой на РНР, выводящей описания альбомов в соответствии с данными этой формы, а для передачи данных формы используется метод get (т. е. ее заголовок имеет вид <FORM action=albm.php method=get name=forma>). Последнее приводит к тому, что в адресе страницы с выведенными описаниями альбомов присутствуют переменные (см. рис. 4.2), т. е. если посетитель занесет этот адрес в "Избранное", то при последующих возвращениях на сайт по этой ссылке (например, для дальнейшей загрузки песен выбранных альбомов) ему не придется вновь выбирать альбомы на заглавной странице, как это было бы в случае использования метода post, не помещающего имена переменных и их значения в строку адреса (что, впрочем, выглядит красивее).

Рис. 4.1. Чтобы просмотреть лишь избранные альбомы, достаточно их отметить...

Кнопка, вызывающая переход на страницу, указанную в параметре action заголовка формы, должна иметь тип submit, например:

<input type=submit value="Вывести оглавления отмеченных альбомов">.

Рис. 4.2. ...и вот, как на ладони -только они

Загрузив заглавную страницу сайта www.harchikov.ru, можно легко изучить структуру расположенной на ней формы, что вы и сделайте, если описание вам непонятно.
В файле же albm.php (адрес именно этого файла указан в заголовке формы заглавной страницы) помещена простая программа, которая выглядит так:

<?php
if ($bar01==True) {include ( "bar01.php"); }
if ($bar02==True) {include ('bar02.php"); }
... по строке на каждый альбом...
?>

В файлах bar01.php, bar02.php и т. д. находятся описания альбомов и ссылки на МРЗ-файлы песен. Если checkbox с соответствующим именем был отмечен на заглавной странице, то переменная его имени оказывается равной True - именно это и проверяется в сценарии.
Удивительно, что этот простейший прием в настоящее время практически не применяется на сайтах Сети - используется традиционная схема размещения информации со множеством ссылок на отдельные разделы. А ведь как удобно - например, на сайте Харчикова можно выбрать альбомы, сгенерировать себе страницу со ссылками на песни из них и, заходя на нее, постепенно загружать песни или передать весь список ссылок на файлы в какую-нибудь из программ-"качалок". Или, скажем, на сайте фирмы "Экон-Профи" (http://www.econprofi.ru) точно так же сделан раздел "Вопросы и ответы" (рис.4.3) - отметив интересующие вопросы на странице раздела, можно получить подробные консультации исключительно по выбранным темам. Полученная страница и загрузится быстрее, да и при ее распечатке лишней бумаги тратить не потребуется.

Рис. 4.3. Если вас заинтересовали лишь отдельные вопросы, нет надобности загружать всю страницу

Данную схему, разумеется, можно доработать. Опыт показывает, что посетители чаще всего предпочитают просмотреть либо два-три выбранных раздела, либо все разделы сразу. В последнем случае им придется отмечать все checkbox'bi страницы, что занимает время и силы. Поэтому стоит поместить на страницу еще и кнопку вывода сразу всех разделов - "Просмотреть все". Ей можно назначить гиперссылку с адресной строкой, содержащей все переменные в значении on, а можно немного доработать код РНР на странице-обработчике запроса, попросту добавив во все условия проверку значения еще одной, общей для всех условий переменной: if (($bar02==True) || ($all==True)) {... (напоминаю, что знак || означает "или"), и тогда гиперссылка может вести всего лишь на адрес albm.php?all=True.
Можно для решения той же задачи поместить на страницу пару сценариев на JavaScript, выполняющих соответственно отметку всех checkbox'oв и, наоборот, их очистку. Так что простор для творчества имеется, и немалый.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 5. РНР: ПРОСТЕЙШИЙ ИНТЕРНЕТ-МАГАЗИН

  • РНР: простейший интернет-магазин
  • Задачи
  • Проект
  • Витрина
  • Отправка заказа
  • Калькулятор
  • Добавление товара
  • Перспективы


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

PHP: ПРОСТЕЙШИЙ ИНТЕРНЕТ-МАГАЗИН

С помощью РНР можно легко сделать мини-Интернет-магазин -т. е. установить на сайт форму заказа, которая будет отправляться вам по электронной почте. При этом почтовая программа посетителя использоваться не будет - ему даже необязательно вообще ее иметь.
К примеру, такой "магазин" сделан на странице http://www.harchikov.ru/cass.php (рис.5.1). В этой главе рассказывается о его устройстве.

Рис.5.1. Реально действующий Интернет-магазин, построенный по описанной в этой главе схеме


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ЗАДАЧИ

Что, собственно, должен делать Интернет-магазин? Пожалуй, следующее:

  • предоставлять посетителю возможность осмотреть ассортимент товаров;
  • позволить посетителю как-нибудь отметить нужные товары;
  • принять у посетителя его контактные данные;
  • передать владельцу магазина список заказанных товаров и контактные данные посетителя. Причем весьма желательно, чтобы этот список был в удобочитаемом виде - чтобы выполнять заказ можно было сразу после его получения, не тратя время, скажем, на расшифровку кодов товаров.

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПРОЕКТ

Из каких же компонентов web-магазин должен быть сделан?
Отобразить ассортимент из пары десятков товаров можно на одной web-странице. На ней же можно разместить "калькулятор" и форму ввода контактных данных.
Раздел страницы, относящийся к одному товару, должен быть снабжен чем-то, что могло бы позволить посетителю как-нибудь этот товар отметить. Для последнего лучше всего использовать выпадающий список (рис.5.2 - наподобие того, в котором устанавливается размер шрифта в Word): он заодно дает посетителю возможность выбрать и количество товара для заказа. На HTML для отображения такого списка необходимо использовать элемент <select паmе="имя этого элемента формы" >, внутри которого размещены тэги <ор-tion. . . >, в которых и указаны те значения, что в меню отображаются. При отправке формы странице-обработчику сценарию на ней передается переменная с именем, равным имени элемента <select...> и значением, равным числу из параметра value того тэга <option...>, который был посетителем выбран.

Рис.5.2. Выпадающее меню

Скажем, список на рис.5.2 может отображаться, например, кодом

<select name=spis>
<option value=45>Пepвым</option>
<option value=81>Bторой</option>
<option value=31>Tpетий</option>
</select>

В зависимости от того, какой пункт списка будет выбран посетителем, сценарию-обработчику передастся в качестве значения переменной $spis (и элемента массива $HTTP_POST_VARS [ ' spis ' ]) то число, которое находилось в параметре value тэга <option>, отображающего выбранный пункт.
Для ввода посетителем контактных данных можно использовать элемент <textarea. . . >, позволяющий помещать в себя достаточно длинные фрагменты текста на нескольких строках (например, почтовый адрес), а для ввода адреса электронной почты - элемент типа text (он отображает однострочное поле для ввода текста), рис.5.3.

Рис.5.3. Виды полей ввода текста

Форма, в которую посетитель внесет сведения о своем заказе и свои контактные данные, должна быть отправлена владельцу сайта. Для этого на странице, указанной в заглавии формы как ее обработчик; нужно разместить сценарий, собирающий значения всех элементов формы в единую текстовую строку и отправляющий эту строку на e-mail владельца сайта. Последнее сделать можно командой PHP mai 1 ().
Итак, весь Интернет-магазин будет состоять из двух файлов: витрины и обработчика заказа. Однако практически все возможности для торговли будут иметься: и список товаров, и возможность указания вида и количества заказываемого товара.
"Калькулятор", о желательности которого упоминалось на предыдущем шаге проектирования, можно сделать на JavaScript. Программа должна отслеживать изменения в выпадающих списках, сверяться со списком цен и в соответствии с данными этого списка выводить посетителю сообщение о стоимости его заказа. Вывод сообщения лучше всего сделать с помощью средств Dynamic HTML, динамически изменяя содержимое страницы.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ВИТРИНА

Итак, вот основное, что должно быть на первой странице Интернет-магазина. Весь дизайн, все оформление остается на ваше собственное усмотрение - важно лишь, чтобы на странице присутствовали перечисленные ниже элементы.
В начале страницы, после тэга <body>, но до каких-либо описаний товаров, должен находиться заголовок формы:

<FORM METHOD="post" ACTION="zakaz.php"
NAME="mainform">

Допустим, что PHP-программа, обрабатывающая форму, находится в файле zakaz.php (и именно на эту страницу произойдет переход после нажатия кнопки типа submit в форме). Не забудьте указать параметр пате в заголовке формы - он потом пригодится для использования в коде калькулятора стоимости заказа. (Кстати, обратите внимание, что так как для передачи данных формы используется метод POST, а не GET, то при этом в адресной строке данные полей формы отображаться не будут.)
Ну а внутри формы следует расположить коды выпадающих списков - по одному на каждый товар (рис.5.4). В качестве значений параметров пате удобнее всего использовать небольшие буквосочетания - коды товаров:

<select name="TOV1">
<option value=0>0</option>
<option value=1>1</option>
<option value=2>2</option>
...
<option value=10>10</option>
</select>

Обратите внимание, что первым по счету в выпадающем списке должно стоять значение 0 - именно оно будет отображаться по умолчанию.

Рис.5.4. Интернет-магазин. Поле заказа количества товара

Также в форме должны присутствовать поля ввода контактной информации - см. на рис.5.1. Скажем, текстовая строка типа text с именем e-mail - для адреса электронной почты и поле ввода текста textarea с именем contact - для ввода контактных данных (что сочтет нужным покупатель - имя, телефон, домашний адрес).

<input name="email" type="text">
<textarea name="contact" cols="30" rows="5" wrap="virtual">
</textarea>

(В параметре cols тэга textarea указывается количество символов, которое должно помещаться в одну строку в поле ввода текста, в параметре rows - количество строк текста, которые можно будет вписать в поле ввода до появления полос прокрутки. Параметр wrap="virtual" разрешает автоматический перенос текста на следующие строки в поле ввода.)
Разумеется, в форме должна быть кнопка ее отправки

<input type=submit>

и закрывающий тэг формы

</form>


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ОТПРАВКА ЗАКАЗА

После оформления заказа и нажатия посетителем кнопки отправки формы произойдет переход на страницу, указанную в заголовке этой формы (в рассматриваемом сценарии - zakaz.php). Именно в этом файле содержится программа отправки заказа.
При передаче формы сценарию на РНР содержимое каждого элемента переданной формы (для поля ввода текста - введенный текст, для элемента <select. . .> - значение параметра value выбранного пункта <орtion>) помещается в переменную, имя которой равно значению параметра пате данного элемента (Так происходит, если в файле pkp.mi установлен в on параметр register_globals). Кроме того, все эти значения помещаются в одноименные соответствующим значениям параметров пате элементы массива $HTTP_POST_VARS (если форма передана методом POST) или $HTTP_GET_VARS (если форма передана методом GET) (Так происходит, если в файле php.ini установлен в on параметр track_vars), а в РНР версии 4.1 и выше - еще и в массивы $_POST и $_GET соответственно. Например, значение элемента <select name="TOV1"> будет доступно сценариям на странице-обработчике в переменной $TOV1 и в элементе массива $HTTP_POST_VARS [ "TOV1' ] (а в РНР версии 4.1 и старше - еще и в элементе массива $_POST [ ' T0V1' ].
Однако особенностью использования этих массивов в частности является то, что для присоединения значения любого их элемента к какой-либо строковой переменной нельзя просто поместить их внутрь текста строки - нужно использовать оператор сложения строк: точку. Скажем, написать

$zak="$zak $HTTP_POST_VARS['TOV1']";

нельзя - надо использовать формат

$zak="$zak "$HTTP_POST_VARS['TOV1'];

Отправка письма осуществляется командой mail, как вы помните, имеющей формат
тай ("Кому", "Тема", "Текст сообщения", "Дополнительныезаголовки");
При выполнении данной команды на сервере формируется электронное письмо в соответствии с указанными параметрами и отправляется с помощью установленной на web-сервере почтовой программы (Вы можете установить такую программу и на своем компьютере - используйте, например, Office Mail Server Юрия Кучуры (доступен с http://eu3eu.chat.ru) или Courier Mail Server Романа Ругаленко (доступен с http.V/courierms. narod. ru)).
В качестве параметра "Кому" может выступать набор адресов, разделенных запятыми.
"Дополнительные заголовки" могут быть любые из допустимых почтовыми протоколами, разделяться они должны комбинацией символов /п, которая в РНР означает перевод строки. Если среди "Дополнительных заголовков" не указано поле From, то оно заполняется по умолчаниюпочтовой программой, установленной на web-сервере, например, именем "Unprivileged User".
Для отправки письма с заказом необходимо приготовить его текст. Можно, конечно, просто включить в письмо значения всех переменных с именами, равными кодам товара (т. е. полученные из элементов <select...>), и в конец добавить контактные данные посетителя. Но куда как лучше, чтобы владелец web-сайта получал не набор кодов, которые он еще должен по своим данным перевести в названия, а уже готовый список заказанных посетителем товаров (рис.5.5). Для этого в текст сценария включим блок определения полного названия товара по его коду.

Рис.5.5. Письмо с заказом. Удобно читать - удобно выполнять

Итак, в любом месте файла-обработчика формы, но лучше всего в начале, следует поместить следующий сценарий:

<?php
$zak="";

(В эту переменную будем последовательно собирать названия заказанных товаров.)

if ($TOV1>0){$zak="$zak Название товара 1 -$TOV1 шт.\n"; }
if ($TOV2>0){$zak="$zak Название товара 2 -$TOV2 шт.\n"; }
...

И такие же строчки - для каждого товара. В качестве имени переменной в условной части блока if ($ . . . >0) указывается значение параметра пате соответствующего тэга <select. . .>, а в последующих фигурных скобках - название того товара, к которому этот тэг относился на странице-витрине. В результате в том случае, если посетитель изменил значение какого-либо выпадающего списка на число, отличное от нуля, то в переменную Szak, которая впоследствии станет текстом отправляемого письма, включается название товара, соответствующего этому выпадающему списку, и сведения о количестве его заказанных единиц - та величина, которая в конце концов и оказалась значением этого выпадающего списка.
Теперь завершим составление текста письма:

$zak="C адреса $email от заказчика с контактными данными $contact пришла заявка на приобретение товара: \n$zak";

и отправим письмо-заявку:

mail ("электронный адрес владельца сайта", "Заказ на товар", $zak, "From: $email\nReply-To: $email\nContent-Type: text/plain; charset=windows-12 51");?>

В результате выполнения этой команды тот, кто обрабатывает заказы, получит аккуратный список заказанных товаров и сведения о заказчике (см. рис.5.5). Причем если посетитель правильно ввел свой е-mail, то для связи с ним после получения письма достаточно нажать кнопку "Ответить" или ей подобную в почтовом клиенте - этот e-mail подставляется в заголовок письма From:.

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

Рис.5.6. Заказ сделан - можно уходить и ждать...

В приведенном сценарии вместо одноименных элементов формы переменных можно использовать и соответствующие элементы массивов $HTTP_POST_VARS и (в РНР версии старше 4.1) SPOST. Например, строка добавления в текст заказа нового товара будет выглядеть как

if ($HTTP_POST_VARS['TOV1']>0){$zak="$zak Название товара 1 -
".$HTTP_POST_VARS['TOV1']." шт.\n"; }

строка генерации письма - как

$zak="C адреса ".$HTTP_POST_VARS['email']. " от заказчика с контактными данными
".$HTTP_POST_VARS['contact']." пришла заявка на приобретение товара:\n$zak";

и команда отправки письма - измененная по тому же принципу.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

КАЛЬКУЛЯТОР

Калькулятор для отображения на странице витрины информации о сумме заказа сделан на Javascript. Его текст приводится ниже. Но, так как книга посвящена РНР, а не Javascript, к его командам даны лишь минимально необходимые комментарии. Просто поместите код сценария в тексте web-страницы, набрав его с клавиатуры или отсканировав страницы книги.
В раздел <head> страницы с витриной следует поместить сценарий:

<SCRIPT LANGUAGE="JavaScript">
function calc()
{

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

tov=new Array("TOV1", "TOV2", "TOV3", "T0V4");

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

prc=new Array (100, 200, З00, 400);

Сценарий продолжается...

var kolvo=0;
var stoim=0;
for (n=0; n<tov.length; n++)
{
if (document.mainform(tov[n])!=null)
{
kolvo=kolvo+l*document.mainform(tov[n]).value;
stoim=prc[n]*document.mainform(tov[n]).value+stoim;
mess.innerНТМL="Количество заказанных товаров -"+kolvo+"<br>"+"CTOИMOCTb заказанных товаров -"+stoim;
document.mainform("stoim").value=stoim; document.mainform("kolvo").value=kolvo;
} </SCRIPT>

Вкратце можно сказать, что этот сценарий при своем запуске просматривает значения всех элементов форм на web-странице, имеющих перечисленные в массиве tov имена (а, как вы помните, в этом массиве перечислены коды товаров: т. е. элементы с этими именами - это соответствующие этим товарам выпадающие списки <select...>), и вычисляет сумму этих значений (общее число заказанных товаров) и сумму произведений этих значений на соответствующее каждому коду число из массива ргс - списка цен (т. е. считает общую сумму покупки). Полученные значения помещаются в элементы web-страницы с именем mess (текстовое сообщение), stoim (стоимость заказа), kolvo (количество заказанных единиц товара) (рис. 5.7).

Рис.5.7. Калькулятор стоимости

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

<select name=TOV1l onchange=calc ()>
<option value=0>0
...
</select>

В том месте страницы, где вы желаете отображать посетителю сведения о заказе, поместите строчку с элементом <р> или <div>, имеющую идентификатор mess - тот же, что упоминался в сценарии (здесь надо использовать именно параметр id, а не nаmе):

<р align=center id=mess> Информация о заказе появится здесь</р>

Где-нибудь в форме также поставьте два скрытых поля:

<input type=hidden name=stoim value=0>
<input type=hidden name=kolvo value=0>

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

$zak="C адреса $email от заказчика с контактными данными $contact пришла заявка на приобретение товара: \n$zак\пКоличество заказанных товаров -$kolvo\n О6щая стоимость заказа - $stoim";


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ДОБАВЛЕНИЕ ТОВАРА

Для добавления в магазин нового товара необходимо:

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПЕРСПЕКТИВЫ

Вот так, очень просто, вы можете сделать элементарный Интернет-магазин. Конечно, небольшой - всего на одной странице. Но заказать представленный на этой странице товар и отправить заказ владельцу посетитель сможет.
При работе с таким Интернет-магазином посетителю даже не нужно быть постоянно подключенным к Интернету во время оформления заказа - он спокойно может загрузить страницу с перечнем товаров, отключиться от Сети, выбрать нужные предложения и заполнить поля формы заказа, а затем, подключившись снова, этот заказ отправить. Да и саму страницу со списком ему необязательно получать именно из Сети - вы можете отправить ее кому-либо по почте или поместить на компакт-диски, раздаваемые друзьям или коллегам (только не забудьте в этом случае указать в заголовке формы полный адрес страницы с обработчиком заказа, а не только ее имя).


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 6. РНР:ПАПКОПОТРОШИЛКА

При создании Интернет-ресурса, содержащего часто обновляющееся однотипное содержание, проблема быстроты и удобства обновления встает достаточно остро. Например, вы являетесь администратором сайта, на котором размещаются статьи разных авторов. В таком случае при поступлении новой статьи вам приходится, помимо размещения на web-сервере (или выделенном вам аккаунте) ее самой, еще и обновлять страницу со списком этих статей, добавив ссылку на новоразмещенную web-страницу со статьей - иначе ведь попасть на новую статью с сайта будет невозможно. А если статьи поступают часто? Да еще и не только поступают, но и удаляются, или в них меняется название? Тогда ведь для отслеживания правильности содержания приходится прилагать немало усилий.
Или другая ситуация - необходимо разместить на сайте новостную ленту. Простое решение напрашивается сразу: просто включать текст новостей в содержащую их страницу. Или, в.крайнем случае, писать новости в отдельном файле, а в web-страницу включать этот файл с помощью команды PHP include - тогда при обновлении новостей придется загружать на сервер только файл с новостями, а не всю страницу. Но все же... не так это и удобно! Каждый раз работать с файлом с гипертекстовой разметкой, каждый раз его загружать на сайт... А если вам надо поручить загрузку человеку, который совершенно не знает HTML? Текст-то он напишет, а вот вставить его в нужное место гипертекстовой разметки?
Или, наконец, третья ситуация - вы делаете файловый архив, и ваши друзья загружают на ваш сервер свои файлы. Как сделать так, чтобы они появлялись в списке доступных для посетителей файлов сразу же после их загрузки, без вашего участия, без необходимости вручную обновлять их список?
Приведенный ниже сценарий на языке РНР пригодится вам во всех трех случаях. Вкратце его алгоритм прост: при вызове содержащей его страницы он пробегает по всем файлам в указанной в сценарии директории и составляет их список. А с этим списком можно уже сделать все что хочется: либо включить их содержимое друг за другом в выводимую web-страницу, либо составить каталог файлов.
Итак - вот сценарий:

<?php

Сначала укажем сценарию имя папки, в которой содержатся подлежащие каталогизации или включению в другую страницу файлы:

$dirct="new";

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

$hdl=opendir($dirct);

Теперь запишем все имена содержащихся в ней файлов в массив $а [ ]. Согласно синтаксису РНР (см. гл. 3), для этого достаточно просто присваивать массиву $а [ ] различные значения - при этом автоматически в него будут добавляться новые члены, которым эти значения будут присваиваться. Для помещения имен файлов (с расширениями) из директории $dirct в массив используется функция readdir (имя каталога), работающая с дескриптором этой директории, записанным ранее в переменную $hdl с'помощью функции opendir.

Комментарий:
Функция readdir предназначена для вывода списка файлов и папок, содержащихся в указанном в ее параметре каталоге. При каждом своем вызове она выдает имя случайно выбранного файла (или вложенной папки) указанного каталога, каждый раз - новое, до тех пор, пока не перечислит имена всех файлов и вложенных папок.

Среди выданных функцией readdir имен будут и ссылки на текущий и родительский (т. е. включающий в себя текущий) каталог, обозначаемые соответственно одной и двумя точками (так уж работает web-сервер). Поскольку нас интересуют только файлы каталога, то данные ссылки из списка файлов следует исключить, добавив проверку состава имени файла.

while ($file = readdir($hdl))
if ( ($file!=".")&&($file!="..")) $a[]=$file;
}

Теперь закроем открытую папку, очистив дескриптор (так необходимо) - функцией closedir (каталог):

closedir($hdl);

Список имен файлов папки, помещенный теперь в массив $а, содержит эти имена в случайном порядке - так их выдает функция readdir. Однако массив можно отсортировать - функциями asort (по алфавиту - прямое) или rsort (по алфавиту - обратное: с z до а). Использование сортировки массива даст возможность включать имена файлов или их содержимое в определенном порядке - достаточно лишь называть их так, чтобы они сортировались нужным образом (скажем, новости удобно именовать датой - файлы с ними могут иметь имена типа 20020901 .php, 20020902.php, тогда при прямой сортировке самые свежие файлы окажутся внизу списка, при обратной -вверху).

rsort($a);

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

foreach ($a as $value) {

Комментарий:
Оператор foreach будет работать только вРНР 4.0 и выше. Если вы можете использовать лишь РНРЗ, то вместо него можно использовать немного более громоздкий код - вначале определим размер полученного списка:
$l=sizeof($a);
а затем выполним нижеследующий цикл для каждого элемента массива с помощью цикла for, указав в его параметрах узнанную величину массива:
for ($k = 1; $k < $1; $k++)
Для удобства можно записать значение очередного элемента массива в переменную:
$value=$a[$k]; и получится практически полный аналог оператора for each.

Дальнейший текст сценария зависит от ваших потребностей (и одинаков как для оператора f oreach, так и при использовании цикла for).
Чтобы вывести простой список файлов в папке $dirct, состоящий из гиперссылок на них, можно использовать такую команду, поместив ее в это место сценария:

echo ("<a href = $dirct/$value>$value</axbr>") ;

Чтобы вставить в страницу содержимое всех файлов в папке Sdirct, можно применить команду include:

include ("$dirct/$value");

Данный способ, например, используется при выводе ленты обьяв-лений и новостей на уже упоминавшемся сайте www.harchikov.ru. в корневом каталоге сайта создана папка news, а на его заглавной странице размещен вышеприведенный сценарий (второй вариант -с использованием команды include)/Для помещения на сайт нового объявления администратору достаточно набрать его текст (при необходимости использовав html-разметку, но можно и без нее), поместить этот текст в файл, назвать файл цифровой записью даты создания объявления (для удобства работы и сортировки) и разместить его в папке news на сайте. Никакой редакции каких-либо страниц сайта не требуется. Для удаления объявления с сайта достаточно просто удалить файл с ним из папки news, и впредь выдаваемые посетителям страницы не будут включать в себя его содержимое. Весь процесс нетрудно поручить даже секретарше или полному "чайнику".
Однако для составления списка статей информации только об именах файлов мало. Ведь в таком списке желательно указать хотя бы название статьи и имя ее автора. Чтобы это сделать, можно, например, указывать эти данные в тэгах meta, включаемые в каждый файл со статьей, а узнать содержимое данных тэгов можно с помощью функции get_meta_tags (имя файла).

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

Например, положим, что названия статей будем писать в мета-тэгах zagol, а имена авторов - в мета-тэгах author (т. е. в раздел <head> каждого файла со статьей нужно будет добавить строчки <meta name="zagol" content="3arоловок статьи "><meta name="author" content="ABTop статьи">). Тогда строки сценария, вытаскивающие из файла содержимое этих тэгов и помещающие их на страницу, будут выглядеть так:

$m=get_meta_tags("$dirct/$value");
echo "<a href=$dirct/$value>$m[zagol]</a> &nbsp;$m[author]<br>";

Использование этого способа иллюстрируется в примере на рис.6.1. В папке duel находится файл index.php сданным сценарием, а в папке stats - статьи. В каждом файле со статьей присутствуют мета-тэги zagol и author, в которых указаны названия статей и их авторы. При вызове файла index.php находящийся в нем сценарий пробегает по всем файлам в папке stats, вытаскивает из них мета-тэги и отображает их на странице. Номера в названиях файлов со статьями используются для установки очередности вывода ссылок на них.
Ну и конец сценария:

}
? >

Рис. 6.1. Публикация статей - одной закачкой. Без всяких иных изменений

При небольшой доработке возможности использования сценария можно серьезно расширить - скажем, генерировать с его помощью списки файлов в любой директории, а не только в указанной. Для этого следует убрать из сценария строку, жестко задавающую имя папки -в приведенном примере $dirct="new";, а значение переменной с именем подлежащей "потрошению" папки с файлами - $dirct -задавать через ссылку для вызова страницы. Если статьи разных номеров журнала помещаются в отдельные папки (например, соответственно называющиеся newsl, news2), то для того чтобы использовать одну и ту же страницу со сценарием для вывода оглавлений различных номеров, нужно указывать имя папки в передаваемой через адресную строку переменной, а впоследствии именно эту переменную использовать в сценарии в качестве имени "потрошимой" папки. Например, ссылки на той странице, откуда происходит переход на страницу со сценарием, могут выглядеть так:

glav.php?dirct=newsl, oglav.php?dirct=news2

и т. д., где oglav.php - страница со сценарием, a $dirct - переменная, в которую записывается имя папки (рис. 6.2).

Рис. 6.2. Один скрипт - на все папки

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 7. РНР: ЗАКАЧКА ФАЙЛОВ

  • РНР: закачка файлов
  • Подготовка
  • Общие сведения
  • Форма для пользователя
  • Сценарий обработки


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

PHP: ЗАКАЧКА ФАЙЛОВ

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПОДГОТОВКА

Для начала следует создать папку, куда будут помещаться закачиваемые посетителями файлы - скажем, user - в том примере, что будет рассматриваться ниже, и присвоить ей атрибут 772, что означает предоставление посетителям сайта возможность записывать в нее файлы. Для присвоения атрибута достаточно, зайдя с помощью, скажем, CuteFTP на аккаунт, выбрать из контекстного меню этой папки (т. е. из меню правой кнопки мыши) пункт CHMOD (рис. 7.1) и указать, что виду пользователей Public разрешается в эту папку что-либо записывать (рис. 7.2).

Рис.7.1. He забудьте назначить папке для файлов нужные права доступа...

Рис.7.2. Например, вот так

В других программах для работы по протоколу FTP права доступа настраиваются аналогично.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ОБЩИЕ СВЕДЕНИЯ

Чтобы пользователь мог загрузить файл на сервер с web-страницы, на этой странице должна присутствовать форма с параметром заголовка enctype, равном "multipart/form-data", а также со специальным полем типа file (выглядит как поле ввода имени файла с кнопкой "Обзор", нажав на которую, можно отобразить окно выбора файла) и кнопкой submit (см., например, рис.7.3). Как только эта кнопка будет нажата, браузер начнет передавать файл, указанный в поле типа file, на сервер. В заголовке формы также следует указать параметр action, значением которого должно быть имя страницы с обрабатывающим загруженный файл сценарием.
Загрузку файла на сервер умеют осуществлять практически все браузеры (только самые старые модели Microsoft Internet Explorer и Netscape Navigator этого не могут), а воспринять ее могут все web-серверы (кроме CERN и некоторых самых простых), в том числе и самый распространенный - Apache.
После того как файл полностью загружен на сервер, он помещается в его временную папку и находится там до тех пор, пока web-сервер не закончит обрабатывать и отдавать браузеру пользователя ту страницу, имя которой было указано в параметре action формы загрузки файла. После полной выдачи страницы пользователю файл удаляется. Отсюда следует, что на этой странице должны обязательно присутствовать команды, перемещающие этот файл в какую-либо папку.
Странице, указанной в параметре action заголовка формы, передаются несколько переменных ( Если в конфигурационном файле РНР - php.ini - параметр regis-ter_globals установлен в on) содержащих информацию о загруженном файле. Именно на их основе сценарий на ней сможет работать с загруженным файлом. Кроме того, эти же самые переменные помещаются в массив $HTTP_POST_FILES ( Если в конфигурационном файле РНР -php.ini - параметр track_varsустановлен в on), а в РНР версий 4.1 и выше -и в массив SFILES (в отличие от переменных и массива SHTTPPOSTFILES этот массив по умолчанию доступен и во всех функциях, размещенных на странице с программой-обработчиком загруженных файлов).
Вот эти переменные:

  1. 1. Переменная, имеющая то же имя, что и поле с типом file в исходной форме. Если оно выглядело как < input name= "uploadf ile" type= " f ile">, то переменная будет иметь имя $uploadfile (и соответственно еще $HTTP_POST_FILES['uploadfile']['tmp_name'], $_FILES [ ' uploadf ile ' ] [ ' tmp_name ' ]). В эту переменную записывается то имя (временное, создающееся автоматически), которое загруженный файл имеет в папке временных файлов. Именно с ним будут работать команды копирования файла.
    Если в исходной форме присутствовало несколько полей типа file с разными именами, то для каждого из них создается своя переменная со значением, относящимся к соответствующему файлу.
  2. 2. Переменная, имеющая имя "Переменная 1 jiame" - т. е. к имени первой переменной просто приписывается горизонтальная черточка и слово name, например, для вышеуказанного примера ее имя будет выглядеть как $uploadf ile_name (ну и, разумеется, то же самое значение получат элементы вышеупомянутых массивов $HTTP_POST_FILES['uploadfile']['name'], $_FILES ['uploadf ile ' ] ['name ' ]). Ее значением является исходное имя файла в системе отправителя.
  3. 3. Переменная, имеющая имя "Переменная 1_size". Ее значение -размер загруженного файла в байтах.
  4. 4. Переменная, имеющая имя "Переменная 1_type". Ее значение -тип загруженного файла согласно спецификации MIME (например, "image/gif").

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ФОРМА ДЛЯ ПОЛЬЗОВАТЕЛЯ

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

<FORM ENCTYPE="multipart/form-data" ACTION "up . php" METHOD=POST>

(Т. е. программа, обрабатывающая загруженный файл, будет помещаться в файле up.php.)

Рис.7.3. Форма ввода имени файла для загрузки и пароля

Теперь - поле ввода пароля. Его значение при передаче формы запишется в переменную с тем же именем, что и у этого поля (в данном случае - в переменную $pass), а также будет доступно в массиве $HTTP_POST_VARS, в элементе $HTTP_POST_VARS ['pass'] (начиная с РНР версии 4.1 - в элементе $_POST['pass']). Ее вы сможете использовать в сценарии на странице, указанной в параметре action заголовка формы. Если вы укажете в параметре type этого поля значение "text", то вводимые пользователем символы будут отображаться на экране, если "password" - то заместятся звездочками (как на рис.7.3).

Ваш пароль: <INPUT NAME="pass" TYPE="password">

И поле ввода имени файла:

Закачать файл:<INPUT NAME="zak" TYPE="file">

Кнопка начала загрузки:

<INPUT TYPE="submit" VALUE="Закачать">

Собственно, и все... Для загрузки достаточно.

</FORM>


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

СЦЕНАРИЙ ОБРАБОТКИ

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

<?php

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

if ($zak=="none")
{echo ("Вы забыли указать файл...");}

Рис.7.4. Сообщение пользователю в случае неуказания имени файла

Примечание:
Команда elseif используется в операторе if для того, чтобы проводить проверку какого-либо условия в том случае, когда то условие, которое указано в заглавии оператора if, неверно. Она идентична конструкции:
}
else
{
if (выражение) {
} }
и введена в РНР для упрощения синтаксиса программ.

Если введенный пользователем пароль не соответствует тому, что указан в данном сценарии (обратите внимание, что правильный пароль для загрузки файлов указывается именно здесь!), то выполнение сценария прекращаем (с выводом сообщения пользователю - как на рис. 7.5), если же нет - то выполняется следующая за данным условием команда elseif.

Рис. 7.5. Сообщение пользователю в случае неправильного ввода пароля

Если вы желаете назначить разным пользователям отдельные пароли (чтобы, скажем, иметь возможность запретить загружать файлы лишь одному из них, не затронув интересы остальных), то просто укажите здесь соответствующее условие (может выглядеть так: "elseif ( ($pass!="paroll")&&($pass! = "parol2") )"):

elseif ($pass!="parol")
{ echo ("Ваш пароль неверен!");}

И наконец, само копирование - допустим, в папку user. По его окончании пользователю выдается соответствующее сообщение (рис. 7.6).

Рис. 7.6. Сообщение пользователю в случае успешной загрузки

В условии elseif в нижеследующей строчке проверяется, выдает ли команда сору значение True - что должно происходить при успешном копировании. (Если не можете разобраться в синтаксисе -смотрите Описание РНР.)

elseif (copy($zak, "user/$zak_name"))
{echo("Файл $zak_name размером $zak_size байт успешно загружен на сайт.");}

Примечание:
Команда сору выполняет копирование файла из того места, которое указано в ее первом параметре, на то, которое указано во втором. При наличии в месте назначения файла с тем же именем, что и у копируемого, новый файл пишется поверх старого. Команда возвращает True, если копирование проходит удачно, и False, если нет, выводя в последнем случае также сообщение на ту страницу, в сценарии на которой она расположена. (Если последнее нежелательно, то заблокируйте вывод сообщений об ошибке, поставив перед командой знак @.)

В том случае, если по какой-то причине копирование осуществить не удаётся, то об этом выдается сообщение. В принципе это и необязательно - неудача копирования является ошибкой РНР, и об этом информация все равно выводится (рис.7.7), однако все же стоит ясно указать пользователю, из-за чего возникла проблема. К тому же не все смогут понять фразу об ошибке на английском языке.

else
{ echo("He удалось скопировать $zak_name");}
Конец скрипта:
?>

Рис.7.7. Сообщение пользователю в случае ошибки копирования

Вот, собственно, и все. Пользователь, зайдя на первую страницу (рис.7.3), должен ввести свой пароль и найти с помощью открывающегося при нажатии на кнопку "Обзор" диалогового окна файл для загрузки. После нажатия кнопки "Загрузить" он увидит одно из трех сообщений - см. рис. 7.4, 7.5, 7.6.
Если вместо имен, содержащих информацию о загружаемом файле и передаваемых через форму переменных, использовать имена соответствующих элементов массивов $HTTP_POST_FILES и $HTTP_POST_VARS, то код обработчика будет выглядеть так:

<?php
if ($HTTP_POST_FILES['zak']['name']=="none") {echo ("Вы забыли указать файл...");}
elseif ($HTTP_POST_VARS['pass']!="parol") { echo ("Ваш пароль неверен!");}
elseif
(copy($HTTP_POST_FILES['zak']['tmp_name'], "user/".$HTTP_POST_FILES['zak']['name']))
{echo ("Файл ".$HTTP_POST_FILES['zak1] ['name'] ." размером ".$HTTP_POST_FILES['zak']['size']." байт успешно загружен на сайт.");}
else
echo("Hfe удалось скопировать ".
$HTTP_POST_FILES['zak']['name']);} ?>

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

echo ("Имя файла: $HTTP_POST_FILES['zak']['name']")

Правильно:

echo ("Имя файла:". $HTTP_POST_FILES t'zak'] ['name'])

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

<input name="uploadfile[]" type="file">
<input name="uploadfile[]" type="file">
<input name="uploadfile[]" type="file">

В результате в программу-обработчик будут переданы:

  1. 1. Массивы $uploadfile[], $uploadfile_name[], $uploadfile_size[], $uploadfile_type[], содержащие соответственно временные имена загруженных файлов, исходные имена загруженных файлов, размеры загруженных файлов и типы загруженных файлов. Порядок элементов в массивах в точности соответствует порядку полей в исходной форме - так, если имя файла file.zip было введено в первое поле типа file, то относящиеся к этому файлу переменные будут располагаться в элементах перечисленных массивов с индексом 0 (не забывайте - нумерация элементов массивов начинается с нуля!).
    Данные массивы будут переданы в обработчик во всех версиях РНР, начиная с 3.0.1, если в файле php.ini ( Настройка этого файла - привилегия администратора web-cepвepa, так что если вы таковым не являетесь, то включить вы ее не сумеете) включена опция regis-ter_globals.
  2. 2. Массивы $HTTP_POST_FILES['uploadfile']['tmp_name'][], $HTTP_POST_FILES[luploadfile')['name'][], $HTTP_POST_FILES ['up-loadfile'H'size'][] и $HTTP_POST_FILES['uploadfile']['type'][], содержащие соответственно временные имена загруженных файлов, исходные имена загруженных файлов, размеры загруженных файлов и типы загруженных файлов. Порядок элементов в массивах опять-таки в точности соответствует порядку полей в исходной форме.
    Данные массивы будут переданы в обработчик во всех версиях РНР, начиная с 3.0.1, если в файле php.ini включена опция track_vars.
  3. 3. Массивы $_FILES['uploadfile']['name'][], $_FILES['uploadfile'] ['tmpjiame'JO, $_FILES['uploadfile']['size'][] u $_FlLES['uploadfile'] I'type'Jl]. Их содержимое аналогично предыдущим. Данные массивы будут переданы в обработчик в версиях РНР, начиная с 4.1.

В данных примерах uploadfde - это всего лишь имя массива, вы, естественно, можете назвать его по-другому.
В РНР 3-й версии с номером подверсии 3.0.17 и выше, а также начиная с версии 4.0.3, в РНР специально для работы с загруженными через форму файлами есть две команды - is_uploaded_file иmove_uploaded_file. При использовании описанного выше способа загрузки файлов существует опасность того, что некий злоумышленник вместо указания в форме реального файла со своего компьютера укажет путь к какому-либо файлу на web-сервере (например, файлу с паролями пользователей), и тем самым сценарий, обрабатывающий загруженный файл, будет работать уже с этим файлом. Ясное дело, такое развитие событий представляется весьма нежелательным. С помощью данных команд можно исключить такую возможность. Первая команда проверяет, был ли тот файл, который указан в ее параметре, загружен через форму загрузки файлов из браузера посетителя, и если да, то возвращает True, в противном случае - False. Вторая же аналогична команде сору, однако, в качсстве#исходного файла для копирования в ней допустимо указывать лишь загруженный от посетителя файл. В противном случае команда не отработает, вернув False (без вывода в документ каких-либо предупреждений, в отличие от ситуации неудачи копирования по каким-либо другим причинам).

Примечание:
Команда is_uploaded__file() no сути дела проверяет, находится ли указанный в ее параметрах файл во временной директории сервера - т. е. той, куда все загружаемые файлы первоначально помещаются. То же самое проверяет иmove_uploaded_file () перед началом копирования.

Так что, как видите, предоставить посетителям возможность загружать файлы на ваш сайт довольно просто. Как и создать простейшую, но довольно эффективную систему ограничения этой возможности по паролю - всего лишь с помощью проверки передаваемой через форму переменной, содержащей пароль; сам же пароль указывается в тексте программы на РНР. Для того, чтобы дать вашему другу возможность вести свою "колонку" на вашем сайте, этого будет достаточно.
Еще, конечно, хотелось бы сделать нечто вроде простого "файл-менеджера", который бы позволил пользователю хотя бы удалять ненужные файлы из его каталога. О том, как реализовать такую возможность - в главе 10 этой книги.
Однако описанные выше сценарии имеют один весьма существенный недостаток, который, в частности, весьма затрудняет загрузку больших файлов. Обратите внимание, что переход на страницу со сценарием, обрабатывающим загруженный файл и помещающим его в нужную папку, а заодно и проверяющим правильность пароля пользователя, возможен только после полной загрузки файла. Т. е. пользователю, который ввёл неверный пароль, все равно придется ждать окончания бесполезной загрузки его файла на сервер, тратя на это свое время в Сети и трафик. Если загружаемые файлы маленькие, то это еще как-то можно потерпеть, а если они имеют мегабайтные размеры? Тогда ведь вполне можно ждать жалоб от разозленных пользователей, потративших по получасу времени в Интернете на то, чтобы узнать в конце концов, что их пароль неправилен...
Поэтому для создания полноценного сервиса размещения пользовательских файлов необходима еще и служба авторизации пользователей, позволяющая им, единожды введя логин и пароль, в дальнейшем при работе на вашем сайте их уже не проверять. Созданию такой службы также будет посвящена следующая глава этой книги.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 8. РНР: АВТОРИЗАЦИЯ ДОСТУПА

  • РНР: авторизация доступа
  • Авторизация средствами web-cepbepa
  • Авторизация с помощью заголовка
  • Авторизация с помощью cookies
  • Авторизация с помощью сессий
  • Сессии
  • Сценарий авторизации
  • Пример сценария


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ
  • PHP: АВТОРИЗАЦИЯ ДОСТУПА

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

АВТОРИЗАЦИЯ СРЕДСТВАМИ WEB-CEPBEPA

Для того, чтобы к файлам, находящимся в какой-либо директории, могли иметь доступ лишь определенные посетители, знающие два кодовых слова (логин и пароль), можно использовать встроенные в Web-сервер Apache средства ограничения доступа.
В конфигурационных файлах Apache есть специальная строчка -AccessFileName. Там указано имя файла, найдя который в той или иной папке, Apache выполнит по отношению к ней указания, содержащиеся в этом файле. По традиции этим именем является .htaccess, и именно таким оно установлено на всех серверах хостинга. В файл .htaccess можно поместить команды ограничения доступа к той папке, в которой это файл находится.
Выглядят эти команды так. Вначале указывается название защищенной зоны - AuthName. Именно это название будет впоследствии выводиться в запросе посетителю (рис. 8.1).

AuthName "Private Zone"
AuthType Basic

В следующем параметре - AuthUserFile - указывается путь к файлу с логинами и паролями посетителей. Этот файл должен быть создан в особом формате, так как пароли в нем хранятся в зашифрованном виде. Для создания файлов с паролями применя-
ются специальные программы - такую программу вы можете взять, например, в разделе технической поддержки компании Valuehost по адресу http://support.valuehost.ru/bbs/files/69-htpasswd.exe. Запускать ее следует из командной строки в формате 69-htpasswd.exe -с имя_файла_паролей логин, а в открывшемся окне ввести пароль (используя только латинские буквы). Чтобы добавить новые логины и пароли в уже имеющийся файл, эту программу следует запускать без параметра -с.
По традиции файл с паролями посетителей принято называть .htpasswd. Обычно Apache настраивается так, что файлы с именами .htaccess и .htpasswd невозможно просмотреть через Web - при такой попытке будет выдаваться лишь сообщение о запрещении доступа. Однако выполнение такой настройки (для этого надо указать несколько параметров в httpd.conf - конфигурационном файле Apache) - целиком на совести администраторов web-сервера.
Обратите внимание, что путь к файлу паролей следует указывать абсолютный - т. е. от корневого каталога сервера с указанием всего дерева каталогов. На серверах хостинга он обычно имеет вид /pub/home/имя аккаунта/..../имя файла паролей, а на вашем локальном компьютере зависит от местоположения web-сервера и его настроек, например, может выглядеть и как f:/www/exper/cov/.htpasswd.

AuthUserFile /pub/home/exper/cov/.htpasswd require valid-user

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

Итак, пожелав "запаролить" доступ к ресурсам какой-либо папки, создайте файл с именем .htaccess с вышеуказанными параметрами.

Комментарий:
Сделать это командой "Проводника" или "Нортона" вам не удастся, так как эти программы не допускают создание файлов без имени (a .htaccess они воспринимают именно как расширение без имени!), поэтому наберите соответствующий текст в какой-нибудь программе, позволяющей это совершить (например, ViewText Георгия Гуляева, http://www. altailand. ru).

Создав файл .htaccess, загрузите программу для создания файла паролей и поработайте с нею. После этого загрузите оба файла на свой сайт: .htaccess - в закрываемую папку, а файл с паролями - в соответствии с прописанным в .htaccess путем к нему (рис.8.1).

Рис.8.1. Пароль на папку средствами web-сервера? Достаточно двух файлов - .htaccess и .htpasswd...

Вот и все! Теперь при попытке запроса любого ресурса из защищенной папки (в том числе и картинок, включенных в другие страницы тэгом < img...>) посетителю будет выдан стандартный запрос логина и пароля (рис. 8.2). Если логин и пароль совпадают с хранящимися в файле паролей (по умолчанию есть три попытки ввода), то доступ разрешается, если нет - средствами web-сервера выводится соответствующее сообщение.

Рис.8.2. Запрос на вход в папку

Доступ открывается "для определенного окна браузера и всех его дочерних окон". Иными словами, если посетитель однажды ввел правильные логин и пароль, то он, работая в одном и том же окне браузера, может не только свободно путешествовать по всем ресурсам в запароленной папке, но и, выйдя из нее, свободно вновь в нее войти. То же самое верно и для всех окон браузера, открытых из исходного с помощью команды "открыть в новом окне". А вот если пользователь откроет новое окно браузера и зайдет уже в нем в эту папку, то запрос на ввод логина и пароля появится вновь (разумеется, если страница не была взята из кэша браузера - в последнем случае достаточно ее обновить).
Использовать данный способ удается не всегда - администрация сервера иной раз не позволяет это делать посетителям, да и программа для создания файла паролей не всегда под рукой. Однако средства РНР позволяют обойтись без применения файлов .htaccess.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

АВТОРИЗАЦИЯ С ПОМОЩЬЮ ЗАГОЛОВКА

В РНР есть команда Header - она позволяет отправить браузеру посетителя, запросившему страницу с содержащим эту команду сценарием, определенную служебную информацию - так называемый "заголовок". Существует довольно много вариантов заголовков (например, заголовок "Location: http://адрес" приведет кперенаправ-лению на указанный URL; то же самое, что и при использовании мета-тэга http-equiv с параметром "Refresh"), однако для авторизации нам потребуется заголовок "WWW-Authenticate".

Примечание:
Заголовок - это данные, передаваемые браузеру до передачи самой web-страницы, сообщающие ему некоторые параметры передаваемого файла ипи определенные команды. Список всех возможных заголовков, которые обязаны поддерживать современные браузеры, можно найти в спецификациях протокола HTTP - они есть, например, на сайте http://www.w3.org. PHP-команда Header выполняет всего одно действие - она просто передает то, что указано в ее параметре, в браузер, запросивший страницу, на которой она находится, в качестве заголовка.
Следует помнить, что заголовок должен передаваться в браузер до любого другого вывода в него, за исключением установки cookie.

В том случае, если браузер получает заголовок "WWW-Authenticate", то он выдает посетителю стандартное окно для ввода логина и пароля, которое вы наверняка много раз видели (рис.8.2). Как только посетитель нажимает кнопку Ok этого окна, браузер вновь заходит на ту страницу, с которой этот заголовок был ему послан, но на этот раз уже передает сценарию на этой странице две переменные - то, что было введено в поля ввода логина и пароля. Web-сервер дает этим переменным имена $PHP_AUTH_USER и $PHP_AUTH_PW, и их становится можно использовать в остальных сценариях на странице как любые другие переменные - использовать в выражениях, сравнивать с каким-либо эталоном, присваивать им какие-либо другие значения, наконец.
Если посетитель нажимает кнопку Cancel в диалоговом окне запроса логина и пароля, то выполнение кода страницы просто продолжается со следующей строчки за командой Header. Никакие переменные странице не передаются.
Однако переменные $PHP_AUTH_USER и $PHP_AUTH_PW - не простые. Если они один раз были определены, то впоследствии они передаются всем web-страницам, которые загружаются в то же самое окно браузера, где произошла авторизация! Иными словами, если по каким-то причинам требуется проверять логин и пароль посетителя на каждой из страниц сайта (скажем, выводить разную информацию авторизованным и неавторизованным посетителям), то каждый раз запрашивать эти данные не нужно - достаточно использовать значения переменных $PHP_AUTH_USER и $PHP_AUTH_PW. Значения данных переменных теряются в случае закрытия окна браузера, в котором изначально произошла авторизация (а в другие окна они и не передаются). При выходе за пределы виртуального сервера, на котором произошла авторизация (обычно его границы совпадают с границами ак-каунта), данные переменные перестают передаваться страницам, однако при повторном входе на исходный адрес вновь становятся доступными (это обеспечение безопасности - за пределами вашего виртуального сервера логины и пароли ваших посетителей никто узнать из их браузеров не сможет).
Кстати, при использовании предыдущего способа - средствами Apache - в переменные $PHP_AUTH_USER и $PHP_AUTH_PW тоже помещаются значения логина и пароля, введенные пользователем. В принципе вы можете найти им какое-нибудь применение.
К примеру, вспомним содержание седьмой главы, в которой рассматривалась программа для самостоятельной загрузки посетителями файлов на сайт. Помните, в чем была проблема - проверка пароля и сама загрузка файлов совершались сценарием на одной и той же странице, и в случае ошибки при вводе пароля посетитель все равно был вынужден ждать окончания загрузки файла на сайт, чтобы тот был сразу же оттуда удален? Так вот - используя данный способ авторизации (и предыдущий - средствами Apache - тоже), можно разделить авторизацию и закачку файлов, предоставив посетителю возможность вначале ввести логин с паролем, а только потом, если они правильные, выдать ему форму для закачки файла. Если добавить на страницу обработки закачанного файла краткую программу для проверки переменных $PHP_AUTH_USER и $PHP_AUTH_PW, то можно не бояться захода на страницу загрузки неавторизованных посетителей (скажем, по закладке или путем прямого набора ее адреса в браузере) - таковые будут отсеяны, а запросы легальных обработаны.
Ниже приводится сценарий, который запрашивает у пользователя логин и пароль, проверяет их по наличию в определенном файле, а затем выводит либо приглашение к загрузке файла, либо сообщение об отказе в авторизации.
Итак, начало сценария. Обратите внимание, что для того, чтобы он сработал, до команды Header в выдаваемый документ не должно ничего выводиться: ни результат выполнения команд РНР, ни простое содержимое страницы, - так уж воспринимают web-страницы браузеры. В частности, данный сценарий должен располагаться в самом начале страницы, и символы <?php должны быть на ней самыми первыми, перед ними не должно быть даже пробела.

<?php

Поскольку после выдачи окна авторизации браузер вновь вызывает web-страницу, передавая ей авторизационные данные, то можно проверить их еще до отправки браузеру "заголовка WWW-Authenticate. В самом деле - если окно авторизации не выводилось вообще, то переменные $PHP_AUTH_USER $PHP_AUTH_PW будут пустыми (вернее, вообще не определены), а если выводилось - то в них окажется информация, введенная посетителем (т. е. логин и пароль).
Наиболее простым вариантом будет указание логина и пароля в тексте самой программы авторизации - ведь все равно код на РНР, размещающийся на странице, посетители увидеть не смогут1. В этом случае команда проверки содержимого переменных $PHP_AUTH_USER и $PHP_AUTH_PW на соответствие указанным будет выглядеть как

if (($PHP_AUTH_USER!="login")||($PHP_AUTH_PW!= "parol"))

Дальше идет тот код, который выполняется в случае несоответствия содержимого переменных указанным в команде логину и паролю. В случае самой первой загрузки страницы он, естественно, тоже вы-
Вернее, смогут лишь в том случае, если данный код располагается в фаше не с тем расширением, которое указано в настройках web-cepeepa как признак страниц с программами на РНР. 70
полнится - переменные $PHP_AUTH_USER и SPHPAUTH PW в таком случае еще не будут определены.
Итак - выдаем окно авторизации, для чего посылаем браузеру соответствующий заголовок:

Header("WWW-Authenticate: Basic
realm=\"Защищенная зона"\"");

Браузер, получив такое, выдаст посетителю окно (такое же, как на рис. 8.1) с запросом логина с паролем. После нажатия кнопки Ok страница будет загружена вновь и в том случае, если логин и пароль соответствовали указанным в ее тексте, будет выводиться остальной ее текст - тот, что последует за командой if, за ее закрывающей фигурной скобкой. Ну а если логин и пароль будут введены неправильно, то окно авторизации выскочит вновь - и у посетителя появится еще один шанс правильно авторизоваться. И так до тех пор, пока не будут введены правильные логин и пароль.
Однако в выдаваемом окне есть еще кнопка "Отмена"! и в том случае, если посетитель нажмет ее, то код просто начнет выполняться дальше, со следующей после Header команды. Следовательно, в этот код и нужно вставить те команды, которые сообщают посетителю, так и не сумевшему ввести правильные логин с паролем, что он не может войти в защищенную зону. (Не забудьте, что все эти команды должны находиться в пределах блока оператора if- ведь нам надо, чтобы они выполнились только в случае нажатия кнопки "Отмена"!).
Выдадим браузеру заголовок, сообщающий об отказе в авторизации (требуется некоторым браузерам, а заодно и обнуляет переменные $PHP_AUTHJJSER и $PHP_AUTH_PW):

Header ("HTTP/1.0 401 Unauthorized");

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

echo ("<р>Доступ закрыт!</р>");

(При желании вы можете сделать целую web-страницу, на которой подробно рассказать, например, как можно достать правильные логин с паролем, и вставлять ее текст сюда в случае отказа в авторизации с помощью команды include:

include ("noauth.php");

Например, так стоит сделать, если код этой страницы весьма большой или одна такая страница будет использоваться для нескольких мест авторизации.)
И наконец, завершим работу с текущей страницей - нам ведь не нужно выполнять тот код, что дальше; он ведь должен быть доступен только авторизованным посетителям. Для выхода используем комаду exit:

exit; }

Она полностью прекращает как вывод web-страницы посетителю, так и выполнение какого-либо кода. Вот, собственно, и все:

?>

Для наглядности - все строчки кода вместе:

<?php
if (($ PHP_AUTH_USER! = "log in") | | ($ PHP_AUTH_PW! = "parol"))
{
Header("WWW-Authenticate: Basic realm=\"Защищенная зона"\"");
Header("HTTP/1.0 401 Unauthorized");
...текст страницы, выдающейся посетителю в случае нажатия им кнопки "Отмена"...
exit;
} ?>

Указание логина и пароля в самом тексте PHP-сценария - простой, но не очень удобный способ их хранения. В самом деле - если вы планируете предоставить доступ нескольким посетителям, то вам придется давать им одну и ту же пару логина и пароля. Это чревато тем, что при необходимости отказать кому-нибудь из них в доступе придется менять пароль, о чем придется сообщать всем остальным.
Ниже приводится небольшой код, реализующий проверку содержимого авторизационных переменных на совпадение с какой-нибудь парой "логин-пароль" из специального файла паролей.
Допустим, файл, содержащий логины и пароли, располагается в папке passw и называется passwr, а формат его прост - запись типа "логин пароль" (через пробел) на каждой строчке (см. рис. 8.3). Для того, чтобы этот файл нельзя было загрузить через web-интерфейс, просто набрав его имя (и тем самым получив на экран все его содержимое), можете сделать это имя как можно более длинным и заковыристым (все равно оно фигурирует только в программном коде, т. е. из Сети его узнать будет никак нельзя), а можете просто запретить чтение данного файла из Web, соответственно установив его атрибуты, например, в 770 (в CuteFTP это делается пунктом CHMOD из контекстного меню файла, рис. 8.4).

Примечание:
Еще запретить чтение содержимого директорий из Web можно, указав в файле настроек web-сервера Apache (именующемся httpd.conf) в разделе описания соответствующего виртуального сервера параметр Location (например:
<Location /passw>
deny from all
</Location>
- в три строки), однако доступ к файлу настроек web-сервера есть не всегда.

Рис.8.З. Простейший файл паролей

Рис. 8.4. Чтобы файл не "достали" из Интернета, установите его параметры вот так...

Итак, начнем сценарий. Командой file считаем файл построчно в массив...

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

...и начнем сравнивать пару "логин-пароль" каждой строчки файла (т. е. каждый элемент массива) с той парой, что мы получили от пользователя. Массив даже нет нужды именовать - достаточно просто указать команду file в цикле обработки всех элементов массива f oreach (как упоминалось в гл. 3, этот оператор считывает каждый элемент указанного в его параметрах массива в переменную с именем, указанным после ключевого слова as, и выполняет для каждого элемента массива код, указанный в фигурных скобках).

<?php
foreach (file("passw/passwr") as $k)
{

Комментарий:
Оператор foreach будет работать только в РНР 4.0 и выше. Если вы можете использовать лишь РНРЗ, то вместо этого оператора можно использовать цикл for, указав в его параметрах величину массива:
$b=file("passw/passwr");
for ($i = 1; $i < $sizeof($b); $i++)
{
Для удобства можно записать значение очередного элемента массива в переменную:
$value=$k[$i];

Поскольку каждая строчка файла завершалась символом перевода строки (вернее, двумя символами - с ASCII-кодами 10 и 13), то его необходимо удалять перед сравнением (в введенных пользователем значениях символа перевода строки-то нет!) - это делает функция substr.

if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW") {

Примечание:
Команда substr предназначена для выделения из строки ее части. Строка (или переменная, ее содержащая) должна быть указана в первом параметре команды. Второй параметр - позиция, с которой начинается выделяемая часть (вернее, число символов, которые необходимо пропустить до начала выделения части строки), а третий -количество выделяемых символов.
Второй параметр может быть и отрицательным. В этом случае отсчет позиции начала выделяемой части будет идти не с начала, а с конца строки. Иными словами, в результате выполнения команды substr ("qwertyuiop", -3, 2) из строки "qwertyuiop" будет выделена строка io - она начинается за 3 символа от конца исходной строки и продолжается 2 символа.
Третий параметр тоже может быть отрицательным. В этом случае будет выделена строка, начинающаяся с указанной во втором параметре позиции и оканчивающаяся за столько символов до конца строки, сколько указано в третьем параметре. Иными словами, в результате выполнения команды substr ("qwertyuiop", 3, -2) из строки "qwertyuiop" будет выделена строка rtyui - она начинается после 3 символа исходной строки и заканчивается за 2 символа до ее окончания.
В том случае, если параметры установлены так, что выделить согласно им символы из строки оказывается невозможно (например, второй параметр больше, чем число ее символов), то результатом работы команды substr будет пустая строка- "".

Если в файле с паролями была найдена пара "логин-пароль", совпадающая с данными, введенными пользователем, то присвоим переменной $rez значение 1. Впоследствии ниже, когда нам надо будет проверить, совершилась ли авторизация, просто будем проверять значение этой переменной - так проще, чем вновь проводить просмотр файла паролей.

$rez=l;
} }

Собственно, и все - проверка завершена. Теперь в том случае, если переменная $rez не равна 1, следует выдать окно авторизации и получить от посетителя логин и пароль, а если равна - то выводить страницу дальше.

if ($rez!=l) {
Header("WWW-Authenticate: Basic realm=\"Защищенная зона"\"");
Header("HTTP/1.0 401 Unauthorized");
...текст страницы, выдающейся посетителю в случае нажатия им кнопки "Отмена"...
exit;
} ?>

Как уже говорилось, переменные SPHPAUTHUSER и $PHP_AUTH_PW передаются всем страницам, которые загружаются в то же самое окно браузера - т. е. на которые посетитель переходит. Поэтому их можно использовать для проверки его прав на выполнение того или иного действия без новых запросов. Скажем, если на какой-нибудь странице, на которую посетитель должен перейти лишь после авторизации, должна производиться загрузка файла, то перед загрузкой (в сценарии-обработчике загруженного файла, подробнее -см. гл. 7) следует вновь проверить соответствие переданных этой странице переменных SPHPAUTHJJSER и $PHP_AUTH_PW какой-нибудь паре логина и пароля в файле паролей:

<?php
foreach (file("passw/passwr") as $k)
{
if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW")
{ ...команды загрузки файла...
} } ?>

Данный код просматривает файл с паролями (да, опять тот же файл...) и определяет, есть ли там пара "логин-пароль", соответствующая переданным странице переменным. Если есть, то файл загружается, если нет (т. е. посетитель зашел на страницу с формой для загрузки файла, скажем, по сделанной в "Избранном" закладке или введя ее URL в адресную строку браузера, миновав страницу авторизации), то загрузка не производится.
Иными словами - один раз введенные посетителем правильные логин с паролем записываются в переменные SPHPAUTHUSER и $PHP_AUTH_PW до тех пор, пока посетитель не закроет окно браузера (и все окна, открытые по ссылкам командой "Открыть в новом окне" из окна, где произошла авторизация). На тех страницах, куда посетитель может попасть после авторизации, значения этих переменных можно проверять, сравнивая с каким-либо эталоном, например, записанными в скрытом файле логинами и паролями, и выдавать посетителю в зависимости от соответствия эталону его авторизационных данных разную информацию. Это предотвратит возможность попасть в "закрытую зону" помимо окна авторизации, через набор адреса в адресной строке или по закладке.
Например, для отправки на страницу авторизации всех, кто ее не прошел, можно воспользоваться кодом

<?php
foreach (file("passw/passwr") as $k)
77
if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW")
{ $rez=l; } }
if ($rez!=l) {
Header ("Location: auth.php"); } ?>

где auth.php - страница с кодом выдачи окна авторизации. Заголовок Location, переданный браузеру, вызывает его переход на указанную в нем страницу. Так как в данном коде используется команда Header, то она сработает без ошибок лишь в том случае, если до нее в браузер посетителя ничего не выдавалось (кроме разве что других заголовков и cookies).
Особенности описанного способа авторизации довольно очевидны. Например, данные авторизации сохраняются в переменных лишь в течение одного сеанса работы посетителя; достаточно ему закрыть окно браузера, чтобы необходимость ввода логина и пароля возникла снова. Для заполнения полей окна авторизации нельзя использовать имеющуюся во многих браузерах функцию автозаполнения форм (современные браузеры могут запоминать соответствие определенному URL лишь одной пары "логин-пароль" и подставлять именно ее в поля окна), да и в интерфейс страницы это окно вписать никак нельзя (оно ведь отображается браузером).
Однако есть еще один прием регламентации доступа к страницам сайта - с использованием файлов cookies.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

АВТОРИЗАЦИЯ С ПОМОЩЬЮ COOKIES

Cookie - это файл в специальном формате, который присылается сервером браузеру посетителя сайта, расположенном на этом сервере (рис.8.5). Браузер, если он поддерживает cookie (и эта поддержка в нем не отключена), помещает его в особое место и впоследствии отправляет назад на сервер при поступлении от него запроса. Иными словами, cookie позволяет серверу хранить свою информацию на компьютерах посетителей и считывать ее оттуда при необходимости. (Современные стандарты безопасности предусматривают, что каждый сервер (Вернее, узел с собственным именем (любого уровня)). может получить назад только те cookie, которые были установлены лично им, так что даже о том, какие сайты еще посещал посетитель, с помощью cookie узнать нельзя.)

Рис.8.5. Cookie изнутри

Примечание:
Cookie можно установить (т. е. прислать на компьютер посетителя) и средствами РНР. Для этого используется команда SetCookie, имеющая параметры: имя cookie, информация, записанная в cookie, время жизни cookie - указывается количество секунд, после истечения которых с 1 января 1970 года cookie не должен считы-ваться с компьютера посетителя (так уж измеряется время в операционных системах типа Unix - с начала "эпохи Unix" 01,01.1970), адреса сайта и каталога на нем, где cookie должен быть действителен, и указание на протокол передачи cookie (подробнее смотрите в Описании РНР). Считать cookie можно простой командой echo ("имя cookie"). Можно сказать, что, как только cookie установлен, сценариям на всех страницах того сайта, на котором он был поставлен, становится доступна переменная с тем же именем, что и у cookie, и тем содержимым, которое было записано в нем (если в файле настройки РНР установлен в on параметр register_globals).
Кроме того, значения cookie помещаются в массив $HTTP_COOKIE_VARS и доступны в его элементах, одноименных с именами cookie - SHTTP_COOKIE_VARS['umh cookie'] (если в файле настройки РНР установлен в on параметр track_vars), а в РНР версии 4.1 и выше - еще и в массив $_С00К1Е.
Для удаления cookie достаточно записать в него пустое значение (это сделает команда SetCookie с единственным параметром -именем cookie).
Для установки времени жизни cookie можно сначала узнать текущее "время Unix" командой time(), а потом просто прибавить к нему то количество секунд, которое cookie должен просуществовать после его установки на компьютер посетителя. Если время жизни для cookie не установлено, то он проживет до закрытия всех окон браузера посетителя.
Как и отправка заголовков командой Header, установка cookie должна предшествовать любому выводу в выдаваемый документ: как результатов выполнения команд РНР, так и простого содержимого страницы. Иначе возникнет ошибка.

Как cookie можно использовать для решения обсуждаемой в этой главе задачи - авторизации доступа? Да вчень просто - запросив от посетителя логин и пароль, записать их в cookie, а потом на каждой странице "защищенной зоны" считывать их оттуда и проверять, имеются ли такие данные в файле паролей. Ну и поступать в соответствии с результатом такого сравнения - например, отправлять те браузеры, которые не смогли представить cookie с правильными логином и паролем, прямиком на страницу авторизации, посылая им с помощью РНР-функции Header заголовок Location с соответствующим параметром, как было показано выше для предыдущего варианта авторизации.
Вот фрагменты сценария, в которых видна технология использования cookies. На той странице, откуда должен осуществляться вход в "защищенную зону", следует поставить простую форму для ввода логина и пароля (см.рис.8.6). Например, такую:

<FORM ACTION="up.php" METHOD=POST> Логин: <INPUT NAME="login" TYPE="text"><br> Пароль: <INPUT NAME="pass" TYPE="password"><br> <INPUT TYPE="submit" VALUE="Войти"></FORM>

Рис.8.6. Авторизация на основе cookies. Просто форма...

На той странице, имя которой указано в параметре ACTION заголовка формы, введенные данные проверяются, и в том случае, если такие логин и пароль имеются в файле паролей, браузеру посетителя отсылается cookie, куда эти логин с паролем записываются.

<?php
foreach (file("passw/passwr") as $k)
{
if (substr($k, 0, -2)=="$login $pass")
{
$rez=l;

И вот - сама установка cookie под именем auth. Ему устанавливается "время жизни" - 3600 с, т. е. час.

SetCookie("auth","$login $pass",time()+3 600);
} } ?>

Дальше должен находиться сценарий, который в зависимости от исхода авторизации - т. е. значения переменной $rez - выводит различную информацию. Например, можно отослать посетителя назад на исходную страницу командой Header ("Location..."), как в примере предыдущего раздела этой главы.
На всех остальных страницах "защищенной зоны" должен находиться сценарий проверки содержимого переменной auth (т. е. той, чье имя совпадает с именем поставленного cookie) - т. е. точно такой же скрипт, как и на той, где cookie ставился, только строка проверки должна выглядеть как

if (substr($k, 0, -2)=="$auth"),

ну и, естественно, самой команды установки cookie быть не должно. Дальнейший текст страницы - на усмотрение web-мастера: если логин с паролем, полученные из cookie, есть в файле паролей, то, скажем, вывести форму для закачки файлов, если нет - то вежливо распрощаться...
Желательно также сделать страницу "выхода", включив в нее команду установку cookie без параметров - SetCookie ("имя cookie").
В результате в том случае, если посетитель единожды прошел авторизацию, то он может спокойно посещать страницы "защищенной зоны" до тех пор, пока cookie "жив" на его компьютере. Он может закрыть окно браузера и даже выключить компьютер, а потом, включив его, вновь зайти на тот же адрес, используя "Историю" браузера или "Закладки"- и он будет авторизован, если время жизни cookie не истекло. Зато те, кто "подглядит" этот адрес или украдет закладку, но не будет иметь соответствующего cookie, авторизованы не будут.
В отличие от предыдущего способа, данный вариант не является абсолютно надежным в плане сохранности в тайне логина с паролем. Во-первых, cookie с этими данными сохраняется на компьютере посетителя, а значит, теоретически может быть с него похищен (тем, кто просто сядет за этот компьютер и скопирует нужный cookie из той папки, где они хранятся). Во-вторых, возможность захода на web-страницу "защищенной зоны" в течение некоторого времени без необходимости ввода логина и пароля может привести и к нежелательным последствиям - если посетитель забудет зайти на страницу выхода, то любой, кто воспользуется его компьютером до истечения срока действия cookie, с точки зрения сервера будет вполне легальным пользователем и сможет устроить истинному владельцу логина немало проблем.
Стоит сказать, что использовать имя cookie как переменную можно только в том случае, если в файле настройки РНР - php.ini - есть параметр register_globals. Там, где этого параметра нет (например, в РНР версии 4.2 и выше он по умолчанию неактивен), работать с cookies как с обычными переменными не получится. Информацию, помещенную в них, придется получать из массива с названием SHTTPCOOKIEVARS (создается автоматически при обнаружении cookies от данного сайта), используя имя нужного cookie в качестве индекса:

<?php
foreach (file("passw/passwr") as $k)
{
if (substr($k, 0, -2)==$HTTP_COOKIE_VARS['auth'])
{ $rez=l;
}
}
...

В РНР версии 4.1 и выше вместо $HTTP_COOKIE_VARS можно использовать массив $_СООК1Е.
Надеюсь, вы поняли, что все эти проверки логинов и паролей в cookies и передающихся между окнами переменных, о которых так подробно рассказывается в этом и предыдущем разделах, предназначены для одной цели - чтобы тот, кто каким бы то ни было образом узнал бы адрес страницы из "защищенной зоны" и зашел бы на эту страницу путем набора ее адреса в адресной строке браузера (или с помощью ярлыка в "Избранном"), не мог бы увидеть на ней то же самое, что и добросовестно прошедшие авторизацию посетители. Чтобы не приходилось запрашивать от посетителей пароль и логин на каждой странице, где есть возможность совершить те действия, которые крайне нежелательно позволять делать всем подряд - как, например, загрузка файлов или просмотр личной почты - а дать посетителям возможность, единожды введя авторизационные данные, свободно перемещаться по "защищенной зоне". Именно это и является основной задачей описанных технологий.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

АВТОРИЗАЦИЯ С ПОМОЩЬЮ СЕССИЙ

Вы, наверное, уже заметили особенность обоих вышеописанных способов авторизации - проверка правильности логина и пароля осуществляется на каждой странице, где требуется авторизованный доступ. Если посетителей на сайте не очень много, то это вполне допустимо, однако при большом числе авторизованных посетителей нагрузка на web-сервер может оказаться немалой.
В связи с этим возникает вопрос: а нельзя ли как-нибудь избежать необходимости каждый раз осуществлять проверку логина и пароля посетителя? Чтобы, единожды авторизовав посетителя, впоследствии предоставлять ему доступ на страницы защищенной зоны без каких-либо проверок? Именно так, кстати, действует защита на основе средств web-сервера - файлов .htaccess, описанная в первом разделе главы. Но можно ли сделать то же самое средствами РНР? Да и вообще использовать cookie для хранения паролей не очень желательно: его содержимое может узнать любой, кто воспользуется компьютером, на котором этот cookie сохранен (многие браузеры хранят cookie в предназначенной для них папке, даже если "время жизни" cookie истекло и он больше не принимается сервером).
Напрашивается первое предложение: а почему бы, например, после успешной авторизации не отправить посетителю cookie с какой-либо пометкой (например, устанавливать в 1 значение переменной в этом cookie), а впоследствии проверять не наличие записанных в cookie логина и пароля в файле паролей или базе данных, а присутствие в cookie этой самой пометки, одинаковой для всех, прошедших авторизацию? Или даже сделать разные типы пометок и в зависимости от типа предоставлять посетителю разные возможности на сайте?
Сделать-то так можно, да вот устойчивость такой системы авторизации к взлому будет не особо великой. Злоумышленнику будет достаточно узнать, что за пометку помещает сценарий авторизации в cookie, чтобы получить к защищенной зоне полный доступ - просто вручную создав такой cookie. (А если при проверке "пометки" использовался не элемент массива $HTTP_COOKIE_VARS, а одноименная переменная, то и просто подставив ее значение в адресной строке при заходе на страницу с такой проверкой: например, page . php?auth=1.) Кроме того, просмотреть значение cookie на компьютере посетителя и узнать, какие его имя и значение являются "пометкой", тоже не так трудно.
Но самое главное - посетители нередко отключают использование cookie при своих путешествиях по Интернету. При отключенных cookie описанная выше система авторизации на их основе работать не будет.
Как же быть?
Следует использовать весьма интересный механизм сессий, появившийся в 4-й версии РНР.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

СЕССИИ

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

Рис. 8.7. Файлы с данными сессий в папке временных файлов сервера. Имена файлов соответствуют идентификаторам сессий

Рис. 8.8. Содержимое одного из таких файлов. В сессии сохранены переменные: legus, wql, wq2, wq3

Если у посетителя браузер принимает cookie, то ему высылается cookie (с определенным именем - по умолчанию "PHPSESSID"), содержащий так называемый "идентификатор сессии" (рис. 8.9), а если нет, то web-сервер автоматически помещает данный идентификатор в переменную PHPSESSID в каждую ссылку (рис. 8.10) на выдаваемых посетителю страницах сайта (естественно, "внутреннюю" - т. е. ведущую на другие страницы того же самого сайта, с тем же самым доменным именем). Таким образом, идентификатор передается на сервер при каждом заходе посетителя на какую-либо из страниц сайта. При этом идентификатор выбирается либо из соответствующего cookie, установленного посетителю при открытии сессии, либо из адресной строки ссылки, куда этот идентификатор автоматически помещается web-сервером.

Рис. 8.9. Содержимое cookie с идентификатором сессии

Рис. 8.10. Ссылка с идентификатором сессии

Как только сервер получает от посетителя определенный идентификатор сессии, то он передает сценарию на той странице, на которую зашел посетитель, все установленные для этого посетителя сохраненные переменные, после чего сценарий может их использовать, т. е. читать, изменять, уничтожать. При переходе на следующую страницу сайта все изменения будут сохранены.
Каждый раз создаётся новый идентификатор сессии. Благодаря хорошему алгоритму генерации вероятность того, что для какой-либо последовательности символов на определенном сервере будет существовать набор сохраненных переменных, пренебрежимо мала. Еще меньше вероятность совпадения двух идентификаторов сессий, так что разные посетители сайта ну никак не смогут получить значения переменных друг друга.
Бесспорно, набор сохраненных переменных, относящихся к одной сессии, будет существовать на сервере не вечно. В параметрах файла конфигурации РНР - php.ini - указывается, какое время жизни устанавливается для cookie с идентификатором сессии (по умолчанию 0 -т. е. до закрытия окна браузера и всех открытых из него окон), а также через какое время данные сессий из папки временных файлов удаляются физически (рис. 8.11). Кроме того, существует специальная команда "разрушения сессии", которая при своем выполнении уничтожает сохраненные в папке временных файлов данные сессии и тем самым делает недействительным идентификатор сессии. Параметры устанавливаемых cookie, в частности, их "время жизни" также можно задать специальной командой в сценарии на РНР, однако время хранения данных сессии в папке временных файлов определяется параметром в php.ini, так что при использовании виртуального хостинга вам не всегда удастся настроить работу с сессиями полностью так, как вам бы хотелось.

Рис.8.11. Файл php.ini, раздел настроек параметров сессий

Чтобы использовать в сценарии на странице возможности работы с сессиями, необходимо включить в него команду session_start () (так как при работе с сессиями используются cookie, то данная команда должна находиться в начале страницы, перед какими-либо выводимыми в браузер данными) - как при первоначальной установке переменных, так и при последующей работе с ними (если в файле php.iniустановлен в 1 параметр session.auto_start, то это делать не обязательно). Чтобы указать, какие переменные следует сохранять в качестве данных сессии, следует использовать команду session register("имя первой переменной", "имя второй переменной",... и т. д.), а чтобы закрыть сессию - команду session_destroy (). При закрытии сессии переменные, переданные сценарию с ее помощью, не обнуляются (последнее делает команда session_unset () ;), так что их можно использовать и в остальной части сценария.
Переменные сессии доступны на сценариях сайта по своим изначальным именам - скажем, если командой session_register переменная $а была зарегистрирована в качестве сессионной, то ее значение будет доступно под тем же самым именем - $а - на всех страницах сайта, где используются сессии (т. е. в их начале размещена команда session_start ()).
Переменные сессии доступны в сценариях сайта по своим изначальным именам. Скажем, если командой session_register переменная $а была зарегистрирована в качестве сессионной, то ее значение будет доступно под тем же самым именем — $а - на всех страницах сайта, где используются сессии (т. е. в их начале размещена команда session_start ()).
Однако в целях безопасности лучше работать в сценарии с переменными сессии через автоматически создаваемые массивы $HTTP_SESSION_VARS и (в РНР версий 4.1 и старше) SSESSION, используя одноименные с переменными элементы этих массивов. Дело в том, что в этом случае сценарий будет огражден от возможных попыток злоумышленников передать ему значения этих переменных через указание их в адресной строке, если сессия не была открыта (в указанные массивы попадают те и только те данные, что были получены с сессией). Такая передача может привести, скажем, к тому, что переменная - пометка об успешном прохождении авторизации будет получена сценарием не из данных сессии (в которых она может появиться только после успешного ввода посетителем правильных логина и пароля), а от злоумышленника.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

СЦЕНАРИЙ АВТОРИЗАЦИИ

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

<?php
foreach (file("passw/passwr") as $k)
{if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW")
{$rez=l;}}
if ($rez!=l) {Header("WWW-Authenticate: Basic realm=\"Защищенная зона"\""); Header("HTTP/1.0 401 Unauthorized");
...текст страницы, выдающейся посетителю в случае нажатия им кнопки "Отмена"...
exit,-}

или таким (если логин и пароль передаются из формы в переменных Slogin и Spass):

<?php
foreach (file("passw/passwr") as $k)
{if (substr($k, 0, -2)=="$login $pass"){$rez=l;
if ($rez!=l) {...текст страницы, выдающейся посетителю в случае ввода неправильных логина и пароля ...
exit;}

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

session_start();

...регистрируем переменную:

session_register("auth");

...и устанавливаем ей определенное значение - дабы потом его и проверять.

$auth=1;

Собственно, и все.

?>

Дальше следует текст страницы, которую посетитель должен увидеть сразу же после успешной авторизации.
Так как идентификатор сессии обычно сохраняется в cookie, то приведенный выше код должен стоять в самом начале страницы, чтобы сервер имел возможность работать с cookies, т. е. был бы в состоянии отправить cookie с идентификатором сессии браузеру посетителя. (Если браузер посетителя не принимает cookie, то идентификатор сессии будет автоматически присоединяться ко всем найденным на данной странице ссылкам на другие ресурсы сайта.)
На каждой странице "защищенной зоны", в самом ее начале нужно поставить код

<?php session_start();
if ($auth!=l)
{...текст страницы, выдающейся посетителю в случае попытки несанкционированного доступа...
exit;}

...и все, что после этого кода, будет выполнено и/или выдано посетителю только в том случае, если он успешно прошел авторизацию на первой странице. При заходе на страницу "защищенной зоны" браузер посетителя перешлет серверу cookie с идентификатором сессии, а сервер возьмет из своего временного хранилища значение всех переменных сессии и передаст их сценарию.
Страница выхода из "защищенной зоны" должна содержать код (если в файле php.ini установлен в 1 параметр session.autostart, то указывать команду session_start () на каждой странице, где используются переменные сессии или производятся действия с самой сессией, не обязательно).

<?php
session_start(); session_destroy(); ?>

После его выполнения для посещения страниц "защищенной зоны" вновь потребуется авторизация.
Если посетитель не воспользовался страницей выхода из защищенной зоны, то время, в течение которого из его браузера можно попасть на другие ее страницы, определяется настройками в файле php.ini. По умолчанию cookie с идентификатором сессии, устанавливаемым данному посетителю, существует до закрытия всех окон браузера, а сами данные сессии хранятся несколько часов. Существует команда session_set_cookie_params () (подробную информацию о ней смотрите в Описании РНР), с помощью которой можно установить другое "время жизни" cookie, однако для изменения настроек в файле php.ini необходимо иметь права администратора для web-сервера.
Посредством сессий можно передавать между страницами сайта и другие данные. Например, при создании сценария Интернет-магазина, витрина которого занимает больше чем одну страницу, данные о заказываемых посетителем товарах имеет смысл передавать по страницам сайта в переменных сессии для последующего их оформления на специальной странице как заказа, как, собственно, и делается на большинстве подобных ресурсов Сети.
Так что, как видите, никаких особых секретов в технологии ограничения доступа нет. Авторизация пользователей на многих службах хостинга, web-интерфейсов почтовых систем, Интернет-форумах обычно строятся на тех же принципах, что и приведенные выше сценарии.
Реализовав данные приемы на своем сайте, вы можете, например, вполне спокойно приглашать к себе на работу ведущих отдельных разделов вашего сайта. Все компоненты для их удобной и безопасной работы у вас уже есть: и "папкопотрошилка", и "закачиватель файлов", теперь вот еще и "защищенная зона"... Разве что стоит добавить еще и нечто вроде "файлового менеджера", чтобы посетители могли и удалять, и переименовывать загруженные ими файлы. Но об этом -еще через пару глав.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПРИМЕР СЦЕНАРИЯ

Вот пример сценария, в котором используется авторизация на основе заголовка WWW-Authenticate. Он состоит из двух страниц - на первой логин с паролем проверяются и в том случае, если они есть в файле паролей, то посетителю выводится форма для загрузки файла. На второй странице осуществляется загрузка файла.

Файл 1

<?php
foreach (file("passw/passwr") as $k)
{
if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW")
{$rez=l;} 1
if ($rez!=l) {
Header("WWW-Authenticate: Basic realm=\"Защищенная зона" \" ") ;
Header("HTTP/1.0 401 Unauthorized"); echo ("<р>Доступ закрыт!</р>"); exit;
<FORM ENCTYPE= "multipart/form-data" АСТION ="Файл 2" METHOD=POST>
Закачать файл:<INPUT NAME="zak" TYPE="file"> <INPUT TYPE="submit" VALUE="Закачать">
</FORM>

Файл 2

<?php
foreach (file("passw/passwr") as $k) {
if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW") { $rez=l; }
if ($rez!=l)
{
echo ("<р>Доступ закрыт!</р>");
exit;
if ($zak=="none")
{echo ("Вы забыли указать файл...");} elseif (copy($zak, "папка для файлов/$гак_пате"))
{echo("Файл $zak_name загружен");} else
{ echo("He удалось скопировать $zak_name");} ?>

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ГЛАВА 9. РНР: ГОСТЕВАЯ КНИГА

Вы наверняка неоднократно встречали в Интернете такой сервис, как гостевые книги, т. е. web-страницы, на которых каждый посетитель может оставить свой отзыв, который будет «виден» другим посетителям, впоследствии зашедшим на страницу. Скорее всего, вы думали, что создание гостевой книги требует долгого и сложного программирования.
Не спорю, сделать крупный Интернет-портал, предоставляющий всем желающим гостевые книги для установки на сайт, довольно трудно. Однако на языке программирования РНР организация простой системы оставления сообщений может быть создана всего несколькими строками кода. Причем нетрудно заставить эти строки обслуживать сразу несколько отдельных гостевых книг, скажем, дать посетителям возможность оставлять свои комментарии и отзывы о различных материалах, размещенных на сайте, на тех же самых страницах, на которых эти материалы размещены. Или, допустим, организовать разные книги для разных категорий посетителей.
Данная глава, как вы, наверное, уже поняли, посвящена рассказу о сценарии на РНР для создания простейшей гостевой книги. В главе разобран сценарий, позволяющий сделать на одном сайте несколько гостевых книг. Очевидно, что приспособить его для работы всего одной гостевой книги элементарно.
Схема работы сценария простой гостевой книги такова.
Для хранения сообщений выделена специальная папка, в которой каждое сообщение хранится в отдельном текстовом файле. Для того чтобы можно было различать сообщения, принадлежащие разным гостевым книгам, каждая книга имеет свой индекс (например, "gbOl"), который указывается в специальном сценарии в ее тексте. Имя каждого файла с сообщением начинается с этого индекса (см. рис. 9.1).
Поскольку в гостевой книге, как нетрудно догадаться, количество сообщений весьма скоро превысит одно, то файлы с ними нужно еще и последовательно нумеровать. Вернее, не "последовательно", а так, чтобы их можно было отсортировать - наверное, достаточно возможности сортировки лишь по дате появления.
В РНР есть интересная функция - time (); она выдает количество секунд между 1 января 1970 года (этот момент считается началом "эпохи Unix") и текущим временем, так называемую "временную метку Unix". (В настоящее время эта величина - чуть больше миллиарда.) Посмотрите - если имя файла с сообщением составлять из индекса гостевой книги и временной метки Unix (см. рис. 9.1), то, во-первых, каждое сообщение будет обладать своим уникальным именем (посылка нескольких сообщений в гостевую книгу разными пользователями в одну и ту же секунду теоретически возможна, но маловероятна), а, во-вторых, их легко можно будет отсортировать по времени появления (время ведь вспять не течет - каждое новое сообщение будет получать большую метку, нежели любое предыдущее).
Бесспорно, так как сортировка имен, состоящих из индекса и временной метки, будет проводиться по законам сортировки строк (т. е., скажем, 21 будет стоять раньше 3 при сортировке по возрастанию - т. к. сравнение ведется с начала строки), то при увеличении разрядности временной метки новые сообщения окажутся посреди старых. Однако какие-либо проблемы в нашем случае начнутся не раньше момента достижения временной меткой значения в 10 миллиардов, а до него еще больше, чем две с половиной сотни лет...

Рис. 9.1. Гостевая книга - все ее файлы

Итак, вот алгоритм работы сценария гостевой книги:

  1. 1. При загрузке посетителем страницы книги просканировать папку с сообщениями, выбрать оттуда сообщения, относящиеся к данной книге (попросту найдя в именах содержащих их файлов индекс этой книги), отсортировать их и вставить в web-страницу.
  2. 2. При вводе посетителем сообщения пересчитать уже имеющиеся и сохранить новое сообщение в файле с именем, состоящим из индекса текущей гостевой книги и временной метки Unix.

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

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

Ну а теперь посмотрим, как все это реализуется на РНР.
В текст каждой web-страницы, на которой должна быть расположена гостевая книга, следует вставить следующий код (см. рис. 9.2):

<?php
$пот="уникальная аббревиатура книги, без пробелов и специальных символов, например, book01";
include ("niz.php"); ?>

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

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

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

<?php

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

$dirct="gb";

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

$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 о ();. Она даст исчерпывающую информацию как по этому, так и по множеству других вопросов.

Рис. 9.3. Внешний вид гостевой книги и файлов с ее сообщениями

При работе приведенного выше сценария после добавления нового сообщения в гостевую книгу (рис. 9.3) посетитель окажется на странице обработки отзывов, в данном случае otziv.php. Можно поместить на ней, например, фразу с благодарностью за добавленное сообщение. Однако куда лучше будет, если после добавления нового сообщения посетитель автоматически вернется в гостевую книгу, куда он только что добавил свое сообщение. Для того чтобы это сделать, можно поместить вконец обработчика строчку Header ("Location: имя_меЬ-страницы_с_гостевой_книгой"); указав имя нужной страницы (например, передав его в форме вместе с остальными переменными, т. е. количеством отзывов и индексом страницы), или просто включить обработчик в сам файл niz.php, а в качестве страницы-обработчика формы указать ту же самую страницу с гостевой книгой.
В таком случае после отправки формы просто загрузится та же самая гостевая книга, но уже с добавленным новым сообщением. В результате весь код гостевой книги уместится в одном файле (а обслуживать он может хоть пару десятков отдельных гостевых книг!).
Итак, вот полный, готовый к употреблению код сценария гостевой книги. Попробуйте разобраться в нем самостоятельно - это будет легко, ведь все его строки уже были подробно разобраны выше.
В каждую страницу, на которой располагается гостевая книга, следует включить такой сценарий:

<?php
$пот="имя (без расширения) web-страницы, на которой расположена гостевая книга";
include ("niz.php"); ?>
Ну а файл niz.php должен содержать весь остальной код:
<?рпр
$dirct="gb"; if ($otziv!="")
{
$otznam=$nom.time();
$hdl = fopen("$dirct/$otznam", "w+"); fwrite($hdl,nl2br(strip_tags($HTTP_POST_VARS['ot ziv'])));
fclose($hdl);
}
$hdl=opendir($dirct); while ($file = readdir($hdl))
{
if (strstr($file, $nom)==True) { $a[]=$file;
$l=sizeof($a); if ($l!=0)
{
rsort($a);
foreach ($a as $k)
include ("$dirct/$k");
echo ("<br>(разделитель сообщений)");
Ваш комментарий:
<form method="post" action="<?php echo ("$nom".".php"); ?>" name="form">
<textarea name="otziv" cols="60" rows="10" wrap="virtual"></textarea>
<input name="submit" type="submit" value="Послать отзыв"></form>

В отличие от разобранного нами кода тут нет необходимости передавать в форме индекс гостевой книги (так как он все равно устанавливается на странице гостевой книги и тем самым доступен и на всем протяжении включенного в нее niz.php), однако необходимо сообщить имя содержащего эту гостевую книгу файла - дабы именно его указать в качестве обработчика формы ввода сообщения. Проще всего именно это имя и указывать в качестве индекса гостевой книги.
Хотя в принципе указывать в сценарии имя файла в качестве индекса гостевой книги не надо. В начало кода в файле niz.php можно включить код, который бы этот самый индекс определял бы автоматически. Скажем, брал бы значение переменной $PHP_SELF - она содержит имя текущего файла вместе с путем к нему от корневой директории сайта (даже если она находится в файле, включенном в текущий с помощью оператора include), скажем, "/guestbooks/gbOl.php", а затем вытаскивал из него само это имя.
В РНР версии 4.1 и выше имя файла без расширения можно узнать командой basename (), указав в ее параметрах это самое расширение:

$nom=basename($PHP_SELF, ".php");

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

В РНР версии до 4.1 команда basename () имя файла без расширения выдать не сможет, однако расширение можно отбросить путем использования команды substr, указав в ее третьем параметре отрицательную величину - число символов от конца строки, которые не должны включаться в выделяемую строку (подробнее см. гл. 8):

$nom=substr(basename($PHP_SELF), 0, -4);

Если эту команду определения имени файла без расширения включить в самое начало кода файла niz.php, то установку значения переменной Snom на web-страницах, содержащих гостевые книги, можно убрать - достаточно одного оператора include:

<?php include ("niz.php"); "?>

...и абсолютно вся программа гостевой книги поместится в одном файле. Вам останется лишь вставлять его командой include всюду, куда захотите (да разве что еще саму папку для сообщений создать вручную вначале).
Настаивать на том, чтобы в качестве индекса гостевой книги использовать имя страницы, на которой она располагается, именно без расширения, не обязательно - если этого не сделать, то в результате работы рассмотренного сценария сообщения будут помещаться в файлы, имена которых будут начинаться с этого полного имени (т. е. вместе с расширением) - всего лишь небольшое косметическое неудобство.
Бесспорно, данный код можно улучшать. Можно, например, сделать так, чтобы на странице отображались не сразу все сообщения, а лишь часть, скажем, последний десяток. Для этого следует немного изменить код вывода сообщений, вместо конструкции foreach использовав, скажем, оператор for в том случае, если количество сообщений больше десяти:

<?php
$dirct="gb";
$nom=substr(basename($PHP_SELF), 0, -4);
if ($otziv!=B")
{
$otznam=$nom.time();
$hdl = fopen("$dirct/$otznam", "w+")
fwrite($hdl, nl2br(strip_tags($HTTP_POST_VARS['otziv']))
fclose($hdl); }
$hdl=opendir($dirct); while ($file = readdir($hdl)) {
if (strstr($file, $nom)==True) { $a[]=$file;
$1=sizeof($a); if ($l!=0) {
rsort($a);
if ($l>10)
{
for ($i = 0; $i < 10; $i++)
{
include ("$dirct/$a[$i]n);
echo ("<br>(разделитель сообщений)");
else
foreach ($a as $k)
{
include ("$dirct/$kB);
echo ("<br>(разделитель сообщений)");
}
}
}
?>
Ваш комментарий:
<form method="post" action="<?php echo ($nom.".php"); ?>" name="form">
<textarea name="otziv" cols="60" rows="10" wrap="virtual"></textarea>
<input name="submit" type="submit" value="Послать отзыв">
</form>

(Измененная часть кода выделена жирным.)
Тогда на странице отобразятся лишь последние 10 сообщений. (Код, выводящий остальные сообщения так же, по десяткам, сделайте самостоятельно.)
Так что, как видите, сделать гостевую книгу на РНР не просто, а очень просто. Весь ее код уместится на одном экране, даже на мониторах с небольшим разрешением. Но даже такой простой скрипт таит в себе немало возможностей для творчества.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПРИЛОЖЕНИЕ 1. ПРЕВРАТИ СВОЙ САЙТ В ПОРТАЛ

  • Преврати свой сайт в портал
  • Мир информеров
  • С миру по нитке
  • Рабочий стол современного человека


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПРЕВРАТИ СВОЙ САЙТ В ПОРТАЛ...

Секрет популярности многих сайтов - в том, что они предоставляют посетителям именно ту информацию, которая их интересует. А что интересует практически всех, независимо от склонностей, увлечений, профессии? Да наверное - прогноз погоды, курс доллара. Еще, разумеется, новости - как общемировые, так и связанные с профессией посетителя.
Всю подобную информацию предоставляют крупные сайты, так называемые порталы. Название "портал" как раз и обозначает то, что сайт универсальный и вполне может являться "точкой входа" в Интернет. Зайдя на портал, пользователь может сразу узнать и о том, что нового приключилось в мире с момента его последнего сеанса работы в Сети, и о том, какую одежду следует одевать сегодня и завтра, и даже о том, у кого из его знакомых в этот день именины.
Сделать полноценный портал и поддерживать его - задача нелегкая и довольно дорогая. И действительно - нужно контактировать и с новостными агентствами, и с Гидрометеоцентром, и изучать литературу различного назначения, дабы ежедневно предоставлять посетителям свежую и полезную информацию.
Однако если вам вдруг захочется стать владельцем портала, то вы сможете это сделать за полчаса! Причем не только практически не потратив денег, но даже и не связывая себя необходимостью впоследствии к этому порталу прикасаться. Если же у вас есть сайт, то за те же полчаса вы превратите его в многофункциональный информационный центр, добавив на него массу полезной информации и сервисов. Обновлять же такой сайт вам придется лишь тогда, когда вы решите добавить на него вашу авторскую информацию.
Как такое возможно? Посредством использования информеров.
Информер в общем случае - это некий содержащий информацию объект (графическое изображение, текст или их сочетание), который предоставляется владельцем того или иного Интернет-ресурса всем желающим для встраивания в создаваемые ими web-страницы. При этом при загрузке web-страницы, содержащей информер, сам информер загружается с ресурса, его предоставившего. Обновления и изменения информера - прерогатива его владельца: от web-мастеров, встроивших информер в свои web-страницы, никаких усилий по обновлению данных, поставляемых через информер, не требуется.
В настоящее время в Интернете есть немало сайтов, предоставляющих информеры. Ниже рассказано о некоторых из них (рассмотрена только русская часть Сети).


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

МИР ИНФОРМЕРОВ

Самый крупный сайт, фактически посвященный информерам и только информерам - это, по моему мнению, созданный при покровительстве компании "Росбизнесконсалтинг" сайт www.informer.ru (рис. П. 1.1).

Рис. П. 1.1. Мир информеров - каждому web-мастеру

Количество информеров на этом сайте весьма велико. Практически каждый web-мастер найдет себе что-нибудь по вкусу. Практически все информеры - графические, т. е. представляют собой рисунок в формате Gif (встраивание такового на страницу производится простым помещением на нее тэга <img згс="адрес информера">), однако есть и основанные на Javascript, и просто текстовые. Коллекция www.informer.ru состоит не только из произведений разработчиков этого сайта, но в ней представлены ведений разработчиков этого сайта, но в ней представлены и предоставляемые другими сайтами аналогичные ресурсы.
К примеру, вы хотите, чтобы ваши посетители при каждом заходе на ваш сайт могли познакомиться с прогнозом погоды? Выберите один или два из целых пятнадцати и установите! Наиболее приглянувшиеся мне информеры я привожу на рис. П. 1.2. Или, скажем, вы желаете дать посетителям возможность при каждом заходе на вашу страничку узнавать курс доллара. В чём же дело? Поставьте на ней парочку соответствующих картинок (рис. П. 1.3). Есть и информеры с графическим изображением колебания курса, и с данными о курсах множества других валют, не только доллара (рис. П. 1.4).

Рис. П. 1.2. Погода - к вашим услугам. Вернее, к услугам ваших посетителей

Рис. П. 1.3. Информеры курсов валют. Выбирай на вкус

Рис. П. 1.4. Можно выбрать, например, такой..

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

Рис. П. 1.5. Все, что от вас требуется - ваш адрес электронной почты

После нажатия кнопки отправки данных формы введенная в нее информация попадет в базу данных www.informer.ru, и спустя некоторое время вам на указанный вами в форме адрес придет письмо с кодом заказанного вами информера, который уже и следует вставлять в web-страницы вашего сайта. Информеры предоставляются абсолютно бесплатно. Единственное, что требуют создатели http://www.informer.ru взамен, так это включение ссылки на их сайт в страницу вашего сайта. Эта ссылка уже включена в высылаемые коды информеров. Надеюсь, вы не откажете им в маленькой любезности и не станете ее оттуда удалять?
Как вам, например, телепрограмма по всем каналам на текущий день или афиша театров (рис. П. 1.6)? Если вы считаете, что вашим посетителям это будет интересно - зайдите в раздел "Рекомендуемое". Или, может быть, вас соблазнит "Конвертор валют", предлагаемый в том же разделе? Представьте, как будет приятно зайти на ваш сайт: и телепрограмму узнать можно, и сумму из долларов в рубли перевести, не говоря уже об информации о погоде. Не ровен час, посетители станут ваш сайт в качестве домашней страницы своих браузеров ставить. А уж если вы им и новости предлагать станете (рис. П. 1.7, раздел так и называется - "Новости"), то, наверное, довольно скоро по посещаемости обгоните всех своих конкурентов.

Рис. П. 1.6. А как вам вот такие информеры?

Рис. П.1.7. Новостной портал - за пять минут... Не рекламный лозунг - реальность

Информеры, содержащие текст или представляющие из себя форму с выпадающими меню (новостные ленты или, например, ТВ-информер на рис. П. 1.5), в подавляющей своей массе реализованы на Javascript. Изменять предоставляемый код формально не запрещено (обязательно лишь сохранять наличие в нем ссылки на сайт www.informer.ru), однако будьте максимально внимательны, работая таким образом с инфор-мерами на Javascript. Проверить их работоспособность можно лишь дав им возможность загружать данные с удаленного сервера, так что обязательно протестируйте полученный результат, подключившись к Интернету.
О сокровищах, скрытых в недрах сайта www.informer.ru, можно говорить еще долго. Но, надеюсь, вы сами, зайдя на этот сайт, сможете исследовать его коллекцию. Вряд ли вы уйдете оттуда без "подарков". А мы двинемся дальше по просторам Сети.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

С МИРУ ПО НИТКЕ

Сайт www.translate.ru предлагает вам уникальную услугу - возможность перевода вашей страницы на английский, немецкий или французский языки (рис. П. 1.8). Если на сайт, где установлен инфор-мер от www.translate.ru, зайдет не знающий русского языка посетитель, то он, указав свой язык в соответствующем поле информера, сможет посмотреть перевод текущей страницы на этот самый язык. Прибегнув к услугам www.translate.ru, вам не придется поддерживать несколько разноязычных версий сайта в расчете на возможные визиты иностранных посетителей. Достаточно лишь информера. Конечно, качество перевода будет не слишком высоким, но для понимания содержания страницы хватит.

Рис. П. 1.8. Ваша страница - на языках мира

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

Рис. П. 1.9. Онлайновый переводчик - для вашего сайта

На сайте http://www.finam.ru вы найдете информеры со сведениями о котировках акций крупных российских компаний (рис. П. 1.10). Если ваш сайт содержит информацию, посвященную экономическим наукам или предназначенную для тех, кто связан с куплей-продажей акций, то информеры от Finam.ru вполне могут их заинтересовать.

Рис. П. 1.10. Финансовая информация - как из первых рук

Котировками валют и акций может вас снабжать и сайт http://www.prologia.ru. Среди выдаваемых им сведений есть и текущие цены на нефть. Даже если среди посетителей вашей странички нет менеджеров и бизнесменов, занимающихся торговлей нефтью, то все равно информер такого рода будет придавать сайту имидж солидного и серьезного.
Сайт www.softbox.ru предлагает владельцам сайтов установить на своих страницах информеры, сообщающие посетителям о новых поступлениях на www.softbox.ru или отображающие список программ, признанных лучшими. Если ваш сайт посвящен обзорам программного обеспечения, то этот бесплатный информер его однозначно украсит.
Посетители, пожелавшие узнать о новостях мира программ, вполне могут начать приходить именно к вам - особенно если вы дадите им и сведения о погоде или свежих новостях.
Хотите свежий анекдот? Наверное... А ваши посетители тоже хотят. И вы вполне можете исполнить это желание, даже не помня ни одного не только анекдота, но даже и сколь-нибудь смешного афоризма. Просто зайдите на http://sporu.net/insert и скопируйте оттуда код информера, помещающего на страницу анекдоты. Анекдот посетителю выдается новый при каждом заходе, так что вполне можно ожидать, что он неоднократно перезагрузит страницу, на которой "анекдотный" информер расположен, подарив тем самым вашему сайту лишние "хиты" на счетчиках и показы баннеров (если таковые есть на странице с информером). Анекдот от http://sporu.net/insert может размещаться на странице как средствами Javascript, так и с помощью технологии CGI.
Информеры с анекдотами предоставляют и другие сайты - например, www.relax.ru. Кстати, последний присутствует и в коллекции http://www.informer.ru.
"Кулинарный информер", получить код для установки которого можно на сайте http://homejungle.km.ru/Cook/Cook_inf.htm, выдает на каждый день свой рецепт какого-нибудь блюда (рис. П.1.11). Для сайтов о домашнем хозяйстве - настоящая находка! Поставляемый информером (с помощью сценария на Javascript) фрагмент текста с рецептом может быть размещен в любом месте страницы и примет форму той ее части, куда он поставлен (т. е. станет такой же ширины, какой и она).
Знаете ли вы, кто из ваших знакомых сегодня именинник? А у кого из знаменитостей нынче день рождения? Если нет, то вам наверняка будет весьма приятно зайти на сайт, на котором есть информер от http://www.prazdniki.ru. А если приятно вам - то будет приятно и посетителям! Так что повод для посещения страницы http://www.prazdniki.ru/export уже есть. Тем более что информер от http://www.prazdniki.ru не просто бесплатный - в ответ на ваше размещение их информера у себя они еще и добавят ваш сайт в свой каталог на почетное место!

Рис. П. 1.11. Рецепт дня - подарок хорошим женам

А не желаете ли вы, чтобы на вашем сайте находился лунный календарь для выращивания растений в согласии с ритмом звезд? Если желаете, зайдите на http://flowers.nm.ru/pick/index.html. Каждый месяц специально для вас будет готовиться календарик с пометками о благоприятных и неблагоприятных днях этого месяца (рис. П. 1.12). Чем не украшение для сайта о домашнем хозяйстве или комнатных растениях?

Рис. П. 1.12. Лунный календарь. И не надо покупать газету...

Рис. П. 1.13. Сайт карикатур. Хотите такую же себе?

На сайте www.glasbergen.ru (рис. П. 1.13) представлены карикатуры американского юмориста Рэнди Гласбергена с русским переводом, выполненным известным журналистом и специалистом в языкознании Александром Петроченковым. Владелец ресурса разрешает web-мастерам размещать на своих сайтах "карикатуру дня" со своего сайта - каждый день новую (она также отображается на главной странице сайта - см.рис. П. 1.13), вместе с переводом ее текстов на русский язык. Выбрать способ размещения информера - на Javascript или РНР - а также получить код для его размещения на своем сайте можно на специальной странице (рис. П. 1.14).

Рис. П. 1.14. Тогда просто скопируйте и вставьте нужный код

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


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

РАБОЧИЙ СТОЛ СОВРЕМЕННОГО ЧЕЛОВЕКА

Но даже если на вашем попечении нет ни одного сайта, то инфор-меры все равно могут вам пригодиться. Они ведь несут весьма полезную информацию, не так ли? Так соберите со всех возможных мест их коды и создайте одну страницу, на которую все эти коды вставьте. После этого вы сможете получать все сведения, какие желаете, просто открыв эту страницу - даже не вводя в браузер никаких адресов и не нажимая на какие-либо ссылки. Запустили браузер - и вот вам погода с новостями.
А если хотите, можно сделать так, что ничего и открывать не придется. В новых версиях Windows (хотя каких уж "новых" - всех, начиная с 98-й) есть возможность в качестве фона Рабочего стола использовать web-страницу - перейти в режим так называемого "Активного Рабочего стола" (Active Desktop). Этой функцией мало кто пользуется, потому она и малоизвестна, но если в качестве подложки под Рабочий стол назначить страницу с информерами, то Рабочий стол превратится в полноценный информационный центр: и погода, и курс валют, и переводчик, и список именинников, и свежий анекдот, и даже цены на компьютерные комплектующие будут у вас просто перед глазами. Вам не надо будет даже куда-либо заходить и на что-либо нажимать -достаточно лишь посмотреть на Рабочий стол, чтобы узнать все самое свежее.
Посмотрите, например, на рис. П. 1.15. Работать за таким Столом -одно удовольствие. Как будто находишься едва ли не в центре мира. Захотелось поднять настроение - гляди вправо и вниз, пора идти на улицу - скоси взгляд к середине, познакомься с погодой. А подумайте, сколько вы времени сэкономите, заменив блуждание по Сети в поисках информации одним взглядом на Рабочий стол... Тем более что и обновляться информеры на нем могут автоматически.

Рис. П. 1.15. Рабочий стол современного человека. Почувствуйте себя в центре событий

Для того чтобы ваш Рабочий стол обрел такое же великолепие, как и показанный на рис. П. 1.15, сделайте следующее. Для начала составьте web-страницу размером с него, на которую и вставьте выбранные вами для размещения на Рабочем столе информеры. Помните, что на эту страницу вы будете смотреть каждый день долго и тщательно, так что уделите ее эргономике и красоте максимум внимания. Затем помещайте страницу на какое-либо постоянное место и, открыв вкладку "Фон" диалогового окна "Свойства экрана", нажмите кнопку "Обзор" (рис. П.1.16). В качестве типа файлов в открывшемся окне установите "Документы HTML" и откройте созданную вами страницу. При ее открытии вам будет предложено включить Active Desktop, если до этого данный режим был выключен, - то, естественно, соглашайтесь. Ну а затем нажимайте Ok - и ваш Рабочий стол волшебно преобразится.

Рис. П. 1.16. Установите здесь страницу с информерами -и вы получите "Рабочий стол современного человека"

Однако в полной мере насладиться возможностями информеров можно лишь при постоянном подключении к Интернету. Если вы используете модемный доступ, то с обновлением информеров может возникнуть проблема, да и для запуска переводчика или антивируса (см. рис. П. 1.15) придется дозваниваться и подключаться. Поэтому в таком случае вам все же лучше ограничиться простой страницей с информерами, не экспериментируя с Активным Рабочим столом. Но постоянное подключение к Сети довольно быстро движется в массы и может статься, что вышеизложенная рекомендация данной статьи станет вам доступна для реализации довольно скоро.
Казалось бы, такая малозаметная деталь Сети - информеры... Но сколько они могут принести пользы - и вам, и посетителям вашего сайта. Не допускайте, чтобы труд их создателей пропадал даром, используйте возможности Интернета на полную мощность!


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ
ПРИЛОЖЕНИЕ 2. ИСПОЛЬЗУЙ ТО, ЧТО ПОД РУКОЮ - И НЕ ИЩИ ВСЕГДА ДРУГОЕ
  • Используй то, что под рукою - и не ищи всегда другое
  • Конвертация текстов
  • "Вытаскивание рисунков"
  • Web-графика - быстро и удобно
  • Неподвластный влияниям


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ИСПОЛЬЗУЙ ТО, ЧТО ПОД РУКОЮ - И НЕ ИЩИ ВСЕГДА ДРУГОЕ

Практически всем известны встроенные в Microsoft Word всех версий, начиная с 97-й, конверторы документов в HTML-формат. И уже притчей во языцех стало качество генерируемого ими web-кода, в который все они добавляют множество ненужной информации. В самом деле - html-документ, созданный в Word97, едва ли не затопляется тэгами <font>, a web-страницы, являющиеся произведениями последующих версий Office, в целях достижения возможности сохранения абсолютно всех доступных в Word параметров документа построены на особом языке, отличительной особенностью которого является крайняя громоздкость и трудность редактирования (рис. П.2.1).

Рис. П.2.1. Слева - код документа HTML, созданного в Word 97. Справа - код документа HTML, созданного в Word

Примечание:
Вызвать конвертор HTML из Word97можно, выбрав изменю "Файл" команду "Сохранить в формате HTML" (будет там, лишь если конвертор установлен), а в Word 2000/XP - вызвав оттуда же команду "Сохранить как web-страницу". Ненужный диалог о выборе кодировки будущей web-страницы при работе с конвертором HTML из Word97 можно отключить, установив в системном реестре строковый параметр "HKEY_LOCAL_MACHlNEsSofiware\MicrosojbShared Tools\TextConverters\ Export\HTML\Options\ShowEncodingDialog" как "No" (рис.П.2.2).

Рис. П.2.2. Диалог о кодировке web-страницы в Word97 отключается здесь

Однако html-конверторы Microsoft Word могут сослужить весьма неплохую службу web-мастеру - если использовать их не по прямому назначению (вернее, по "не совсем прямому"). Как? Читайте ниже.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

КОНВЕРТАЦИЯ ТЕКСТОВ

Если вам необходимо быстро отконвертировать большой обьем текста в формат HTML, Microsoft Word 97 для этого - идеальное средство. Даже если исходно информация подготавливалась в каком-либо другом редакторе, то для помещения текста в Web достаточно сохранить его в формате Rtf, а потом открыть полученный файл в Word и конвертировать в HTML. Все таблицы, содержавшиеся в исходном документе, тоже будут отконвертированы в HTML.
Однако полученный код окажется весьма громоздким - html-конвертор Word97 вставит в него множество лишних тэгов. Поэтому его придется дорабатывать. Для этого его нужно открыть в любом текстовом редакторе, поддерживающем функцию замены (весьма хорошим выбором будет Microsoft Word 6.0, поставленный поверх Word 97 в другой каталог, однако можно использовать и режим "Вид" - "Источник HTML" в самом Word 97), и удалить все тэги <font... >, </font>, &#9; (символ табуляции), все лишние ссылки и строчки, а затем немного подредактировать (добавив вручную пару-тройку гиперссылок в начало, в конец текста, установив желаемый шрифт и параметры фона). Если для редактирования полученного web-документа использовать Microsoft Word 6.0 или Microsoft Word 97 в режиме просмотра источника HTML, то имеет смысл все операции замены записать в макрокоманду и впоследствии применять ее для обработки всех отконвертированных файлов.
К сожалению, код, выдаваемый html-конвертором из Word2000/XP, ручной коррекции практически не поддается, поэтому при установке этих новых версий Office предыдущую, 97-ю версию желательно сохранить, задав при инсталляции соответствующую опцию. Но зато со храненная посредством html-конвертора из Word2000/XP почти полностью сохраняет свое форматирование (однако отобразить ее с сохранением оформления сможет лишь браузер Microsoft Internet Explorer версией не ниже четвертой), что может иногда потребоваться при необходимости размещения в Сети сложнооформленного документа. Впрочем, в HTML-конверторе Word2000 и WordXP есть функция сохранения документа "как web-страницы с фильтром", при использовании которой в создаваемый web-документ не включаются многие параметры форматирования исходного текста, в результате чего web-страница получается меньшего размера, а ее исходный код становится по крайней мере читаемым.

Комментарий:
Если имеется желание оформить документ так же, как и текст на листе бумаги (т. е. без расстояния между абзацами и с отступами красных строк), то стоит заменить все границы однотипных по выравниванию абзацев конструкциями типа < br > &nbsp;&nbsp;&nbsp;, a также добавить символы &nbsp;&nbsp;&nbsp; (попросту пробелы) в начало каждого абзаца, за исключением центрированных заголовков.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

"ВЫТАСКИВАНИЕ РИСУНКОВ"

Еще одна полезная функция HTML-конвертора Word - это "вытаскивание" рисунков из документов. Вопрос о переводе рисунка, внедренного в Word, в формат Gif или Jpeg иногда встает очень остро. Простое копирование рисунка в MS Paint, Photo Editor, Adobe Photoshop через буфер обмена к хорошему результату не приведет -качество изображения будет очень плохим. Многие издательства вследствие этого не принимают к публикации файлы Word с внедренными рисунками, если у них используются для верстки другие программы. Однако "вытащить" рисунки из документа Word элементарно просто - нужно всего лишь сохранить его в формате HTML (подойдет Word любой версии). При этом все внедренные графические объекты окажутся сохраненными в формате Gif или Jpeg в той же папке, что и полученный web-документ.
HTML-конвертор Word 97 сохраняет изображения очень аккуратно. Он самостоятельно выбирает формат - Gif или Jpeg - для каждого рисунка, исходя из соотношения между размером и качеством будущего файла. Само сохранение происходит крайне корректно и экономно. Если один и тот же bmp-файл отконвертировать в Jpeg-формат с помощью графического редактора, например, ACDSee, или вставить в документ Word, сохранить тот в формате HTML и сравнить размеры полученных файлов с рисунками (качество будет одинаковым), то разница может достигать даже пары десятков процентов раз в пользу HTML-конвертора Word. Таким образом, этот конвертор можно считать на настоящее время еще и наиболее эффективным средством для конвертации графических изображений в форматы Gif или Jpeg.

Рис. П.2.3. Вытащить из Word рисунки, да еще и с определенным разрешением? Достаточно одного нажатия мыши...

В Word2000/XP есть возможность указать разрешение рисунков в получаемом с помощью html-конвертора документе. Делается это в диалоговом окне сохранения файла, в меню "Сервис" (рис. П.2.3). Воспользуйтесь этой функцией, если Вам нужна графика в определенном разрешении (это, например, иногда требуется в некоторых издательствах и редакциях). Кроме того, помимо форматов Gif и Jpeg, при сохранении документа в формате HTML в Word2000/XP может использоваться еще и Png (при установке соответствующей опции в параметрах web-документа, окно которых доступно из меню "Сервис" диалогового окна сохранения файла, см.рис. П.2.3).


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

WEB-ГРАФИКА - БЫСТРО И УДОБНО

С помощью html-конверторов Word можно быстро и легко создавать довольно сложные графические объекты для вставки на web-страницы, например, диаграммы и формулы. В результате для того, чтобы поместить на web-страницу график или алгебраическое выражение, не придется осваивать сложные графические редакторы или возиться со сканером. Достаточно будет, подготовив график или изображение соответственно в Microsoft Graph и Microsoft Equation Editor, вставить в документ Word и сохранить его в формате HTML, чтобы все такие обьекты превратились в файлы Gif или Jpeg.
При разработке несложной графики для размещения в Web, например, блок-схем, Word тоже может оказать неоценимую помощь, предоставив пользователю богатые возможности по рисованию с помощью автофигур. Сделать сложнотекстурную заливку фигуры (установив ей соответствующие свойства) тоже труда не составит, а при сохранении документа с рисунками из автофигур в формате HTML эти рисунки превратятся в файлы Gif или Jpeg (рис.П.2.4). Однако имейте в виду, что так происходит только в двух последних версиях Office -HTML-конвертором Word 97 автофигуры не обрабатываются и при сохранении документа игнорируются. Поэтому в том случае, если вы работаете именно с этой версией редактора, то не забудьте перед сохранением файла, содержащего картинки из автофигур, каждую из этих картинок сгруппировать и, вырезав в буфер обмена, вставить на свое же место с помощью команды "Правка - Специальная вставка" как "Рисунок Wmf'.
Вставив в документ объект WordArt и сохранив его в формате HTML, можно без всяких Photoshop'oB получить красивый заголовок для web-страницы или просто узорчатый текст в графическом файле (рис. П.2.5). (При работе с Word97 следует перед конвертацией сделать то же, что и с автофигурами, т. е. вырезать и вставить "Специальной вставкой". Html-конвертор этой версии Word объекты WordArt игнорирует.)
Грамотно используя возможности Word по созданию графических объектов вкупе с его html-конвертором, вы сможете очень часто при создании графики для Web не прибегать к услугам специализированных графических редакторов.

Рис. П.2.4. Превратить такие схемы в картинки.Gif или Jpeg - задача по плечу
лишь для Word

Рис. П 2.5. Надо сделать красивый заголовок? Достаточно Word97


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

НЕПОДВЛАСТНЫЙ ВЛИЯНИЯМ...

В Word 2000 и WordXP документ можно сохранить в виде "web-архива" (с расширением .mht или .mthml, рис. П.2.6), т. е. одного файла, в который включаются как текст документа, так и все рисунки и таблицы стилей. Внутренняя структура такого файла построена на основе стандарта MIME. Web-архив может просматриваться через браузер Microsoft Internet Explorer версии не ниже 4.0.
Представляется весьма интересным использование web-архива в качестве замены стандартному типу файлов .doc, используемому в Word для сохранения документов по умолчанию. В самом деле, при полном сохранении оформления текста web-архив весьма устойчив к повреждениям, так как фактически представляет собой HTML-документ с фрагментами, закодированными base64 или uuencode (повреждение хотя бы одного байта в обычном документе Word почти всегда приведет к полной нечитаемости файла, а изменение даже нескольких десятков байт в HTML-документе в самом крайнем случае приведет к нечитаемости лишь этих поврежденных байт), а, кроме того, может быть просмотрен даже в том случае, если у пользователя не установлен ни Word, ни какой-либо другой просмотрщик .doc-файлов, в Microsoft Internet Explorer'e (правда, сложноструктурированные документы могут отображаться в браузере немного некорректно).
Таким образом, можно будет обеспечить как надежность хранения информации, так и ее легкую переносимость. Вам не надо будет заботиться, есть ли у того, кому вы отправляете файл, Microsoft Word для его чтения. Однако необходимость постоянной конвертации web-архива при его открытии и сохранениях может вызвать замедление работы Word, что, впрочем, на современных компьютерах не очень существенно.

Рис. П.2.6. Web-архив: Надежность. Совместимость. Компактность

Так что, как видите, старый добрый Word сгодится не только для набора текстов. В умелых руках web-мастера он иной раз может творить буквально чудеса. Не стоит забывать об его возможностях.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ПРИЛОЖЕНИЕ 3. НА САЙТЕ - КАК В "ВИНДЕ"

Один из основных законов так называемого "usability", т. е. принципов создания удобных вещей гласит, что интерфейс объекта, с которым работает человек, должен быть ему знакомым. В применении к web-сайтам принцип сохраняется - зайдя на web-страницу, посетитель не должен гадать и думать, для чего предназначен тот или иной ее элемент. Достигнуть этого можно с помощью похожести интерфейса web-страницы на какой-нибудь другой, уже привычный пользователю. Например, на интерфейс операционной системы.
Первый, банальный прием напрашивается сразу. Можно поставить в качестве ссылок такие же иконки файлов, как и соответствующие их формату в интерфейсе операционной системы, например, всем знакомое изображение сжатых струбциной ящиков от стола для архива формата Zip или картинка листа бумаги с эмблемой Word'a для документов Word. Тогда посетитель, зайдя на страницу, сразу увидит знакомые значки и ему будет проще ориентироваться на ней, так как то, что предназначено для загрузки с сайта, будет видно сразу (рис. П.3.1).

Рис. П.3.1. Сразу ясно, что надо скачивать...

Однако просто использовать в качестве ссылок иконки архивов -это банально и неинтересно... Полной идентичности с интерфейсом операционной системы достигнуть нельзя, да и незачем, так как при работе с браузерами пользователи уже давно привыкли к одинарному щелчку для доступа к данным, а не к двойному.
Однако все, работающие с Windows 98 и более старшими версиями этой операционной системы, помнят о возможности настроить вид папок так, что при наведении курсора иконка файла будет затеняться, а при нажатии в этот момент левой кнопки мыши файл откроется (рис. П.3.2). Так, может быть, сделать иконки файлов, предназначенных для загрузки, такими же затемняющимися, как и в Windows? Представьте себе - навел посетитель курсор мыши на значок, а он стал темным, увел - он стал обычным.

Рис. П.3.2. Затенение иконки под курсором

Так почему бы не реализовать такой же эффект на web-странице, содержащей ссылки на архивы или другие файлы, подлежащие загрузке или открытию?
Но как это сделать?
Можно, разумеется, использовать традиционный метод - использовать два варианта значка (обычный и затемненный) и с помощью небольшого скрипта организовать их замену друг на друга при наведении и уходе курсора мыши. Однако такое устройство страницы приведет к тому, что на страницу придется поместить еще и сценарий для предварительной загрузки картинок (иначе соответствующие варианты значков будут загружаться лишь при наведении мыши, т. е. - не сразу). Кроме того, при сохранении web-страницы на локальном диске посетителя иконки, загружаемые в сценариях, не копируются на жесткий диск, и в итоге во время работы пользователя с сохраненной страницей при наведении курсора мыши иконки будут заменяться на белые "дырки", что, естественно, не может считаться удачным решением.
Однако для достижения требуемого эффекта вполне можно обойтись и одним изображением, если использовать так называемые "фильтры" - воспринимаемые браузером команды, позволяющие особым образом преобразовать изображение или текст, к которым они применяются.
Если вы пожелаете использовать на web-странице фильтры для достижения эффекта затемнения иконок при наведении на них курсора, то в начало страницы, в раздел <head> следует добавить небольшой скрипт, разобранный ниже по строчкам. Синтаксис Javascript во многом похож на синтаксис РНР, так что изучение данного сценария вряд ли станет для вас проблемой.
Начало сценария:

<script language="JavaScriptl. 2">

Для экономии места используется одна функция, которой сообщается имя графического объекта на web-странице, на котором используется затемнение, и требуемое действие - либо применение этого затемнения, либо его отмена.

function g (c,w)
{

Если нужно "затемнить" картинку:

if (w==0)

применяем фильтр "light", который окрашивает картинку в определенный цвет...

с.style.filter="light";

и задаем в качестве затемняющего цвета - темно-синий оттенок. Эта команда используется лишь в том случае, когда браузер может работать с фильтрами - именно поэтому она помещена после оператора if, проверяющего, существует ли для браузера фильтр light.

if (с.filters.light) {
c.filters.light.addAmbient(130,130,210,120) }

Ну а если нужно, наоборот, вернуть картинке первоначальный вид, то просто отменяем все фильтры.

else
с.style.filter=0
}

Вот и все:

}
</script>

Вышеописанный сценарий будет "обслуживать" все картинки на странице, для которых вы пожелаете применить эффект "затемнения". Ну а чтобы это происходило - в тэг каждой картинки, для которой требуется "затемнение", следует вставить команды
"onMouseover="g (this,0)" onMouseout="g (this,1)", например:

<IMG src="z.gif" border=0 height=30 width=30 on-Mouseover="g(this,0)" onMouseout="g(this,1)">

В результате при наведении курсора мыши на картинку она будет затемняться - как на рис. П.3.3.

Рис. П.3.3. Затемнение иконки под курсором. Но уже на сайте, а не на Рабочем столе

К сожалению, данный прием работает только в браузере Microsoft Internet Explorer версии 5.0 и старше. Пользователи же остальных браузеров увидят простую непереливающуюся картинку и ничего больше.
Примеры сценария, а также иконки архивов вы можете взять с адресов http://www.harchikov.ru, http://antorlov.chat.ru, http://karamur2a.chat.ru. Просто копируйте картинки и переписывайте сценарий из "Источника HTML", а затем размещайте на своем сайте.


УЧЕБНИКИ
ПРОФЕССИОНАЛОВ

ВВЕДЕНИЕ

Когда-то давно, еще в прошлом веке, для того чтобы сделать сайт "на мировом уровне", достаточно было просто уметь делать web-страницы на HTML и обладать художественным вкусом. Спустя некоторое время требования усложнились: использование JavaScript и Dynamic HTML стало рутинным и дизайн сайта, не имеющего подобных "украшений", считался устаревшим. Ещё по прошествии небольшого времени правилом "хорошего тона" для корпоративного сайта стало применение сложных программ на Perl или C++, а создавать такие сайты стало по силам, пожалуй, лишь коллективам дизайнерских студий.
Однако простые web-дизайнеры не желали мириться с такой ситуацией, и ответом на их пожелания стало появление РНР - языка программирования, обладающего возможностями сложных скриптовых языков, но в то же время удивительно простого и легкого в изучении и применении. РНР расшифровывается как "PHP: Hypertext Preprocessor" (в названии используется такой прием, как рекурсия: наличествующая в расшифровке аббревиатура "РНР" вновь может быть расшифрована как "РНР: Hypertext Preprocessor" - и так до бесконечности). Этот язык благодаря своей простоте и мощности быстро завоевал огромную популярность среди web-мастеров, и количество сайтов, использующих РНР, увеличивается с каждым днем. Немаловажно и то, что он бесплатен для использования всеми желающими.
В этой небольшой книге будет рассказано о том, как использовать. РНР для того, чтобы сделать сайт функциональным и удобным, чтобы предоставить его посетителям (да и самому web-мастеру) новые возможности по работе с информацией на сайте. Основной упор в изложении сделан именно на практическое применение - после кратких сведений о синтаксисе и основных командах РНР в брошюре приводятся тексты реальных работающих сценариев, каждый из которых вполне может пригодиться практически на любом сайте. При этом в сценариях комментируется и разбирается каждая строчка кода, что позволяет использовать их тексты еще и в обучающих целях, для изучения структуры языка и принципов написания программ на нем.
Книгу отнюдь не обязательно читать подряд. Если вы интересуетесь основами РНР, то вам следует ознакомиться с третьей главой. Если же вас интересует тот или иной сценарий - то сразу переходите к описывающей его главе. Поскольку книга предназначена не столько
для обучения, сколько для непосредственного практического применения, то нужные сведения по синтаксису команд РНР даются в главах по мере необходимости - в зависимости от их использования в рассматриваемом сценарии.