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
627 lines
19 KiB
2 years ago
|
<?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;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
?>
|