Rollback use onli ver AVE.CMS v3.28

This commit is contained in:
2026-02-18 19:01:56 +05:00
parent 1ec47d7ddc
commit 38cb18cc6f
10 changed files with 278 additions and 730 deletions

View File

@@ -1,8 +1,8 @@
### forms
## Модуль Формы v2.1.0
## Модуль Формы v1.26.0
### адаптирован для AVE.CMS AVE.CMS v3.28 и AVE.CMS v3.29 ALT
### адаптирован для AVE.CMS v3.28
### Модуль предназначен для создания веб-форм (например, обратной связи или простейшего оформления заказа), которые могут состоять из любого набора полей.
@@ -12,11 +12,6 @@
### Changelog:
08.11.2025 - Версия v2.1.0 - модуль обновлен для работы с шаблонизатором Smarty 5
25.09.2025 - Версия v2.0.0 - модуль обновлен для работы в среде PHP-8.4.x и MySQL-8.4.x
Добавлен функционал массовых действий с историей: удаление, изменение статусов
01.09.2019 - Версия v1.26.0 - Модуль переименован в модуль Формы. Адаптация для версии ave-cms версии 3.25 и выше, удалено лишнее.
27.04.2017 - Версия 1.2.4 - добавлена возможность в поле "Атрибуты тега поля" работать атрибутом value, в …

View File

@@ -13,7 +13,7 @@
*
* @package AVE.cms
* @subpackage module: forms
* @since 2.1.0
* @since 1.4
* @author
* @filesource
*/
@@ -117,7 +117,7 @@
/**
* Метод забирает форму из бд по алиасу/id
*
* @param $alias_id
* @param $alias_id
* @param bool $_fields
*
* @return array
@@ -143,8 +143,7 @@
$form['alias_id'] = $alias_id;
// получатели
// ИСПРАВЛЕНИЕ: Добавляем @ для подавления Warning при десериализации, т.к. пользователь сообщил о проблеме
$form['mail_set'] = @unserialize($form['mail_set']);
$form['mail_set'] = unserialize($form['mail_set']);
if ($_fields === true)
{
@@ -166,22 +165,18 @@
if (in_array($field['type'],array('doc','multidoc')) && !empty($field['setting']) && is_numeric($field['setting']))
$field['setting'] = array(0 => $field['setting']);
else
// ИСПРАВЛЕНИЕ: Добавляем @ для подавления Warning при десериализации
$field['setting'] = @unserialize($field['setting']) !== false ? @unserialize($field['setting']) : array();
$field['setting'] = unserialize($field['setting']) !== false ? unserialize($field['setting']) : array();
}
// если тип поля поменялся, ставим пустую строку
// ИСПРАВЛЕНИЕ: Добавляем дополнительную проверку на то, что строка может быть сериализована (начинается с 'a', 'O', 's', 'i', 'd', 'b')
elseif (is_string($field['setting']) && strlen($field['setting']) > 2 && in_array($field['setting'][0], ['a', 'O', 's', 'i', 'd', 'b']) && @unserialize($field['setting']) !== false) $field['setting'] = '';
elseif (unserialize($field['setting']) !== false) $field['setting'] = '';
// раскрываем массив опций по умолчанию для мультиселекта
if ($field['type'] == 'multiselect')
{
// ИСПРАВЛЕНИЕ: Добавляем @ для подавления Warning при десериализации
$field['defaultval'] = @unserialize($field['defaultval']) !== false ? @unserialize($field['defaultval']) : array();
$field['defaultval'] = unserialize($field['defaultval']) !== false ? unserialize($field['defaultval']) : array();
}
// если тип поля поменялся, ставим пустую строку
// ИСПРАВЛЕНИЕ: Добавляем дополнительную проверку на то, что строка может быть сериализована
elseif (is_string($field['defaultval']) && strlen($field['defaultval']) > 2 && in_array($field['defaultval'][0], ['a', 'O', 's', 'i', 'd', 'b']) && @unserialize($field['defaultval']) !== false) $field['defaultval'] = '';
elseif (unserialize($field['defaultval']) !== false) $field['defaultval'] = '';
// главные поля
if (in_array($field['title'],$this->fields_main) && $field['main'])
@@ -204,20 +199,19 @@
}
/**
/**
* Метод убирает слэши во всей переменной
*
* @param mixed $var
* @param $var
*
* @return array|string
*/
function _stripslashes($var)
{
if (is_array($var))
return array_map(array($this, '_stripslashes'), $var);
if (! is_array($var))
return stripslashes($var);
else
// ИСПРАВЛЕНИЕ: Гарантируем, что $var является строкой, используя ?? ''
return stripslashes($var ?? '');
return array_map(array($this, '_stripslashes'), $var);
}
@@ -237,41 +231,43 @@
}
/**
* Метод чистит переменную от пустых значений и массивов
*
* @param $var
*
* @return array|null|string
*/
function _cleanvar($var)
{
if (!is_array($var)) {
return trim($var) > ''
? trim($var)
: null;
}
/**
* Метод чистит переменную от пустых значений и массивов
*
* @param $var
*
* @return array|null|string
*/
function _cleanvar($var)
{
if (! is_array($var))
return trim($var) > ''
? trim($var)
: null;
$narr = array();
$narr = array();
// Заменяем while (list($key, $val) = each($var)) на foreach
foreach ($var as $key => $val) {
if (is_array($val)) {
$val = $this->_cleanvar($val);
if (count($val) > 0) {
$narr[$key] = $val;
}
} else {
if (trim($val) > '') {
$narr[$key] = $val;
}
}
}
while (list($key, $val) = each($var))
{
if (is_array($val))
{
$val = $this->_cleanvar($val);
unset($var);
if (count($val) > 0)
$narr[$key] = $val;
}
else
{
if (trim($val) > '')
$narr[$key] = $val;
}
}
unset ($var);
return $narr;
}
return $narr;
}
/**
* Валидация Email-а
@@ -367,7 +363,7 @@ function _cleanvar($var)
}
/**
/**
* Парсинг главных тегов
*/
function _parse_tags ($str)
@@ -383,9 +379,6 @@ function _cleanvar($var)
$str = parse_hide($str);
// Получаем запись пользователя ОДИН раз
// Если get_user_rec_by_id(UID) вернет null, мы можем безопасно использовать ее дальше.
$user_rec = get_user_rec_by_id(UID);
return str_replace(array(
'[tag:docid]',
'[tag:formtitle]',
@@ -403,7 +396,6 @@ function _cleanvar($var)
'[tag:uemail]',
'[tag:sitename]',
'[tag:sitehost]',
'[tag:submitted_page]',
),array(
$AVE_Core->curentdoc->Id,
$this->form['title'],
@@ -411,19 +403,15 @@ function _cleanvar($var)
$_SERVER['REQUEST_URI'],
$this->form['alias'] ? $this->form['alias'] : $this->form['id'],
ABS_PATH,
ABS_PATH . 'templates/' . ((defined('THEME_FOLDER') === false) ? DEFAULT_THEME_FOLDER : THEME_FOLDER) . '/',
ABS_PATH . 'templates/' . THEME_FOLDER . '/',
'inc/captcha.php',
$_SESSION['user_name'],
// ИСПРАВЛЕНИЕ: Безопасное получение firstname и lastname
$user_rec->firstname ?? '',
$user_rec->lastname ?? '',
$_SESSION['user_login'] ?? '',
$_SESSION['user_email'] ?? '',
get_user_rec_by_id(UID)->firstname,
get_user_rec_by_id(UID)->lastname,
$_SESSION['user_login'],
$_SESSION['user_email'],
htmlspecialchars(get_settings('site_name'), ENT_QUOTES),
$_SERVER['HTTP_HOST'],
getSiteUrl() . $_SERVER['REQUEST_URI'],
), $str);
}
@@ -495,7 +483,7 @@ function _cleanvar($var)
*/
function _parse_tag_fld_post ($matches)
{
return $_POST['form-' . $this->form['alias_id']][$matches[1]] ?? '';
return $_POST['form-' . $this->form['alias_id']][$matches[1]];
}
/**
@@ -505,10 +493,6 @@ function _cleanvar($var)
{
$field_id = (int)$matches[1];
if (!isset($this->form['fields'][$field_id])) {
return $matches[0];
}
// забираем массив поля
$field = $this->form['fields'][$field_id];
@@ -523,16 +507,11 @@ function _cleanvar($var)
$alias_id = $this->form['alias_id'];
$fld_val = $this->form['is_submited']
? $this->_stripslashes($_POST['form-' . $alias_id][$field_id] ?? null)
? $this->_stripslashes($_POST['form-' . $alias_id][$field_id])
: (in_array($field['type'],array('input','textarea'))
? $this->_eval2var('?>' . $field['defaultval'] . '<?')
: $field['defaultval']);
// Убедитесь, что $fld_val является массивом
if (!is_array($fld_val)) {
$fld_val = [$fld_val]; // Преобразуем в массив
}
$attributes = trim($field['attributes']);
$this->form['fields'][$field_id]['is_used'] = true;
@@ -542,78 +521,78 @@ function _cleanvar($var)
switch ($field['type'])
{
case 'input':
$input = '<input ' . (strpos(strtolower($attributes), 'type=') === false ? ' type="text" ' : ' ') . '
name="form-' . $alias_id . '[' . $field['id'] . ']"
' . (strpos(strtolower($attributes), 'value=') === false ? ' value="' . ($field['title'] == 'captcha' ? '' : htmlspecialchars($fld_val[0], ENT_QUOTES)) . '" ' : ' ') . ' ' . $attributes . '>';
break;
case 'input':
$input = '<input ' . (strpos(strtolower($attributes),'type=') === false ? ' type="text" ' : ' ') . '
name="form-' . $alias_id . '[' . $field['id'] . ']"
' . (strpos(strtolower($attributes),'value=') === false ? ' value="' . ($field['title'] == 'captcha' ? '' : htmlspecialchars($fld_val,ENT_QUOTES)) . '" ' : ' ') . ' ' . $attributes . '>';
break;
case 'textarea':
$input = '<textarea name="form-' . $alias_id . '[' . $field['id'] . ']" ' . $attributes . '>' . htmlspecialchars($fld_val[0], ENT_QUOTES) . '</textarea>';
break;
case 'textarea':
$input = '<textarea name="form-' . $alias_id . '[' . $field['id'] . ']" ' . $attributes . '>' . htmlspecialchars($fld_val,ENT_QUOTES) . '</textarea>';
break;
case 'select':
$input = '<select name="form-' . $alias_id . '[' . $field['id'] . ']" ' . $attributes . '>';
foreach ($field['setting'] as $val => $title) {
$selected = in_array($val, $fld_val) ? ' selected="selected"' : '';
$input .= '<option value="' . $val . '"' . $selected . '>' . (is_array($title) ? $title['name'] : $title) . '</option>';
}
$input .= '</select>';
break;
case 'select':
$input = '<select name="form-' . $alias_id . '[' . $field['id'] . ']" ' . $attributes . '>';
foreach ($field['setting'] as $val => $title)
{
$input .= '<option value="' . $val . '"' . ($val == $fld_val ? ' selected="selected"' : '') . '>' . (is_array($title) ? $title['name'] : $title) . '</option>';
}
$input .= '</select>';
break;
case 'multiselect':
$input = '<select multiple="multiple" name="form-' . $alias_id . '[' . $field['id'] . '][]" ' . $attributes . '>';
foreach ($field['setting'] as $val => $title) {
$selected = in_array($val, $fld_val) ? ' selected="selected"' : '';
$input .= '<option value="' . $val . '"' . $selected . '>' . $title . '</option>';
}
$input .= '</select>';
break;
case 'multiselect':
$input = '<select multiple="multiple" name="form-' . $alias_id . '[' . $field['id'] . '][]" ' . $attributes . '>';
foreach ($field['setting'] as $val => $title)
{
$input .= '<option value="' . $val . '"' . (in_array($val,$fld_val) ? ' selected="selected"' : '') . '>' . $title . '</option>';
}
$input .= '</select>';
break;
case 'checkbox':
$input = '
<input type="hidden" name="form-' . $alias_id . '[' . $field['id'] . ']" value="0">
<input type="checkbox" name="form-' . $alias_id . '[' . $field['id'] . ']"' . ($fld_val[0] ? ' checked="checked"' : '') . ' value="1" ' . $attributes . '>';
break;
case 'checkbox':
$input = '
<input type="hidden" name="form-' . $alias_id . '[' . $field['id'] . ']" value="0">
<input type="checkbox" name="form-' . $alias_id . '[' . $field['id'] . ']"' . ($fld_val ? ' checked="checked"' : '') . ' value="1" ' . $attributes . '>';
break;
case 'file':
$input = '<input type="file" name="form-' . $alias_id . '[' . $field['id'] . ']" ' . $attributes . '>';
break;
case 'file':
$input = '<input type="file" name="form-' . $alias_id . '[' . $field['id'] . ']" ' . $attributes . '>';
break;
case 'doc':
$input = '<select name="form-' . $alias_id . '[' . $field['id'] . ']" ' . $attributes . '>';
$docs = $this->_docs($field['setting']);
foreach ($docs as $val => $title) {
$selected = ($val == $fld_val[0]) ? ' selected="selected"' : '';
$input .= '<option value="' . $val . '"' . $selected . '>' . $title . '</option>';
}
$input .= '</select>';
break;
case 'doc':
$input = '<select name="form-' . $alias_id . '[' . $field['id'] . ']" ' . $attributes . '>';
$docs = $this->_docs($field['setting']);
foreach ($docs as $val => $title)
{
$input .= '<option value="' . $val . '"' . ($val == $fld_val ? ' selected="selected"' : '') . '>' . $title . '</option>';
}
$input .= '</select>';
break;
case 'multidoc':
$input = '<select multiple="multiple" name="form-' . $alias_id . '[' . $field['id'] . '][]" ' . $attributes . '>';
$docs = $this->_docs($field['setting']);
foreach ($docs as $val => $title) {
$selected = in_array($val, $fld_val) ? ' selected="selected"' : '';
$input .= '<option value="' . $val . '"' . $selected . '>' . $title . '</option>';
}
$input .= '</select>';
break;
case 'multidoc':
$input = '<select multiple="multiple" name="form-' . $alias_id . '[' . $field['id'] . '][]" ' . $attributes . '>';
$docs = $this->_docs($field['setting']);
foreach ($docs as $val => $title)
{
$input .= '<option value="' . $val . '"' . (in_array($val,$fld_val) ? ' selected="selected"' : '') . '>' . $title . '</option>';
}
$input .= '</select>';
break;
}
// Вставляем поле в шаблон поля
$return = trim($field['tpl']) > ''
? str_replace('[tag:fld]', $input, $field['tpl'])
: $input;
// вставляем поле в шаблон поля
$return = trim($field['tpl']) > ''
? str_replace('[tag:fld]',$input,$field['tpl'])
: $input;
// Парсим теги названия и id
$return = str_replace(array(
'[tag:id]',
'[tag:title]',
), array(
$field['id'],
'[tag:title:' . $field_id . ']',
), $return);
// парсим теги названия и id
$return = str_replace(array(
'[tag:id]',
'[tag:title]',
), array(
$field['id'],
'[tag:title:' . $field_id . ']',
), $return);
// если попытка отправить форму, обрабатываем валидацию и пустоту
if ($this->form['is_submited'])
@@ -626,39 +605,13 @@ function _cleanvar($var)
{
$valid = false;
// если капча
if ($field['title'] == 'captcha') $valid = (empty($_SESSION['captcha_keystring']) || empty($fld_val[0]) || $_SESSION['captcha_keystring'] != $fld_val[0]) ? false : true;
// если файл
elseif ($field['type'] == 'file') {
$file_size = (isset($_FILES['form-' . $alias_id]['size'][$field_id])) ? $_FILES['form-' . $alias_id]['size'][$field_id] : 0;
$valid = ($file_size / 1024 / 1024) <= $field['setting'];
}
// Если передали регулярку
elseif (isset($field['setting'][0]) && $field['setting'][0] == '/') {
$valid = false; // Изначально считаем, что валидности нет
// Если $fld_val - массив, проверяем каждое значение
if (is_array($fld_val)) {
foreach ($fld_val as $value) {
if (preg_match($field['setting'], $value) === 1) {
$valid = true; // Если хотя бы одно значение валидно
break; // Выходим из цикла
}
}
} else {
// Если это одно значение, просто проверяем его
$valid = preg_match($field['setting'],$fld_val) === 1 ? true : false;
}
}
if ($field['title'] == 'captcha') $valid = (empty($_SESSION['captcha_keystring']) || empty($fld_val) || $_SESSION['captcha_keystring'] != $fld_val) ? false : true;
// если файл
elseif ($field['type'] == 'file') $valid = ($_FILES['form-' . $alias_id]['size'][$field_id] / 1024 / 1024) <= $field['setting'];
// если передали регулярку
elseif ($field['setting']{0} == '/') $valid = preg_match($field['setting'],$fld_val) === 1 ? true : false;
// если константу
elseif (isset($field['setting']) && is_string($field['setting']) && defined($field['setting']))
{
if (is_array($fld_val) && isset($fld_val[0])) {
$fld_val = $fld_val[0]; // Берем первое значение из массива
}
$valid = filter_var($fld_val, constant($field['setting'])) !== false ? true : false;
}
elseif (defined($field['setting'])) $valid = filter_var($fld_val,constant($field['setting'])) !== false ? true : false;
// иначе, ничего не делаем
else return 'Неверные параметры валидации!';
// парсим теги валидности
@@ -683,13 +636,11 @@ function _cleanvar($var)
// пустота (для любых обязательных полей)
if (! empty($field['required']) && $field['required'])
{
if ($field['type'] == 'file') {
// Безопасный доступ к $_FILES
$is_uploaded = isset($_FILES['form-' . $alias_id]['tmp_name'][$field_id]) && !empty($_FILES['form-' . $alias_id]['tmp_name'][$field_id]);
$has_error = isset($_FILES['form-' . $alias_id]['error'][$field_id]) && !empty($_FILES['form-' . $alias_id]['error'][$field_id]);
$empty = (!$is_uploaded || $has_error);
}
if ($field['type'] == 'file')
$empty = (
empty($_FILES['form-' . $alias_id]['tmp_name'][$field_id]) ||
!empty($_FILES['form-' . $alias_id]['error'][$field_id])
);
else
{
$clean_fld_val = $this->_cleanvar($fld_val);
@@ -738,8 +689,7 @@ function _cleanvar($var)
if ($field['is_used'] !== true || empty($field['active'])) return '';
// иначе, продолжаем
$alias_id = $this->form['alias_id'];
// Если ключ $field_id отсутствует в $_POST, берем пустую строку.
$val = $_POST['form-' . $alias_id][$field_id] ?? '';
$val = $_POST['form-' . $alias_id][$field_id];
$newval = '';
$tag_mail_empty = ($this->form['mail_set']['format'] === 'text' ? '<' : '&lt;') . $AVE_Template->get_config_vars('tag_mail_empty') . ($this->form['mail_set']['format'] === 'text' ? '>' : '&gt;');
@@ -773,14 +723,8 @@ function _cleanvar($var)
}
break;
case 'file':
// 1. Безопасно получаем массив имен файлов, используя оператор объединения с null (??).
// Если $_FILES['form-bag-report'] отсутствует или не содержит ['name'],
// $file_names будет пустым массивом [].
$file_names = $_FILES['form-' . $alias_id]['name'] ?? [];
// 2. implode() теперь безопасно работает с $file_names (массив или []).
$newval = implode(', ', $file_names);
case 'file':
$newval = implode(', ',$_FILES['form-' . $alias_id]['name']);
break;
default:
@@ -849,16 +793,12 @@ function _cleanvar($var)
// для правильного вывода селектов
if (empty($form['mail_set']['receivers'])) $form['mail_set']['receivers'] = array(0 => array());
// Добавляем проверку, чтобы избежать ошибки
if (is_array($form['fields']))
foreach ($form['fields'] as &$field)
{
foreach ($form['fields'] as &$field)
if (($field['type'] == 'select' || $field['type'] == 'multiselect') && empty($field['setting']))
{
if (($field['type'] == 'select' || $field['type'] == 'multiselect') && empty($field['setting']))
{
$field['setting'] = array(array());
}
$field['setting'] = array(0 => '');
$field['setting_empty'] = true;
}
}
}
@@ -875,7 +815,7 @@ function _cleanvar($var)
$assign['rubrics'] = $this->_rubrics();
// назначаем массив CodeMirror
$assign['codemirror_data'] = array(
$assign['codemirror'] = array(
'rubheader' => 200,
'from_name' => 60,
'from_email' => 60,
@@ -919,22 +859,13 @@ function _cleanvar($var)
return $AVE_Template->fetch($this->tpl_dir . 'form_fields.tpl');
}
/**
/**
* Сохранение формы
*/
function form_save ($fid)
{
global $AVE_DB;
// 🛑 ИСПРАВЛЕНИЕ PHP 8.4: Инициализация mail_set и receivers, если они отсутствуют в $_REQUEST
if (!isset($_REQUEST['mail_set']) || !is_array($_REQUEST['mail_set'])) {
$_REQUEST['mail_set'] = array();
}
if (!isset($_REQUEST['mail_set']['receivers']) || !is_array($_REQUEST['mail_set']['receivers'])) {
$_REQUEST['mail_set']['receivers'] = array();
}
// ----------------------------------------------------------------------------------
// проверяем Email-ы получателей
$receivers = array();
foreach ($_REQUEST['mail_set']['receivers'] as $receiver)
@@ -942,13 +873,9 @@ function _cleanvar($var)
if ($this->_email_validate($receiver['email'])) $receivers[] = $receiver;
}
$_REQUEST['mail_set']['receivers'] = $receivers;
// параметры отправителя
// 🛑 ИСПРАВЛЕНИЕ PHP 8.4: Использование оператора ?? '' для from_email
if (! trim($_REQUEST['mail_set']['from_email'] ?? '') > '') $_REQUEST['mail_set']['from_email'] = get_settings('mail_from');
// 🛑 ИСПРАВЛЕНИЕ PHP 8.4: Использование оператора ?? '' для from_name
if (! trim($_REQUEST['mail_set']['from_name'] ?? '') > '') $_REQUEST['mail_set']['from_name'] = get_settings('mail_from_name');
if (! trim($_REQUEST['mail_set']['from_email']) > '') $_REQUEST['mail_set']['from_email'] = get_settings('mail_from');
if (! trim($_REQUEST['mail_set']['from_name']) > '') $_REQUEST['mail_set']['from_name'] = get_settings('mail_from_name');
if ($fid)
{
@@ -966,7 +893,7 @@ function _cleanvar($var)
code_onsubmit = '" . addslashes($_REQUEST['code_onsubmit']) . "',
code_onvalidate = '" . addslashes($_REQUEST['code_onvalidate']) . "',
code_onsend = '" . addslashes($_REQUEST['code_onsend']) . "',
code_beforesend = '" . addslashes(isset($_REQUEST['code_beforesend']) ? $_REQUEST['code_beforesend'] : '') . "'
code_beforesend = '" . addslashes($_REQUEST['code_beforesend']) . "'
WHERE
id = '" . $fid . "'
");
@@ -992,13 +919,6 @@ function _cleanvar($var)
mail_set = '" . addslashes(serialize($mail_set)) . "'
");
$fid = (int)$AVE_DB->InsertId();
/* // 🛑 ИСПРАВЛЕНИЕ AJAX: Явный вывод ID для редиректа JS (fid=NaN)
if (isset($_REQUEST['ajax']) && empty($_REQUEST['demo'])) {
echo $fid;
return; // Прекращаем выполнение, чтобы не выводить лишние данные полей
}*/
$_REQUEST['fields'] = $this->fields_main_data;
// прописываем алерт об успешном создании
if ($fid > 0) $_SESSION['module_forms_admin'][$fid]['edit_alert'] = array('text' => 'created', 'theme' => 'accept');
@@ -1012,14 +932,7 @@ function _cleanvar($var)
// обновляем форму с данными примера
$this->form_save($fid);
// подставляем в шаблон новые id полей
$demo['form_tpl'] = preg_replace_callback(
'/\[tag:fld:(\d+)]/',
function($matches) {
return "[tag:fld:" . ($_REQUEST["demo_change"][(int)$matches[1]] ?? '') . "]";
},
$demo['form_tpl']
);
$demo['form_tpl'] = preg_replace_callback('/\[tag:fld:(\d+)]/', create_function('$matches','return "[tag:fld:" . $_REQUEST["demo_change"][(int)$matches[1]] . "]";'),$demo['form_tpl']);
$AVE_DB->Query("
UPDATE " . PREFIX . "_module_forms_forms
SET
@@ -1034,7 +947,7 @@ function _cleanvar($var)
foreach ($_REQUEST['fields'] as $field_id => $field)
{
if (!trim($field['title'])) continue;
if (isset($field['setting']) && is_array($field['setting']))
if (is_array($field['setting']))
{
$settings = array();
foreach ($field['setting'] as $setting)
@@ -1050,32 +963,28 @@ function _cleanvar($var)
}
elseif ($field['type'] == 'file') $field['setting'] = (int)$field['setting'];
// 🛑 ИСПРАВЛЕНИЕ PHP 8.4: Проверка существования ключа перед доступом
if (isset($field['defaultval']) && is_array($field['defaultval'])) {
$field['defaultval'] = serialize($field['defaultval']);
}
if (is_array($field['defaultval'])) $field['defaultval'] = serialize($field['defaultval']);
$sql = "
title = '" . addslashes($field['title']) . "',
active = '" . (int)($field['active'] ?? 0) . "',
active = '" . (int)$field['active'] . "',
type = '" . $field['type'] . "',
setting = '" . addslashes($field['setting'] ?? '') . "',
required = '" . (int)($field['required'] ?? 0) . "',
defaultval = '" . addslashes($field['defaultval'] ?? '') . "',
attributes = '" . addslashes(trim($field['attributes'] ?? '')) . "',
tpl = '" . addslashes($field['tpl'] ?? '') . "'
setting = '" . addslashes($field['setting']) . "',
required = '" . (int)$field['required'] . "',
defaultval = '" . addslashes($field['defaultval']) . "',
attributes = '" . addslashes(trim($field['attributes'])) . "',
tpl = '" . addslashes($field['tpl']) . "'
";
// ИСПРАВЛЕНИЕ PHP 8.4: Проверка существования ключа 'new'
if (isset($field['new']) && $field['new'])
if ($field['new'])
{
$AVE_DB->Query("
INSERT INTO " . PREFIX . "_module_forms_fields
SET
form_id = '" . (int)$fid . "',
main = '" . (int)($field['main'] ?? 0) . "',
main = '" . (int)$field['main'] . "',
" . $sql . "
");
if ($_REQUEST['demo'] ?? false) $_REQUEST['demo_change'][$field_id] = (int)$AVE_DB->InsertId();
if ($_REQUEST['demo']) $_REQUEST['demo_change'][$field_id] = (int)$AVE_DB->InsertId();
}
else
{
@@ -1089,20 +998,18 @@ function _cleanvar($var)
");
}
}
foreach ($_REQUEST['field_del'] as $field_id => $delete)
{
if (empty($delete)) continue;
$AVE_DB->Query("
DELETE FROM " . PREFIX . "_module_forms_fields
WHERE
id = '" . (int)$field_id . "' AND
main != '1'
");
}
// ИСПРАВЛЕНИЕ PHP 8.4: Безопасная итерация по удаляемым полям
foreach ($_REQUEST['field_del'] ?? [] as $field_id => $delete)
{
if (empty($delete)) continue;
$AVE_DB->Query("
DELETE FROM " . PREFIX . "_module_forms_fields
WHERE
id = '" . (int)$field_id . "' AND
main != '1'
");
}
return $fid;
return $fid;
}
/**
@@ -1189,15 +1096,12 @@ function _cleanvar($var)
// rubheader
$GLOBALS['user_header']['module_forms_' . $alias_id] = $this->_parse_tags($this->form['rubheader']);
// вывод финишной страницы, если включена проверка от повторной отправки
// вывод финишной страницы, если включена проверка от повторной отправки
if (! empty($_GET['mcnfinish']) && $form['protection'])
{
$session_key = $form['id'] . $_GET['mcnfinish']; // Определяем ключ заранее
// ИСПРАВЛЕНО: Используем isset() для проверки существования ключа сессии
if (isset($_SESSION['mcnfinish'][$session_key]) && $_SESSION['mcnfinish'][$session_key] === true)
if ($_SESSION['mcnfinish'][$form['id'] . $_GET['mcnfinish']] === true)
{
unset($_SESSION['mcnfinish'][$session_key]);
unset($_SESSION['mcnfinish'][$form['id'] . $_GET['mcnfinish']]);
// формируем финишную страницу
$tpl = $this->_parse_tags($form['finish_tpl']);
@@ -1276,21 +1180,16 @@ function _cleanvar($var)
// формируем список получателей
$recs = array();
// Определяем ID главных полей безопасно (Line 1225 fix preparation)
$copy_field_id = isset($form['fields_main']['copy']) ? $form['fields_main']['copy'] : null;
$email_field_id = isset($form['fields_main']['email']) ? $form['fields_main']['email'] : null;
// пользователь (отправка копии) - (Line 1225 fix)
// Проверяем наличие ключа 'copy' и его значение в POST или в defaultval
$send_copy_post = ($copy_field_id !== null && isset($_POST['form-' . $alias_id][$copy_field_id]) && $_POST['form-' . $alias_id][$copy_field_id] == 1);
$send_copy_default = ($copy_field_id !== null && isset($fields[$copy_field_id]['defaultval']) && $fields[$copy_field_id]['defaultval'] == 1);
if (($form['is_copy'] === true && $send_copy_post) || $send_copy_default)
// пользователь (отправка копии)
if (
($form['is_copy'] === true && $_POST['form-' . $alias_id][$form['fields_main']['copy']] == 1) ||
$fields[$form['fields_main']['copy']]['defaultval'] == 1
)
{
$email = '';
if ($form['is_email'] === true && $email_field_id !== null && isset($_POST['form-' . $alias_id][$email_field_id]))
$email = $_POST['form-' . $alias_id][$email_field_id];
if ($form['is_email'] === true)
$email = $_POST['form-' . $alias_id][$form['fields_main']['email']];
if (empty($email))
$email = $_SESSION['user_email'];
@@ -1310,8 +1209,8 @@ function _cleanvar($var)
{
$email = '';
if ($form['is_email'] === true && $email_field_id !== null && isset($_POST['form-' . $alias_id][$email_field_id]))
$email = $_POST['form-' . $alias_id][$email_field_id];
if ($form['is_email'] === true)
$email = $_POST['form-' . $alias_id][$form['fields_main']['email']];
if (empty($email))
$email = $_SESSION['user_email'];
@@ -1320,24 +1219,13 @@ function _cleanvar($var)
}
// главные получатели
// Проверка, что receivers - это массив, прежде чем слиять
$mail_receivers = is_array($form['mail_set']['receivers']) ? $form['mail_set']['receivers'] : [];
$recs = array_merge($recs, $mail_receivers);
$recs = array_merge($recs, $form['mail_set']['receivers']);
// выбранные в форме получатели
if ($this->form['is_receivers'] === true)
{
// Проверка наличия ключа 'receivers' (Line 1268 fix)
$recs_field_id = isset($form['fields_main']['receivers']) ? $form['fields_main']['receivers'] : null;
if ($recs_field_id !== null && isset($_POST['form-' . $alias_id][$recs_field_id]))
{
// Проверка, что поле и его настройки существуют, прежде чем получить значение
$post_value = $_POST['form-' . $alias_id][$recs_field_id];
if (isset($fields[$recs_field_id]['setting'][$post_value])) {
$recs[] = $fields[$recs_field_id]['setting'][$post_value];
}
}
$recs_field_id = $form['fields_main']['receivers'];
$recs[] = $fields[$recs_field_id]['setting'][$_POST['form-' . $alias_id][$recs_field_id]];
}
// если ни один получатель не назначен, отправляем админскому
@@ -1351,34 +1239,17 @@ function _cleanvar($var)
foreach ($recs as $rec)
{
// Fix Line 1282: Убеждаемся, что $rec — это массив и имеет ключ 'email'
if (is_array($rec) && isset($rec['email']))
{
$trimmed_email = trim($rec['email']);
if (!isset($this->form['receivers'][$trimmed_email]) && $trimmed_email > '')
$this->form['receivers'][$trimmed_email] = $rec;
}
if (!isset($this->form['receivers'][$rec['email']]) && trim($rec['email']) > '')
$this->form['receivers'][trim($rec['email'])] = $rec;
}
$recs = $this->form['receivers'];
$recs[] = array('agent' => 'history');
// обрабатываем тему по умолчанию
// Проверка наличия ключа 'subject' и самого поля
$subject_field_id = isset($form['fields_main']['subject']) ? $form['fields_main']['subject'] : null;
if ($subject_field_id !== null && isset($form['fields'][$subject_field_id]))
if (!$form['fields'][$form['fields_main']['subject']]['active'] || !$form['fields'][$form['fields_main']['subject']]['is_used'])
{
$subject_field = $form['fields'][$subject_field_id];
// Добавляем isset для 'active' и 'is_used'
$is_active = isset($subject_field['active']) ? $subject_field['active'] : false;
$is_used = isset($subject_field['is_used']) ? $subject_field['is_used'] : false;
if (!$is_active || !$is_used)
{
$_POST['form-' . $alias_id][$subject_field_id] = $subject_field['defaultval'];
}
$_POST['form-' . $alias_id][$form['fields_main']['subject']] = $form['fields'][$form['fields_main']['subject']]['defaultval'];
}
// обрабатываем шаблон письма
@@ -1394,10 +1265,7 @@ function _cleanvar($var)
foreach ($fields as $field_id => $field)
{
// Fix Line 1308: Проверка существования ключа 'is_used'
$is_used = isset($field['is_used']) ? $field['is_used'] : false;
if ($is_used !== true || $field['title'] == 'captcha' || empty($field['active']))
if ($field['is_used'] !== true || $field['title'] == 'captcha' || empty($field['active']))
continue;
$easy .= "[tag:title:$field_id]" . ": [tag:fld:$field_id];" . ($form['mail_set']['format'] === 'text' ? "\r\n" : '<br>');
@@ -1426,9 +1294,7 @@ function _cleanvar($var)
{
foreach ($_FILES['form-' . $alias_id]['name'] as $field_id => $fname)
{
// ИСПРАВЛЕНИЕ: Безопасное получение расширения
$path_parts = pathinfo($fname);
$ext = $path_parts['extension'] ?? '';
$ext = (end(explode('.', $fname)));
if (
!empty($_FILES['form-' . $alias_id]['tmp_name'][$field_id]) &&
@@ -1481,7 +1347,7 @@ function _cleanvar($var)
$subject = $subject_tpl;
$if_user_open = (($rec['agent'] ?? '') === 'user'); // ИСПРАВЛЕНО: Безопасный доступ к 'agent'
$if_user_open = ($rec['agent'] === 'user');
$if_admin_open = !$if_user_open;
$this->_parse_tag_if($mail,'if_user',$if_user_open);
@@ -1497,7 +1363,7 @@ function _cleanvar($var)
$subject = trim($this->_eval2var(' ?>' . $subject . '<?' . 'php '));
// сохраняем в бд историю (письмо, которое пришло админу)
if (($rec['agent'] ?? '') === 'history') // ИСПРАВЛЕНО: Безопасный доступ к 'agent'
if ($rec['agent'] === 'history')
{
$history['dialog']['request']['body'] = $mail;
$history['dialog']['request']['format'] = $form['mail_set']['format'];
@@ -1692,18 +1558,18 @@ function _cleanvar($var)
if (!empty($request_author))
$history['dialog']['request'] = array_merge($history['dialog']['request'], $request_author);
// ответы
foreach ($history['dialog']['response'] ?? [] as &$response)
{
$response_author = $AVE_DB->Query("
SELECT user_name, firstname, lastname
FROM " . PREFIX . "_users
WHERE Id = '" . $response['user_id'] . "'
")->FetchAssocArray();
// ответы
foreach ($history['dialog']['response'] as &$response)
{
$response_author = $AVE_DB->Query("
SELECT user_name, firstname, lastname
FROM " . PREFIX . "_users
WHERE Id = '" . $response['user_id'] . "'
")->FetchAssocArray();
if (!empty($response_author))
$response = array_merge($response, $response_author);
}
if (!empty($response_author))
$response = array_merge($response, $response_author);
}
// форма ответа
if (empty($history['dialog']['response_draft']))

View File

@@ -27,15 +27,6 @@ $form_tpl = array(
</div>
</div>
</form>
<script>
document.addEventListener(\\\'DOMContentLoaded\\\', (event) => {
const captchaRefreshBtn = document.getElementById(\\\'captcha-ref\\\');
const captchaImage = document.getElementById(\\\'captcha\\\').querySelector(\\\'img\\\');
captchaRefreshBtn.addEventListener(\\\'click\\\', () => {
captchaImage.src = \\\'../inc/captcha.php?refresh=\\\' + new Date().getTime();
});
});
</script>
[tag:if_form_invalid]
<script>
function form_popover () {
@@ -80,14 +71,9 @@ $form_tpl = array(
</div>
</form>
<script>
document.addEventListener(\\\'DOMContentLoaded\\\', (event) => {
const captchaRefreshBtn = document.getElementById(\\\'captcha-ref\\\');
const captchaImage = document.getElementById(\\\'captcha\\\').querySelector(\\\'img\\\');
captchaRefreshBtn.addEventListener(\\\'click\\\', () => {
captchaImage.src = \\\'../inc/captcha.php?refresh=\\\' + new Date().getTime();
});
});
$(\\\'#form_[tag:formalias]\\\').off();
$(\\\'#captcha-ref\\\').on(\\\'click\\\', function(){$(\\\'#captcha img\\\').attr(\\\'src\\\', \\\'[tag:path][tag:captcha]?refresh=\\\' + new Date().getTime());});
function form_popover (action) {
var _action = (action == undefined || !action) ? \\\'show\\\' : action;
$(\\\'#form_[tag:formalias] .form-control.invalid\\\').each(function(index, element) {
@@ -149,13 +135,6 @@ $form_tpl = array(
</div>
</form>
<script>
document.addEventListener(\\\'DOMContentLoaded\\\', (event) => {
const captchaRefreshBtn = document.getElementById(\\\'captcha-ref\\\');
const captchaImage = document.getElementById(\\\'captcha\\\').querySelector(\\\'img\\\');
captchaRefreshBtn.addEventListener(\\\'click\\\', () => {
captchaImage.src = \\\'../inc/captcha.php?refresh=\\\' + new Date().getTime();
});
});
$(\\\'#[tag:formalias] form\\\').on(\\\'submit\\\', function (e) {
e.preventDefault();
var form = $(this);

View File

@@ -4,7 +4,7 @@
$module = array(
'ModuleSysName' => 'forms',
'ModuleVersion' => '2.1.0',
'ModuleVersion' => '1.26.0',
'ModuleAutor' => 'AVE.cms Team',
'ModuleCopyright' => '&copy; 2007-' . date('Y') . ' AVE.cms',
'ModuleIsFunction' => 1,
@@ -14,6 +14,6 @@
'ModuleTag' => '[mod_forms:alias/id:email]',
'ModuleTagLink' => null,
'ModuleAveTag' => '#\\\[mod_forms:([A-Za-z0-9-_]{1,20})\\\]#',
'ModulePHPTag' => "<?php mod_forms(\"$1\"); ?>"
'ModulePHPTag' => "<?php mod_forms(''$1''); ?>"
);
?>

View File

@@ -1,8 +1,8 @@
[name]
MODULE_NAME = "Формы"
MODULE_DESCRIPTION = "Данный модуль предназначен для создания веб-форм (например, обратной связи или простейшего оформления заказа), которые могут состоять из любого набора полей. Для вывода в публичной части сайта используйте тег <strong>[mod_forms:XXX]</strong>, где XXX - это id или алиас формы."
[module]
contacts = "Формы"
mod_info = "В данном разделе приведен список всех форм. Вы можете, добавить новую форму или отредактировать существующую."
forms = "Список форм"
@@ -71,7 +71,6 @@ edit = "Редактировать"
copy = "Копировать"
delete = "Удалить"
actions = "Действия"
actions_sel = "Действия с выбранными"
saved = "Сохранено"
notsaved = "Во время сохранения произошла ошибка"
created = "Форма успешно создана"
@@ -79,7 +78,6 @@ copied = "Форма успешно скопирована и сохранен
deleting = "Удаление..."
add_refresh = "Добавить и обновить"
save = "Сохранить"
save_changes = "Сохранить изменения"
return_to_forms = "Вернуться к списку форм"
refresh = "Обновить"
mail_set = "Настройки письма"
@@ -183,13 +181,4 @@ cn_count_messages = "сообщений: "
cn_copy_to_clipboard = "Скопировать в буфер обмена"
cn_return_list_form = "Вернуться к списку форм"
cn_mod_info = "Важно: модуль использует метод отправки почты установленный в системных настройках, в разделе "
cn_mod_info_a = "Настройки почты."
info_attr_name = "Атрибут <span style='color:#2474B0'>name</span> уже установлен и используется по умолчанию, его значение:"
cn_select_for_action = "Выберите хотя бы один элемент"
cn_confirm_mass_del = "Вы уверены, что хотите удалить выбранные элементы?"
delete_error = "Ошибка удаления"
action_confirm_title = "Удаление истории"
action_error_title = "Действия в истории"
form_title_error_text = "Пожалуйста, укажите название формы"
form_title_error_title = "Создание формы"
tag_submitted_page = "Тег выведет ссылку на страницу с которой и на которой была заполнена и отправлена форма"
cn_mod_info_a = "Настройки почты."

View File

@@ -50,7 +50,7 @@
$lang_file = BASE_DIR . '/modules/forms/lang/' . $_SESSION['user_language'] . '.txt';
$AVE_Template->config_load($lang_file, 'module');
switch($_REQUEST['action'] ?? '')
switch($_REQUEST['action'])
{
case '':
case 'full':
@@ -81,8 +81,6 @@
$lang_file = BASE_DIR . '/modules/forms/lang/' . $_SESSION['admin_language'] . '.txt';
$AVE_Template->config_load($lang_file, 'module');
$response = '';
// создаём переменные с версией движка
$ave14 = ((float)str_replace(',', '.', APP_VERSION) < 1.5);
$AVE_Template->assign('ave14', $ave14);
@@ -154,7 +152,7 @@
break;
}
if ($_REQUEST['ajax'] ?? false)
exit((string)$response);
if ($_REQUEST['ajax'])
exit((string)$response);
}
?>

View File

@@ -37,8 +37,8 @@
$fid = parseInt('{$fid}');
$sess = '{$sess}';
$smarty = new Array;
$smarty['start_alert'] = '{$alert.text|default:''}';
$smarty['start_alert_theme'] = '{$alert.theme|default:''}';
$smarty['start_alert'] = '{$alert.text}';
$smarty['start_alert_theme'] = '{$alert.theme}';
</script>
<div class="title">
@@ -91,38 +91,38 @@ $smarty['start_alert_theme'] = '{$alert.theme|default:''}';
{/if}
</td>
</tr>
{if !empty($dialog.response)}
<tr>
<td colspan="2"><h5>{if $dialog.response|@count == 1}{#response#}{else}{#responses#}{/if}</h5></td>
</tr>
{foreach from=$dialog.response item=item}
<tr>
<td valign="middle">
{if $item.user_name|default:false} <-- ИСПРАВЛЕНИЕ: Проверяем user_name безопасно
[<a target="_blank" href="index.php?do=user&amp;action=edit&Id={$item.user_id}&cp={$sess}" class="toprightDir" title="{#profile_look#}">{$item.user_name}</a>] {if $item.firstname|default:false || $item.lastname|default:false}{$item.firstname|default:''} {$item.lastname|default:''}{/if}<br/>
{/if}
{#from#} <a href="mailto:{$item.from_email}" title="{#write_email#}" class="toprightDir">{$item.from_email}</a> &lt;{$item.from_name|escape}&gt;<br/>
<span class="date_text dgrey">{$item.date|date_format:$TIME_FORMAT|pretty_date}</span>
</td>
<td>
{if $item.format=='text'}
<div style="white-space:pre">{$item.body}</div>
{if $dialog.response}
<tr>
<td colspan="2"><h5>{if $dialog.response|@count == 1}{#response#}{else}{#responses#}{/if}</h5></td>
</tr>
{foreach from=$dialog.response item=item}
<tr>
<td valign="middle">
{if $item.user_name}
[<a target="_blank" href="index.php?do=user&amp;action=edit&Id={$item.user_id}&cp={$sess}" class="toprightDir" title="{#profile_look#}">{$item.user_name}</a>] {if $item.firstname || $item.lastname}{$item.firstname} {$item.lastname}{/if}<br/>
{/if}
{#from#} <a href="mailto:{$item.from_email}" title="{#write_email#}" class="toprightDir">{$item.from_email}</a> &lt;{$item.from_name|escape}&gt;<br/>
<span class="date_text dgrey">{$item.date|date_format:$TIME_FORMAT|pretty_date}</span>
</td>
<td>
{if $item.format=='text'}
<div style="white-space:pre">{$item.body}</div>
{else}
{$item.body}
{/if}
</td>
</tr>
{/foreach}
{else}
{$item.body}
<tr class="{if $status==='replied'}yellow{/if}">
<td colspan="2" style="padding:15px 10px;">
{if $status!=='replied'}<a href="index.php?do=modules&amp;action=modedit&amp;mod=forms&amp;moduleaction=dialog_status&amp;hid={$hid}&amp;status=replied&amp;fid={$fid}&amp;cp={$sess}" class="btn redBtn">{#set_replied#}</a>
{else}
<strong>{#marked_replied#}</strong>
{/if}
</td>
</tr>
{/if}
</td>
</tr>
{/foreach}
{else}
<tr class="{if $status==='replied'}yellow{/if}">
<td colspan="2" style="padding:15px 10px;">
{if $status!=='replied'}<a href="index.php?do=modules&amp;action=modedit&amp;mod=forms&amp;moduleaction=dialog_status&amp;hid={$hid}&amp;status=replied&amp;fid={$fid}&amp;cp={$sess}" class="btn redBtn">{#set_replied#}</a>
{else}
<strong>{#marked_replied#}</strong>
{/if}
</td>
</tr>
{/if}
</tbody>
</table>
</div>
@@ -148,18 +148,16 @@ $smarty['start_alert_theme'] = '{$alert.theme|default:''}';
</tr>
<tr>
<td>{#mfld_subject#}:</td>
<td><input type="text" name="subject" placeholder="{#mfld_subject#}" class="mousetrap" value="{($dialog.response_draft.subject|default:'')|escape|default:"RE: $subject"}"/></td>
<td><input type="text" name="subject" placeholder="{#mfld_subject#}" class="mousetrap" value="{$dialog.response_draft.subject|escape|default:"RE: $subject"}"/></td>
</tr>
<tr>
<td>{#format#}:</td>
<td>
<input class="mousetrap" type="radio" name="format" value="text"
{if $dialog.response_draft.format|default:'text'!='html'}checked="checked"{/if}/>
<label>{#text#}</label>
<input class="mousetrap" type="radio" name="format" value="html"
{if $dialog.response_draft.format|default:''=='html'}checked="checked"{/if}/>
<label>HTML</label>
</td>
<td>
<input class="mousetrap" type="radio" name="format" value="text" {if $dialog.response_draft.format!='html'}checked="checked"{/if}/>
<label>{#text#}</label>
<input class="mousetrap" type="radio" name="format" value="html" {if $dialog.response_draft.format=='html'}checked="checked"{/if}/>
<label>HTML</label>
</td>
</tr>
<tr>
<td>{#body#}</td>

View File

@@ -90,14 +90,12 @@
$fid = parseInt('{$fid}');
$sess = '{$sess}';
$smarty = new Array;
$smarty['start_alert'] = '{$alert.text|default:''}';
$smarty['start_alert_theme'] = '{$alert.theme|default:''}';
$smarty['start_alert'] = '{$alert.text}';
$smarty['start_alert_theme'] = '{$alert.theme}';
$smarty['_email_accept'] = '{#email_accept#}';
$smarty['_email_error'] = '{#email_error#}';
$smarty['tpl_dir'] = '{$tpl_dir}';
$smarty['_refresh'] = '{#refresh#}';
$smarty['form_title_error_text'] = '{#form_title_error_text#}';
$smarty['form_title_error_title'] = '{#form_title_error_title#}';
</script>
<div class="title">
@@ -134,7 +132,7 @@ $smarty['form_title_error_title'] = '{#form_title_error_title#}';
<tr class="noborder">
<td>{#title#}:</td>
<td>
<input type="text" name="title" id="form_title" value="{$form.title|default:''|escape}" class="mousetrap" placeholder="{#title#}" size="40" {if !$fid}autofocus{/if} />
<input type="text" name="title" id="form_title" value="{$form.title|escape}" class="mousetrap" placeholder="{#title#}" size="40" {if !$fid}autofocus{/if} />
</td>
</tr>
<tr>
@@ -146,9 +144,9 @@ $smarty['form_title_error_title'] = '{#form_title_error_title#}';
</td>
<td>
<div class="pr12" style="display: table;">
<input type="text" name="alias" id="form_alias" value="{$form.alias|default:''|escape}" class="mousetrap" data-accept="{#alias_accept#}" data-error-syn="{#alias_er_syn#}" data-error-exists="{#alias_er_exists#}" placeholder="{#alias#}" maxlength="20" size="40" />
<input type="text" name="alias" id="form_alias" value="{$form.alias|escape}" class="mousetrap" data-accept="{#alias_accept#}" data-error-syn="{#alias_er_syn#}" data-error-exists="{#alias_er_exists#}" placeholder="{#alias#}" maxlength="20" size="40" />
<input type="text" id="form_tag_{$fid}" value="[mod_forms:{if $fid && $form.alias}{$form.alias}{elseif $fid}{$fid}{/if}]" readonly size="40" class="mousetrap" />
<a style="text-align: center; padding: 5px 3px 4px 3px;" class="whiteBtn copyBtn topDir" href="javascript:void(0);" data-clipboard-action="copy" data-clipboard-target="#form_tag_{$form.id|default:'0'}" title="{#cn_copy_to_clipboard#}">
<a style="text-align: center; padding: 5px 3px 4px 3px;" class="whiteBtn copyBtn topDir" href="javascript:void(0);" data-clipboard-action="copy" data-clipboard-target="#form_tag_{$form.id}" title="{#cn_copy_to_clipboard#}">
<img style="margin-top: -3px; position: relative; top: 4px; padding: 0 3px;" class="clippy" src="{$ABS_PATH}admin/templates/images/clippy.svg" width="13"></a>
</div>
</td>
@@ -161,7 +159,7 @@ $smarty['form_title_error_title'] = '{#form_title_error_title#}';
</div>
</td>
<td>
<input type="checkbox" name="protection" value="1" {if $form.protection|default:'1' !== '0'}checked="checked"{/if} class="mousetrap"/>
<input type="checkbox" name="protection" value="1" {if $form.protection!=='0'}checked="checked"{/if} class="mousetrap"/>
</td>
</tr>
{if !$fid}
@@ -601,26 +599,8 @@ $(function() {
});
});
// Функция сохранения формы
// функция сохранения формы
function form_save (fields_reload, data) {
// 1. ПРОВЕРКА ПОЛЯ "НАЗВАНИЕ"
var formTitle = $('#form_title').val().trim();
if (formTitle === "") {
// 1.1. Выводим сообщение об ошибке с использованием jAlert
jAlert($smarty['form_title_error_text'], $smarty['form_title_error_title']);
// 1.2. Устанавливаем фокус на поле
$('#form_title').focus();
return false; // Прерываем выполнение функции
}
// КОНЕЦ ПРОВЕРКИ
// 2. СТАНДАРТНАЯ ЛОГИКА AJAX (Если проверка пройдена)
if (data == undefined) var data = new Object();
var form = $('#form_edit');
data.ajax = 1;
@@ -784,16 +764,10 @@ $(document)
{/literal}
<!-- Оформляем поля в CodeMirror -->
<script type="text/javascript">var hlLine;</script>
{* Итерируем по новому, чистому массиву *}
{foreach from=$codemirror_data key='cdmr_id' item='cdmr_h'}
{foreach from=$codemirror key='cdmr_id' item='cdmr_h'}
{if $ave15}
{* Ветка $ave15 (инклуд) *}
{include file="$codemirror_editor" ctrls='form_save();' conn_id="_$cdmr_id" textarea_id=$cdmr_id height=$cdmr_h}
{else}
{* Ветка !ave15 (оригинальный код) *}
<script>
var editor_{$cdmr_id} = CodeMirror.fromTextArea(document.getElementById('{$cdmr_id}'), {ldelim}
extraKeys: {ldelim}
@@ -819,46 +793,21 @@ $(document)
{rdelim});
editor_{$cdmr_id}.setSize('100%',{$cdmr_h});
function getSelectedRange_{$cdmr_id}() {ldelim}
return {ldelim}
from: editor_{$cdmr_id}.getCursor(true),
to: editor_{$cdmr_id}.getCursor(false)
{rdelim};
{rdelim}
function textSelection_{$cdmr_id}(startTag,endTag) {ldelim}
var range = getSelectedRange_{$cdmr_id}();
editor_{$cdmr_id}.replaceRange(startTag + editor_{$cdmr_id}.getRange(range.from, range.to) + endTag, range.from, range.to)
editor_{$cdmr_id}.setCursor(range.from.line, range.from.ch + startTag.length);
{rdelim}
</script>
{/if}
{/foreach}
<!-- /Оформляем поля в CodeMirror -->
<script type="text/javascript">var clipboard = new Clipboard('.copyBtn');</script>
{literal}
<script>
$(document).ready(function() {
// Привязываемся к событию submit формы id="form_edit"
$('#form_edit').submit(function(event) {
// Получаем значение поля "Название"
var formTitle = $('#form_title').val().trim(); // Поле ввода: id="form_title"
// 1. Выполняем проверку
if (formTitle === "") {
// Если поле пустое:
// Предотвращаем стандартную отправку формы
event.preventDefault();
// 2. Выводим сообщение об ошибке с использованием jAlert
jAlert($smarty['form_title_error_text'], $smarty['form_title_error_title']);
// 3. Устанавливаем фокус на поле
$('#form_title').focus();
return false;
} else {
// Если поле заполнено:
// 4. Показываем оверлей и позволяем форме отправиться
$.alerts._overlay('show');
// return true; (не обязательно, форма отправится сама)
}
});
});
</script>
{/literal}
<script type="text/javascript">var clipboard = new Clipboard('.copyBtn');</script>

View File

@@ -56,8 +56,8 @@
{if $field.main && $field.title=='receivers'}
{foreach from=$field.setting item=receiver name=receivers}
<div class="add_wrap">
<input type="text" name="fields[{$field.id}][setting][{$smarty.foreach.receivers.index}][email]" value="{$receiver.email|default:''|escape}" placeholder="Email" size="20" class="mousetrap email form_field_switch" />
<input type="text" name="fields[{$field.id}][setting][{$smarty.foreach.receivers.index}][name]" value="{$receiver.name|default:''|escape}" placeholder="{#name#}" size="20" class="mousetrap form_field_switch" />
<input type="text" name="fields[{$field.id}][setting][{$smarty.foreach.receivers.index}][email]" value="{$receiver.email|escape}" placeholder="Email" size="20" class="mousetrap email form_field_switch" />
<input type="text" name="fields[{$field.id}][setting][{$smarty.foreach.receivers.index}][name]" value="{$receiver.name|escape}" placeholder="{#name#}" size="20" class="mousetrap form_field_switch" />
{if $smarty.foreach.receivers.index == 0}
<input type="button" value="+" class="btn basicBtn smallBtn addParentBtn mousetrap form_field_switch" data-content='<div class="add_wrap"><input type="text" class="mousetrap email form_field_switch" name="fields[{$field.id}][setting][%count%][email]" placeholder="Email" size="20"/> <input class="mousetrap form_field_switch" type="text" name="fields[{$field.id}][setting][%count%][name]" placeholder="{#name#}" size="20"/> <input type="button" value="&times;" class="btn redBtn smallBtn delParentBtn form_field_switch" data-target="div"></div>' data-target="td" data-count="{$field.setting|@count}">
{else}
@@ -139,7 +139,6 @@
<a class="docname botDir" title="{#tag_uname#}" href="javascript:void(0);" onClick="textSelection_field_defaultval_{$field.id}('[tag:uname]','');"><strong>[tag:uname]</strong></a> |
<a class="docname botDir" title="{#tag_ufname#}" href="javascript:void(0);" onClick="textSelection_field_defaultval_{$field.id}('[tag:ufname]','');"><strong>[tag:ufname]</strong></a> |
<a class="docname botDir" title="{#tag_ulname#}" href="javascript:void(0);" onClick="textSelection_field_defaultval_{$field.id}('[tag:ulname]','');"><strong>[tag:ulname]</strong></a> |
<a class="docname botDir" title="{#tag_submitted_page#}" href="javascript:void(0);" onClick="textSelection_field_defaultval_{$field.id}('[tag:submitted_page]','');"><strong>[tag:submitted_page]</strong></a>
</div>
<!-- Оформляем поле в CodeMirror -->
{if $ave15}
@@ -186,11 +185,11 @@
</script>
{/if}
{elseif ($field.type=='select' || $field.type=='multiselect')}
{if !$field.setting_empty|default:0}
{if !$field.setting_empty}
<select style="width:300px" name="fields[{$field.id}][defaultval]{if $field.type=='multiselect'}[]{/if}" {if $field.type=='multiselect'}multiple="multiple" size="{$field.setting|@count}" style="width:100%"{/if} class="mousetrap">
{foreach from=$field.setting item=item name=select}
{if $field.main && $field.title=='receivers'}
<option value="{$smarty.foreach.select.index}" {if $smarty.foreach.select.index==$field.defaultval}selected="selected"{/if}>{$item.name|default:''|escape}</option>
<option value="{$smarty.foreach.select.index}" {if $smarty.foreach.select.index==$field.defaultval}selected="selected"{/if}>{$item.name|escape}</option>
{else}
<option value="{$smarty.foreach.select.index}" {if ($field.type=='select' && $smarty.foreach.select.index==$field.defaultval) || ($field.type=='multiselect' && $smarty.foreach.select.index|in_array:$field.defaultval)}selected="selected"{/if}>{$item|escape}</option>
{/if}
@@ -206,7 +205,7 @@
</td>
<td align="center">
<a class="topleftDir icon_sprite ico_template form_field_tpl_btn" href="javascript:void(0);" title="{#fld_tpl_toggle#}"></a>
<input type="hidden" class="form_field_tpl_input" name="field_tpl_open[{$field.id}]" value="{if isset($field_tpl_open[$field_id]) && $field_tpl_open[$field_id]}1{else}0{/if}">
<input type="hidden" class="form_field_tpl_input" name="field_tpl_open[{$field.id}]" value="{if $field_tpl_open[$field_id]}1{else}0{/if}">
</td>
<td align="center">
{if !$field.main}
@@ -214,30 +213,10 @@
{/if}
</td>
</tr>
<tr class="form_field_tpl_tr {if !isset($field_tpl_open[$field_id]) || !$field_tpl_open[$field_id]}hide{/if}">
<tr class="form_field_tpl_tr {if !$field_tpl_open[$field_id]}hide{/if}">
<td colspan="8">
<div class="col-half">
<h6 ><span style="padding-right: 20px;">{#attributes#}</span> <img style="margin-top: -2px; position: relative; top: 0pt; padding: 0 3px;" class="clippy" src="{$ABS_PATH}admin/templates/images/uploader/error.png" width="10"> <span style="padding-right: 5px;">{#info_attr_name#}</span>
<div class="pr12" style="display: inline">
<input
type="text"
id="field_name_{$form.id|default:''}"
value='name="form-{if $form.alias|default:false}{$form.alias}{else}{$form.id|default:''}{/if}[{$field.id|default:''}]"'
style="width:120px; display: table-cell"
readonly
class="mousetrap"
/>
<a
style="display: table-cell; text-align: center"
class="whiteBtn copyBtn topDir"
href="javascript:void(0);"
data-clipboard-action="copy"
data-clipboard-target="#field_name_{$form.id|default:''}"
title="{#cn_copy_to_clipboard#}"
>
<img style="margin-top: -3px; position: relative; top: 4px; padding: 0 3px;" class="clippy" src="{$ABS_PATH}admin/templates/images/clippy.svg" width="13"></a>
</div>
</h6>
<h6>{#attributes#}</h6>
<textarea name="fields[{$field.id}][attributes]" id="field_attr[{$field.id}]" placeholder="{#attributes#}" class="mousetrap" rows="8">{$field.attributes|escape}</textarea>
<div> |
php |
@@ -263,7 +242,7 @@
</div>
</div>
<div class="col-half">
<h6 style="line-height: 22px;">{#field_tpl#}</h6>
<h6>{#field_tpl#}</h6>
<textarea name="fields[{$field.id}][tpl]" id="field_tpl[{$field.id}]" placeholder="{#field_tpl#}" class="mousetrap" rows="8">{$field.tpl|escape}</textarea>
<div> |
php |

View File

@@ -11,12 +11,6 @@
$smarty = new Array;
$smarty['stat_replied'] = '{#stat_replied#}';
$smarty['stat_viewed'] = '{#stat_viewed#}';
$smarty['delete'] = '{#delete#}';
$smarty['cn_select_for_action'] = '{#cn_select_for_action#}';
$smarty['cn_confirm_mass_del'] = '{#cn_confirm_mass_del#}';
$smarty['delete_error'] = '{#delete_error#}';
$smarty['action_confirm_title'] = '{#action_confirm_title#}';
$smarty['action_error_title'] = '{#action_error_title#}';
</script>
<div class="title">
@@ -32,7 +26,7 @@ $smarty['action_error_title'] = '{#action_error_title#}';
<li><a href="index.php?do=modules&amp;cp={$sess}">{#MODULES_SUB_TITLE#}</a></li>
<li><a href="index.php?do=modules&amp;action=modedit&amp;mod=forms&amp;moduleaction=1&amp;cp={$sess}">{#contacts#}</a></li>
<li><a href="index.php?do=modules&amp;action=modedit&amp;mod=forms&amp;moduleaction=1&amp;cp={$sess}">{#forms#}</a></li>
<li><strong class="code"><a href="index.php?do=modules&amp;action=modedit&amp;mod=forms&amp;moduleaction=form_edit&amp;fid={$fid}&amp;cp={$sess}" {if $ave14}style="float:none; display:inline;"{/if}>{$form.title|default:''|escape}</a></strong></li>
<li><strong class="code"><a href="index.php?do=modules&amp;action=modedit&amp;mod=forms&amp;moduleaction=form_edit&amp;fid={$fid}&amp;cp={$sess}" {if $ave14}style="float:none; display:inline;"{/if}>{$form.title|escape}</a></strong></li>
<li>{#history#}</li>
</ul>
</div>
@@ -46,7 +40,6 @@ $smarty['action_error_title'] = '{#action_error_title#}';
</div>
<table cellpadding="0" cellspacing="0" width="100%" class="tableStatic mainForm" id="forms">
<colgroup>
<col width="10">
<col width="100"/>
<col/>
<col width="1"/>
@@ -55,7 +48,6 @@ $smarty['action_error_title'] = '{#action_error_title#}';
</colgroup>
<thead>
<tr>
<td><div align="center"><input type="checkbox" id="selectAll" value="1" /></div></td>
<td>{#date#}</td>
<td>{#mfld_subject#}</td>
<td>{#author#}</td>
@@ -66,7 +58,6 @@ $smarty['action_error_title'] = '{#action_error_title#}';
<tbody>
{foreach from=$dialogs item=dialog}
<tr class="{if $dialog.status==='new'}green{elseif $dialog.status==='viewed'}yellow{/if}">
<td nowrap="nowrap"><div><input name="form[{$dialog.id}]" type="checkbox" value="1" class="checkbox his-checkbox" /></div></td>
<td align="right" nowrap="nowrap">
<span class="date_text dgrey">{$dialog.date|date_format:$TIME_FORMAT|pretty_date}</span>
</td>
@@ -100,36 +91,9 @@ $smarty['action_error_title'] = '{#action_error_title#}';
</tr>
{/foreach}
</tbody>
{if $dialog}
<thead>
<tr>
<td></td>
<td>{#date#}</td>
<td>{#mfld_subject#}</td>
<td>{#author#}</td>
<td>{#status#}</td>
<td>{#cn_actions#}</td>
</tr>
</thead>
{/if}
</table>
{if $dialog}
<div class="rowElem" id="saveBtn">
<div class="saveBtn">
<select name="moderation" class="action-in-moderation">
<option value="none" selected="selected">{#actions_sel#}</option>
<option value="viewed">{#stat_viewed#}</option>
<option value="replied">{#stat_replied#}</option>
<option value="delete">{#delete#}</option>
</select>
&nbsp;&nbsp;<input type="button" class="basicBtn" value="{#save_changes#}" id="massActionButton" />
<script>// разукрашиваем select
$('select').styler({ldelim}selectSearch:false, selectVisibleOptions:5{rdelim});
</script>
</div>
</div>
{/if}
</div>
{if $page_nav}
<div class="pagination">
<ul class="pages">
@@ -170,173 +134,4 @@ function status_change (sel) {
});
};
</script>
{/literal}
{literal}
<script>
// =========================================================
// 1. ФУНКЦИЯ ДЛЯ СБРОСА ВСЕХ ВЫБРАННЫХ ЧЕКБОКСОВ ПОСЛЕ AJAX
// =========================================================
function resetAllCheckedHisCheckboxes() {
// 1. Сначала пытаемся сбросить через главный чекбокс, если он активен
var $selectAll = $('#selectAll');
if ($selectAll.prop('checked')) {
// Используем .click() для корректной работы с плагином стилизации
$selectAll.click();
}
// 2. Агрессивный сброс: Проходим по всем подчиненным элементам, которые могли остаться отмеченными
$('#forms tbody .his-checkbox:checked').each(function() {
var $checkbox = $(this);
// Вызываем click() для снятия отметки, если она еще стоит
$checkbox.click();
});
}
// =========================================================
// 2. ОБРАБОТЧИК КЛИКА ПО ГЛАВНОМУ ЧЕКБОКСУ (#selectAll)
// =========================================================
$(document).on('click', '#selectAll', function() {
var isChecked = $(this).prop('checked');
var $hisCheckboxes = $('#forms tbody .his-checkbox');
$hisCheckboxes.each(function() {
var $checkbox = $(this);
// Используем .click() для принудительного обновления стилизованного элемента
if ($checkbox.prop('checked') !== isChecked) {
$checkbox.click();
}
});
});
// =========================================================
// 3. ОБРАБОТЧИК КНОПКИ МАССОВОГО ДЕЙСТВИЯ (#massActionButton)
// =========================================================
$(document).on('click', '#massActionButton', function() {
var $selectElement = $('.action-in-moderation');
// Получаем значение, читая выбранный <option> (для обхода плагина стилизации)
var selectedAction = $selectElement.find('option:selected').val();
var $checkedRows = $('#forms tbody .his-checkbox:checked');
if ($checkedRows.length === 0) {
if (selectedAction !== 'none') {
jAlert($smarty['cn_select_for_action'], $smarty['action_error_title']); // "Выберите хотя бы один элемент"
}
return false;
}
// --- ЛОГИКА МАССОВОГО УДАЛЕНИЯ ---
if (selectedAction === 'delete') {
// 1. Подтверждение удаления через jConfirm
jConfirm($smarty['cn_confirm_mass_del'], $smarty['action_confirm_title'], function(r) {
if (r) {
var deletions = [];
// Сбор ID и визуальное удаление
$checkedRows.each(function() {
var $checkbox = $(this);
var nameAttr = $checkbox.attr('name');
var match = nameAttr.match(/form\[(\d+)\]/);
if (match && match[1]) {
var dialogId = match[1];
var $row = $checkbox.closest('tr');
deletions.push(dialogId);
$row.fadeOut(300, function() { $(this).remove(); });
}
});
// Выполнение AJAX-запросов
if (deletions.length > 0) {
$.alerts._overlay('show');
var completedRequests = 0;
deletions.forEach(function(hid) {
$.ajax({
url: 'index.php?do=modules&action=modedit&mod=forms&moduleaction=email_del&hid=' + hid + '&ajax=1',
type: 'GET',
success: function() {
completedRequests++;
if (completedRequests === deletions.length) {
$.alerts._overlay('hide');
resetAllCheckedHisCheckboxes(); // Сброс
}
},
error: function() {
completedRequests++;
if (completedRequests === deletions.length) {
$.alerts._overlay('hide');
jAlert($smarty['delete_error'], $smarty['action_error_title']);
}
}
});
});
}
}
});
// --- ЛОГИКА МАССОВОГО ИЗМЕНЕНИЯ СТАТУСА ---
} else if (selectedAction === 'viewed' || selectedAction === 'replied') {
var completedRequests = 0;
var totalRequests = $checkedRows.length;
$.alerts._overlay('show');
// Перебираем выбранные чекбоксы
$checkedRows.each(function() {
var $checkbox = $(this);
var nameAttr = $checkbox.attr('name');
var match = nameAttr.match(/form\[(\d+)\]/);
if (match && match[1]) {
var hid = match[1];
var $row = $checkbox.closest('tr');
var $tdStatus = $row.find('td:eq(4)'); // 5-я ячейка со статусом
// Отправляем AJAX-запрос
$.ajax({
url: 'index.php?do=modules&action=modedit&mod=forms&moduleaction=dialog_status',
type: 'POST',
data: { hid: hid, status: selectedAction, ajax: 1 },
success: function(e) {
// Обновление ячейки статуса в DOM (взято из status_change)
$tdStatus.empty();
if (selectedAction === 'replied') {
$tdStatus.text($smarty['stat_replied']);
$row.removeClass('green yellow');
}
else if (selectedAction === 'viewed') {
$row.removeClass('green').addClass('yellow');
$('<select class="dialog_status" data-hid="'+hid+'" onChange="status_change($(this));"><option value="viewed">'+$smarty['stat_viewed']+'</option><option value="replied">'+$smarty['stat_replied']+'</option></select>').appendTo($tdStatus).jqTransform({imgPath: "../images"}).styler({selectVisibleOptions: 5,selectSearch: false});
}
completedRequests++;
if (completedRequests === totalRequests) {
$.alerts._overlay('hide');
resetAllCheckedHisCheckboxes(); // Сброс
}
},
error: function() {
completedRequests++;
if (completedRequests === totalRequests) {
$.alerts._overlay('hide');
jAlert('{#status_change_error#}', $smarty['action_error_title']);
}
}
});
}
});
} else {
return false;
}
});
</script>
{/literal}