PHP

advertisement
Задание 1. Установка и начальная настройка web-сервера Apache
1. Загрузите дистрибутив Apache из Интернет:
a. Откройте web-обозреватель и в адресной строке введите адрес
http://www.apache.org.
b. В открывшейся странице перейдите по ссылке HTTP Server.
c. Перейдите в раздел сайта Download.
d. Найдите в странице часть, относящуюся к версии программы 1.3.n (n –
«нижний» номер версии).
e. Выберите вариант Win32 Binary и нажмите на ссылку для загрузки файла
дистрибутива.
f. Выберите сохранение файла локально, в каталог C:\install\ (если такой
каталог не существует, создайте его). Сохраненный файл должен иметь
имя вида apache_1.3.n-win32-x86-no_src.exe, где вместо n – некоторое
число (номер версии).
2. Процесс установки:
a. Запустите инсталлятор.
b. Приветствие инсталлятора («Welcome…») – нажмите кнопку Next.
c. Подтвердите согласие с условиями лицензии («License Agreement») –
выберите вариант «I accepted terms…».
d. Окно с информацией о продукте («Read This First») - нажмите Next.
e. Ввод информации о сервере (поля «Network Domain», «Server Name» и
«Administrator’s Email Address») – в первые два поля следует ввести
значение «localhost», в третье – какой-либо (лучше, собственный) адрес email.
Все три введенные значения будут помещены в файл конфигурации
httpd.conf и могут быть позднее изменены. Второе поле задает значение
параметра ServerName, третье – параметра ServerAdmin, а первое
предназначено для задания имени домена, внутри которого располагается
данный сервер. Значение из первого поля будет использовано в качестве
атрибута для некоторых директив «Allow…».
Здесь же следует указать способ запуска web-сервера: в качестве сервиса –
автоматически при загрузке операционной системы («Run as a service»).
Другой вариант запуска – вручную.
f. Выбор варианта установки («Setup Type») – полная («complete») или
выборочная («custom»). Укажите вариант «полная».
g. Задание каталога для размещения файлов Apache («Destination Folder»).
Укажите путь C:\Apache\.
h. Для начала копирования файлов, в окне «Ready to Install» следует нажать
кнопку Install, а по окончании копирования – кнопку Finish.
3. Убедитесь, что Apache запущен в качестве сервиса Windows и работоспособен:
a. Нажмите кнопку Пуск на панели инструментов Windows.
b. Выберите пункт Панель управления.
c. В открывшемся окне выберите раздел Администрирование.
d. Выберите ярлык Службы.
1
e. Убедитесь, что в списке присутствует сервис с именем Apache и его
состояние – Работает.
f. Запустите web-броузер и введите в строке адреса значение
http://localhost. Должна открыться тестовая страница Apache:
4. Измените корневой каталог web-сервера.
Изначально корневым каталогом web-сервера является каталог
C:\Apache\htdocs\. Именно в нем размещается HTML-документ, который был
отображен броузером (см. выше).
a. Создайте каталог C:\webroot\.
b. Используя какой-либо текстовый редактор, откройте для редактирования
файл httpd.conf, находящийся в каталоге C:\Apache]conf\.
c. Найдите в файле директиву DocumentRoot, задающую имя корневого
каталога web-сервера и замените ее значение с C:/Apache/htdocs на
C:/webroot.
Обратите внимание, что при задании путей в файле конфигурации
следует использовать символ «прямой слэш» - /.
d. Измените также имя каталога в блоке, задающем свойства корневого
каталога. Найдите директиву <Directory "C:/Apache/htdocs">,
открывающую этот блок и замените имя каталога на C:/webroot.
e. Сохраните файл конфигурации.
f. Перезапустите Apache, чтобы изменения вступили в силу. Для этого
используйте окно сервисов (служб) Windows (см. выше).
Если сервис Apache будет остановлен, но не запустится снова, значит
при редактировании файла конфигурации были допущены ошибки.
g. Снова обратитесь в web-обозревателе к серверу http://localhost. При этом
должен отобразиться документ следующего вида:
2
Это означает, что в корневом каталоге web-сервера нет подходящего
документа для отображения, и web-сервер формирует документ,
содержащий список файлов корневого каталога (который пуст).
5. Создайте собственную страницу «по умолчанию» для корневого каталога webсервера.
a. Создайте в каталоге C:\webroot\ файл index.html следующего вида:
<html>
<body>
<h1>My first page</h1>
</body>
</html>
b. Снова обратитесь в web-обозревателе к серверу http://localhost. При этом
должен отобразиться созданный документ.
Задание 2. Установка и начальная настройка интерпретатора PHP
1. Загрузите архив с интерпретатором PHP из Интернет:
a. Откройте web-обозреватель и в адресной строке введите адрес
http://www.php.net.
b. В открывшейся странице перейдите по ссылке Downloads.
c. Найдите в странице часть, относящуюся к версии программы 4.4.n (n –
«нижний» номер версии).
d. Под заголовком Windows Binaries нажмите на ссылку PHP 4.4.n zip
package.
Дистрибутив PHP для Windows представлен в двух вариантах: архив и
инсталлятор. Инсталлятор имеет меньший объем, при этом он
предусматривает установку PHP только в режиме CGI, также в него не
входят модули расширения PHP. По этим причинам следует использовать
архив, содержащий более полную версию программы.
e. Из открывшегося списка выберите «зеркало» с которого следует загружать
файл архива.
f. Выберите сохранение файла локально, в каталог C:\install\ (если такой
каталог не существует, создайте его). Сохраненный файл должен иметь
имя вида php-4.4.n-Win32.zip, где вместо n – некоторое число (номер
версии).
2. Распакуйте архив и проверьте работоспособность интерпретатора:
3
a. Создайте каталог C:\php4\.
b. Извлеките содержимое загруженного файла в созданный каталог.
c. Создайте каталог C:\phpprog\, а в нем – файл test.php следующего вида:
<?php
print "Test!";
?>
d. Перейдите в созданный каталог и наберите в командной строке команду:
С:\php4\php.exe test.php
При этом в окне консоли должно появиться сообщение:
Content-type: text/html
X-Powered-By: PHP/4.4.0
Test!
Первые две строки, отделенные пустой строкой – поля HTTP-заголовков,
необходимые при работе под управлением web-сервера. При вызове
интерпретатора из командной строки вывод заголовка можно подавить
параметром –q:
С:\php4\php.exe –q test.php
В последней строке – собственно результат работы программы.
3. Создайте и настройте файл конфигурации PHP.
a. Скопируйте файл php.ini-dist (находящийся в каталоге C:\php4\) в каталог
размещения операционной системы Windows (C:\winnt\) под именем
php.ini.
Этот файл содержит настройки, более подходящие для процесса
разработки и отладки сайта. Для действующего сервера лучше брать за
основу файл php.ini-recommended.
b. Внесите необходимое исправление в файл конфигурации – найдите
директиву extension_dir и присвойте ей правильное значение:
extension_dir = "C:/php4/extensions/"
Эта директива указывает имя каталога, в котором размещаются
различные расширения PHP (например, для работы с СУБД MySQL).
4. Подключите PHP к web-серверу Apache в качестве модуля.
Способы подключения PHP-интерпретатора к различным web-серверам
описаны в файле install.txt.
a. Откройте в редакторе файл конфигурации Apache (httpd.conf) и добавьте в
его конец следующие строки:
LoadModule php4_module C:/php4/sapi/php4apache.dll
AddType application/x-httpd-php .php
Первая из директив указывает Apache файл, в котором содержится модуль,
который необходимо подключить. Вторая директива определяет, что
файлы, имеющие расширение .php, должны быть обработаны данным
модулем (выполнены).
b. Найдите в файле httpd.conf директиву DirectoryIndex. Изначально она
имеет вид:
DirectoryIndex index.html
Измените ее следующим образом:
DirectoryIndex index.html index.php
4
Директива указывает допустимые имена для файлов «по умолчанию».
Если в запросе указано имя каталога без имени файла, Apache будет
искать в этом каталоге файлы с именами из данного списка.
c. Скопируйте файл php4ts.dll, который находится в каталоге C:\php4\, в
каталог C:\php4\sapi\.
Без этой операции Apache не сможет корректно использовать PHP как
модуль.
d. Перезапустите сервис Apache (см. выше).
5. Проверьте работоспособность PHP-интерпретатора в качестве модуля Apache.
a. Создайте в корневом каталоге web-сервера (C:\webroot) файл test_php.php
следующего содержания:
<html>
<body>
<center>
<h1>HTML context - OK</h1>
<?php
print "<h1>PHP context - OK</h1>";
?>
</center>
</body>
</html>
b. Введите в адресной строке броузера адрес:
http://localhost/test_php.php
Броузер должен отобразить документ следующего вида:
Задание 3. Работа с интерпретатором PHP в режиме командной строки
Для размещения программ используйте созданный ранее каталог C:\phpprog\.
1. Создайте и выполните программу с именем prog1.php следующего содержания:
<?php
$pi = 3.1415926;
$radius = 5;
$len = 2 * $pi * $radius;
echo "pi = $pi; radius = $radius\nlen = $len\n";
?>
Внимательно изучите исходный текст программы и полученный результат.
2. Создайте и выполните программу с именем prog2.php следующего содержания:
<?php
5
$arr = array(1 => 'cat', 'two' => "dog");
$arr[] = 'mouse';
$arr['four'] = 'elephant';
$arr[] = array( "roaches" );
print_r( $arr );
foreach( $arr as $id => $val) {
echo "key = $id; value = $val\n";
}
?>
Проанализируйте исходный текст программы и полученный результат.
3. Создайте и выполните программу с именем prog3.php следующего содержания:
<?
function fib( $n ) {
$a = $b = $r = 1;
for( $i = 3; $i <= $n; $i++ ) {
$r = $a + $b;
$a = $b;
$b = $r;
}
return $r;
}
for( $n = 1; $n <= 20; $n++ ) {
$rez = fib( $n );
echo "fib($n) = $rez\n";
}
?>
Программа вычисляет и отображает первые 20 чисел Фибоначчи.
Проанализируйте исходный текст программы и полученный результат.
Определите, почему эта программа неэффективна и как ее можно улучшить.
Задание 4. Создание сайта с использованием шаблонов
1. Ознакомьтесь с рекомендациями по построению шаблонов (см. ниже).
2. Продумайте вид собственного сайта:
a. Определите назначение сайта (персональный, тематический, сайт
организации …).
b. Найдите в Интернет сайты подобного назначения и познакомьтесь с их
структурой и наполнением.
c. Определите состав страниц сайта (например: «главная», «обо мне», «моя
работа», «мое хобби», «контакты» …).
d. Выберите структуру (способ компоновки) страниц сайта.
3. Создайте сайт:
a. Для размещения файлов сайта создайте каталог C:\webroot\site\.
b. Создайте страницу-прототип, содержащую структуру и оформление сайта.
c. Выберите способ построения шаблона.
d. Создайте файлы шаблонов на основе страницы-прототипа.
6
e. Создайте пустые заготовки страниц сайта (одна из страниц должна иметь
имя index.php).
f. Заполните каждую из страниц данными.
4. Проверьте работу сайта:
a. Запустите web-обозреватель и в адресной строке введите адрес
http://localhost/site/.
b. Проверьте работу системы навигации (меню) сайта и корректность
отображения каждой из страниц.
Задание 5. Выполнение клиентских HTTP-запросов средствами PHP
Для размещения программ и результатов их работы используйте созданный ранее
каталог C:\phpprog\.
1. Ознакомьтесь с описанием утилиты http_get.php.
2. Используя утилиту, выполните запрос к каталогу /site/ локального сервера
localhost (переменной host следует присвоить значение localhost, а переменной
path – значение /site/). Переадресуйте ответ сервера в файл answer1.html.
3. Просмотрите содержимое созданного файла. В начале файла присутствует
HTTP-заголовок, конец которого обозначен пустой строкой, а затем –
содержимое HTML-документа, сформированного скриптом index.php.
4. Создайте копию этого файла под именем answer1-2.html. В новом файле
удалите заголовок, оставив только тело HTML-документа. Сохраните файл.
5. Откройте файл answer1-2.html в броузере. Убедитесь, что его вид соответствует
документу, отображаемому броузером при обращении к серверу
непосредственно (по адресу http://localhost/site/). Отметьте отличия, если
таковые имеют место.
6. Используя ту же утилиту, выполните запрос к серверу www.yandex.ru.
Предварительно проконсультируйтесь о необходимости использования проксисервера. При обращении задайте следующие значения переменных:
host – www.yandex.ru
path - /yandsearch?text=what+does+PHP+mean%3F
(будьте аккуратны при наборе текста пути). Переадресуйте ответ сервера в файл
answer2.html.
7. Просмотрите HTTP-заголовок в созданном файле.
8. Скопируйте файл под именем answer2-2.html. Удалите из нового файла HTTPзаголовок. Сохраните файл.
9. Откройте файл answer2-2.html в броузере.
10.Откройте новое окно броузера и в адресной строке наберите адрес
http://www.yandex.ru.
11.В строке поиска yandex наберите текст “what does PHP mean?” (без кавычек) и
нажмите кнопку Найти.
12.Сравните полученный документ с тем, который был получен ранее с помощью
утилиты.
13.Сравните текст, введенный в строке поиска yandex с текстом, отображаемым в
адресной строке броузера и текстом, введенным ранее в переменную path
утилиты.
14.С помощью той же утилиты исследуйте несколько других сайтов.
7
Задание 6. Передача данных HTML-формы на сервер
О назначении функций get_magic_quotes_gpc() и stripslashes() – см. раздел
«Волшебные кавычки».
1. Создайте каталог C:\webroot\exercises\, если он не существует.
2. В каталоге создайте PHP-скрипт form1.php следующего вида:
<?php
header("Content-Type: text/html; charset=windows-1251");
?>
<html>
<body>
<?php
$text1 = "";
if( $_REQUEST['send'] ) {
$text1 = $_REQUEST['text1'];
if( get_magic_quotes_gpc() ) {
$text1 = stripslashes( $text1 );
}
//
$text1 = htmlspecialchars( $text1 );
print <<<ENDTEXT
Вы ввели:<br>
text1: $text1<br>
ENDTEXT;
}
?>
<form method=get>
<input type=hidden name=send value=1>
<input type=text name=text1 value="<?= $text1?>">
<input type=submit value="Послать">
</form>
</body>
</html>
3. Обратитесь к созданному скрипту через броузер (по адресу
http://localhost/exercises/form1.php).
4. В текстовое поле введите некоторый текст и нажмите кнопку Послать. В ответ
сервер должен выдать страницу, в которой введенный текст отображен вверху и
внутри текстового поля. Обратите внимание, что при отправке запроса
введенный текст (после некоторого кодирования) был добавлен к адресной
строке (запрос послан методом GET).
5. Проделайте операцию отправки данных еще несколько раз, вводя различный
текст.
6. Введите в поле текст, содержащий в середине символы “ и > (двойная кавычка и
знак «больше»). Нажмите кнопку и просмотрите полученный результат. Текст
должен быть отображен в странице с ошибками.
7. Используйте функцию броузера «Просмотреть в виде HTML» для просмотра
исходного текста страницы. Выясните причину неверного отображения текста.
8. Удалите в скрипте символ комментария со строки, содержащей вызов функции
htmlspecialchars(). Вновь выполните отправку тех же данных на сервер. Теперь
текст должен отображаться верно.
8
9. Просмотрите в броузере исходный текст страницы. Выясните, каким образом
удалось избежать ошибки.
10.Добавьте в форму, описанную в скрипте, еще несколько полей различных типов
(в том числе checkbox, select и textarea). Убедитесь, что различные вводимые в
форму данные отображаются в странице корректно.
11.Измените в теге form имя метода с get на post. Теперь при отправке формы на
сервер данные не должны отображаться в адресной строке.
Задание 7. Создание простой гостевой книги
1. Создайте каталог C:\webroot\exercises\, если он не существует.
2. В каталоге создайте PHP-скрипт gb1.php следующего вида:
<?php
header("Cache-Control: no-cache");
header("Pragma: no-cache");
header("Content-Type: text/html; charset=windows-1251");
?>
<html>
<body>
<?php
if( $_REQUEST['send'] ) {
$name = $_REQUEST['name'];
$message = $_REQUEST['message'];
if( get_magic_quotes_gpc() ) {
$name = trim( stripslashes( $name ) );
$message = trim( stripslashes( $message ) );
}
if( strlen($message) > 0 ) {
$name = nl2br( htmlspecialchars( $name ) );
$message = nl2br( htmlspecialchars( $message ) );
$newrecord = "<tr><td>$name</td><td>$message</td></tr>\n";
$prevfile = join( "", file("gbdata.txt") );
$newfile = $newrecord . $prevfile;
$f = fopen( "gbdata.txt", "w+" );
fwrite( $f, $newfile );
fclose( $f );
}
}
?>
<center><h1>Гостевая книга</h1></center>
Добавление нового сообщения:
<form method=post>
<input type=hidden name=send value=1>
Имя: <input type=text name=name value="Незнакомец" size=50><br>
Текст сообщения: <textarea name=message cols=30
rows=4></textarea><br>
<input type=submit value="Послать сообщение">
</form>
Ранее оставленные сообщения:
<table width=100%>
<?php
print join( "", file("gbdata.txt") );
9
?>
</table>
</body>
</html>
3. Обратитесь к созданному скрипту через броузер (по адресу
http://localhost/exercises/gb1.php).
4. Заполните в форме поля Имя и Текст сообщения и нажмите кнопку Послать
сообщение. В странице должно отобразиться введенное сообщение.
5. Обратите внимание, что в каталоге exercises появился файл gbdata.txt, в котором
сохранено посланное сообщение.
6. Введите еще несколько сообщений. Обратите внимание, что каждое новое
сообщение добавляется в начало файла.
7. Внимательно изучите текст скрипта. Выясните назначение незнакомых функций
в данном пособии или в онлайн-документации по PHP
(http://www.php.net/manual/ru/).
8. Встройте созданную гостевую книгу в свой сайт. Для этого добавьте в сайт
новую страницу, оформленную по общему шаблону, и скопируйте в нее
необходимые элементы из созданного скрипта.
Способ встраивания может различаться для шаблонов разных типов.
Создание шаблонов оформления сайтов при помощи PHP
Смысл использования шаблонов при построении сайтов:
1. В сайте зачастую несколько страниц могут иметь одинаковое оформление
(дизайн) и различаться только наполнением. Шаблон позволяет создать
оформление сайта единожды и применять его к разным страницам. Если
потребуется оформление сайта изменить, не придется вносить одни и те же
изменения в различные страницы.
2. Оформление сайта полезно отделить от наполняющих данных для облегчения
работы с этими данными – скрипт, формирующий страницу, не будет
загроможден элементами оформления.
На рис. ниже показаны несколько типичных вариантов компоновки сайтов (серым
цветом выделены элементы, отличающиеся для каждой страницы). В реальных
ситуациях могут встречаться более сложные формы. Рассмотрим два способа
построения шаблонов на примере сайта, наиболее похожего на вариант c).
«Шапка» сайта
«Шапка» сайта
Меню (перечень страниц)
Тело
страницы
Меню
(перечень
страниц)
Нижняя подпись (копирайт и т.п.)
Тело
страницы
Нижняя подпись (копирайт и т.п.)
a)
b)
10
«Шапка» сайта
Название страницы
Меню
(перечень
страниц)
Тело
страницы
Нижняя подпись (копирайт и т.п.)
c)
Сначала создадим HTML-структуру (прототип) страницы (файл prototype.html):
<html>
<head>
<title>
Текст заголовка окна - зависит от страницы
</title>
</head>
<body>
<table width=100% border=1 cellpadding=0 cellspacing=0>
<tr>
<td colspan=2>
<center>
"Шапка" сайта - что-то красивое
</center>
</td>
</tr>
<tr>
<td colspan=2>
<center>
Текст заголовка страницы
</center>
</td>
</tr>
<tr>
<td colspan=1 width=200 valign=top>
<center>
Меню сайта:<br>
<a href="">Страница 1</a><br>
<a href="">Страница 2</a><br>
<a href="">Страница 3</a><br>
<a href="">Страница 4</a><br>
</center>
</td>
<td colspan=1 valign=top>
Тело страницы
</td>
</tr>
<tr>
<td colspan=2>
Подпись внизу страницы
</td>
</tr>
</table>
11
</body>
</html>
Серым цветом выделены переменные элементы (уникальные для каждой страницы).
Таким образом, страница состоит из четырех постоянных фрагментов и трех
переменных.
В броузере такая страница будет иметь следующий вид:
Первый способ построения шаблона заключается в том, что каждый постоянный
фрагмент помещается в отдельный файл и эти файлы включаются в тело каждой
страницы по мере необходимости. Между включениями файлов будут помещены
данные, уникальные для этой страницы.
Так будет выглядеть текст отдельной страницы (index.php):
<?php include("template1.php"); ?>
Текст заголовка окна - зависит от страницы
<?php include("template2.php"); ?>
Текст заголовка страницы
<?php include("template3.php"); ?>
Тело страницы
<?php include("template4.php"); ?>
Файлы template1.php – template4.php содержат соответствующие фрагменты HTMLоформления.
При втором способе формируется единственный файл шаблона на основе созданного
прототипа, а вместо данных, уникальных для каждой страницы, подставляется PHPкод, выводящий в выходной поток значения некоторых переменных. Сами эти
переменные должны быть сформированы в каждой конкретной странице, и для разных
страниц иметь разные значения. Файл шаблона включается в страницу после того, как
все необходимые переменные сформированы.
Файл шаблона template.php:
<html>
<head>
<title>
<?php echo $windowtitle;?>
</title>
</head>
<body>
12
<table width=100% border=1 cellpadding=0 cellspacing=0>
<tr>
<td colspan=2>
<center>
"Шапка" сайта - что-то красивое
</center>
</td>
</tr>
<tr>
<td colspan=2>
<center>
<?php echo $pagetitle;?>
</center>
</td>
</tr>
<tr>
<td colspan=1 width=200 valign=top>
<center>
Меню сайта:<br>
<a href="">Страница 1</a><br>
<a href="">Страница 2</a><br>
<a href="">Страница 3</a><br>
<a href="">Страница 4</a><br>
</center>
</td>
<td colspan=1 valign=top>
<?php echo $pagebody;?>
</td>
</tr>
<tr>
<td colspan=2>
Подпись внизу страницы
</td>
</tr>
</table>
</body>
</html>
Файл страницы index.php:
<?php
$windowtitle = "Текст заголовка окна - зависит от страницы";
$pagetitle = "Текст заголовка страницы";
$pagebody = <<<PAGEBODY
Тело страницы
PAGEBODY;
include("template.php");
?>
Страницы, сформированные двумя приведенными способами, выглядят одинаково.
Существенное различие способов заключается в том, что в первом случае в процессе
обработки страницы сформированные данные постепенно выдаются в выходной
поток, а во втором – сначала в скрипте страницы формируются все необходимые
переменные, а передача данных в выходной поток начинается только при
подключении файла шаблона. Если формирование какой-либо переменной занимает
13
длительное время (например, при выполнении сложного запроса к базе данных),
разница между этими двумя способами может стать заметной пользователю. С другой
стороны, второй способ более надежно отделяет оформление страницы от ее
наполнения. При первом способе изменение компоновки (дизайна) сайта может
повлиять на количество шаблонов и порядок их подключение и, как следствие, с
большей вероятностью вызвать необходимость внесения исправлений во все страницы
сайта.
Целесообразность применения того или иного способа зависит от конкретной задачи.
Кроме приведенных двух способов формирования страниц «по шаблону» могут
использоваться и другие.
Формат сообщений протокола HTTP
Сообщениями в HTTP являются запросы клиентов и
ответы серверов. Сеанс связи между клиентом и
сервером состоит из передачи сообщения-запроса и
получения сообщения-ответа.
Стартовая строка CRLF
Поле заголовка 1 CRLF
Поле заголовка 2 CRLF
Поле заголовка N CRLF
CRLF
[Тело сообщения]
Сообщение содержит заголовок и необязательное
тело сообщения. Заголовок состоит из строк, каждая
из которых завершается парой символов «CR» и «LF»
(символы «возврат каретки» и «перевод строки», с кодами 13 и 10 соответственно).
После заголовка помещается пустая строка, за которой при необходимости следует
тело сообщения.
Вид стартовой строки (первой строки заголовка) различен для запросов и ответов. В
запросе это строка запроса, а в ответе – строка статуса. Далее следуют поля
заголовка в виде пар <имя>=<значение>. Формат тела сообщения определяется
значениями некоторых полей заголовка.
Строка запроса имеет следующий формат:
<метод><пробел><URL или абсолютный путь><пробел><версия HTTP>
Методы: GET, POST, HEAD (это не полный список). При обращении методом GET
указывается имя или URL документа, который должен быть возвращен сервером. Тело
сообщения в запросе методом GET отсутствует. Сервер возвращает ответ, содержащий
запрошенный документ. Метод HEAD отличается от GET тем, что сервер возвращает
только поля заголовка, характеризующие указанный в запросе документ, но не
возвращает сам документ. Метод POST позволяет при запросе документа передать
серверу для обработки дополнительную информацию, помещенную в теле сообщения.
Вид возвращаемого сервером документа может формироваться в зависимости от
переданной информации.
URL – полный адрес документа в сети. Абсолютный путь – URL без указания схемы,
хоста и номера порта. При этом предполагается, что документ размещен на том самом
сервере, к которому адресован запрос. В обоих вариантах к имени может быть
14
добавлена строка параметров, которые должны быть учтены сервером при выдаче
документа. Передача параметров, как и тела сообщения при использовании метода
POST, имеет смысл, если запрашиваемый документ формируется на сервере
динамически и формирующая его программа готова выполнить обработку данных.
При обращении к статически хранящимся на сервере документам переданные данные
будут проигнорированы. При работе через proxy-сервер обязательно должен
указываться URL документа. Web-сервер же в некоторых случаях может отклонять
запросы, содержащие URL, ожидая, что будет задан только путь.
Совет: указывайте URL документа при обращении к proxy-серверу и путь при
обращении напрямую к web-серверу.
Версия HTTP – имеет формат: HTTP/<цифры>.<цифры>
Цифры определяют «верхний» и «нижний» номера версии. В настоящее время
возможны варианты: HTTP/0.9 (это уже анахронизм), HTTP/1.0 и HTTP/1.1.
Примеры строки запроса:
GET http://www.w3.org/Protocols/rfc2616/rfc2616.html HTTP/1.1
POST /books/index.php HTTP/1.0
GET /search.php?q=who%20am%20i HTTP/1.0
В первом случае запрашивается документ, заданный полным URL. Во втором – для
документа задан абсолютный путь. Поскольку выбран метод POST, в теле сообщения
клиент должен поместить некоторые данные. В третьем примере к имени документа
добавлена строка-параметр, которая будет обработана сервером перед выдачей ответа.
Строка статуса, входящая в ответ сервера, имеет формат:
<версия HTTP><пробел><код статуса><пробел><комментарий>
Код статуса – трехзначное число, сообщающее клиенту о выполнении запроса.
Комментарий дает краткое текстовое описание кода статуса. Код предназначен для
обработки программой, комментарий – для просмотра человеком.
Первая цифра кода статуса определяет класс ответа, остальные две содержат более
детальную информацию. Определены 5 классов для кодов статуса:
 1xx – информационные, введены только в HTTP/1.1
 2xx – запрос выполнен успешно
 3xx – перенаправление, клиенту следует сделать новый запрос
 4xx – ошибка клиента, запрос содержал ошибочные данные
 5xx – ошибка сервера, клиент, возможно, и не виноват
Расшифровка некоторых кодов статуса:
 200 Ok – запрос выполнен, тело сообщения содержит запрошенный документ.
Это обычное значение для нормально завершенного запроса.
 204 No Content – Запрос выполнен, но сервер не возвращает тело ответа, только
заголовок. Броузер, получив этот код, не должен заменять текущий
отображаемый документ. Т.е. при обращении по ссылке выполняется запрос к
15








серверу, на сервере производятся некоторые действия (например, обновление
информации в базе данных), но при этом пользователь видит тот же документ,
что и прежде.
301 Moved Permanently – запрошенный документ теперь находится по другому
адресу и в дальнейшем следует обращаться туда. При этом новый адрес
документа указывается в поле заголовка Location.
302 Moved Temporarily – запрошенный документ временно находится по
другому адресу (указанному в поле Location), но в дальнейшем его следует
искать на прежнем месте.
400 Bad Request – запрос имел неверный синтаксис и не был понят сервером.
401 Unauthorized – для доступа к запрошенному документу требуется
авторизация. Дополнительно возвращается поле заголовка WWW-Authenticate,
в котором уточняется способ аутентификации (см. ниже). Клиент может
повторить запрос, указав определенное значение в поле заголовка Authorization.
Если поле Authorization в запросе уже было задано, значит, указанное в нем
значение не дает права на доступ к документу.
403 Forbidden – сервер понял смысл запроса, но отказывается вернуть
запрошенный документ, поскольку доступ к нему запрещен. Этот код также
может быть возвращен после неудачной попытки авторизации, когда от
пользователя получено поле Authorization, значение которого не дает права на
доступ к документу.
404 Not Found – этот код знаком практически всем пользователям всемирной
паутины. Код 404 сообщает клиенту, что запрошенный документ на сервере не
обнаружен. Если же клиенту не полагается знать об отсутствии документа,
сервер должен вернуть код 403.
500 Internal Server Error – на сервере произошло нечто, чего он не в силах
исправить или даже понять.
501 Not Implemented – сервер не обнаружил нарушений в синтаксисе запроса,
но выполнение таких запросов он не поддерживает. Например, указан не
известный серверу метод.
Если сервер возвращает код 3xx, он также должен сформировать тело документа,
содержащее информацию для пользователя о местоположении запрошенного
документа. Этот документ будет отображен, если программа-клиент не выполнит
самостоятельно переход к новому документу.
Поля заголовков протокола HTTP
Host (в запросе)
При разработке HTTP/1.0 предполагалось, что одному IP адресу соответствует одно
доменное имя и после того, как соединение с сервером установлено, достаточно
указать путь требуемого ресурса. В настоящее время такой подход устарел (сейчас
количество зарегистрированных доменных имен разных уровней сопоставимо с
размерами пространства IP-адресов, притом, что большинство компьютеров являются
клиентскими). Один физический сервер может содержать множество виртуальных
хостов с различными доменными именами. После установления соединения требуется
16
указать имя виртуального хоста, на котором размещен запрашиваемый документ. Поле
Host введено в [RFC 2616] и должно поддерживаться клиентами и серверами. Для
запросов HTTP/1.1 задание поля Host является обязательным, при его отсутствии
сервер должен возвращать статус «400 Bad Request».
Пример заголовка запроса:
GET /Protocols/rfc2616/rfc2616.html HTTP/1.1
Host: www.w3.org
Location (в ответе)
Поле Location может присутствовать в ответах сервера, сообщая клиенту адрес
документа, к которому следует обратиться. Обычно Location используется совместно
с кодами переадресации 3xx, указывая новое местоположение искомого документа.
Наличие этого поля позволяет броузеру автоматически перейти к новому документу. В
[RFC 1945] и [RFC 2616] определено требование, что поле Location должно содержать
полный URL, но броузеры обычно способны работать и с адресом, задающим только
путь. При этом URL нового документа формируется на основе исходного URL.
Server (в ответе)
Поле сообщает клиенту сведения о программном обеспечении, используемом на
сервере: о самом web-сервере и наиболее значительных модулях.
Пример заголовка ответа:
HTTP/1.0 200 OK
Server: Apache/1.3.27 (Unix) mod_ssl/2.8.14 PHP/4.3.3-dev
Referer (в запросе)
Если клиент выполняет переход к данному документу по ссылке, указанной в другом
документе, он может передать серверу поле Referer, указывая адрес ссылающейся
страницы. Если указан только путь, он должен рассматриваться относительно URL
запрашиваемого документа. Поле Referer обычно используется для анализа
посещаемости. Следует иметь в виду, что значение поля может быть
фальсифицировано или просто не указано по соображениям конфиденциальности.
WWW-Authenticate (в ответе) и Authorization (в запросе)
Поле WWW-Authenticate должно присутствовать в ответе, содержащем код статуса
401 Unauthorized. Поле содержит информацию о допускаемых сервером схемах
аутентификации (установления личности) пользователя. Значение поля представляется
в форме: <имя_схемы> realm="<имя_области>". Параметр realm определяет имя
защищаемой области. Имя области вместе с корневым URL сервера определяют
некоторое защищенное множество ресурсов. В пределах одного сервера может
существовать несколько защищенных множеств, различающихся именем области. В
HTTP/1.0 определена единственная схема - Basic. При этом значение атрибута имеет
вид: Basic realm="<имя_области>".
Для получения доступа к документу, клиент должен передать серверу поле
Authorization, значение которого представлено в форме: <имя_схемы> <параметр>.
Для схемы Basic значение поля имеет вид: Basic <параметр>. Здесь параметр
представляет собой строку, содержащую логин и пароль пользователя, разделенные
17
двоеточием и закодированные методом base64 [RFC 2045]. Клиент-броузер должен
предложить пользователю ввести логин и пароль. В дальнейшем, при обращении к
другим документам в пределах того же защищенного множества, броузер может
использовать ранее введенные пользователем данные.
Схема Basic использует передачу пароля открытым текстом (кодировка base64 не
является шифром), и потенциально возможен его перехват. Для повышения
безопасности авторизованного доступа в HTTP/1.1 введена схема Digest. Схемы Basic
и Digest рассматриваются в [RFC 2617].
Пример.
Заголовок ответа сервера с требованием авторизации:
HTTP/1.0 401 Unauthorized
WWW-Authenticate: Basic realm="My Site"
Заголовок запроса клиента с данными для авторизации:
GET /index.html HTTP/1.0
Authorization: Basic bXlsb2dpbjpteXBhc3N3b3Jk
(здесь закодированные данные – строка «mylogin:mypassword» в формате base64).
Заголовок ответа сервера на предыдущий запрос:
HTTP/1.0 200 OK
Date (в запросе и ответе), Last-Modified (в ответе), Expires (в ответе)
Если поле Date присутствует в сообщении, оно должно содержать дату/время создания
сообщения. Поле Last-Modified предназначено для передачи даты/времени последнего
изменения документа. Поле Expires указывает время, после которого клиент должен
будет считать документ устаревшим. Эти поля позволяют клиенту или proxy-серверу
принимать решение о длительности кэширования и необходимости обновления
(повторного запроса) документа.
Протокол HTTP допускает несколько форматов представления даты/времени, из
которых предпочтительным является описанный в [RFC 822, RFC 2822].
Пример заголовка ответа:
HTTP/1.0 200 OK
Date: Tue, 23 Mar 2004 10:25:14 GMT
Last-Modified: Tue, 23 Mar 2004 00:22:37 GMT
Pragma (в запросе и ответе)
Для поля Pragma существует единственное предопределенное значение: «no-cache».
Присутствие этого поля в теле запроса указывает на то, что клиент хочет получить от
сервера последнюю версию документа. При этом должны быть проигнорированы
копии документа, ранее сохраненные proxy-сервером или броузером. Если поле
Pragma со значением «no-cache» присутствует в ответе сервера, этот ответ не должен
кэшироваться броузерами и proxy-серверами.
Cache-Control (в запросе и ответе)
В HTTP/1.1 для более гибкого управления кэшированием введено поле Cache-Control.
В значении поля размещаются директивы, определяющие допустимость и
длительность кэширования. Приведем две наиболее важные из них.
18
Директива «no-cache» имеет то же назначение, что и для поля Pragma. Директива
«public» используется в заголовке ответа, разрешая кэширование документа.
Совет: поскольку некоторые броузеры и proxy-серверы могут считать устаревшим
поле Pragma, а другие - не поддерживать поле Cache-Control, для гарантированного
запрета кэширования лучше использовать оба поля: «Pragma: no-cache» и «CacheControl: no-cache» .
Content-Length (в запросе и ответе)
Поле Content-Length содержит размер (в байтах) тела передаваемого сообщения. При
ответе на запрос методом HEAD, поле указывает размер тела сообщения, которое
может быть передано в ответ на запрос методом GET.
При получении ответа сервера, если размер тела ответа не указан, клиент может
установить достижение конца ответа по разрыву соединения сервером. При отправке
серверу запроса методом POST, клиент обязательно должен указать размер тела,
поскольку сервер не способен определить конец сообщения (клиент не может
разорвать соединение до получения ответа от сервера).
Content-Type (в запросе и ответе)
Всякое сообщение, имеющее тело, должно содержать поле Content-Type,
определяющее медиа-тип (media-type) [RFC 2046] передаваемых данных. Значения
поля могут иметь следующий вид: <тип>/<подтип>[; <параметр>]. Тип и подтип
передаваемых данных определяют способ, которым принимающее приложение
должно эти данные обработать. Полный перечень зарегистрированных типов/подтипов
можно найти в [IANA/MEDIA]. Документы HTML имеют тип «text/html» [RFC 2854].
При передаче обычного текста, не содержащего элементов форматирования,
указывается тип «text/plain» [RFC 2046]. Если тип не указан, предполагается значение
«application/octet-stream» [RFC 2046] (просто двоичные данные).
Вид необязательного параметра зависит от типа. Для типа «text» может быть задан
параметр «charset» (character set – набор символов). Набор символов определяет
способ отображения передаваемого текста, т.е. соответствие между байтами данных и
представляемыми ими символами. Полный список зарегистрированных наборов
символов размещен в [IANA/CHARSETS]. Если в сообщении набор символов не
определен, получатель должен считать, данные соответствуют набору латинских
символов ISO-8859-1 (другое название – latin1).
Существует несколько наборов для представления кириллических символов:
 windows-1251 – используется в операционных системах семейства Windows;
 koi8-r – используется в большинстве клонов ОС Unix;
 koi8-u – поддерживает символы украинского алфавита;
 ISO-8859-5 – стандарт, редко используемый на практике;
 Cp866 – так называемая «альтернативная кодировка», используется в
