Location: PHPKode > scripts > param > param.php
<?php
/**
 *  @package Param
 *  @author Domenico Pontari <hide@address.com>
 *  @copyright Copyright (c) 2009, Domenico Pontari
 *  @license http://opensource.org/licenses/bsd-license.php New and Simplified BSD licenses
 *  @version 1.0
 *
 *  This class allow you to define a parameter or a list of parameters that must be
 *  read from $_POST or $_GET variables. Features are:
 *  1. a param type can be an array or an object, not only a scalar value
 *  2. you can define custom function to set restriction for the values
 *  3. you can define a type casting for the param
 *  4. SQL INJECTION management
 *
 *  It follows a factory pattern: each param type
 *  must be an extended class of "param" base class
 */

    /**#@+
     * param types
     */
    define ('PARAM_DIM_SINGLE', 'single');
    define ('PARAM_DIM_ARRAY', 'array');
    define ('PARAM_DIM_ASSOCIATIVE', 'associative array');
    define ('PARAM_DIM_OBJECT', 'object');
    
    define ('PARAM_TYPE_BOOL', 'boolean');
    define ('PARAM_TYPE_INT', 'integer');
    define ('PARAM_TYPE_STRING', 'string');
    define ('PARAM_TYPE_AUTO', 'auto');

    define ('PARAM_CTRL_INPUT', 'input');
    
    define ('PARAM_INPUT_GET', 'get');
    define ('PARAM_INPUT_POST', 'post');
    define ('PARAM_INPUT_DEFAULT_VALUE', 'default value'); // value defined in the "value" attribute of "paramVars" class
    /**#@-*/

    /**
     *  required library
     *  @link http://www.phpclasses.org/package/5969-PHP-Tokenizer-split-strings-into-tokens.html
     */
    require_once ('tokenizer.php');

    /**
      *  @package Param
      */
    class param {
        /**
         *  @var string inclusion path for extended classes
         */
        static $includePath = '';

        protected $vars = false;
        function get() {return $this->vars;}

        /**
         *  @param paramVars|array
         */
        static function register ($vars) {
            if (!is_a($vars, 'paramVars')) $vars = new paramVars ($vars);
            if ($vars->refClass !== false) {
                $className = $vars->refClass . "Param";
                if (!class_exists($className)) {
                    include_once ($includePath . "param_$vars->refClass");
                    if (!class_exists($className)) trigger_error ('unableToFindParamClassExtension', E_USER_ERROR);
                }
            } else $className = 'param';
            $param = new $className ($vars);
            if ($param->get() === false) return false;
            return $param;
        }

        function __construct ($vars) {
            $this->set($vars);
            if ($this->vars->startGettingFromInput) $this->setValueFromURL();
        }
        
        /**
         *  @return void
         */
        function set($vars) {
            $this->vars = $vars;
        }
        
        protected function getVar ($varName) {
            if (!isset($this->vars->$varName)) trigger_error ('paramValueNotSetted');
            return $this->vars->$varName;
        }
        
        protected function setVar ($varName, $varValue) {
            $this->vars->$varName = $varValue;
        }

        function __get ($varName) {
            switch ($varName) {
                case 'value':
                case 'name':
                    $result = $this->getVar ($varName);
                break;
                default:
                    trigger_error ('paramAttributeNotFound', E_USER_ERROR);
            }
            return $result;
        }
        
        function __set ($varName, $varValue) {
            switch ($varName) {
                case 'value':
                    $result = $this->setVar ($varName, $varValue);
                break;
                default:
                    trigger_error ('unableToSetThisAttribute', E_USER_ERROR);
            }
        }
        
        function getDefaultValue () {
            return $this->vars->defaultValue;
        }

        /**
         *  @return string|false if no valid input is found false will be returned
         *
         *  if PARAM_INPUT_DEFAULT_VALUE is found it will return false as well
         */
        function getInputStringFromURL () {
            $result = false;
            $defaultValue = $this->getDefaultValue();
            foreach ($this->vars->inputList as $input) {
                if (($input == PARAM_INPUT_POST) && (isset($_POST[$this->vars->name])))
                    $result = $_POST[$this->vars->name];
                if (($input == PARAM_INPUT_GET) && (isset($_GET[$this->vars->name])))
                    $result = $_GET[$this->vars->name];
                if (($input == PARAM_INPUT_DEFAULT_VALUE) && (isset($defaultValue)))
                    return false;
                if ($result !== false) {
                    if (self::sqlInjectionAttempted($result)) trigger_error ('sqlInjectionDetected', E_USER_ERROR);
                    return $result;
                }
            }
            return $result;
        }
        
        function setValueFromURL () {
            $inputString = $this->getInputStringFromURL();
            if ($inputString !== false)
                $this->vars->value = $this->stringToValue($inputString);
            elseif (in_array(PARAM_INPUT_DEFAULT_VALUE, $this->vars->inputList)) {
                $defaultValue = $this->getDefaultValue();
                if (isset($defaultValue)) $this->vars->value = $defaultValue;
            }
        }
        
        protected function stringToValue ($string) {
            $value = self::splitInputString ($string, $this->vars->dimension);
            $value = self::castType ($value, $this->vars->type);
            if (isset($this->vars->maxLen)) {
                self::checkMaxLen ($value, $this->vars->maxLen, $newValue);
                $value = $newValue;
            }
            $value = $this->filter($value);
            if (!$this->validate($value)) trigger_error ('errorValidatingParam', E_USER_ERROR);
            return $value;
        }

        /**
         *  This function tell you if this param value is a default value so that
         *  you can omit it to define current state
         */
        function isInIrrelevantState () {
            $defaultValue = $this->getDefaultValue();
            if (!isset($defaultValue)) return false;
            if ($this->vars->value === $defaultValue) return true;
            return false;
        }

        /**
         *  Function to be extended
         *  @return mixed filtered value
         */
        function filter ($value) {return $value;}
        
        /**
         *  Function to be extended
         *  @return bool
         */
        function validate ($value) {return true;}

        static protected function splitInputString ($string, $dimension) {
            $result = $string;
            switch ($dimension) {
                case PARAM_DIM_OBJECT:
                case PARAM_DIM_ASSOCIATIVE:
                    $result = json_decode ($result);
                break;
                case PARAM_DIM_ARRAY:
                    $result = explode(",", $result);
                break;
            }
            return $result;
        }
        
        /**
         *  @param mixed
         *  @param int
         *  @param mixed cutted values
         *  @return bool
         */
        static protected function checkMaxLen ($value, $maxLen, &$cuttedValue = NULL) {
            if (!is_scalar ($value)) {
                foreach ($value as $el)
                    if (!checkMaxLen ($el, $maxLen)) return false;
                return true;
            }
            $oversize = (strlen($value) > $maxLen);
            if (gettype($value) != 'string') {
                $module = '1';
                for ($i = 1; $i < $maxLen; $i++) $module .= '0';
                $module = intval($module);
                $cuttedValue = $value % $module;
            } else $cuttedValue = substr($value, 0, $maxLen);
            return !$oversize;
        }
        
        /**
         *  Used to detect SQL injection attempted
         *  Criteria:
         *  1. found ('select', 'update', 'delete', 'insert') AND ('from')
         *  2. found ('execute', 'exec', 'cast') AND parenthesis
         *  @return bool
         */
        static protected function sqlInjectionAttempted ($string) {
            if (empty($string)) return false;
            $string = strtolower($string);
            $separators = array (',', '"', "'", "(", ")", " ");
            $tokenizer = new tokenizer ();
            $tokenizer->setLimits ($separators);
            $tokenizer->tokenize($string);
            $tokens = $tokenizer->getTokens(true);

            // First check
            $wordFound = false;
            foreach ($tokens as $token) {
                $wordFound = in_array($token, array('select', 'update', 'delete', 'insert'));
                if ($wordFound == true) break;
            }
            if (($wordFound)&&(in_array('from', $tokens))) return true;

            // Second check
            $wordFound = false;
            foreach ($tokens as $token) {
                $wordFound = in_array($token, array('execute', 'exec', 'cast'));
                if ($wordFound == true) break;
            }
            if (($wordFound)&&(in_array('(', $tokens))) return true;
            return false;
        }

        static protected function castType ($value, $type) {
            if (!is_scalar($value)) {
                foreach ($value as $name => $el)
                    $value[$name] = self::castType ($el, $type);
                return $value;
            }
            
            if (($type == PARAM_TYPE_BOOL) || ($type == PARAM_TYPE_AUTO)) {
                if ($value === 'false') $value = false;
                if ($value === 'true') $value = true;
            }
            switch ($type) {
                case PARAM_TYPE_AUTO:
                    if (is_numeric($value)) $type = PARAM_TYPE_INT;
                    if (empty($value) || is_bool($value)) $type = PARAM_TYPE_BOOL;
                default:
                    if (!settype ($value, $type)) trigger_error ('unableToCastParam', E_USER_ERROR);
            }
            return $value;
        }
    }
    
     /**
      *  @package Param
      */
    class paramVars {
        public $name;
        public $type = PARAM_TYPE_AUTO;
        public $value;
        public $dimension = PARAM_DIM_SINGLE;
        public $description = '';
        public $startGettingFromInput = true;

        /**
         *  @var string|false class name where are defined custom functions. If false
         *  base "param" class will be used
         */
        public $refClass = false;

        /**
         *  @var int you can decide if this param must be retrieve from $_GET, $_POST or both
         *  the order in the array is preserved: if something is found for the first input type
         *  the others are not followed
         */
        public $inputList = array(PARAM_INPUT_POST, PARAM_INPUT_GET, PARAM_INPUT_DEFAULT_VALUE);

        public $maxLen;

        public $defaultValue;
        public $defaultValueDescription = '';

        /**
         *  @var string HTML control type
         */
        public $controlType = PARAM_CTRL_INPUT;
        
        /**
         *  @param array an associative array with custom values
         */
        function __construct ($array = array()) {
            if (!is_array($array)) trigger_error ('varsToDefineParamMustBeAnArray', E_USER_ERROR);
            if (empty($array)) return;
            foreach ($this as $var => $value) {
                if (isset($array[$var])) $this->$var = $array[$var];
            }
        }
    }




?>
Return current item: param