
Отправка данных
SendIt умеет отправлять данные на 4 события Javascript: submit (если не указан атрибут data-si-event), change, input и click. Все 4 события можно использовать внутри одной формы.
Пример формы:
<form data-si-form="oneStepForm" data-si-preset="onestepform" data-si-event="submit" data-si-nosave> // [!code warning]
<label>
<input type="text" name="name" placeholder="Полное имя">
<p data-si-error="name"></p> // [!code warning]
</label>
<label>
<input type="text" name="email" placeholder="Email">
<p data-si-error="email"></p>
</label>
<label>
<input type="tel" name="phone" placeholder="+7(">
<p data-si-error="phone"></p>
</label>
<label for="politics">
<input type="checkbox" name="politics" id="politics">
Я на всё согласен!
</label>
<button type="submit">Отправить</button>
</form>Описание атрибутов
- data-si-preset - содержит название набора параметров(необязательный).
- data-si-event - содержит название события, при котором будет произведена отправка(необязательный).
- data-si-nosave - позволяет отменить сохранение введённых данных(необязательный).
- data-si-form - содержит название формы; сам атрибут нужен, чтобы компонент мог работать с этой формой; значение атрибута позволяет сохранять введённые данные и редактировать параметры из админки.
- data-si-error - содержит имя валидируемого поля, указывает на элемент, в котором будет показан текст ошибки(необязательный); если не указан ошибка будет выведена при помощи всплывающих уведомлений.
Пресеты
Путь к файлу с пресетами указан в системной настройке si_path_to_presets. Путь следует указывать относительно core_path (MODX_CORE_PATH). Это подключаемый PHP файл, который должен возвращать массив вот такого формата:
return [
'default' => [
'validate' => 'phone:required,name:required,email:email:required,politics:checkbox:required',
]
]Информация
Подсвеченная строка (№2) содержит ключ пресета, который следует указывать в атрибуте data-si-preset.
Компонент поддерживает все параметры доступные для FormIt. Полный список представлен в документации. Кроме того, существуют специфические параметры необходимые для работы тех или иных функций, например регистрация. Также вы можете добавлять произвольные параметры, которые будут доступны в обработчике и в JavaScript.
return [
'default' => [
'validate' => 'phone:required,name:required,email:email:required,politics:checkbox:required',
'successMessage' => 'Мы всё послали!',
],
'onestepform' => [
'extends' => 'default',
'redirectTo' => 0,
'redirectTimeout' => 3000,
'clearFieldsOnSuccess' => 1,
'fieldNames' => 'age==Возраст',
'successMessage' => 'Форма отправлена!',
],
]В примере видно, пресет onestepform имеет параметр extends, это означает, что к пресету будут добавлены параметры из пресета default. Если в обоих наборах есть одинаковые ключи, приоритет будет у значений из onestepform, т.е. в случае успешной отправки пользователь увидит сообщение Форма отправлена!.
Внимание
Наследование рекурсивное, другими словами, если пресет default наследует пресет third, параметры пресета third будут добавлены кк набору onestepform
Если вы используете кастомные валидаторы, то нет необходимости вручную добавлять параметр customValidators, т.к. он будет добавлен автоматически из данных в параметре validate.
Внимание
Валидатор checkbox не имеет реализации в виде сниппета и создавать его не нужно. Задача этого валидатора указать на то, что поле с именем politics это input[type="checkbox"]. Таким образом комбинация :checkbox:required позволяет сделать поле politics обязательным.
Никакие дополнительные манипуляции для валидации чекбоксов выполнять не требуется, т.е. добавлять скрытые поля и заполнять их средствами JS не нужно.
Отправка на событие "change"
Этот вариант отправки можно применять как ко всей форме, в случаях когда требуется передать все поля, или к одному конкретному полю. Если НЕ нужно отправлять всю форму, а только несколько полей, сгруппируйте нужные поля так, как показано в примере ниже:
<form>
<input name="username">
<div data-si-form data-si-preset="change_handler" data-si-event="change"> // [!code ++]
<input name="code">
<input name="phone">
</div>
</form>Информация
Поля code и phone будут отправлены на сервер при внесении изменений в любое из них.
Если нужно отправлять какое-то конкретное поле, то следует писать так:
<form>
<input name="username">
<input name="code" data-si-form data-si-preset="change_handler" data-si-event="change"> // [!code ++]
<input name="phone">
</form>И наконец, можно отправить всю форму целиком при изменении в любом из её полей:
<form data-si-form data-si-preset="change_handler" data-si-event="change"> // [!code ++]
<input name="username">
<input name="code">
<input name="phone">
</form>Отправка на событие "input"
Информация
Отправка при вводе работает аналогично отправке при изменении, только атрибут будет таким data-si-event="input".
Для чего нужна такая возможность? Представьте, что вам нужно, чтобы пользователь выбрал 1 вариант из 1000. Обычный select тут будет, мягко говоря, неудобным, зато можно по мере ввода отправлять данные на сервер, осуществлять поиск по 1000 значениям, и выводить пользователю подсказки. Отслеживание изменений в поле и отправку данных берёт на себя SendIt, поиск и вывод подсказок остается за вами.
Отправка на событие "click"
Для того чтобы понять, как лучше всего использовать данную возможность, рассмотрим пример. Допустим перед вами стоит задача проверить реальность введённого пользователем номера телефона посредством отправки ему кода. Вы создаёте форму
<form data-si-form data-si-preset="register">
<input name="phone" data-si-preset="send_code" data-si-event="change">
<input name="code">
<button type="button"
data-si-preset="check_code"
data-si-event="click">Подтвердить<button> // [!code ++]
<button type="submit" disabled>Регистрация<button>
</form>Работать она будет так:
- Пользователь вводит свой телефон и данные отправляются в обработчик пресета send_code, который отправит код и сохранит его в сессию.
- Получив код, пользователь вводит его в соответсвующее поле, жмёт кнопку Подтвердить и данные снова улетают на сервер, но уже в обработчик пресета check_code.
- И наконец, если проверка пройдена, можно разблокировать кнопку Регистрация и зарегистрировать пользователя.
Отправка целей в Яндекс.Метрику
Для того, чтобы SendIt отправлял цели в метрику, нужно установить значение ДА для системной настройки si_send_goal, указать ID счётчика в настройке si_counter_id и передать в пресете параметр goalName с названием цели.
Внимание
Цель должна иметь тип JavaScript-событие
Информация
Убедитесь, что на сайте установлен актуальный код метрики
<!-- Yandex.Metrika counter -->
<script type="text/javascript">
(function (m, e, t, r, i, k, a) {
m[i] = m[i] || function () {
(m[i].a = m[i].a || []).push(arguments)
};
m[i].l = 1 * new Date();
for (var j = 0; j < document.scripts.length; j++) {
if (document.scripts[j].src === r) {
return;
}
}
k = e.createElement(t), a = e.getElementsByTagName(t)[0], k.async = 1, k.src = r, a.parentNode.insertBefore(k, a)
})
(window, document, "script", "https://mcc.yandex.ru/metrika/tag.js", "ym");
ym(12345678, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
</script>
<noscript>
<div>
<img src="https://mc.yandex.ru/watch/57463354" style="position:absolute; left:-9999px;" alt=""/>
</div>
</noscript>
<!-- /Yandex.Metrika counter -->Защита от ботов и внешнего доступа
Информация
Из коробки компонент не поддерживает капчу, но вы можете добавить её проверку самостоятельно, иcпользуя События
С версии 3.1.0 компонент использует трёхуровневую антиспам-защиту, которая настраивается на уровне пресетов.
1. Proof of Work (PoW)
Перед отправкой формы браузер должен решить вычислительную задачу — найти такое значение (nonce), при котором SHA-256 хеш от challenge + nonce содержит заданное количество ведущих нулевых бит. Боты и скрипты не смогут массово отправлять формы, так как каждая отправка требует вычислений.
Параметры пресета:
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
usePoW | int | 0 | 1 — включить проверку, 0 — отключить |
powDifficulty | int | 18 | Количество ведущих нулевых бит. Чем больше, тем дольше решение. 18 = ~1-5 сек. |
Как работает:
- При загрузке страницы плагин генерирует случайный
challengeи сохраняет его в сессию и в cookiesipowchallenge. - Перед отправкой JS-модуль
ProofOfWorkрешает задачу, перебирая nonce. - Найденный nonce отправляется на сервер в параметре
_pow_nonce. - Сервер проверяет, что
hash('sha256', challenge + nonce)содержит нужное количество ведущих нулей. - После успешной проверки генерируется новый challenge для следующей отправки.
2. Поведенческая подпись (BehaviorSign)
Результат анализа поведения пользователя шифруется на клиенте алгоритмом AES-128-GCM и расшифровывается на сервере. Это не позволяет подделать результат анализа со стороны клиента.
Параметры пресета:
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
useBehaviorSign | int | 0 | 1 — включить проверку, 0 — отключить |
maxBotScore | int | 50 | Максимально допустимый балл подозрительности (0–100) |
minFillTime | int | 3 | Минимальное время заполнения формы в секундах |
Что проверяется на сервере:
- Флаг
isBot— должен бытьfalse. - Балл подозрительности
score— не должен превышатьmaxBotScore. - Соответствие
powChallenge— подпись привязана к текущему challenge. - Время заполнения формы — должно быть не менее
minFillTimeсекунд.
После успешной проверки генерируется новый ключ шифрования.
3. Анализ поведения (UserBehaviorTracker)
Модуль UserBehaviorTracker непрерывно анализирует поведение пользователя и вычисляет балл подозрительности (0–100).
Анализируемые метрики:
- Автоматизация — обнаружение
navigator.webdriver, headless-браузеров, маленького экрана и т.д. - Движения мыши — прямые линии, прямые углы (минимум 50 движений для анализа).
- Клики — одинаковые позиции, неестественно равные интервалы (минимум 3 клика).
- Нажатия клавиш — равномерные интервалы, повторяющиеся паттерны (минимум 5 нажатий).
- Скроллинг — одинаковая дистанция и интервалы (минимум 5 скроллов).
- Общая активность — слишком высокая или слишком низкая частота взаимодействий.
- Время заполнения формы — отслеживается от первого
focusinна форме.
Параметры анализа можно настроить в JS-конфигурации модуля (см. раздел Начало работы).
Настройка защиты в пресете
Защита настраивается для каждого пресета отдельно. Можно использовать наследование через extends:
return [
'default' => [
'validate' => 'name:required,email:email:required',
'usePoW' => 1,
'powDifficulty' => 18,
'useBehaviorSign' => 1,
'minFillTime' => 3,
],
'simpleform' => [
'extends' => 'default',
'validate' => 'email:email:required,name:required',
// наследует usePoW, useBehaviorSign, minFillTime из default
],
'search' => [
'hooks' => '',
'snippet' => 'searchSnippet',
// защита не включена — поиск не требует антиспама
],
];Подсказка
Рекомендуется включать защиту для форм, отправляющих письма или регистрирующих пользователей. Для форм поиска, пагинации и подобных операций защита обычно не нужна.
Внимание
Если для пресета включена поведенческая подпись (useBehaviorSign), но не включён PoW (usePoW), проверка challenge в подписи пропускается. Для максимальной защиты рекомендуется включать оба механизма вместе.
Карта защиты (protectionMap)
Компонент автоматически формирует карту защиты на основе всех пресетов и передаёт её на фронтенд через window.siConfig.protectionMap. Фронтенд использует эту карту, чтобы определить, какие проверки нужно выполнить перед отправкой конкретной формы.
Защита от внешнего доступа
Каждый запрос на сервер подписывается специальным токеном, это не полноценный CSRF-токен, так как живёт он до перезагрузки страницы и сгенерировать его достаточно просто. Однако этого должно быть достаточно для того, чтобы отвадить спамеров.
Если спам продолжает докучать, то можно использовать плагин, который ограничит отправку по IP.
Ограничение частоты отправки
Чтобы усложнить отправку ручного спама, предусмотрены две системные настройки:
- si_max_sending_per_session - позволяет указать максимальное количество отправок одной формы без перезагрузки.
- si_pause_between_sending - позволяет указать паузу между отправками.
Ограничения также можно задавать в пресете, используя параметры pauseBetweenSending и sendingPerSession.
Внимание
Обе настройки действуют, только на формы в вызове, которых есть хуки FormItAutoResponder или email или параметр antispam равным 1.
Вы можете снять ограничения для некоторых форм, написав плагин на событие OnCheckPossibilityWork.
Программная отправка
Подсказка
Если вам нужно выполнять программную (автоматическую) отправку формы, например по таймеру или в ответ на событие, защита может заблокировать такую отправку. Чтобы этого избежать, отключите защиту в пресете для автоматической формы, или переопределите параметры в слушателе события si:send:before:
document.addEventListener('si:send:before', (e) => {
const preset = e.detail.headers['X-SIPRESET'];
if (preset === 'auto_preset') {
e.detail.fetchOptions.body.set('isBot', '0');
}
});Для программной отправки используйте метод sendRequest:
const form = document.querySelector('[data-si-form="auto_preset"]');
SendIt.Sending.sendRequest(form, 'auto_preset');Обработка ответа сервера
С версии 2.0.0 компонент умеет выводить полученный HTML на страницу.
Чтобы воспользоваться данной возможностью нужно в пресете указать параметр resultBlockSelector. В качестве значения он принимает валидный CSS-селектор блока для помещения ответа.
Ответ может быть вставлен или добавлен к текущему содержимому блока за это отвечает параметр resultShowMethod, по умолчанию имеющий значение insert (замена содержимого), если требуется добавление используйте значение append.
Самое главное сниппет возвращающий ответ должен в параметре data устанавливать ключ html со строкой в формате HTML.
Конфигурация JavaScript
Конфигурация по умолчанию
export const ModulesConfig = {
Sending: {
forceLoad: true,
className: 'Sending',
pathToScripts: '../modules/sending.js',
rootSelector: '[data-si-form]',
presetSelector: '[data-si-preset]',
rootKey: 'siForm',
presetKey: 'siPreset',
eventKey: 'siEvent',
goalKey: 'siGoal',
actionUrl: '/assets/components/sendit/action.php',
errorBlockSelector: '[data-si-error="${fieldName}"]',
eventSelector: '[data-si-event="${eventName}"]',
errorClass: 'si-error'
},
}| Ключ | Описание | Значение |
|---|---|---|
| Ключ | Описание | Значение |
| :--------------------: | :----------------------------------------: | :---------------------------------------------------------------------: |
pathToScripts | ../modules/sending.js | путь к модулю, указывается относительно файла sendit.js |
rootSelector | [data-si-form] | селектор формы |
presetSelector | [data-si-preset] | селектор пресета |
rootKey | siForm | ключ свойства dataset с именем формы |
presetKey | siPreset | ключ свойства dataset атрибута с именем пресета |
eventKey | siEvent | ключ свойства dataset атрибута с именем события для отправки данных |
goalKey | siGoal | ключ свойства dataset с названиями целей разделённых запятыми |
actionUrl | /assets/components/sendit/action.php | путь к коннектору |
errorBlockSelector | [data-si-error="${fieldName}"] | селектор блока вывода ошибок |
eventSelector | [data-si-event="${eventName}"] | селектор события отправки |
errorClass | si-error | класс, добавляемый полям с ошибками |
