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