Капча, корректная работа с ЧПУ, формирование и вывод ошибок для модуля "Контакты"

 

Доброго времени суток! Спасибо что заглянули на мой блог! Сегодня нам предстоит не легкая работа, если Вы следите за циклом "Создать блог с нуля", то должны знать, что пользовательский модуль контактов у нас не развивался очень давно, не имеет ни капчи ни проверки на корректность ввода информации. Если прикинуть, то по сути придется модуль переписать полностью, и это не учитывая того глюкас капчей который я обнаружил совсем недавно.

 

 

Но капча еще подождет, внесенные в нее изменения не слишком глобальны, так что пока поработает в таком режиме.

Я отвлекся =) Так вот, сегодня нам необходимо будет:

  • Переделать шаблон контактов
  • Переписать функцию вывода формы. Добавим вывод ошибок, подключим капчу. Для того чтобы вспомнить, что к чему можете перечитать две статьи, мини цикла апгрейда модуля комментариев ("Апаем функционал модуля комментариев Часть I", "Апаем функционал модуля комментариев Часть II") Работа модуля комментариев аналогична модулю контактов
  • Переписать обработчик добавление сообщений в базу данных. Добавим проверки на корректность и сформируем массив с ошибками, если ошибки имеются.
  • По колдовать с сообщением о удачной отправки, для этого мы будем использовать куки (нам понадобится две новых, не больших, функции), надеюсь приблизительно знаете что это.

 

Для новоприбывших

 

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

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

Если Вы планируете задержаться на моем блоге, то обязательно подпишитесь на RSS ленту блога через ридер, или же по почте, так Вы точно не пропустите новые заметки цикла!

 

Шаблон формы контактов - contacts.html

 

Первым делом нам необходимо переделать шаблон (шаблон очень похож на шаблон формы комментариев), а именно:

  • Вставить код-слово [_error] - Вывод ошибок заполнения формы, если есть таковы
  • Вставить код-слово [_action] - Это код-слово будет заменено на полную ЧПУ или же динамическую ссылку (аналог код-слова [_gomore] у кнопки "читать дальше")
  • html код капчи. В него входят такие код-слова как
    • [_q] - Вместо него, код нам выдаст название картинки капчи (аналогом является форма модуля комментариев)
    • [_codeX] - Четыре кода капчи
    • [_imgX] - Четыре изображения с фруктами

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

<p style="width:500px;" align="center">Если Вам нужно, по какой то причине связаться со мной, то Вы можете это сделать через форму обратной связи, которую Вы видите ниже.</p><br/>
[_error]
<br/>
<form action="[_action]" method="post" name="form2">
<input class="input" name="author_contact" id="author_contact" onclick="if(document.getElementById('author_contact').value == 'Введите имя*')document.getElementById('author_contact').value = '';" type="text" value="Введите имя*">
<br>
<input class="input" name="email_contact" id="email_contact" onclick="if(document.getElementById('email_contact').value == 'E-mail*')document.getElementById('email_contact').value = '';" type="text" value="E-mail*">
<br>
<input class="input" name="them_contact" id="them_contact" onclick="if(document.getElementById('them_contact').value == 'Тема*')document.getElementById('them_contact').value = '';" type="text" value="Тема*">
<br>
<textarea class="input" name="txt_contact" id="txt_contact" onclick="if(document.getElementById('txt_contact').value == 'Введите текст*')document.getElementById('txt_contact').value = '';" rows="10">Введите текст*</textarea>
<br><br>
<p style="margin:0px;">Если вы человек, то нажмите на картинку "<span style="font-weight:bold;">[_q]</span>"</p>
<br>
<input id="code_comm" name="code_contact" type="hidden" value="">
<table width="160px" height="40px" cellpadding="0" cellspacing="0" border="0px">
<tr>
<td>
<img id="cp1OK" style="position:absolute;display:none;" src="img/okCPha.png" border="0px">
<img style="cursor:pointer;" onclick="capcha(1,'[_code0]');" src="[_img0]" border="0px">
</td>
<td>
<img id="cp2OK" style="position:absolute;display:none;" src="img/okCPha.png" border="0px">
<img style="cursor:pointer;" onclick="capcha(2,'[_code1]');" src="[_img1]" border="0px">
</td>
<td>
<img id="cp3OK" style="position:absolute;display:none;" src="img/okCPha.png" border="0px">
<img style="cursor:pointer;" onclick="capcha(3,'[_code2]');" src="[_img2]" border="0px">
</td>
<td>
<img id="cp4OK" style="position:absolute;display:none;" src="img/okCPha.png" border="0px">
<img style="cursor:pointer;" onclick="capcha(4,'[_code3]');" src="[_img3]" border="0px">
</td>
</tr>
</table>
<br>
<p><input class="sub" type="submit" value="Отправить сообщение"></p>
</form>

