Completed
Push — master ( d0941c...c232a4 )
by Richard
14s
created

HttpRequest::detectByParam()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
ccs 0
cts 4
cp 0
crap 6
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 */
11
12
namespace Xoops\Core;
13
14
/**
15
 * WARNING: THIS IS A PLACEHOLDER ONLY. IMPLEMENTATION AND DETAILS WILL CHANGE.
16
 *
17
 * This provides some of the functionality that was in the Xoops_Request classes.
18
 * The majority of use for the class was the 'asXyz()' methods, and all such uses
19
 * should move to Xmf\Request::getXyz() methods.
20
 *
21
 * These are methods which reveal some aspects of the HTTP request environment.
22
 * This will eventually be reworked to depend on a full HTTP message library
23
 * (anticipating an official PSR-7 implementation.)
24
 *
25
 * For now, this is a reduced version of a Cake derivative.
26
 *
27
 */
28
29
/**
30
 * HttpRequest
31
 *
32
 * @category  Xoops\Core\HttpRequest
33
 * @package   Xoops\Core
34
 * @author    trabis <[email protected]>
35
 * @author    Kazumi Ono <[email protected]>
36
 * @author    Richard Griffith <[email protected]>
37
 * @copyright 2011-2015 XOOPS Project (http://xoops.org)
38
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
39
 * @link      http://xoops.org
40
 */
