Скрипт формы обратной связи с вложением, капчей, памятью, контролем длины сообщения и проверками как через JS на стороне клиента, так и на сервере. Возможность отправки в несколько адресов – в скрипте реализовано в два адреса + администратору.
За основу взят скрипт http://blog.webmasterschool.ru/php/184/. Подробные объяснения по скрипту можно найти там же.
Все привнесенное вроде бы объяснено, но с благодарностью восприму комментарии/замечания/пожелания/улучшения и на вопросы постараюсь ответить.
*Примечание: количество файлов для отправки определяйте опытным путем – 5 файлов проходит. Почему через JS ограничение в 900 символов (хотя в php
оставлено 1500) – стандартное количество символов в печатном листе А4 – 1800, взята половинка. Меняется в файле dlina_post.js
. Кнопка очистки введенного работает только при первоначальном заполнении формы, поскольку потом все берется из сохраненного в сессии.
- Память, то есть сохранение введенного в полях формы при ошибке, исключающей отправку (пустое поле, неправильный формат в
e-mail
, неправильный или невведенный проверочный код), реализовано через сессии. - Контроль длины сообщения – через JQuery
- Капча – с использованием исходников проекта Kcaptcha
- Проверка полей на стороне сервера – через PHP :)
- Проверка полей на заполнение на стороне клиента – через JS (активация кнопки при заполнении)
- Добавление файлов для вложения – через JS
- Есть подсказка включить JS в браузере
- В исходник включены все необходимые для работы скрипта файлы
Пример использования:
Перед <!DOCTYPE>
:
<?php
include('kcaptcha/kcaptcha.php'); //подключаем капчу
session_start(); //начинаем сессию
/*
получатели */
// Какая кнопка нажата, туда и отправляем
if ($_POST['sendMail']) {
$admin = "name@domen.ru".", "; //адрес отправки по первой кнопке
$admin .= "admin@domen.ru";// админу (или просто одновременно во второй адрес
}
if ($_POST['sendMail1']) {
$admin = "name1@domen.ru".", "; //во второй адрес по второй кнопке
$admin .= "admin@domen.ru";// и админу
}
if ( isset( $_POST['sendMail'] ) or isset( $_POST['sendMail1'] ) )
{
$name = substr( $_POST['name'], 0, 64 );
$email = substr( $_POST['email'], 0, 64 );
$subject = substr( $_POST['subject'], 0, 64 );
$message = substr( $_POST['message'], 0, 1500 );
$_SESSION['name'] = htmlspecialchars($_POST['name']);
$_SESSION['email'] = htmlspecialchars($_POST['email']);
$_SESSION['subject'] = htmlspecialchars($_POST['subject']);
$_SESSION['message'] = htmlspecialchars($_POST['message']);
$error = '';
if (empty ( $_POST['keystring'] ) ) $error = $error.'<li >Не заполнено поле "Проверочный код"</li>';
if ( !empty ( $_POST['keystring'] ) && ( $_SESSION['captcha_keystring'] !== $_POST['keystring'] ) ) $error = $error.'<li>Ошибка проверочного кода</li>';
if ( empty( $name ) ) $error = $error.'<li>Не заполнено поле "Имя"</li>';
if ( empty( $email ) ) $error = $error.'<li>Не заполнено поле "E-mail"</li>';
if ( empty( $subject ) ) $error = $error.'<li>Не заполнено поле "ТЕМА"</li>';
if ( empty( $message ) ) $error = $error.'<li>Не заполнено поле "Сообщение"</li>';
if ( !empty( $email ) and !preg_match( "#^[0-9a-z_\-\.]+@[0-9a-z\-\.]+\.[a-z]{2,6}$#i", $email ) )
$error = $error.'<li>поле "E-mail" должно соответствовать формату name@domen.ru</li>';
if ( !empty( $error ) ) {
$_SESSION['sendMailForm']['error'] = '<p>При заполнении формы допущены ошибки:</p><ul>'.$error.'</ul>';
$_SESSION['sendMailForm']['name'] = $name;
$_SESSION['sendMailForm']['email'] = $email;
$_SESSION['sendMailForm']['subject'] = $subject;
$_SESSION['sendMailForm']['message'] = $message;
header( 'Location: '.$_SERVER['PHP_SELF'] );
die();
}
// вложения
$filepath = array();
$filename = array();
for( $i = 0; $i < count($_FILES['file']); $i++) {
if ( !empty( $_FILES['file']['tmp_name'][$i] ) and $_FILES['file']['error'][$i] == 0 ) {
$filepath[] = $_FILES['file']['tmp_name'][$i];
$filename[] = $_FILES['file']['name'][$i];
}
}
$body = "АВТОР:\r\n".$name."\r\n\r\n";
$body .= "E-MAIL:\r\n".$email."\r\n\r\n";
$body .= "ТЕМА:\r\n".$subject."\r\n\r\n";
$body .= "СООБЩЕНИЕ:\r\n".$message;
if ( send_mail($admin, $body, $email, $filepath, $filename) )
$_SESSION['success'] = true;
else
$_SESSION['success'] = false;
header( 'Location: '.$_SERVER['PHP_SELF'] );
die();
}
// Вспомогательная функция для отправки почтового сообщения с вложением
function send_mail($admin, $body, $email, $filepath, $filename)
{
$subject = '=?utf-8?B?'.base64_encode('Заполнена форма на сайте').'?='; //заменить utf-8 на windows-1251, если нужно и замените ниже
$boundary = "--".md5(uniqid(time())); // генерируем разделитель
$headers = "From: ".strtoupper($_SERVER['SERVER_NAME'])." <".$email.">\r\n";
$headers .= "Return-path: <".$email.">\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .="Content-Type: multipart/mixed; boundary=\"".$boundary."\"\r\n";
$multipart = "--".$boundary."\r\n";
$multipart .= "Content-type: text/plain; charset=\"utf-8\"\r\n"; //заменить utf-8 на windows-1251, если заменили выше
$multipart .= "Content-Transfer-Encoding: quoted-printable\r\n\r\n";
$body = quoted_printable_encode( $body )."\r\n\r\n";
$multipart .= $body;
$file = '';
$count = count( $filepath );
if ( $count > 0 ) {
for ( $i = 0; $i < $count; $i++ ) {
$fp = fopen($filepath[$i], "r");
if ( $fp ) {
$content = fread($fp, filesize($filepath[$i]));
fclose($fp);
$file .= "--".$boundary."\r\n";
$file .= "Content-Type: application/octet-stream\r\n";
$file .= "Content-Transfer-Encoding: base64\r\n";
$file .= "Content-Disposition: attachment; filename=\"".$filename[$i]."\"\r\n\r\n";
$file .= chunk_split(base64_encode($content))."\r\n";
}
}
}
$multipart .= $file."--".$boundary."--\r\n";
if( mail($admin, $subject, $multipart, $headers) )
return true;
else
return false;
}
// для PHP 5.3 и выше этот блок убрать - начало
function quoted_printable_encode ( $string ) {
// rule #2, #3 (leaves space and tab characters in tact)
$string = preg_replace_callback (
'/[^\x21-\x3C\x3E-\x7E\x09\x20]/',
'quoted_printable_encode_character',
$string
);
$newline = "=\r\n"; // '=' + CRLF (rule #4)
// make sure the splitting of lines does not interfere with escaped characters
// (chunk_split fails here)
$string = preg_replace ( '/(.{73}[^=]{0,3})/', '$1'.$newline, $string);
return $string;
}
// для PHP 5.3 и выше этот блок убрать - end
function quoted_printable_encode_character ( $matches ) {
$character = $matches[0];
return sprintf ( '=%02x', ord ( $character ) );
}
?>
Между <head></head>
:
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Скрипт формы обратной связи PHP "Full" - с вложением, капчей, памятью, контролем длины сообщения и проверками</title>
<script src="js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="js/dlina_post.js"></script>
<script>var i=1; function addtext(el){a=el.parentNode;a.innerHTML=a.innerHTML+'<br />'+(i++)+'-й <input type="file" name="file[]" />';}</script>
<style>
#java_error {padding-top:18px;padding-bottom:20px;font-size:24px;height:px;width:750px;text-align:center;margin: 0 auto;background-color:yellow;}
#java_error span {color:blue;text-decoration:underline;}
</style>
Между <body></body>
:
<noscript><div id="java_error">Для нормальной работы сайта включите JavaScript.<a href="http://www.google.ru/support/bin/answer.py?answer=23852" target="_blank"><span style="margin-left:10px;">Как?</span></a><br /><br />
For normal operation of the site enable JavaScript.<a href="http://support.google.com/bin/answer.py?hl=en-GB&hlrm=ru&answer=23852" target="_blank"><span style="margin-left:10px;">How?</span></a></div></noscript>
<div style="text-align:center">
<h1>Скрипт формы обратной связи PHP "Full" - с вложением, капчей, памятью, контролем длины сообщения и проверками</h1>
<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="POST" enctype="multipart/form-data" name="mainForm">
<table id="mailform" style="margin:0 auto;">
<tr><td style="font-weight:bold">Имя: </td><td style="float:left"><input onkeyup="changeButtonStatus()" onchange="changeButtonStatus()" type="text" name="name" maxlength="64" value="<?php if ($_SESSION['sendMailForm']['error']) echo ($name = $_SESSION['name']); ?>" /></td></tr>
<tr><td style="font-weight:bold">E-mail: </td><td style="padding-top:5px;float:left"><input onkeyup="changeButtonStatus()" onchange="changeButtonStatus()" type="text" name="email" maxlength="64" value="<?php if ($_SESSION['sendMailForm']['error']) echo ($name = $_SESSION['email']); ?>" /></td></tr>
<tr><td style="font-weight:bold">Тема: </td><td style="padding-top:5px;float:left"><input onkeyup="changeButtonStatus()" onchange="changeButtonStatus()" type="text" name="subject" maxlength="64" value="<?php if ($_SESSION['sendMailForm']['error']) echo ($name = $_SESSION['subject']); ?>" /></td></tr>
<tr><td style="font-weight:bold;">Сообщение: </td><td style="padding-top:5px;"><textarea onkeyup="changeButtonStatus()" onchange="changeButtonStatus()" name="message" rows="7" id="message" cols="90" ><?php if ($_SESSION['sendMailForm']['error']) echo ($name = $_SESSION['message']); ?></textarea><br /><span style="float:left">Максимальная длина сообщения 900 символов. Осталось <span id="left"> </span> символов</span></td></tr>
<tr><td style="font-weight:bold"> </td><td style="float:left"><div style="text-align:left"><input type="button"value="Прикрепить файл" onclick="addtext(this);" /></div></td></tr>
<tr><td> </td><td style="text-align:center;padding-top:10px;"><div style="float:left"><input type="submit" title="Отправить форму" name="sendMail" value=" ▲ Отправить в первый адрес " id="send_but" style="margin-bottom:5px" /><br />
<input type="submit" title="Отправить форму" name="sendMail1" value=" ▲ Отправить во второй адрес " id="send_but" /></div>
<b>Проверочный код:</b> <input class="inputIE" type="text" size="7" style="height:18px;" name="keystring" id="keystring" /> <img style="vertical-align:middle;" src="kcaptcha/index.php?<?php echo session_name()?>=<?php echo session_id()?>">
<input type="reset" title="Очистить форму" value=" ○ Очистить " id="clear_but" style="margin-left:5px;" /><br /><span id="request_all"><span id="star">*</span> Все поля обязательны для заполнения</span></td></tr></table></form>
<?php
if ( isset( $_SESSION['success'] ) ) {
if ( $_SESSION['success'] )
echo '<p style="background:lightgreen">Письмо успешно отправлено</p>';
else
echo '<p style="background:yellow;border:1px solid red">Ошибка при отправке письма</p>';
unset( $_SESSION['success'] );
}
if ( isset( $_SESSION['sendMailForm'] ) ) {
echo $_SESSION['sendMailForm']['error'];
$name = htmlspecialchars ( $_SESSION['sendMailForm']['name'] );
$email = htmlspecialchars ( $_SESSION['sendMailForm']['email'] );
$subject = htmlspecialchars ( $_SESSION['sendMailForm']['subject'] );
$message = htmlspecialchars ( $_SESSION['sendMailForm']['message'] );
unset( $_SESSION['sendMailForm'] );
} else {
$name = '';
$email = '';
$subject = '';
$message = '';
}
?>
</div>
<script language="JavaScript">
<!--
var f=document.mainForm;
function changeButtonStatus(){
f.sendMail.disabled=(f.name.value && f.email.value && f.subject.value && f.message.value) ? false : true;
f.sendMail1.disabled=(f.name.value && f.email.value && f.subject.value && f.message.value) ? false : true;
}
changeButtonStatus();
//-->
</script>
<script type="text/javascript" src="js/check_dlina.js"></script>
PHP>=5.3
: PHP=5.2
: При отправке письма из примера почта пойдет в тот же адрес, что и при отправке из "Контакт".
Комментарии:
coder.hol.es /* Админ */#
Посмотрите: _http://habrahabr.ru/post/37753/. Думается, что в почтовой форме это не столь уж необходимо – это не загрузка файла на сервер. Кроме того, защита по расширению не мешает переименовать файл в нужное расширение другого типа. А обрабатывать файл по содержимому в почтовой форме также не стоит, имхо.
Кирилл#
Спасибо за скрипт. Но такой вопрос максимальный вес прикрепляемого файла примерно 8 Mb… как его увеличить, если это возможно и где это проверяется???
coder.hol.es /* Админ */#
Пожалуйста=) Если есть доступ к php.ini, то меняется в строке post_max_size = 8M; если доступа нет (как правило), то можно в htaccess установить флаг: php_value post_max_size 10M
Цифры перед М меняете на нужные.
Проверяется – закидываете на хостинг в корень файл php с одной строкой <?php echo phpinfo(); ?>, вызываете его и смотрите цифру в разделе "Core".
Anton#
Спасибо, здорово помогли!
coder.hol.es /* Админ */#
Рад, пожалуйста=)