Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like CI_Input often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use CI_Input, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
51 | View Code Duplication | class CI_Input { |
|
|
|||
52 | |||
53 | /** |
||
54 | * IP address of the current user |
||
55 | * |
||
56 | * @var string |
||
57 | */ |
||
58 | protected $ip_address = FALSE; |
||
59 | |||
60 | /** |
||
61 | * Allow GET array flag |
||
62 | * |
||
63 | * If set to FALSE, then $_GET will be set to an empty array. |
||
64 | * |
||
65 | * @var bool |
||
66 | */ |
||
67 | protected $_allow_get_array = TRUE; |
||
68 | |||
69 | /** |
||
70 | * Standardize new lines flag |
||
71 | * |
||
72 | * If set to TRUE, then newlines are standardized. |
||
73 | * |
||
74 | * @var bool |
||
75 | */ |
||
76 | protected $_standardize_newlines; |
||
77 | |||
78 | /** |
||
79 | * Enable XSS flag |
||
80 | * |
||
81 | * Determines whether the XSS filter is always active when |
||
82 | * GET, POST or COOKIE data is encountered. |
||
83 | * Set automatically based on config setting. |
||
84 | * |
||
85 | * @var bool |
||
86 | */ |
||
87 | protected $_enable_xss = FALSE; |
||
88 | |||
89 | /** |
||
90 | * Enable CSRF flag |
||
91 | * |
||
92 | * Enables a CSRF cookie token to be set. |
||
93 | * Set automatically based on config setting. |
||
94 | * |
||
95 | * @var bool |
||
96 | */ |
||
97 | protected $_enable_csrf = FALSE; |
||
98 | |||
99 | /** |
||
100 | * List of all HTTP request headers |
||
101 | * |
||
102 | * @var array |
||
103 | */ |
||
104 | protected $headers = array(); |
||
105 | |||
106 | /** |
||
107 | * Raw input stream data |
||
108 | * |
||
109 | * Holds a cache of php://input contents |
||
110 | * |
||
111 | * @var string |
||
112 | */ |
||
113 | protected $_raw_input_stream; |
||
114 | |||
115 | /** |
||
116 | * Parsed input stream data |
||
117 | * |
||
118 | * Parsed from php://input at runtime |
||
119 | * |
||
120 | * @see CI_Input::input_stream() |
||
121 | * @var array |
||
122 | */ |
||
123 | protected $_input_stream; |
||
124 | |||
125 | protected $security; |
||
126 | protected $uni; |
||
127 | |||
128 | // -------------------------------------------------------------------- |
||
129 | |||
130 | /** |
||
131 | * Class constructor |
||
132 | * |
||
133 | * Determines whether to globally enable the XSS processing |
||
134 | * and whether to allow the $_GET array. |
||
135 | * |
||
136 | * @return void |
||
137 | * |
||
138 | * @codeCoverageIgnore |
||
139 | */ |
||
140 | public function __construct() |
||
141 | { |
||
142 | $this->_allow_get_array = (config_item('allow_get_array') !== FALSE); |
||
143 | $this->_enable_xss = (config_item('global_xss_filtering') === TRUE); |
||
144 | $this->_enable_csrf = (config_item('csrf_protection') === TRUE); |
||
145 | $this->_standardize_newlines = (bool) config_item('standardize_newlines'); |
||
146 | |||
147 | $this->security =& load_class('Security', 'core'); |
||
148 | |||
149 | // Do we need the UTF-8 class? |
||
150 | if (UTF8_ENABLED === TRUE) |
||
151 | { |
||
152 | $this->uni =& load_class('Utf8', 'core'); |
||
153 | } |
||
154 | |||
155 | // Sanitize global arrays |
||
156 | $this->_sanitize_globals(); |
||
157 | |||
158 | // CSRF Protection check |
||
159 | if ($this->_enable_csrf === TRUE && ! is_cli()) |
||
160 | { |
||
161 | $this->security->csrf_verify(); |
||
162 | } |
||
163 | |||
164 | log_message('info', 'Input Class Initialized'); |
||
165 | } |
||
166 | |||
167 | // -------------------------------------------------------------------- |
||
168 | |||
169 | /** |
||
170 | * Fetch from array |
||
171 | * |
||
172 | * Internal method used to retrieve values from global arrays. |
||
173 | * |
||
174 | * @param array &$array $_GET, $_POST, $_COOKIE, $_SERVER, etc. |
||
175 | * @param mixed $index Index for item to be fetched from $array |
||
176 | * @param bool $xss_clean Whether to apply XSS filtering |
||
177 | * @return mixed |
||
178 | * |
||
179 | * @codeCoverageIgnore |
||
180 | */ |
||
181 | protected function _fetch_from_array(&$array, $index = NULL, $xss_clean = NULL) |
||
182 | { |
||
183 | is_bool($xss_clean) OR $xss_clean = $this->_enable_xss; |
||
184 | |||
185 | // If $index is NULL, it means that the whole $array is requested |
||
186 | isset($index) OR $index = array_keys($array); |
||
187 | |||
188 | // allow fetching multiple keys at once |
||
189 | if (is_array($index)) |
||
190 | { |
||
191 | $output = array(); |
||
192 | foreach ($index as $key) |
||
193 | { |
||
194 | $output[$key] = $this->_fetch_from_array($array, $key, $xss_clean); |
||
195 | } |
||
196 | |||
197 | return $output; |
||
198 | } |
||
199 | |||
200 | if (isset($array[$index])) |
||
201 | { |
||
202 | $value = $array[$index]; |
||
203 | } |
||
204 | elseif (($count = preg_match_all('/(?:^[^\[]+)|\[[^]]*\]/', $index, $matches)) > 1) // Does the index contain array notation |
||
205 | { |
||
206 | $value = $array; |
||
207 | for ($i = 0; $i < $count; $i++) |
||
208 | { |
||
209 | $key = trim($matches[0][$i], '[]'); |
||
210 | if ($key === '') // Empty notation will return the value as array |
||
211 | { |
||
212 | break; |
||
213 | } |
||
214 | |||
215 | if (isset($value[$key])) |
||
216 | { |
||
217 | $value = $value[$key]; |
||
218 | } |
||
219 | else |
||
220 | { |
||
221 | return NULL; |
||
222 | } |
||
223 | } |
||
224 | } |
||
225 | else |
||
226 | { |
||
227 | return NULL; |
||
228 | } |
||
229 | |||
230 | return ($xss_clean === TRUE) |
||
231 | ? $this->security->xss_clean($value) |
||
232 | : $value; |
||
233 | } |
||
234 | |||
235 | // -------------------------------------------------------------------- |
||
236 | |||
237 | /** |
||
238 | * Fetch an item from the GET array |
||
239 | * |
||
240 | * @param mixed $index Index for item to be fetched from $_GET |
||
241 | * @param bool $xss_clean Whether to apply XSS filtering |
||
242 | * @return mixed |
||
243 | * |
||
244 | * @codeCoverageIgnore |
||
245 | */ |
||
246 | public function get($index = NULL, $xss_clean = NULL) |
||
247 | { |
||
248 | return $this->_fetch_from_array($_GET, $index, $xss_clean); |
||
249 | } |
||
250 | |||
251 | // -------------------------------------------------------------------- |
||
252 | |||
253 | /** |
||
254 | * Fetch an item from the POST array |
||
255 | * |
||
256 | * @param mixed $index Index for item to be fetched from $_POST |
||
257 | * @param bool $xss_clean Whether to apply XSS filtering |
||
258 | * @return mixed |
||
259 | * |
||
260 | * @codeCoverageIgnore |
||
261 | */ |
||
262 | public function post($index = NULL, $xss_clean = NULL) |
||
263 | { |
||
264 | return $this->_fetch_from_array($_POST, $index, $xss_clean); |
||
265 | } |
||
266 | |||
267 | // -------------------------------------------------------------------- |
||
268 | |||
269 | /** |
||
270 | * Fetch an item from POST data with fallback to GET |
||
271 | * |
||
272 | * @param string $index Index for item to be fetched from $_POST or $_GET |
||
273 | * @param bool $xss_clean Whether to apply XSS filtering |
||
274 | * @return mixed |
||
275 | * |
||
276 | * @codeCoverageIgnore |
||
277 | */ |
||
278 | public function post_get($index, $xss_clean = NULL) |
||
284 | |||
285 | // -------------------------------------------------------------------- |
||
286 | |||
287 | /** |
||
288 | * Fetch an item from GET data with fallback to POST |
||
289 | * |
||
290 | * @param string $index Index for item to be fetched from $_GET or $_POST |
||
291 | * @param bool $xss_clean Whether to apply XSS filtering |
||
292 | * @return mixed |
||
293 | * |
||
294 | * @codeCoverageIgnore |
||
295 | */ |
||
296 | public function get_post($index, $xss_clean = NULL) |
||
297 | { |
||
298 | return isset($_GET[$index]) |
||
299 | ? $this->get($index, $xss_clean) |
||
300 | : $this->post($index, $xss_clean); |
||
301 | } |
||
302 | |||
303 | // -------------------------------------------------------------------- |
||
304 | |||
305 | /** |
||
306 | * Fetch an item from the COOKIE array |
||
307 | * |
||
308 | * @param mixed $index Index for item to be fetched from $_COOKIE |
||
309 | * @param bool $xss_clean Whether to apply XSS filtering |
||
310 | * @return mixed |
||
311 | * |
||
312 | * @codeCoverageIgnore |
||
313 | */ |
||
314 | public function cookie($index = NULL, $xss_clean = NULL) |
||
315 | { |
||
316 | return $this->_fetch_from_array($_COOKIE, $index, $xss_clean); |
||
317 | } |
||
318 | |||
319 | // -------------------------------------------------------------------- |
||
320 | |||
321 | /** |
||
322 | * Fetch an item from the SERVER array |
||
323 | * |
||
324 | * @param mixed $index Index for item to be fetched from $_SERVER |
||
325 | * @param bool $xss_clean Whether to apply XSS filtering |
||
326 | * @return mixed |
||
327 | * |
||
328 | * @codeCoverageIgnore |
||
329 | */ |
||
330 | public function server($index, $xss_clean = NULL) |
||
331 | { |
||
332 | return $this->_fetch_from_array($_SERVER, $index, $xss_clean); |
||
333 | } |
||
334 | |||
335 | // ------------------------------------------------------------------------ |
||
336 | |||
337 | /** |
||
338 | * Fetch an item from the php://input stream |
||
339 | * |
||
340 | * Useful when you need to access PUT, DELETE or PATCH request data. |
||
341 | * |
||
342 | * @param string $index Index for item to be fetched |
||
343 | * @param bool $xss_clean Whether to apply XSS filtering |
||
344 | * @return mixed |
||
345 | * |
||
346 | * @codeCoverageIgnore |
||
347 | */ |
||
348 | public function input_stream($index = NULL, $xss_clean = NULL) |
||
361 | |||
362 | // ------------------------------------------------------------------------ |
||
363 | |||
364 | /** |
||
365 | * Set cookie |
||
366 | * |
||
367 | * Accepts an arbitrary number of parameters (up to 7) or an associative |
||
368 | * array in the first parameter containing all the values. |
||
369 | * |
||
370 | * @param string|mixed[] $name Cookie name or an array containing parameters |
||
371 | * @param string $value Cookie value |
||
372 | * @param int $expire Cookie expiration time in seconds |
||
373 | * @param string $domain Cookie domain (e.g.: '.yourdomain.com') |
||
374 | * @param string $path Cookie path (default: '/') |
||
375 | * @param string $prefix Cookie name prefix |
||
376 | * @param bool $secure Whether to only transfer cookies via SSL |
||
377 | * @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript) |
||
378 | * @return void |
||
379 | * |
||
380 | * modified by ci-phpunit-test |
||
381 | */ |
||
382 | public function set_cookie($name, $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL) |
||
383 | { |
||
384 | if (is_array($name)) |
||
385 | { |
||
386 | // always leave 'name' in last place, as the loop will break otherwise, due to $$item |
||
387 | foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item) |
||
388 | { |
||
389 | if (isset($name[$item])) |
||
390 | { |
||
391 | $$item = $name[$item]; |
||
392 | } |
||
393 | } |
||
394 | } |
||
395 | |||
396 | if ($prefix === '' && config_item('cookie_prefix') !== '') |
||
397 | { |
||
398 | $prefix = config_item('cookie_prefix'); |
||
399 | } |
||
400 | |||
401 | if ($domain == '' && config_item('cookie_domain') != '') |
||
402 | { |
||
403 | $domain = config_item('cookie_domain'); |
||
404 | } |
||
405 | |||
406 | if ($path === '/' && config_item('cookie_path') !== '/') |
||
407 | { |
||
408 | $path = config_item('cookie_path'); |
||
409 | } |
||
410 | |||
411 | $secure = ($secure === NULL && config_item('cookie_secure') !== NULL) |
||
412 | ? (bool) config_item('cookie_secure') |
||
413 | : (bool) $secure; |
||
414 | |||
415 | $httponly = ($httponly === NULL && config_item('cookie_httponly') !== NULL) |
||
416 | ? (bool) config_item('cookie_httponly') |
||
417 | : (bool) $httponly; |
||
418 | |||
419 | if ( ! is_numeric($expire)) |
||
420 | { |
||
421 | $expire = time() - 86500; |
||
422 | } |
||
423 | else |
||
424 | { |
||
425 | $expire = ($expire > 0) ? time() + $expire : 0; |
||
426 | } |
||
427 | |||
428 | // setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly); |
||
429 | |||
430 | // Save cookie in Output object |
||
431 | // added by ci-phpunit-test |
||
432 | $CI =& get_instance(); |
||
433 | $output = $CI->output; |
||
434 | $output->_cookies[$prefix.$name][] = [ |
||
435 | 'value' => $value, |
||
436 | 'expire' => $expire, |
||
437 | 'path' => $path, |
||
438 | 'domain' => $domain, |
||
439 | 'secure' => $secure, |
||
440 | 'httponly' => $httponly, |
||
441 | ]; |
||
442 | } |
||
443 | |||
444 | // -------------------------------------------------------------------- |
||
445 | |||
446 | /** |
||
447 | * Fetch the IP Address |
||
448 | * |
||
449 | * Determines and validates the visitor's IP address. |
||
450 | * |
||
451 | * @return string IP address |
||
452 | * |
||
453 | * @codeCoverageIgnore |
||
454 | */ |
||
455 | public function ip_address() |
||
456 | { |
||
457 | if ($this->ip_address !== FALSE) |
||
458 | { |
||
459 | return $this->ip_address; |
||
460 | } |
||
461 | |||
462 | $proxy_ips = config_item('proxy_ips'); |
||
463 | if ( ! empty($proxy_ips) && ! is_array($proxy_ips)) |
||
464 | { |
||
465 | $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips)); |
||
466 | } |
||
467 | |||
468 | $this->ip_address = $this->server('REMOTE_ADDR'); |
||
469 | |||
470 | if ($proxy_ips) |
||
471 | { |
||
472 | foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header) |
||
473 | { |
||
474 | if (($spoof = $this->server($header)) !== NULL) |
||
475 | { |
||
476 | // Some proxies typically list the whole chain of IP |
||
477 | // addresses through which the client has reached us. |
||
478 | // e.g. client_ip, proxy_ip1, proxy_ip2, etc. |
||
479 | sscanf($spoof, '%[^,]', $spoof); |
||
480 | |||
481 | if ( ! $this->valid_ip($spoof)) |
||
482 | { |
||
483 | $spoof = NULL; |
||
484 | } |
||
485 | else |
||
486 | { |
||
487 | break; |
||
488 | } |
||
489 | } |
||
490 | } |
||
491 | |||
492 | if ($spoof) |
||
493 | { |
||
494 | for ($i = 0, $c = count($proxy_ips); $i < $c; $i++) |
||
495 | { |
||
496 | // Check if we have an IP address or a subnet |
||
497 | if (strpos($proxy_ips[$i], '/') === FALSE) |
||
498 | { |
||
499 | // An IP address (and not a subnet) is specified. |
||
500 | // We can compare right away. |
||
501 | if ($proxy_ips[$i] === $this->ip_address) |
||
502 | { |
||
503 | $this->ip_address = $spoof; |
||
504 | break; |
||
505 | } |
||
506 | |||
507 | continue; |
||
508 | } |
||
509 | |||
510 | // We have a subnet ... now the heavy lifting begins |
||
511 | isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.'; |
||
512 | |||
513 | // If the proxy entry doesn't match the IP protocol - skip it |
||
514 | if (strpos($proxy_ips[$i], $separator) === FALSE) |
||
515 | { |
||
516 | continue; |
||
517 | } |
||
518 | |||
519 | // Convert the REMOTE_ADDR IP address to binary, if needed |
||
520 | if ( ! isset($ip, $sprintf)) |
||
521 | { |
||
522 | if ($separator === ':') |
||
523 | { |
||
524 | // Make sure we're have the "full" IPv6 format |
||
525 | $ip = explode(':', |
||
526 | str_replace('::', |
||
527 | str_repeat(':', 9 - substr_count($this->ip_address, ':')), |
||
528 | $this->ip_address |
||
529 | ) |
||
530 | ); |
||
531 | |||
532 | for ($j = 0; $j < 8; $j++) |
||
533 | { |
||
534 | $ip[$j] = intval($ip[$j], 16); |
||
535 | } |
||
536 | |||
537 | $sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b'; |
||
538 | } |
||
539 | else |
||
540 | { |
||
541 | $ip = explode('.', $this->ip_address); |
||
542 | $sprintf = '%08b%08b%08b%08b'; |
||
543 | } |
||
544 | |||
545 | $ip = vsprintf($sprintf, $ip); |
||
546 | } |
||
547 | |||
548 | // Split the netmask length off the network address |
||
549 | sscanf($proxy_ips[$i], '%[^/]/%d', $netaddr, $masklen); |
||
550 | |||
551 | // Again, an IPv6 address is most likely in a compressed form |
||
552 | if ($separator === ':') |
||
553 | { |
||
554 | $netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr)); |
||
555 | for ($j = 0; $j < 8; $j++) |
||
556 | { |
||
557 | $netaddr[$j] = intval($netaddr[$j], 16); |
||
558 | } |
||
559 | } |
||
560 | else |
||
561 | { |
||
562 | $netaddr = explode('.', $netaddr); |
||
563 | } |
||
564 | |||
565 | // Convert to binary and finally compare |
||
566 | if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0) |
||
567 | { |
||
568 | $this->ip_address = $spoof; |
||
569 | break; |
||
570 | } |
||
571 | } |
||
572 | } |
||
573 | } |
||
574 | |||
575 | if ( ! $this->valid_ip($this->ip_address)) |
||
576 | { |
||
577 | return $this->ip_address = '0.0.0.0'; |
||
578 | } |
||
579 | |||
580 | return $this->ip_address; |
||
581 | } |
||
582 | |||
583 | // -------------------------------------------------------------------- |
||
584 | |||
585 | /** |
||
586 | * Validate IP Address |
||
587 | * |
||
588 | * @param string $ip IP address |
||
589 | * @param string $which IP protocol: 'ipv4' or 'ipv6' |
||
590 | * @return bool |
||
591 | * |
||
592 | * @codeCoverageIgnore |
||
593 | */ |
||
594 | public function valid_ip($ip, $which = '') |
||
595 | { |
||
596 | switch (strtolower($which)) |
||
597 | { |
||
598 | case 'ipv4': |
||
599 | $which = FILTER_FLAG_IPV4; |
||
600 | break; |
||
601 | case 'ipv6': |
||
602 | $which = FILTER_FLAG_IPV6; |
||
603 | break; |
||
604 | default: |
||
605 | $which = NULL; |
||
606 | break; |
||
607 | } |
||
608 | |||
609 | return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which); |
||
610 | } |
||
611 | |||
612 | // -------------------------------------------------------------------- |
||
613 | |||
614 | /** |
||
615 | * Fetch User Agent string |
||
616 | * |
||
617 | * @return string|null User Agent string or NULL if it doesn't exist |
||
618 | * |
||
619 | * @codeCoverageIgnore |
||
620 | */ |
||
621 | public function user_agent($xss_clean = NULL) |
||
622 | { |
||
623 | return $this->_fetch_from_array($_SERVER, 'HTTP_USER_AGENT', $xss_clean); |
||
624 | } |
||
625 | |||
626 | // -------------------------------------------------------------------- |
||
627 | |||
628 | /** |
||
629 | * Sanitize Globals |
||
630 | * |
||
631 | * Internal method serving for the following purposes: |
||
632 | * |
||
633 | * - Unsets $_GET data, if query strings are not enabled |
||
634 | * - Cleans POST, COOKIE and SERVER data |
||
635 | * - Standardizes newline characters to PHP_EOL |
||
636 | * |
||
637 | * @return void |
||
638 | * |
||
639 | * @codeCoverageIgnore |
||
640 | */ |
||
641 | protected function _sanitize_globals() |
||
642 | { |
||
643 | // Is $_GET data allowed? If not we'll set the $_GET to an empty array |
||
644 | if ($this->_allow_get_array === FALSE) |
||
645 | { |
||
646 | $_GET = array(); |
||
647 | } |
||
648 | elseif (is_array($_GET)) |
||
649 | { |
||
650 | foreach ($_GET as $key => $val) |
||
651 | { |
||
652 | $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); |
||
653 | } |
||
654 | } |
||
655 | |||
656 | // Clean $_POST Data |
||
657 | if (is_array($_POST)) |
||
658 | { |
||
659 | foreach ($_POST as $key => $val) |
||
660 | { |
||
661 | $_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); |
||
662 | } |
||
663 | } |
||
664 | |||
665 | // Clean $_COOKIE Data |
||
666 | if (is_array($_COOKIE)) |
||
667 | { |
||
668 | // Also get rid of specially treated cookies that might be set by a server |
||
669 | // or silly application, that are of no use to a CI application anyway |
||
670 | // but that when present will trip our 'Disallowed Key Characters' alarm |
||
671 | // http://www.ietf.org/rfc/rfc2109.txt |
||
672 | // note that the key names below are single quoted strings, and are not PHP variables |
||
673 | unset( |
||
674 | $_COOKIE['$Version'], |
||
675 | $_COOKIE['$Path'], |
||
676 | $_COOKIE['$Domain'] |
||
677 | ); |
||
678 | |||
679 | foreach ($_COOKIE as $key => $val) |
||
680 | { |
||
681 | if (($cookie_key = $this->_clean_input_keys($key)) !== FALSE) |
||
682 | { |
||
683 | $_COOKIE[$cookie_key] = $this->_clean_input_data($val); |
||
684 | } |
||
685 | else |
||
686 | { |
||
687 | unset($_COOKIE[$key]); |
||
688 | } |
||
689 | } |
||
690 | } |
||
691 | |||
692 | // Sanitize PHP_SELF |
||
693 | $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']); |
||
694 | |||
695 | log_message('debug', 'Global POST, GET and COOKIE data sanitized'); |
||
696 | } |
||
697 | |||
698 | // -------------------------------------------------------------------- |
||
699 | |||
700 | /** |
||
701 | * Clean Input Data |
||
702 | * |
||
703 | * Internal method that aids in escaping data and |
||
704 | * standardizing newline characters to PHP_EOL. |
||
705 | * |
||
706 | * @param string|string[] $str Input string(s) |
||
707 | * @return string |
||
708 | * |
||
709 | * @codeCoverageIgnore |
||
710 | */ |
||
711 | protected function _clean_input_data($str) |
||
712 | { |
||
713 | if (is_array($str)) |
||
714 | { |
||
715 | $new_array = array(); |
||
716 | foreach (array_keys($str) as $key) |
||
717 | { |
||
718 | $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($str[$key]); |
||
719 | } |
||
720 | return $new_array; |
||
721 | } |
||
722 | |||
723 | /* We strip slashes if magic quotes is on to keep things consistent |
||
724 | |||
725 | NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and |
||
726 | it will probably not exist in future versions at all. |
||
727 | */ |
||
728 | if ( ! is_php('5.4') && get_magic_quotes_gpc()) |
||
729 | { |
||
730 | $str = stripslashes($str); |
||
731 | } |
||
732 | |||
733 | // Clean UTF-8 if supported |
||
734 | if (UTF8_ENABLED === TRUE) |
||
735 | { |
||
736 | $str = $this->uni->clean_string($str); |
||
737 | } |
||
738 | |||
739 | // Remove control characters |
||
740 | $str = remove_invisible_characters($str, FALSE); |
||
741 | |||
742 | // Standardize newlines if needed |
||
743 | if ($this->_standardize_newlines === TRUE) |
||
744 | { |
||
745 | return preg_replace('/(?:\r\n|[\r\n])/', PHP_EOL, $str); |
||
746 | } |
||
747 | |||
748 | return $str; |
||
749 | } |
||
750 | |||
751 | // -------------------------------------------------------------------- |
||
752 | |||
753 | /** |
||
754 | * Clean Keys |
||
755 | * |
||
756 | * Internal method that helps to prevent malicious users |
||
757 | * from trying to exploit keys we make sure that keys are |
||
758 | * only named with alpha-numeric text and a few other items. |
||
759 | * |
||
760 | * @param string $str Input string |
||
761 | * @param bool $fatal Whether to terminate script exection |
||
762 | * or to return FALSE if an invalid |
||
763 | * key is encountered |
||
764 | * @return string|bool |
||
765 | * |
||
766 | * @codeCoverageIgnore |
||
767 | */ |
||
768 | protected function _clean_input_keys($str, $fatal = TRUE) |
||
769 | { |
||
770 | if ( ! preg_match('/^[a-z0-9:_\/|-]+$/i', $str)) |
||
771 | { |
||
772 | if ($fatal === TRUE) |
||
773 | { |
||
774 | return FALSE; |
||
775 | } |
||
776 | else |
||
777 | { |
||
778 | set_status_header(503); |
||
779 | echo 'Disallowed Key Characters.'; |
||
780 | exit(7); // EXIT_USER_INPUT |
||
781 | } |
||
782 | } |
||
783 | |||
784 | // Clean UTF-8 if supported |
||
785 | if (UTF8_ENABLED === TRUE) |
||
786 | { |
||
787 | return $this->uni->clean_string($str); |
||
788 | } |
||
789 | |||
790 | return $str; |
||
791 | } |
||
792 | |||
793 | // -------------------------------------------------------------------- |
||
794 | |||
795 | /** |
||
796 | * Request Headers |
||
797 | * |
||
798 | * @param bool $xss_clean Whether to apply XSS filtering |
||
799 | * @return array |
||
800 | * |
||
801 | * @codeCoverageIgnore |
||
802 | */ |
||
803 | public function request_headers($xss_clean = FALSE) |
||
804 | { |
||
805 | // If header is already defined, return it immediately |
||
806 | if ( ! empty($this->headers)) |
||
807 | { |
||
808 | return $this->_fetch_from_array($this->headers, NULL, $xss_clean); |
||
809 | } |
||
810 | |||
811 | // In Apache, you can simply call apache_request_headers() |
||
812 | if (function_exists('apache_request_headers')) |
||
813 | { |
||
814 | $this->headers = apache_request_headers(); |
||
815 | } |
||
816 | else |
||
817 | { |
||
818 | isset($_SERVER['CONTENT_TYPE']) && $this->headers['Content-Type'] = $_SERVER['CONTENT_TYPE']; |
||
819 | |||
820 | foreach ($_SERVER as $key => $val) |
||
821 | { |
||
822 | if (sscanf($key, 'HTTP_%s', $header) === 1) |
||
823 | { |
||
824 | // take SOME_HEADER and turn it into Some-Header |
||
825 | $header = str_replace('_', ' ', strtolower($header)); |
||
826 | $header = str_replace(' ', '-', ucwords($header)); |
||
827 | |||
828 | $this->headers[$header] = $_SERVER[$key]; |
||
829 | } |
||
830 | } |
||
831 | } |
||
832 | |||
833 | return $this->_fetch_from_array($this->headers, NULL, $xss_clean); |
||
834 | } |
||
835 | |||
836 | // -------------------------------------------------------------------- |
||
837 | |||
838 | /** |
||
839 | * Get Request Header |
||
840 | * |
||
841 | * Returns the value of a single member of the headers class member |
||
842 | * |
||
843 | * @param string $index Header name |
||
844 | * @param bool $xss_clean Whether to apply XSS filtering |
||
845 | * @return string|null The requested header on success or NULL on failure |
||
846 | * |
||
847 | * modified by ci-phpunit-test |
||
848 | */ |
||
849 | public function get_request_header($index, $xss_clean = FALSE) |
||
850 | { |
||
851 | // static $headers; |
||
852 | |||
853 | if ( ! isset($headers)) |
||
854 | { |
||
855 | empty($this->headers) && $this->request_headers(); |
||
856 | foreach ($this->headers as $key => $value) |
||
857 | { |
||
858 | $headers[strtolower($key)] = $value; |
||
859 | } |
||
860 | } |
||
861 | |||
862 | $index = strtolower($index); |
||
863 | |||
864 | if ( ! isset($headers[$index])) |
||
865 | { |
||
866 | return NULL; |
||
867 | } |
||
868 | |||
869 | return ($xss_clean === TRUE) |
||
870 | ? $this->security->xss_clean($headers[$index]) |
||
871 | : $headers[$index]; |
||
872 | } |
||
873 | |||
874 | // -------------------------------------------------------------------- |
||
875 | |||
876 | /** |
||
877 | * Is AJAX request? |
||
878 | * |
||
879 | * Test to see if a request contains the HTTP_X_REQUESTED_WITH header. |
||
880 | * |
||
881 | * @return bool |
||
882 | * |
||
883 | * @codeCoverageIgnore |
||
884 | */ |
||
885 | public function is_ajax_request() |
||
886 | { |
||
887 | return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'); |
||
888 | } |
||
889 | |||
890 | // -------------------------------------------------------------------- |
||
891 | |||
892 | /** |
||
893 | * Is CLI request? |
||
894 | * |
||
895 | * Test to see if a request was made from the command line. |
||
896 | * |
||
897 | * @deprecated 3.0.0 Use is_cli() instead |
||
898 | * @return bool |
||
899 | * |
||
900 | * @codeCoverageIgnore |
||
901 | */ |
||
902 | public function is_cli_request() |
||
903 | { |
||
904 | return is_cli(); |
||
905 | } |
||
906 | |||
907 | // -------------------------------------------------------------------- |
||
908 | |||
909 | /** |
||
910 | * Get Request Method |
||
911 | * |
||
912 | * Return the request method |
||
913 | * |
||
914 | * @param bool $upper Whether to return in upper or lower case |
||
915 | * (default: FALSE) |
||
916 | * @return string |
||
917 | * |
||
918 | * @codeCoverageIgnore |
||
919 | */ |
||
920 | public function method($upper = FALSE) |
||
926 | |||
927 | // ------------------------------------------------------------------------ |
||
928 | |||
929 | /** |
||
930 | * Magic __get() |
||
931 | * |
||
932 | * Allows read access to protected properties |
||
933 | * |
||
934 | * @param string $name |
||
935 | * @return mixed |
||
936 | * |
||
937 | * @codeCoverageIgnore |
||
938 | */ |
||
939 | public function __get($name) |
||
951 | |||
952 | } |
||
953 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.