Сделать стартовой  Добавить в избранное
Воскресенье, 19.05.2024, 18:13
Главная
Регистрация
Вход
Мир софта!
Приветствую Вас Гость | RSS
Mirsoft
Меню сайта
Наш опрос
Какое радио ты любиш?
Всего ответов: 29
Автоматическое построение форм различной сложности и отправка их письмом с аттачами произвольного количества

Все сталкивались с тривиальной задачей — создание формы для отправки по e-mail.
Обычно не возникает никаких проблемм. Но и работа эта не столь интересна и увлекательна. Простая рутина.
Возникает идея создать программу, которая автоматизировала бы этот процесс.
Для начала определим задачу.
Предположим, нам нужно создать формы на сайте.
В формах может присутствовать:

  • заголовок раздела формы
  • текстовое поле (text)
  • текстовый блок (textarea)
  • поле пароля (password)
  • поле выбора из списка (select)
  • поле checkbox
  • поле радио буттона (radio)
  • невидимое поле (hidden)
  • поле загрузки файла (file)

Отсылать письма предполагается в текстовом виде с аттачами. Письма в формате html не пользуются популярностью у народа.
Должна быть проверка на заполненность полей, обязательных к заполнению.
Вот все пункты задачи готовы.
Решено сделать 3 файла:

  • файл с формой
  • файл отправки формы
  • файл инициализации формы

Забегая вперед, могу предположить, что кто-то захочет положить файлы программы (первые два) в отдельный каталог, например forms, и будет просто инклюдить файл с формой на нужных страницах сайта, передавая ему параметром путь к файлу инициализации данной формы. Так как формы могут все-таки отличаться друг от друга в оформлении, я не стану городить огромный файл с бесконечным количеством вариантов и приведу полностью рабочий пример, работающий на сайте «Седьмого континента» в разделе «поставщики», а также на сайте gipragor.ru в разделе «задать вопрос».

Добавлю, что в наших случаях в формах были вариации вида полей text, textarea (в форме «Седьмого континента» 3 вида поля text). В вашем случае, возможно, понядобится еще несколько вариантов для полей. Все делается аналогично тому, что будет рассмотрено ниже.

Начнем с описания файла инициализации формы.

Ниже приведен текст файла ini.php


Выбор адресата^head^0
Выберите из списка^select^1^mail консультант|info@gipragor.ru|selected админ|totoeval@mtu-net.ru
Ваши координаты^head^0
Имя^text^1
Телефон^text^0
Факс^text^0
<nobr>Е-mail</nobr>^text^0
Я хочу получить ответ по телефону^checkbox^0^checked
Вопрос^head^0
Тема^textarea^1
Вопрос^textarea^1^long
Присоединить файл^file^0^attach
Присоединить файл 2^file^0^attach2
Предыдущая страница^hidden^0^refer

Как видим, каждое поле формы описывается отдельной строкой.
Как я ни старался сделать универсальным оформление всех полей форм, — не получилось.
Вследствие этого, предлагаю такое оформление:
Первым везде идет название поля, которое выводится на экран.
Вторым — тип поля формы:
  • text
  • password
  • textarea
  • checkbox
  • radio
  • hidden
  • file

Третий — указатель обязательного заполнения поля. Если стоит 1 — поле обязательно. Если параметр пустой или любой отличающийся от 1, то поле не обязательное.
Четвертым указываем дополнительный параметр, если он необходим. У каждого вида поля свои дополнительные параметры:

  • text — long указывает на то, что поле-строка будет длинной и размещена под названием; обычное поле, без параметра, размещается справа от названия
  • textarea — то же самое, что и у text
  • checkbox — checked указывает на то, что чекбокс будет выбран по-умолчанию
  • radio — четвертым параметром указывается имя группы радио-буттонов, а пятым — checked, как и у checkbox
  • file — указываем имя указателя массива загружаемых файлов
  • hidden — указываем параметр, в соответствии с которым в значение этого поля будет подставлено определенное значение, либо параметр будет передан как есть

