Отправка формы Ajax с комментариями в каждый строке кода

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

Отправка формы ajax запросом — это значит отдать вводимые данные серверу и вернуть результат пользователю без перезагрузки страницы, при этом все проверки на ввод данных производится на сервере, а не на клиенте при помощи javascript.

В этом уроке я расскажу

  1. Как отправлять post input   при помощи ajax 
  2. Обработать каждый POST запрос на наличие вредоносного кода
  3. Проверить вводимые данные на валидатность (emal или теолефон)
  4. Преобразовать данные в массив json
  5. Выдать пользователю результат об успехе или об конкретной ошибке

Примечание: Всю красоту и вывод сообщений настраиваете под свой проект, я лишь покажу принцип работы.(каждую строку попытаюсь закомментировать)

Что нам понадобится

  1. Библиотека jquery
  2. Библиотека phpmailer, для отправки на почту уведомления
  3. Компоненты bootstrap (мне было лень писать свои стили, по этому я использовал готовый шаблон)

 

Разметка формы

Взял наиболее часто встречаемые типы инпутов.

<form id="form" onsubmit="return false">
	<div><input type="text" name="name" value="" placeholder="Ваше имя" class="form-control"/></div>
	<div><input type="text" name="email" value=""  placeholder="Email" class="form-control"/></div>
	<div><input type="text" name="phone" value="" placeholder="Телефон" class="form-control"/></div>
	<div class="radio"><label><input type="radio" name="pol" value="Муж." > - муж.</label></div>
	<div class="radio"><label><input type="radio" name="pol" value="Жен." > - Жен.</label></div>
	<div>Тема:</div>
	<select name="theme" class="form-control">
		<option value="Общие вопросы" selected="selected">Общие вопросы</option>
		<option value="Жалоба">Жалоба</option>
		<option value="Реклама">Реклама</option>
		<option value="Деловое предложение">Деловое предложение</option>
	</select>
	<div><textarea rows="2" name="comment" placeholder="Сообщение" class="form-control" ></textarea></div>
	<div class="checkbox"><label><input type="checkbox" name="privat" value="1"> - согласен на обработку персональных данных</label></div>
	<button class="btn btn-primary" onclick="callback('#form')">Отправить</button>
	<div id="form_result"></div>
</form>

Немного распишу что для чего

onsubmit="return false" - Для того что бы форма не отправляла данные, иначе у нас перезагрузится страница.
onclick="callback('#form')" — функция javascipt, которая будет отправлять ajax форму

Функция отправки формы через ajax

function callback(id) // переменная ID - это идишник формы'
{
	$.ajax({ // создаем конструкцию ajax
		 url: "callback.php", // файл обрабодчик, который будет проверять данные
		 type : "POST", // тип запроса ajax
		 data: $(id).serialize(), // откуда забираем данные (все input в форме с идишником переменной id)
		 success: function(data){ // что будет делаться когда, запрос будет выполнен (не важно успешно или нет)
				data = jQuery.parseJSON(data); // преобразовываем данные в json формат
				if(data.success) // если все проверки прошли валидацию
				{
					$(id+"_result").html(data.success.text); //выводим сообщение об успешной отправке email
					$(id+" .has-error").removeClass(); // удаляем класс, который сигнализировал нас об ошибке в инпутах, если они были
					$(id+" input").val(""); // чистим input ы
					$(id+" textarea").val(""); // чистим textarea
				}
				else // если данные не прошли валидацию
				{
					$(id+" .has-error").removeClass(); // удаляем предыдущие ошибки, для того что бы вывести новые
					$.each(data, function(index, data){ // цикл ошибок, в которые нужно показать пользвателю
						 if(data.error) // если есть ошибки, подсветить инпуты пользователю
						 {
								$(id+' input[name="'+data.error.input+'"], '+id+' textarea[name="'+data.error.input+'"]').parent().addClass("has-error")
						 }
					});
				}
		}
	});
}

Файл обработки ajax запроса

