Issues (3948)

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.

app/Foundation/Http/Request.php (6 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
2
3
/*
4
 * This file is part of Jitamin.
5
 *
6
 * Copyright (C) Jitamin Team
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Jitamin\Foundation\Http;
13
14
use Jitamin\Foundation\Base;
15
use Jitamin\Foundation\Exceptions\AccessForbiddenException;
16
use Pimple\Container;
17
18
/**
19
 * Request class.
20
 */
21
class Request extends Base
22
{
23
    /**
24
     * Pointer to PHP environment variables.
25
     *
26
     * @var array
27
     */
28
    private $server;
29
    private $get;
30
    private $post;
31
    private $files;
32
    private $cookies;
33
34
    /**
35
     * Constructor.
36
     *
37
     * @param \Pimple\Container $container
38
     * @param array             $server
39
     * @param array             $get
40
     * @param array             $post
41
     * @param array             $files
42
     * @param array             $cookies
43
     */
44
    public function __construct(Container $container, array $server = [], array $get = [], array $post = [], array $files = [], array $cookies = [])
0 ignored issues
show
__construct 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...
__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 $_FILES 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...
45
    {
46
        parent::__construct($container);
47
        $this->server = empty($server) ? $_SERVER : $server;
48
        $this->get = empty($get) ? $_GET : $get;
49
        $this->post = empty($post) ? $_POST : $post;
50
        $this->files = empty($files) ? $_FILES : $files;
51
        $this->cookies = empty($cookies) ? $_COOKIE : $cookies;
52
    }
53
54
    /**
55
     * Set GET parameters.
56
     *
57
     * @param array $params
58
     */
59
    public function setParams(array $params)
60
    {
61
        $this->get = array_merge($this->get, $params);
62
    }
63
64
    /**
65
     * Get query string string parameter.
66
     *
67
     * @param string $name          Parameter name
68
     * @param string $default_value Default value
69
     *
70
     * @return string
71
     */
72
    public function getStringParam($name, $default_value = '')
73
    {
74
        return isset($this->get[$name]) ? $this->get[$name] : $default_value;
75
    }
76
77
    /**
78
     * Get query string integer parameter.
79
     *
80
     * @param string $name          Parameter name
81
     * @param int    $default_value Default value
82
     *
83
     * @return int
84
     */
85
    public function getIntegerParam($name, $default_value = 0)
86
    {
87
        return isset($this->get[$name]) && ctype_digit($this->get[$name]) ? (int) $this->get[$name] : $default_value;
88
    }
89
90
    /**
91
     * Get a form value.
92
     *
93
     * @param string $name Form field name
94
     *
95
     * @return string|null
96
     */
97
    public function getValue($name)
98
    {
99
        $values = $this->getValues();
100
101
        return isset($values[$name]) ? $values[$name] : null;
102
    }
103
104
    /**
105
     * Get form values and check for CSRF token.
106
     *
107
     * @return array
108
     */
109
    public function getValues()
110
    {
111
        if ($this->checkCSRFParam()) {
112
            return $this->post;
113
        }
114
115
        return [];
116
    }
117
118
    /**
119
     * Check for CSRF token.
120
     *
121
     * @return void
122
     */
123
    public function checkCSRFToken()
124
    {
125
        if (!$this->checkCSRFParam()) {
126
            throw new AccessForbiddenException();
127
        }
128
    }
129
130
    /**
131
     * Get the raw body of the HTTP request.
132
     *
133
     * @return string
134
     */
135
    public function getBody()
136
    {
137
        return file_get_contents('php://input');
138
    }
139
140
    /**
141
     * Get the Json request body.
142
     *
143
     * @return array
144
     */
145
    public function getJson()
146
    {
147
        return json_decode($this->getBody(), true) ?: [];
148
    }
149
150
    /**
151
     * Get the content of an uploaded file.
152
     *
153
     * @param string $name Form file name
154
     *
155
     * @return string
156
     */
157
    public function getFileContent($name)
158
    {
159
        if (isset($this->files[$name]['tmp_name'])) {
160
            return file_get_contents($this->files[$name]['tmp_name']);
161
        }
162
163
        return '';
164
    }
165
166
    /**
167
     * Get the path of an uploaded file.
168
     *
169
     * @param string $name Form file name
170
     *
171
     * @return string
172
     */
173
    public function getFilePath($name)
174
    {
175
        return isset($this->files[$name]['tmp_name']) ? $this->files[$name]['tmp_name'] : '';
176
    }
177
178
    /**
179
     * Get info of an uploaded file.
180
     *
181
     * @param string $name Form file name
182
     *
183
     * @return array
184
     */
185
    public function getFileInfo($name)
186
    {
187
        return isset($this->files[$name]) ? $this->files[$name] : [];
188
    }
189
190
    /**
191
     * Return HTTP method.
192
     *
193
     * @return bool
194
     */
195
    public function getMethod()
196
    {
197
        return $this->getServerVariable('REQUEST_METHOD');
198
    }
199
200
    /**
201
     * Return true if the HTTP request is sent with the POST method.
202
     *
203
     * @return bool
204
     */
205
    public function isPost()
206
    {
207
        return $this->getServerVariable('REQUEST_METHOD') === 'POST';
208
    }
209
210
    /**
211
     * Return true if the HTTP request is an Ajax request.
212
     *
213
     * @return bool
214
     */
215
    public function isAjax()
216
    {
217
        return $this->getHeader('X-Requested-With') === 'XMLHttpRequest';
218
    }
219
220
    /**
221
     * Check if the page is requested through HTTPS.
222
     *
223
     * Note: IIS return the value 'off' and other web servers an empty value when it's not HTTPS
224
     *
225
     * @return bool
226
     */
227
    public function isHTTPS()
228
    {
229
        if ($this->getServerVariable('HTTP_X_FORWARDED_PROTO') === 'https') {
230
            return true;
231
        }
232
233
        return $this->getServerVariable('HTTPS') !== '' && $this->server['HTTPS'] !== 'off';
234
    }
235
236
    /**
237
     * Get cookie value.
238
     *
239
     * @param string $name
240
     *
241
     * @return string
242
     */
243
    public function getCookie($name)
244
    {
245
        return isset($this->cookies[$name]) ? $this->cookies[$name] : '';
246
    }
247
248
    /**
249
     * Return a HTTP header value.
250
     *
251
     * @param string $name Header name
252
     *
253
     * @return string
254
     */
255
    public function getHeader($name)
256
    {
257
        $name = 'HTTP_'.str_replace('-', '_', strtoupper($name));
258
259
        return $this->getServerVariable($name);
260
    }
261
262
    /**
263
     * Get remote user.
264
     *
265
     * @return string
266
     */
267
    public function getRemoteUser()
268
    {
269
        return $this->getServerVariable(REVERSE_PROXY_USER_HEADER);
270
    }
271
272
    /**
273
     * Returns query string.
274
     *
275
     * @return string
276
     */
277
    public function getQueryString()
278
    {
279
        return $this->getServerVariable('QUERY_STRING');
280
    }
281
282
    /**
283
     * Return URI.
284
     *
285
     * @return string
286
     */
287
    public function getUri()
288
    {
289
        return $this->getServerVariable('REQUEST_URI');
290
    }
291
292
    /**
293
     * Get the user agent.
294
     *
295
     * @return string
296
     */
297
    public function getUserAgent()
298
    {
299
        return empty($this->server['HTTP_USER_AGENT']) ? t('Unknown') : $this->server['HTTP_USER_AGENT'];
300
    }
301
302
    /**
303
     * Get the IP address of the user.
304
     *
305
     * @return string
306
     */
307
    public function getIpAddress()
308
    {
309
        $keys = [
310
            'HTTP_X_REAL_IP',
311
            'HTTP_CLIENT_IP',
312
            'HTTP_X_FORWARDED_FOR',
313
            'HTTP_X_FORWARDED',
314
            'HTTP_X_CLUSTER_CLIENT_IP',
315
            'HTTP_FORWARDED_FOR',
316
            'HTTP_FORWARDED',
317
            'REMOTE_ADDR',
318
        ];
319
320
        foreach ($keys as $key) {
321
            if ($this->getServerVariable($key) !== '') {
322
                foreach (explode(',', $this->server[$key]) as $ipAddress) {
323
                    return trim($ipAddress);
324
                }
325
            }
326
        }
327
328
        return t('Unknown');
329
    }
330
331
    /**
332
     * Get start time.
333
     *
334
     * @return float
335
     */
336
    public function getStartTime()
337
    {
338
        return $this->getServerVariable('REQUEST_TIME_FLOAT') ?: 0;
339
    }
340
341
    /**
342
     * Get server variable.
343
     *
344
     * @param string $variable
345
     *
346
     * @return string
347
     */
348
    public function getServerVariable($variable)
349
    {
350
        return isset($this->server[$variable]) ? $this->server[$variable] : '';
351
    }
352
353
    /**
354
     * Check if the CSRF token from the URL is correct.
355
     */
356
    protected function checkCSRFParam()
357
    {
358
        if (!empty($this->post) && !empty($this->post['csrf_token']) && $this->token->validateCSRFToken($this->post['csrf_token'])) {
0 ignored issues
show
The property token does not exist on object<Jitamin\Foundation\Http\Request>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
359
            unset($this->post['csrf_token']);
360
361
            return true;
362
        }
363
364
        return false;
365
    }
366
}
367