Pull to refresh

Фильтрация входных данных для PHP

Reading time5 min
Views1.6K
Хочу поделиться своими мыслями по поводу организации фильтрации входных данных (php).

Первая мысль — это разработка классов-обёрток String, Integer, Float, Array для стандартных типов. Данные классы предназначены для более удобной работы со строками, массивами и т.п., а так же для применения их в фильтрах входных данных.

Например:
function test ( TFloat $a, TInteger $b ) {
}

// вызов функции
test ( new TFloat($_POST['price']), new TInteger ($_POST['count']) );

Классы TFloat, TInteger в конструкторах выполняют некоторые операции приведения типов. TFloat например заменяет символ "," на ".", TFloat и TInteger так же удаляют все нецифровые символы (TFloat оставляет е+-).

Но одними «базовыми» классами обойтись сложно, так как в разных случаях на один и тот же тип TInteger могут накладываться дополнительные ограничения — например «минимум(0)», «диапазон(2,10)», «максимум(5)». Для TString — «минимальная длина(5)», «regexp(/.../)» и т.д.

Поэтому второй мыслью стали дополнительные функции-фильтры для каждого из базовых типов.

Например:
TString:
- min # минимальная длина
- max # максимальная длина
- range # диапазон (min, max)
- match # соответствие регулярному выражению

Фильтр должен возвращать true|false, таким образом можно выстроить логику проверки. Используя фильтры так же можно конструировать собственные типы.

Например:
Login:
    TString:
        # обычные функции
        # используются для предварительной "чистки" данных
        - trim, toLowerCase
        # соответствие регулярному выражению
        # если значение не проходит проверку (знак !),
        # то срабатывает выражение после знака ?
        # error(some text) - сообщение об ошибке
        - ! match(/[a-z0-9_]/i) ? error(Логин должен состоять из символов a-z, 0-9, _)
 
Password:
    TString:
        # минимальная / максимальная длина
        - ! min(5) ? error(Пароль должен быть больше 5и символов)
        - ! match(/[a-z0-9_]/i) ? error(Пароль должен состоять из символов a-z, 0-9, _)
 
Email:
    TString:
        - trim, toLowerCase
        - ! match(/e-mail-regexp/) ? error(E-mail не корректен)

Далее в коде используются уже новые типы (классы должны генерироваться автоматически, на основе описанной выше конфигурации и подгружаться через механизм autoload):
<br/>function register( Login $login, Password $password, Password $confirm_password, Email $email ) {
<br/>}

Но в данном случае необходимы дополнительные проверки — например $password и $confirm_password должны быть идентичны.
Следовательно необходимы дополнительные описания уже для самой функции:
User: # имя модуля
    register: # метод
        params: # список параметров
            login:
                type: Login
                filters:
                    - empty ? error(Не указан логин)
                    # callback - способ описания более сложных проверок
                    # в данном случае вызывается метод класса, возвращающий true|false
                    - ! callback(User->isLoginUnique($login)) ? error(Логин занят, укажите другой)
 
            password:
                type: Password
                filters:
                    - empty ? error(Пароль не указан)
                    # eq делает проверку на равенство текущей переменной с аргументом
                    # post.confirm_password - переменная переданная методом POST, 
                    # get.confirm_password - через GET - /path?confirm_password=123
                    - ! eq(post.confirm_password) ? error(Поля "пароль" и "подтверждение пароля" не совпадают)
 
            confirm_password:
                type: Password
                filters:
                    - empty ? error(Подтверждение пароля не указанo)

Весь синтаксис конфигаруций — Yaml. Так же не считаю особенно удачным способ описания фильтров и т.п., но это и не так важно, интересны ваши мысли по написанному.

Конструктивные комментарии и критика приветствуются…
Tags:
Hubs:
Total votes 10: ↑5 and ↓50
Comments10

Articles