Отправка формы 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);
}
?>

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

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

Калькулятор услуг на php и javascript — формирование word.docx документа

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

Фишка этого калькулятора в том, что в итоге все расчеты можно сохранить в word документ и формирует он все данные за считанные мили-секунды. 

Для чего мы создаем такой калькулятор расчетов услуг

  1. Быстрая готовая смета
  2. Сформированный документ можно уже отправлять клиенту
  3. Экономия времени пользователю, тем самым повышаем КПД

Какие методы используем

  1. Формирование шаблона на HTML
  2. Использование многомерного массива в input
  3. Запросы к базе данных для вывода услуг
  4. Расчет при помощи javascript
  5. Php формирование документа

Создаем калькулятор расчета за 6 простых шагов

Шаг 1. Создаем базу данных в mysql

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

price_cat — таблица с категориями
price_item — таблица с услугами

Создаем базу данных импортируем файл calculator.sql  в созданную базу данных и подключаемся к ней.

$dblocation = "localhost";
$dbname = "calculator";
$dbuser = "root";
$dbpasswd = "";
$dbcnx = @mysql_connect($dblocation,$dbuser,$dbpasswd);
if (!$dbcnx) {
echo( mysql_error() );
exit();
}
mysql_query("SET NAMES utf8",$dbcnx);
if (!@mysql_select_db($dbname, $dbcnx)) {
echo( mysql_error() );
exit();
}

Все готово. Теперь необходимо разметить html шаблон и одновременно формировать запросы к базе.

Шаг 2. Разметим html + php шаблон

Подключаем библиотеки, которые нам понадобятся

<link href="css/bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="js/calculator.js"></script>
<script src="js/bootstrap.min.js"></script>

Обратите внимания: 
Я использовал bootstrap компоненты, а так же библиотеку awesome иконки, а в calculator.js мы будем писать скрипт расчетов.

Разметка калькулятора

<div class="container">
<form method='post' action='save_word.php' >
<h1>Калькулятор ремонта</h1>
<?php 
$res_category = mysql_query("SELECT *FROM price_cat ORDER BY sort");
if(mysql_num_rows($res_category)>0)
{
?>
<div class="panel-group" id="accordion">
<?
$category = mysql_fetch_array($res_category);
$i=1;
do
{
?>
<div class="panel panel-default category">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" class="open_category" aria-expanded="false" data-parent="#accordion" href="#price_cat<?php echo $i;?>">
<i class="fa fa-angle-down"></i> <?php echo $category["name"];?> <span class="summa_category"></span>
</a>
<input type="hidden" name="category[<?=$i;?>][name]" value="<?php echo $category["name"];?>" />
<input type="hidden" name="category[<?=$i;?>][summa]" value="" class="summa_category_input" />
</h4>
</div>
<div id="price_cat<?php echo $i;?>" class="panel-collapse collapse">
<div class="">
<?php 
$res_item = mysql_query("SELECT *FROM price_item WHERE catid = '$category[id]'");
if(mysql_num_rows($res_item)>0)
{
?>
<div class="teble-responsive">
<table class="table table-striped">
<th>Наименование работ</th>
<th style="text-align:center;">Ед. изм.</th>
<th style="text-align:center;">Стоимость</th>
<th style="text-align:center;">Кол-во</th>
<th style="text-align:center;">Сумма</th>
<?
$item = mysql_fetch_array($res_item);
$k=1;
do
{
$price = number_format($item["cost"], 0, '', ' ');
?>
<tr>
<td>
<span class=""><?php echo $item["name"];?></span>
<input type="hidden" name="category[<?=$i;?>][items][<?=$k;?>][name]" value="<?php echo $item["name"];?>" />
</td>
<td style="text-align:center;">
<span class=""><?php echo $item["shortdesc"];?></span>
<input type="hidden" name="category[<?=$i;?>][items][<?=$k;?>][ed_izm]" value="<?php echo $item["shortdesc"];?>" />
</td>
<td style="text-align:center;">
<span class=""><?php echo $price;?></span>
<input type="hidden" name="category[<?=$i;?>][items][<?=$k;?>][price]" value="<?php echo $item["cost"];?>" />
</td>
<td><input type="number" step="0.1" min="0" class="form-control calc" name="category[<?=$i;?>][items][<?=$k;?>][kolvo]" value="" style="width:70px; margin:0 auto;"></td>
<td><input type="text" readonly="readonly" class="form-control item_summa" name="category[<?=$i;?>][items][<?=$k;?>][summa]" value="" style="width:80px; margin:0 auto; text-align:center;"></td>
</tr>
<?	
$k++;
}
while($item = mysql_fetch_array($res_item));
?>
</table>
</div>
<?
}
?>
</div>
</div>
<div class="panel-body" style="border-top:1px solid #ddd;">
<div class="pull-right">
<div><strong>Итого:</strong> <big class="summa_category">0</big> руб.</div>
</div>
</div>
</div>
<?
$i++;
}
while($category = mysql_fetch_array($res_category));
?>
</div>
<?
}
?>
<div class="panel-body well well-sm">
<div class="row">
<div class="col-xs-12 col-md-6 "><button class="btn btn-primary btn-sm" name="save_word">Сохранить в WORD документ</button></div>
<div class="col-xs-12 col-md-6">
<div class=" pull-right" style="font-size:20px;">
<strong>Итого:</strong> <span class="total">0</span> руб.
<input type="hidden" name="total" class="total_input" value="" />
</div>
</div>
</div>
</div>
</form>
</div>

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