Думаю проблем, в понимание, у Вас тут не возникнет. Мы подобный шаблон уже делали!

 

Теория работы функции вывода формы

 

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

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

Вопрос, как определить какой именно результат должна вывести функция? Раньше условием было пере направления пользователя на страницу с таким адресом

http://имя сайта/index.php?contact=2

При этом страница с формой была по адресу

http://имя сайта/index.php?contact=1

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

Теперь такой вариант не пройдет, ибо при включенном ЧПУ ссылка будет вот такого вида:

http://имя сайта/contacts.html

И менять ее не красиво =) Именно поэтому я решил использовать cookie.

Cookie (куки) - не большой файл, созданный веб-страничкой, и хранится он на компьютере пользователя.

Если конкретно, куки это эдакая переменная, которая лежит на компе пользователя и доступна даже если загрузится страничка на которой эта переменная не объявляется. Как раз то, что нам нужно!

Я предлагаю следующий алгоритм:

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

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

  • Функция создание куки
  • Функция удаление куки

 

Функции создания и удаления куки

 

Вот код обеих функций, поместите их в файле contact.php, в самом низу

function contactCOOKIE($server_root)//функция создание куки
{
preg_match("/http:\/\/(.*?)\//s",$server_root,$cookieSITE);//чистим переменную с доменом от http://
$cookieSITE = str_replace("www.","",$cookieSITE[1]);//чистим имя домена от www

setcookie("contMESS","YES",time()+300,"/",".".$cookieSITE);//создаем куку, время жизни 5 минут
}
//----------------------------------
function contactCOOKIEdel($server_root)//функция уничтожения куки
{
preg_match("/http:\/\/(.*?)\//s",$server_root,$cookieSITE);//чистим переменную с доменом от http://
$cookieSITE = str_replace("www.","",$cookieSITE[1]);//чистим имя домена от www

setcookie("contMESS","",time()-300,"/",".".$cookieSITE);//назначаем время на минус 5 минут от сейчас
//тем самым кука считается старой и уже не действует
}

Встроенная в php, функция setcookie() позволяет нам создать маленький файл (куку).

  • Первый параметр функции - имя, то бишь название элемент глобальной переменной $_COOKIE ($_COOKIE['имя'])
  • Второй параметр - значение, то есть содержания куки
  • Третий параметр - время существования куки. Время определяется в формате целого числа (сек), то бишь в UNIX формате. Если нам необходимо что бы кука жила 5 минут, мы к сейчас прибавляем 300 секунд ( time()+300 )
  • Четвертый параметр - область видимости куки. Я про него ничего не знаю, поэтому говорить ничего не буду =)
  • Пятый параметр - домен, необходим для того чтобы, кука вызывалась только на том домене на котором она создалась!

Советую почитать подробнее про эту функцию, ибо я про нее знаю лишь поверхностно!

Немного о функциях, код которых я Вам дал. Ничего сложного в них нет. Первая функция (contactCOOKIE())  создает куку, которая будет жить 5 минут. Вторая функция (contactCOOKIEdel()) принудительно делает маленький файл, устаревшим, тем самым кука удаляется.

 

Функция вывод формы - contact()

 

Функция переписана полностью, поэтому лучше скопируйте ее и замените

