Issues (1240)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

system/libraries/Input.php (18 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php defined('SYSPATH') or die('No direct access allowed.');
2
/**
3
 * Input library.
4
 *
5
 * $Id: Input.php 4346 2009-05-11 17:08:15Z zombor $
6
 *
7
 * @package    Core
8
 * @author     Kohana Team
9
 * @copyright  (c) 2007-2008 Kohana Team
10
 * @license    http://kohanaphp.com/license.html
11
 */
12
class Input_Core
13
{
14
15
    // Enable or disable automatic XSS cleaning
16
    protected $use_xss_clean = false;
17
18
    // Are magic quotes enabled?
19
    protected $magic_quotes_gpc = false;
20
21
    // IP address of current user
22
    public $ip_address;
23
24
    // Input singleton
25
    protected static $instance;
26
27
    /**
28
     * Retrieve a singleton instance of Input. This will always be the first
29
     * created instance of this class.
30
     *
31
     * @return  object
32
     */
33
    public static function instance()
34
    {
35
        if (Input::$instance === null) {
36
            // Create a new instance
37
            return new Input;
38
        }
39
40
        return Input::$instance;
41
    }
42
43
    /**
44
     * Sanitizes global GET, POST and COOKIE data. Also takes care of
45
     * magic_quotes and register_globals, if they have been enabled.
46
     *
47
     * @return  void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
48
     */
49
    public function __construct()
0 ignored issues
show
__construct uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
__construct uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
__construct uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
__construct uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
__construct uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
50
    {
51
        // Use XSS clean?
52
        $this->use_xss_clean = (bool) Kohana::config('core.global_xss_filtering');
53
54
        if (Input::$instance === null) {
55
            // magic_quotes_runtime is enabled
56
            if (get_magic_quotes_runtime()) {
57
                set_magic_quotes_runtime(0);
58
                Kohana::log('debug', 'Disable magic_quotes_runtime! It is evil and deprecated: http://php.net/magic_quotes');
59
            }
60
61
            // magic_quotes_gpc is enabled
62
            if (get_magic_quotes_gpc()) {
63
                $this->magic_quotes_gpc = true;
64
                Kohana::log('debug', 'Disable magic_quotes_gpc! It is evil and deprecated: http://php.net/magic_quotes');
65
            }
66
67
            // register_globals is enabled
68
            if (ini_get('register_globals')) {
69
                if (isset($_REQUEST['GLOBALS'])) {
70
                    // Prevent GLOBALS override attacks
71
                    exit('Global variable overload attack.');
0 ignored issues
show
Coding Style Compatibility introduced by
The method __construct() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
72
                }
73
74
                // Destroy the REQUEST global
75
                $_REQUEST = array();
76
77
                // These globals are standard and should not be removed
78
                $preserve = array('GLOBALS', '_REQUEST', '_GET', '_POST', '_FILES', '_COOKIE', '_SERVER', '_ENV', '_SESSION');
79
80
                // This loop has the same effect as disabling register_globals
81
                foreach (array_diff(array_keys($GLOBALS), $preserve) as $key) {
82
                    global $$key;
83
                    $$key = null;
84
85
                    // Unset the global variable
86
                    unset($GLOBALS[$key], $$key);
87
                }
88
89
                // Warn the developer about register globals
90
                Kohana::log('debug', 'Disable register_globals! It is evil and deprecated: http://php.net/register_globals');
91
            }
92
93 View Code Duplication
            if (is_array($_GET)) {
0 ignored issues
show
This code seems to be duplicated across your project.

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.

Loading history...
94
                foreach ($_GET as $key => $val) {
95
                    // Sanitize $_GET
96
                    $_GET[$this->clean_input_keys($key)] = $this->clean_input_data($val);
97
                }
98
            } else {
99
                $_GET = array();
100
            }
101
102 View Code Duplication
            if (is_array($_POST)) {
0 ignored issues
show
This code seems to be duplicated across your project.

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.

Loading history...
103
                foreach ($_POST as $key => $val) {
104
                    // Sanitize $_POST
105
                    $_POST[$this->clean_input_keys($key)] = $this->clean_input_data($val);
106
                }
107
            } else {
108
                $_POST = array();
109
            }
110
111
            if (is_array($_COOKIE)) {
112
                foreach ($_COOKIE as $key => $val) {
113
                    // Ignore special attributes in RFC2109 compliant cookies
114
                    if ($key == '$Version' or $key == '$Path' or $key == '$Domain') {
115
                        continue;
116
                    }
117
118
                    // Sanitize $_COOKIE
119
                    $_COOKIE[$this->clean_input_keys($key)] = $this->clean_input_data($val);
120
                }
121
            } else {
122
                $_COOKIE = array();
123
            }
124
125
            // Create a singleton
126
            Input::$instance = $this;
127
128
            Kohana::log('debug', 'Global GET, POST and COOKIE data sanitized');
129
        }
130
    }
131
132
    /**
133
     * Fetch an item from the $_GET array.
134
     *
135
     * @param   string   key to find
136
     * @param   mixed    default value
137
     * @param   boolean  XSS clean the value
138
     * @return  mixed
139
     */
140
    public function get($key = array(), $default = null, $xss_clean = false)
0 ignored issues
show
get uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
141
    {
142
        return $this->search_array($_GET, $key, $default, $xss_clean);
143
    }
144
145
    /**
146
     * Fetch an item from the $_POST array.
147
     *
148
     * @param   string   key to find
149
     * @param   mixed    default value
150
     * @param   boolean  XSS clean the value
151
     * @return  mixed
152
     */
153
    public function post($key = array(), $default = null, $xss_clean = false)
0 ignored issues
show
post uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
154
    {
155
        return $this->search_array($_POST, $key, $default, $xss_clean);
156
    }
157
158
    /**
159
     * Fetch an item from the $_COOKIE array.
160
     *
161
     * @param   string   key to find
162
     * @param   mixed    default value
163
     * @param   boolean  XSS clean the value
164
     * @return  mixed
165
     */
166
    public function cookie($key = array(), $default = null, $xss_clean = false)
0 ignored issues
show
cookie uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
167
    {
168
        return $this->search_array($_COOKIE, $key, $default, $xss_clean);
169
    }
170
171
    /**
172
     * Fetch an item from the $_SERVER array.
173
     *
174
     * @param   string   key to find
175
     * @param   mixed    default value
176
     * @param   boolean  XSS clean the value
177
     * @return  mixed
178
     */
179
    public function server($key = array(), $default = null, $xss_clean = false)
0 ignored issues
show
server uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
180
    {
181
        return $this->search_array($_SERVER, $key, $default, $xss_clean);
182
    }
183
184
    /**
185
     * Fetch an item from a global array.
186
     *
187
     * @param   array    array to search
188
     * @param   string   key to find
189
     * @param   mixed    default value
190
     * @param   boolean  XSS clean the value
191
     * @return  mixed
192
     */
193
    protected function search_array($array, $key, $default = null, $xss_clean = false)
194
    {
195
        if ($key === array()) {
196
            return $array;
197
        }
198
199
        if (! isset($array[$key])) {
200
            return $default;
201
        }
202
203
        // Get the value
204
        $value = $array[$key];
205
206
        if ($this->use_xss_clean === false and $xss_clean === true) {
207
            // XSS clean the value
208
            $value = $this->xss_clean($value);
209
        }
210
211
        return $value;
212
    }
213
214
    /**
215
     * Fetch the IP Address.
216
     *
217
     * @return string
218
     */
219
    public function ip_address()
220
    {
221
        if ($this->ip_address !== null) {
222
            return $this->ip_address;
223
        }
224
225
        // Server keys that could contain the client IP address
226
        $keys = array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR');
227
228
        foreach ($keys as $key) {
229
            if ($ip = $this->server($key)) {
0 ignored issues
show
$key is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
230
                $this->ip_address = $ip;
231
232
                // An IP address has been found
233
                break;
234
            }
235
        }
236
237
        if ($comma = strrpos($this->ip_address, ',') !== false) {
238
            $this->ip_address = substr($this->ip_address, $comma + 1);
239
        }
240
241
        if (! valid::ip($this->ip_address)) {
242
            // Use an empty IP
243
            $this->ip_address = '0.0.0.0';
244
        }
245
246
        return $this->ip_address;
247
    }
248
249
    /**
250
     * Clean cross site scripting exploits from string.
251
     * HTMLPurifier may be used if installed, otherwise defaults to built in method.
252
     * Note - This function should only be used to deal with data upon submission.
253
     * It's not something that should be used for general runtime processing
254
     * since it requires a fair amount of processing overhead.
255
     *
256
     * @param   string  data to clean
257
     * @param   string  xss_clean method to use ('htmlpurifier' or defaults to built-in method)
258
     * @return  string
259
     */
260
    public function xss_clean($data, $tool = null)
261
    {
262
        if ($tool === null) {
263
            // Use the default tool
264
            $tool = Kohana::config('core.global_xss_filtering');
265
        }
266
267
        if (is_array($data)) {
268
            foreach ($data as $key => $val) {
269
                $data[$key] = $this->xss_clean($val, $tool);
270
            }
271
272
            return $data;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $data; (array) is incompatible with the return type documented by Input_Core::xss_clean of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
273
        }
274
275
        // Do not clean empty strings
276
        if (trim($data) === '') {
277
            return $data;
278
        }
279
280
        if ($tool === true) {
281
            // NOTE: This is necessary because switch is NOT type-sensative!
282
            $tool = 'default';
283
        }
284
285
        switch ($tool) {
286
            case 'htmlpurifier':
287
                /**
288
                 * @todo License should go here, http://htmlpurifier.org/
289
                 */
290
                if (! class_exists('HTMLPurifier_Config', false)) {
291
                    // Load HTMLPurifier
292
                    require Kohana::find_file('vendor', 'htmlpurifier/HTMLPurifier.auto', true);
293
                    require 'HTMLPurifier.func.php';
294
                }
295
296
                // Set configuration
297
                $config = HTMLPurifier_Config::createDefault();
298
                $config->set('HTML', 'TidyLevel', 'none'); // Only XSS cleaning now
299
300
                // Run HTMLPurifier
301
                $data = HTMLPurifier($data, $config);
302
            break;
303
            default:
304
                // http://svn.bitflux.ch/repos/public/popoon/trunk/classes/externalinput.php
305
                // +----------------------------------------------------------------------+
306
                // | Copyright (c) 2001-2006 Bitflux GmbH                                 |
307
                // +----------------------------------------------------------------------+
308
                // | Licensed under the Apache License, Version 2.0 (the "License");      |
309
                // | you may not use this file except in compliance with the License.     |
310
                // | You may obtain a copy of the License at                              |
311
                // | http://www.apache.org/licenses/LICENSE-2.0                           |
312
                // | Unless required by applicable law or agreed to in writing, software  |
313
                // | distributed under the License is distributed on an "AS IS" BASIS,    |
314
                // | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or      |
315
                // | implied. See the License for the specific language governing         |
316
                // | permissions and limitations under the License.                       |
317
                // +----------------------------------------------------------------------+
318
                // | Author: Christian Stocker <[email protected]>                        |
319
                // +----------------------------------------------------------------------+
320
                //
321
                // Kohana Modifications:
322
                // * Changed double quotes to single quotes, changed indenting and spacing
323
                // * Removed magic_quotes stuff
324
                // * Increased regex readability:
325
                //   * Used delimeters that aren't found in the pattern
326
                //   * Removed all unneeded escapes
327
                //   * Deleted U modifiers and swapped greediness where needed
328
                // * Increased regex speed:
329
                //   * Made capturing parentheses non-capturing where possible
330
                //   * Removed parentheses where possible
331
                //   * Split up alternation alternatives
332
                //   * Made some quantifiers possessive
333
334
                // Fix &entity\n;
335
                $data = str_replace(array('&amp;', '&lt;', '&gt;'), array('&amp;amp;', '&amp;lt;', '&amp;gt;'), $data);
336
                $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
337
                $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
338
                $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
339
340
                // Remove any attribute starting with "on" or xmlns
341
                $data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
342
343
                // Remove javascript: and vbscript: protocols
344
                $data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
345
                $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
346
                $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);
347
348
                // Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
349
                $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
350
                $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
351
                $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);
352
353
                // Remove namespaced elements (we do not need them)
354
                $data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
355
356
                do {
357
                    // Remove really unwanted tags
358
                    $old_data = $data;
359
                    $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
360
                } while ($old_data !== $data);
361
            break;
362
        }
363
364
        return $data;
365
    }
