Issues (320)

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.

src/php/Apix/Response.php (8 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
 *
5
 * This file is part of the Apix Project.
6
 *
7
 * (c) Franck Cassedanne <franck at ouarz.net>
8
 *
9
 * @license     http://opensource.org/licenses/BSD-3-Clause  New BSD License
10
 *
11
 */
12
13
namespace Apix;
14
15
/**
16
 * Represents a response.
17
 */
18
class Response extends Listener
19
{
20
21
    /**
22
     * List of supported response formats.
23
     * @var array
24
     */
25
    protected $formats = array('json', 'xml', 'html');
26
27
    /**
28
     * Holds the current output format.
29
     * Also use to set the default value.
30
     * @var string
31
     */
32
    protected $format = 'html';
33
34
    /**
35
     * Character encoding.
36
     * @var string
37
     */
38
    protected $encoding = 'UTF-8';
39
40
    /**
41
     * Holds the arrays of HTTP headers.
42
     * @var  array
43
     */
44
    protected $headers = array();
45
46
    /**
47
     * Holds the current HTTP Code.
48
     * @var  string
49
     */
50
    protected $http_code = 200;
51
52
    /**
53
     * Holds the current output.
54
     * @var  string
55
     */
56
    public $output = null;
57
58
    /**
59
     * Associative array of HTTP phrases.
60
     *
61
     * @var  array
62
     * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
63
     * @link http://tools.ietf.org/html/rfc2616#section-10
64
     */
65
    protected static $http_phrases = array(
66
67
        // 1xx: Informational - Request received, continuing process
68
        100 => 'Continue',
69
        101 => 'Switching Protocols',
70
71
        // 2xx: Success - The action was successfully received, understood and
72
        // accepted
73
        200 => 'OK',
74
        201 => 'Created',
75
        202 => 'Accepted',
76
        203 => 'Non-Authoritative Information',
77
        204 => 'No Content',
78
        205 => 'Reset Content',
79
        206 => 'Partial Content',
80
        207 => 'Multi-Status',
81
82
        // 3xx: Redirection - Further action must be taken in order to complete
83
        // the request
84
        300 => 'Multiple Choices',
85
        301 => 'Moved Permanently',
86
        302 => 'Found',  // 1.1
87
        303 => 'See Other',
88
        304 => 'Not Modified',
89
        305 => 'Use Proxy',
90
        307 => 'Temporary Redirect',
91
92
        // 4xx: Client Error - The request contains bad syntax or cannot be
93
        // fulfilled
94
        400 => 'Bad Request',
95
        401 => 'Unauthorized',
96
        402 => 'Payment Required',
97
        403 => 'Forbidden',
98
        404 => 'Not Found',
99
        405 => 'Method Not Allowed',
100
        406 => 'Not Acceptable',
101
        407 => 'Proxy Authentication Required',
102
        408 => 'Request Timeout',
103
        409 => 'Conflict',
104
        410 => 'Gone',
105
        411 => 'Length Required',
106
        412 => 'Precondition Failed',
107
        413 => 'Request Entity Too Large',
108
        414 => 'Request-URI Too Long',
109
        415 => 'Unsupported Media Type',
110
        416 => 'Requested Range Not Satisfiable',
111
        417 => 'Expectation Failed',
112
        422 => 'Unprocessable Entity',
113
        423 => 'Locked',
114
        424 => 'Failed Dependency',
115
        426 => 'Upgrade Required',
116
117
        // 5xx: Server Error - The server failed to fulfill an apparently
118
        // valid request
119
        500 => 'Internal Server Error',
120
        501 => 'Not Implemented',
121
        502 => 'Bad Gateway',
122
        503 => 'Service Unavailable',
123
        504 => 'Gateway Timeout',
124
        505 => 'HTTP Version Not Supported',
125
        506 => 'Variant Also Negotiates',
126
        507 => 'Insufficient Storage',
127
        509 => 'Bandwidth Limit Exceeded',
128
        510 => 'Not Extended'
129
    );
130
131
    /**
132
     * Associative array of long HTTP phrases.
133
     *
134
     * @var  array
135
     */
136
    protected static $long_http_phrases = array(
137
138
        200 => 'The request has succeeded.',
139
        201 => 'The request has been fulfilled and resulted in a new resource being created.',
140
141
        // Resulting from a POST, requires to use ->setHeader("Location", "/resource/action/id")
142
        202 => 'The request has been accepted for processing, but the processing has not been completed.',
143
144
        // DELETE
145
        204 => 'Request fulfilled successfully.',
146
147
        // Errors
148
        400 => 'Request is malformed.',
149
        401 => 'Not Authenticated.',
150
        403 => 'Access to this ressource has been denied.',
151
        404 => 'No ressource found at the Request-URI.',
152
        501 => 'This resource entity is not (yet) implemented. Try again later.',
153
        503 => 'The service is currently unable to handle the request due to a temporary overloading or maintenance of the server. Try again later.'
154
    );
155
156
    /**
157
     * @var Apix\Request
158
     */
159
    protected $request;
160
161
   /**
162
     * Returns the request object.
163
     *
164
     * @return Request
165
     */
166
    public function getRequest()
167
    {
168
        return $this->request;
169
    }
170
171
    /**
172
     * @var Apix\Router
173
     */
174
    protected $route;
175
176
    /**
177
     * Sets the route object.
178
     */
179
    public function setRoute(Router $route)
180
    {
181
        $this->route = $route;
0 ignored issues
show
Documentation Bug introduced by
It seems like $route of type object<Apix\Router> is incompatible with the declared type object<Apix\Apix\Router> of property $route.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
182
    }
183
184
    /**
185
     * Returns the route object.
186
     *
187
     * @return Router
188
     */
189
    public function getRoute()
190
    {
191
        return $this->route;
192
    }
193
194
    /**
195
     * Constructor.
196
     *
197
     * @param Request $request
198
     */
199
    public function __construct(Request $request)
200
    {
201
        $this->request = $request;
0 ignored issues
show
Documentation Bug introduced by
It seems like $request of type object<Apix\Request> is incompatible with the declared type object<Apix\Apix\Request> of property $request.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
202
    }
203
204
    /**
205
     * Sets the output format.
206
     *
207
     * @param  string           $format
208
     * @param  string           $default
209
     * @throws \DomainException 406
210
     */
211
    public function setFormat($format, $default=null)
212
    {
213
        $format = strtolower($format);
214
        if (!in_array($format, $this->getFormats())) {
215
            $this->format = strtolower($default);
216
            throw new \DomainException(
217
                sprintf('Format (%s) not supported.', $format),
218
                406 // maybe 404?
219
            );
220
        }
221
        $this->format = $format;
222
    }
223
224
    /**
225
     * Returns the output format.
226
     *
227
     * @return string
228
     */
229
    public function getFormat()
230
    {
231
        return $this->format;
232
    }
233
234
    /**
235
     * Sets all the response formats available.
236
     *
237
     * @return void
238
     */
239
    public function setFormats(array $formats)
240
    {
241
        $this->formats = $formats;
242
    }
243
244
    /**
245
     * Returns all the response formats available.
246
     *
247
     * @return array
248
     */
249
    public function getFormats()
250
    {
251
        return $this->formats;
252
    }
253
254
    /**
255
     * Sets a response header.
256
     *
257
     * @param string  $key
258
     * @param string  $value
259
     * @param boolean $overwrite Wether to overwrite an existing header.
260
     */
261
    public function setHeader($key, $value, $overwrite=true)
262
    {
263
        if (!$overwrite && isset($this->headers[$key])) {
264
            return;
265
        }
266
        $this->headers[$key] = $value;
267
    }
268
269
    /**
270
     * Gets the specified response header.
271
     *
272
     * @param  string $key
273
     * @return string
274
     */
275
    public function getHeader($key)
276
    {
277
        return isset($this->headers[$key]) ? $this->headers[$key] : null;
278
    }
279
280
    /**
281
     * Returns the header array.
282
     *
283
     * @return array
284
     */
285
    public function getHeaders()
286
    {
287
        return $this->headers;
288
    }
289
290
    /**
291
     * Sends the headers thru HTTP.
292
     *
293
     * header('Cache-Control: no-cache, must-revalidate');    // HTTP/1.1
294
     * header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');  // Date in the past
295
     * // upload example
296
     * header('Content-Disposition: attachment; filename="downloaded.pdf"');
297
     * readfile('original.pdf');
298
     *
299
     * @param integer $http_code
300
     * @param string  $version
301
     */
302
    public function sendAllHttpHeaders($http_code, $version)
303
    {
304
        // PHP bug? TODO:
305
        // $out = $this->sendheader("Status: $http_code " . static::getStatusPrases($http_code));
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
306
        // //$out = $this->sendheader("HTTP/1.0 $http_code " . static::getStatusPrases($http_code), true);
307
        // $out[] = array( $this->sendHeader('X-Powered-By: ' . $version_string) );
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
308
309
        $out = array(
310
            $this->sendHeader('X-Powered-By: ' . $version, true, $http_code)
311
        );
312
313
        foreach ($this->headers as $key => $value) {
314
           $out[] = $this->sendheader($key . ': ' . $value);
315
        }
316
317
        return $out;
318
    }
319
320
    /**
321
     * Sends one header thru HTTP
322
     * @param vary
323
     */
324
    public function sendHeader()
325
    {
326
        $args = func_get_args();
327
328
        return isset($this->unit_test)
329
            ? $args
330
            : call_user_func_array('header', $args);
331
    }
332
333
    /**
334
     * Sets the current HTTP code.
335
     *
336
     * @param  integer $int
337
     * @return void
338
     */
339
    public function setHttpCode($int)
340
    {
341
        $this->http_code = (int) $int;
0 ignored issues
show
Documentation Bug introduced by
The property $http_code was declared of type string, but (int) $int is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
342
    }
343
344
    /**
345
     * Gets the current HTTP code.
346
     *
347
     * @return intger
348
     */
349
    public function getHttpCode()
350
    {
351
        return $this->http_code;
352
    }
353
354
    /**
355
     * Returns an HTTP status phrase.
356
     *
357
     * @param  integer $http_code
358
     * @param  boolean $long
359
     * @return string
360
     */
361
    public static function getStatusPrases($http_code=null, $long=false)
362
    {
363
        //$http_code = is_null($http_code) ? $this->http_code : $http_code;
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
364
        $type = $long === true ? self::$long_http_phrases : self::$http_phrases;
365
        $status = self::$http_phrases[$http_code];
366
367
        return $long === true
368
            ? isset($type[$http_code]) ? $type[$http_code] : $http_code . ' ' . $status
369
            : $status;
370
    }
371
372
    /**
373
     * Returns sucessful or failed string.
374
     *
375
     * @param  integer $http_code
376
     * @return string
377
     */
378
    public static function getStatusAdjective($http_code)
379
    {
380
        return floor($http_code/100)<=3 ? 'successful' : 'failed';
381
    }
382
383
    /**
384
     * Returns a collated array representation of the output.
385
     *
386
     * @return array
387
     */
388
    public function collate(array $results)
389
    {
390
        $top =  is_object($this->route)
391
                && $this->route->getController()
392
                    ? $this->route->getController()
393
                    : 'index';
394
395
        return array($top => $results);
396
    }
397
398
    /**
399
     * Generates the response & send the headers...
400
     *
401
     * @param  array  $results
402
     * @param  string $version_string
403
     * @param  string $rootNode
404
     * @return string
405
     */
406
    public function generate(array $results, $version_string='ouarz', $rootNode='root')
407
    {
408
        $this->results = $this->collate($results);
0 ignored issues
show
The property results does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
409
        // var_dump( $results );echo __METHOD__;exit;
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
410
411
        // early listeners @ post-response
412
        $this->hook('response', 'early');
413
414
        $renderer = __NAMESPACE__ . '\Output\\' . ucfirst($this->getFormat());
415
        $view = new $renderer($this->encoding);
416
417
        $this->setHeader('Content-Type', $view->getContentType());
418
        $this->sendAllHttpHeaders($this->getHttpCode(), $version_string);
419
420
        if (null === $this->output) {
421
            $this->output = $view->encode(
422
                $this->results,
423
                $rootNode
424
            );
425
        }
426
427
        // late listeners @ post-response
428
        $this->hook('response', 'late');
429
    }
430
431
    /**
432
     * Returns the response output.
433
     *
434
     * @return string
435
     */
436
    public function getOutput()
437
    {
438
        return $this->output;
439
    }
440
441
    /**
442
     * Sets the response output.
443
     *
444
     * @param string $string
445
     */
446
    public function setOutput($string)
447
    {
448
        $this->output = $string;
449
    }
450
451
}
452