1: <?php
2: /**
3: * Horde_Variables:: class. Provides OO-way to access form variables.
4: *
5: * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
6: *
7: * See the enclosed file COPYING for license information (LGPL). If you
8: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
9: *
10: * @author Robert E. Coyle <robertecoyle@hotmail.com>
11: * @author Chuck Hagenbuch <chuck@horde.org>
12: * @category Horde
13: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
14: * @package Util
15: */
16: class Horde_Variables implements Countable, Iterator, ArrayAccess
17: {
18: /**
19: * The list of expected variables.
20: *
21: * @var array
22: */
23: protected $_expected = array();
24:
25: /**
26: * Has the input been sanitized?
27: *
28: * @var boolean
29: */
30: protected $_sanitized = false;
31:
32: /**
33: * Array of form variables.
34: *
35: * @var array
36: */
37: protected $_vars;
38:
39: /**
40: * Returns a Horde_Variables object populated with the form input.
41: *
42: * @param string $sanitize Sanitize the input variables?
43: *
44: * @return Horde_Variables Variables object.
45: */
46: static public function getDefaultVariables($sanitize = false)
47: {
48: return new self(null, $sanitize);
49: }
50:
51: /**
52: * Constructor.
53: *
54: * @param array $vars The list of form variables (if null, defaults
55: * to PHP's $_REQUEST value).
56: * @param string $sanitize Sanitize the input variables?
57: */
58: public function __construct($vars = array(), $sanitize = false)
59: {
60: if (is_null($vars)) {
61: $request_copy = $_REQUEST;
62: $vars = Horde_Util::dispelMagicQuotes($request_copy);
63: }
64:
65: if (isset($vars['_formvars'])) {
66: $this->_expected = @unserialize($vars['_formvars']);
67: unset($vars['_formvars']);
68: }
69:
70: $this->_vars = $vars;
71:
72: if ($sanitize) {
73: $this->sanitize();
74: }
75: }
76:
77: /**
78: * Sanitize the form input.
79: */
80: public function sanitize()
81: {
82: if (!$this->_sanitized) {
83: foreach (array_keys($this->_vars) as $key) {
84: $this->$key = $this->filter($key);
85: }
86: $this->_sanitized = true;
87: }
88: }
89:
90: /**
91: * Alias of isset().
92: *
93: * @see __isset()
94: */
95: public function exists($varname)
96: {
97: return isset($this->$varname);
98: }
99:
100: /**
101: * isset() implementation.
102: *
103: * @param string $varname The form variable name.
104: *
105: * @return boolean Does $varname form variable exist?
106: */
107: public function __isset($varname)
108: {
109: return count($this->_expected)
110: ? $this->_getExists($this->_expected, $varname, $value)
111: : $this->_getExists($this->_vars, $varname, $value);
112: }
113:
114: /**
115: * Implements isset() for ArrayAccess interface.
116: *
117: * @see __isset()
118: */
119: public function offsetExists($field)
120: {
121: return $this->__isset($field);
122: }
123:
124: /**
125: * Returns the value of a given form variable.
126: *
127: * @param string $varname The form variable name.
128: * @param string $default The default form variable value.
129: *
130: * @return mixed The form variable, or $default if it doesn't exist.
131: */
132: public function get($varname, $default = null)
133: {
134: return $this->_getExists($this->_vars, $varname, $value)
135: ? $value
136: : $default;
137: }
138:
139: /**
140: * Returns the value of a given form variable.
141: *
142: * @param string $varname The form variable name.
143: *
144: * @return mixed The form variable, or null if it doesn't exist.
145: */
146: public function __get($varname)
147: {
148: $this->_getExists($this->_vars, $varname, $value);
149: return $value;
150: }
151:
152: /**
153: * Implements getter for ArrayAccess interface.
154: *
155: * @see __get()
156: */
157: public function offsetGet($field)
158: {
159: return $this->__get($field);
160: }
161:
162: /**
163: * Given a variable name, returns the value and sets a variable indicating
164: * whether the value exists in the form data.
165: *
166: * @param string $varname The form variable name.
167: * @param boolean &$exists Reference to variable that will indicate
168: * whether $varname existed in form data.
169: *
170: * @return mixed The form variable, or null if it doesn't exist.
171: */
172: public function getExists($varname, &$exists)
173: {
174: $exists = $this->_getExists($this->_vars, $varname, $value);
175: return $value;
176: }
177:
178: /**
179: * Sets the value of a given form variable.
180: *
181: * @see __set()
182: */
183: public function set($varname, $value)
184: {
185: $this->$varname = $value;
186: }
187:
188: /**
189: * Sets the value of a given form variable.
190: *
191: * @param string $varname The form variable name.
192: * @param mixed $value The value to set.
193: */
194: public function __set($varname, $value)
195: {
196: $keys = array();
197:
198: if (Horde_Array::getArrayParts($varname, $base, $keys)) {
199: array_unshift($keys, $base);
200: $place = &$this->_vars;
201: $i = count($keys);
202:
203: while ($i--) {
204: $key = array_shift($keys);
205: if (!isset($place[$key])) {
206: $place[$key] = array();
207: }
208: $place = &$place[$key];
209: }
210:
211: $place = $value;
212: } else {
213: $this->_vars[$varname] = $value;
214: }
215: }
216:
217: /**
218: * Implements setter for ArrayAccess interface.
219: *
220: * @see __set()
221: */
222: public function offsetSet($field, $value)
223: {
224: $this->__set($field, $value);
225: }
226:
227: /**
228: * Deletes a given form variable.
229: *
230: * @see __unset()
231: */
232: public function remove($varname)
233: {
234: unset($this->$varname);
235: }
236:
237: /**
238: * Deletes a given form variable.
239: *
240: * @param string $varname The form variable name.
241: */
242: public function __unset($varname)
243: {
244: Horde_Array::getArrayParts($varname, $base, $keys);
245:
246: if (is_null($base)) {
247: unset($this->_vars[$varname]);
248: } else {
249: $ptr = &$this->_vars[$base];
250: $end = count($keys) - 1;
251: foreach ($keys as $key => $val) {
252: if (!isset($ptr[$val])) {
253: break;
254: }
255: if ($end == $key) {
256: array_splice($ptr, array_search($val, array_keys($ptr)), 1);
257: } else {
258: $ptr = &$ptr[$val];
259: }
260: }
261: }
262: }
263:
264: /**
265: * Implements unset() for ArrayAccess interface.
266: *
267: * @see __unset()
268: */
269: public function offsetUnset($field)
270: {
271: $this->__unset($field);
272: }
273:
274: /**
275: * Merges a list of variables into the current form variable list.
276: *
277: * @param array $vars Form variables.
278: */
279: public function merge($vars)
280: {
281: foreach ($vars as $varname => $value) {
282: $this->$varname = $value;
283: }
284: }
285:
286: /**
287: * Set $varname to $value ONLY if it's not already present.
288: *
289: * @param string $varname The form variable name.
290: * @param mixed $value The value to set.
291: *
292: * @return boolean True if the value was altered.
293: */
294: public function add($varname, $value)
295: {
296: if ($this->exists($varname)) {
297: return false;
298: }
299:
300: $this->_vars[$varname] = $value;
301: return true;
302: }
303:
304: /**
305: * Filters a form value so that it can be used in HTML output.
306: *
307: * @since Horde_Util 1.2.0
308: *
309: * @param string $varname The form variable name.
310: *
311: * @return mixed The filtered variable, or null if it doesn't exist.
312: */
313: public function filter($varname)
314: {
315: $val = $this->$varname;
316:
317: if (is_null($val) || $this->_sanitized) {
318: return $val;
319: }
320:
321: return is_array($val)
322: ? filter_var_array($val, FILTER_SANITIZE_STRING)
323: : filter_var($val, FILTER_SANITIZE_STRING);
324: }
325:
326: /* Protected methods. */
327:
328: /**
329: * Fetch the requested variable ($varname) into $value, and return
330: * whether or not the variable was set in $array.
331: *
332: * @param array $array The array to search in (usually either
333: * $this->_vars or $this->_expected).
334: * @param string $varname The name of the variable to look for.
335: * @param mixed &$value $varname's value gets assigned to this variable.
336: *
337: * @return boolean Whether or not the variable was set (or, if we've
338: * checked $this->_expected, should have been set).
339: */
340: protected function _getExists($array, $varname, &$value)
341: {
342: if (Horde_Array::getArrayParts($varname, $base, $keys)) {
343: if (!isset($array[$base])) {
344: $value = null;
345: return false;
346: }
347:
348: $searchspace = &$array[$base];
349: $i = count($keys);
350:
351: while ($i--) {
352: $key = array_shift($keys);
353: if (!isset($searchspace[$key])) {
354: $value = null;
355: return false;
356: }
357: $searchspace = &$searchspace[$key];
358: }
359: $value = $searchspace;
360:
361: return true;
362: }
363:
364: $value = isset($array[$varname])
365: ? $array[$varname]
366: : null;
367:
368: return !is_null($value);
369: }
370:
371: /* Countable methods. */
372:
373: /**
374: */
375: public function count()
376: {
377: return count($this->_vars);
378: }
379:
380: /* Iterator methods. */
381:
382: public function current()
383: {
384: return current($this->_vars);
385: }
386:
387: public function key()
388: {
389: return key($this->_vars);
390: }
391:
392: public function next()
393: {
394: next($this->_vars);
395: }
396:
397: public function rewind()
398: {
399: reset($this->_vars);
400: }
401:
402: public function valid()
403: {
404: return (key($this->_vars) !== null);
405: }
406:
407: }
408: