Оцените идеи валидации данных поступающих от пользователя.

Bermuda

Новичок
Оцените идеи валидации данных поступающих от пользователя.

Класс валидации данных

Есть метод класса
PHP:
getParamER($erName, $check, $escapar = true, $escaparhtml = true, $method = "BOTH")
$erName - имя параметра
$check - тип проверки
Доступные типы проверки (думаю из названия непонятно только FECHA - дата по испански)
NONE, INTEGER, NUMERIC, STRING, MINLENGTH, MAXLENGTH, GREATERTHAN, PRIMARYKEY, KEYWORD, TELEFONO, CP, FECHAб EMAIL, ARRAY, HTML, XML, LOGIN, PASSW, PAGINAWEB, CIF
$escapar - экранирует кавычки (учитывается magic_quotes)
$escaparhtml - удаляет html форматирование
$method - метод передачи параметра (POST/GET/BOTH)

Метод проверяет переменную с именем $erName согласно требуемому типу данных $check и методу передачи $method. Если переменная не соотетствует своему типу и методу передачи, то метод возвращает пустое значение.

Т. е. чтобы получить переменную $_POST["id"] (предполагается, что это индекс записи в базе данных, скажем, MySQL), нужно сделать

PHP:
$id = $this->pet->getParam("id", "PRIMARYKEY", true, true, "POST");
Недостаток: метод не возвращает причину почему параметр не прошел валидацию, то ли он был пустой, то ли передан неверным методом, то ли не соответствует типу данных, то ли после очистки html от данных ничего не осталось. В большинстве случаев данный недостаток некритичен. Просто можно говорить пользователю, что данные неверны, а уж почему -- не его дело.

Но хочется пойти дальше. Лично я не вижу никакой надобности в том, чтобы в коде указывать тип передаваемых данных. Тип передаваемых данных можно указывать прямо при передаче данных. Имя параметра можно конструировать следующим образом

типданных_имяпараметра

Например:
<input type="text" name="login_user">

В данном случае
login - тип данных
user - имя параметра

Таким образом можно можно фильтровать весь массив POST на предмет соответствия данных их типу. Отднако у пользователя остается возможность самому манипулировать этими данными используя фокус вроде этого
<input type="text" name="array_user[]">
и послать вместо ожидаемого имени пользователя массив. Для предотвращения таких фокусов можно подписывать параметры сдедующим образом
типданных_имяпараметра_подпись(типданных + имяпараметра + секретныйключ)

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

В итоге выйдет что-то похожее на
<input type="text" name="login_user_6be920966072470cb659cb74478888dd">
где
login - тип данных
user - имя параметра
6be920966072470cb659cb74478888dd - подпись

Идея всего этого не указывать в коде тип передаваемых данных, а передавать тип данных вместе с самими данными.

Имеет ли смысл подписывать данные? Использует ли кто-нибудь что-либо подобное? Есть какие-либо минусы у данного метода?
 

svetasmirnova

маленький монстрик
Есть:
1. Если применять на уже готовом проекте, придётся весь HTML переписывать.
2. Логика приложения выносится в html. Но в данном случае это неоднозначный минус: пользователь ведь должен знать что за данные вводить.

-~{}~ 03.11.05 13:59:

Минус №3: длина GET ограничена 256 символами.
 

chulim

Новичок
а в чем разница? либо тебе указывать тип в темплейте, либо в коде?
если я правильно понял
 

Bermuda

Новичок
chulim, разница в том, что в темплете можно также не указывать, а парсить автоматом при выводе формы, напрмер... Хотя это те же яйца, только вид сбоку :)

-~{}~ 03.11.05 12:38:

Автор оригинала: svetasmirnova
Минус №3: длина GET ограничена 256 символами.
Ну GET-ом обычно передается в среднем 3-5 параметров (разбитие на страницы, сортировка, id), так что это некритично.
 

ddurach

Новичок
Автор оригинала: svetasmirnova

Минус №3: длина GET ограничена 256 символами.
С каких пор?

Нет доки под рукой, но код:

PHP:
<?

$url = str_repeat("a[]=1&", 100);

echo "<a href='index.php?$url'>long url</a>";
phpinfo(32);

?>
чудестно работает
 