<?php 
require "phpmailer/class.phpmailer.php"; // подключаем библиотеку отправки почты
foreach($_POST as $type=>$value) // цикл преобразует post ы, во избежания вредоносного кода или html кода
{
	if(ini_get('magic_quotes_gpc'))
	$_POST[$k]=stripslashes($_POST[$k]);
	$_POST[$k]=htmlspecialchars(strip_tags($_POST[$k]));
	$_POST[$k]=mysql_escape_string($_POST[$k]);
}
//присваиваем в переменные вводимые данные
$name = $_POST['name']; 
$email = $_POST['email'];
$phone = $_POST['phone'];
$pol = $_POST['pol'];
$theme = $_POST['theme'];
$comment = $_POST['comment'];
$privat = $_POST['privat'];
$ip=$_SERVER['REMOTE_ADDR'];
// пишем правила: если пусто, то в загоняем в массив error текст ошибки и название input 
if($name=="")
{
	$json[]["error"] = array(
	'text' => "Введите ваше имя!",
	'input' => "name" // это необходимо что бы подсветить нужный input пользователю (name="phone")'
	);
}
if($email=="" or !checkEmail($email)) // проверяем email на корректность
{
	$json[]["error"] = array(
	'text' => "Не корректный email",
	'input' => "email"
	);
}
if($phone=="" or !checkPhone($phone)) // проверяем телефон на корретность
{
	$json[]["error"] = array(
	'text' => "Не корректный телефон",
	'input' => "phone"
	);
}
if($pol=="") //проверка radio
{
	$json[]["error"] = array(
	'text' => "Выберите пол!",
	'input' => "pol"
	);
}
if($theme=="")
{
	$json[]["error"] = array(
	'text' => "Выберите тему сообщения!",
	'input' => "theme"
	);
}
if($comment=="")
{
	$json[]["error"] = array(
	'text' => "Введите сообщение",
	'input' => "comment"
	);
}
if(!isset($privat)) //проверка checkbox 
{
	$json[]["error"] = array(
	'text' => "Согласитесь с персональными данными",
	'input' => "privat"
	);
}
if(count($json)==0) // если нет ошибок, выводим сообщение пользователю, отправляем письмо на почту
{
	$json["success"] = array(
	'text' => "Сообщение отправленно",
	);
	$address=$email; // на какую почту пойдет отправка
	$subject=$theme; // тема письма
	// тело письма
	$message_email="<div style='font-family: Helvetica;  background: #f1f1f1;  padding: 15px;  border: 1px solid #ddd;'> 
	<div>
		<h3 style='font-weight:400; margin-top:0px;'>Сообщение с сайта ".$_SERVER["HTTP_HOST"]."</h3>
		<div>
			<strong>Имя:</strong> $name<br/>
			<strong>Email:</strong> $email<br/>
			<strong>Телефон:</strong> $phone<br/>
			<strong>Пол :</strong> $pol<br/><br/>
			<strong>Тема сообщения :</strong> $theme<br/>
			<strong>Сообщение:</strong><br/>$comment
			<hr>
			ip-адрес: $ip
		</div>
	</div>
	</div>";
	$mail = new PHPMailer(); // создаем письмо
	$mail->IsMail(); 
	$mail->AddAddress($address); // куда отправляем(можно указать несколько писем для отправки)
	$mail->AddReplyTo("noreply@".$_SERVER["HTTP_HOST"],$_SERVER["HTTP_HOST"]);// кому отвечать
	$mail->SetFrom("noreply@".$_SERVER["HTTP_HOST"],$_SERVER["HTTP_HOST"]); // от кого пришло и с какой почты
	$mail->Subject = $subject; // тема письма
	$mail->MsgHTML($message_email); //указываем, что тело письма это html
	$mail->Send(); //отправка письма
	
}
	
echo json_encode($json); // преобразование массива в json формат и показываем пользователю результат
//функции 
function checkPhone($str) //Проверка русских символов и чисел 
{
	return preg_match("/^\+?[0-9]{7,12}$/", $str);
}
function checkEmail($str) //Проверка email
{
	return preg_match("/^[\.A-z0-9_\-\+]+[@][A-z0-9_\-]+([.][A-z0-9_\-]+)+[A-z]{1,4}$/", $str);
}
?>

Вот что у нас получилось

