Добро пожаловать!
Здесь вы можете найти ответ на интересующий вас вопрос в отрасли сайтостроения, познакомится ближе с web технологиями и web стандартами.

Статьи

HTML-формы. Массивы $_POST и $_GET

HTML-формы. Методы отправки данных на сервер

С HTML-формами вы наверняка уже встречались:

<form method="GET" action="/cgi-bin/form_handler.cgi">
  Введите Ваше имя: <input type="text" name="name">
  <br/>
  <input type="submit" name="okbutton" value="OK" />
</form>

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

Введите Ваше имя:

Тэг <form>, имеющий парный завершающий тэг </form>, собственно и задает форму. Его атрибуты — оба необязательные:

  • action — указывает URL (полный или относительный), на который будет отправлена форма. Если этот атрибут не указать, большинство браузеров (точнее говоря, все известные мне браузеры) отправляют форму на текущий документ, то есть "саму на себя". Это удобное сокращение, но по стандарту HTML атрибут action обязателен.
  • method — способ отправки формы. Их два.
    • GET — отправка данных формы в адресной строке.
      Вы могли заметить на различных сайтах присутствие в конце URL символа "?" и следующих за ним данных в формате параметр=значение. Здесь "параметр" соответствует значению атрибута name элементов формы (см. ниже про тэг <input>), а "значение" — содержимому атрибута value (в нем, например, содержится ввод пользователя в текстовое поле того же тэга <input>).
      Для примера — попробуйте поискать что-нибудь в Яндексе и обратите внимание на адресную строку браузера. Это и есть способ GET.
    • POST — данные формы отправляются в теле запроса. Если не совсем понятно (или совсем непонятно), что это такое — не беспокойтесь, скоро мы к этому вопросу вернемся.
    Если атрибут method не указан — подразумевается GET.

Тэг <input> — задает элемент формы, определяемый атрибутом type:

  • Значение "text" задает однострочное текстовое поле ввода
  • Значение "submit" задает кнопку, при нажатии которой происходит отправка формы на сервер

Возможны и другие значения (да и <input> — не единственный тэг, задающий элемент формы).

Итак, что же происходит, когда мы нажимаем кнопку "OK"?

  1. Браузер просматривает входящие в форму элементы и формирует из их атрибутов name и value данные формы. Допустим, введено имя Vasya. В этом случае данные формы - name=Vasya&okbutton=OK
  2. Браузер устанавливает соединение с сервером, отправляет на сервер запрос документа, указанного в атрибуте action тэга <form>, используя метод отправки данных, указанный в атрибуте method (в данном случае - GET), передавая в запросе данные формы.
  3. Сервер анализирует полученный запрос, формирует ответ, отправляет его браузеру и закрывает соединение
  4. Браузер отображает полученный от сервера документ

Отправка того же запроса вручную (с помошью telnet) выглядит следующим образом (предположим, что доменное имя сайта — www.example.com):

telnet www.example.com 80
GET /cgi-bin/form_handler.cgi?name=Vasya&okbutton=OK HTTP/1.0\r\n
Host: www.example.com\r\n
\r\n

Как вы, скорее всего, уже догадались, нажатие submit-кнопки в форме с методом отправки "GET" аналогично вводу соответствующего URL (со знаком вопроса и данными формы в конце) в адресной строке браузера:

http://www.example.com/cgi-bin/form_handler.cgi?name=Vasya&okbutton=OK

На самом деле, метод GET используется всегда, когда вы запрашиваете с сервера какой-либо документ, просто введя его URL, или щелкнув по ссылке. При использовании <form method="GET" ... >, к URL просто добавляются знак вопроса и данные формы.

Возможно, все эти технические подробности и упражнения с telnet-ом кажутся вам невероятно скучными и даже ненужными ("а при чем тут PHP?"). А зря. :) Это основы работы по протоколу HTTP, которые необходимо знать назубок каждому Web-программисту, и это не теоретические знания — все это пригодится на практике.

Теперь заменим первую строку нашей формы на следующую:

<form method="POST" action="/cgi-bin/form_handler.cgi">

Мы указали метод отправки "POST". В этом случае данные отправляются на сервер несколько другим способом:

telnet www.example.com 80
POST /cgi-bin/form_handler.cgi HTTP/1.0\r\n
Host: www.example.com\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 41263\r\n
\r\n
name=Vasya&okbutton=OK

При использовании метода POST данные формы отправляются уже после "двух Enter-ов" — в теле запроса. Все, что выше — на самом деле заголовок запроса (и когда мы использовали метод GET, данные формы отправлялись в заголовке). Для того, чтобы сервер знал, на каком байте закончить чтение тела запроса, в заголовке присутствует строка Content-Length; о том же, что данные формы будут переданы виде параметр1=значение1&параметр2=значение2..., причем значения передаются в виде urlencode — то есть, точно так же, как и с помощью метода GET, но в теле запроса, — серверу сообщает заголовок Content-Type: application/x-www-form-urlencoded.

Преимущество метода POST — отсутствие ограничения на длину строки с данными формы.

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

При использовании POST-формы, в ее атрибуте action можно указать после знака вопроса и параметры GET-формы. Таким образом, метод POST включает в себя и метод GET.

Массивы $_GET и $_POST

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

Рассмотрим простой пример:

<html>
<body>
<?php
  
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    echo 
'<h1>Привет, <b>' $_POST['name'] . '</b></h1>!';
  }
?>
<form method="POST" action="<?=$_SERVER['PHP_SELF']?>">
Введите Ваше имя: <input type="text" name="name">
<br>
<input type="submit" name="okbutton" value="OK">
</form>
</body>
</html>

Форма, приведенная в строках 8-12, содержит два элемента: name и okbutton. Атрибут method указывает метод отправки формы POST, атрибут же action, указывающий URL, на который отправляется форма, заполняется значением серверной переменной PHP_SELF - адресом выполняемого в данный момент скрипта.

<?=$_SERVER['PHP_SELF']?> — сокращенная форма записи для <? echo $_SERVER['PHP_SELF']; ?>.

Предположим, в поле name мы ввели значение Вася, и нажали кнопку OK. При этом браузер отправляет на сервер POST-запрос. Тело запроса: name=Вася&okbutton=OK. PHP автоматически заполняет массив $_POST:

$_POST['name'] = 'Вася'
$_POST['okbutton'] = 'OK'

В действительности, значение "Вася" отправляется браузером в urlencode-виде; для кодировки windows-1251 это значение выглядит как %C2%E0%F1%FF. Но, поскольку PHP автоматически осуществляет необходимое декодирование, мы можем "забыть" об этой особенности — пока не придется работать с HTTP-запросами вручную.

Так как в теле запроса указываются только имена и значения, но не типы элементов форм, PHP понятия не имеет, соответствует $_POST['name'] строке ввода, кнопке, или списку. Но эта информация нам, в общем-то, совершенно не нужна. :)

Поскольку знать, что написано на кнопке submit, нам необязательно, в строке 11 можно удалить атрибут name, сократив описание кнопки до <input type="submit" value="OK">. В этом случае, браузер отправит POST-запрос name=Вася.

А теперь — то же самое, но для GET-формы:

<html>
<body>
<?php
  
if (isset($_GET['name'])) {
    echo 
'<h1>Привет, <b>' $_GET['name'] . '</b></h1>!';
  }
?>
<form action="<?=$_SERVER['PHP_SELF']?>">
Введите Ваше имя: <input type="text" name="name">
<br/>
<input type="submit" value="OK">
</form>
</body>
</html>

В строке 8 можно было бы с таким же успехом написать <form method="GET">: GET — метод по умолчанию. В этот раз браузер отправляет GET-запрос, который равносилен вводу в адресной строке адреса: http://адрес-сайта/имя-скрипта.php?name=Вася.

PHP с GET-формами поступает точно так же, как и с POST, с тем отличием, что заполняется массив $_GET.

Кардинальное же отличие — в строке 4. Поскольку простой ввод адреса в строке браузера является GET-запросом, проверка if ($_SERVER['REQUEST_METHOD'] == 'GET') бессмысленна. Поэтому мы прибегаем к конструкции isset(), которая возвращает true, если данная переменная определена (т.е. ей было присвоено значение), и false — если переменная не определена. Если форма была заполнена — как вы уже поняли, PHP автоматически присваивает $_GET['name'] соответствующее значение.

Cпособ проверки с помощью isset() — универсальный, его можно было бы использовать и для POST-формы. Более того, он предпочтительнее, так как позволяет выяснить, какие именно поля формы заполнены.

Немного более сложный пример.

<html>
<body>
<?php
  
if (isset($_POST['name'], $_POST['year'])) {
    if (
$_POST['name'] == '') {
      echo 
'Укажите имя!<br>';
    } else if (
$_POST['year'] < 1900 || $_POST['year'] > 2004) {
      echo 
'Укажите год рождения! Допустимый диапазон значений: 1900..2004<br/>';
    } else {
      echo 
'Здравствуйте, ' $_POST['name'] . '!<br/>';
      
$age 2004 $_POST['year'];
      echo 
'Вам ' $age ' лет<br>';
    }
    echo 
'<hr>';
  }
?>
<form method="post" action="<?=$_SERVER['PHP_SELF']?>">
Введите Ваше имя: <input type="text" name="name">
<br/>
Введите Ваш год рождения: <input type="text" name="year">
<br/>
<input type="submit" value="OK">
</form>
</body>
</html>

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

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

<html>
<body>
<?php
  $name 
= isset($_POST['name']) ? $_POST['name'] : '';
  
$year = isset($_POST['year']) ? $_POST['year'] : '';

  if (isset(
$_POST['name'], $_POST['year'])) {
    if (
$_POST['name'] == '') {
      echo 
'Укажите имя!<br/>';
    } else if (
$_POST['year'] < 1900 || $_POST['year'] > 2004) {
      echo 
'Укажите год рождения! Допустимый диапазон значений: 1900..2004<br/>';
    } else {
      echo 
'Здравствуйте, ' $_POST['name'] . '!<br/>';
      
$age 2004 $_POST['year'];
      echo 
'Вам ' $age ' лет<br/>';
    }
    echo 
'<hr>';
  }
?>
<form method="post" action="<?=$_SERVER['PHP_SELF']?>">
Введите Ваше имя: <input type="text" name="name" value="<?=$name?>">
<br/>
Введите Ваш год рождения: <input type="text" name="year" value="<?=$year?>">
<br/>
<input type="submit" value="OK">
</form>
</body>
</html>

Несколько непонятными могут оказаться строки 4 и 5. Все очень просто: строку 4 можно было бы записать так:

if (isset($_POST['name']))
  
$name $_POST['name'];
else
  
$name '';

Может возникнуть вопрос — почему бы не выбросить строки 4-5 и не написать:

Введите Ваше имя: <input type="text" name="name" value="<?=$_POST['name']?>"><br/>
Введите Ваш год рождения: <input type="text" name="year" value="<?=$_POST['year']?>">

Дело в том, что, если эти POST-переменные не определены — а так и будет, если форму еще не заполняли, — PHP выдаст предупреждения об использовании неинициализированных переменных (причем, вполне обоснованно: такое сообщение позволяет быстро находить труднообнаружимые опечатки в именах переменных, а также предупреждает о возможных "дырах" на сайте). Можно, конечно, поместить код с isset прямо в форму, но получится слишком громоздко.

Разобрались? А теперь попробуйте найти ошибку в приведенном коде. Ну, не совсем ошибку, — но недочет.

htmlspecialchars()

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

Введите Ваше имя: <input type="text" name="name" value="Ва"ся">

То есть — ничего хорошего. А если бы хитрый пользователь ввел JavaScript-код?

Для решения этой проблемы необходимо воспользоваться функцией htmlspecialchars(), которая заменит служебные символы на их HTML-представление (например, кавычку — на &quot;):

<html>
<body>
<?php
  $name 
= isset($_POST['name']) ? htmlspecialchars($_POST['name']) : '';
  
$year = isset($_POST['year']) ? htmlspecialchars($_POST['year']) : '';

  if (isset(
$_POST['name'], $_POST['year'])) {
    if (
$_POST['name'] == '') {
      echo 
'Укажите имя!<br/>';
    } else if (
$_POST['year'] < 1900 || $_POST['year'] > 2004) {
      echo 
'Укажите год рождения! Допустимый диапазон значений: 1900..2004<br/>';
    } else {
      echo 
'Здравствуйте, ' $name '!<br/>';
      
$age 2004 $_POST['year'];
      echo 
'Вам ' $age ' лет<br/>';
    }
    echo 
'<hr>';
  }
?>
<form method="post" action="<?=$_SERVER['PHP_SELF']?>">
Введите Ваше имя: <input type="text" name="name" value="<?=$name?>">
<br/>
Введите Ваш год рождения: <input type="text" name="year" value="<?=$year?>">
<br/>
<input type="submit" value="OK">
</form>
</body>
</html>

Повторите опыт и убедитесь, что теперь HTML-код корректен.

Запомните — функцию htmlspecialchars() необходимо использовать всегда, когда выводится содержимое переменной, в которой могут присутствовать спецсимволы HTML.

phpinfo()

Функция phpinfo() — одна из важнейших в PHP. Она выводит информацию о настройках PHP, значения всевозможных конфигурационных переменных...

Почему я упоминаю о ней в статье, посвященной формам? phpinfo() — удобнейшее средство отладки. phpinfo(), помимо прочего, выводит значения всех $_GET, $_POST и $_SERVER переменных. Так что, если переменная формы "потерялась", самый простой способ обнаружить, в чем дело — воспользоваться функцией phpinfo(). Для того, чтобы функция выводила только значения переменных (и вам не пришлось прокручивать десяток страниц), ее следует вызвать следующим образом: phpinfo(INFO_VARIABLES);, или — что абсолютно то же самое — phpinfo(32);.

Пример:

<html>
<body>
<form method="post" action="<?=$_SERVER['PHP_SELF']?>">
Введите Ваше имя: <input type="text" name="name">
<input type="submit" value="OK">
</form>
<?php
  phpinfo
(32);
?>
</body>
</html>

Или, например, такая ситуация: вы хотите узнать IP-адрес посетителя. Вы помните, что соответствующая переменная хранится в массиве $_SERVER, но — вот незадача — забыли, как именно переменная называется. Опять же, вызываем phpinfo(32);, ищем в табличке свой IP-адрес и находим его — в строке $_SERVER["REMOTE_ADDR"].