Создание привлекательной формы. Часть 3

Создание привлекательной формы

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

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

Итак, приступим…

План урока:

    1. Написание серверного скрипта.

Детали учебника

Тема: PHP

Сложность: Средняя

Урок: Видео версия (.mp4)

Время: 00:45:54

Размер архива: 90 Mb

скачать исходникискачать урок

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

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

$fields = array("lastname" => "Фамилия", "firstname" => "Имя", "email" => "Email", "comment" => "Отзыв");

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

Здесь мы имеем ассоциативный массив, ключами которого есть имена полей, а значениями — описания полей. Зачем нужен именно ассоциативный массив? Дело в том, что переданные данные формы мы получаем из глобального массива POST. При этом ключами элементов массива будут как раз имена полей, поэтому при проверке полученных данных достаточно посмотреть имеется ли проверяемый ключ элемента глобального массива POST в массиве fields. Если таковой ключ имеется, значит мы проверяем обязательное поле. Ну а значения массива fields нам пригодятся при выводе информации о том, какие именно из полей не были заполнены. Вот такая вот у нас задумка. Начнем ее реализовывать.

Для начала создадим условие, которое будет выполняться при поступлении данных формы:

if($_POST){
	$error = false;
}

Здесь мы сразу же установили флаг заполнения обязательных полей, присвоив ему булево значение FALSE. Как Вы уже могли догадаться, в конце скрипта мы проверим значение переменной $error, если оно останется FALSE — значит с данными все в порядке, иначе — какие-то поля или чекбокс не были заполнены.

Теперь пройдемся в цикле по массиву POST. При этом мы будем проверять выполнение двух условий для каждого из элементов массива POST:

Присутствует ли ключ проверяемого элемента в массиве fields?

Пусто ли значение проверяемого элемента?

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

session_start();

Ну и, собственно, описанный выше цикл:

foreach ($_POST as $key => $value) {
	$value = trim($value);
	if(array_key_exists($key, $fields) && empty($value)){
		$_SESSION['res']['error'] .= "Вы не заполнили поле {$fields[$key]} <br />";
		$error = true;
	}
}

Таким образом, если пользователь не заполнит любое из обязательных полей, то в сессионном массиве $_SESSION['res'] создается элемент error с сообщением, что не заполнено конкретное поле. Вот для этого нам как раз и нужен был именно ассоциативный массив fields, чтобы по его ключу получить значение. Ну а благодаря оператору конкатенации (знак точки перед знаком равно) мы дозаписываем значение $_SESSION['res']['error'], не стирая прежнее. Также стоит обратить внимание на использование функции trim(), которая обрезает концевые пробелы у значения. Сделано это для того, чтобы принимать только значимую для нас информацию, а не пробелы вместо нее.

Теперь проверим, отмечен ли чекбокс:

if($_POST['confirm'] != 'on'){
	$_SESSION['res']['error'] .= "Вы не подтвердили согласие на публикацию!";
	$error = true;
}

Если чекбокс был отмечен, то в массиве POST значение соответствующего элемента будет равно строке «on». Если такового значения нет, значит чекбокс не отмечен, и мы в переменную $_SESSION['res']['error'] добавим соответствующее сообщение и изменим значение флага.

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

Поскольку мы работаем с сессиями, то сделать это не составит особого труда. Мы вновь пройдемся в цикле по массиву POST и в сессионном массиве $_SESSION['res'] создадим элементы с ключами, соответствующими именами полей формы.

Если же значение флага не изменилось, значит с данными все ок и можно продолжать работу (отправлять письмо, класть в БД и т.п.). В нашем случае мы ограничимся выводом сообщения пользователю об успешной отправке отзыва — для этого создадим переменную $_SESSION['res']['ok']:

if($error){
	foreach ($_POST as $key => $value) {
		$_SESSION['res'][$key] = trim($value);
	}
}else{
	$_SESSION['res']['ok'] = "Спасибо, Ваш отзыв принят.";
}

Ну и для решения проблемы F5 в конце скрипта организуем редирект, сбрасывая, таким образом, POST-данные:

header("Location: {$_SERVER['PHP_SELF']}");
exit;

Осталось вывести все сессионные переменные. Прежде всего, давайте выведем их в качестве возможных значений полей:

<form method="post" action="" class="form">
		<p>
			<label for="lastname"><span class="formTextRed">*</span> Фамилия:</label>
			<input type="text" name="lastname" id="lastname" value="<?=$_SESSION['res']['lastname']?>" />
		</p>
		<p>
			<label for="firstname"><span class="formTextRed">*</span> Имя:</label>
			<input type="text" name="firstname" id="firstname" value="<?=$_SESSION['res']['firstname']?>" />
		</p>
		<p>
			<label for="middlename">Отчество:</label>
			<input type="text" name="middlename" id="middlename" value="<?=$_SESSION['res']['middlename']?>" />
		</p>
		<p>
			<label for="email"><span class="formTextRed">*</span> Email:</label>
			<input type="text" name="email" id="email" value="<?=$_SESSION['res']['email']?>" />
		</p>
		<p>
			<label for="emailAlt">Альтернативные Email:</label>
			<input type="text" name="emailAlt" id="emailAlt" value="<?=$_SESSION['res']['emailAlt']?>" />
		</p>
		<p>
			<label for="country">Страна:</label>
			<select name="country" id="country">
				<?php foreach($countries as $country): ?>
				<option <?php if($country == $_SESSION['res']['country']) echo "selected" ?> value="<?=$country?>"><?=$country?></option>
				<?php endforeach; ?>
			</select>
		</p>
		<p>
			<label for="comment"><span class="formTextRed">*</span> Отзыв:</label>
			<textarea rows="10" name="comment" id="comment"><?=$_SESSION['res']['comment']?></textarea>
		</p>
		<p>
			<input type="checkbox" name="confirm" id="confirm" />
			<label for="confirm" class="confirm"><span class="formTextRed">*</span> Не возражаю против публикации моего отзыва на сайте в рекламных целях</label>
		</p>
		<p class="submit">
			<input type="submit" value="Отправить" />
		</p>
	</form>

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

