You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

627 lines
19 KiB

<?php
// +---------------------------------------------------------------------------+
// | This file is part of the core package. |
// | Copyright (c) laiketui.com |
// | |
// | For the full copyright and license information, please view the LICENSE |
// | file that was distributed with this source code. You can also view the |
// | LICENSE file online at http://www.laiketui.com |
// +---------------------------------------------------------------------------+
/**
* ValidatorConfigHandler allows you to register validators with the system.
*
* @package laiketui
* @subpackage config
*
* @author ketter (ketter@laiketui.com)
* @since 3.0.0
*/
class ValidatorConfigHandler extends IniConfigHandler
{
// +-----------------------------------------------------------------------+
// | METHODS |
// +-----------------------------------------------------------------------+
/**
* Execute this configuration handler.
*
* @param string An absolute filesystem path to a configuration file.
*
* @return string Data to be written to a cache file.
*
* @throws <b>ConfigurationException</b> If a requested configuration file
* does not exist or is not readable.
* @throws <b>ParseException</b> If a requested configuration file is
* improperly formatted.
*
* @author ketter (ketter@laiketui.com)
* @since 3.0.0
*/
public function & execute ($config)
{
// set our required categories list and initialize our handler
$categories = array('required_categories' => array('methods', 'names'));
$this->initialize($categories);
// parse the ini
$ini = $this->parseIni($config);
// init our data, includes, methods, names and validators arrays
$data = array();
$includes = array();
$methods = array();
$names = array();
$validators = array();
// get a list of methods and their registered files/parameters
foreach ($ini['methods'] as $method => &$list)
{
$method = strtoupper($method);
if (!isset($methods[$method]))
{
// make sure that this method is GET or POST
if ($method != 'GET' && $method != 'POST')
{
// unsupported request method
$error = 'Configuration file "%s" specifies unsupported ' .
'request method "%s"';
$error = sprintf($error, $config, $method);
throw new ParseException($method);
}
// create our method
$methods[$method] = array();
}
if (trim($list) == '')
{
// we have an empty list of names
continue;
}
// load name list
$this->loadNames($config, $method, $methods, $names, $ini, $list);
}
// load attribute list
$this->loadAttributes($config, $methods, $names, $validators, $ini,
$list);
// generate GET file/parameter data
$data[] = "if (\$_SERVER['REQUEST_METHOD'] == 'GET')";
$data[] = "{";
$this->generateRegistration('GET', $data, $methods, $names,
$validators);
// generate POST file/parameter data
$data[] = "} else if (\$_SERVER['REQUEST_METHOD'] == 'POST')";
$data[] = "{";
$this->generateRegistration('POST', $data, $methods, $names,
$validators);
$data[] = "}";
// compile data
$retval = "<?php\n" .
"// auth-generated by ValidatorConfigHandler\n" .
"// date: %s\n%s\n%s\n?>";
$retval = sprintf($retval, date('m/d/Y H:i:s'),
implode("\n", $includes), implode("\n", $data));
return $retval;
}
// -------------------------------------------------------------------------
/**
* Generate raw cache data.
*
* @param string A request method.
* @param array The data array where our cache code will be appended.
* @param array An associative array of request method data.
* @param array An associative array of file/parameter data.
* @param array A validators array.
*
* @author ketter (ketter@laiketui.com)
* @since 3.0.0
*/
private function generateRegistration ($method, &$data, &$methods, &$names,
&$validators)
{
// setup validator array
$data[] = "\t\$validators = array();";
// determine which validators we need to create for this request method
foreach ($methods[$method] as $name)
{
if (preg_match('/^([a-z0-9\-_]+)\{([a-z0-9\s\-_]+)\}$/i', $name,
$match))
{
// this file/parameter has a parent
$subname = $match[2];
$parent = $match[1];
$valList =& $names[$parent][$subname]['validators'];
} else
{
// no parent
$valList =& $names[$name]['validators'];
}
if ($valList == null)
{
// no validator list for this file/parameter
continue;
}
foreach ($valList as &$valName)
{
if (isset($validators[$valName]) &&
!isset($validators[$valName][$method]))
{
// retrieve this validator's info
$validator =& $validators[$valName];
$tmp = "\t\$validators['%s'] = new %s();\n";
$tmp .= "\t\$validators['%s']->initialize(%s, %s);";
$data[] = sprintf($tmp, $valName, $validator['class'],
$valName, '$context',
$validator['parameters']);
// mark this validator as created for this request method
$validators[$valName][$method] = true;
}
}
}
foreach ($methods[$method] as $name)
{
if (preg_match('/^([a-z0-9\-_]+)\{([a-z0-9\s\-_]+)\}$/i', $name,
$match))
{
// this file/parameter has a parent
$subname = $match[2];
$parent = $match[1];
$name = $match[2];
$attributes =& $names[$parent][$subname];
} else
{
// no parent
$attributes =& $names[$name];
}
// register file/parameter
$tmp = "\t\$validatorManager->registerName('%s', %s, %s, %s, " .
"%s, %s);";
$data[] = sprintf($tmp, $name, $attributes['required'],
$attributes['required_msg'],
$attributes['parent'], $attributes['group'],
$attributes['file']);
// register validators for this file/parameter
foreach ($attributes['validators'] as &$validator)
{
$tmp = "\t\$validatorManager->registerValidator('%s', %s, " .
"%s);";
$data[] = sprintf($tmp, $name,
"\$validators['$validator']",
$attributes['parent']);
}
}
}
// -------------------------------------------------------------------------
/**
* Load the linear list of attributes from the [names] category.
*
* @param string The configuration file name (for exception usage).
* @param array An associative array of request method data.
* @param array An associative array of file/parameter names in which to
* store loaded information.
* @param array An associative array of validator data.
* @param array The loaded ini configuration that we'll use for
* verification purposes.
* @param string A comma delimited list of file/parameter names.
*
* @return void
*
* @author ketter (ketter@laiketui.com)
* @since 3.0.0
*/
private function loadAttributes (&$config, &$methods, &$names, &$validators,
&$ini, &$list)
{
foreach ($ini['names'] as $key => &$value)
{
// get the file or parameter name and the associated info
preg_match('/^(.*?)\.(.*?)$/', $key, $match);
if (count($match) != 3)
{
// can't parse current key
$error = 'Configuration file "%s" specifies invalid key "%s"';
$error = sprintf($error, $config, $key);
throw new ParseException($error);
}
$name = $match[1];
$attribute = $match[2];
// get a reference to the name entry
if (preg_match('/^([a-z0-9\-_]+)\{([a-z0-9\s\-_]+)\}$/i', $name,
$match))
{
// this name entry has a parent
$subname = $match[2];
$parent = $match[1];
if (!isset($names[$parent][$subname]))
{
// unknown parent or subname
$error = 'Configuration file "%s" specifies unregistered ' .
'parent "%s" or subname "%s"';
$error = sprintf($error, $config, $parent, $subname);
throw new ParseException($error);
}
$entry =& $names[$parent][$subname];
} else
{
// no parent
if (!isset($names[$name]))
{
// unknown name
$error = 'Configuration file "%s" specifies unregistered ' .
'name "%s"';
$error = sprintf($error, $config, $name);
throw new ParseException($error);
}
$entry =& $names[$name];
}
if ($attribute == 'validators')
{
// load validators for this file/parameter name
$this->loadValidators($config, $validators, $ini, $value,
$entry);
} else if ($attribute == 'type')
{
// name type
$lvalue = strtolower($value);
if ($lvalue == 'file')
{
$entry['file'] = 'true';
} else
{
$entry['file'] = 'false';
}
} else
{
// just a normal attribute
$entry[$attribute] = $this->literalize($value);
}
}
}
// -------------------------------------------------------------------------
/**
* Load all request methods and the file/parameter names that will be
* validated from the [methods] category.
*
* @param string The configuration file name (for exception usage).
* @param string A request method.
* @param array An associative array of request method data.
* @param array An associative array of file/parameter names in which to
* store loaded information.
* @param array The loaded ini configuration that we'll use for
* verification purposes.
* @param string A comma delimited list of file/parameter names.
*
* @return void
*
* @author ketter (ketter@laiketui.com)
* @since 3.0.0
*/
private function loadNames (&$config, &$method, &$methods, &$names, &$ini,
&$list)
{
// explode the list of names
$array = explode(',', $list);
// loop through the names
foreach ($array as $name)
{
$name = trim($name);
// make sure we have the required status of this file or parameter
if (!isset($ini['names'][$name . '.' . 'required']))
{
// missing 'required' attribute
$error = 'Configuration file "%s" specifies file or ' .
'parameter "%s", but it is missing the "required" ' .
'attribute';
$error = sprintf($error, $config, $name);
throw new ParseException($error);
}
// determine parent status
if (preg_match('/^([a-z0-9\-_]+)\{([a-z0-9\s\-_]+)\}$/i', $name,
$match))
{
// this name has a parent
$subname = $match[2];
$parent = $match[1];
if (!isset($names[$parent]) ||
!isset($names[$parent][$name]))
{
if (!isset($names[$parent]))
{
// create our parent
$names[$parent] = array('_is_parent' => true);
}
// create our new name entry
$entry = array();
$entry['file'] = 'false';
$entry['group'] = 'null';
$entry['parent'] = "'$parent'";
$entry['required'] = 'true';
$entry['required_msg'] = "'Required'";
$entry['validators'] = array();
// add our name entry
$names[$parent][$subname] = $entry;
}
} else if (strpos($name, '{') != false ||
strpos($name, '}') != false)
{
// name contains an invalid character
// this is most likely a typo where the user forgot to add a
// brace
$error = 'Configuration file "%s" specifies method "%s" ' .
'with invalid file/parameter name "%s"';
$error = sprintf($error, $config, $method, $name);
throw new ParseException($error);
} else
{
// no parent
if (!isset($names[$name]))
{
// create our new name entry
$entry = array();
$entry['file'] = 'false';
$entry['group'] = 'null';
$entry['parent'] = 'null';
$entry['required'] = 'true';
$entry['required_msg'] = "'Required'";
$entry['type'] = 'parameter';
$entry['validators'] = array();
// add our name entry
$names[$name] = $entry;
}
}
// add this name to the current request method
$methods[$method][] = $name;
}
}
// -------------------------------------------------------------------------
/**
* Load a list of validators.
*
* @param string The configuration file name (for exception usage).
* @param array An associative array of validator data.
* @param array The loaded ini configuration that we'll use for
* verification purposes.
* @param string A comma delimited list of validator names.
* @param array A file/parameter name entry.
*
* @return void
*
* @author ketter (ketter@laiketui.com)
* @since 3.0.0
*/
private function loadValidators (&$config, &$validators, &$ini, &$list,
&$entry)
{
// create our empty entry validator array
$entry['validators'] = array();
if (trim($list) == '')
{
// skip the empty list
return;
}
// get our validator array
$array = explode(',', $list);
foreach ($array as &$validator)
{
$validator = trim($validator);
// add this validator name to our entry
$entry['validators'][] =& $validator;
// make sure the specified validator exists
if (!isset($ini[$validator]))
{
// validator hasn't been registered
$error = 'Configuration file "%s" specifies unregistered ' .
'validator "%s"';
$error = sprintf($error, $config, $validator);
throw new ParseException($error);
}
// has it already been registered?
if (isset($validators[$validator]))
{
continue;
}
if (!isset($ini[$validator]['class']))
{
// missing class key
$error = 'Configuration file "%s" specifies category ' .
'"%s" with missing class key';
$error = sprintf($error, $config, $validator);
throw new ParseException($error);
}
// create our validator
$validators[$validator] = array();
$validators[$validator]['class'] = $ini[$validator]['class'];
$validators[$validator]['file'] = null;
$validators[$validator]['parameters'] = null;
if (isset($ini[$validator]['file']))
{
// we have a file for this validator
$file = $ini[$validator]['file'];
// keyword replacement
$file = $this->replaceConstants($file);
$file = $this->replacePath($file);
if (!is_readable($file))
{
// file doesn't exist
$error = 'Configuration file "%s" specifies ' .
'category "%s" with nonexistent or unreadable ' .
'file "%s"';
$error = sprintf($error, $config, $validator, $file);
throw new ParseException($error);
}
$validators[$validator]['file'] = $file;
}
// parse parameters
$parameters = ParameterParser::parse($ini[$validator]);
$validators[$validator]['parameters'] = $parameters;
}
}
}
?>