Теперь самое интересное. Напишем скрипт для расчета стоимости услуг на javascript.

Шаг 3. Пишем скрипт на javascript онлайн расчета

Некоторые строки я пояснил прямо в коде. 

$(function(){
	// смена стрелочки у категории
	$(".open_category").click(function(){
		var status = $(this).attr("aria-expanded")
		if(status=="false")
		{
			$(this).find("i").attr("class","fa fa-angle-up");
		}
		else
		{
			$(this).find("i").attr("class","fa fa-angle-down");
		}
	})
	
	
	// событие при наборе кол-ва в калькуляторе
	$(".calc").on("change keyup", function(){
		var value = $(this).val();
		var price = $(this).parent().prev().find("input").val();
		price = price.replace(/\s/g, ''); // удаляем пробелы
		var item_summa = value*price;
		item_summa = item_summa.Crop(2); // 2 знаka после запятой
		$(this).parent().next().find("input").val(item_summa);
		
		
		var summa_category = 0; // сюда будем загонять сумму в каждоый категории
		var total_summa = 0; // сюда будем загонять итоговую сумму
		var item_summa_category = $(this).parent().next().find("input");
		$(item_summa_category).each(function(){ // пробегаемся по всем суммам и суммируем
			var k = parseFloat($(this).val());
			if(!k || k==0){k=0;}
			summa_category += k;
		})
		
		// записываем расчеты по категориям
		$(this).parents(".category").find(".summa_category").text(summa_category); 
		$(this).parents(".category").find(".summa_category_input").val(summa_category);
		
		$("big.summa_category").each(function(){ // пробегаемся по всем суммам в категориях и суммируем
			var t = parseFloat($(this).text());
			if(!t || t==0){t=0;}
			total_summa += t; // считаем общую стоимость
			
		})
		
		// выводим итоговую сумму
		$(".total").text(total_summa);
		$(".total_input").val(total_summa);
		
	})
	
})
// функция знаки после запятой
Number.prototype.Crop = function (x){
	var s = this+'', a = s.split('.');
	a[1]=a[1]||'';      
	return parseFloat(a[0]+'.'+a[1].substring(0,x));
}

Отлично теперь, если вы сделали все правильно, то у наш созданный калькулятор уже должен считать.

Шаг 4. Пишем скрипт формирования содержимого в word.docx документ.

В исходниках есть файл sample.rtf, его вы должны разместить у Вас на сервере. Он послужит нам шаблоном для создания документа формата .docx на php. Он так же содержит метки, куда мы будем присваивать переменные, созданные в файле save_word.php. Этот файл и есть обработчик формирования word документа.