41
class HttpRequest
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
42
{
43
    /**
44
     * @var array
45
     */
46
    protected $params;
47
48
    /**
49
     * @var HttpRequest The reference to *Singleton* instance of this class
50
     */
51
    private static $instance;
52
53
    /**
54
     * The built in detectors used with `is()` can be modified with `addDetector()`.
55
     * There are several ways to specify a detector, see HttpRequest::addDetector() for the
56
     * various formats and ways to define detectors.
57
     *
58
     * @var array
59
     */
60
    protected $detectors = array(
61
        'get'       => array('env' => 'REQUEST_METHOD', 'value' => 'GET'),
62
        'post'      => array('env' => 'REQUEST_METHOD', 'value' => 'POST'),
63
        'put'       => array('env' => 'REQUEST_METHOD', 'value' => 'PUT'),
64
        'delete'    => array('env' => 'REQUEST_METHOD', 'value' => 'DELETE'),
65
        'head'      => array('env' => 'REQUEST_METHOD', 'value' => 'HEAD'),
66
        'options'   => array('env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'),
67
        'safemethod'=> array('env' => 'REQUEST_METHOD', 'options' => array('GET', 'HEAD')),
68
        'ssl'       => array('env' => 'HTTPS', 'value' => 1),
69
        'ajax'      => array('env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'),
70
        'flash'     => array('env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'),
71
        'mobile'    => array(
72
            'env'     => 'HTTP_USER_AGENT',
73
            'options' => array(
74
                'Android',
75
                'AvantGo',
76
                'BlackBerry',
77
                'DoCoMo',
78
                'Fennec',
79
                'iPod',
80
                'iPhone',
81
                'iPad',
82
                'J2ME',
83
                'MIDP',
84
                'NetFront',
85
                'Nokia',
86
                'Opera Mini',
87
                'Opera Mobi',
88
                'PalmOS',
89
                'PalmSource',
90
                'portalmmm',
91
                'Plucker',
92
                'ReqwirelessWeb',
93
                'SonyEricsson',
94
                'Symbian',
95
                'UP\\.Browser',
96
                'webOS',
97
                'Windows CE',
98
                'Windows Phone OS',
99
                'Xiino'
100
            )
101
        ),
102
        'robot'     => array(
103
            'env'     => 'HTTP_USER_AGENT',
104
            'options' => array(
105
                /* The most common ones. */
106
                'Googlebot',
107
                'msnbot',
108
                'Slurp',
109
                'Yahoo',
110
                /* The rest alphabetically. */
111
                'Arachnoidea',
112
                'ArchitextSpider',
113
                'Ask Jeeves',
114
                'B-l-i-t-z-Bot',
115
                'Baiduspider',
116
                'BecomeBot',
117
                'cfetch',
118
                'ConveraCrawler',
119
                'ExtractorPro',
120
                'FAST-WebCrawler',
121
                'FDSE robot',
122
                'fido',
123
                'geckobot',
124
                'Gigabot',
125
                'Girafabot',
126
                'grub-client',
127
                'Gulliver',
128
                'HTTrack',
129
                'ia_archiver',
130
                'InfoSeek',
131
                'kinjabot',
132
                'KIT-Fireball',
133
                'larbin',
134
                'LEIA',
135
                'lmspider',
136
                'Lycos_Spider',
137
                'Mediapartners-Google',
138
                'MuscatFerret',
139
                'NaverBot',
140
                'OmniExplorer_Bot',
141
                'polybot',
142
                'Pompos',
143
                'Scooter',
144
                'Teoma',
145
                'TheSuBot',
146
                'TurnitinBot',
147
                'Ultraseek',
148
                'ViolaBot',
149
                'webbandit',
150
                'www\\.almaden\\.ibm\\.com\\/cs\\/crawler',
151
                'ZyBorg',
152
            )
153
        ),
154
    );
155
156
    /**
157
     * __construct
158
     */
159
    private function __construct()
0 ignored issues
show
Coding Style introduced by
__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...
Coding Style introduced by
__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...
160
    {
161
        switch (strtolower($this->getEnv('REQUEST_METHOD'))) {
162
            case 'get':
163
                $params = $_GET;
164
                break;
165
            case 'put':
166
                parse_str(file_get_contents('php://input'), $put);
167
                $params = array_merge($_GET, $put);
168
                break;
169
            default:
170
                $params = array_merge($_GET, $_POST);
171
        }
172
        $this->params = $params;
173
    }
174
175
    /**
176
     * get singleton instance, establish the request data on first access
177
     *
178
     * @return HttpRequest
179
     */
180 10
    public static function getInstance()
181
    {
182 10
        if (null === static::$instance) {
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
183
            static::$instance = new static();
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
184
        }
185 10
        return static::$instance;
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
186
    }
187
188
    /**
189
     * get a http header for the current request
190
     *
191
     * @param null|string $name header name
192
     *
193
     * @return null|string
194
     */
195
    public function getHeader($name = null)
196
    {
197
        if ($name === null) {
198
            return $name;
199
        }
200
201
        // Try to get it from the $_SERVER array first
202
        if ($res = $this->getEnv('HTTP_' . strtoupper(str_replace('-', '_', $name)))) {
203
            return $res;
204
        }
205
206
        // This seems to be the only way to get the Authorization header on
207
        // Apache
208
        if (function_exists('apache_request_headers')) {
209
            $headers = apache_request_headers();
210
            if (!empty($headers[$name])) {
211
                return $headers[$name];
212
            }
213
        }
214
        return null;
215
    }
216
217
    /**
218
     * get the scheme of current request
219
     *
220
     * @return string
221
     */
222 1
    public function getScheme()
223
    {
224 1
        return $this->getEnv('HTTPS') ? 'https' : 'http';
225
    }
226
227
    /**
228
     * get the host from the current request
229
     *
230
     * @return string
231
     */
232 1
    public function getHost()
233
    {
234 1
        return $this->getEnv('HTTP_HOST') ? (string) $this->getEnv('HTTP_HOST') : 'localhost';
235
    }
236
237
    /**
238
     * get the URI of the current request
239
     *
240
     * @return null|string
241
     */
242
    public static function getUri()
0 ignored issues
show
Coding Style introduced by
getUri 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...
243
    {
244
        if (empty($_SERVER['PHP_SELF']) || empty($_SERVER['REQUEST_URI'])) {
245
            // IIS
246
            $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'];
247
            if (!empty($_SERVER['QUERY_STRING'])) {
248
                $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
249
            }
250
            return $_SERVER['REQUEST_URI'];
251
        }
252
        return isset($_SERVER['ORIG_REQUEST_URI']) ? $_SERVER['ORIG_REQUEST_URI'] : $_SERVER['REQUEST_URI'];
253
    }
254
255
    /**
256
     * get the referer of the current request
257
     *
258
     * @return string
259
     */
260 1
    public function getReferer()
261
    {
262 1
        return $this->getEnv('HTTP_REFERER') ? $this->getEnv('HTTP_REFERER') : '';
263
    }
264
265
    /**
266
     * get the current script name associated with the request
267
     *
268
     * @return string
269
     */
270 1
    public function getScriptName()
271
    {
272 1
        return $this->getEnv('SCRIPT_NAME')
273 1
            ? $this->getEnv('SCRIPT_NAME')
274 1
            : ($this->getEnv('ORIG_SCRIPT_NAME') ? $this->getEnv('ORIG_SCRIPT_NAME') : '');
275
    }
276
277
    /**
278
     * Get the domain name and include $tldLength segments of the tld.
279
     *
280
     * @return string Domain name without subdomains
281
     */
282 1
    public function getDomain()
283
    {
284 1
        $host = $this->getHost();
285 1
        $domain =  \Xoops::getInstance()->getBaseDomain($host);
286 1
        return is_null($domain) ? $host : $domain;
287
    }
288
289
    /**
290
     * Get the subdomains for a host.
291
     *
292
     * @return string subdomain portion of host name
293
     */
294 1
    public function getSubdomains()
295
    {
296 1
        $host = $this->getHost();
297 1
        $regDom  = \Xoops::getInstance()->getBaseDomain($host);
298 1
        $fullDom = \Xoops::getInstance()->getBaseDomain($host, true);
299 1
        if (empty($regDom) || empty($fullDom)) {
300
            return '';
301
        }
302 1
        $regPattern = '/' . $regDom . '$/';
303 1
        $subdomain = preg_replace($regPattern, '', $fullDom);
304 1
        $subdomain = preg_replace('/\.$/', '', $subdomain);
305 1
        return empty($subdomain) ? '' : $subdomain;
306
    }
307
308
    /**
309
     * Get the Client IP address, optionally attempting to peek behind any proxies
310
     * to get a real routable address.
311
     *
312
     * @param boolean $considerProxy true to enable proxy tests
313
     *
314
     * @return string
315
     */
316
    public function getClientIp($considerProxy = false)
0 ignored issues
show
Coding Style introduced by
getClientIp 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...
317
    {
318
        $default = (array_key_exists('REMOTE_ADDR', $_SERVER)) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
319
320
        if (!$considerProxy) {
321
            return $default;
322
        }
323
324
        $keys = array(
325
            'HTTP_CLIENT_IP',
326
            'HTTP_X_FORWARDED_FOR',
327
            'HTTP_X_FORWARDED',
328
            'HTTP_X_CLUSTER_CLIENT_IP',
329
            'HTTP_FORWARDED_FOR',
330
            'HTTP_FORWARDED',
331
        );
332
        foreach ($keys as $key) {
333
            if (array_key_exists($key, $_SERVER) === true) {
334
                foreach (explode(',', $_SERVER[$key]) as $ip) {
335
                    $ip = trim($ip);
336
                    if (false !== filter_var(
337
                        $ip,
338
                        FILTER_VALIDATE_IP,
339
                        FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
340
                    )) {
341
                        return $ip;
342
                    }
343
                }
344
            }
345
        }
346
347
        return $default;
348
    }
349
350
    /**
351
     * Return current url
352
     *
353
     * @return string
354
     */
355
    public function getUrl()
356
    {
357
        $url = $this->getScheme() . "://" . $this->getHost();
358
        $port = $this->getEnv('SERVER_PORT');
359
        if (80 != $port) {
360
            $url .= ":{$port}";
361
        }
362
        return $url . $this->getUri();
363
    }
364
365
    /**
366
     * Gets an environment variable from available sources, and provides emulation
367
     * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
368
     * IIS, or SCRIPT_NAME in CGI mode).  Also exposes some additional custom
369
     * environment information.
370
     * Note : code modifications for XOOPS
371
     *
372
     * @param string $name    Environment variable name.
373
     * @param mixed  $default default value
374
     *
375
     * @return string|boolean Environment variable setting.
376
     * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#env
377
     *
378
     * @todo this methods and Xoops::getEnv() need to be unified
379
     */
380 13
    public function getEnv($name, $default = null)
0 ignored issues
show
Coding Style introduced by
getEnv 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...
Coding Style introduced by
getEnv uses the super-global variable $_ENV 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...
381
    {
382 13
        if ($name === 'HTTPS') {
383 1
            if (isset($_SERVER['HTTPS'])) {
384 1
                return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
385
            }
386 1
            return (strpos($this->getEnv('SCRIPT_URI'), 'https://') === 0);
387
        }
388
389 13
        if ($name === 'SCRIPT_NAME' && !isset($_SERVER[$name])) {
390
            if ($this->getEnv('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) {
391
                return $_ENV['SCRIPT_URL'];
392
            }
393
        }
394
395 13
        if ($name === 'REMOTE_ADDR' && !isset($_SERVER[$name])) {
396
            $address = $this->getEnv('HTTP_PC_REMOTE_ADDR');
397
            if ($address !== null) {
398
                return $address;
399
            }
400
        }
401
402 13
        $val = null;
403 13
        if (isset($_SERVER[$name])) {
404 12
            $val = $_SERVER[$name];
405 6
        } elseif (isset($_ENV[$name])) {
406 1
            $val = $_ENV[$name];
407
        }
408
409 13
        if ($val !== null) {
410 12
            return $val;
411
        }
412
413
        switch ($name) {
414 6
            case 'SCRIPT_FILENAME':
415 1
                $val = preg_replace('#//+#', '/', $this->getEnv('PATH_TRANSLATED'));
416 1
                return preg_replace('#\\\\+#', '\\', $val);
417
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
418 5
            case 'DOCUMENT_ROOT':
419 1
                $name = $this->getEnv('SCRIPT_NAME');
420 1
                $filename = $this->getEnv('SCRIPT_FILENAME');
421 1
                $offset = 0;
422 1
                if (!strpos($name, '.php')) {
423 1
                    $offset = 4;
424
                }
425 1
                return substr($filename, 0, -(strlen($name) + $offset));
426
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
427 4
            case 'PHP_SELF':
428 1
                return str_replace($this->getEnv('DOCUMENT_ROOT'), '', $this->getEnv('SCRIPT_FILENAME'));
429
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
430 3
            case 'CGI_MODE':
431 1
                return (PHP_SAPI === 'cgi');
432
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
433 2
            case 'HTTP_BASE':
434 1
                $host = $this->getEnv('HTTP_HOST');
435 1
                $val = \Xoops::getInstance()->getBaseDomain($host);
436 1
                if (is_null($val)) {
437 1
                    return $default;
438
                } else {
439 1
                    return '.' . $val;
440
                }
441
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
442
        }
443 1
        return $default;
444
    }
445
446
    /**
447
     * get files associated with the current request
448
     *
449
     * @param string $name name of file
450
     *
451
     * @return array
452
     */
453
    public static function getFiles($name)
0 ignored issues
show
Coding Style introduced by
getFiles 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...
454
    {
455
        if (empty($_FILES)) {
456
            return array();
457
        }
458
459
        if (isset($_FILES[$name])) {
460
            return $_FILES[$name];
461
        }
462
463
        if (false === $pos = strpos($name, '[')) {
464
            return array();
465
        }
466
467
        $base = substr($name, 0, $pos);
468
        $key = str_replace(array(']', '['), array('', '"]["'), substr($name, $pos + 1, -1));
469
        $code = array(sprintf('if (!isset($_FILES["%s"]["name"]["%s"])) return array();', $base, $key));
470
        $code[] = '$file = array();';
471
        foreach (array('name', 'type', 'size', 'tmp_name', 'error') as $property) {
472
            $code[] = sprintf('$file["%1$s"] = $_FILES["%2$s"]["%1$s"]["%3$s"];', $property, $base, $key);
473
        }
474
        $code[] = 'return $file;';
475
476
        return eval(implode(PHP_EOL, $code));
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
477
    }
478
479
    /**
480
     * Check whether or not a Request is a certain type.  Uses the built in detection rules
481
     * as well as additional rules defined with HttpRequest::addDetector().  Any detector can be called
482
     * as `is($type)` or `is$Type()`.
483
     *
484
     * @param string $type The type of request you want to check.
485
     *
486
     * @return boolean Whether or not the request is the type you are checking.
487
     */
488
    public function is($type)
489
    {
490
        $type = strtolower($type);
491
        if (!isset($this->detectors[$type])) {
492
            return false;
493
        }
494
        $detect = $this->detectors[$type];
495
        if (isset($detect['env'])) {
496
            return $this->detectByEnv($detect);
497
        } elseif (isset($detect['param'])) {
498
            return $this->detectByParam($detect);
499
        } elseif (isset($detect['callback']) && is_callable($detect['callback'])) {
500
            return call_user_func($detect['callback'], $this);
501
        }
502
        return false;
503
    }
504
505
    /**
506
     * detectByEnv - perform detection on detectors with an 'env' component
507
     *
508
     * @param array $detect a detectors array entry to test against
509
     *
510
     * @return boolean true if detect is matched, false if not
511
     */
512
    protected function detectByEnv($detect)
513
    {
514
        if (isset($detect['value'])) {
515
            return (bool) $this->getEnv($detect['env']) == $detect['value'];
516
        } elseif (isset($detect['pattern'])) {
517
            return (bool) preg_match($detect['pattern'], $this->getEnv($detect['env']));
518
        } elseif (isset($detect['options'])) {
519
            $pattern = '/' . implode('|', $detect['options']) . '/i';
520
            return (bool) preg_match($pattern, $this->getEnv($detect['env']));
521
        }
522
        return false; // can't match a broken rule
523
    }
524
525
    /**
526
     * detectByParam - perform detection on detectors with an 'param' component.
527
     * To match an entry with the name in the 'param' key of the $detect rule must
528
     * exist in the $params property and be equal to the 'value' entry specified
529
     * in the $detect array.
530
     *
531
     * @param array $detect a detectors array entry to test against. Param entries are
532
     *                      of the form array('param' => name, 'value' => value)
533
     *
534
     * @return boolean true if detect is matched, false if not
535
     */
536
    protected function detectByParam($detect)
537
    {
538
        $name = $detect['param'];
539
        $value = $detect['value'];
540
        return isset($this->params[$name]) ? $this->params[$name] == $value : false;
541
    }
542
543
    /**
544
     * Add a new detector to the list of detectors that a request can use.
545
     * There are several different formats and types of detectors that can be set.
546
     * ### Environment value comparison
547
     * An environment value comparison, compares a value fetched from `env()` to a known value
548
     * the environment value is equality checked against the provided value.
549
     * e.g `addDetector('post', array('env' => 'REQUEST_METHOD', 'value' => 'POST'))`
550
     * ### Pattern value comparison
551
     * Pattern value comparison allows you to compare a value fetched from `env()` to a regular expression.
552
     * e.g `addDetector('iphone', array('env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i'));`
553
     * ### Option based comparison
554
     * Option based comparisons use a list of options to create a regular expression.  Subsequent calls
555
     * to add an already defined options detector will merge the options.
556
     * e.g `addDetector('mobile', array('env' => 'HTTP_USER_AGENT', 'options' => array('Fennec')));`
557
     * ### Callback detectors
558
     * Callback detectors allow you to provide a 'callback' type to handle the check.  The callback will
559
     * receive the request object as its only parameter.
560
     * e.g `addDetector('custom', array('callback' => array('SomeClass', 'someMethod')));`
561
     * ### Request parameter detectors
562
     * Allows for custom detectors on the request parameters.
563
     * e.g `addDetector('post', array('param' => 'requested', 'value' => 1)`
564
     *
565
     * @param string $name    The name of the detector.
566
     * @param array  $options The options for the detector definition.  See above.
567
     *
568
     * @return void
569
     */
570
    public function addDetector($name, $options)
571
    {
572
        $name = strtolower($name);
573
        if (isset($this->detectors[$name]) && isset($options['options'])) {
574
            $options = \Xoops\Utils::arrayRecursiveMerge($this->detectors[$name], $options);
575
        }
576
        $this->detectors[$name] = $options;
577
    }
578
579
    /**
580
     * Determine if a client accepts a given media type
581
     *
582
     * @param string $mediaType The content type to check for.
583
     *
584
     * @return boolean true if client accepts the media type, otherwise false
585
     */
586 1
    public function clientAcceptsType($mediaType)
587
    {
588 1
        $accepts = $this->getAcceptMediaTypes();
589
590 1
        $mediaType = trim($mediaType);
591 1
        if (isset($accepts[$mediaType])) {
592 1
            return true;
593
        }
594 1
        list($type) = explode('/', $mediaType);
595 1
        if (isset($accepts[$type.'/*'])) {
596 1
            return true;
597
        }
598
599 1
        return isset($accepts['*/*']);
600
    }
601
602
    /**
603
     * getAcceptMediaTypes returns the http-accept header as an
604
     * array of media types arranged by specified preference
605
     *
606
     * @return array associative array of preference (numeric weight >0 <=1.0 )
607
     *               keyed by media types, and sorted by preference
608
     */
609 1 View Code Duplication
    public function getAcceptMediaTypes()
610
    {
611 1
        $types = array();
612 1
        $accept = $this->getHeader('ACCEPT');
613
614 1
        if (!empty($accept)) {
615 1
            $entries = explode(',', $accept);
616 1
            foreach ($entries as $e) {
617 1
                $mt = explode(';q=', $e);
618 1
                if (!isset($mt[1])) {
619 1
                    $mt[1] = 1.0;
620
                }
621 1
                $types[trim($mt[0])] = (float) $mt[1];
622
            }
623
624
            // sort list based on value
625 1
            arsort($types, SORT_NUMERIC);
626
        }
627
628 1
        return($types);
629
    }
630
631
    /**
632
     * getAcceptedLanguages returns the http-accept-language header as an
633
     * array of language codes arranged by specified preference
634
     *
635
     * @return array associative array of preference (numeric weight >0 <=1.0 )
636
     *               keyed by language code, and sorted by preference
637
     */
638 1 View Code Duplication
    public function getAcceptedLanguages()
639
    {
640 1
        $languages = array();
641 1
        $accept = $this->getHeader('ACCEPT_LANGUAGE');
642
643 1
        if (!empty($accept)) {
644 1
            $entries = explode(',', $accept);
645 1
            foreach ($entries as $e) {
646 1
                $l = explode(';q=', $e);
647 1
                if (!isset($l[1])) {
648 1
                    $l[1] = 1.0;
649
                }
650 1
                $languages[trim($l[0])] = (float) $l[1];
651
            }
652
653
            // sort list based on value
654 1
            arsort($languages, SORT_NUMERIC);
655
        }
656
657 1
        return($languages);
658
    }
659
}
660