Тэг для формы
Posted: Tue Sep 28, 2010 11:33 pm
Написал тэг который позволяет быстро создать форму для отправки на email. Может кому полезно будет.
Для тех, кто спросит - зачем? Отвечу: альтернативный вариант модулю, ну и постарался сделать как можно проще в использовании...
Текущий вариант поддерживает модуль капчи.
Текущая версия не охватывает все возможные случаи, но легко расширяется...
Чего нет:
1. разных валидаторов. Сейчас только капча и на заполненость.
2. не все варианты полей формы.
3. Не используется smarty как шаблонизатор.
Итак, поехали.
1. Создаем 2 тэга пользователя. Один - собственно базовый класс, второй - описание формы. Тэг класса я назвал тэг rzForm. В принципе можно вынести в файл и инклудить. Текст класса - ниже.
2. Настраиваем форму. Для этого создаем второй тэг (см ниже примеры). Я назвал тэги faq
3. Прописываем тэги в месте, где нужно вызвать форму ({rzForm} {faq})
примеры:
Код примера со своим шаблоном и капчей:
код класса
Для тех, кто спросит - зачем? Отвечу: альтернативный вариант модулю, ну и постарался сделать как можно проще в использовании...
Текущий вариант поддерживает модуль капчи.
Текущая версия не охватывает все возможные случаи, но легко расширяется...
Чего нет:
1. разных валидаторов. Сейчас только капча и на заполненость.
2. не все варианты полей формы.
3. Не используется smarty как шаблонизатор.
Итак, поехали.
1. Создаем 2 тэга пользователя. Один - собственно базовый класс, второй - описание формы. Тэг класса я назвал тэг rzForm. В принципе можно вынести в файл и инклудить. Текст класса - ниже.
2. Настраиваем форму. Для этого создаем второй тэг (см ниже примеры). Я назвал тэги faq
3. Прописываем тэги в месте, где нужно вызвать форму ({rzForm} {faq})
примеры:
Код примера со своим шаблоном и капчей:
Code: Select all
// Это массив с данными для отправки
$email = array(
// адрес, куда отправлять (обязательно)
'email' => 'xxx@yyy.com',
// тема (обязательно)
'theme' => 'Новый вопрос с сайта',
// отправитель
'from' => 'robot@example.ru',
// имя отправителя
'fromName' => 'Mail Robot',
);
// массив описания формы. Здесь перечисляем поля и типы. На данный момент поддерживаются:
// text
// select
// textarea,
// checkbox
// capcha - собственно - капча - использует модуль капчи,
// title - разделитель, или пустое название
$data = array(
// ключ будет участвовать в формировании названия поля и id
'name' => array(
// это название, которое будет выводиться на форме и в почте
'title' => 'Ваше имя',
// тип поля
'type' => 'text',
// если обязателен, иначе можно не указывать
'required' => true,
),
'q' => array(
'title' => 'Вопрос',
'type' => 'textarea',
'required' => true,
),
'title' => array(
'title' => 'Какой-нть разделитель',
'type' => 'text',
),
'category' => array(
'title' => 'Раздел',
'type' => 'select',
// Здесь перечисляем все варианты селекта. При этом имя и значени будут совпадать - нам ведь нужно только отправить
'items' => array(
'делимый',
'неделимый',
),
),
'yes' => array(
'title' => 'Уврены?',
// у чекбокса в итоге будет значение либо "да" - если выбран, либо "нет" - если не выбран
'type' => 'checkbox',
),
//
'capcha' => array(
'title' => 'Защита от роботов',
'type' => 'capcha',
'required' => true,
),
);
// массив шаблонов. Вобщем-то можно и без него - в классе есть шаблоны по умолчанию - элементы формы в таблице. Однако, если используется - то нужно перечислить все поля.
// особенности - форма должна передаваться постом
// сабмит должен иметь имя. По умолчанию при создании объекта используется go, можно переопределить, например, если нужно несколько форм на одной странице.
// В шаблоне 3 вида замещений:
// 1. Тайтл - ##title_ключ_из_массива##
// 2. Элемент формы - ##field_ключ_из_массива##
// 3. Значение - ##value_ключ_из_массива## - используется в шаблоне письма
$templates = array();
// шаблон формы - здесь перечислены только 3 поля, остальные по аналогии. Если нет этого шаблона, то используется по умолчанию - там все поля в таблице.
$templates['form'] = <<< tpl
<form method="post">
<div class="form_name">
##title_name##:
</div>
<div class="text_input">
##field_name##
</div>
<div class="form_name">
##title_q##:
</div>
<div class="textarea">
##field_q##
</div>
<div class="form_name">
##title_capcha##:
</div>
<div class="textarea">
##field_capcha##
</div>
<div class="submit">
<input type="submit" value="Задать" name="go" />
</div>
</form>
tpl;
// это шаблон ошибки. Пока незнает поля в которых произошла ошибка
$templates['error'] = <<< tpl
<p style="color: red">Не заполнены все поля или неверно введен код с картинки!</p>
tpl;
// Шаблон успешной отправки - если все нормально после сабмита, то форма не показывается
$templates['ok'] = <<< tpl
<p><strong>Ваш вопрос принят.</strong></p>
tpl;
// Шаблон почты.
$templates['mail'] = <<< tpl
Вопрос от пользователя ##value_name## :
##value_q##
tpl;
// Ну а это собственно инициализация. Последним параметром можно передать имя сабмита, при необходимости.
$form = new rzForm($email, $data, $templates);
echo $form->run();
код класса
Code: Select all
if (!class_exists('rzForm')) {
/**
* Класс для быстрой генерации форм для отправки
*/
class rzForm{
/**
* @var array Массив описания полей
*/
private $_data = array();
/**
* @var string шаблон формы
*/
private $_tplForm = '';
/**
* @var string шаблон письма
*/
private $_tplMail = '';
/**
* @var string Шаблон ошибки
*/
private $_tplError = '';
/**
* @var string Шаблон сообщения успешной отправки
*/
private $_tplOk = '';
/**
* @var array Массив соответсвий переменных шаблона и их значений
*/
private $_tplData = array();
/**
* @var bool Все поля валидны
*/
private $_valid = true;
/**
* @var string Адрес получателя
*/
private $_email = '';
/**
* @var string Тема письма
*/
private $_emailTheme = '';
/**
* @var bool|string Адрес отправителя
*/
private $_emailFrom = '';
/**
* @var bool|string Имя отправителя
*/
private $_emailFromName = '';
private $_go = '';
/**
* @param array $email Массив с адресом, темой и отправителем
* @param array $data Массив описания формы
* @param array $templates Массив со всеми шаблонами
* @return void
*/
public function __construct($email, $data, $templates, $go = 'go') {
$this->_data = $data;
$this->_email = $email['email'];
$this->_emailTheme = $email['theme'];
$this->_emailFrom = isset($email['from']) ? $email['from'] : false;
$this->_emailFromName = isset($email['fromName']) ? $email['fromName'] : false;
$this->_tplForm = $templates['form'];
$this->_tplMail = $templates['mail'];
$this->_tplError = $templates['error'];
$this->_tplOk = $templates['ok'];
$this->_go = $go;
}
/**
* Основной публичный метод, который вызывется после создания объекта
* @return string|void сгенерированый html
*/
public function run() {
$showForm = true;
if (isset($_POST[$this->_go]) && $_POST[$this->_go]) {
$this->prepareFields($_POST['f']);
if ($this->_valid) {
$this->send();
$showForm = false;
}
} else {
$this->prepareFields();
$this->_valid = true;
}
if ($showForm) {
$ret = $this->showForm();
} else {
$ret = $this->processTpl($this->_tplOk, array());
}
return $ret;
}
/**
* Отобразить форму
* @return void
*/
private function showForm() {
$ret = '';
if ($this->_tplForm) {
if (!$this->_valid) {
$ret .= $this->processTpl($this->_tplError, $this->_tplData);
}
$ret .= $this->processTpl($this->_tplForm, $this->_tplData);
} else {
$ret = $this->quickForm();
}
return $ret;
}
/**
* Обработать шаблон
* @param $tpl
* @param $data
* @return string
*/
private function processTpl($tpl, $data) {
return strtr($tpl, $data);
}
/**
* Обработать массив данных с учетом поста
* @param array $data
* @return void
*/
private function prepareFields($data = array()) {
$data = array_map('htmlspecialchars', array_map('trim', $data));
foreach ($this->_data as $field => &$options) {
$options['value'] = isset($data[$field]) ? $data[$field] : '';
$options['name'] = "f[{$field}]";
$options['id'] = "id_{$field}";
$options['valid'] = true;
$options['required'] = isset($options['required']) && $options['required'];
$html = ' name="' . $options['name'] . '" id="' . $options['id'] . '" ';
switch ($options['type']) {
case 'title':
$options['html'] = '';
break;
case 'text':
$options['html'] = '<input type="text" ' . $html . ' value="' . $options['value'] . '">';
break;
case 'checkbox':
$options['value'] = $options['value'] ? 'да' : 'нет';
$checked = $options['value'] == 'да' ? ' checked="checked" ' : '';
$options['html'] = '<input type="checkbox" ' . $html . $checked . ' value="да">';
break;
case 'select':
$options['html'] = '<select ' . $html . '>';
foreach ($options['items'] as $item) {
$item = htmlspecialchars(trim($item));
$selected = $item == $options['value'] ? ' selected="selected" ' : '';
$options['html'] .= '<option value="' . $item . '" ' . $selected . '>' . $item . '</option>';
}
$options['html'] .= '</select>';
break;
case 'textarea':
$options['html'] = '<textarea ' . $html . '>' . $options['value'] . '</textarea>';
break;
case 'capcha':
global $gCms;
if (isset($gCms->modules['Captcha'])) {
$captcha =& $gCms->modules['Captcha']['object'];
}
$options['html'] = '<input type="text" ' . $html . ' value="">' . $captcha->getCaptcha();
$options['valid'] = $captcha->checkCaptcha($options['value']);
$this->_valid = $options['valid'];
break;
default:
break;
}
$this->_tplData["##title_{$field}##"] = $options['title'];
$this->_tplData["##field_{$field}##"] = $options['html'];
$this->_tplData["##value_{$field}##"] = $options['value'];
if ($options['required'] && !$options['value']) {
$options['valid'] = false;
$this->_valid = false;
}
}
}
/**
* Отправить сообщение на почту
* @return void
*/
private function send() {
$this->mail(
$this->_email,
$this->_emailTheme,
$this->_tplMail ? $this->processTpl($this->_tplMail, $this->_tplData) : $this->quickEmail()
);
}
/**
* Непосредственно отправка
* @param $email
* @param $theme
* @param $message
* @param string $fileName
* @return void
*/
private function mail($email, $theme, $message, $fileName = '') {
$enc_in = 'UTF-8';
$enc_out = 'CP1251';
$theme = iconv($enc_in, $enc_out, $theme);
$message = iconv($enc_in, $enc_out, $message);
$headers = array();
if ($this->_emailFrom) {
$headers[] = $this->_emailFromName ?
"From: {$this->_emailFromName} <{$this->_emailFrom}>" :
"{$this->_emailFrom}";
}
if ($fileName && file_exists($fileName)) {
$un = strtoupper(uniqid(time()));
$headers[] = 'Mime-Version: 1.0';
$headers[] = 'Content-Type: multipart/mixed; boundary="----------'.$un.'"';
$zag = "------------".$un."\nContent-type: text/plain; charset=\"windows-1251\";\n";
$zag .= "Content-Transfer-Encoding: 8bit\n\n{$message}\n\n";
$zag .= "------------".$un."\n";
$zag .= "Content-Type: application/octet-stream;";
$zag .= "name=\"".basename($fileName)."\"\n";
$zag .= "Content-Transfer-Encoding:base64\n";
$zag .= "Content-Disposition:attachment;";
$zag .= "filename=\"".basename($fileName)."\"\n\n";
$zag .= chunk_split(base64_encode(file_get_contents($fileName)))."\n";
$message = $zag;
} else {
$headers[] = 'Content-type: text/plain; charset="windows-1251"';
}
mail("{$email}", $theme, $message, implode("\n", $headers), $this->_emailFrom ? "-f{$this->_emailFrom}" : null);
}
private function quickForm() {
$text = '';
if (!$this->_valid) {
$text .= '<p style="color:red">Не заполнены все требуемые поля</p>';
}
$text .= '<form method="post"><table>';
foreach ($this->_data as $f) {
if ($f['type'] == 'title') {
$text .= "<tr><th colspan=\"2\" align=\"center\">{$f['title']}</th>";
} else {
$required = $f['required'] ? ' *' : '';
$text .= "<tr><th>{$f['title']} {$required} :</th><td>{$f['html']}</td>";
}
}
$text .= '<tr><th colspan="2"><input type="submit" value="Отправить" name="' . $this->_go . '" /></th></tr>';
$text .= '</table></form>';
return $text;
}
private function quickEmail() {
$text = '';
foreach ($this->_data as $f) {
$text .= "{$f['title']}: {$f['value']}\n";
}
$text .= "\n\n";
return $text;
}
}
}