Ну вот покончили с инициализацией формы.

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

Создаем файл index.php с нижеприведенным содержимым.

<!-- начало -->

<h1>Задать вопрос</h1>

<?

if ($is_send == "send_query")
{
echo "<p>Вопрос был отправлен.</p>";
}
?>

<!--
 Выводим форму типа multipart/form-data 
 для отправки через нее текстовых полей и файлов
-->
<form method="post" action="send.php" ENCTYPE="multipart/form-data" 
onsubmit="return Validate(this);">
<table border="0" cellspacing="0" cellpadding="5" width="100%">
<tr><td class="text" colspan="2" align="center"><b></b></td></tr>
<?
// читаем файл инициализации в массив $texts
$texts=file("ini.php");

// перебираем все строки в файле и определяем пустые
for ($j=0; $j<(sizeof($texts)); $j++)
{
 // оператором trim удаляем у строки слева и справа пробелы и переносы
 $texts[$j]=trim($texts[$j]);
 // если есть пустые строки, то в новый массив $proposal_text они не записываются
 if ($texts[$j] != "") {$proposal_text[]=$texts[$j];}
}

// обнуляем переменную, в которую будут занесены все обязательные для заполнения поля
$fields=""; // имена полей формы
$fieldnames=""; // названия полей формы

// перебираем все строки инициализации в массиве $proposal_text
// имена полей будут называться form[0], form[1], form[2]...
// Таким образом, мы передадим всю форму в одном массиве.
// Индекс элемента массива будет указателем строки описания поля в файле инициализации
// для дальнейшей обработки полученной формы.
for ($i=0; $i<(sizeof($proposal_text)); $i++)
{
 // разобьем строки специальным разделительным символом ^
 // тогда $proposal[0] - текстовое название поля
 // тогда $proposal[1] - указатель типа поля формы:
 // text - текстовое поле-строка
 // textarea - текстовое поле-блок
 // hidden - невидимое поле
 // password - поле ввода пароля
 // file - форма для загрузки файла
 // checkbox - чекбокс
 // radio - радио буттон
 // head - заголовки разделов форм, не имеют никаких полей, 
 // лишь текст выводится полужирным шрифтом, либо выделяется иным способом
 // тогда $proposal[2] - указатель обязательного заполнения поля посетителем.
 //Если он равен 1, то поле обязательно, если любое другое значение - нет
 // тогда $proposal[3] - дополнительный параметр.
 // например, у нас это:
 // long в поле text и поле textarea означает, что поле бОльшей ширины
 // и расположено под названием поля
 // refer в поле hidden говорит о том, что передается в невидимом поле
 // адрес предыдущей страницы, посещенной пользователем
 // attach в поле file - имя поля загружаемого пользователем файла

 // все поля оформляются соответственно указанному типу ниже в блоке switch
 $proposal=explode('^',$proposal_text[$i]);
 // переменной type присвоем тип поля
 $type=trim($proposal[1]);

 // определяем, обязательно ли к заполнению текущее поле
 if (isset($proposal[2]))
 {
 if (trim($proposal[2]) == '1')
 // если в поле указателя содержится 1, то добавляем имя поля к 
 {
 // если в переменную fields уже были записаны данные,
 // то ставим запятую
 if ($fields != "") {$fields.=', ';}
 $fields.="'form[$i]'";
 if ($fieldnames != "") {$fieldnames.=', ';}
 $fieldnames.="'".$proposal[0]."'";
 $imperative=" *";
 }
 else {$imperative="";}
 }
 
 // если в строке есть дополнительный параметр, то записываем его в пtременную param
 if (isset($proposal[3])) {$param=trim($proposal[3]);}

 // стравниваем тип поля с возможными вариантами и соответственно оформляем его
 switch ($type) {
 case "head": // поле заголовка
 echo "<tr>\n\t".
 "<td class=\"text\" colspan=\"2\"><br>".
 "<p><b>$proposal[0]</b></p>".
 "</td>\n</tr>\n";
 break;
 case "text": // текстовое поле 
 if (isset($proposal[3])) {
 if ($param == "long") {
 // если поле длинное, то располагаем его под названием
 // и увеличиваем длину
 echo "<tr>\n\t".
 "<td colspan=\"2\" class=\"text\">".
 $proposal[0]."$imperative<div align=\"right\">\n\t".
 "<input type=\"text\" name=\"form[$i]\" size=\"102\">".
 "</div></td>\n</tr>\n";
 }
 }
 else {
 // иначе выводим стандартное поле-строку справа от названия поля
 echo "<tr>\n\t".
 "<td class=\"text\">".$proposal[0]."$imperative</td>\n\t".
 "<td align=\"right\" valign=\"top\">".
 "<input type=\"text\" name=\"form[$i]\" size=\"50\">".
 "</td>\n</tr>\n";
 }
 break;
 case "password": // поле пароля
 echo "<tr>\n\t".
 "<td class=\"text\">".$proposal[0]."$imperative</td>\n\t".
 "<td align=\"right\" valign=\"top\">".
 "<input type=\"password\" name=\"form[$i]\" size=\"50\">".
 "</td>\n</tr>\n";
 break;
 case "textarea": // поле текстового блока оформляем аналогично текстовому полю
 if (isset($proposal[3])) {
 if ($param == "long") {
 echo "<tr>\n\t".
 "<td colspan=\"2\" class=\"text\">".
 $proposal[0]."$imperative".
 "<div align=\"right\">\n\t".
 "<textarea name=\"form[$i]\" rows=\"6\" cols=\"102\">".
 "</textarea></div></td>\n</tr>\n";
 }
 }
 else {
 echo "<tr>\n\t".
 "<td class=\"text\" valign=\"top\">".
 $proposal[0]."$imperative</td>\n\t".
 "<td align=\"right\" valign=\"top\">".
 "<textarea name=\"form[$i]\" rows=\"4\" cols=\"50\">".
 "</textarea></td>\n</tr>\n";
 }
 break;
 case "radio": // радио буттон.
 //Его дополнительный параметр - имя переменной-группы радио-буттонов.
 if (!isset($proposal[3])) {$param = "form[$i]";}
 if (!isset($proposal[4])) {$checked = "";}
 // если не задан параметр выбора буттона по-умолчанию
 else {$checked = " checked";}
 // если выбран по-умолчанию
 echo "<tr>\n\t".
 "<td colspan=\"2\" class=\"text\">".
 "<input type=\"radio\" name=\"$param\" id=\"id$i\"$checked>".
 "<label for=\"id$i\"> $proposal[0]</label></td>\n</tr>\n";
 break;
 case "checkbox": // чекбокс
 if (!isset($proposal[3])) {$checked = "";}
 // если не задан параметр выбора чекбокса по-умолчанию
 else {$checked = " checked";}
 // если выбран по-умолчанию
 echo "<tr>\n\t".
 "<td colspan=\"2\" class=\"text\">".
 "<input type=\"checkbox\" name=\"form[$i]\" id=\"id$i\"$checked>".
 "<label for=\"id$i\"> $proposal[0]</label></td>\n</tr>\n";
 break;
 case "hidden": // невидимое поле.
 // От его параметра зависит, что в нем будет передаваться.
 // Если параметр не описан, то он будет передан по-умолчанию как есть
 if (!isset($proposal[3])) {$param = "form[$i]";}
 echo "<input type=\"hidden\" name=\"form[$i]\"";
 if ($param=="refer") {echo " value=\"".urlencode($HTTP_REFERER)."\">";}
 else {echo " value=\"$param\">\n";}
 break;
 case "file": // поле загружаемого пользователем файла
 if (!isset($proposal[3])) {$param = "form[$i]";}
 echo "<tr>\n\t".
 "<td align=\"right\" valign=\"bottom\">".
 "<p align=\"left\">$proposal[0]$imperative<br>".
 "<input type=\"file\" name=\"file_att[$param]\" size=\"35\"></p>".
 "</td></tr>\n";
 break;
 case "select": // поле выбора селект
 if (isset($proposal[3])) { // если заданы параметры селекта
 $options = explode("\t", $proposal[3]);
 // разделяем параметры каждой строки селекта
 $option_text=explode("|",$option[0]);
 // разбиваем первый подпараметр селекта
 // на имя селекта и вид (multiselect и обычный)
 // получаем в $option_text[1] - вид селекта
 if ($option_text[1]=="multiselect")
 {
 if (isset($option_text[2]))
 {
 $multiselect="size=$option_text[2]";
 }
 $multiselect.=" multiselect";
 }
 else {$multiselect=" size=\"1\"";}
 echo "<tr>\n\t".
 "<td class=\"text\">$proposal[0]$imperative</td>\n\t".
 "<td align=\"right\" valign=\"top\">".
 "<select name=\"form[$i]\" style=\"width: 317\"$multiselect>\n";
 // выводим тег селекта
 for ($z=1; $z<sizeof($options); $z++)
 // в 0 строке селекта у нас параметр, указывающий отправщику,
 // как обрабатывать текущий селект
 {
 // выводим строки селекта
 $option_text=explode("|", $options[$z]);
 // в первой части - текст строки,
 // во второй - передаваемое значение
 if (!isset($option_text[2])) {$option_text[2]="";}
 // если параметр "выбранная строка" не установлен
 echo "\t<option value=\"$option_text[1]\" $option_text[2]>".
 "$option_text[0]</option>\n";
 // вывели строку селекта
 }
 echo "</select></td>\n</tr>\n";
 }
 break;
 default:
 // если тип не определен, то ничего не выводится.
 // И, следовательно, стоит подумать, что еще не учтено.
 } 
}
?>
</table>
<!--
 Выведена таблица с формой. 
 Осталось вывести на экран кнопки "отправить" и "очистить",
 как это делают умные дядьки на других сайтах.
