Location: PHPKode > scripts > DbProxy > dbproxy/assets/ParamsProxy.php
<?php
    /**
    * "Takes an XML file as input, parses it and sets parsed values as field values for a given class
    * instance."
    * @author: Claudius Tiberiu Iacob <hide@address.com>
    * @license: Creative Commons Attribution Share Alike - Claudius Tiberiu Iacob 2009
    */
    class ParamsProxy {

        const ILLEGAL_ROOT_ELEMENT = "ILLEGAL_ROOT_ELEMENT";
        const FOREIGN_CONFIG_FILE = "FOREIGN_CONFIG_FILE";
        const EMPTY_ROOT_ELEMENT = "EMPTY_ROOT_ELEMENT";
        const ILLEGAL_PARAM_ELEMENT = "ILLEGAL_PARAM_ELEMENT";
        const EMPTY_PARAM_ELEMENT = "EMPTY_PARAM_ELEMENT";
        const ILLEGAL_PROPERTY = "ILLEGAL_PROPERTY";
        const TOO_FEW_PROPERTIES = "TOO_FEW_PROPERTIES";
        const TOO_MANY_PROPERTIES = "TOO_MANY_PROPERTIES";
        const INVALID_PROPERTY_NAME = "INVALID_PROPERTY_NAME";
        const INVALID_PROPERTY_VALUE = "INVALID_PROPERTY_VALUE";
        const ILLEGAL_ITEM_ELEMENT = "ILLEGAL_ITEM_ELEMENT";
        const TOO_MANY_ITEM_ATTRIBUTES = "TOO_MANY_ITEM_ATTRIBUTES";
        const ILLEGAL_ITEM_ELEMENT_ATTRIBUTE_NAME = "ILLEGAL_ITEM_ELEMENT_ATTRIBUTE_NAME";
        const ILLEGAL_ITEM_ELEMENT_ATTRIBUTE_VALUE = "ILLEGAL_ITEM_ELEMENT_ATTRIBUTE_VALUE";
        const EMPTY_ITEM_ELEMENT = "EMPTY_ITEM_ELEMENT";
        const ILLEGAL_STRING_FOR_BOOLEAN_DEFINITION = "ILLEGAL_STRING_FOR_BOOLEAN_DEFINITION";
        const ILLEGAL_STRING_FOR_NUMBER_DEFINITION = "ILLEGAL_STRING_FOR_NUMBER_DEFINITION";
        const INVALID_CONFIG_PATH = "INVALID_CONFIG_PATH";
        const NOT_ABSOLUTE_CONFIG_PATH = "NOT_ABSOLUTE_CONFIG_PATH";
        const CONFIG_PATH_UNDER_DOC_ROOT = "CONFIG_PATH_UNDER_DOC_ROOT";
        const CONFIG_PATH_UNDER_INCLUDES_PATH = "CONFIG_PATH_UNDER_INCLUDES_PATH";
        const MISSING_CONFIG_FILE = "MISSING_CONFIG_FILE";
        const INVALID_CONFIG_FILE = "INVALID_CONFIG_FILE";
        const MISSING_REQUIRED_NAME = "MISSING_REQUIRED_NAME";
        const MISSING_REQUIRED_VALUE = "MISSING_REQUIRED_VALUE";

        protected $configFolderPath = null;

        private $ownClassName = "ParamsProxy";
        private $ownConfigFile = "ParamsProxy_config.xml";
        private $configFolderParamName = "configurationFolder";
        private $clientConfigFileName = "config.xml";
        private $params = array ();
        private $isInitialized = false;

        private $rootElementName = "config";
        private $rootElementType = 1;
        private $rootBindAttributeName = "for";
        private $paramElementType = 1;
        private $paramElementName = "param";
        private $propertyElementType = 1;
        private $propertyElementName_name = "name";
        private $propertyElementName_type = "type";
        private $propertyElementName_value = "value";
        private $propertyElementValue_string = "string";
        private $propertyElementValue_number = "number";
        private $propertyElementValue_boolean = "boolean";
        private $propertyElementValue_array = "array";
        private $propertyElementValue_null = "null";
        private $propertyElementValue_auto = "auto";
        private $propertyElementName_item = "item";
        private $attributeName_key = "key";
        private $attributeName_type = "type";
        private $attributeValue_string = "string";
        private $attributeValue_number = "number";
        private $attributeValue_boolean = "boolean";
        private $attributeValue_null = "null";
        private $attributeValue_auto = "auto";

        private static $instance = null;

        public static function getInstance() {
            if (!self::$instance instanceof self) {
              self::$instance = new self();
            }
            return self::$instance;
        }

        public function configure($instance) {
            $this->doConfigure ($instance);
        }

        protected function __construct () {
            $this->provideDocumentRoot ();
            $ownConfigString = $this->getFileContent ($this->ownConfigFile);
            $ownConfigData =& $this->parseXML ($ownConfigString);
            $this->params =& $this->getParams ($ownConfigData);
            $this->configFolderPath = $this->params [$this->configFolderParamName];
            $this->configFolderPath = $this->proofConfigFolderPath ($this->configFolderPath);
            $this->isInitialized = true;
        }

        private function __clone () {
        }

        private function __wakeup() {
        }

        private function doConfigure ($instance) {
            if ($this->isInitialized) {
                $this->clientClsName = $this->getClassName($instance);
                $clientConfFile = $this->configFolderPath . "/" . $this->clientClsName . "/" .
                	$this->getConfigFileName();
                $clientConfStr = $this->getFileContent ($clientConfFile);
                $clientConfData =& $this->parseXML ($clientConfStr);
                $clientParams =& $this->getParams ($clientConfData);
                $this->applyParams($instance, $clientParams);
            }
        }

        private function getClassName ($instance) {
            $ret = array ();
            $name = get_class($instance);
            preg_match('/\w+$/', $name, $ret);
            return $ret[0];
        }

        protected function getConfigFileName () {
            return $this->clientConfigFileName;
        }

        protected function applyParams ($targetInstance, $params) {
            foreach ($params as $name => $value) {
                $setterName = "set" . ucwords($name);
                $targetInstance->$setterName($value);
            }
        }

        private function provideDocumentRoot () {
            if (!isset ($_SERVER['DOCUMENT_ROOT'])) {
                if (isset ($_SERVER['SCRIPT_FILENAME'])) {
                    $_SERVER['DOCUMENT_ROOT'] = str_replace ( '\\', '/',
                        substr ($_SERVER['SCRIPT_FILENAME'], 0, 0 - strlen ($_SERVER['PHP_SELF'])));
                }
            }
            if (!isset ($_SERVER['DOCUMENT_ROOT'])) {
                if (isset($_SERVER['PATH_TRANSLATED'])) {
                    $_SERVER['DOCUMENT_ROOT'] = str_replace ( '\\', '/',
                        substr (str_replace ('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0,
                        0 - strlen ($_SERVER['PHP_SELF'])));
                }
            }
        }

        private function getFileContent ($filePath) {
            if (!$this->isInitialized) {
                $current = __FILE__;
                $filePath = dirname($current) . DIRECTORY_SEPARATOR . $filePath;
            }
            $ret = @file_get_contents($filePath);
            if ($ret === false) {
                trigger_error(ParamsProxy::MISSING_CONFIG_FILE, E_USER_ERROR);
            }
            return $ret;
        }

        private function getParams ($data) {
           $ret = array ();
           $rootNode =& $this->parseRootNode ($data);
           if (!$rootNode->hasChildNodes()) {
                trigger_error(ParamsProxy::EMPTY_ROOT_ELEMENT, E_USER_ERROR);
           }
           $count = $rootNode->childCount;
           if (!$this->isInitialized) {
               if ($count > 1) {
                   trigger_error(INVALID_CONFIG_FILE, E_USER_ERROR);
               }
           }
           $children =& $rootNode->childNodes;
           for ($i = 0; $i < $count; $i++) {
                $child =& $children[$i];
                if ($child->nodeType == $this->paramElementType) {
                    if ($child->nodeName !== $this->paramElementName) {
                        trigger_error(ParamsProxy::ILLEGAL_PARAM_ELEMENT, E_USER_ERROR);
                    }
                    $result = &$this->parseParamNode($child);
                    if (!$this->isInitialized) {
                        if($result[$this->propertyElementName_name] !==
                            $this->configFolderParamName) {
                            trigger_error(INVALID_CONFIG_FILE, E_USER_ERROR);
                        }
                    }
                    $ret[$result[$this->propertyElementName_name]] = &$result[$this->propertyElementName_value];
                }
           }
           return $ret;
        }

        private function proofConfigFolderPath ($path) {
            $realPath = realpath ($path);
            if ($realPath === false) {
                trigger_error(ParamsProxy::INVALID_CONFIG_PATH, E_USER_ERROR);
            }
            $path = preg_replace('/\x5c{1,}/', '/', $path);
            $path = preg_replace('/\x2f$/', '', $path);
            $realPath = preg_replace('/\x5c{1,}/', '/', $realPath);
            $realPath = preg_replace('/\x2f$/', '', $realPath);
            if ($path !== $realPath) {
                trigger_error(ParamsProxy::NOT_ABSOLUTE_CONFIG_PATH, E_USER_ERROR);
            }
            $docRoot = $_SERVER['DOCUMENT_ROOT'];
            if (strpos($path, $docRoot) === 0) {
                trigger_error(ParamsProxy::CONFIG_PATH_UNDER_DOC_ROOT, E_USER_ERROR);
            }
            $includePaths = ini_get('include_path');
            $paths = array();
            if (preg_match('/\x5c|;\w:/', $includePaths) === 1) {
                $paths = explode(";", $includePaths);
            } else {
                $paths = explode(":", $includePaths);
            }
            foreach ($paths as $testPath) {
                $testPath = realpath($testPath);
                $testPath = preg_replace('/\x5c{1,}/', '/', $testPath);
                $testPath = preg_replace('/\x2f$/', '', $testPath);
                if ($testPath === "") {
                	continue;
                }
                if (strpos($path, $testPath) === 0) {
                    trigger_error (ParamsProxy::CONFIG_PATH_UNDER_INCLUDES_PATH, E_USER_ERROR);
                }
            }
            return $path;
        }

        private function parseXML ($xmlString) {
            $data = new DOMIT_Document();
            DOMIT_DOMException::setErrorMode(DOMIT_ONERROR_DIE);
            $success = $data->parseXML($xmlString, false);
            if (!$success) {
                trigger_error (ParamsProxy::INVALID_CONFIG_FILE . "\n" . $data->getErrorCode() .
                    ": " . $data->getErrorString(), E_USER_ERROR);
            }
            return $data;
        }

        private function parseRootNode ($data) {
            $rootNode =& $data->documentElement;
            if (!$rootNode ||
                $rootNode->nodeName !== $this->rootElementName ||
                $rootNode->nodeType !== $this->rootElementType ||
                !$rootNode->hasAttribute($this->rootBindAttributeName)) {
                trigger_error(ParamsProxy::ILLEGAL_ROOT_ELEMENT, E_USER_ERROR);
            }
            if (!$rootNode->hasAttribute($this->rootBindAttributeName)) {
                trigger_error(ParamsProxy::ILLEGAL_ROOT_ELEMENT, E_USER_ERROR);
            }
            $attributes =& $rootNode->attributes;
            $attrLength = $attributes->getLength();
            if ($attrLength > 1) {
                 trigger_error(ParamsProxy::ILLEGAL_ROOT_ELEMENT, E_USER_ERROR);
            }
            $bindAttr =& $rootNode->getAttributeNode($this->rootBindAttributeName);
            $bindValue = $bindAttr->getValue();
            if($this->isInitialized) {
                if ($bindValue != $this->clientClsName) {
                    trigger_error(ParamsProxy::FOREIGN_CONFIG_FILE, E_USER_ERROR);
                }
            } else {
                if ($bindValue != $this->ownClassName) {
                    trigger_error(ParamsProxy::FOREIGN_CONFIG_FILE, E_USER_ERROR);
                }
            }
            return $rootNode;
        }

        private function parseParamNode (&$paramNode) {
            $nodeData = array ();
            if (!$paramNode->hasChildNodes()) {
                trigger_error(ParamsProxy::EMPTY_PARAM_ELEMENT, E_USER_ERROR);
            }
            $count = $paramNode->childCount;
            if ($count < 2) {
                trigger_error(ParamsProxy::TOO_FEW_PROPERTIES, E_USER_ERROR);
            } elseif ($count > 3) {
                trigger_error(ParamsProxy::TOO_MANY_PROPERTIES, E_USER_ERROR);
            }
            $children = $paramNode->childNodes;
            $hasName = false;
            for ($i=0; $i<$count; $i++) {
                $child =& $children[$i];
                if ($child->nodeType == $this->propertyElementType) {
                    $name = $child->nodeName;
                    if ($name === $this->propertyElementName_name ||
                        $name === $this->propertyElementName_type ||
                        $name === $this->propertyElementName_value) {
                        $value = $child->getText();
                        $value = trim($value);
                        if ($name === $this->propertyElementName_type) {
                            if ($value !== $this->propertyElementValue_string &&
                                $value !== $this->propertyElementValue_number &&
                                $value !== $this->propertyElementValue_boolean &&
                                $value !== $this->propertyElementValue_array &&
                                $value !== $this->propertyElementValue_null &&
                                $value !== $this->propertyElementValue_auto) {
                                trigger_error(ParamsProxy::INVALID_PROPERTY_NAME, E_USER_ERROR);
                            }
                        }
                        if ($name === $this->propertyElementName_name) {
                            $hasName = true;
                        }
                        $nodeData [$name] = $value;
                    } else {
                         trigger_error(ParamsProxy::ILLEGAL_PROPERTY, E_USER_ERROR);
                    }
                }
            }
            if (!$hasName) {
                trigger_error(ParamsProxy::MISSING_REQUIRED_NAME, E_USER_ERROR);
            }
            if ($nodeData[$this->propertyElementName_type] == $this->propertyElementValue_null) {
                $nodeData[$this->propertyElementName_value] = null;
            }
            if ($nodeData[$this->propertyElementName_type] == null) {
                $nodeData[$this->propertyElementName_type] = $this->propertyElementValue_auto;
            }
            if ($nodeData[$this->propertyElementName_type] == $this->propertyElementValue_auto) {
                $value = $nodeData[$this->propertyElementName_value];
                if ($value === "null") {
                    $nodeData[$this->propertyElementName_value] = null;
                } elseif ($value === "true") {
                    $nodeData[$this->propertyElementName_value] = true;
                } elseif ($value === "false") {
                    $nodeData[$this->propertyElementName_value] = false;
                } elseif (is_numeric ($value)) {
                    $isNegative = $value[0] == "-";
                    $hasDecimalPart = (stripos($value,".") !== false);
                    $hasExponentialPart = (stripos($value,"e") !== false);
                    $converted = 0;
                    if ($hasDecimalPart || $hasExponentialPart) {
                        $converted = (float) $value;
                    } else {
                       $converted = (int) $value;
                    }
                    if ($isNegative && $converted > 0) {
                       $converted *= -1;
                    }
                    if ("" . $converted === $value) {
                        $nodeData[$this->propertyElementName_value] = $converted;
                    }
                }
            } elseif ($nodeData[$this->propertyElementName_type] ==
                $this->propertyElementValue_boolean) {
                $value = $nodeData[$this->propertyElementName_value];
                if ($value === "true") {
                    $nodeData[$this->propertyElementName_value] = true;
                } elseif ($value === "false") {
                    $nodeData[$this->propertyElementName_value] = false;
                } else {
                    trigger_error(ParamsProxy::ILLEGAL_STRING_FOR_BOOLEAN_DEFINITION, E_USER_ERROR);
                }
            } elseif ($nodeData[$this->propertyElementName_type] ==
                $this->propertyElementValue_number) {
                $value = $nodeData[$this->propertyElementName_value];
                if (is_numeric ($value)) {
                    $isNegative = $value[0] == "-";
                    $hasDecimalPart = (stripos($value,".") !== false);
                    $hasExponentialPart = (stripos($value,"e") !== false);
                    $converted = 0;
                    if ($hasDecimalPart || $hasExponentialPart) {
                        $converted = (float) $value;
                    } else {
                       $converted = (int) $value;
                    }
                    if ($isNegative && $converted > 0) {
                       $converted *= -1;
                    }
                    $nodeData[$this->propertyElementName_value] = $converted;
                } else {
                    trigger_error(ParamsProxy::ILLEGAL_STRING_FOR_NUMBER_DEFINITION, E_USER_ERROR);
                }
            } elseif ($nodeData[$this->propertyElementName_type] ==
                $this->propertyElementValue_array) {
                 $nodeData[$this->propertyElementName_value] = $this->extractArrayValue ($paramNode);
            }
            if (!@isset ($nodeData[$this->propertyElementName_value]) &&
                !@is_null ($nodeData[$this->propertyElementName_value])) {
                trigger_error(ParamsProxy::MISSING_REQUIRED_VALUE, E_USER_ERROR);
            } elseif ($nodeData[$this->propertyElementName_value] === "") {
                trigger_error(ParamsProxy::MISSING_REQUIRED_VALUE, E_USER_ERROR);
            }
            return  $nodeData;
        }

        private function extractArrayValue (&$paramNode) {
            $ret = array();
            $nodeList =& $paramNode->getElementsByTagName($this->propertyElementName_value);
            $valueEl = $nodeList->item(0);
            $count = $valueEl->childCount;
            $children = $valueEl->childNodes;
            for ($i=0; $i<$count; $i++) {
                $itemData = array();
                $child =& $children[$i];
                if ($child->nodeType == $this->propertyElementType) {
                    if ($child->nodeName != $this->propertyElementName_item) {
                        trigger_error(ParamsProxy::ILLEGAL_ITEM_ELEMENT, E_USER_ERROR);
                    }
                    $attributes =& $child->attributes;
                    $numAttributes =& $attributes->getLength();
                    if ($numAttributes > 2) {
                        trigger_error(ParamsProxy::TOO_MANY_ITEM_ATTRIBUTES, E_USER_ERROR);
                    }
                    for ($j=0; $j<$numAttributes; $j++) {
                        $attribute =& $attributes->item($j);
                        $attrName = $attribute->getName();
                        $attrValue = $attribute->getValue();
                        if ($attrName == $this->attributeName_key ||
                            $attrName == $this->attributeName_type) {
                            if ($attrValue == "") {
                               trigger_error(ParamsProxy::ILLEGAL_ITEM_ELEMENT_ATTRIBUTE_VALUE,
                                    E_USER_ERROR);
                            }
                            if ($attrName == $this->attributeName_key) {
                                if (is_numeric($attrValue)) {
                                    $converted = (int) $attrValue;
                                    if ("" . $converted === $attrValue) {
                                        $attrValue = $converted;
                                    }
                                }
                                $itemData[$this->attributeName_key] = $attrValue;
                            }
                            if ($attrName == $this->attributeName_type){
                                if ($attrValue == $this->attributeValue_string ||
                                    $attrValue == $this->attributeValue_number ||
                                    $attrValue == $this->attributeValue_boolean ||
                                    $attrValue == $this->attributeValue_null ||
                                    $attrValue == $this->attributeValue_auto) {
                                    $itemData[$this->attributeName_type] = $attrValue;
                                } else {
                                    trigger_error(ParamsProxy::ILLEGAL_ITEM_ELEMENT_ATTRIBUTE_VALUE,
                                        E_USER_ERROR);
                                }
                            }
                        } else {
                            trigger_error(ParamsProxy::ILLEGAL_ITEM_ELEMENT_ATTRIBUTE_NAME,
                                E_USER_ERROR);
                        }
                    }
                    $itemValue = $child->getText();
                    $itemValue = trim ($itemValue);
                    $itemData["value"] = $itemValue;
                    if (!isset ($itemData[$this->attributeName_type])) {
                        $itemData[$this->attributeName_type] = $this->attributeValue_auto;
                    }
                    if ($itemData[$this->attributeName_type] == $this->attributeValue_null) {
                        $itemData["value"] = null;
                    }
                    if ($itemData[$this->attributeName_type] !== $this->attributeValue_null &&
                        $itemData["value"] === "") {
                        trigger_error(ParamsProxy::EMPTY_ITEM_ELEMENT, E_USER_ERROR);
                    }
                    switch ($itemData[$this->attributeName_type]) {
                        case $this->attributeValue_number:
							if (is_numeric($itemData["value"])) {
                                $isNegative = ($itemData["value"][0] == "-");
                                $hasDecimalPart = (stripos($itemData["value"],".") !== false);
                                $hasExponentialPart = (stripos($itemData["value"],"e") !== false);
                                $converted = 0;
                                if ($hasDecimalPart || $hasExponentialPart) {
                                    $converted = (float) $itemData["value"];
                                } else {
                                   $converted = (int) $itemData["value"];
                                }
                                if ($isNegative && $converted > 0) {
                                   $converted *= -1;
                                }
                                $itemData["value"] = $converted;
                            } else {
                                trigger_error(ParamsProxy::ILLEGAL_STRING_FOR_NUMBER_DEFINITION,
                                    E_USER_ERROR);
                            }
                            break;
                        case $this->attributeValue_boolean:
                            if ($itemData["value"] === "true") {
                                $itemData["value"] = true;
                            } elseif ($itemData["value"] === "false") {
                                $itemData["value"] = false;
                            } else {
                                trigger_error(ParamsProxy::ILLEGAL_STRING_FOR_BOOLEAN_DEFINITION,
                                    E_USER_ERROR);
                            }
                            break;
                        case $this->attributeValue_auto:
                            if ($itemData["value"] === "null") {
                                $itemData["value"] = null;
                            } elseif ($itemData["value"] === "true") {
                                $itemData["value"] = true;
                            } elseif ($itemData["value"] === "true") {
                                $itemData["value"] = false;
                            } elseif (is_numeric ($itemData["value"])) {
                                $value = $itemData["value"];
                                $isNegative = $value[0] == "-";
                                $hasDecimalPart = (stripos($value,".") !== false);
                                $hasExponentialPart = (stripos($value,"e") !== false);
                                $converted = 0;
                                if ($hasDecimalPart || $hasExponentialPart) {
                                    $converted = (float) $value;
                                } else {
                                    $converted = (int) $value;
                                }
                                if ($isNegative && $converted > 0) {
                                   $converted *= -1;
                                }
                                if ("" . $converted === $value) {
                                    $itemData["value"] = $converted;
                                }
                            }
                            break;
                    }
                    if (isset ($itemData[$this->attributeName_key])) {
                        $ret [$itemData[$this->attributeName_key]] = $itemData["value"];
                    } else {
                        $ret[] = $itemData["value"];
                    }
                }
            }
            return $ret;
        }
    }
?>
Return current item: DbProxy