366
367
    /**
368
     * This is a helper method. It enforces W3C specifications for allowed
369
     * key name strings, to prevent malicious exploitation.
370
     *
371
     * @param   string  string to clean
372
     * @return  string
373
     */
374
    public function clean_input_keys($str)
375
    {
376
        $chars = PCRE_UNICODE_PROPERTIES ? '\pL' : 'a-zA-Z';
377
378
        if (! preg_match('#^['.$chars.'0-9:_.-]++$#uD', $str)) {
379
            exit('Disallowed key characters in global data.');
0 ignored issues
show
Coding Style Compatibility introduced by
The method clean_input_keys() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
380
        }
381
382
        return $str;
383
    }
384
385
    /**
386
     * This is a helper method. It escapes data and forces all newline
387
     * characters to "\n".
388
     *
389
     * @param   unknown_type  string to clean
390
     * @return  string
391
     */
392
    public function clean_input_data($str)
393
    {
394 View Code Duplication
        if (is_array($str)) {
0 ignored issues
show
This code seems to be duplicated across your project.

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.

Loading history...
395
            $new_array = array();
396
            foreach ($str as $key => $val) {
397
                // Recursion!
398
                $new_array[$this->clean_input_keys($key)] = $this->clean_input_data($val);
399
            }
400
            return $new_array;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $new_array; (array) is incompatible with the return type documented by Input_Core::clean_input_data of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
401
        }
402
403
        if ($this->magic_quotes_gpc === true) {
404
            // Remove annoying magic quotes
405
            $str = stripslashes($str);
406
        }
407
408
        if ($this->use_xss_clean === true) {
409
            $str = $this->xss_clean($str);
410
        }
411
412
        if (strpos($str, "\r") !== false) {
413
            // Standardize newlines
414
            $str = str_replace(array("\r\n", "\r"), "\n", $str);
415
        }
416
417
        return $str;
418
    }
419
} // End Input Class
420