function contact($mess,$error,$chpu,$server_root)//функция вывода формы
{
if($mess == 1)//Если пользователь еще не отправлял сообщение
{
$sm_read = file("templates/contacts.html");//...подключаем шаблон
$sm_read = implode("",$sm_read);//функция file() возвращаем массив, поэтому склеиваем его

//Вывод ошибки
if($error != "")//если есть ошибки
{
$error = explode("|",$error);//превращаем строку в массив
$echoERROR .= "<p style='color:red;margin:0px;'>Обнаружены следующие ошибки:</p>";//заголовок
for($i=0;isset($error[$i]);$i++)//цикл формирующий список ошибок
{
if($error[$i] != "")$echoERROR .= "<p style='color:red;margin:0px;'>>$error[$i]</p>";//ошибки
}
$sm_read = str_replace("[_error]",$echoERROR,$sm_read);//вывод ошибок на экран
}
else $sm_read = str_replace("[_error]","",$sm_read);//если ошибок нет, то удаляем код-слово
//Вывод ошибки
//капча
include ("moduls/capcha.php");//подключаем модуль капчи
$cods = capcha();//формируем массив с кодами
for($i=0;$i<4;$i++)//цикл вывода инфы из массива
{
$sm_read = str_replace("[_code".$i."]",$cods[$i][1],$sm_read);//вставляем 4 кода в форму
$sm_read = str_replace("[_img".$i."]",$cods[$i][3],$sm_read);//вставляем 4 изображения в форму
if($cods[$i][5] == "true")$sm_read = str_replace("[_q]",$cods[$i][4],$sm_read);//вклеиваем вопрос в форму
}
//капча
}

if($mess == 2)//Если пользователь уже отправил сообщение
{
$sm_read = "<p align='center'>Ваше сообщение отправлено</p>";//Пользователь увидит следующее сообщение
contactCOOKIEdel($server_root);//функция удаления куки с уведомлением о отправки сообщения
}

if($chpu == 0)$action = "index.php?contact=1";//если чпу отключен, то выводим динамическую ссылку в атрибут action
else $action = "contacts.html";//если чпу включен выводим чпу в атрибут action
$sm_read = str_replace("[_action]",$action,$sm_read);//адрес обработчика

return $sm_read;//Выводим с генерированный html код
}

Параметры функции следующие:

  • $mess - индикатор позволяющий определить какую часть функции запустить. Если $mess равна единице, то пользователь увидит форму. Если $mess равна двум, то пользователь увидит уведомление
  • $error - все ошибки, что были созданы во время работы обработчика. Если обработчик еще не был запущен, то эта переменная является пустой, что не даст запустится циклу вывода ошибок
  • $chpu - индикатор позволяющий определить включен или отключен режим ЧПУ. Если включен, то вместо код-слова [_action] в шаблон попадет ссылка вида
    http://имя сайта/contacts.html
    Если режим выключен, то вид у ссылки будет вот таким
    http://имя сайта/index.php?contact=1
  • $server_root - содержит адрес сайта (домен), необходим для создание и удаление куки

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

Вторая часть функции содержит текст уведомления пользователя, так же в этой части запускается функция удаления куки.

 

Обработчик модуля контактов

 

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

//--------------ОБРАБОТЧИК КОНТАКТОВ
$date_day = date("d");//Определяем день
$date_month = date("m");//Определяем месяц
$date_year = date("Y");//Определяем год
$date_time = date("H:i");//Определяем часы и минуты
$date_cont = $date_day."/".$date_month."/".$date_year." ".$date_time;//Склеим все переменные в одну
//получим дату для записи в формате день/месяц/год часы:минуты

//Определяем посланные переменные из формы
if(isset($_POST['author_contact']))$author_contact = $_POST['author_contact'];
if(isset($_POST['email_contact']))$email_contact = $_POST['email_contact'];
if(isset($_POST['them_contact']))$them_contact = $_POST['them_contact'];
if(isset($_POST['txt_contact']))$txt_contact = $_POST['txt_contact'];
if(isset($_POST['code_contact']))$code_contact = $_POST['code_contact'];