Согласен, не очень красиво, но я надеюсь что принцип обработки данных вам понятен. 
Если что не ясно пишите комментарии, а на них отвечаю.

Проверка валидности формы на JavaScript и HTML5 — это легко

HTML5 представляет несколько новых атрибутов для реализации проверки на основе браузера. pattern Атрибут является регулярным выражением , которое определяет диапазон допустимых входов для textarea элементов и большинство типов input. required Атрибут определяет, требуется ли поле. Для устаревших браузеров, которые не реализуют эти атрибуты, мы можем использовать их значения в качестве основы для полифилла. Мы также можем использовать их для обеспечения более интересного усовершенствования — мгновенной проверки формы.

Мы должны быть очень осторожны, чтобы не увлечься, создавая чрезмерно агрессивную проверку, которая нарушает естественное поведение браузера и попадает на людей. Например, я видел формы, в которых невозможно нажать Tab, то есть исключить перейти на другой input. Очень злоупотребляется javascript, чтобы заставить фокус оставаться внутри поля, пока он не будет действительным. Это очень плохое использование и прямо противоречит рекомендациям по доступности.

То, что мы собираемся сделать в этой статье, гораздо менее навязчиво. Это даже не полная проверка на стороне клиента — это просто тонкое усовершенствование юзабилити, реализованное доступным способом, которое (как я обнаружил при тестировании скрипта) почти идентично тому, что теперь делает Firefox изначально!

Конечно, это не происходит сразу. Если бы это было так, то по умолчанию каждое обязательное поле имело бы эту схему. Вместо этого эти контуры отображаются только после того, как вы взаимодействовали с полем, которое в основном (хотя и не точно) аналогично onchange событию.

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

Определение HTML и CSS

 Итак, давайте посмотрим на нашу реализацию, начиная с HTML, на которой она основана:

<form action="#" method="post">
  <fieldset>
    <legend><strong>Add your comment</strong></legend>
    <p>
      <label for="author">Name <abbr title="Required">*</abbr></label>
      <input 
        aria-required="true"
        id="author"
        name="author"
        pattern="^([- \w\d\u00c0-\u024f]+)$"
        required="required"
        size="20"
        spellcheck="false"
        title="Your name (no special characters, diacritics are okay)"
        type="text"
        value="">
    </p>
    <p>
      <label for="email">Email <abbr title="Required">*</abbr></label>
      <input 
        aria-required="true"
        id="email"
        name="email"
        pattern="^(([-\w\d]+)(\.[-\w\d]+)*@([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2})$" 
        required="required"
        size="30"
        spellcheck="false"
        title="Your email address"
        type="email"
        value="">
    </p>
    <p>
      <label for="website">Website</label>
      <input
        id="website"
        name="website"
        pattern="^(http[s]?:\/\/)?([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2}(\/([-~%\.\(\)\w\d]*\/*)*(#[-\w\d]+)?)?$"
        size="30"
        spellcheck="false"
        title="Your website address"
        type="url"
        value="">
    </p>
    <p>
      <label for="text">Comment <abbr title="Required">*</abbr></label> 
      <textarea
        aria-required="true"
        cols="40"
        id="text"
        name="text"
        required="required"
        rows="10"
        spellcheck="true"
        title="Your comment"></textarea>
    </p>
  </fieldset>
  <fieldset>
    <button name="preview" type="submit">Preview</button>
    <button name="save" type="submit">Submit Comment</button>
  </fieldset>
</form>

Этот пример представляет собой простую форму комментариев, в которой требуются некоторые поля, некоторые проверяются. Области, которые required также имеют , чтобы обеспечить запасную семантику для вспомогательных технологий, которые не понимают новых aria-required input типы.

Спецификация ARIA также определяет атрибут, и это то, что мы собираемся использовать, чтобы указать, когда поле является недопустимым (для которого нет эквивалентного атрибута в HTML5). Атрибут, очевидно, обеспечивает доступную информацию, но он может быть также использован в качестве CSS крюка , чтобы применить красный контур:aria-invalid

input[aria-invalid="true"], textarea[aria-invalid="true"] {
  border: 1px solid #f00;
  box-shadow: 0 0 4px 0 #f00;
}