Перед формой выведем возможные сообщения об успехе или ошибках отправки формы:

<?php
if($_SESSION['res']['error']){
	echo "<div class='answerError'>{$_SESSION['res']['error']}</div>";
}
if($_SESSION['res']['ok']){
	echo "<div class='answerOk'>{$_SESSION['res']['ok']}</div>";
}
?>

Ну а после формы удалим сессионный массив $_SESSION['res'] со всеми его переменными. Это делается для того, чтобы не выводить всю эту информацию после успешной отправки формы:

<?php unset($_SESSION['res']) ?>

Ну и несколько стилевых правил для классов answerError и answerOk:

.answerError{
	width: 550px;
	padding: 5px;
	border: gray dashed 1px;
	background: #FFEDED;
	color: #7F5354;
}

.answerOk{
	width: 550px;
	padding: 5px;
	border: 1px solid #ADC092;
	background: #F0FAF1;
	color: #58715E;
}

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

На этом у меня все. Удачи!

Проверка формы без перезагрузки с помощью JavaScript

Прямо сейчас посмотрите курс по организации динамической работы с формами!

Смотреть курс

Метки:

Комментарии Вконтакте:

Комментарии Facebook:

Комментарии (21)

  1. Марат

    Просим записать урок про отправку данных на электронный адресс или в БД

  2. Илья

    Добавьте, пож-та, проверку правильности заполнения поля Email

    • Андрей Кудлай

      Ок, в следующем уроке покажем валидацию поля Email и отправку данных формы на Email.

  3. Виталик

    Хороший качественный материал.
    Если будите делать продолжение, то вот парочка идей:
    1) проверку полученных данных из формы на скрепты и ненужные коды
    2) небольшую проверку от СПАМА
    3) загрузить картинку
    4) при выборе страны, выбрать область или район.
    Так же и «Уведомить меня об ответах на мой комментарий по e-mail.» то же можно.
    При током дополнении форма получится универсальной и пользователь (ученик) сможет выбрать то что ему нужно для ресурса.

    • Андрей Кудлай

      Спасибо за идеи… возьмем на заметку ;)

      • Виталик

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

  4. Константин

    Добрый вечер.
    Хочу заметить следующее: линк через header работает идеально в мазиле и IE, в хроме же линкается лишь 1 раз по нажатию f5, после эта фишка не работает и псое каждого обновления страницы он посылает данные.

    • Андрей Кудлай

      Здравствуйте.
      Что значат фразы «линк через хедер» и «в хроме линкается лишь один раз»? Рискну предположить, что Вы подразумевали редирект функцией header(). Если мое предположение верно, то в хроме должно работать абсолютно точно также, как и в прочих браузерах, поскольку мы говорим о серверных вещах (функция header — это функция серверного языка программирования), которые никоим образом не связаны с понятием кроссбраузерности. Сервер просто отдает результат выполнения скрипта браузеру… ну а что это будет за браузер — серверу абсолютно не интересно.

      • Константин

        Да, под словом «линк» я подразумевал редирект.
        Какого было моё удивление, когда я заметил что хрому наплевать на редирект, может быть конечно где то я сглупил, но он не работает как надо.
        Вот я и брожу в поисках истины по этому вопросу, ищу приемлемый выход из данной ситуации.

        • Андрей Кудлай

          Ок, я завтра проверю работоспособность в хроме. Только лучше давайте перенесем обсуждение темы на форум. Можете там создать тему и там постараемся найти решение проблемы или ее корень, если проблема действительно есть :)

        • Андрей Кудлай

          Константин, как оказалось, это действительно своеобразный баг хрома. На форуме предложил простое решение проблемы.
          Вам спасибо за интересную проблему ;)

  5. Арам

    Здравствуйте.
    Почему в этом примере при редиректе на ту же страницу сообщение об успешном оформлении отзыва остаётся ? у меня не остаётся, тоесть проблема следующая : я сделал примерно такую же форму, в конце у меня проверяется переменная ошибки на значение false, тоесть если она равна false, то данные отправляются в БД, и сразу после этого запроса (после вставки данных в БД) выводится сообщение об успехе, затем выполняется редирект на ту же страницу чтобы избежать многократной вставки одних и тех же данных, и тут, если всё хорошо, то должно вывестись сообщение об успехе, но оно теряется (не выводится), почему? естесвтвенно если убрать редирект (функция header()) сообщение выводится, но проблема f5 остается, как быть?

    • Андрей Кудлай

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

  6. Сергей

    Доброго времени суток!

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

    • Андрей Кудлай

      Здравствуйте.
      Для того, чтобы помочь, нужно знать, какие именно ошибки и видеть ваш код… ни того, ни другого я не вижу, поэтому подсказать, как исправить ошибку — невозможно. Создайте на нашем форуме тему, выложите текст ошибки, код чекбокса в форме и его обработку, тогда можно будет уже что-то подсказать.
      P.S. Да, и сейчас взглянув на код, я вижу, что чекбокс мы ведь используем в форме, а отправка самой формы показана в следующем уроке.

      • Сергей

        Спасибо!
        Сейчас создам.
        А уроки я все прошёл, и писал с видео в ручную, изучая доскональна!))
        Потом только о 5 уроке узнал и перешёл на сайт, и увидел исходники!))))
        Конечно не растроился, зато всё сам разбирал))

      • Сергей

        Создал тему!)))
        webformyself.com/forum/index.php/topic/2096/

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree