Формы в Wepps Platform: От шаблона до базы данных за 5 минут

В Wepps Platform работа с формами организована как конвейер: вы описываете форму в шаблоне, система автоматически собирает данные, валидирует их, показывает ошибки и обрабатывает успешную отправку. Давайте разберёмся, как это работает и почему это намного проще, чем кажется.

08.01.2026

Вам нужно добавить форму обратной связи на сайт? Создать форму регистрации, обработать опрос, собрать заявку на консультацию? Обычно это превращается в квест: свёрстай HTML, напиши JavaScript для валидации, создай PHP-скрипт обработки, настрой отправку на email, не забудь про безопасность... И так каждый раз для каждой новой формы.

А что если просто написать HTML-форму в шаблоне, добавить пару строк PHP-кода для валидации — и всё? Форма работает, данные проверены, письмо отправлено, информация сохранена в базе.

В Wepps Platform работа с формами организована как конвейер: вы описываете форму в шаблоне, система автоматически собирает данные, валидирует их, показывает ошибки и обрабатывает успешную отправку. Давайте разберёмся, как это работает и почему это намного проще, чем кажется.

Конвейер обработки форм: как это понять

Представьте, что форма на сайте — это производственная линия на заводе. У вас есть:

  1. Шаблон формы (HTML) — это чертёж изделия. Вы описываете, какие поля нужны (имя, email, телефон), какие типы данных (текст, файл, чекбокс). Smarty-шаблон рисует форму на странице.

  2. JavaScript (Forms.js) — это контроль качества на входе. Проверяет базовые вещи: заполнены ли обязательные поля, не пустая ли форма. Отправляет данные на сервер через AJAX.

  3. Request.php — это главный цех обработки. Получает данные, проверяет их серьёзно (валидация email, телефона), решает что делать: отправить письмо, сохранить в базу, вернуть ошибку.

  4. Validator — это отдел технического контроля. Проверяет каждое поле по правилам и говорит: "Это email неправильный", "Телефон должен быть из 10 цифр", "Поле пустое".

  5. Обратная связь пользователю — готовое изделие. Показывает красные подсветки у неправильных полей или зелёное сообщение "Спасибо, ваше сообщение отправлено!".

Или вспомните ресторан:

  • Шаблон формы — это меню, где клиент делает заказ
  • JavaScript — официант, который сразу говорит "Выберите хотя бы одно блюдо"
  • Request.php — кухня, где готовят заказ
  • Validator — шеф-повар, который проверяет качество ингредиентов

Суть в том, что вы просто описываете форму, а платформа берёт на себя всю техническую работу.

Что такое FormWepps? Ваш личный менеджер форм

FormWepps — это JavaScript-класс, который управляет всеми формами на сайте. Его главная задача — собрать данные из формы и отправить на сервер, не перезагружая страницу.

Суперсилы FormWepps:

  • Отправка через AJAX. Страница не перезагружается, пользователь остаётся на месте. Современно и удобно.

    • На практике: пользователь нажал "Отправить" → данные улетели на сервер → через секунду появилось "Сообщение отправлено" — и всё это без белого экрана загрузки.
  • Загрузка файлов. Прикрепить резюме, фото, документ — всё работает автоматически.

    • На практике: выбрал файл → он сразу загрузился в сессию → при отправке формы файл прикрепится к письму.
  • Автоматическая очистка ошибок. Показал ошибки в полях → пользователь начал исправлять → ошибки исчезли.

Где вы это видите на любом сайте?

  • Форма "Заказать звонок" в модальном окне
  • Форма обратной связи в футере
  • Форма регистрации с загрузкой аватара
  • Опрос с чекбоксами и радиокнопками

Что такое Validator? Контролёр качества данных

Validator — это PHP-класс с набором методов для проверки данных. Если FormWepps — это почтальон, который доставляет письмо, то Validator — это таможня, которая проверяет содержимое.

Суперсилы Validator:

  • Проверка типов данных. Email это email, телефон это телефон, число это число — никакой самодеятельности.
  • Визуализация ошибок. Автоматически генерирует JavaScript, который подсвечивает неправильные поля красным и показывает текст ошибки.
  • Гибкие проверки. От простых "поле не пустое" до сложных "это валидный штрих-код EAN13".

Проще простого: Вы пишете Validator::isEmail($email, "Неверный email") — и класс либо вернёт пустую строку (всё ок), либо текст ошибки.

Что такое Request? Мозг обработки форм

Request — это абстрактный класс, от которого наследуются все обработчики форм. Он организует весь процесс: получает данные, вызывает валидацию, подключает шаблоны ответа.

Суперсилы Request:

  • Автоматический сбор данных. Все переменные из $_REQUEST попадают в $this->get уже очищенными от лишних пробелов.
  • Встроенная работа с шаблонами. Можете вернуть HTML-ответ через Smarty-шаблон.
  • Метод outer(). Один вызов — и готов JavaScript с ошибками или сообщением успеха.

Магия в соединении: создаём рабочую форму за 5 шагов

Давайте создадим форму обратной связи с нуля:

Шаг 1. Создаём HTML-форму в шаблоне

В файле Contacts.tpl пишем:

<form action="javascript:formWepps.send('feedback','feedback-form','/ext/Contacts/Request.php')"
    id="feedback-form" class="w_form">
    <h2>Напишите сообщение</h2>
    <fieldset>
        <section>
            <div class="title">Ваше имя</div>
            <label class="w_label w_input w_require">
                <input type="text" name="name" placeholder="" />
            </label>
        </section>
        <section>
            <div class="title">Email</div>
            <label class="w_label w_input w_require">
                <input type="email" name="email" placeholder="" />
            </label>
        </section>
        <section>
            <div class="title">Сообщение</div>
            <label class="w_label w_area w_require">
                <textarea name="comment" placeholder=""></textarea>
            </label>
        </section>
    </fieldset>
    <fieldset>
        <section>
            <label class="w_label w_checkbox">
                <input type="checkbox" name="approve" />
                <span>Я согласен на обработку персональных данных</span>
            </label>
            <label class="w_label w_button">
                <input type="submit" value="Отправить" disabled />
            </label>
        </section>
    </fieldset>
</form>

Ключевые моменты:

  • action="javascript:formWepps.send(...)" — отправка через AJAX
  • id="feedback-form" — уникальный ID формы для обработки ошибок
  • name="name", name="email" — эти имена будут ключами в PHP-массиве $this->get
  • class="w_require" — визуальная пометка обязательных полей
  • disabled на кнопке — активируется только после согласия с обработкой данных

Шаг 2. Создаём обработчик Request.php

В файле packages/WeppsExtensions/Contacts/Request.php:

<?php
require_once '../../../configloader.php';

use WeppsCore\Request;
use WeppsCore\Validator;
use WeppsCore\Connect;
use WeppsExtensions\Addons\Messages\Mail\Mail;

class RequestContacts extends Request
{
    public function request($action = '')
    {
        switch ($action) {
            case 'feedback':
                $this->feedback();
                break;
            default:
                Exception::error404();
                break;
        }
    }

    private function feedback()
    {
        // Валидация полей
        $this->errors = [];
        $this->errors['name'] = Validator::isNotEmpty($this->get['name'], "Не заполнено");
        $this->errors['email'] = Validator::isEmail($this->get['email'], "Неверный формат email");
        $this->errors['comment'] = Validator::isNotEmpty($this->get['comment'], "Не заполнено");

        // Показываем ошибки или сообщение успеха
        $outer = Validator::setFormErrorsIndicate($this->errors, $this->get['form']);
        $this->assign('jscode', $outer['html']);

        // Если ошибок нет — обрабатываем
        if ($outer['count'] == 0) {
            // Формируем сообщение
            $subject = "Сообщение с сайта";
            $message = "Имя: {$this->get['name']}\n";
            $message .= "Email: {$this->get['email']}\n";
            $message .= "Сообщение: {$this->get['comment']}\n";

            // Сохраняем в базу
            $row = [
                'Name' => trim($this->get['name']),
                'Email' => $this->get['email'],
                'Descr' => trim($message),
                'SDate' => date("Y-m-d H:i:s"),
                'SGroup' => 'Обратная связь'
            ];
            Connect::$instance->insert("FormsData", $row);

            // Отправляем письмо
            $mail = new Mail('html');
            $mail->mail(Connect::$projectInfo['email'], $subject, nl2br($message));

            // Показываем успех
            $arr = Validator::setFormSuccess("Спасибо! Ваше сообщение отправлено", $this->get['form']);
            $this->assign('jscode', $arr['html']);
        }

        $this->tpl = "RequestContacts.tpl";
    }
}

$request = new RequestContacts($_REQUEST);
$smarty->assign('get', $request->get);
$smarty->display($request->tpl);

Шаг 3. Создаём шаблон ответа RequestContacts.tpl

{$jscode}

Всё! Этот минималистичный шаблон выводит JavaScript-код с ошибками или сообщением успеха.

Шаг 4. Подключаем JavaScript и стили

В основном классе расширения Contacts.php:

$this->headers->js("/ext/Template/Forms/Forms.{$this->rand}.js");
$this->headers->css("/ext/Template/Forms/Forms.{$this->rand}.css");

Класс FormWepps уже реализован в Forms.js — не нужно ничего писать!

Шаг 5. Готово!

Теперь форма:

  • ✅ Проверяет обязательные поля
  • ✅ Валидирует email
  • ✅ Отправляет данные без перезагрузки
  • ✅ Показывает ошибки красным цветом рядом с полями
  • ✅ Сохраняет данные в таблицу FormsData
  • ✅ Отправляет письмо на email администратора
  • ✅ Показывает "Спасибо, сообщение отправлено!"

Вот и вся магия! Вы описали форму в HTML, добавили 3 строки валидации, указали что делать с данными — и готово. Остальное платформа сделала сама.

Почему это круто? Выгоды для всех

🚀 Для владельца бизнеса:

  • Быстрое добавление форм. Новая форма — это несколько часов, а не дней разработки.
  • Все заявки в одном месте. Таблица FormsData хранит все обращения с разных форм.
  • Письма на email. Дублирование в почту — ничего не потеряется.
  • Готовые стили. Формы выглядят современно из коробки (классы w_form, w_label, w_input).

👨‍💻 Для разработчика:

  • Не нужно писать AJAX каждый раз. FormWepps — это глобальный объект, доступный везде.
  • Валидация за 1 строку. Validator::isEmail() вместо регулярных выражений и проверок.
  • Автоматическая визуализация ошибок. Метод setFormErrorsIndicate() генерирует весь JavaScript.
  • Загрузка файлов из коробки. Просто <input type="file"> — и всё работает.
  • Безопасность. Все данные очищаются от пробелов через Utils::trim().
  • Гибкость настройки. Полный контроль над HTML-разметкой через .tpl шаблоны.
  • Единая структура. Все формы следуют одному паттерну — легко поддерживать и масштабировать.

👥 Для администратора контента:

  • Все заявки в одном месте. Таблица FormsData в админке показывает все обращения с разных форм сайта.
  • Просмотр вложений. Если клиент прикрепил файлы (резюме, документы) — они доступны прямо из админки.
  • Удобная фильтрация. Поиск по дате, группе формы (обратная связь, заявки, подписки), статусу обработки.
  • Экспорт данных. Выгрузка заявок в Excel для анализа и отчётов.

✅ Для всех вместе:

  • Единый стандарт. Все формы на сайте работают одинаково — клиенты привыкают, меньше ошибок.
  • Мобильная адаптация. Стили w_form адаптивны по умолчанию.
  • Доступность. Правильная разметка с <label> для всех полей.
  • Масштабируемость. Одна форма или 50 форм — подход не меняется.

Реальные сценарии использования

Сценарий 1: Форма "Заказать звонок" в модальном окне

Ситуация: Нужна быстрая форма в popup с двумя полями: имя и телефон.

Решение:

<form action="javascript:formWepps.popup('callback','callback-form','/ext/Contacts/Request.php')"
    id="callback-form">
    <label class="w_label w_input w_require">
        <input type="text" name="name" placeholder="Ваше имя" />
    </label>
    <label class="w_label w_input w_require">
        <input type="text" name="phone" placeholder="+7 (___) ___-__-__" />
    </label>
    <label class="w_label w_button">
        <input type="submit" value="Заказать звонок" />
    </label>
</form>

Добавляем в Request.php:

case 'callback':
    $this->errors['name'] = Validator::isNotEmpty($this->get['name'], "Укажите имя");
    $this->errors['phone'] = Validator::isNotEmpty($this->get['phone'], "Укажите телефон");
    // ... обработка

Результат: Форма в popup, маска на телефон (через inputmask.js), данные в базу, уведомление на email — за 15 минут.

Сценарий 2: Добавление поля загрузки файла

Ситуация: Нужно добавить в форму возможность загрузить файл (резюме, документ, фото).

Решение: Добавьте в форму секцию с полем загрузки файла:

<section>
    <div class="title">Резюме</div>
    <label class="w_label w_upload">
        <input type="file" name="resume-upload" />
        <span>Прикрепить файл (PDF, DOC, DOCX)</span>
    </label>
    <div class="w_upload_add">
        {foreach $uploaded['resume-upload'] as $k => $file}
            <div class="w_upload_file" data-key="{$k}">
                {$file.name} <i class="bi bi-x-circle-fill"></i>
            </div>
        {/foreach}
    </div>
</section>

В PHP:

$files = new Files();
if ($filesAttach = $files->getUploaded($this->get['form'], 'resume-upload')) {
    $mail->setAttach($filesAttach);
}
$mail->mail($email, $subject, $message);
$files->removeUploaded($this->get['form'], 'resume-upload');

Результат: Файл загружается в сессию при выборе, прикрепляется к письму при отправке, автоматически удаляется после.

Сценарий 3: Сложная форма с чекбоксами, радио, селектами

Ситуация: Опросник с разными типами полей.

Решение:

<fieldset>
    <section>
        <div class="title">Интересующие услуги</div>
        <label class="w_label w_checkbox">
            <input type="checkbox" name="services[]" value="web"> <span>Разработка сайтов</span>
        </label>
        <label class="w_label w_checkbox">
            <input type="checkbox" name="services[]" value="seo"> <span>SEO-продвижение</span>
        </label>
    </section>
    <section>
        <div class="title">Бюджет проекта</div>
        <label class="w_label w_radio">
            <input type="radio" name="budget" value="small"> <span>До 100 000 ₽</span>
        </label>
        <label class="w_label w_radio">
            <input type="radio" name="budget" value="medium"> <span>100 000 - 500 000 ₽</span>
        </label>
    </section>
    <section>
        <div class="title">Срочность</div>
        <label class="w_label w_select">
            <select name="urgency">
                <option value="month">В течение месяца</option>
                <option value="week">Срочно, неделя</option>
            </select>
        </label>
    </section>
</fieldset>

В PHP:

// Массив чекбоксов
if (!empty($this->get['services'])) {
    $services = implode(', ', $this->get['services']);
    $message .= "Услуги: $services\n";
}

// Радио и селект — обычные переменные
$message .= "Бюджет: {$this->get['budget']}\n";
$message .= "Срочность: {$this->get['urgency']}\n";

Результат: Все типы полей работают, массивы обрабатываются автоматически, Select2 подключается для красивых селектов.

Частые вопросы и заблуждения

❓ Нужно ли писать JavaScript для каждой формы?

Заблуждение: Для каждой новой формы нужно писать свой обработчик на JavaScript.

Реальность: Нет! Класс FormWepps — глобальный объект, доступный на всех страницах. Вы просто указываете formWepps.send('action', 'form-id', '/путь/к/Request.php') в атрибуте action формы — и всё. JavaScript для загрузки файлов, очистки ошибок, работы с чекбоксами — уже написан один раз для всех форм.

❓ Как защититься от спама и ботов?

Заблуждение: Формы в платформе не защищены от автоматических отправок.

Реальность: Есть несколько уровней защиты:

  1. Honeypot — добавьте скрытое поле <input type="text" name="honeypot" style="display:none">. В PHP проверяйте: если оно заполнено — это бот.
  2. Временные метки — сохраняйте в сессии время показа формы, проверяйте что прошло хотя бы 3 секунды.
  3. reCAPTCHA — подключается через класс расширения.

Пример honeypot:

if (!empty($this->get['honeypot'])) {
    return; // Бот, игнорируем
}

❓ Можно ли отправить форму БЕЗ AJAX (обычным POST)?

Ответ: Да, но не рекомендуется. Просто уберите javascript: из action:

<form action="/ext/Contacts/Request.php" method="POST">

Но тогда:

  • ❌ Страница перезагрузится
  • ❌ Ошибки не подсветятся красным автоматически
  • ❌ Пользователь увидит белый экран во время обработки

AJAX-подход современнее и удобнее.

Сравнение: традиционный подход vs Wepps Platform

Аспект Традиционный подход Wepps Platform
Создание формы HTML + jQuery validation + AJAX-запрос + PHP-обработка HTML + formWepps.send() — готово ✅
Валидация Писать регулярки или использовать библиотеку Validator::isEmail() — одна строка ✅
Показ ошибок Писать JS для подсветки полей красным setFormErrorsIndicate() — автоматически ✅
Загрузка файлов Настройка FormData, проверка размера, MIME-типов <input type="file"> — работает из коробки ✅
Сохранение в БД Писать SQL-запросы, защищаться от инъекций Connect::$instance->insert($table, $row)
Отправка email Настройка PHPMailer или SwiftMailer $mail->mail($to, $subject, $message)
Время разработки 4-8 часов на форму 30 минут - 1 час ✅

Пошаговое руководство для начинающих

Шаг 1: Определите поля формы

Запишите на бумаге или в блокноте:

  • Какие данные нужно собрать? (имя, email, телефон, сообщение)
  • Какие поля обязательные? (name, email — обязательно; телефон — опционально)
  • Нужна ли загрузка файлов? (да/нет)

Шаг 2: Создайте HTML-разметку в .tpl файле

Используйте шаблон:

<form action="javascript:formWepps.send('myaction','myform','/ext/MyExtension/Request.php')"
    id="myform" class="w_form">
    <fieldset>
        <section>
            <div class="title">Название поля</div>
            <label class="w_label w_input w_require">
                <input type="text" name="fieldname" />
            </label>
        </section>
        <!-- ... другие поля ... -->
    </fieldset>
    <fieldset>
        <label class="w_label w_button">
            <input type="submit" value="Отправить" />
        </label>
    </fieldset>
</form>

Типы полей:

  • w_input + <input type="text"> — текстовое поле
  • w_area + <textarea> — многострочное поле
  • w_checkbox + <input type="checkbox"> — чекбокс
  • w_radio + <input type="radio"> — радиокнопка
  • w_select + <select> — выпадающий список
  • w_upload + <input type="file"> — загрузка файла

Шаг 3: Создайте или откройте Request.php

Структура:

<?php
require_once '../../../configloader.php';

use WeppsCore\Request;
use WeppsCore\Validator;
use WeppsCore\Connect;

class RequestMyExtension extends Request
{
    public function request($action = '')
    {
        switch ($action) {
            case 'myaction':
                $this->myaction();
                break;
            default:
                Exception::error404();
                break;
        }
    }

    private function myaction()
    {
        // Здесь будет код обработки
        $this->tpl = "RequestMyExtension.tpl";
    }
}

$request = new RequestMyExtension($_REQUEST);
$smarty->assign('get', $request->get);
$smarty->display($request->tpl);

Шаг 4: Добавьте валидацию полей

Внутри метода myaction():

$this->errors = [];
$this->errors['name'] = Validator::isNotEmpty($this->get['name'], "Укажите имя");
$this->errors['email'] = Validator::isEmail($this->get['email'], "Неверный email");

$outer = Validator::setFormErrorsIndicate($this->errors, $this->get['form']);
$this->assign('jscode', $outer['html']);

Доступные методы Validator:

  • isNotEmpty($var, $msg) — поле не пустое
  • isEmail($var, $msg) — валидный email
  • isInt($var, $msg) — целое число
  • isFloat($var, $msg) — число с плавающей точкой
  • isUrl($var, $msg) — корректный URL
  • isPhone($var, $msg) — телефон (10 цифр)
  • isDate($var, $msg) — корректная дата

Шаг 5: Обработайте успешную отправку

Если ошибок нет ($outer['count'] == 0):

if ($outer['count'] == 0) {
    // Сохраните в базу
    $row = [
        'Name' => $this->get['name'],
        'Email' => $this->get['email'],
        'SDate' => date("Y-m-d H:i:s")
    ];
    Connect::$instance->insert("FormsData", $row);

    // Отправьте письмо
    $mail = new Mail('html');
    $message = "Имя: {$this->get['name']}\nEmail: {$this->get['email']}";
    $mail->mail('admin@site.ru', 'Новая заявка', nl2br($message));

    // Покажите успех
    $arr = Validator::setFormSuccess("Спасибо! Ваша заявка принята", $this->get['form']);
    $this->assign('jscode', $arr['html']);
}

Шаг 6: Создайте минимальный шаблон ответа

Файл RequestMyExtension.tpl:

{$jscode}

Шаг 7: Подключите стили и скрипты в основном классе

В файле MyExtension.php:

$this->headers->js("/ext/Template/Forms/Forms.{$this->rand}.js");
$this->headers->css("/ext/Template/Forms/Forms.{$this->rand}.css");

Шаг 8: Протестируйте форму

  1. Откройте страницу с формой
  2. Попробуйте отправить пустую форму — должны появиться красные подсветки
  3. Заполните неправильно email — должна появиться ошибка "Неверный email"
  4. Заполните правильно — должно появиться "Спасибо! Ваша заявка принята"
  5. Проверьте таблицу FormsData в базе — там должна быть новая запись
  6. Проверьте почту — должно прийти письмо

Совет: Включите режим разработки в config.php ('debug' => 1), чтобы видеть все ошибки PHP.

Принципы работы с формами

✅ Делайте так:

  • Используйте уникальные ID форм — каждая форма должна иметь свой id, чтобы ошибки подсвечивались правильно.

    <form id="feedback-form"> <!-- Уникальный ID -->
    <form id="callback-form">  <!-- Другой ID -->
  • Добавляйте класс w_require к обязательным полям — пользователь увидит красную звёздочку.

    <label class="w_label w_input w_require">
      <input type="text" name="email" />
    </label>
  • Всегда оборачивайте input в label — это улучшает доступность и удобство клика.

    <!-- ✅ Правильно -->
    <label class="w_label w_input">
      <input type="text" name="name" />
    </label>
    
    <!-- ❌ Неправильно -->
    <input type="text" name="name" />
  • Используйте говорящие имена полейname="user_email" лучше, чем name="field1".

    $this->errors['user_email'] = Validator::isEmail($this->get['user_email'], "Неверный email");

❌ Не делайте так:

  • Не дублируйте ID форм — если на странице две формы с id="form", ошибки будут показываться неправильно.

  • Не используйте методы валидации неправильноisEmail() для телефона или isInt() для строки вернут ошибки.

    // ❌ Неправильно
    $this->errors['phone'] = Validator::isEmail($this->get['phone'], "Ошибка");
    
    // ✅ Правильно
    $this->errors['phone'] = Validator::isPhone($this->get['phone'], "Неверный формат телефона");
  • Не забывайте про $outer['count'] == 0 — иначе код выполнится даже при наличии ошибок.

    // ❌ Плохо
    Connect::$instance->insert("FormsData", $row); // Выполнится всегда!
    
    // ✅ Хорошо
    if ($outer['count'] == 0) {
      Connect::$instance->insert("FormsData", $row);
    }

Типичные ошибки и как их избежать

Ошибка 1: Форма не отправляется, кнопка неактивна

Что происходит: Кнопка отправки остаётся серой (disabled), форма не реагирует на клик.

Причина: Не снята галочка с чекбокса "Согласие на обработку данных", или отсутствует JavaScript для активации кнопки.

Как исправить:

// Этот код уже есть в Forms.js, но если у вас своя форма:
$('input[name="approve"]').on('change', function () {
    let isChecked = $(this).prop('checked');
    $(this).closest('form').find('input[type="submit"]').prop('disabled', !isChecked);
});

Как избежать: Используйте стандартные классы и структуру форм — тогда formsInit() из Forms.js автоматически всё настроит.

Ошибка 2: Ошибки не подсвечиваются красным

Что происходит: Форма отправляется, но неправильные поля не подсвечиваются, ошибки не видны.

Причина:

  1. Не подключён Forms.css (там стили .w_error, .w_error_parent)
  2. Неправильный id формы в вызове setFormErrorsIndicate()
  3. Имена полей в HTML не совпадают с ключами в $this->errors

Как исправить:

// Проверьте, что form = id формы
$outer = Validator::setFormErrorsIndicate($this->errors, $this->get['form']);
//                                                       ^^^^^^^^^^^^^^^^
// Это значение приходит из JavaScript: formWepps.send('action', 'form-id', ...)
//                                                                 ^^^^^^^^^
<!-- В HTML -->
<form id="feedback-form">
    <input type="text" name="email" />
</form>

<!-- В JavaScript -->
<form action="javascript:formWepps.send('feedback','feedback-form','/...')">
                                                     ^^^^^^^^^^^^^^^
// В PHP — ключ массива = name поля
$this->errors['email'] = Validator::isEmail($this->get['email'], "Ошибка");
//             ^^^^^                                 ^^^^^

Как избежать: Всегда используйте одинаковые имена: name атрибут → ключ в $this->errors → ключ в $this->get.

Ошибка 3: Файлы не загружаются или не прикрепляются к письму

Что происходит: Выбрали файл, но он не появляется в списке загруженных, или письмо приходит без вложения.

Причина:

  1. Не подключён JavaScript Forms.js (там обработчик загрузки файлов)
  2. Не настроена сессия (session_start() должен быть в начале Request.php)
  3. Не вызван метод удаления файлов после отправки

Как исправить:

// В начале Request.php
if (!session_id()) {
    session_start();
}

// При отправке письма
use WeppsExtensions\Addons\Files\Files;

