home *** CD-ROM | disk | FTP | other *** search
- <?php
- /* vim: set noai expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
- /**
- * System_Daemon turns PHP-CLI scripts into daemons.
- *
- * PHP version 5
- *
- * @category System
- * @package System_Daemon
- * @author Kevin van Zonneveld <kevin@vanzonneveld.net>
- * @copyright 2008 Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD Licence
- * @version SVN: Release: $Id$
- * @link http://trac.plutonia.nl/projects/system_daemon
- */
-
- /**
- * Mechanism for validating, getting and setting a predefined set of options.
- *
- * @category System
- * @package System_Daemon
- * @author Kevin van Zonneveld <kevin@vanzonneveld.net>
- * @copyright 2008 Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD Licence
- * @version SVN: Release: $Id$
- * @link http://trac.plutonia.nl/projects/system_daemon
- *
- */
- class System_Daemon_Options
- {
- /**
- * Keep track of active state for all Options
- *
- * @var array
- */
- private $_options = array();
-
- /**
- * Definitions for all Options
- *
- * @var array
- */
- private $_definitions = array();
-
- /**
- * Wether all the options have been initialized
- *
- * @var boolean
- */
- private $_isInitialized = false;
-
- /**
- * Holds errors
- *
- * @var array
- */
- public $errors = array();
-
-
- /**
- * Constructor
- *
- * @param array $definitions The predefined option definitions
- */
- public function __construct($definitions)
- {
- if (!is_array($definitions) || !count($definitions)) {
- return false;
- }
-
- $this->_definitions = $definitions;
- }
-
- /**
- * Retrieves any option found in $_definitions
- *
- * @param string $name Name of the Option
- *
- * @return boolean
- */
- public function getOption($name)
- {
- if (!isset($this->_options[$name])) {
- return null;
- }
- return $this->_options[$name];
- }//end getOption()
-
- /**
- * Gets an array of options found in $_definitions
- *
- * @return array
- */
- public function getOptions()
- {
- return $this->_options;
- }//end getOptions()
-
- /**
- * Sets any option found in $_definitions
- *
- * @param string $name Name of the Option
- * @param mixed $value Value of the Option
- *
- * @return boolean
- */
- public function setOption($name, $value)
- {
- // Not validated?
- if (!$this->_validate($name, $value, $reason)) {
- // Default not used or failed as well!
- $this->errors[] = "Option ".$name." invalid: ".$reason;
- return false;
- }
-
- $this->_options[$name] = $value;
- }//end setOption()
-
- /**
- * Sets an array of options found in $_definitions
- *
- * @param array $use_options Array with Options
- *
- * @return boolean
- */
- public function setOptions($use_options)
- {
- $success = true;
- foreach ($use_options as $name=>$value) {
- if (!$this->setOption($name, $value)) {
- $success = false;
- }
- }
- return $success;
- }//end setOptions()
-
- /**
- * Wether options are initialized
- *
- * @return boolean
- */
- public function isInitialized()
- {
- return $this->_isInitialized;
- }//end isInitialized()
-
- /**
- * Checks if all the required options are set & met.
- * Initializes, sanitizes & defaults unset variables
- *
- * @param boolean $premature Whether to do a premature option init
- *
- * @return mixed integer or boolean
- */
- public function init($premature=false)
- {
- // If already initialized, skip
- if (!$premature && $this->isInitialized()) {
- return true;
- }
-
- $options_met = 0;
-
- foreach ($this->_definitions as $name=>$definition) {
- // Skip non-required options
- if (!isset($definition["required"])
- || $definition["required"] !== true ) {
- continue;
- }
-
- // Required options remain
- if (!isset($this->_options[$name])) {
- if (!$this->_setDefault($name) && !$premature) {
- $this->errors[] = "Required option: ".$name.
- " not set. No default value available either.";
- return false;
- }
- }
-
- $options_met++;
- }
-
- if (!$premature) {
- $this->_isInitialized = true;
- }
-
- return $options_met;
-
- }//end init()
-
-
-
- /**
- * Validates any option found in $_definitions
- *
- * @param string $name Name of the Option
- * @param mixed $value Value of the Option
- * @param string &$reason Why something does not validate
- *
- * @return boolean
- */
- private function _validate($name, $value, &$reason="")
- {
- $reason = false;
-
- if (!$reason && !isset($this->_definitions[$name])) {
- $reason = "Option ".$name." not found in definitions";
- }
-
- $definition = $this->_definitions[$name];
-
- if (!$reason && !isset($definition["type"])) {
- $reason = "Option ".$name.":type not found in definitions";
- }
-
- // Compile array of allowd main & subtypes
- $_allowedTypes = $this->_allowedTypes($definition["type"]);
-
- // Loop over main & subtypes to detect matching format
- if (!$reason) {
- $type_valid = false;
- foreach ($_allowedTypes as $type_a=>$sub_types) {
- foreach ($sub_types as $type_b) {
-
- // Determine range based on subtype
- // Range is used to contain an integer or strlen
- // between min-max
- $parts = explode("-", $type_b);
- $from = $to = false;
- if (count($parts) == 2 ) {
- $from = $parts[0];
- $to = $parts[1];
- $type_b = "range";
- }
-
- switch ($type_a) {
- case "boolean":
- $type_valid = is_bool($value);
- break;
- case "object":
- $type_valid = is_object($value) || is_resource($value);
- break;
- case "string":
- switch ($type_b) {
- case "email":
- $exp = "^[a-z0-9]+([._-][a-z0-9]+)*@([a-z0-9]+";
- $exp .= "([._-][a-z0-9]+))+$";
- if (eregi($exp, $value)) {
- $type_valid = true;
- }
- break;
- case "unix":
- if ($this->strIsUnix($value)) {
- $type_valid = true;
- }
- break;
- case "existing_dirpath":
- if (is_dir($value)) {
- $type_valid = true;
- }
- break;
- case "existing_filepath":
- if (is_file($value)) {
- $type_valid = true;
- }
- break;
- case "creatable_filepath":
- if (is_dir(dirname($value))
- && is_writable(dirname($value))) {
- $type_valid = true;
- }
- break;
- case "normal":
- default:
- // String?
- if (!is_resource($value) && !is_array($value)
- && !is_object($value)) {
- // Range?
- if ($from === false && $to === false) {
- $type_valid = true;
- } else {
- // Enfore range as well
- if (strlen($value) >= $from
- && strlen($value) <= $to) {
- $type_valid = true;
- }
- }
- }
- break;
- }
- break;
- case "number":
- switch ($type_b) {
- default:
- case "normal":
- // Numeric?
- if (is_numeric($value)) {
- // Range ?
- if ($from === false && $to === false) {
- $type_valid = true;
- } else {
- // Enfore range as well
- if ($value >= $from && $value <= $to) {
- $type_valid = true;
- }
- }
- }
- break;
- }
- break;
- default:
- $this->errors[] = "Type ".
- $type_a." not defined";
- break;
- }
- }
- }
- }
-
- if (!$type_valid) {
- $reason = "Option ".$name." does not match type: ".
- $definition["type"]."";
- }
-
- if ($reason !== false) {
- $this->errors[] = $reason;
- return false;
- }
-
- return true;
- }//end _validate()
-
- /**
- * Sets any option found in $_definitions to its default value
- *
- * @param string $name Name of the Option
- *
- * @return boolean
- */
- private function _setDefault($name)
- {
- if (!isset($this->_definitions[$name])) {
- return false;
- }
- $definition = $this->_definitions[$name];
-
- if (!isset($definition["type"])) {
- return false;
- }
- if (!isset($definition["default"])) {
- return false;
- }
-
- // Compile array of allowd main & subtypes
- $_allowedTypes = $this->_allowedTypes($definition["type"]);
-
- $type = $definition["type"];
- $value = $definition["default"];
-
- if (isset($_allowedTypes["string"]) && !is_bool($value)) {
- // Replace variables
- $value = preg_replace_callback('/\{([^\{\}]+)\}/is',
- array("self", "_replaceVars"), $value);
-
- // Replace functions
- $value = preg_replace_callback('/\@([\w_]+)\(([^\)]+)\)/is',
- array("self", "_replaceFuncs"), $value);
- }
-
- $this->_options[$name] = $value;
- return true;
- }//end _setDefault()
-
- /**
- * Callback function to replace variables in defaults
- *
- * @param array $matches Matched functions
- *
- * @return string
- */
- private function _replaceVars($matches)
- {
- // Init
- $allowedVars = array(
- "SERVER.SCRIPT_NAME",
- "OPTIONS.*"
- );
- $filterVars = array(
- "SERVER.SCRIPT_NAME"=>array("realpath")
- );
-
- $fullmatch = array_shift($matches);
- $fullvar = array_shift($matches);
- $parts = explode(".", $fullvar);
- list($source, $var) = $parts;
- $var_use = false;
- $var_key = $source.".".$var;
-
- // Allowed
- if (!in_array($var_key, $allowedVars)
- && !in_array($source.".*", $allowedVars)) {
- return "FORBIDDEN_VAR_".$var_key;
- }
-
- // Mapping of textual sources to real sources
- if ($source == "SERVER") {
- $source_use = &$_SERVER;
- } elseif ($source == "OPTIONS") {
- $source_use = &$this->_options;
- } else {
- $source_use = false;
- }
-
- // Exists?
- if ($source_use === false) {
- return "UNUSABLE_VARSOURCE_".$source;
- }
- if (!isset($source_use[$var])) {
- return "NONEXISTING_VAR_".$var_key;
- }
-
- $var_use = $source_use[$var];
-
- // Filtering
- if (isset($filterVars[$var_key]) && is_array($filterVars[$var_key])) {
- foreach ($filterVars[$var_key] as $filter_function) {
- if (!function_exists($filter_function)) {
- return "NONEXISTING_FILTER_".$filter_function;
- }
- $var_use = call_user_func($filter_function, $var_use);
- }
- }
-
- return $var_use;
- }//end _replaceVars()
-
- /**
- * Callback function to replace function calls in defaults
- *
- * @param array $matches Matched functions
- *
- * @return string
- */
- private function _replaceFuncs($matches)
- {
- $allowedFunctions = array("basename", "dirname");
-
- $fullmatch = array_shift($matches);
- $function = array_shift($matches);
- $arguments = $matches;
-
- if (!in_array($function, $allowedFunctions)) {
- return "FORBIDDEN_FUNCTION_".$function;
- }
-
- if (!function_exists($function)) {
- return "NONEXISTING_FUNCTION_".$function;
- }
-
- return call_user_func_array($function, $arguments);
- }//end _replaceFuncs()
-
- /**
- * Compile array of allowed types
- *
- * @param string $str String that contains allowed type information
- *
- * @return array
- */
- private function _allowedTypes($str)
- {
- $allowed_types = array();
- $raw_types = explode("|", $str);
- foreach ($raw_types as $raw_type) {
- $raw_subtypes = explode("/", $raw_type);
- $type_a = array_shift($raw_subtypes);
- if (!count($raw_subtypes)) {
- $raw_subtypes = array("normal");
- }
- $allowed_types[$type_a] = $raw_subtypes;
- }
- return $allowed_types;
- }
-
-
-
- /**
- * Check if a string has a unix proof format (stripped spaces,
- * special chars, etc)
- *
- * @param string $str What string to test for unix compliance
- *
- * @return boolean
- */
- protected function strIsUnix( $str )
- {
- return preg_match('/^[a-z0-9_]+$/', $str);
- }//end strIsUnix()
-
- /**
- * Convert a string to a unix proof format (strip spaces,
- * special chars, etc)
- *
- * @param string $str What string to make unix compliant
- *
- * @return string
- */
- protected function strToUnix( $str )
- {
- return preg_replace('/[^0-9a-z_]/', '', strtolower($str));
- }//end strToUnix()
-
- }//end class
- ?>