xref: /dokuwiki/inc/Input/Input.php (revision d4f83172d9533c4d84f450fe22ef630816b21d75)
1ccc4c71cSAndreas Gohr<?php
2ccc4c71cSAndreas Gohr
3ccc4c71cSAndreas Gohrnamespace dokuwiki\Input;
4ccc4c71cSAndreas Gohr
5ccc4c71cSAndreas Gohr/**
6ccc4c71cSAndreas Gohr * Encapsulates access to the $_REQUEST array, making sure used parameters are initialized and
7ccc4c71cSAndreas Gohr * have the correct type.
8ccc4c71cSAndreas Gohr *
9ccc4c71cSAndreas Gohr * All function access the $_REQUEST array by default, if you want to access $_POST or $_GET
10ccc4c71cSAndreas Gohr * explicitly use the $post and $get members.
11ccc4c71cSAndreas Gohr *
12ccc4c71cSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
13ccc4c71cSAndreas Gohr */
14ccc4c71cSAndreas Gohrclass Input
15ccc4c71cSAndreas Gohr{
16ccc4c71cSAndreas Gohr    /** @var Post Access $_POST parameters */
17ccc4c71cSAndreas Gohr    public $post;
18ccc4c71cSAndreas Gohr    /** @var Get Access $_GET parameters */
19ccc4c71cSAndreas Gohr    public $get;
20ccc4c71cSAndreas Gohr    /** @var Server Access $_SERVER parameters */
21ccc4c71cSAndreas Gohr    public $server;
22ccc4c71cSAndreas Gohr
23ccc4c71cSAndreas Gohr    protected $access;
24ccc4c71cSAndreas Gohr
25ccc4c71cSAndreas Gohr    /**
26ccc4c71cSAndreas Gohr     * @var Callable
27ccc4c71cSAndreas Gohr     */
28ccc4c71cSAndreas Gohr    protected $filter;
29ccc4c71cSAndreas Gohr
30ccc4c71cSAndreas Gohr    /**
31ccc4c71cSAndreas Gohr     * Intilizes the dokuwiki\Input\Input class and it subcomponents
32ccc4c71cSAndreas Gohr     */
33ccc4c71cSAndreas Gohr    public function __construct()
34ccc4c71cSAndreas Gohr    {
35ccc4c71cSAndreas Gohr        $this->access = &$_REQUEST;
36ccc4c71cSAndreas Gohr        $this->post = new Post();
37ccc4c71cSAndreas Gohr        $this->get = new Get();
38ccc4c71cSAndreas Gohr        $this->server = new Server();
39ccc4c71cSAndreas Gohr    }
40ccc4c71cSAndreas Gohr
41ccc4c71cSAndreas Gohr    /**
42ccc4c71cSAndreas Gohr     * Apply the set filter to the given value
43ccc4c71cSAndreas Gohr     *
44ccc4c71cSAndreas Gohr     * @param string $data
45ccc4c71cSAndreas Gohr     * @return string
46ccc4c71cSAndreas Gohr     */
47ccc4c71cSAndreas Gohr    protected function applyfilter($data)
48ccc4c71cSAndreas Gohr    {
49ccc4c71cSAndreas Gohr        if (!$this->filter) return $data;
50ccc4c71cSAndreas Gohr        return call_user_func($this->filter, $data);
51ccc4c71cSAndreas Gohr    }
52ccc4c71cSAndreas Gohr
53ccc4c71cSAndreas Gohr    /**
54ccc4c71cSAndreas Gohr     * Return a filtered copy of the input object
55ccc4c71cSAndreas Gohr     *
56ccc4c71cSAndreas Gohr     * Expects a callable that accepts one string parameter and returns a filtered string
57ccc4c71cSAndreas Gohr     *
58ccc4c71cSAndreas Gohr     * @param Callable|string $filter
59ccc4c71cSAndreas Gohr     * @return Input
60ccc4c71cSAndreas Gohr     */
61ccc4c71cSAndreas Gohr    public function filter($filter = 'stripctl')
62ccc4c71cSAndreas Gohr    {
63ccc4c71cSAndreas Gohr        $this->filter = $filter;
64ccc4c71cSAndreas Gohr        $clone = clone $this;
65ccc4c71cSAndreas Gohr        $this->filter = '';
66ccc4c71cSAndreas Gohr        return $clone;
67ccc4c71cSAndreas Gohr    }
68ccc4c71cSAndreas Gohr
69ccc4c71cSAndreas Gohr    /**
70ccc4c71cSAndreas Gohr     * Check if a parameter was set
71ccc4c71cSAndreas Gohr     *
72ccc4c71cSAndreas Gohr     * Basically a wrapper around isset. When called on the $post and $get subclasses,
73ccc4c71cSAndreas Gohr     * the parameter is set to $_POST or $_GET and to $_REQUEST
74ccc4c71cSAndreas Gohr     *
75ccc4c71cSAndreas Gohr     * @see isset
76ccc4c71cSAndreas Gohr     * @param string $name Parameter name
77ccc4c71cSAndreas Gohr     * @return bool
78ccc4c71cSAndreas Gohr     */
79ccc4c71cSAndreas Gohr    public function has($name)
80ccc4c71cSAndreas Gohr    {
81ccc4c71cSAndreas Gohr        return isset($this->access[$name]);
82ccc4c71cSAndreas Gohr    }
83ccc4c71cSAndreas Gohr
84ccc4c71cSAndreas Gohr    /**
85ccc4c71cSAndreas Gohr     * Remove a parameter from the superglobals
86ccc4c71cSAndreas Gohr     *
87ccc4c71cSAndreas Gohr     * Basically a wrapper around unset. When NOT called on the $post and $get subclasses,
88ccc4c71cSAndreas Gohr     * the parameter will also be removed from $_POST or $_GET
89ccc4c71cSAndreas Gohr     *
90ccc4c71cSAndreas Gohr     * @see isset
91ccc4c71cSAndreas Gohr     * @param string $name Parameter name
92ccc4c71cSAndreas Gohr     */
93ccc4c71cSAndreas Gohr    public function remove($name)
94ccc4c71cSAndreas Gohr    {
95ccc4c71cSAndreas Gohr        if (isset($this->access[$name])) {
96ccc4c71cSAndreas Gohr            unset($this->access[$name]);
97ccc4c71cSAndreas Gohr        }
98ccc4c71cSAndreas Gohr        // also remove from sub classes
99ccc4c71cSAndreas Gohr        if (isset($this->post) && isset($_POST[$name])) {
100ccc4c71cSAndreas Gohr            unset($_POST[$name]);
101ccc4c71cSAndreas Gohr        }
102ccc4c71cSAndreas Gohr        if (isset($this->get) && isset($_GET[$name])) {
103ccc4c71cSAndreas Gohr            unset($_GET[$name]);
104ccc4c71cSAndreas Gohr        }
105ccc4c71cSAndreas Gohr    }
106ccc4c71cSAndreas Gohr
107ccc4c71cSAndreas Gohr    /**
108ccc4c71cSAndreas Gohr     * Access a request parameter without any type conversion
109ccc4c71cSAndreas Gohr     *
110ccc4c71cSAndreas Gohr     * @param string $name Parameter name
111ccc4c71cSAndreas Gohr     * @param mixed $default Default to return if parameter isn't set
112ccc4c71cSAndreas Gohr     * @param bool $nonempty Return $default if parameter is set but empty()
113ccc4c71cSAndreas Gohr     * @return mixed
114ccc4c71cSAndreas Gohr     */
115ccc4c71cSAndreas Gohr    public function param($name, $default = null, $nonempty = false)
116ccc4c71cSAndreas Gohr    {
117ccc4c71cSAndreas Gohr        if (!isset($this->access[$name])) return $default;
118ccc4c71cSAndreas Gohr        $value = $this->applyfilter($this->access[$name]);
119ccc4c71cSAndreas Gohr        if ($nonempty && empty($value)) return $default;
120ccc4c71cSAndreas Gohr        return $value;
121ccc4c71cSAndreas Gohr    }
122ccc4c71cSAndreas Gohr
123ccc4c71cSAndreas Gohr    /**
124ccc4c71cSAndreas Gohr     * Sets a parameter
125ccc4c71cSAndreas Gohr     *
126ccc4c71cSAndreas Gohr     * @param string $name Parameter name
127ccc4c71cSAndreas Gohr     * @param mixed $value Value to set
128ccc4c71cSAndreas Gohr     */
129ccc4c71cSAndreas Gohr    public function set($name, $value)
130ccc4c71cSAndreas Gohr    {
131ccc4c71cSAndreas Gohr        $this->access[$name] = $value;
132ccc4c71cSAndreas Gohr    }
133ccc4c71cSAndreas Gohr
134ccc4c71cSAndreas Gohr    /**
135ccc4c71cSAndreas Gohr     * Get a reference to a request parameter
136ccc4c71cSAndreas Gohr     *
137ccc4c71cSAndreas Gohr     * This avoids copying data in memory, when the parameter is not set it will be created
138ccc4c71cSAndreas Gohr     * and intialized with the given $default value before a reference is returned
139ccc4c71cSAndreas Gohr     *
140ccc4c71cSAndreas Gohr     * @param string $name Parameter name
141ccc4c71cSAndreas Gohr     * @param mixed $default If parameter is not set, initialize with this value
142ccc4c71cSAndreas Gohr     * @param bool $nonempty Init with $default if parameter is set but empty()
143ccc4c71cSAndreas Gohr     * @return mixed (reference)
144ccc4c71cSAndreas Gohr     */
145ccc4c71cSAndreas Gohr    public function &ref($name, $default = '', $nonempty = false)
146ccc4c71cSAndreas Gohr    {
147ccc4c71cSAndreas Gohr        if (!isset($this->access[$name]) || ($nonempty && empty($this->access[$name]))) {
148ccc4c71cSAndreas Gohr            $this->set($name, $default);
149ccc4c71cSAndreas Gohr        }
150ccc4c71cSAndreas Gohr
151ccc4c71cSAndreas Gohr        return $this->access[$name];
152ccc4c71cSAndreas Gohr    }
153ccc4c71cSAndreas Gohr
154ccc4c71cSAndreas Gohr    /**
155ccc4c71cSAndreas Gohr     * Access a request parameter as int
156ccc4c71cSAndreas Gohr     *
157ccc4c71cSAndreas Gohr     * @param string $name Parameter name
158ccc4c71cSAndreas Gohr     * @param int $default Default to return if parameter isn't set or is an array
159ccc4c71cSAndreas Gohr     * @param bool $nonempty Return $default if parameter is set but empty()
160ccc4c71cSAndreas Gohr     * @return int
161ccc4c71cSAndreas Gohr     */
162ccc4c71cSAndreas Gohr    public function int($name, $default = 0, $nonempty = false)
163ccc4c71cSAndreas Gohr    {
164ccc4c71cSAndreas Gohr        if (!isset($this->access[$name])) return $default;
165ccc4c71cSAndreas Gohr        if (is_array($this->access[$name])) return $default;
166ccc4c71cSAndreas Gohr        $value = $this->applyfilter($this->access[$name]);
167ccc4c71cSAndreas Gohr        if ($value === '') return $default;
168ccc4c71cSAndreas Gohr        if ($nonempty && empty($value)) return $default;
169ccc4c71cSAndreas Gohr
170ccc4c71cSAndreas Gohr        return (int)$value;
171ccc4c71cSAndreas Gohr    }
172ccc4c71cSAndreas Gohr
173ccc4c71cSAndreas Gohr    /**
174ccc4c71cSAndreas Gohr     * Access a request parameter as string
175ccc4c71cSAndreas Gohr     *
176ccc4c71cSAndreas Gohr     * @param string $name Parameter name
177ccc4c71cSAndreas Gohr     * @param string $default Default to return if parameter isn't set or is an array
178ccc4c71cSAndreas Gohr     * @param bool $nonempty Return $default if parameter is set but empty()
179ccc4c71cSAndreas Gohr     * @return string
180ccc4c71cSAndreas Gohr     */
181ccc4c71cSAndreas Gohr    public function str($name, $default = '', $nonempty = false)
182ccc4c71cSAndreas Gohr    {
183ccc4c71cSAndreas Gohr        if (!isset($this->access[$name])) return $default;
184ccc4c71cSAndreas Gohr        if (is_array($this->access[$name])) return $default;
185ccc4c71cSAndreas Gohr        $value = $this->applyfilter($this->access[$name]);
186ccc4c71cSAndreas Gohr        if ($nonempty && empty($value)) return $default;
187ccc4c71cSAndreas Gohr
188ccc4c71cSAndreas Gohr        return (string)$value;
189ccc4c71cSAndreas Gohr    }
190ccc4c71cSAndreas Gohr
191ccc4c71cSAndreas Gohr    /**
192ccc4c71cSAndreas Gohr     * Access a request parameter and make sure it is has a valid value
193ccc4c71cSAndreas Gohr     *
194ccc4c71cSAndreas Gohr     * Please note that comparisons to the valid values are not done typesafe (request vars
195ccc4c71cSAndreas Gohr     * are always strings) however the function will return the correct type from the $valids
196ccc4c71cSAndreas Gohr     * array when an match was found.
197ccc4c71cSAndreas Gohr     *
198ccc4c71cSAndreas Gohr     * @param string $name Parameter name
199ccc4c71cSAndreas Gohr     * @param array $valids Array of valid values
200ccc4c71cSAndreas Gohr     * @param mixed $default Default to return if parameter isn't set or not valid
201ccc4c71cSAndreas Gohr     * @return null|mixed
202ccc4c71cSAndreas Gohr     */
203ccc4c71cSAndreas Gohr    public function valid($name, $valids, $default = null)
204ccc4c71cSAndreas Gohr    {
205ccc4c71cSAndreas Gohr        if (!isset($this->access[$name])) return $default;
206ccc4c71cSAndreas Gohr        if (is_array($this->access[$name])) return $default; // we don't allow arrays
207ccc4c71cSAndreas Gohr        $value = $this->applyfilter($this->access[$name]);
208ccc4c71cSAndreas Gohr        $found = array_search($value, $valids);
209ccc4c71cSAndreas Gohr        if ($found !== false) return $valids[$found]; // return the valid value for type safety
210ccc4c71cSAndreas Gohr        return $default;
211ccc4c71cSAndreas Gohr    }
212ccc4c71cSAndreas Gohr
213ccc4c71cSAndreas Gohr    /**
214ccc4c71cSAndreas Gohr     * Access a request parameter as bool
215ccc4c71cSAndreas Gohr     *
216ccc4c71cSAndreas Gohr     * Note: $nonempty is here for interface consistency and makes not much sense for booleans
217ccc4c71cSAndreas Gohr     *
218ccc4c71cSAndreas Gohr     * @param string $name Parameter name
219ccc4c71cSAndreas Gohr     * @param mixed $default Default to return if parameter isn't set
220ccc4c71cSAndreas Gohr     * @param bool $nonempty Return $default if parameter is set but empty()
221ccc4c71cSAndreas Gohr     * @return bool
222ccc4c71cSAndreas Gohr     */
223ccc4c71cSAndreas Gohr    public function bool($name, $default = false, $nonempty = false)
224ccc4c71cSAndreas Gohr    {
225ccc4c71cSAndreas Gohr        if (!isset($this->access[$name])) return $default;
226ccc4c71cSAndreas Gohr        if (is_array($this->access[$name])) return $default;
227ccc4c71cSAndreas Gohr        $value = $this->applyfilter($this->access[$name]);
228ccc4c71cSAndreas Gohr        if ($value === '') return $default;
229ccc4c71cSAndreas Gohr        if ($nonempty && empty($value)) return $default;
230ccc4c71cSAndreas Gohr
231ccc4c71cSAndreas Gohr        return (bool)$value;
232ccc4c71cSAndreas Gohr    }
233ccc4c71cSAndreas Gohr
234ccc4c71cSAndreas Gohr    /**
235ccc4c71cSAndreas Gohr     * Access a request parameter as array
236ccc4c71cSAndreas Gohr     *
237ccc4c71cSAndreas Gohr     * @param string $name Parameter name
238ccc4c71cSAndreas Gohr     * @param mixed $default Default to return if parameter isn't set
239ccc4c71cSAndreas Gohr     * @param bool $nonempty Return $default if parameter is set but empty()
240ccc4c71cSAndreas Gohr     * @return array
241ccc4c71cSAndreas Gohr     */
242*a469bafbSAndreas Gohr    public function arr($name, $default = [], $nonempty = false)
243ccc4c71cSAndreas Gohr    {
244ccc4c71cSAndreas Gohr        if (!isset($this->access[$name])) return $default;
245ccc4c71cSAndreas Gohr        if (!is_array($this->access[$name])) return $default;
246ccc4c71cSAndreas Gohr        if ($nonempty && empty($this->access[$name])) return $default;
247ccc4c71cSAndreas Gohr
248*a469bafbSAndreas Gohr        return $this->access[$name];
249ccc4c71cSAndreas Gohr    }
250ccc4c71cSAndreas Gohr
251ccc4c71cSAndreas Gohr    /**
252ccc4c71cSAndreas Gohr     * Create a simple key from an array key
253ccc4c71cSAndreas Gohr     *
254ccc4c71cSAndreas Gohr     * This is useful to access keys where the information is given as an array key or as a single array value.
255ccc4c71cSAndreas Gohr     * For example when the information was submitted as the name of a submit button.
256ccc4c71cSAndreas Gohr     *
257ccc4c71cSAndreas Gohr     * This function directly changes the access array.
258ccc4c71cSAndreas Gohr     *
259ccc4c71cSAndreas Gohr     * Eg. $_REQUEST['do']['save']='Speichern' becomes $_REQUEST['do'] = 'save'
260ccc4c71cSAndreas Gohr     *
261ccc4c71cSAndreas Gohr     * This function returns the $INPUT object itself for easy chaining
262ccc4c71cSAndreas Gohr     *
263ccc4c71cSAndreas Gohr     * @param string $name
264ccc4c71cSAndreas Gohr     * @return Input
265ccc4c71cSAndreas Gohr     */
266ccc4c71cSAndreas Gohr    public function extract($name)
267ccc4c71cSAndreas Gohr    {
268ccc4c71cSAndreas Gohr        if (!isset($this->access[$name])) return $this;
269ccc4c71cSAndreas Gohr        if (!is_array($this->access[$name])) return $this;
270ccc4c71cSAndreas Gohr        $keys = array_keys($this->access[$name]);
271ccc4c71cSAndreas Gohr        if (!$keys) {
272ccc4c71cSAndreas Gohr            // this was an empty array
273ccc4c71cSAndreas Gohr            $this->remove($name);
274ccc4c71cSAndreas Gohr            return $this;
275ccc4c71cSAndreas Gohr        }
276ccc4c71cSAndreas Gohr        // get the first key
277ccc4c71cSAndreas Gohr        $value = array_shift($keys);
278ccc4c71cSAndreas Gohr        if ($value === 0) {
279ccc4c71cSAndreas Gohr            // we had a numeric array, assume the value is not in the key
280ccc4c71cSAndreas Gohr            $value = array_shift($this->access[$name]);
281ccc4c71cSAndreas Gohr        }
282ccc4c71cSAndreas Gohr
283ccc4c71cSAndreas Gohr        $this->set($name, $value);
284ccc4c71cSAndreas Gohr        return $this;
285ccc4c71cSAndreas Gohr    }
286ccc4c71cSAndreas Gohr}
287