Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
<?php
/**
 * Copyright 2009-2017 Horde LLC (http://www.horde.org/)
 *
 * See the enclosed file LICENSE for license information (LGPL). If you
 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 *
 * @category  Horde
 * @copyright 2009-2017 Horde LLC
 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
 * @package   Util
 */

/**
 * An OO-way to access form variables.
 *
 * @todo $_expected and $_vars are used inconsistently. $_expected is used in
 * exists(), but not in getExists(). And both are expected to be of the same
 * format, while Horde_Form submits $_expected as a flat list and $_vars as a
 * multi-dimensional array, if the the form elements are or array type (like
 * object[] in Turba).
 * @todo The sanitized feature doesn't seem to be used anywhere at all.
 *
 * @author    Robert E. Coyle <robertecoyle@hotmail.com>
 * @author    Chuck Hagenbuch <chuck@horde.org>
 * @author    Michael Slusarz <slusarz@horde.org>
 * @category  Horde
 * @copyright 2009-2017 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.
     */
    public static 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 $this->__isset($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);
> ? filter_var_array($val, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES) > : filter_var($val, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES);
} /* 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); } }