Файл save_word.php

header('Content-Type: text/html; charset= utf-8');
$categories = isset($_POST['category']) ? $_POST['category'] : array(); // Записываем в многомерный массив все инпуты, которые мы разметели с помощью цикла в php
//В Переменную word мы будем присваивать все что мы расчитали.
$word = "<div style=\"font-family: Helvetica, Arial, sans-serif;\"><table cellpadding=\"0\" border=\"1\" cellspacing=\"0\" style=\"width:100%; border-color: #ddd;\">";
// пробегаемся по категориям
foreach($categories as $category) {
	if($category["summa"]!=0) //Проверяем, если есть расчеты в категории, то считаем.
	{	
		// Обратите внимания, в переменнюу word мы присваем с точкой в начале ".=", это значит что мы добавляем содержимое к тому что было ранее. То есть иными словами Лево+Право=ЛевоПраво
		$word .= "<tr><th colspan=\"5\"><div style=\"font-family: Helvetica, Arial, sans-serif; padding:15px; text-align:left; background: #ececec; font-size: 16px;\">$category[name] ($category[summa] руб.)</th></div></tr>";
		$word .= "
		<tr style=\"font-size:13px;\">
				<td><div style=\"padding:5px; font-family: Helvetica, Arial, sans-serif;\"><strong>Наименование работ</strong></div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif; padding:5px; text-align:center\"><strong>Ед. изм.</strong></div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center\"><strong>Стоимость</strong></div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center\"><strong>Кол-во</strong></div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center\"><strong>Сумма</strong></div></td>
				</tr>
		";
		foreach($category["items"] as $items) //Пробегаемся по всем услугам
		{
			if($items["summa"]!=0) // По аналогии. ну тут понятно думаю.
			{
				$word .="<tr style=\"font-size:12px;\">
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px;\">$items[name]</div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center;\">$items[ed_izm]</div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center;\">$items[price]</div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center;\">$items[kolvo]</div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center;\">$items[summa]</div></td>
				</tr>";
			}
		}
	}
}
$word .="</table>";
$word .="<div style=\"padding:15px; margin-top:30px; font-size:18px; \"><strong>Итого:</strong> ".$_POST['total']." руб.</div></div>";
$d=Date('d.m.Y');
$name_doc = "Ваш прайс-лист ($d)";
//Сгенерировать заголовки, которые упростят браузеру выбор требуемого приложения для визуализации 
header('Content-type: application/msword');
header('Content-disposition: inline; filename='.$name_doc.'.doc'); 
// Открыть файл шаблона 
$filename = 'sample.rtf'; 
$fp = fopen($filename,'r'); 
//прочитать шаблон в перменную 
$output = fread($fp, filesize($filename)); 
fclose($fp); 
//Заменить заполнители в шаблоне требуемыми переменными 
$output = str_replace('<<NAME>>',$word,$output); 
//Отправить сгенерированный документ в браузер 
html_entity_decode(iconv("utf-8", "windows-1251", $output), ENT_QUOTES, "windows-1251");
echo $output

В некоторых моментах мне было лень присваивать классы, прописывать к ним стили, а потом подключать новую CSS. По этому я писал стили прямо в коде в тегах, конечно же плохой пример, не делайте так, но из-за 2-3 строк, тоже время терять не хочется.

Все готово, можете тестировать и визуализировать выводимый word формат.

Вывод

В этом уроке мы создали онлайн калькулятор расчета услуг, на примере калькулятора ремонта, позаимствовав идею у сайта remont-cityper.ru. Написанный нами код очень сильно отличается от кода, который использован в демо примере. ( можете убедится сами). Так же мы научились создавать word документ под средством php, использовав шаблон rtf и специальные метки. Это отличный урок по созданию счетов, бланков, прайс-листов и т.д. 

Пишите комментарии по этому поводу, я буду раз услышать от вас рекомендации или советы.

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