if(isset($author_contact) & isset($email_contact) & isset($them_contact) & isset($txt_contact))//Если посланные переменные определены как существующие
{
//Переводим html код (если есть) в каракозябры =)
//В общем то тут несколько лишних строк, но у меня паранойя, поэтому я проверяю ВСЕ переменные
$txt_contact = htmlspecialchars($txt_contact);
$them_contact = htmlspecialchars($them_contact);

//проверка кода
if($code_contact != "")//Если поле было заполнено
{
session_start();//открываем сессию
if(md5($code_contact) != $_SESSION['code'])$error_contact .= "Вы выбрали не ту картинку!|";//Если код не правильный
unset($_SESSION['code']);//уничтожаем код
session_destroy();//уничтожаем сессию
}
else $error_contact .= "Вы не подтвердили, что Вы человек|";//если поле не заполнялось

//проверка поля 'автор'
if($author_contact != "" AND $author_contact != "Введите имя*")//Если поле было заполнено
{
//проверчем корректность ввода имени, только русские и английские буквы, ни каких символов кроме - _ и пробела
if(!preg_match("/^[-_0-9a-zA-Zа-яА-Я ]+$/s",$author_contact))$error_contact .= "Не правильный формат поля 'Введите имя'|";
//поле не должно содержать более 25 символов
if(mb_strlen($author_contact) > 25)$error_contact .= "В поле 'Введите имя' слишком много символов|";
}
else $error_contact .= "Вы не заполнили поле 'Введите имя'|";//если поле не заполнялось

//проверяем заполняли ли поле текст
if($txt_contact == "" OR $txt_contact == "Введите текст*")$error_contact .= "Вы не заполнили поле 'Введите текст'|";

//проверка поля емайл
if($email_contact != "" AND $email_contact != "E-mail*")//если поле было заполнено
{
//проверяем на корректность ввода (по сути отсеиваем не нужные символы в переменной)
if(!preg_match("/^[-_a-zA-Z0-9.]+@[-_a-zA-Z0-9.]+\.[-_a-zA-Z]+$/s",$email_contact))$error_contact .= "Вы ввели некорректный E-mail|";
}
else $error_contact .= "Вы не заполнили поле 'E-mail'|";//если поле не заполнялось

//проверка адреса сайта
if($them_contact != "" AND $them_contact != "Тема*")//Если поле заполнили
{
if(mb_strlen($them_contact) > 250)$error_contact .= "В поле 'Тема' слишком много символов|";
}
else $error_contact .= "Вы не заполнили поле 'Тема'|";//если поле не заполнялось

if(!isset($error_contact))
{
//Избавляемся от кавычки
$them_contact = str_replace("'","&#039",$them_contact);
$txt_contact = str_replace("'","&#039",$txt_contact);
$txt_contact = str_replace("\n","<BR>",$txt_contact);//Заменяем переносы строки на тег <BR>

//ДОБАВЛЯЕМ СООБЩЕНИЕ В БАЗУ ДАННЫХ
$result_add_cont = mysql_query ("INSERT INTO mess_admin (login,them,date_g,email,text)
VALUES ('$author_contact','$them_contact','$date_cont','$email_contact','$txt_contact')");
//ДОБАВЛЯЕМ СООБЩЕНИЕ В БАЗУ ДАННЫХ
//ИЛИ
//ООТПРАВЛЯЕМ СООБЩЕНИЕ ПО ПОЧТЕ
//$to = "test@test.ru";//Ваш почтовый адрес
//$txt_contact = $author_contact." <".$email_contact."> Вам пишет: ".$txt_contact;//Приклеиваем к тексту сообщения
//контактную информацию отправителя
//mail($to,$them_contact,$txt_contact);//Собственно сама отправка
//ООТПРАВЛЯЕМ СООБЩЕНИЕ ПО ПОЧТЕ
contactCOOKIE($server_root);//функция которая создаст куку с уведомлением о том что сообщение отправленно

header("location: ".getenv('HTTP_REFERER'));//Перенаправляем пользователя
exit;//к сообщениею об успешной отправки
}
}
//--------------ОБРАБОТЧИК КОНТАКТОВ

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

Нам осталось совсем не много, так что давайте уже заканчивать =)

 

