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/helpers/request.php (11 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
 * Request helper class.
4
 *
5
 * $Id: request.php 4355 2009-05-15 17:18:28Z kiall $
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 request_Core
13
{
14
15
    // Possible HTTP methods
16
    protected static $http_methods = array('get', 'head', 'options', 'post', 'put', 'delete');
17
18
    // Content types from client's HTTP Accept request header (array)
19
    protected static $accept_types;
20
21
    /**
22
     * Returns the HTTP referrer, or the default if the referrer is not set.
23
     *
24
     * @param   mixed   default to return
25
     * @return  string
26
     */
27
    public static function referrer($default = false)
0 ignored issues
show
referrer 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...
28
    {
29
        if (! empty($_SERVER['HTTP_REFERER'])) {
30
            // Set referrer
31
            $ref = $_SERVER['HTTP_REFERER'];
32
33
            if (strpos($ref, url::base(false)) === 0) {
34
                // Remove the base URL from the referrer
35
                $ref = substr($ref, strlen(url::base(false)));
36
            }
37
        }
38
39
        return isset($ref) ? $ref : $default;
40
    }
41
42
    /**
43
     * Returns the current request protocol, based on $_SERVER['https']. In CLI
44
     * mode, NULL will be returned.
45
     *
46
     * @return  string
0 ignored issues
show
Should the return type not be null|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
47
     */
48
    public static function protocol()
0 ignored issues
show
protocol 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...
49
    {
50
        if (PHP_SAPI === 'cli') {
51
            return null;
52
        } elseif (! empty($_SERVER['HTTPS']) and $_SERVER['HTTPS'] === 'on') {
53
            return 'https';
54
        } else {
55
            return 'http';
56
        }
57
    }
58
59
    /**
60
     * Tests if the current request is an AJAX request by checking the X-Requested-With HTTP
61
     * request header that most popular JS frameworks now set for AJAX calls.
62
     *
63
     * @return  boolean
64
     */
65
    public static function is_ajax()
0 ignored issues
show
is_ajax 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...
66
    {
67
        return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) and strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
68
    }
69
70
    /**
71
     * Returns current request method.
72
     *
73
     * @throws  Kohana_Exception in case of an unknown request method
74
     * @return  string
75
     */
76
    public static function method()
0 ignored issues
show
method 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...
77
    {
78
        $method = strtolower($_SERVER['REQUEST_METHOD']);
79
80
        if (! in_array($method, request::$http_methods)) {
81
            throw new Kohana_Exception('request.unknown_method', $method);
82
        }
83
84
        return $method;
85
    }
86
87
    /**
88
     * Returns boolean of whether client accepts content type.
89
     *
90
     * @param   string   content type
91
     * @param   boolean  set to TRUE to disable wildcard checking
92
     * @return  boolean
93
     */
94
    public static function accepts($type = null, $explicit_check = false)
95
    {
96
        request::parse_accept_header();
97
98
        if ($type === null) {
99
            return request::$accept_types;
100
        }
101
102
        return (request::accepts_at_quality($type, $explicit_check) > 0);
103
    }
104
105
    /**
106
     * Compare the q values for given array of content types and return the one with the highest value.
107
     * If items are found to have the same q value, the first one encountered in the given array wins.
108
     * If all items in the given array have a q value of 0, FALSE is returned.
109
     *
110
     * @param   array    content types
111
     * @param   boolean  set to TRUE to disable wildcard checking
112
     * @return  mixed    string mime type with highest q value, FALSE if none of the given types are accepted
0 ignored issues
show
Consider making the return type a bit more specific; maybe use integer|string|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
113
     */
114
    public static function preferred_accept($types, $explicit_check = false)
115
    {
116
        // Initialize
117
        $mime_types = array();
118
        $max_q = 0;
119
        $preferred = false;
120
121
        // Load q values for all given content types
122
        foreach (array_unique($types) as $type) {
123
            $mime_types[$type] = request::accepts_at_quality($type, $explicit_check);
124
        }
125
126
        // Look for the highest q value
127
        foreach ($mime_types as $type => $q) {
128
            if ($q > $max_q) {
129
                $max_q = $q;
130
                $preferred = $type;
131
            }
132
        }
133
134
        return $preferred;
135
    }
136
137
    /**
138
     * Returns quality factor at which the client accepts content type.
139
     *
140
     * @param   string   content type (e.g. "image/jpg", "jpg")
141
     * @param   boolean  set to TRUE to disable wildcard checking
142
     * @return  integer|float
143
     */
144
    public static function accepts_at_quality($type = null, $explicit_check = false)
145
    {
146
        request::parse_accept_header();
147
148
        // Normalize type
149
        $type = strtolower((string) $type);
150
151
        // General content type (e.g. "jpg")
152
        if (strpos($type, '/') === false) {
153
            // Don't accept anything by default
154
            $q = 0;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $q. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
155
156
            // Look up relevant mime types
157
            foreach ((array) Kohana::config('mimes.'.$type) as $type) {
158
                $q2 = request::accepts_at_quality($type, $explicit_check);
159
                $q = ($q2 > $q) ? $q2 : $q;
160
            }
161
162
            return $q;
163
        }
164
165
        // Content type with subtype given (e.g. "image/jpg")
166
        $type = explode('/', $type, 2);
167
168
        // Exact match
169
        if (isset(request::$accept_types[$type[0]][$type[1]])) {
170
            return request::$accept_types[$type[0]][$type[1]];
171
        }
172
173
        // Wildcard match (if not checking explicitly)
174 View Code Duplication
        if ($explicit_check === false and isset(request::$accept_types[$type[0]]['*'])) {
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...
175
            return request::$accept_types[$type[0]]['*'];
176
        }
177
178
        // Catch-all wildcard match (if not checking explicitly)
179 View Code Duplication
        if ($explicit_check === false and isset(request::$accept_types['*']['*'])) {
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...
180
            return request::$accept_types['*']['*'];
181
        }
182
183
        // Content type not accepted
184
        return 0;
185
    }
186
187
    /**
188
     * Parses client's HTTP Accept request header, and builds array structure representing it.
189
     *
190
     * @return  void
191
     */
192
    protected static function parse_accept_header()
0 ignored issues
show
parse_accept_header 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...
193
    {
194
        // Run this function just once
195
        if (request::$accept_types !== null) {
196
            return;
197
        }
198
199
        // Initialize accept_types array
200
        request::$accept_types = array();
201
202
        // No HTTP Accept header found
203
        if (empty($_SERVER['HTTP_ACCEPT'])) {
204
            // Accept everything
205
            request::$accept_types['*']['*'] = 1;
206
            return;
207
        }
208
209
        // Remove linebreaks and parse the HTTP Accept header
210
        foreach (explode(',', str_replace(array("\r", "\n"), '', $_SERVER['HTTP_ACCEPT'])) as $accept_entry) {
211
            // Explode each entry in content type and possible quality factor
212
            $accept_entry = explode(';', trim($accept_entry), 2);
213
214
            // Explode each content type (e.g. "text/html")
215
            $type = explode('/', $accept_entry[0], 2);
216
217
            // Skip invalid content types
218
            if (! isset($type[1])) {
219
                continue;
220
            }
221
222
            // Assume a default quality factor of 1 if no custom q value found
223
            $q = (isset($accept_entry[1]) and preg_match('~\bq\s*+=\s*+([.0-9]+)~', $accept_entry[1], $match)) ? (float) $match[1] : 1;
0 ignored issues
show
The variable $match does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
224
225
            // Populate accept_types array
226
            if (! isset(request::$accept_types[$type[0]][$type[1]]) or $q > request::$accept_types[$type[0]][$type[1]]) {
227
                request::$accept_types[$type[0]][$type[1]] = $q;
228
            }
229
        }
230
    }
231
} // End request
232