Мы могли бы просто использовать и не беспокоиться об этом, и, откровенно говоря, это выглядело бы лучше, но тогда у нас не было бы никаких признаков в браузерах, которые не поддерживают теней коробок, таких как IE8.box-shadow border

Добавление JavaScript

Теперь, когда у нас есть статический код, мы можем добавить скрипты. Первое, что нам понадобится, — это основная функция: addEvent()

function addEvent(node, type, callback) {
  if (node.addEventListener) {
    node.addEventListener(type, function(e) {
      callback(e, e.target);
    }, false);
  } else if (node.attachEvent) {
    node.attachEvent('on' + type, function(e) {
      callback(e, e.srcElement);
    });
  }
}

Затем нам понадобится функция для определения того, должно ли данное поле быть проверено, что просто проверяет, что он не отключен и не читается, и что он имеет либо атрибут, patter nлибо required атрибут:

function shouldBeValidated(field) {
  return (
    !(field.getAttribute("readonly") || field.readonly) &&
    !(field.getAttribute("disabled") || field.disabled) &&
    (field.getAttribute("pattern") || field.getAttribute("required"))
  );
}

Первые два условия могут показаться многословными, но они необходимы, потому что элементы disabled и readonly свойства не обязательно будут отражать  состояния атрибутов. В Opera, например, поле с жестко закодированным атрибутом по- прежнему будет возвращаться для своего свойства (свойство dot только соответствует состояниям, которые задаются через скрипты).readonly="readonly"undefinedreadonly

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

function instantValidation(field) {
  if (shouldBeValidated(field)) {
    var invalid =
      (field.getAttribute("required") && !field.value) ||
      (field.getAttribute("pattern") &&
        field.value &&
        !new RegExp(field.getAttribute("pattern")).test(field.value));
    if (!invalid && field.getAttribute("aria-invalid")) {
      field.removeAttribute("aria-invalid");
    } else if (invalid && !field.getAttribute("aria-invalid")) {
      field.setAttribute("aria-invalid", "true");
    }
  }
}

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

Поскольку patternу же задан строковым регулярным выражением, то нам нужно передать эту строку RegExp конструктору и создать объект регулярного выражения, который мы можем проверить по значению. Но нам нужно предварительно проверить значение, чтобы убедиться, что оно не пустое, так что самому регулярному выражению не нужно учитывать пустые строки.

Как только мы установили, является ли поле недопустимым, мы можем управлять его атрибутом, указывая, что это добавление в недопустимое поле, которое его еще не имеет значения,  чтобы все это входило в действие, нам нужно привязать функцию проверки к событию. Это должно быть так просто: aria-invalidonchange

addEvent(document, "change", function(e, target) {
  instantValidation(target);
});

Однако для того, чтобы работать, onchange события должны пузыриться (используя технику, которая обычно известна как делегирование событий ), но в Internet Explorer 8 и ранее onchange события не пузырятся . Мы могли бы просто игнорировать эти браузеры, но я думаю, что это был бы позор, особенно когда проблема настолько проста в обходе. Это просто означает немного более сложный код — нам нужно получить коллекции input и textarea элементы, перебрать их и связать onchange событие с каждым полем отдельно:

var fields = [
  document.getElementsByTagName("input"),
  document.getElementsByTagName("textarea")
];
for (var a = fields.length, i = 0; i < a; i++) {
  for (var b = fields[i].length, j = 0; j < b; j++) {
    addEvent(fields[i][j], "change", function(e, target) {
      instantValidation(target);
    });
  }
}

Смотрим что получилось

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

Вы можете посмотреть демо ниже:

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

Я должен признаться, я не уверен, что это действительно того стоит! Если у вас уже есть это усовершенствование (которое работает во всех современных браузерах обратно в IE7), и учитывая, что у вас нет другого выбора, кроме как выполнить проверку на стороне сервера, а также с учетом того, что браузеры, которые поддерживают pattern и required уже используют их для проверки перед отправкой — Учитывая все это, действительно ли есть какая-то точка, добавляющая еще один полиполк?

Кисамеев Логотип
Не в сети
Услуги