Обработка данных из HTML-форм при помощи PHP

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

Итак, данные из HTML-форм отправляются при помощи GET или POST HTTP-запросов. В GET-запросе параметры находятся непосредственно в URL и видны в адресной строке браузера. В POST-запросе данные находятся в теле HTTP-пакета. Данные получает страница, указанная в атрибуте action тега HTML-формы form, например, PHP-скрипт.

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

С точки зрения PHP принципиального отличия между GET и POST-параметрами нет. GET-параметры размещаются в глобальном массиве $_GET, POST — в $_POST.

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

<form method="GET" action="<?php echo $_SERVER['PHP_SELF']; ?>">
  <input type="text" name="name" /><br />
  <input type="submit" value="Send" />
</form>

Сразу обратите внимание, что значение атрибута action представляет собой PHP-вставку. Переменная $_SERVER['PHP_SELF'] содержит имя и путь текущего выполняемого PHP-скрипта относительно корневого каталога веб-сервера. Таким образом, action всегда будет указывать на самого себя, в независимости от расположения и имени файла.

Определить, что данные были переданы можно несколькими способами. Например, можно проверять размер массива $_GET (или $_POST в случае с POST-запросом). Если размер ненулевой, то были переданы какие-то данные:

if ( count($_GET) > 0 )
{
    echo 'GET-параметры были приняты!';
    //--Здесь можно обрабатывать принятые данные
}

Давайте теперь добавим какое-то ограничение на вводимые данные. Например:

Введите ваше имя (минимум 3 символа): <input type="text" name="name" /><br />

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

if ( count($_GET) > 0 ) //--Если были приняты данные из HTML-формы
{
    $name = $_GET['name']; //--Получаем имя из GET-параметров
    if ( strlen($name) >= 3 ) //--Проверяем, допустимая ли длина имени
    {
        //--Здесь обрабатываем полученное имя
        echo 'Спасибо! Ваше имя успешно получено!';
        exit; //--Завершаем работу PHP-скрипта. В этом случае HTML-форма выведена не будет
    }
    else //--Иначе предупреждаем пользователя
    {
        echo 'Вы ввели слишком короткое имя!';
    }
 
}

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

Введите ваше имя (минимум 3 символа): <input type="text" name="name" value="<?php echo $name; ?>" /><br />

Тут есть два замечания. Во-первых, при отсутствии GET-данных переменная $name становится не определена. В этом случае ей лучше задать пустое значение:

$name = '';

Во-вторых, пользователь умышленно или неумышленно может ввести в поле ввода имени часть HTML-кода, например:

" />

и тогда при подставлении данных в value мы получим следующее:

<input type="text" name="name" value="" />" /><br />

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

$name = $_GET['name'];

Обработаем параметр с помощью PHP-функции htmlspecialchars:

$name = htmlspecialchars($_GET['name']);

Данная функция заменяет в строке одинарные, двойные кавычки, треугольные скобки и амперсанд на соответствующие коды HTML-спецсимволов, что позволяет, допустим, выводить HTML-код в виде текста без обработки браузером. Таким образом текст гарантированно не попадет за пределы значения value.

И еще, условие проверки длины

if ( strlen($name) >= 3 )

лучше заменить на

if ( strlen($_GET['name']) >= 3 )

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

<?php
 
  $name = ''; //--Инициализируем переменную name
 
  if ( count($_GET) > 0 ) //--Если были приняты данные из HTML-формы
  {
      $name = htmlspecialchars($_GET['name']); //--Получаем имя из GET-параметров
      if ( strlen($_GET['name']) >= 3 ) //--Проверяем, допустимая ли длина имени
      {
          //--Здесь обрабатываем полученное имя
          echo 'Спасибо! Ваше имя ' . $name . ' успешно получено!';
          exit; //--Завершаем работу PHP-скрипта. В этом случае HTML-форма выведена не будет
      }
      else //--Иначе предупреждаем пользователя
      {
          echo 'Вы ввели слишком короткое имя!';
      }
  }
 
?>
 
<form method="GET" action="<?php echo $_SERVER['PHP_SELF']; ?>">
  Введите ваше имя (минимум 3 символа): <input type="text" name="name" value="<?php echo $name; ?>" /><br />
  <input type="submit" value="Send" />
</form>

В реальных условиях не забываем полностью оформлять код HTML-страницы (заголовки, body и т.п.).

Флажки на форме служат для ответа вида "да/нет". Как отмечалось в прошлой статье, если флажок не отмечен, в параметрах ничего не передается. Иначе большинством браузеров передается параметр со значением on (если не задано конкретное значение value). Для анализа, в принципе, не важно значение, важно определить наличие параметра. Допустим, на форме есть флажок "Запомнить меня на сайте" с именем remember. В PHP это может быть обработано следующим образом:

if ( isset($_POST['remember']) ) //--Проверяем наличие параметра remember
{
  //--Флажок был установлен. Выполняем операции по запоминанию юзера на сайте
}
else
{
  //--Флажок не был установлен
}

Флажки также часто используются для выбора определенных элементов из набора. Рассмотрим пример. Допустим, есть массив предметов:

$elements = array(
    array('id' => 1, 'name' => 'яблоко'),
    array('id' => 2, 'name' => 'пирожок'),
    array('id' => 3, 'name' => 'камень'),
    array('id' => 4, 'name' => 'морковка'),
    array('id' => 5, 'name' => 'ножницы'),
    array('id' => 6, 'name' => 'огурец')
);

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

echo 'Выберите съедобные предметы:'. "\n";
//--Открывающий тег form с action на самого себя
echo '<form method="GET" action="' . $_SERVER['PHP_SELF'] . '">' . "\n";
foreach($elements as $element) //--Пробегаемся циклом по массиву предметов
{
    //--Выводим флажок для каждого предмета. name будет содержать идентификаторы элементов
    echo '  <input type="checkbox" name="element' . $element['id'] . '" id="element' . $element['id'] . '">';
    //--Выводим надпись для каждого флажка (название предмета)
    echo ' <label for="element' . $element['id'] . '">' . $element['name'] . '</label><br />'. "\n";
}
echo '  <input type="submit" value="Готово" />'. "\n";
echo '</form>'. "\n";

Результат работы этого PHP-кода следующий:

Выберите съедобные предметы:
<form method="GET" action="/form.php">
  <input type="checkbox" name="element1" id="element1"> <label for="element1">яблоко</label><br />
  <input type="checkbox" name="element2" id="element2"> <label for="element2">пирожок</label><br />
  <input type="checkbox" name="element3" id="element3"> <label for="element3">камень</label><br />
  <input type="checkbox" name="element4" id="element4"> <label for="element4">морковка</label><br />
  <input type="checkbox" name="element5" id="element5"> <label for="element5">ножницы</label><br />
  <input type="checkbox" name="element6" id="element6"> <label for="element6">огурец</label><br />
  <input type="submit" value="Готово" />
</form>

В обработчике проверяем, какие элементы были выбраны пользователем:

if ( count($_GET) > 0 ) //--Если были приняты данные из HTML-формы
{
    echo 'Ваш выбор:<br />';
    foreach($elements as $element) //--Пробегаемся циклом по массиву предметов
    {
        //--Проверяем, был ли передан параметр element1, element2 и т.д. 
        if ( isset($_GET[ 'element' . $element['id'] ]) )
            echo $element['name'] . '<br />';
    }
    exit;
}

Обработчик помещается сразу после объявления массива. Конечный код:

<?php
 
  $elements = array(
      array('id' => 1, 'name' => 'яблоко'),
      array('id' => 2, 'name' => 'пирожок'),
      array('id' => 3, 'name' => 'камень'),
      array('id' => 4, 'name' => 'морковка'),
      array('id' => 5, 'name' => 'ножницы'),
      array('id' => 6, 'name' => 'огурец')
  );
 
  if ( count($_GET) > 0 ) //--Если были приняты данные из HTML-формы
  {
      echo 'Ваш выбор:<br />';
      foreach($elements as $element) //--Пробегаемся циклом по массиву предметов
      {
          //--Проверяем, был ли передан параметр element1, element2 и т.д. 
          if ( isset($_GET[ 'element' . $element['id'] ]) )
              echo $element['name'] . '<br />';
      }
      exit;
  }
 
  echo 'Выберите съедобные предметы:'. "\n";
  //--Открывающий тег form с action на самого себя
  echo '<form method="GET" action="' . $_SERVER['PHP_SELF'] . '">' . "\n";
  foreach($elements as $element) //--Пробегаемся циклом по массиву предметов
  {
      //--Выводим флажок для каждого предмета. name будет содержать идентификаторы элементов
      echo '  <input type="checkbox" name="element' . $element['id'] . '" id="element' . $element['id'] . '">';
      //--Выводим надпись для каждого флажка (название предмета)
      echo ' <label for="element' . $element['id'] . '">' . $element['name'] . '</label><br />'. "\n";
  }
  echo '  <input type="submit" value="Готово" />'. "\n";
  echo '</form>'. "\n";
 
?>

Хочу показать еще один способ обработки информации из таких форм. Значение атрибута name у всех флажков генерируется одинаковое, но с символами "[]" на конце. В этом случае PHP формирует переменную в виде массива, в котором будут содержаться значения атрибутов value отмеченных флажков. Соответственно, необходимо задать атрибуты value для флажков. Строку кода вывода флажков приводим к следующему виду:

echo '  <input type="checkbox" name="element[]" id="element' . $element['id'] . '" value="' . $element['id'] . '">';

В результате HTML-код флажков будет таким:

<input type="checkbox" name="element[]" id="element1" value="1"> <label for="element1">яблоко</label><br />
<input type="checkbox" name="element[]" id="element2" value="2"> <label for="element2">пирожок</label><br />
<input type="checkbox" name="element[]" id="element3" value="3"> <label for="element3">камень</label><br />
<input type="checkbox" name="element[]" id="element4" value="4"> <label for="element4">морковка</label><br />
<input type="checkbox" name="element[]" id="element5" value="5"> <label for="element5">ножницы</label><br />
<input type="checkbox" name="element[]" id="element6" value="6"> <label for="element6">огурец</label><br />

При такой реализации, при отметке флажков "яблоко", "пирожок", "морковка", "огурец" массив $_GET будет иметь следующие значения:

[element] => Array
    (
        [0] => 1
        [1] => 2
        [2] => 4
        [3] => 6
    )

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

Статья получается слишком объемной, пожалуй, продолжение в следующей части. Если есть вопросы, welcome в комментарии ;)

Комментарии

Оставить комментарий »

 
Игорь
12 июля 2011, 9:48
#1
 

Благодарю за интересный материал!

sasha
1 января 2012, 21:41
#2
 

спасибо

ЗлойЧёрт
13 марта 2012, 9:06
#3
 

ничё не понял :'(

Joker-jar
13 марта 2012, 18:35
#4
 

Совсем ничего? Спрашивайте, расскажем :)

Владимир
24 марта 2012, 20:35
#5
 

Спасибо за материал! Может подскажете как сделать, чтоб я смог выбрать 2 яблока, 3 пирожка, 4 морковки и один огурец?

Joker-jar
25 марта 2012, 19:44
#6
 

Владимир, с использованием каких элементов форм?

Nucleon
17 июля 2012, 19:41
#7
 

Хорошая статейка=) нашёл для себя пару приёмчиков.

Эдуард
7 октября 2012, 7:09
#8
 

Приветствую, подскажите пожалуйста, как можно реализовать вывод отмеченных chekbox и option в select и radio, ранее отмеченных в форме при передаче POST-ом, чтобы если произошла ошибка и пользователь исправив которую заново не выбирал, а чтобы значения подставлялись из post как в inpute type="text" или textarea

Joker-jar
7 октября 2012, 19:06
#9
 

Эдуард, при выводе нужно проверять наличие переданных POST-параметров и, при необходимости, выделять элемент. Пример для checkbox'а:

$remember_checked = isset($_POST['remember']) ? ' checked="checked"' : '';
echo '<input type="checkbox" name="remember"' . $remember_checked . ' />';

для select'а:

$selected = ( isset($_POST['country']) && $_POST['country'] = 'russia' ) ? ' selected="selected"' : '';
echo '<option value="russia"' . $selected . '>Россия</option>';

второй вариант, обычно, обрабатывается в цикле, но суть, я думаю, ясна.

Эдуард
8 октября 2012, 7:41
#10
 

У меня была проблема в том что чек боксы я передавал ввиде массива поэтому придумал только такое решение:

<input id="checkbox_1" type="checkbox" name="Фрукты[1]" <?=isset ($_POST['Фрукты']['1']) ? ' checked="checked"' : '';?> value="Яблоки" class="checkbox"/>
	<label for="checkbox_1">Яблоки</label><br />
<input id="checkbox_2" type="checkbox" name="Фрукты[2]" <?=isset ($_POST['Фрукты']['2']) ? ' checked="checked"' : '';?> value="Груши" class="checkbox"/>
	<label for="checkbox_2">Груши</label><br />

Для radio придумал такой вариан:

<input type="radio" name="radio" value="выбор1" id="radio_1" <?=in_array('выбор1', $_POST) ? ' checked="checked"' : ''?> />
            <label for="radio_1">Radio button 1</label><br />
 
А для select такой вариан:
<select name="select">
                <option value="">- Select -</option>
                <option value="1" <?=in_array('1', $_POST) ? ' selected="selected"' : ''?>>Select option 1</option>
                <option value="2" <?=in_array('2', $_POST) ? ' selected="selected"' : ''?>>Select option 2</option>
                <option value="Выбираем третий пункт" <?=in_array('Выбираем третий пункт', $_POST) ? ' selected="selected"' : ''?>>Выбираем третий пункт&nbsp;</option>
            </select>

Оставить комментарий

Ваше имя
 
Ваш e-mail
 
Комментарий