Хочу поделиться своими мыслями по поводу организации фильтрации входных данных (php).
Первая мысль — это разработка классов-обёрток String, Integer, Float, Array для стандартных типов. Данные классы предназначены для более удобной работы со строками, массивами и т.п., а так же для применения их в фильтрах входных данных.
Например:
Классы TFloat, TInteger в конструкторах выполняют некоторые операции приведения типов. TFloat например заменяет символ "," на ".", TFloat и TInteger так же удаляют все нецифровые символы (TFloat оставляет е+-).
Но одними «базовыми» классами обойтись сложно, так как в разных случаях на один и тот же тип TInteger могут накладываться дополнительные ограничения — например «минимум(0)», «диапазон(2,10)», «максимум(5)». Для TString — «минимальная длина(5)», «regexp(/.../)» и т.д.
Поэтому второй мыслью стали дополнительные функции-фильтры для каждого из базовых типов.
Например:
Фильтр должен возвращать true|false, таким образом можно выстроить логику проверки. Используя фильтры так же можно конструировать собственные типы.
Например:
Далее в коде используются уже новые типы (классы должны генерироваться автоматически, на основе описанной выше конфигурации и подгружаться через механизм autoload):
Но в данном случае необходимы дополнительные проверки — например $password и $confirm_password должны быть идентичны.
Следовательно необходимы дополнительные описания уже для самой функции:
Весь синтаксис конфигаруций — Yaml. Так же не считаю особенно удачным способ описания фильтров и т.п., но это и не так важно, интересны ваши мысли по написанному.
Конструктивные комментарии и критика приветствуются…
Первая мысль — это разработка классов-обёрток 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. Так же не считаю особенно удачным способ описания фильтров и т.п., но это и не так важно, интересны ваши мысли по написанному.
Конструктивные комментарии и критика приветствуются…