* @author Chuck Hagenbuch * @author Michael Slusarz * @category Horde * @copyright 2009-2014 Horde LLC * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 * @package Util */ class Horde_Variables implements ArrayAccess, Countable, IteratorAggregate { /** * The list of expected variables. * * @var array */ protected $_expected = array(); /** * Has the input been sanitized? * * @var boolean */ protected $_sanitized = false; /** * Array of form variables. * * @var array */ protected $_vars; /** * Returns a Horde_Variables object populated with the form input. * * @param string $sanitize Sanitize the input variables? * * @return Horde_Variables Variables object. */ static public function getDefaultVariables($sanitize = false) { return new self(null, $sanitize); } /** * Constructor. * * @param array $vars The list of form variables (if null, defaults * to PHP's $_REQUEST value). If '_formvars' * exists, it must be a JSON encoded array that * contains the list of allowed form variables. * @param string $sanitize Sanitize the input variables? */ public function __construct($vars = array(), $sanitize = false) { if (is_null($vars)) { $request_copy = $_REQUEST; $vars = Horde_Util::dispelMagicQuotes($request_copy); } if (isset($vars['_formvars'])) { $this->_expected = @json_decode($vars['_formvars'], true); unset($vars['_formvars']); } $this->_vars = $vars; if ($sanitize) { $this->sanitize(); } } /** * Sanitize the form input. */ public function sanitize() { if (!$this->_sanitized) { foreach (array_keys($this->_vars) as $key) { $this->$key = $this->filter($key); } $this->_sanitized = true; } } /** * Alias of isset(). * * @see __isset() */ public function exists($varname) { return isset($this->$varname); } /** * isset() implementation. * * @param string $varname The form variable name. * * @return boolean Does $varname form variable exist? */ public function __isset($varname) { return count($this->_expected) ? $this->_getExists($this->_expected, $varname, $value) : $this->_getExists($this->_vars, $varname, $value); } /** * Implements isset() for ArrayAccess interface. * * @see __isset() */ public function offsetExists($field) { return $this->__isset($field); } /** * Returns the value of a given form variable. * * @param string $varname The form variable name. * @param string $default The default form variable value. * * @return mixed The form variable, or $default if it doesn't exist. */ public function get($varname, $default = null) { return $this->_getExists($this->_vars, $varname, $value) ? $value : $default; } /** * Returns the value of a given form variable. * * @param string $varname The form variable name. * * @return mixed The form variable, or null if it doesn't exist. */ public function __get($varname) { $this->_getExists($this->_vars, $varname, $value); return $value; } /** * Implements getter for ArrayAccess interface. * * @see __get() */ public function offsetGet($field) { return $this->__get($field); } /** * Given a variable name, returns the value and sets a variable indicating * whether the value exists in the form data. * * @param string $varname The form variable name. * @param boolean &$exists Reference to variable that will indicate * whether $varname existed in form data. * * @return mixed The form variable, or null if it doesn't exist. */ public function getExists($varname, &$exists) { $exists = $this->_getExists($this->_vars, $varname, $value); return $value; } /** * Sets the value of a given form variable. * * @see __set() */ public function set($varname, $value) { $this->$varname = $value; } /** * Sets the value of a given form variable. * * @param string $varname The form variable name. * @param mixed $value The value to set. */ public function __set($varname, $value) { $keys = array(); if (Horde_Array::getArrayParts($varname, $base, $keys)) { array_unshift($keys, $base); $place = &$this->_vars; $i = count($keys); while ($i--) { $key = array_shift($keys); if (!isset($place[$key])) { $place[$key] = array(); } $place = &$place[$key]; } $place = $value; } else { $this->_vars[$varname] = $value; } } /** * Implements setter for ArrayAccess interface. * * @see __set() */ public function offsetSet($field, $value) { $this->__set($field, $value); } /** * Deletes a given form variable. * * @see __unset() */ public function remove($varname) { unset($this->$varname); } /** * Deletes a given form variable. * * @param string $varname The form variable name. */ public function __unset($varname) { Horde_Array::getArrayParts($varname, $base, $keys); if (is_null($base)) { unset($this->_vars[$varname]); } else { $ptr = &$this->_vars[$base]; $end = count($keys) - 1; foreach ($keys as $key => $val) { if (!isset($ptr[$val])) { break; } if ($end == $key) { array_splice($ptr, array_search($val, array_keys($ptr)), 1); } else { $ptr = &$ptr[$val]; } } } } /** * Implements unset() for ArrayAccess interface. * * @see __unset() */ public function offsetUnset($field) { $this->__unset($field); } /** * Merges a list of variables into the current form variable list. * * @param array $vars Form variables. */ public function merge($vars) { foreach ($vars as $varname => $value) { $this->$varname = $value; } } /** * Set $varname to $value ONLY if it's not already present. * * @param string $varname The form variable name. * @param mixed $value The value to set. * * @return boolean True if the value was altered. */ public function add($varname, $value) { if ($this->exists($varname)) { return false; } $this->_vars[$varname] = $value; return true; } /** * Filters a form value so that it can be used in HTML output. * * @param string $varname The form variable name. * * @return mixed The filtered variable, or null if it doesn't exist. */ public function filter($varname) { $val = $this->$varname; if (is_null($val) || $this->_sanitized) { return $val; } return is_array($val) ? filter_var_array($val, FILTER_SANITIZE_STRING) : filter_var($val, FILTER_SANITIZE_STRING); } /* Protected methods. */ /** * Fetch the requested variable ($varname) into $value, and return * whether or not the variable was set in $array. * * @param array $array The array to search in (usually either * $this->_vars or $this->_expected). * @param string $varname The name of the variable to look for. * @param mixed &$value $varname's value gets assigned to this variable. * * @return boolean Whether or not the variable was set (or, if we've * checked $this->_expected, should have been set). */ protected function _getExists($array, $varname, &$value) { if (Horde_Array::getArrayParts($varname, $base, $keys)) { if (!isset($array[$base])) { $value = null; return false; } $searchspace = &$array[$base]; $i = count($keys); while ($i--) { $key = array_shift($keys); if (!isset($searchspace[$key])) { $value = null; return false; } $searchspace = &$searchspace[$key]; } $value = $searchspace; return true; } $value = isset($array[$varname]) ? $array[$varname] : null; return !is_null($value); } /* Countable methods. */ /** */ public function count() { return count($this->_vars); } /* IteratorAggregate method. */ public function getIterator() { return new ArrayIterator($this->_vars); } }