Управление передачей HTTP-заголовков
Установка «плюшек»: setcookie
Взаимодействие с сервером WWW
Загрузка файлов на сервер
Работа с удаленными файлами
Управление соединениями
Аутентификация пользователей
В этой небольшой главе мы рассмотрим, как PHP-программа может заниматься
«не своим делом», а именно корректировать по своему усмотрению работу HTTP-протокола. В самом деле, в подавляющем большинстве случаев с задачей пересылки страниц пользователю успешно справляется WWW-сервер.
Но иногда, при решении особо изощренных задач, вам может потребоваться заняться регулированием трафика самостоятельно. А поскольку работа HTTP-протокола фактически определяется содержимым специальных пакетов — «заголовков» (headers), которыми обмениваются сервер и программа-клиент, то и вашей
PHP-программе фактически необходимо только вовремя подсуетиться и отправить «правильный» заголовок. Для этого необходимо воспользоваться специальными функциями, рассматриваемыми в разделе 15.1. Вторая точка воздействия на
поведение системы — это клиентская программа-навигатор, на которой с помощью
механизма «плюшек» можно организовать хранение личной информации пользователя с последующей автоматической загрузкой в PHP-программу. Этот вопрос
мы подробно рассмотрим в разделе 15.2. И наконец, нам осталось только пристально
взглянуть на сам WWW-сервер. В разделе 15.3 мы разберемся, как РНР-машина
может взаимодействовать с некоторыми функциями популярного сервера Apache,
а также как организовать загрузку файлов с машины клиента на сервер (раздел
15.4) и как работать с удаленными файлами (раздел 15.5).
Для работы с заголовками HTTP-протокола в РНР предусмотрено всего две функции, которых оказывается вполне достаточно для эффективной работы.
15.1.1. Отправка заголовка клиенту: header
int header (string string)
Функция header () используется до начала генерации собственно HTML-файла,
вмешиваясь в переговоры между сервером WWW и программой клиента.
Подробное описание заголовков, которыми вы можете манипулировать, вы найдете в спецификации HTTP 1.1, доступной по адресу www.w3.org.
Стоит отметить, что часто в PHP-программах используется два несколько необычных заголовка. Первый из них — это заголовок Location. Его особенность заключается в том, что он не только отправляется программе-клиенту, но также автоматически возвращает WWW-серверу код состояния REDIRECT. Вот как он обычно
используется:
header ("Location: http://come.to/vodol.az");
// Перенаправляем пользователя на мою страничку
exit;
// И сразу же завершаем работу, чтобы больше никаких данных от
// сервера не поступало, пока мы переходим на другую страницу.
Второй «особый случай» — это семейство заголовков, которые начинаются со строки HTTP/. Например, если ваша PHP-программа машины поиска должна сформировать сообщение об отсутствии запрошенной пользователем страницы, это про-
ще всего реализовать с помощью стандартного кода завершения — хорошо известной вам ошибки 404. Поэтому вам достаточно поместить в программу до начала
генерации какого-либо HTML-кода следующую строку:
header ("HTTP/1.0 404 Not Found");
В тех случаях, когда вы интенсивно используете РНР для генерации динамического HTML, вам может потребоваться принудительно отключить кэширование
на стороне клиента или в промежуточных прокси-серверах. Здесь вам на помощь
могут прийти следующие заголовки:
// Принудительное установление уже прошедшей даты,
// что заставляет прокси-сервер или клиентскую программу
// обновлять страницу
header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
// Принудительное отключение кэширования
header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header ("Pragma: no-cache"); // HTTP/1.0
Очень важно помнить, что функция header () должна вызываться до того, как вы
начнете генерировать HTML-код, пусть даже это будут ничего не значащие пробелы. В противном случае отправленные вами заголовки будут просто проигнорированы. Одна из весьма распространенных ошибок в PHP-программировании заключается во включении внешнего файла с помощью include() (см. раздел 6.12)
или requi re() (см. раздел 6.11), которые по каким-либо тайным мотивам разработчиков содержат операторы, выводящие в выходной поток пробелы или пустые
строки до того, как вы производите вызов функции header (). Так что будьте бдительны и не ленитесь анализировать исходный текст сгенерированного HTML-файла.
Вот пример возникновения подобной ошибки:
<?php require("user_logging.inc") ?>
<?php header ("Content-Type: audio/x-pn-realaudio"); ?>
// Все правильно, но почти... Обратите внимание на две пустые
// строки. Они ведь введены в HTML-контексте!
15.1.2. Проверка отправки заголовков: headers_sent
bool headers_sent ()
Эта функция достаточно проста. Она возвращает true, если все заголовки, касающиеся текущей страницы, уже были отправлены и вы можете только генерировать
HTML-код, и false, если поезд еще не ушел.
Сразу же отметим, что РНР достаточно естественным образом поддерживает механизм «плюшек», введенных в обиход компанией Netscape. «Плюшки» (Cookies)
представляют собой механизмы для сохранения информации на стороне клиента
см., например, [4]) и таким образом позволяют идентифицировать пользователей
распределенной Интернет/Интранет-системы или контролировать их работу. Для
установки значений «плюшек» в РНР предусмотрена специальная функция
setcookiе(). Поскольку «плюшки» представляют собой разновидность заголовков HTTP, вызов этой функции, как и функции header () (см. раздел 15.1.1), должен выполняться до начала генерации собственно HTML-кода.
Все «плюшки», отправляемые вам со стороны клиента, так же, как и переменные
форм ввода, автоматически преобразуются в переменные РНР. Если же вы хотите,
чтобы в одной «плюшке» вместо однородной начинки поместилась целая фруктовая смесь — просто добавьте к имени «плюшки» идентификатор массива [ ]:
int setcookie (string name [, string value
[, int expi re
[, string path
[, string domain [, int secure]]]]])
Функция setcookie() определяет параметры плюшки, которая должна быть отправлена клиенту вместе с другими заголовками. Помните, что отправлять плюшки следует до начала генерации HTML-кода. Это ограничение связано с особенностью реализации HTTP-протокола и не имеет прямого отношения к работе
РНР-машины.
Все аргументы функции, кроме имени плюшки, являются необязательными. Если
используется сокращенная форма вызова с одним единственным аргументом, то
плюшка с указанным именем будет попросту удалена с машины клиента. Аргументы expirensecure должны представлять собой целые числа, которые не могут замещаться пустыми строками, как любой из остальных аргументов. Аргумент
expire должен содержать стандартное представление времени в формат UNIX,
которое может быть получено с помощью функций time() (см. раздел 13.1.12) или
mktime() (см. раздел 13.1.10). Аргумент secure указывает, что передача данной
плюшки разрешена только по защищенному соединению HTTPS.
При работе с плюшками необходимо помнить о следующих особенностях их применения.
- Плюшки остаются невидимыми для PHP-программы до очередной загрузки страницы по запросу клиента, которому эта плюшка была оставлена.
- Удалять плюшки необходимо с тем же набором параметров, с которым вы их создавали.
Вообще-то, я стараюсь поменьше путать читателя упоминаниями о древней версии РНР 3 и сосредоточиться на описании именно РНР 4. Но вот работа с плюшками — этот как раз тот случай, когда необходимо упомянуть о важном различии
между версиями. Раньше, в РНР 3, все операции с плюшками помещались в своеобразный стек, а затем извлекались из него в обратном порядке, поэтому чтобы
удалить старую плюшку и установить новую, вам пришлось бы вначале ввести
новое значение, а потом удалить старое. Нет нужды доказывать, что это не способствовало повышению ясности кода и приводило к огромному количеству ошибок.
В новой версии РНР многократные обращения к функции setcookiе () выполняются без создания стека, что позволяет вам помещать вызовы функции естественным образом.
примечание
Точнее говоря, на смену стеку «первым вошел — вышел последним» пришла очередь «первым пришел — первым вышел».
Теперь давайте перейдем к примерам.
Вот несколько вариантов установки плюшек:
setcookie ( "TestCookie" , "Test Value");
// Эта плюшка проживет только час:
setcookie ("TestCookie", $value , time()+3600) ;
// Эта тоже проживет только час, но ее сфера применения
// к тому же, существенно более ограниченна:
setcookie ("TestCookie", $value , time()+3600,
"/~rasmus/", " . utoronto. ca" , 1);
А теперь посмотрите, что нам необходимо сделать, чтобы удалить установленные
в приведенном выше фрагменте плюшки:
setcookie ("TestCookie");
// Это подходит для простой плюшки
setcookie ("TestCookie", "", time() - 3600);
// Эту плюшку мы искусственно состарили
setcookie ("TestCookie", "", time() - 3600,
"/-rasmus/", ". utoronto. ca" , 1);
// И эту тоже, но нам необходимо указать все параметры,
// с которыми она была создана
совет
Удаляя плюшку, вы должны позаботиться о том, чтобы ее срок жизни заканчивался где-
нибудь в прошлом. Только в этом случае произойдет автоматическая активизация механизма удаления ненужных плюшек.
Следует иметь в виду, что значение плюшки при ее отправке автоматически кодируется и столь же автоматически декодируется при считывании. При этом в РНР-
программе создается переменная, имя которой совпадает с именем плюшки, поэтому чтобы увидеть и использовать содержимое установленных ранее плюшек,
вы можете использовать любую из приведенных ниже конструкций:
echo $TestCookie;
echo $HTTP_COOKIE_VARS["TestCookie"] ;
С тем же успехом вы можете создавать массивы плюшек, используя индексы массива с именами создаваемых плюшек. Фактически вы должны создать столько
плюшек, сколько элементов должен содержать создаваемый вами массив. Это может оказаться неудобным при создании плюшек, но при последующем их считывании вы действительно получите в свое распоряжение массив:
setcookie ( "cookie [three] ", "Три");
setcookie ("cookie[two] " , "Два");
setcookie ("cookie [one] ", "Раз");
if (isset ($cookie)) {
while (list ($name, $value) = each ($cookie)) {
echo "$name == $value \n" ;
Полную спецификацию плюшек можно найти на сервере Netscape по адресу: http:/
/www.netscape.com/newsref/std/cookie_spec.html.
|