-->
<table border="0" cellspacing="5" cellpadding="0" width="100%">
<tr>
 <td align="right" valign="bottom"><input type="submit" value="Отправить">
 <img src="/images/1x1.gif" width="10" height="50">
 <input type="reset" value="Очистить">
 </td>
</tr>
</table>
<!--
 Конечно, здесь могло не быть этого кода,
 а кнопки отправки формы и очищения можно задать в файле инициализации,
 добавив и их обработку в программе.
-->
</form>
<p>Вы можете задать вопрос.
 С вопросом можно отправить файлы.<br>
 Ответ вы получите на адрес электронной почты,
 указанный в координатах,
 либо по телефону, если поставите галочку у соответствующего пункта.</p>
<!-- 
 Яваскрипт, которому мы передали список полей формы, обязательных к заполнению
 Он определит после попытки отправки формы, заполненны ли эти поля.
 Если не заполнены, то скрипт ругнется и укажет какое поле не заполненно,
 установив в него курсор.
-->
<script language="JavaScript">
fields = new Array(<? echo $fields; ?>);
fieldnames = new Array(<? echo $fieldnames; ?>);
function Validate(forma)
{
 for(i=0;i<fields.length;i++)
 {
 field = fields[i];
 if (forma.elements[field].value == "")
 {
 alert("Вы должны заполнить поле \""+fieldnames[i]+"\"");
 forma.elements[field].focus();
 return false;
 }
 }
 return true;
}
</script>



</td>
</tr>
</table>
<!-- конец -->

Ну вот, наша форма выводится на экран пользователя, и он старательно, прикусив язык, заполняет все её поля.

Но мы-то знаем, что вывести форму и заполнить её — половина дела. Важно получить форму, обработать её и отправить по выбранному или указанному по-умолчанию адресу.

Ниже приведен текст файла отправки письма с аттачами send.php, который мы кладем в папку с index.php.


<?
// определяем, с какой страницы пришел посетитель на страницу отправки
if (strpos($HTTP_REFERER, "gipragor.ru/feedback") === false) {
 // если не со страницы отправки формы, то кидаем его в форму
 header("location: .");
}

// если посетитель прошел проверку, читаем файл инициализации
$texts=file("ini.php");

// перебираем все строки в файле и сохраняем в новый массив только не пустые
for ($j=0; $j<(sizeof($texts)); $j++)
{
 $texts[$j]=trim($texts[$j]);
 if ($texts[$j] != "") {$proposal_text[]=$texts[$j];}
}

// Объявляем пустую строковую переменную, в которой будет храниться сообщение
$mailtext="";

// Перебираем все строки массива формы
for ($i=0; $i<(sizeof($proposal_text)); $i++)
{
 // Разбиваем строки по разделительному символу ^
 // получаем подстроки, в которых хранится:
 // 0 - текст названия поля формы
 // 1 - тип поля формы
 // 2 - указатель обязательности заполнения поля формы
 // 3 - дополнительные параметры поля формы
 $proposal=explode('^',$proposal_text[$i]);
 $type=trim($proposal[1]);
 if (isset($proposal[3])) {$proposal[3]=trim($proposal[3]);}
 if (!isset($form[$i])) {$form[$i]="нет данных";}
 // перебираем варианты типов полей формы
 switch ($type)
 {
 case "head": // если заголовок раздела формы
 if ($mailtext != "")
 {
 // если это не первый заголовок в форме,
 // то ставим перед ним 2 пустые строки
 $mailtext.="\n\n";
 }
 $mailtext.="\t$proposal[0]\n";
 break;
 case "text": // если поле текствое - строка
 if (isset($proposal[3]))
 {
 if ($proposal[3] == "long")
 { // если строка длинная, то выводим ее под названием поля
 $mailtext.="$proposal[0]:\n$form[$i]\n\n";
 }
 }
 else
 { // если строка не длинная, то выводим ее справа от названия поля
 $mailtext.="$proposal[0]: $form[$i]\n";
 }
 break;
 case "textarea": // поле текстового блока
 $mailtext.="$proposal[0]:\n$form[$i]\n\n";
 break;
 case "radio": // радио буттон
 $group == "$proposal[2]";
 $mailtext.="$proposal[0]: $group\n";
 break;
 case "checkbox": // чекбокс
 if (trim($form[$i]) == "on")
 { // если чекбокс выделили, то его значение - on
 $mailtext.="$proposal[0]\n";
 }
 break;
 case "hidden": // скрытое поле. Обрабатываем его взависимости от параметра
 if (!isset($proposal[3])) {$param = "form[$i]";}
 if ($param="refer") {$form[$i]=urldecode($form[$i]);}
 $mailtext.="$proposal[0]: $form[$i]\n";
 break;
 case "file": // поле файла отправляемого пользователем в виде аттача к письму
 if (!isset($proposal[3])) {$param = "form[$i]";}
 else {$param=$proposal[3];}
 // создаем массив из файлов-аттачей
 $att_arr[]=$file_att[$param];
 $att_arr_type[]=$file_att_type[$param];
 $att_arr_name[]=$file_att_name[$param];
 break;
 case "select": // поле селекта
 if (isset($proposal[3])) { // если есть параметры селекта
 $options = explode("\t", $proposal[3]);
 // разбиваем параметры и перебираем каждую строку
 $option_text=explode("|",$option[0]);
 // разбиваем первый подпараметр селекта
 //на имя селекта и вид (multiselect и обычный)
 if ($option_text[0] == "mail") {$mailto=$form[$i];}
 // если 0 параметр равен mail -
 // значит это варианты e-mail адресата (в нашем случае)
 $mailtext.="$proposal[0]: $form[$i]\n";
 }
 break;
 default:
 }
}