ForJest

- свежая кровь
Bermuda
В целом это довольно примитивный процедурный подход.
Что ты имеешь в итоге?
NONE, INTEGER, NUMERIC, STRING, MINLENGTH, MAXLENGTH, GREATERTHAN, PRIMARYKEY, KEYWORD, TELEFONO, CP, FECHAб EMAIL, ARRAY, HTML, XML, LOGIN, PASSW, PAGINAWEB, CIF
по сути - эти параметры должны являться отдельными классами, а значения параметров - типами классов.
---------------------
Таким образом можно легко создать конструкцию типа
$FormFields = array(
new Numeric('user'),
new Email('email'),
);
После чего просто и ясно обработать данные
PHP:
$DataSet = array();
foreach(array_keys($FormFields) as $key)
{
     $FormFields[$key]->set_post($_POST);
     $FormFields[$key]->set_get($_GET);
     $FormFields[$key]->set_cookie($_COOKIE);
     $DataSet[$FormFields[$key]->get_name()] = $FormFields[$key]->get_value();
}
Дизайн кода существенно упростится, появится возможность расширять и создавать новые типы данных для проверки.
По-моему схожий подход использован в PEAR::HTML::QuickForm
 

Bermuda

Новичок
ForJest, спасибо за идею. Однако на каждый чих писать класс думаю это сурово. Не помню точно кто, но вспоминается что какой-то из разработчиков PHP не рекомендовал использовать много инклюдов. Насколько я помню, при включении более 5-6 инклюдов начинает резко падать производительность. Лично я не проверял. Хотя идея красивая -- можно расширять каждый отдельный класс до посинения.
 

ForJest

- свежая кровь
Bermuda
Понимаешь - у тебя сейчас реализована функциональность этих классов в одном. Не обязательно, опять же держать каждый класс в отдельном файле - как сейчас тебе не мешает держать их синтаксически в разных классах :).
Просто один файл со "стандартными" классами и это снимет оверхед на инклюды.
А вообще Zend Optimizer снимает и этот оверхед тоже, так что принципиальной разности по кол-ву инклюдов нету.

-~{}~ 04.11.05 17:41:

И посмотри реализацию QuickForm - после объяснения мною концепта, думаю ты помёшь что там к чему и не будешь изобретать велосипед :)
 

Bermuda

Новичок
ForJest, спасибо дядя, идея мне все больше и больше нравится :)
 

Роберт

Аналитик
А действительно ведь вроде GET не должен передать больше 256 символов (сам специально пробывал - создал textarea и пытался через него передать 5 строчек русского текста в UTF8 - не вышло). Но пример который показал ddurach действительно работает (даже передать 300 параметров!)
 

[Gisma]

Новичок
NONE, INTEGER, NUMERIC, STRING, MINLENGTH, MAXLENGTH, GREATERTHAN, PRIMARYKEY, KEYWORD, TELEFONO, CP, FECHAб EMAIL, ARRAY, HTML, XML, LOGIN, PASSW, PAGINAWEB, CIF
действительно конечно классный методы серверной проверки но ведь понадобятся еще, так что вынести логику этих в расширения класса (другие файлы), далее не нужно выносить имена и типы на HTML это приводит к потере элементарной логики, ведь мы получается проверяем хтмл, который над подают, а не нужный нам html. Так что лучше тогда уж описать какой нить файл-конфиг, например в виде хеша, в самом пхп файле. Его написать и быстрее будет и мозги себе долбать потом читая и отлаживая свой html меньше будешь;)
 

ForJest

- свежая кровь
[Gisma]
Я ничего не понял из того то ты написал.
Приведи что ли поясняющие примеры. А то получается несколько предложений малосвязанного текста.
 

tf

крылья рулят
секретныйключ пользователю известен быть не может
В итоге выйдет что-то похожее на
<input type="text" name="login_user_6be920966072470cb659cb74478888dd">
почему известен не может если он передается пользователю

>>$id = $this->pet->getParam("id", "PRIMARYKEY", true, true, "POST");
Bermuda
лично я против такого смешивания php sql
как то он все вместе все делает
мое видение в разделении снчало все что нужно собрать обработать и затем только в базу другими методами пихать
 

svetasmirnova

