В просторах интернета очень много примеров отправки формы через ajax, но большинство примеров используют проверку вводимых данных на стороне клиента, что не очень правильно и безопасно. Любое условие можно подстроить, а затем переработать.
Отправка формы ajax запросом — это значит отдать вводимые данные серверу и вернуть результат пользователю без перезагрузки страницы, при этом все проверки на ввод данных производится на сервере, а не на клиенте при помощи javascript.
В этом уроке я расскажу
Как отправлять post input при помощи ajax
Обработать каждый POST запрос на наличие вредоносного кода
Проверить вводимые данные на валидатность (emal или теолефон)
Преобразовать данные в массив json
Выдать пользователю результат об успехе или об конкретной ошибке
Примечание: Всю красоту и вывод сообщений настраиваете под свой проект, я лишь покажу принцип работы.(каждую строку попытаюсь закомментировать)
Что нам понадобится
Библиотека jquery
Библиотека phpmailer, для отправки на почту уведомления
Компоненты bootstrap (мне было лень писать свои стили, по этому я использовал готовый шаблон)
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);
}
?>
Вот что у нас получилось
Согласен, не очень красиво, но я надеюсь что принцип обработки данных вам понятен. Если что не ясно пишите комментарии, а на них отвечаю.
HTML5 представляет несколько новых атрибутов для реализации проверки на основе браузера. pattern Атрибут является регулярным выражением , которое определяет диапазон допустимых входов для textarea элементов и большинство типов input. required Атрибут определяет, требуется ли поле. Для устаревших браузеров, которые не реализуют эти атрибуты, мы можем использовать их значения в качестве основы для полифилла. Мы также можем использовать их для обеспечения более интересного усовершенствования — мгновенной проверки формы.
Мы должны быть очень осторожны, чтобы не увлечься, создавая чрезмерно агрессивную проверку, которая нарушает естественное поведение браузера и попадает на людей. Например, я видел формы, в которых невозможно нажать Tab, то есть исключить перейти на другой input. Оченьзлоупотребляется javascript, чтобы заставить фокус оставаться внутри поля, пока он не будет действительным. Это очень плохое использование и прямо противоречит рекомендациям по доступности.
То, что мы собираемся сделать в этой статье, гораздо менее навязчиво. Это даже не полная проверка на стороне клиента — это просто тонкое усовершенствование юзабилити, реализованное доступным способом, которое (как я обнаружил при тестировании скрипта) почти идентично тому, что теперь делает Firefox изначально!
Конечно, это не происходит сразу. Если бы это было так, то по умолчанию каждое обязательное поле имело бы эту схему. Вместо этого эти контуры отображаются только после того, как вы взаимодействовали с полем, которое в основном (хотя и не точно) аналогично onchange событию.
Так вот что мы собираемся делать, используя onchange в качестве запуска событие. В качестве альтернативы мы могли бы использовать oninput событие, которое срабатывает, как только любое значение набирается или вставляется в поле. Но это действительно слишком быстро, так как данный метод будет запускать и отключать многие типы событий в быстрой последовательности при наборе текста, создавая эффект мигания, который будет раздражать или отвлекать для некоторых пользователей. И, в любом случае, oninput не срабатывает от программного ввода, который onchange делает, и нам может понадобиться, чтобы обрабатывать такие вещи, как автозаполнение от сторонних надстроек.
Определение HTML и CSS
Итак, давайте посмотрим на нашу реализацию, начиная с HTML, на которой она основана:
Этот пример представляет собой простую форму комментариев, в которой требуются некоторые поля, некоторые проверяются. Области, которые required также имеют , чтобы обеспечить запасную семантику для вспомогательных технологий, которые не понимают новых aria-requiredinput типы.
Спецификация ARIA также определяет атрибут, и это то, что мы собираемся использовать, чтобы указать, когда поле является недопустимым (для которого нет эквивалентного атрибута в HTML5). Атрибут, очевидно, обеспечивает доступную информацию, но он может быть также использован в качестве CSS крюка , чтобы применить красный контур:aria-invalid
Мы могли бы просто использовать и не беспокоиться об этом, и, откровенно говоря, это выглядело бы лучше, но тогда у нас не было бы никаких признаков в браузерах, которые не поддерживают теней коробок, таких как IE8.box-shadowborder
Добавление 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 атрибут:
Первые два условия могут показаться многословными, но они необходимы, потому что элементы 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
Однако для того, чтобы работать, 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 уже используют их для проверки перед отправкой — Учитывая все это, действительно ли есть какая-то точка, добавляющая еще один полиполк?
Ckeditor довольно хороший визуальный инструмент для редактирование контента на Вашем сайте, но его стандартные функции не всегда удовлетворяют потребности концепции сайта. Настройка подразумевает в себя подключение плагинов, дополнительных css, удаление не нужных кнопок на панели CKeditor, а так же внедрение bootstrap компонентов.
На официальном сайте есть конструктор для сбора своего пакета, но как показала практика это не очень хорошее решение, так как некоторые плагины не совместимы текущей версией CKeditor или выбранные плагины конфликтуют друг с другом.
По этому мы соберем своей редактор с нуля, разбирая каждый плагин отдельно.
Вот такую панель в итоге мы получим
По сравнению со стандартной панелью, эта панель имеет подключение дополнительных плагинов и отключены ненужные кнопки
var editor = CKEDITOR.replace('editor',{height: 500});
AjexFileManager.init({returnTo: 'ckeditor', editor: editor});
Итак, мы поставили самый стандартный полный пакет функций от CKEditor, теперь приступим к его настройке. Переходим к файлу config.js, который находится в папке /js/ckeditor/config.js
Копируем содержимое папки в папку с плагинами http://example.com/js/ckeditor/plugins/youtube
Кстати на странице почти любого плагина есть своя документация на английском языке, но не думаю что в этом будут сложности, все познается путем перебора разных параметров.
config.extraPlugins = 'youtube';
Обновляем страницу, а если не помогло обновляем кэш страницы и видим кнопку youtube. По аналогии подключаем и другие необходимые плагины.
Вот что у меня получилось, когда я собирал плагины для редактирования статей и уроков на этом сайте.
tableresize — редактирование размера таблицы путем движения курсора
ckawesome — подключение иконок
Удаление ненужных кнопок из CKEditor
Некоторые плагины почти ни когда не используются, давайте займемся отключением ненужных плагинов такие как: О CKEditor, Сохранить, Новая страница, Печать, Шаблоны, Flash, Смайлики, Поиск.
Я ими ни когда не пользуюсь, по этому считаю что их можно отключить из панели редактора.
var editor = CKEDITOR.replace('editor',{height: 500});
AjexFileManager.init({returnTo: 'ckeditor', editor: editor});
Подключение CSS в CKEditor
Обратите внимание: Когда мы работаем в редакторе, то стиль написания контента берется от ckeditor. Он различается от общего стиля сайта, это выражается во многом, например: межстрочный интервал разный, размера шрифта отличаются друг от друга, стиль тегов h1, h2, h3 другой и это заметно во многих других мелочах. Давайте подключим свои стили сайта.
Подключаем 2 CSS файла, bootstrap.css и styles.css