операционной системе Dos.
 utf-8 – специальная кодировка, позволяющая отображать в документе
одновременно символы различных алфавитов. В ней символы, не входящие в
19
набор символов Ascii, могут представляться последовательностью двух или
более байт.
Пример:
Content-Type: text/html; charset=windows-1251
В [RFC 2046] описан, в частности, медиа-тип «multipart», предназначенный для
размещения в теле одного сообщения нескольких различных блоков данных. При этом
каждый блок данных может содержать собственные поля заголовка, указывающие его
медиа-тип и другие характеристики. Допустимо использовать поля, имя которых
начинается с «Content-» («Content-Type», «Content-Disposition» и т.п.). Если внутри
блока не указано поле заголовка «Content-Type», подразумевается тип «text/plain».
Если поле «Content-Type» содержит значение типа «multipart», оно должно содержать
также параметр «boundary» - строку, служащую разделителем для разных блоков
данных. Во избежание ошибочного толкования получателем, строка, выбранная в
качестве разделителя, не должна содержаться ни в одном из передаваемых блоков
данных. Использование разделителей позволяет обойтись без указания точного
размера передаваемых данных в поле «Content-Length».
В HTTP, для передачи данных от клиента серверу, может быть использован подтип
«multipart/form-data» [RFC 2388]. Он позволяет передавать данные, введенные
пользователем в HTML-форму. В каждом разделе тела сообщения содержатся данные
одного из элементов формы. Каждый раздел должен также включать поле заголовка
«Content-Disposition» со значением «form-data» и параметром «name», содержащим
имя соответствующего элемента формы. При передаче файлов, также должны
указываться их имена в параметре «filename». Если клиент передает серверу
содержимое файла, следует обязательно указать его медиа-тип.
Пример:
Content-Type: multipart/form-data; boundary=AbCd4321
--AbCd4321
Content-Disposition: form-data; name="field1"
Текст 1...
--AbCd4321
Content-Disposition: form-data; name="field2"
Текст 2...
--AbCd4321
Content-Disposition: form-data; name="field3"; filename="myfile.txt"
Content-Type: text/plain
... тело файла ...
--AbCd4321--
Здесь передаются данные формы, состоящие из трех полей. В заголовке определено
значение строки-разделителя: «AbCd4321». Перед каждой из частей сообщения
помещается строка-разделитель, дополненная в начале двумя символами «-». После
последнего блока помещается разделитель, дополненный двумя символами «-» и в
20
начале, и в конце. Первые две части сообщения содержат текстовые данные из полей
формы (с именами «field1» и «field2» соответственно). В третьей части помещается
содержимое передаваемого файла, выбранного пользователем с помощью элемента
формы с именем «field3».
Cookie, Set-Cookie
См. ниже: описание функции setcookie и раздел «Механизм cookies»
Функции поддержки сетевого и транспортного уровней в PHP
pointer fsockopen(addr, port [, errno [, errstr [, timeout]]])
Функция fsockopen() устанавливает сокетное соединение с ресурсом, заданным
адресом (addr) и портом (port). Необязательными параметрами являются errno и errstr
(переменные, получающие номер и текстовое описание ошибки соответственно), а
также вещественное значение timeout, определяющее время ожидания соединения (в
секундах). Если соединение установлено, функция возвращает указатель открытого
потока pointer. В случае ошибки возвращается значение «false». Для работы с
полученным указателем могут быть использованы функции файлового ввода/вывода –
такие, как fgets(), fputs(), feof() и fclose().
Значение addr представляет собой строку, содержащую имя компьютера, его IP-адрес
или имя сокета UNIX. В строке addr может присутствовать префикс вида
«транспорт://», определяющий тип транспорта. Возможные типы транспорта: «tcp»,
«udp», «ssl», «tls» и «unix». Первые два указывают на используемый протокол
прикладного уровня, «ssl» и «tls» - на то, что устанавливается соединение TCP,
дополненное шифрованием. Транспорт «unix» используется для связи с UNIXсокетом. При этом параметр port должен быть равен «0». Если тип транспорта не
указан, значением по умолчанию является «tcp».
Транспорт «udp» поддерживается в PHP, начиная с версии 4.0, «ssl» и «tls» - с версии
4.3.
При открытии UDP-сокета, функция fsockopen может завершиться без ошибки, даже
если указанный хост недоступен. При этом ошибка возникает только при попытке
чтения/записи. Такая ситуация возможна, поскольку протокол UDP не
предусматривает установление соединения и взаимодействие происходит только при
передаче/приеме данных.
Примеры.
Открытие TCP-соединения, порт 80:
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 10);
Соединение с UNIX-сокетом:
$fp = fsockopen("unix:///tmp/mysock", 0);
hostname gethostbyaddr(hostip)
21
Функция определяет имя хоста по его IP-адресу. Параметр hostip – строка, содержащая
IP-адрес в виде четырех чисел, разделенных точками («a.b.c.d»). Возвращаемое
значение должно содержать имя хоста. Если hostip не является правильным IPадресом, функция возвращает значение «false». Если не удалось определить имя хоста,
будет возвращено входное значение.
Эту функцию следует использовать осторожно, поскольку одному IP-адресу может
соответствовать много имен (при этом возвращено будет только одно из них), или ни
одного.
Пример.
$name = gethostbyaddr("127.0.0.1");
Переменная $name будет содержать имя компьютера, на котором выполняется данный
скрипт (скорее всего, будет возвращено значение «localhost»).
hostip gethostbyname(hostname)
Функция определяет IP-адрес хоста по его имени. В случае успеха функция
возвращает строку, содержащую IP-адрес в формате «a.b.c.d». В противном случае
будет возвращено входное значение.
При выполнении функций gethostbyaddr() и gethostbyname() происходит обращение к
службе DNS и время ожидания ответа может оказаться значительным.
number ip2long(ip)
Функция преобразует IP-адрес (IPv4), представленный в формате «a.b.c.d» в длинное
целое число. В случае ошибки возвращается значение «-1». Поскольку числа в PHP
рассматриваются как знаковые, многие IP-адреса преобразуются в отрицательные
значения. В частности, адресу «255.255.255.255» соответствует число «-1».
Для отображения чисел как положительных без знака, следует использовать средства
форматированного вывода (printf(), sprintf() и т.п.).
В листинге 1 приведен фрагмент кода, который преобразует IP-адрес в число и
выводит его в форме со знаком и без знака.
$addr = "192.168.0.1";
$number = ip2long($addr);
if ($number == -1) {
print "Bad IP address\n";
} else {
print $addr . "\n";
// 192.168.0.1
print $number . "\n";
// -1062731775
printf("%u\n", $number); // 3232235521
}
Листинг 1
22
ip long2ip(number)
Функция преобразует числовое значение в строку, содержащую IP-адрес в формате
«a.b.c.d». Входное значение может быть как знаковым, так без знака. Если входное
число превышает максимально возможное значение (положительное или
отрицательное), в зависимости от используемой платформы могут возвращаться
строки «255.255.255.255» или «0.0.0.1» (соответствующие числовым значениям «-1» и
«1»).
Пример.
Приведенный ниже фрагмент кода должен дважды вывести одно и то же значение
«192.168.0.1» (см. комментарии в листинге 1):
print long2ip(-1062731775) . "\n";
print long2ip(3232235521) . "\n";
Преобразование IP-адреса в числовую форму может быть использовано, например, для
экономии занимаемого места и повышения производительности при хранении адресов
в базе данных.
Утилита http_get.php
Утилита предназначена для выполнения клиентских запросов к web-серверу. Она
выполняет примерно те же действия, что и броузер – используя протокол HTTP,
посылает запрос по указанному адресу и принимает ответ сервера. Утилита дает
пользователю возможность увидеть весь ответ сервера полностью, включая заголовки
HTTP.
Переменной host нужно присвоить имя хоста web-сервера, к которому следует
выполнить запрос. Переменная path задает имя документа, запрашиваемого с этого
сервера (может включать строку параметров запроса). Если при обращении к серверу
требуется использовать прокси-сервер, переменной useproxy следует присвоить
значение true, а переменным proxyserver и proxyport – имя хоста и номер порта
прокси-сервера соответственно. Если для доступа к документу требуется передать
логин и пароль, следует задействовать переменные useauth, login и pass.
При запуске программы для подавления избыточной информации следует
использовать параметр –q:
C:\php4\php.exe –q http_get.php
Выводимый программой текст можно (средствами Windows) переадресовать в файл
для дальнейшего просмотра и обработки, например:
C:\php4\php.exe –q http_get.php > result.html
<?
// *******************************************
// Здесь следует установить параметры запроса
$host = "localhost"; // Имя хоста web-сервера
23
$port = 80; // Порт web-сервера
$path = "/"; // Имя документа
$useproxy = false;
//$useproxy = true; // Следует использовать proxy
//$proxyserver = "localhost"; // Адрес proxy
//$proxyport = 3128; // Порт proxy-сервера
$useauth = false;
//$useauth = true;
//$login = "mylogin";
//$pass = "mypassword";
// *******************************************
// Настройка, в зависимости от параметров
if($useproxy) {
$connectaddr =
$connectport =
$requestaddr =
} else {
$connectaddr =
$connectport =
$requestaddr =
}
$proxyserver;
$proxyport;
"http://$host:$port$path";
$host;
$port;
$path;
// *******************************************
// Выполнение запроса
// Установление соединения
$p = fsockopen($connectaddr, $connectport);
if( $p ) {
// Передача строки запроса
fputs($p, "GET $requestaddr HTTP/1.0\r\n");
// Передача полей заголовка
fputs($p, "Host: $host\r\n");
fputs($p, "Connection: close\r\n");
// Передать поле Authorization, если требуется
if ($useauth)
fputs($p, "Authorization: Basic ".
base64_encode("$login:$pass").
"\r\n");
// Пустая строка в конце заголовка
fputs($p, "\r\n");
// Прочитать ответ сервера построчно
while ( !feof($p) )
print fgets($p);
// Закрыть соединение
fclose($p);
} else {
24
print "Error\n";
}
?>
HTML-формы
В языке HTML (HyperText Markup Language) [W3/HTML40] для ввода данных
пользователем применяются формы. Форма определяется парой тегов
<FORM name=имя action=URL method=метод enctype=тип> и </FORM>,
между которыми размещаются теги, описывающие элементы ввода.
Ниже перечислены основные виды тегов, определяющих элементы ввода:
<INPUT name=имя type=тип value=значение>
Атрибут «name» определяет имя элемента ввода, под которым его содержимое будет
передано на сервер. Имена разных элементов могут совпадать, но при их попадании на
сервер обрабатывающий скрипт получит значение только одного из одноименных
элементов (в некоторых случаях при необходимости можно восстановить все
значения, но этот не слишком эстетичный путь). Если в качестве серверного
обработчика будет использован PHP-скрипт, элементам можно присваивать имена,
содержащие пару квадратных скобок. Такие элементы будут получены скриптом в
форме массива. Этот способ позволяет использовать при обработке циклы. Например,
когда несколько полей ввода требуют одинакового способа обработки сервером.
Атрибут «type» задает тип элемента. Основные типы: text, password, hidden, checkbox,
radio, submit, reset, button, file.
Тип «text» определяет поле, в которое пользователь может ввести некоторую строку
текста, которая затем будет передана серверу.
Тип «password» аналогичен типу «text», но содержимое поля при отображении
заменяется звездочками. Тип используется для ввода конфиденциальной информации
(например, пароля).
Элемент типа «hidden» не отображается (является скрытым). При формировании
сервером документа, в нем могут быть размещены скрытые поля форм, значения
которых будут впоследствии снова переданы серверу. Таким методом сервер может, в
частности, поддерживать сеанс работы с пользователем. В скрытом поле помещается
некоторый идентификатор сеанса, который впоследствии поможет серверу
«вспомнить», о чем ранее шел «разговор» с данным пользователем. Или, если ввод
данных состоит из нескольких последовательных шагов и обработка сервером будет
произведена только после завершения всей процедуры, скрытые поля могут хранить
данные, введенные пользователем на предыдущих этапах.
Элемент «checkbox» определяет двухпозиционный переключатель. Если элемент
«включен», то при отправке формы серверу его имя и значение будут переданы, в
25
противном случае – нет. Само значение элемента не отображается и пользователь его
менять не может. Если начальное состояние элемента должно быть «включен», в теге
следует разместить атрибут «checked».
Элемент «radio» отличается от элемента «checkbox» тем, что из нескольких
присутствующих в форме одноименных элементов типа «radio» в каждый момент
времени «включенным» может быть только один. Элементы «radio» обеспечивают
выбор одного варианта из нескольких.
Элемент типа «submit» определяет кнопку, при нажатии на которую происходит
отправка формы.
Элемент «reset» - кнопка, вызывающая сброс введенных пользователем в поля формы
данных и возврат к начальным значениям.
Элемент «button» - кнопка, у которой нет предопределенных действий. Для нее можно
определить функцию-обработчик (например, на языке JavaScript), которая будет
вызвана при нажатии на эту кнопку.
Элемент типа «file» предназначен для задания пользователем имени файла, который
должен быть послан на сервер при отправке формы. Элемент состоит из текстового
поля, в котором отображается имя файла, и кнопки «Обзор», открывающей диалоговое
окно для навигации по файловой системе.
Назначение атрибута «value» тега «INPUT» зависит от типа элемента. Для элементов
«text» и «password» он содержит начальное значение элемента, которое может быть
изменено пользователем. Для элементов «hidden», «checkbox» и «radio» - значение,
которое будет передано серверу при отправке. Для элементов «submit», «reset» и
«button» - надпись на кнопке.
<TEXTAREA name=имя rows=число cols=число>…</TEXTAREA>
Элемент, определяемый тегом TEXTAREA, как и элемент типа «text», определяемый
тегом INPUT, предназначен для ввода текста пользователем. В отличие от последнего,
элемент TEXTAREA имеет закрывающий тег и позволяет вводить/редактировать
многострочный текст. Между открывающим и закрывающим тегами может быть
помещено начальное значение (текст, который будет отредактирован пользователем).
Атрибуты «rows» и «cols» определяют размер при отображении элемента (число
текстовых строк и столбцов соответственно).
<SELECT name=имя multiple>…</SELECT>
Элемент SELECT предназначен для построения списка, из которого пользователь
может выбрать один или несколько элементов (выбор нескольких элементов разрешен,
если в теге присутствует атрибут «multiple»). Для определения элементов списка
используются теги <OPTION value=значение selected>текст</OPTION>,
размещаемые между открывающим и закрывающим тегами SELECT. Присутствие
26
атрибута «selected» указывает на то, что этот элемент списка выбран изначально.
Текст, размещенный между открывающим и закрывающим тегами, отображается в
соответствующей строке списка. Атрибут «value» содержит значение, которое будет
передано серверу при отправке формы, если этот элемент списка будет выбран. Если
атрибут «value» не задан, в качестве значения будет передан отображаемый текст.
Если в списке разрешен многовариантный выбор, несколько выбранных значений
будут передаваться под одним и тем же именем (именем списка). В случае, если
данные формы поступают в PHP, можно добавить к имени списка пару квадратных
скобок. Тогда все выбранные значения будут помещены в один массив.
Пример:
<select name="mylist[]" multiple>
<option value="1">Элемент 1</option>
<option value="2">Элемент 2</option>
<option value="3">Элемент 3</option>
</select>
В этом фрагменте объявляется список, содержащий три элемента и допускающий
многовариантный выбор. После отправки формы, PHP-обработчик получит массив с
именем «mylist», содержащий значения атрибутов «value» выбранных элементов.
Атрибуты тега <FORM> и способы передачи данных:
Атрибут «name» задает имя формы. Имя может быть использовано для обращения к
элементам формы из скриптов, выполняемых на стороне клиента. В HTML версии 4
рекомендовано вместо имени применять для этих целей атрибут «id».
Атрибут «action» задает URL или путь (определяемый относительно текущего URL)
ресурса, который будет запрошен для обработки данных при отправке формы. Если
атрибут «action» не определен, данные формы будут переданы ресурсу, URL которого
совпадает с URL текущего документа (документа, содержащего эту форму).
Атрибут «method» указывает на метод, которым должен быть запрошен ресурсобработчик формы. Возможные значения – «GET» (по умолчанию) и «POST».
При обращении методом «GET», из данных формы образуются пары вида
«имя=значение», которые объединяются символом «&» и добавляются к строке
параметров запрашиваемого URL. Строка параметров отделяется от имени документа
символом «?». При этом данные преобразуются к набору символов, присутствие
которых допустимо в URL [RFC 1738]: пробелы заменяются символом «+», каждый
запрещенный символ заменяется последовательностью вида «%HH», где HH –
шестнадцатеричное представление ASCII-кода символа. Поскольку клиентское и
серверное программное обеспечение ограничивает допустимую длину строки URL,
метод «GET» нельзя использовать для передачи больших объемов данных форм. Если
форма выполняет передачу файлов, использование метода «POST» является
обязательным.
Пример:
27
<form method="get" action="target.php">
<input type=hidden name="key" value="123/456">
Пол:
<input type=radio name="gender" value="male" checked>М
<input type=radio name="gender" value="female">Ж
<input type=submit value="Отправить форму">
</form>
При отправке приведенной здесь формы броузер должен выполнить запрос вида:
GET /путь/target.php?key=123%2F456&gender=male HTTP/1.0
Предполагается, что ресурс «target.php» расположен по тому же адресу, что и текущий
документ.
Атрибут «enctype» определяет способ кодирования данных формы при передаче
методом «POST». Возможны два варианта: «application/x-www-form-urlencoded» (по
умолчанию) и «multipart/form-data».
В первом случае данные формы перед передачей обрабатываются тем же способом,
что и для метода «GET»: образуются пары вида «имя=значение», закодированные в
соответствии с требованиями [RFC 1738], в качестве разделителя также используется
символ «&». При этом данные передаются в теле запроса, а не в строке URL. Такой
способ позволяет избежать проблем, вызванных ограничением длины строки URL, но
передача файлов при этом также невозможна. Кроме того, кодирование «application/xwww-form-urlencoded» неэффективно при передаче больших объемов двоичных
данных, поскольку каждый не-ASCII символ заменяется последовательностью из трех
символов.
Пример. Если в предыдущем примере вместо метода «GET» указать «POST», броузер
должен будет выполнить следующий запрос:
POST /путь/target.php HTTP/1.0
Поля заголовка
Content-Type: application/x-www-form-urlencoded
key=123%2F456&gender=male
Здесь пустая строка указывает на окончание заголовка и начало тела запроса.
Если значение атрибута «enctype» равно «multipart/form-data», данные будут переданы
с использованием соответствующего медиа-типа «multipart/form-data» [RFC 2388]. При
этом тело сообщение состоит из отдельных блоков, каждый блок содержит данные
одного элемента формы (см. также 2.1.3 – описание полей «Content-Type» и «ContentDisposition»).
Пример. Если в ранее приведенном примере применить кодирование «multipart/formdata», запрос броузера будет иметь следующий вид:
POST /путь/target.php HTTP/1.0
Поля заголовка
Content-Type: multipart/form-data; boundary=AbCd4321
--AbCd4321
Content-Disposition: form-data; name="key"
28
123/456
--AbCd4321
Content-Disposition: form-data; name="gender"
male
--AbCd4321--
Здесь отдельные блоки не содержат полей «Content-Type» - по умолчанию
подразумевается значение «text/plain».
Кодирование методом «multipart/form-data» - единственно допустимое при передаче на
сервер файлов. В случае, если передается много элементов, каждый из которых
содержит небольшой объем данных, такой способ кодирования оказывается менее
эффективным (размер тела запроса больше, чем при кодировании методом
«application/x-www-form-urlencoded»).
Пример: HTML-документ, содержащий форму
В листинге приведен пример HTML-документа,
который содержит форму. На рис. показано,
как эта форма может выглядеть в окне
броузера.
<html>
<body>
<form name=myform method=post enctype="multipart/form-data">
Имя: <input type=text name="fname">
<br>
Фамилия: <input type=text name="lname">
<br>
Пол:
<input type=radio name="gender" value="male" checked>М
<input type=radio name="gender" value="female">Ж
<br>
Фото:
<input type=file name="photo">
<br>
<input type=submit value="Отправить форму">
</form>
</body>
</html>
Доступ к полученным данным на сервере
PHP-скрипт, выполняемый под управлением web-сервера и обрабатывающий запрос
клиента, получает доступ к необходимым данным посредством набора PHPпеременных. Все переменные размещаются в суперглобальных ассоциативных
массивах с предопределенными именами. Данные, переданные клиентом, помещаются
в массивы $_GET, $_POST, $_FILES, $_COOKIE, $_REQUEST. Такие имена массивов
были введены в PHP версии 4.1. В более ранних версиях использовались глобальные
(но не суперглобальные) массивы $HTTP_GET_VARS, $HTTP_POST_VARS,
29
$HTTP_POST_FILES и $HTTP_COOKIE_VARS, которые по-прежнему доступны, но
их не рекомендуется использовать. Аналога массиву $_REQUEST в прежних версиях
нет.
Кроме этого, скрипт может получить полный перечень полей заголовка запроса с
помощью функции apache_request_headers() (или getallheaders()).
$_GET
Массив содержит данные, переданные клиентом через параметры URL запроса.
Наличие данных в этом массиве не означает того, что запрос был выполнен именно
методом HTTP «GET».
Пример. Если клиент выполнит запрос к ресурсу вида
target.php?key=123%2F456&gender=male
На сервере будет выполнен скрипт «target.php», при этом массив $_GET будет
содержать два элемента:
(
[key] => 123/456
[gender] => male
)
$_POST
В массив помещаются данные, переданные клиентом в теле запроса по методу
«POST».
$_FILES
Массив содержит информацию о файлах, переданных на сервер методом «POST».
Имена элементов массива совпадают с именами соответствующих элементов HTMLформы. Каждый элемент массива $_FILES – массив, хранящий информацию об одном
из загруженных файлов. Массивы содержат следующие элементы:
 name – исходное имя загруженного файла.
 type – медиа-тип файла.
 size – размер файла, в байтах. Если файл не был выбран пользователем, значение
size равно «0».
 tmp_name – путь и имя временного размещения загруженного файла. Файл
помещается в каталог на сервере, предназначенный для временных файлов. В
конфигурации PHP может быть определен параметр «upload_tmp_dir»,
указывающий имя временного каталога для загруженных файлов. Временный
файл нужно перенести в подходящее место или удалить после обработки
(функция unlink()). Предполагается, что по окончании работы скрипта
временные файлы будут удалены автоматически, но полагаться на это особенно
не следует. Для работы с загруженными файлами предназначены функции
is_uploaded_file() и move_uploaded_file().
 error – код ошибки. Коды ошибок введены в PHP версии 4.2, в версии 4.3 были
добавлены соответствующие предопределенные константы.
Коды ошибок:
0 (константа UPLOAD_ERR_OK) – загрузка файла выполнена успешно.
30
1 (UPLOAD_ERR_INI_SIZE) – превышен допустимый размер файла,
установленный в параметре конфигурации PHP «upload_max_filesize».
2 (UPLOAD_ERR_FORM_SIZE) – размер файла превышает значение
«MAX_FILE_SIZE», заданное в форме HTML.
3 (UPLOAD_ERR_PARTIAL) – файл был загружен лишь частично.
4 (UPLOAD_ERR_NO_FILE) – файл не был загружен.
Пример. Пусть на стороне клиента была отображена HTML-форма, содержащая
элемент для выбора файла:
<input type=file name="myphoto">
и пусть пользователь выбрал для передачи на сервер файл с именем «picture.gif».
После отправки формы, PHP-скрипт на сервере получит массив $_FILES, содержащий
один элемент – массив с именем «myphoto»:
(
[myphoto] => Array (
[name] => picture.gif
[type] => image/gif
[tmp_name] => E:\WINNT\TEMP\phpE1.tmp
[error] => 0
[size] => 1542
)
)
$_COOKIE
Массив содержит переменные, переданные в скрипт через механизм HTTP «cookie».
$_REQUEST
Массив, объединяющий данные массивов $_GET, $_POST, $_COOKIE. До версии 4.3 в
него также входили данные из массива $_FILES. Порядок включения переменных в
этот массив определяется параметром «variables_order». Порядок играет роль, если
массивы $_GET, $_POST и $_COOKIE содержат переменные с одинаковыми именами.
Из значений нескольких одноименных переменных в массиве $_REQUEST останется
то, которое было помещено последним.
Переменные окружения и переменные сервера
В PHP определено еще два суперглобальных массива: $_ENV и $_SERVER. Они
появились в версии 4.1, в более ранних версиях для тех же целей следует использовать
глобальные массивы $HTTP_ENV_VARS и $HTTP_SERVER_VARS соответственно.
Массив $_ENV содержит переменные окружения скрипта, состав которых зависит от
среды, в которой скрипт выполняется. Размещенные в массиве данные можно
получить с помощью функции getenv().
В массиве $_SERVER находятся сведения о самом скрипте, сервере, заголовке HTTPзапроса. Многие из элементов массива $_SERVER (но не все) описаны в
спецификации CGI (Common Gateway Interface) [W3/CGI] – они считаются
переменными окружения и их также можно получить с помощью функции getenv().
31
Переменные, начинающиеся с префикса «HTTP_», содержат информацию о полях
заголовка обрабатываемого HTTP-запроса. Например, HTTP_HOST, HTTP_REFERER,
HTTP_USER_AGENT.
PHP_SELF – содержит абсолютный путь (относительно корня web-сервера)
выполняемого в данный момент скрипта (с точки зрения клиента).
SCRIPT_NAME – содержит абсолютный путь реально выполняемого в данный момент
скрипта.
REQUEST_URI –содержит абсолютный путь скрипта вместе со строкой параметров.
QUERY_STRING – содержит строку параметров (строку запроса).
PATH_INFO – содержит т.н. «виртуальную» часть пути. Если сразу после имени
скрипта, который будет реально выполнен на сервере, в строке URL находятся символ
«/», оставшаяся часть URL (до начала строки параметров) помещается в переменную
«PATH_INFO». «Виртуальный» путь существует только с точки зрения клиента, в
действительности на сервере таких каталогов может не быть.
SCRIPT_FILENAME – абсолютный путь размещения на сервере выполняемого в
настоящий момент скрипта.
DOCUMENT_ROOT – абсолютный путь размещения корневого каталога web-сервера.
SERVER_NAME – имя сервера (или виртуального хоста), на котором выполняется
скрипт.
SERVER_PORT – номер порта, через который было установлено соединение.
SERVER_PROTOCOL – наименование и номер версии протокола, по которому
выполнен запрос.
REQUEST_METHOD – имя метода HTTP, которым выполнен запрос (GET, POST и
т.п.).
GATEWAY_INTERFACE – указание на используемую версию спецификации CGI.
Пример. Пусть запрошенный методом «GET» URL имеет вид:
http://localhost/test/testvars.php/aaa/bbb?asd=fgh
При этом реально выполняется скрипт «testvars.php». Корневой каталог web-сервера «d:\web\». Переменные будут содержать следующие значения:
PHP_SELF: /test/testvars.php/aaa/bbb
SCRIPT_NAME: /test/testvars.php
REQUEST_URI: /test/testvars.php/aaa/bbb?asd=fgh
QUERY_STRING: asd=fgh
PATH_INFO: /aaa/bbb
SCRIPT_FILENAME: d:/web/test/testvars.php
32
DOCUMENT_ROOT: d:/web
SERVER_NAME: localhost
SERVER_PORT: 80
SERVER_PROTOCOL: HTTP/1.1 (или HTTP/1.0)
REQUEST_METHOD: GET
GATEWAY_INTERFACE: CGI/1.1
argv – массив аргументов командной строки (в стиле Си). При работе скрипта под
управлением сервера, массив содержит строку запроса.
argc – содержит число аргументов командной строки.
REMOTE_ADDR, REMOTE_HOST и REMOTE_PORT – IP-адрес, имя хоста и номер
порта компьютера – источника поступившего запроса. Для того, чтобы имя хоста было
определено, в конфигурации Apache должен быть включен параметр
«HostnameLookups», разрешающий web-серверу автоматическое определение имени
хоста по IP-адресу. Также можно воспользоваться функцией PHP gethostbyaddr().
PHP_AUTH_USER, PHP_AUTH_PW и AUTH_TYPE – в случае, если клиент передал
данные для аутентификации в поле «Authorization» HTTP-заголовка, эти переменные
содержат имя пользователя, его пароль и имя схемы аутентификации. Переменные
доступны при работе PHP в качестве модуля Apache.
Волшебные кавычки
Зачастую данные, передаваемые пользователем через HTML-формы или
содержащиеся в элементах cookie, используются для добавления, обновления или
поиска в таблицах баз данных. Перед помещением данных в строку SQL-запроса,
содержащиеся в них служебные символы (одинарные и двойные кавычки, символы «\»
и NULL – символ с кодом «0») должны быть заэкранированы. Для этих целей
используется функция addslashes().
Однако, для экранирования данных, поступающих через запросы GET и POST, а также
механизм cookie, может быть использована возможность PHP-обработчика,
называемая «волшебные кавычки» (magic quotes). Если параметр «magic_quotes_gpc»
установлен в значение «On», все переменные, поступающие в массивы $_GET,
$_POST и $_COOKIE, экранируются автоматически. При этом если поступившие
данные предназначены не для базы данных, экранирование с них должно быть снято
функцией stripslashes(). Проверить, включены ли «волшебные кавычки», можно с
помощью функции get_magic_quotes_gpc().
На содержимое файлов, загруженных методом POST, «волшебные кавычки» не
влияют.
В листинге приведен фрагмент кода, в котором проверяется состояние параметра
«magic_quotes_gpc» и при необходимости снимается экранирование со всех элементов
массивов $_GET, $_POST и $_COOKIE. Содержимое массива $_REQUEST при этом
33
не меняется. При обработке учитывается, что элементы этих массивов могут быть
также массивами (обработка выполняется рекурсивно).
function mystripslashes(&$v) {
if ( is_array($v) )
return array_map("mystripslashes", $v);
else
return stripslashes($v);
}
if ( get_magic_quotes_gpc() ) {
$_GET = mystripslashes($_GET);
$_POST = mystripslashes($_POST);
$_COOKIE = mystripslashes($_COOKIE);
}
Функции PHP для работы с данными запроса и окружения
array apache_request_headers()
Функция возвращает массив, содержащий имена и значения полей заголовка HTTPзапроса. Строка запроса в этот массив не входит. Функция apache_request_headers()
добавлена в PHP версии 4.3. В более ранних версиях можно использовать
аналогичную функцию getallheaders(), которая в последующих версиях стала
синонимом функции apache_request_headers().
Функции apache_request_headers() и getallheaders() доступны только в случае, когда
PHP работает в качестве модуля web-сервера Apache.
См. также пример в описании функции apache_response_headers().
string getenv(name)
Функция возвращает значение переменной окружения по ее имени. Переменные
окружения также доступны через предопределенные массивы $_ENV и $_SERVER.
result is_uploaded_file(filename)
Функция проверяет, был ли указанный файл загружен методом POST протокола HTTP.
В качестве аргумента следует указывать имя временного файла. Функция возвращает
значение «true», если указанный файл действительно был загружен по HTTP и «false»
в противном случае. Функция доступна в PHP версии 4.0.3 и выше.
Пример:
if ( is_uploaded_file($_FILES['myfile']['tmp_name'] ) {
...
}
result move_uploaded_file(filename, destination)
34
Функция переносит файл, загруженный через HTTP, в указанное место. Аргумент
filename – имя временного файла, destination –путь и имя для нового местоположения
файла. Функция возвращает значение «false», если указанный файл не был загружен
через HTTP, или по какой-либо причине перенести файл не удалось, и «true» в случае
успеха. Функция доступна в PHP версии 4.0.3 и выше.
Пример:
$filesdir = $_SERVER['DOCUMENT_ROOT'] . '/files/';
$src = $_FILES['myfile']['tmp_name'];
$dst = $filesdir . $_FILES['myfile']['name'];
if ( move_uploaded_file($src, $dst) {
... // OK
}
result import_request_variables(types [, prefix])
Функция import_request_variables() копирует переменные, полученные через методы
GET, POST и механизм cookies, в пространство глобальных переменных. Использовать
функцию имеет смысл, если автоматическая регистрация (параметр PHP
register_globals) запрещена. Аргумент types – строка, которая может содержать буквы
«g», «p» и «c». Буквы указывают, переменные каких типов и в каком порядке должны
быть зарегистрированы в качестве глобальных. Регистр букв не играет роли, а порядок
имеет значение, если у переменных из разных источников совпадают имена. Значения
переменных, регистрируемых последними, замещают значения ранее
зарегистрированных одноименных переменных. Необязательный аргумент prefix –
строка, которая будет добавлена в качестве префикса при задании имен глобальных
переменных. Функция доступна в PHP версии 4.1 и выше.
Пример:
import_request_variables("gp", "uservar_");
Переменные, загруженные методами GET и POST, регистрируются в качестве
глобальных. Имена переменных будут начинаться с «uservar_».
См. также функцию extract().
result get_magic_quotes_gpc()
Функция возвращает текущую установку параметра «magic_quotes_gpc» (волшебные
кавычки). «Разрешено» - значение «1», «запрещено» - значение «0».
Формирование заголовка ответа
Интерпретатор PHP самостоятельно формирует по умолчанию некоторые поля
заголовка – например, «Content-Type» (значение по умолчанию для «Content-Type»
определяется параметром «default_mimetype» и обычно равно «text/html», набор
символов может быть задан параметром «default_charset»). Код статуса по умолчанию
– 200.
35
Для задания желаемых значений полей заголовков и кода статуса, в PHP используется
функция header(). Передаваемые клиенту элементы cookie также помещаются в поля
заголовка. Для установки значений cookie используется функция setcookie(). При
необходимости для этих целей также может быть использована функция header().
Все заголовки должны быть определены до того, как будет начато формирование тела
ответа. Поля заголовка накапливаются в процессе интерпретации скрипта, но, как
только в стандартный поток вывода начинают поступать данные, сервер отсылает
клиенту заголовок и переходит к передаче тела. Даже ошибочно помещенные HTMLконтекст пробел или пустая строка вынуждают интерпретатор отправить клиенту
заголовок и начать передачу тела сообщения. После начала передачи тела, попытка
установить поля заголовка вызовет сообщение об ошибке. Функция headers_sent()
позволяет проверить, были ли уже отосланы клиенту поля заголовка. Функция
apache_request_headers() возвращает массив полей заголовка, сформированных на
текущий момент.
Чаще всего PHP-скрипты используются для формирования HTML-содержимого,
отображаемого в окне броузера. Именно поэтому медиа-тип по умолчанию –
«text/html». Однако общение между броузером и сервером не исчерпывается только
запросом и передачей HTML-страниц. Сервером также может передавать клиенту
данные и других типов – например, изображения, встраиваемые внутрь HTMLдокументов, файлы архивов, которые должны быть сохранены пользователем
локально или файлы любого другого формата, предназначенные для обработки какимто специфичным приложением.
Для документов, содержащих текст, в поле «Content-Type» также нужно указывать
набор символов. Ниже приведены два варианта заголовка для документов,
содержащих кириллический текст в кодировке windows. Первый – для HTMLдокумента, второй – для неформатированного текста:
header('Content-Type: text/html; charset=windows-1251');
header('Content-Type: text/plain; charset=windows-1251');
Медиа-тип (поле заголовка «Content-Type») сообщает броузеру, как именно следует
поступить с содержащимися в ответе данными. Если броузеру известно, какое
приложение отвечает за обработку данных указанного типа, он может передать данные
этому приложению. Именно медиа-тип, а не расширение имени файла, указанного в
строке URL, определяет способ обработки. Поэтому при формировании заголовка
следует обязательно установить верное значение поля «Content-Type».
В частности, PHP-скрипт, выполняемый на сервере, может иметь расширение
«HTML», но при этом он не является статическим документом и способен
формировать данные любого типа.
Пример. Пусть имеется URL некоторого документа:
http://www.example.com/getimage.html?id=5
и пусть файл «getimage.html» является PHP-скриптом, который возвращает данные,
указывая в качестве медиа-типа «image/gif» (изображение). Формируемое им
36
изображение может быть встроено в HTML-документ с помощью тега следующего
вида:
<img src="http://www.example.com/getimage.html?id=5">
и будет обрабатываться броузером именно как изображение благодаря заданному
медиа-типу.
С другой стороны, если пользователю требуется сохранить формируемый скриптом
файл, броузер должен предложить для файла имя. При отсутствии иной информации,
броузер попытается сформировать имя файла на основе имени документа, указанного
в запрошенном URL.
Поскольку в конкретных операционных системах для определения способа обработки
файла (его медиа-типа) зачастую используется расширение имени файла, при
сохранении файла броузер должен присвоить файлу адекватное расширение. Так, при
попытке сохранить файл из приведенного выше примера, броузер может
сформировать имя наподобие «getimage.html.gif». Конечно, пользователь способен
самостоятельно переименовать файл, но лучше, если сервер «подскажет» броузеру
подходящее имя.
Кроме того, при получении файла, броузер должен принимать решение: открыть файл
немедленно для обработки (если ему известно, как обрабатывать данные этого типа)
или предложить пользователю сохранить его. В некоторых случаях сервер может
«помочь» броузеру определить предпочтительный вариант.
Для сообщения клиенту дополнительных сведений о передаваемом файле
используется поле заголовка «Content-Disposition» [RFC 2183]. Поле может принимать
одно из двух значений: «inline» или «attachment». В первом случае сервер
«рекомендует» броузеру сразу открыть полученный файл (с помощью подходящего
приложения), во втором – предложить пользователю сохранить его. Параметр
«filename» указывает предпочтительное имя файла при сохранении. Содержимое этого
поля имеет, скорее, рекомендательное назначение и не запрещает броузеру
действовать «по обстановке».
В приведенном выше примере, если картинка сразу должна отображаться, поля
заголовка могут быть определены следующим образом:
header('Content-Type: image/gif');
header('Content-Disposition: inline');
Если некоторый скрипт передает броузеру файл zip-архива, который следует
сохранить на диске, поля заголовка могут иметь такой вид:
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="myarchive.zip"');
Другой, альтернативный, способ заставить броузер присвоить файлу «правильное»
имя – добавить это имя в URL в виде виртуального пути. Приведенный выше URL
может быть заменен на такой:
http://www.example.com/getimage.html/photo5.gif?id=5
37
При этом на сервере по прежнему будет выполняться скрипт «getimage.html», но
броузер «обманывается» и полагает, что истинное имя файла – «photo5.gif».
Поле заголовка «Content-Length», указывающее размер передаваемых данных, не
является обязательным, поскольку броузер способен иным путем определить
окончание передачи (например, по разрыву соединения сервером), но при пересылке
файлов большого размера его желательно задавать, чтобы броузер смог оценить время,
необходимое для получения файла. Броузер будет информировать пользователя о
полном размере файла и текущем состоянии процесса загрузки.
Формирование тела ответа
Тело ответа формируется в PHP -скрипте путем вывода данных в стандартный
выходной поток. Вывод происходит при вызове соответствующих операторов и
функций, а также при размещении данных в HTML-контексте. При этом данные
выдаются клиенту по мере поступления.
Если клиенту передаются какие-либо данные с жестко определенным двоичным
форматом (например, архив или изображение), особенно важно не допускать вывода
любых, не предусмотренных посторонних символов. Нужно следить, чтобы не было
случайных пустых строк или пробелов, помещенных в HTML-контекст скрипта.
Такую ошибку легко совершить, но обнаружить ее иногда бывает сложнее.
Функции PHP поддержки протокола HTTP на стороне сервера
header(string [, replace [, code]])
Функция header() используется для формирования полей заголовка HTTP-ответа или
замены значений уже определенных полей. Первый аргумент - строка, содержащая
имя и значение поля заголовка. Необязательный второй аргумент определяет действия
в том случае, если поле с таким именем уже присутствует в заголовке. Значение «true»
(по умолчанию) определяет, что значение поля следует заменить новым, значение
«false» - добавить второе поле с тем же именем. Аргумент code (добавлен, начиная с
версии 4.3) позволяет одновременно задать код статуса.
Строка статуса также может быть также определена целиком функцией header().
Независимо от последовательности определения различных полей функцией header(),
строка статуса будет передана клиенту первой (в соответствии с требованием
протокола HTTP).
Пример:
header("Content-type: text/html");
header("HTTP/1.0 301 Moved Permanently");
header("Location: http://www.example.com");
При определении поля Location PHP автоматически меняет код статуса на 302, если не
был установлен какой-либо из кодов 3xx.
38
result setcookie(name [, value [, expire [, path [, domain [,
secure]]]]])
Функция setcookie() устанавливает значение cookie, которое должно быть передано
клиенту. Аргумент name – имя, под которым cookie будет сохранено. value –
устанавливаемое значение.
expire – время, после которого клиент будет считать это cookie устаревшим и удалит
его. Время задается в формате Unix timestamp (число секунд от начала «эры Unix»).
Поскольку параметр «устаревания» обычно отсчитывается от текущего момента
времени, для его определения удобно использовать функцию time(), прибавляя к ее
результату нужное число секунд. Если значение аргумента expire установлено «0»,
время «устаревания» для cookie не будет передано клиенту. В этом случае cookie будет
уничтожено по окончании сеанса работы пользователя (при закрытии окна броузера).
path – путь на сервере. При запросе к ресурсам, размещенным в пределах этого пути,
клиент будет передавать серверу данный cookie. Если создаваемое cookie должно быть
доступно на всем сервере, указывается корневой каталог – «/». Если аргумент path не
задан, по умолчанию клиент будет использовать путь, принадлежащий текущему
ресурсу.
domain – доменное имя, в пределах которого действует cookie. Например, если задано
значение «.example.com», данное cookie будет передаваться клиентом серверу при
обращении к ресурсам указанного домена и всех его поддоменов
(«www.example.com», «test.example.com» и т.п.). Если аргумент не задан, по
умолчанию используется имя хоста текущего ресурса.
Если аргумент secure равен «1», данное cookie должно передаваться только клиентам,
которые обратились через безопасное HTTPS-соединение. Функция возвращает
значение «true» при успешном завершении и «false» в противном случае.
Сохраненное значение cookie будет передано клиентом серверу при следующем
обращении. Полученные сервером cookie доступны в PHP-скрипте как элементы
глобальных массивов $HTTP_COOKIE_VARS (считается устаревшим), $_COOKIE и
$_REQUEST (доступны, начиная с версии PHP 4.1).
Поскольку cookie передается как поле HTTP-заголовка, для setcookie() действуют те
же ограничения, что и для функции header(). Она должна вызываться до того, как
будет начата передача клиенту тела ответа.
Вместо функции setcookie() при необходимости можно использовать header(). Следует
соблюдать формат заголовка Set-Cookie. В частности, время «устаревания» должно
задаваться в формате «Wdy, DD-Mon-YY HH:MM:SS GMT» (время по Гринвичу) [RFC
2109].
Пример.
39
Обе приведенные ниже функции выполняют одинаковые действия (срок жизни,
определенный для cookie – 1 час):
setcookie("mycookie", "myvalue", time()+3600, "/");
header("Set-Cookie: mycookie=myvalue; expires= ".
gmdate("D, d-M-Y H:i:s \G\M\T", time()+3600)."; path=/");
При этом клиент получит приблизительно такой заголовок:
Set-Cookie: mycookie=myvalue; expires=Sun, 28-Mar-2004 00:45:28 GMT;
path=/
Имена cookie могут быть заданы как имена массивов (с квадратными скобками):
setcookie("mycookies[0]", "myvalue0", time()+3600, "/");
setcookie("mycookies[1]", "myvalue1", time()+3600, "/");
setcookie("mycookies[2]", "myvalue2", time()+3600, "/");
Эти элементы будут переданы клиенту, сохранены и впоследствии переданы клиентом
серверу как три отдельных cookie. Но, после их поступления на сервер, в PHP будет
образован массив, содержащий три элемента.
Пример:
print_r( $_COOKIE['mycookies'] );
result headers_sent([file [, line]])
Функция headers_sent() позволяет проверить, были ли заголовки отосланы клиенту.
Если заголовки отосланы, будет возвращено значение «true», если еще нет – «false».
Необязательные аргументы file и line (добавлены в PHP версии 4.3) –переменные, в
которые будут записаны имя файла и номер строки скрипта, где была инициирована
отправка заголовков.
Использование функции headers_sent() позволит избежать ошибок, вызванных
обращением к функциям header() или setcookie() уже после отправки заголовков.
array apache_response_headers()
Функция возвращает массив, содержащий имена и значения полей заголовка HTTPответа, которые уже отправлены или будут отправлены клиенту. Строка статуса в этот
массив не входит. Функция добавлена в PHP версии 4.3.
Функция apache_response_headers() доступны только в случае, когда PHP работает в
качестве модуля web-сервера Apache.
См. также описание функции apache_request_headers().
Механизм cookies
Буквальный перевод слова «cookie» - домашнее печенье. Предполагается, что каждая
хорошая хозяйка должна иметь собственный рецепт, отличающий ее продукт от всех
других. Видимо, эта аналогия была использована при разработке спецификации
cookies [NETSCAPE/COOKIES].
40
Спецификация добавляет в протокол HTTP возможности, позволяющие серверу
сохранять некоторые данные на стороне клиента (средствами броузера). При
последующих обращениях клиента к тем же ресурсам, броузер передает сохраненные
значения серверу. Этот механизм позволяет серверу отличать одного пользователя от
другого, не расходуя при этом собственные ресурсы на «запоминание» информации о
пользователях. В отличие от механизма аутентификации, когда от пользователя
требуется явно ввести некоторую идентифицирующую его информацию, прием и
передача cookies происходят незаметно для самого пользователя.
Как различать пользователей в пределах одного компьютера – проблема броузера и
операционной системы. В многопользовательских ОС для каждого
зарегистрированного в системе пользователя должно существовать собственное
пространство данных cookies. Броузер должен обращаться к данным именно того
пользователя, который в настоящий момент с ним работает.
Сервер может использовать cookies для запоминания персональных данных
пользователя, его предпочтениях или о предыстории своего диалога с ним («…так на
чем же мы остановились в прошлый раз?»). Например, при первом посещении
страницы сервер предлагает пользователю ввести свое имя (которое будет сохранено в
виде cookie), а при последующих посещениях – приветствует его по имени.
Другой пример: пользователь, пришедший в электронный магазин, изучает его
ассортимент и отбирает некоторые товары в свою «корзину». До тех пор, пока
пользователь не пожелает расплатиться, его личность серверу глубоко безразлична, и
хранить содержимое корзины в собственной базе данных он не будет (если
пользователь передумает покупать, потом придется искать и вычищать мусор).
Перечень отобранных товаров при этом может запоминаться посредством cookies.
Для передачи cookies клиенту, сервер использует поле HTTP-заголовка «Set-Cookie».
Для добавления этого поля в заголовок в PHP-скрипте используется функция
setcookie(). Также можно при необходимости применять функцию header(). От клиента
серверу значения cookies передаются через поля заголовка «Cookie» и в PHP доступны
через суперглобальные массивы $_COOKIE и $_REQUEST.
При передаче броузеру каждого cookie, сервер определяет область его действия –
доменное имя и путь. Если сервер не задал доменное имя, броузер должен
использовать имя того хоста, к которому он выполнял запрос. Если не задан путь –
нужно использовать путь ресурса, в ответ на запрос к которому был получен этот
элемент cookie.
При выполнении запроса к некоторому ресурсу, броузер должен передавать на сервер
те cookies, в область действия которых этот ресурс попадает. Ресурс попадает в
область действия cookie, если доменное имя cookie содержится в его доменном имени
(домен ресурса совпадает с доменом cookie или является его поддоменом) и путь
cookie содержится в его пути.
41
Элементы cookie (с точки зрения броузера) различаются между собой сочетанием
имени и области действия. Потому, один и тот же ресурс может получить от броузера
несколько cookie с одинаковым именем, но с разными областями действия (одна из
областей более широкая, чем другая). Таких ситуаций стоит избегать: во-первых,
броузер передает серверу только имена и значения cookie, но не указывает область их
действия (не установить, чья область действия шире); во-вторых, в PHP из нескольких
cookie с одинаковыми именами останется какое-то одно (остальные будут потеряны).
Для элемента cookie должно быть определено время жизни, точнее – время, когда
броузер должен будет считать его устаревшим и удалить. Если время устаревания не
задано, элемент будет существовать только в течение одного сеанса работы – пока
пользователь не закроет окно броузера.
Механизм cookie не слишком надежен, поскольку зависит от способа его реализации в
броузере. По соображениям конфиденциальности броузер может отказываться
сохранять принятые cookie. Влияют также другие пользовательские настройки
(например, неверно установленные дата/время).
В листинге 5 приведен пример, иллюстрирующий работу серверного скрипта с
объектами cookie и HTTP-заголовками. При каждом обращении клиента к этому
скрипту (с интервалом менее часа), значение cookie «counter» будет увеличиваться на
«1». Если больше часа данный клиент к скрипту не обращался, cookie «counter» будет
удалено и отсчет начнется с «0».
<?
header("Cache-Control: no-cache");
header("Pragma: no-cache");
header("Content-Type: text/html; charset=windows-1251");
if( isset($_COOKIE['counter']) )
$cnt = $_COOKIE['counter'];
else
$cnt = 0;
setcookie ("counter", $cnt+1, time()+3600, "/");
if( $cnt>0 ) {
print "Вы на этой странице уже были " .$cnt. " раз(а)";
} else {
print "Вы на этой странице впервые за последний час";
}
?>
Листинг 5 (файл «test_cookie.php»)
Функции PHP для работы с файлами
resource fopen(filename, mode)
Функция открывает файл с именем filename в режиме, заданном строкой mode.
Возвращает переменную-ресурс для последующих обращений к открытому файлу.
42
Допустимые режимы:
 r – открыть для чтения
 r+ – открыть файл для чтения и записи, не очищая его
 w – открыть только для записи, если существует – очистить
 w+ – открыть для чтения и записи, если существует – очистить
 a – открыть только для записи, поместив указатель в конец файла
 a+ – открыть для чтения и записи, поместив указатель в конец файла
bool fclose(handle)
Закрыть ранее открытый файл.
int filesize(filename)
Возвращает размер файла с заданным именем (в байтах).
bool feof(handle)
Возвращает true, если достигнут конец файла.
array file(filename)
Читает содержимое файла с заданным именем построчно и возвращает массив,
содержащий строки. Не требуется предварительного открытия функцией fopen.
Конструкция join( "", file( filename ) ) помещает все содержимое файла в одну
переменную-строку.
string fread(handle, length)
Читает указанное число байт из открытого файла. Конструкция fread( handle, filesize(
filename ) ) позволяет прочитать файл целиком.
int fwrite(handle, string)
Записывает данные из переменной-строки в открытый файл.
int readfile(filename)
Передает содержимое файла с заданным именем целиком в выходной поток PHP.
bool unlink(filename)
Удаляет файл с заданным именем.
43
Скачать