Подключение модуля

 

Открываем файл пользовательский файл index.php и правим в нем подключение модуля

//МОДУЛЬ КОНТАКТЫ
if($contact)//Если существует переменная
{//то
include("moduls/contact.php");//подключаем модуль
if(!isset($error_contact))$error_contact = "";//Если ошибок нет, то заносим в переменную пустоту
if(isset($_COOKIE['contMESS']))$contact = 2;//если существует кука, то выводим меняем значение
//переменной, так пользователь увидит сообщение о удачной отправки

$txt = contact($contact,$error_contact,$chpu,$server_root);//Выводим результат функции в переменную, которая отобразится на экране пользователя
}
//МОДУЛЬ КОНТАКТЫ

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

 

Последний штрих, функция javascript по работе с капчей

 

Открываем шаблон comm_form.html и вырезаем из нее функцию капчи и функцию плавного перемещения к комментарию. Было бы очень плохо оставить эти две функции в шаблоне, поэтому давайте перенесем их в файл js.js

Теперь открываем файл js.js и вставляем в него вырезанные функции

function capcha(v,val)
{
document.getElementById("code_comm").value = "";
for(var i=1;i<=4;i++)document.getElementById("cp"+i+"OK").style.display = "none";

document.getElementById("cp"+v+"OK").style.display = "block";
document.getElementById("code_comm").value = val;
}
//--------------------------------------
function reqcomm(id,author,step)
{
if(step == 0)
{
document.getElementById("recomm").value = id;
document.getElementById("reauthor").innerHTML = author;
document.getElementById("messFROM").style.display = "block";
jQuery.scrollTo('#messFROM',1000);
}
if(step == 1)
{
document.getElementById("recomm").value = id;
document.getElementById("reauthor").innerHTML = author;
document.getElementById("messFROM").style.display = "none";
}
footer();
}

Если не перенести функцию капчи в общий файл с функциями javascript, то капча контактов работать не будет

 

Заключение

 

После проделанной работы, наш модуль контактов будет работать по тому же принципу как модуль комментариев. При этом атрибут action у формы контактов будет принимать двоякое значение, все зависит от того включен режим ЧПУ или нет

 

результат работы

 

Если у Вас что-то не получается, то пользуйтесь формой ниже, я обязательно попробую Вам помочь. Если Вы еще не подписаны на мой блог, то обязательно подпишитесь на RSS ленту блога через ридер, или же по почте, так Вы точно не пропустите новые заметки цикла!

Всего Вам наилучшего! У меня Все!

Исходник

_______

P.S.: Если Вы сталкивались с вопросом продления лицензии на услуги связи для своей компании, то обратитесь за помощью к людям из ИнфоСвязь Консалтинг, по ссылке www.license-pro.ru/prolong.html

 

Возможно Вам будут интересны следующие заметки

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

Ваше имя *
Сайт
Ваш E-mail *
Ваше сообщение *
 
Влад, 10 Июня 2014 г. 07:40 пишет:
Читатель
Доброго времени суток Вам, Алексей. Уже больше месяца изучаю Ваш метод создания СМS с нуля и хочу заметить - статьи просто отличные. Материал изложен и подан на 5+, браво.
Собственно, я хотел бы задать вопрос. Почему в своих примерах (комментарии/контакты), Вы делали обработку вводимых данных на сервере средствами php, а не js?
Вопрос появился после того, как я закончил с этой статьей, и проверил модуль контактов. Если была допущена ошибка при заполнении формы, например при вводе капчи, все заполненные данные теряются. Это не критично, но все же, не совсем приятно.
Алексей, 14 Июня 2014 г. 11:50 пишет:
Автор
Это все результат упрощения подоваемой информации.
Ответ для пользователя: Влад