// удалим из текста формы теги html
$mailtext=strip_tags($mailtext);

// удалим специальные символы из текста формы
// используя стандартный способ из руководства php
$search = array ("'&(amp|#38);'i",
 "'&(lt|#60);'i",
 "'&(gt|#62);'i",
 "'&(nbsp|#160);'i",
 "'&(iexcl|#161);'i",
 "'&(cent|#162);'i",
 "'&(pound|#163);'i",
 "'&(copy|#169);'i",
 "'&#(\d+);'e",
 "'—'i",
 "'–'i");
$replace = array ("&",
 "<",
 ">",
 " ",
 chr(161),
 chr(162),
 chr(163),
 chr(169),
 "chr(\\1)",
 " - ",
 "-");
$mailtext = preg_replace ($search, $replace, $mailtext);


// Параметры отправляемого сообщения
if ($mailto == "")
{ // если адресат не был выбран в форме, то указываем его по-умолчанию
 $to = "totoeval@mtu-net.ru";
}
else
{ // если адресат был выбран посетителем в форме
 $to = $mailto;
}
$from = "webmaster@$SERVER_NAME";
$subject = "New Providers";
$message = $mailtext;

// объявление в заголовке письма параметр From - от кого.
$headers = "From: $from";

// Оформляем boundary string - строку-разделитель
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";