$files = new Files();
if ($filesAttach = $files->getUploaded($this->get['form'], 'file-field-name')) {
    $mail->setAttach($filesAttach);
}
$mail->mail($email, $subject, $message);
$files->removeUploaded($this->get['form'], 'file-field-name'); // Удаляем из сессии!

Как избежать:

  1. Всегда стартуйте сессию в Request.php
  2. Используйте правильное имя поля (name="file-field-name")
  3. Удаляйте файлы после обработки, чтобы они не накапливались в сессии

Производительность

Оптимизация: кэширование списка форм

Если у вас на сайте много форм с одинаковыми данными (например, список городов в селекте), не запрашивайте данные при каждом рендере:

// ❌ Неоптимально — запрос к БД при каждой загрузке страницы
$obj = new Data("Cities");
$cities = $obj->fetch("IsHidden=0");
$smarty->assign('cities', $cities);
// ✅ Оптимально — кэширование через Memcached
$cacheKey = "cities_list";
$cities = Connect::$memcached->get($cacheKey);

if (!$cities) {
    $obj = new Data("Cities");
    $cities = $obj->fetch("IsHidden=0");
    Connect::$memcached->set($cacheKey, $cities, 3600); // Кэш на 1 час
}

$smarty->assign('cities', $cities);

Оптимизация: минимизация CSS/JS форм

В режиме продакшн ('debug' => 0 в config.php) платформа автоматически минифицирует и кэширует CSS/JS. Но вы можете ускорить загрузку, объединив несколько файлов:

// Объединяем стили форм и валидации в один файл
$this->headers->css("/ext/Template/Forms/FormsBundle.{$this->rand}.css");

Оптимизация: отложенная загрузка Select2

Если на странице нет селектов, не подключайте библиотеку:

// В основном классе расширения
if ($hasSelects) { // Флаг наличия селектов
    $this->headers->js("/packages/vendor/select2/select2/dist/js/select2.full.min.js");
}

Безопасность

Защита от SQL-инъекций

Проблема: Данные из форм могут содержать вредоносный SQL-код.

Решение: Используйте методы класса Connect, которые используют подготовленные запросы (prepared statements):

// ❌ Небезопасно — прямой SQL-запрос
$name = $this->get['name'];
Connect::$instance->db->query("INSERT INTO FormsData (Name) VALUES ('$name')");

// ✅ Безопасно — метод insert() использует prepared statements
$row = ['Name' => $this->get['name']];
Connect::$instance->insert("FormsData", $row);

Защита от XSS-атак

Проблема: Пользователь может ввести <script>alert('XSS')</script> в поле формы.

Решение: Экранируйте вывод в шаблонах Smarty:

{* ❌ Небезопасно — выводится как есть *}
{$get.name}

{* ✅ Безопасно — экранируется автоматически *}
{$get.name|escape}

Для email-сообщений используйте htmlspecialchars():

// ❌ Небезопасно
$message = "Имя: {$this->get['name']}";

// ✅ Безопасно
$message = "Имя: " . htmlspecialchars($this->get['name'], ENT_QUOTES, 'UTF-8');

Защита от CSRF-атак

Проблема: Злоумышленник может отправить форму от имени пользователя с другого сайта.

Решение: Добавьте CSRF-токен в форму:

// В основном классе расширения (при рендере формы)
if (!isset($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
$smarty->assign('csrf_token', $_SESSION['csrf_token']);
<!-- В шаблоне формы -->
<input type="hidden" name="csrf_token" value="{$csrf_token}" />
// В Request.php (при обработке)
if (!isset($_SESSION['csrf_token']) || $this->get['csrf_token'] !== $_SESSION['csrf_token']) {
    $this->errors['_general'] = "Ошибка безопасности. Попробуйте еще раз.";
    // ... показываем ошибку и выходим
    return;
}

Интеграция с другими компонентами

Работа с расширением Files (загрузка файлов)

use WeppsExtensions\Addons\Files\Files;

// Получить загруженные файлы из сессии
$files = new Files();
$uploaded = $files->getUploaded($formId, $fieldName);
// Вернёт массив: [['name' => 'file.pdf', 'path' => '/files/...', ...], ...]

// Прикрепить к письму
if ($filesAttach = $files->getUploaded($this->get['form'], 'resume')) {
    $mail->setAttach($filesAttach);
}

// Удалить из сессии после обработки
$files->removeUploaded($this->get['form'], 'resume');

// Передать список загруженных файлов в шаблон (для отображения)
if (isset($_SESSION['uploads'][$formId])) {
    $smarty->assign('uploaded', $_SESSION['uploads'][$formId]);
}

Работа с расширением Mail (отправка писем)

use WeppsExtensions\Addons\Messages\Mail\Mail;

// Создать объект письма (тип: text или html)
$mail = new Mail('html');

// Отправить простое письмо
$mail->mail(
    'client@example.com',        // Кому
    'Ваш заказ принят',          // Тема
    '<p>Спасибо за заказ!</p>'   // Сообщение (HTML)
);

// Отправить письмо с вложениями
$mail->setAttach([
    ['path' => '/files/lists/invoice.pdf', 'name' => 'Счет.pdf'],
    ['path' => '/files/lists/contract.doc', 'name' => 'Договор.doc']
]);
$mail->mail('client@example.com', 'Документы', $message);

// Отправить письмо с копией
$mail->mail(
    'client@example.com',        // Основной получатель
    'Уведомление',
    $message,
    'admin@site.ru'              // Копия администратору
);

Работа с Telegram (отправка уведомлений в Telegram)

use WeppsExtensions\Addons\Messages\Telegram\Telegram;

// Отправить уведомление в Telegram-канал или чат
$telegram = new Telegram();
$message = "🔔 Новая заявка!\n\n";
$message .= "Имя: {$this->get['name']}\n";
$message .= "Email: {$this->get['email']}\n";
$message .= "Телефон: {$this->get['phone']}";

$telegram->send($message);
// Отправится на chat_id, указанный в config.php: Connect::$projectServices['telegram']

Заключение

Формы в Wepps Platform предоставляют:

  • ✅ Готовый JavaScript-класс FormWepps для AJAX-отправки
  • ✅ Полный набор валидаторов в классе Validator
  • ✅ Автоматическую визуализацию ошибок с подсветкой полей
  • ✅ Загрузку файлов через сессии без дополнительного кода
  • ✅ Интеграцию с отправкой email и Telegram-уведомлений
  • ✅ Безопасность через подготовленные запросы и экранирование

Создание новой формы — это не квест, а простой процесс из 5 шагов: HTML-разметка → валидация в PHP → обработка данных → шаблон ответа → готово. Не нужно каждый раз изобретать велосипед, писать AJAX-обработчики или регулярки для email — платформа уже сделала это за вас.

Начните с простой формы обратной связи из раздела "Магия в соединении", экспериментируйте с типами полей, добавляйте загрузку файлов — и через час у вас будет работающая, безопасная, красивая форма.


Файлы:

  • packages/WeppsCore/Validator.php — класс валидации
  • packages/WeppsCore/Request.php — базовый класс обработчиков
  • packages/WeppsExtensions/Template/Forms/Forms.js — JavaScript для форм
  • packages/WeppsExtensions/Template/Forms/Forms.css — стили форм
  • packages/WeppsExtensions/Contacts/Request.php — пример обработчика

Как фреймворк: Гибкость разработки

Полный контроль над кодом, архитектурой и расширениями для сложных проектов

wapps framework

Как CMS: Простота управления

Интуитивная админ-панель для редакторов контента без программирования

wapps cms

Как платформа: Готовые решения

Быстрый старт проектов с возможностью глубокой кастомизации под любые задачи

wapps platform
A
AJAX-запросы в Wepps Platform: Обновляем страницу без перезагрузки

А что если страница могла бы обновляться мгновенно, без перезагрузки? Пользователь отправляет форму — и тут же видит результат. Открывает попап — контент подгружается моментально. Добавляет товар в корзину — счётчик обновляется без единого мерцания экрана.

06.01.2026
G
CSS Grid в Wepps Platform: Система классов для двумерных макетов (строки + колонки)

CSS Grid Layout - мощный инструмент для создания двумерных макетов веб-страниц. В платформе Wepps реализована система утилитарных классов для работы с Grid, которая позволяет быстро создавать адаптивные сетки без написания дополнительного CSS. Система поддерживает до 6 колонок, адаптивные breakpoints и полный контроль над выравниванием и отступами.

31.12.2025
F
Flexbox в Wepps Platform: Руководство по построению интерфейсов

Flexbox.css - это готовая система классов для создания адаптивных макетов в Wepps Platform. Система предоставляет удобные классы для управления раскладкой без необходимости писать CSS вручную.

28.12.2025

☝️ Будьте в курсе: полезные статьи, новости проекта и практические советы по работе с платформой Wepps.