Валидатор массивов

Beavis

Banned
Валидатор массивов

Вот для валидации XML'я придумали schema'ы, DTD и пр.
Может кто-нибудь реализовывал или видел что-нибудь похожее для массивов в PHP?

Что-нибудь типа
PHP:
$definition = array(
   "id" => array("type" => "int", "min_value" => 1, "max_value" => 999),
   "name" => array("type" => "string", "min_len" => 1, "max_len" => 255, "unique" => true,
);
$arr = array(
   array("id" => 2, "name" => "xxx"),
   array("id" => 3, "name" => "yyy"),
   array("id" => 4, "name" => "zzz"),
);
$result = validate_array($arr, $definition);
Я похожее видел в http://ru2.php.net/manual/en/function.filter-var-array.php но там очень мало возможностей, даже тип толком не проверить, а что самое главное, позволяет работать только с плоскими массивами..
А вот как лучше сделать для сложных массивов (которые состоят не только из скалярных значений, а ещё и из массивов, а те в свою очередь.............) я пока не могу придумать
 

fixxxer

К.О.
Партнер клуба
цепочка валидаторов

ручками, ручками :) один раз сделать и радоваться
 

crocodile2u

http://vbolshov.org.ru
В filter_* очень много возможностей, в частности, валидация при помощи коллбэков. Ту конкретную задачу, что ты описал - можно решить запросто.
 

Beavis

Banned
crocodile2u
Т.е. даже для того чтобы длину строки проверить, надо колбек писать?

А если массив будет такой?
PHP:
$arr = array(
  array(
    "k1" => "v1",
    "k2" => "v2",
    "k3" => array(
        "k4" => "v4"
     )
  ),
  "k5" => array(
      "k6" => "v6"
   )
);
Так что filter_* штука хорошая, не спорю, но годится она только для проверки данных из запроса/куков и т.д., где массивы плоские
 

Dreammaker

***=Ф=***
Наткнулся сегодня на вот такую штуку (выборки из массивов с помощью SQL-подобных запросов).

http://www.codeplex.com/PHPLinq/Wiki/View.aspx?title=Examples&referringTitle=Features

Это не совсем то, что нужно, но может получиться приспособить :) И второе не проверял как оно с многомерными массивами работает.
 

crocodile2u

http://vbolshov.org.ru
Beavis
не буду разводить флейм, лучше скажу по теме (правда, не знаю, насколько понравится такой вариант): можно массив сериализовать в ХМЛ и валидировать с помощь XMLSchema или RelaxNG. Задача, возможно, не такая уж простая (ну и вообще не знаю пока, насколько такой способ имеет право на жизнь) - зато механизм валидации (оговорюсь - это я про XMLSchema, с RelaxNG не работал):
а) стандартизован Первосвященниками W3C
б) имеет замечательные возможности вроде ComplexType'ов.
 

Beavis

Banned
Автор оригинала: crocodile2u
Beavis
не буду разводить флейм, лучше скажу по теме (правда, не знаю, насколько понравится такой вариант): можно массив сериализовать в ХМЛ и валидировать с помощь XMLSchema или RelaxNG. Задача, возможно, не такая уж простая (ну и вообще не знаю пока, насколько такой способ имеет право на жизнь) - зато механизм валидации (оговорюсь - это я про XMLSchema, с RelaxNG не работал):
а) стандартизован Первосвященниками W3C
б) имеет замечательные возможности вроде ComplexType'ов.
Ну это слишком накладно=) Вот я и хотел найти что-нибудь типа XSD только для массивов. Видимо придется писать самому, только надо придумать как это всё в декларативной форме описать.
 

crocodile2u

http://vbolshov.org.ru
А ты попробуй, попробуй... Есть сомнения в том, что у тебя получится намного проще и удобнее, чем используя filter_*
 

Beavis

Banned
crocodile2u
Как мне провалидировать многоуровневый массив с помощью filter_* ?
 

Beavis

Banned
PHP:
$data = array(
    'product_id'    => 'libgd<script>',
    'component'     => '10',
    'versions'      => '2.0.33',
    'testscalar'    => array('2', '23', '10', '12'),
    'testarray'     => '2',
);
Это не многоуровневый, а двухуровневый.

Да и двухуровневый толком нельзя проверить, например такой:
PHP:
$data = array(
    'product_id'    => 'libgd<script>',
    'component'     => '10',
    'versions'      => '2.0.33',
    'testscalar'    => array(10, false, "somestring", array(1, 2, "3")),
    'testarray'     => '2',
);
 

AmdY

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

Beavis

Banned
AmdY
Хорошо, пусть двухуровневый будет многоуровневым. Но дело в том, что нельзя с помощью filter полноценно проверить даже двухуровневый массив (callback'и не в счет, т.к. можно и вообще без filter'а всё проверить с помощью функций).

Я, к сожалению, пока не могу придумать как нормально написать $definition для валидации сложного массива. И как оттуда вытаскивать описания ошибок.
 

kode

never knows best
PHP:
function findPath($index,$parents,$filter){
	$return = array($index);
	foreach (array_reverse($parents) as $parent){
		$idx = $parent."=>".end($return);
		if(isset($filter[$idx])){
			return $filter[$idx];
		}
	}
	return null;
}

function validate_array($array,$filters,$parent=array()){
	$return = $array;
	foreach ($return as $key=>&$value){
		if(is_array($value)){
			$my_parents = $parent;
			array_push($my_parents,$key);
			$value = validate_array($value,$filters,$my_parents);
		}else{
			$newval = "";
			$filter = findPath($key,$parent,$filters);
			if($filter && ($newval = filter_var($value,$filter)) !== false){
				$value = $newval;
			}
		}
	}
	return $return;
}
Немного тут за 5 минут набросал, не тестил, так что не судите строго :3 Proof of Concept как говорится

-~{}~ 06.08.08 13:56:

смысл в том что в $filters хранятся значиения типа

array(
'user=>login'=>array(...),
'logs=>05.03.21=>10=>message'=>array(...),
);

в идеале неплохо бы приделать систему шаблонов, те
'logs=>05.03.21=>:num=>message'
или
'logs=>05.03.21=>*=>message'
или
'users=>:string=>lastlogin'
или
'users=>/^[a-Z0-9]$/=>regdate'
и.т.п
 
Сверху