// определяем, был ли отправлен файл с письмом
if (sizeof($att_arr)>0)
{ // если файл отправлен
 // Добавляем к заголовку письма тип передаваемых данных
 $headers .= "\nMIME-Version: 1.0\n" .
 "Content-Type: multipart/mixed;\n" .
 " boundary=\"{$mime_boundary}\"";
 // Добавляем к сообщению multipart boundary и тип передаваемых данных,
 // а затем присоединяем текст письма
 $message = "This is a multi-part message in MIME format.\n\n" .
 "--{$mime_boundary}\n" .
 "Content-Type: text/plain; charset=\"windows-1251\"\n" .
 "Content-Transfer-Encoding: 7bit\n\n" .
 $message . "\n\n";
}
else
{ // если письмо без приаттаченных файлов
 // Добавляем к заголовку письма тип передаваемых данных
 $headers .= "\nMIME-Version: 1.0\n" .
 "Content-Type: text/plain; charset=\"windows-1251\"\n" .
 " boundary=\"{$mime_boundary}\"";
 // Добавляем к сообщению boundary и тип передаваемых данных (текст),
 // а затем присоединяем текст письма
 $message = "Content-Type: text/plain; charset=\"windows-1251\"\n" .
 "Content-Transfer-Encoding: 7bit\n\n" .
 $message . "\n\n";
 
}

// перебираем имеющиеся приаттаченные файлы
// если их нет, то аттач производиться не будет
for ($files=0; $files<sizeof($att_arr); $files++)
{

 $fileatt=$att_arr[$files];
 $fileatt_type=$att_arr_type[$files];
 $fileatt_name=$att_arr_name[$files];

 if (is_uploaded_file($fileatt)) 
 { // проверяем, верно ли заапплоаден файл
 // Читаем файл аттача ('rb' = читаем в двоичном виде)
 $file = fopen($fileatt,'rb'); // открываем поток
 $data = fread($file,filesize($fileatt));

 fclose($file); // закрываем поток

 // Кодируем Base64 содержимое файла
 $data = chunk_split(base64_encode($data));

 // Добавляем содержимое файла к сообщению 
 // с соответствующими заголовком и описанием типа данных
 $message .= "--{$mime_boundary}\n".
 "Content-Type: {$fileatt_type};\n".
 " name=\"{$fileatt_name}\"\n".
 "Content-Transfer-Encoding: base64\n\n".
 $data."\n\n";
 }// так перебираем все отправляемые файлы

}
$message .= "--{$mime_boundary}--\n";
// в конец сообщения добавляем разделительную строку с окончанием сообщения

// Отправляем сообщение
@mail($to, $subject, $message, $headers);

// сообщаем в куки, что письмо отправлено
setcookie ("is_send", "send_query", time()+120);
// переводим пользователя к странице формы
// где ему сообщат, что письмо его отправлено
header("location: .");

?>
Форма входа
Календарь новостей
«  Май 2024  »
ПнВтСрЧтПтСбВс
  12345
6789101112
13141516171819
20212223242526
2728293031
Поиск
Друзья сайта
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

| Copyright MyCorp © 2024 | Используются технологии uCoz |
<