маленький монстрик
tf
подписывать параметры сдедующим образом
типданных_имяпараметра_подпись(типданных + имяпараметра + секретныйключ)
В этом случае нельзя подменить тип параметра
 

Bermuda

Новичок
Автор оригинала: tf
почему известен не может если он передается пользователю
Где ты увидел, что ключ передается пользователю? Пользователю передается "составное" имя переменной которое содержит имя переменной, ожидаемый тип данных и подпись. Подпись гарантирует неизменность составного имени. Про подписи слышал, я надеюсь?

-~{}~ 14.11.05 17:08:

tf
И где ты усмотрел SQL вообще?
лично я против такого смешивания словарных слов и sql в словаре английского языка, а то как то он все вместе все делает :)
 

tf

крылья рулят
сории за ключ. довольно часто читаю по горизонтали - не туда смотрел
наверно я имел ввиду что твоему вредному пользователю мешает послать тебе login_user_6be920966072470cb659cb74478888dd[] и что от этого изменится если это будет login_user
данные все равно придется проверять в коде. почему ты против описания типов данных в коде?


Bermuda
>>И где ты усмотрел SQL вообще?
Т. е. чтобы получить переменную $_POST["id"] (предполагается, что это индекс записи в базе данных, скажем, MySQL), нужно сделать
$id = $this->pet->getParam("id", "PRIMARYKEY", true, true, "POST");
ну ты сам подумай
ты сам сказал что это индекс записи данных PRIMARYKEY. скажи что тебе это дает. ну есть у меня primarykey char(20) как тут твой метод проверит его валидность
 

Gas

может по одной?
tf

данные все равно придется проверять в коде. почему ты против описания типов данных в коде?
потому что теоритически их можно привести к нужному типу автоматически по их описанию в html, избавившись от ненужной работы.

ну есть у меня primarykey char(20) как тут твой метод проверит его валидность
для сокращения кода и уменьшения сложности, часто пишутся решения в которых изначально залаживаются какие-то ограничения, типа, база mysql, primary key - int и т.д. и оставляется возможность для расширения функциональности. Если сделать как предлагает, например ForJest, то ты можешь дописать свой класс MY_PRIMARYKEY.
 

Bermuda

Новичок
tf
наверно я имел ввиду что твоему вредному пользователю мешает послать тебе login_user_6be920966072470cb659cb74478888dd[] и что от этого изменится если это будет login_user
login - тип данных = имя пользователя
user - имя параметра = user
6be920966072470cb659cb74478888dd - подпись
Т. е. ожидаемый тип данных -- имя пользователя, а придет массив, а так как массив не является именем пользователя, то данные невалидны. Т. е. мне в коде проверки валидности данных не нужно будет указывать как рассматривать тип данных каждого параметра, описние этого типа будет содержаться в его имени. Но, как я уже сам поймал себя ранее, это лишь вынесение части функционала из логики приложения в логику представления, что никакого ощутимого прeимущества не дает.

ну есть у меня primarykey char(20) как тут твой метод проверит его валидность
Все верно, PRIMARYKEY в данном конкретном примере не имеет прямой связи с первичным ключом таблицы реляционной базы данных, но является подмножеством множества INT, что достаточно часто совпадает с типом первичного ключа в MySQL. Возможно, такое название не совсем корректно, чтобы тебе было спокойнее, в дальнейшем буду называть его MY_INT, однако суть вопроса была не в этом.
 

tf

крылья рулят
главное то для чего ты это делаеш
>> Лично я не вижу никакой надобности в том, чтобы в коде указывать тип передаваемых данных. Тип передаваемых данных можно указывать прямо при передаче данных.
>>Идея всего этого не указывать в коде тип передаваемых данных, а передавать тип данных вместе с самими данными.
крайне не согласен с передачей типов параметров во внейший мир. шифруй не шифруй я не согласен
затраты затраченные на взлом твоего метода должны быть больше стоимости твоих данных. но зачем давай лишний повод это проверять.
меня лично не устраивает и сколь было малый процент случая так как в моем понимае реальностей возможно все. и любой случай либо он есть либо его нет но он возможен т.е. случай =1 значит он может быть
надеюсь я правильно обяснил свою позицию
 
Сверху