GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 4a11d4...61e32b )
by やかみ
02:13
created

Request   C

Complexity

Total Complexity 66

Size/Duplication

Total Lines 365
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 365
rs 5.7474
c 1
b 0
f 0
wmc 66
lcom 2
cbo 2

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B getRequestParams() 0 25 6
A get() 0 4 1
A post() 0 10 2
A server() 0 4 1
D cookie() 0 76 19
B isSecure() 0 12 7
A getBaseUrl() 0 11 4
D getClientIp() 0 29 9
B getHostName() 0 30 5
A isGet() 0 4 1
A isPost() 0 4 1
A isPut() 0 4 1
A isAjax() 0 4 3
A isCli() 0 4 1
A isMobile() 0 9 4

How to fix   Complexity   

Complex Class

Complex classes like Request often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Request, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Kotori.php
4
 *
5
 * A Tiny Model-View-Controller PHP Framework
6
 *
7
 * This content is released under the Apache 2 License
8
 *
9
 * Copyright (c) 2015-2017 Kotori Technology. All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 *     http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23
24
/**
25
 * Request Class
26
 *
27
 * @package     Kotori
28
 * @subpackage  Http
29
 * @author      Kokororin
30
 * @link        https://kotori.love
31
 */
32
namespace Kotori\Http;
33
34
use Kotori\Core\SoulInterface;
35
use Kotori\Core\SoulTrait;
36
use Kotori\Debug\Hook;
37
38
class Request implements SoulInterface
39
{
40
    use SoulTrait;
41
    /**
42
     * Params
43
     *
44
     * @var string
45
     */
46
    protected $_put = null;
47
48
    /**
49
     * Ip address
50
     *
51
     * @var array
52
     */
53
    protected $_ip = null;
54
55
    /**
56
     * Class constructor
57
     *
58
     * Initialize Request.
59
     *
60
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

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

Please refer to the PHP core documentation on constructors.

Loading history...
61
     */
62
    public function __construct()
63
    {
64
        Hook::listen(__CLASS__);
65
    }
66
67
    /**
68
     * Internal method used to retrieve values from given arrays.
69
     *
70
     * @param  array $source $_GET, $_POST, $_COOKIE, $_SERVER, etc.
71
     * @param  mixed $key Index for item to be fetched from $source
72
     * @return mixed
73
     */
74
    protected function getRequestParams(&$source, $key = null)
75
    {
76
        // If $key is NULL, it means that the whole $source is requested
77
        if (!isset($key) || $key == null) {
78
            $key = array_keys($source);
79
        }
80
81
        if (is_array($key)) {
82
            $output = array();
83
            foreach ($key as $k) {
84
                $output[$k] = $this->getRequestParams($source, $k);
85
            }
86
87
            return $output;
88
        }
89
90
        if (isset($source[$key])) {
91
            $value = $source[$key];
92
        } else {
93
            return null;
94
        }
95
96
        return $value;
97
98
    }
99
100
    /**
101
     * Fetch an item from the GET array
102
     *
103
     * @param  mixed $key Index for item to be fetched from $_GET
104
     * @return mixed
105
     */
106
    public function get($key = null)
0 ignored issues
show
Coding Style introduced by
get uses the super-global variable $_GET which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
107
    {
108
        return $this->getRequestParams($_GET, $key);
109
    }
110
111
    /**
112
     * Fetch an item from the POST array
113
     *
114
     * @param  mixed $key Index for item to be fetched from $_POST
115
     * @return mixed
116
     */
117
    public function post($key = null)
0 ignored issues
show
Coding Style introduced by
post uses the super-global variable $_POST which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
118
    {
119
        $rawPostData = file_get_contents('php://input');
120
        $source = json_decode($rawPostData, true);
121
        if (json_last_error() != JSON_ERROR_NONE) {
122
            $source = $_POST;
123
        }
124
125
        return $this->getRequestParams($source, $key);
126
    }
127
128
    /**
129
     * Fetch an item from the SERVER array
130
     *
131
     * @param  mixed $key Index for item to be fetched from $_SERVER
132
     * @return mixed
133
     */
134
    public function server($key = null)
0 ignored issues
show
Coding Style introduced by
server uses the super-global variable $_SERVER which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
135
    {
136
        return $this->getRequestParams($_SERVER, $key);
137
    }
138
139
    /**
140
     * Set or Get cookie
141
     *
142
     * @param  mixed $key Index for item for cookie
143
     * @param  string $value cookie value
144
     * @param  mixed  options for cookie setting
145
     * @return mixed
146
     */
147
    public function cookie($key = '', $value = '', $options = null)
0 ignored issues
show
Coding Style introduced by
cookie uses the super-global variable $_COOKIE which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
148
    {
149
        $defaultOptions = [
150
            'prefix' => '',
151
            'expire' => 86400,
152
            'path' => '/',
153
            'secure' => false,
154
            'httponly' => false,
155
        ];
156
157
        if (!is_null($options)) {
158
            if (is_numeric($options)) {
159
                $options = ['expire' => $options];
160
            } elseif (is_string($options)) {
161
                parse_str($options, $options);
162
            }
163
164
            $options = array_merge($defaultOptions, array_change_key_case($options));
165
        }
166
167
        if (!empty($options['httponly'])) {
168
            ini_set('session.cookie_httponly', 1);
169
        }
170
171
        if (is_null($key)) {
172
            if (empty($_COOKIE)) {
173
                return null;
174
            }
175
176
            $prefix = empty($value) ? $options['prefix'] : $value;
177
            if (!empty($prefix)) {
178
                foreach ($_COOKIE as $key => $val) {
179
                    if (0 === stripos($key, $prefix)) {
180
                        setcookie($key, '', time() - 3600, $options['path'], $options['domain'], $options['secure'], $options['httponly']);
181
                        unset($_COOKIE[$key]);
182
                    }
183
                }
184
            }
185
186
            return null;
187
        } elseif ('' === $key) {
188
            // Get All Cookie
189
            return $_COOKIE;
190
        }
191
192
        $key = $options['prefix'] . str_replace('.', '_', $key);
193
        if ('' === $value) {
194
            if (isset($_COOKIE[$key])) {
195
                $value = $_COOKIE[$key];
196
                if (0 === strpos($value, 'kotori:')) {
197
                    $value = substr($value, 6);
198
                    return array_map('urldecode', json_decode(MAGIC_QUOTES_GPC ? stripslashes($value) : $value, true));
199
                } else {
200
                    return $value;
201
                }
202
            } else {
203
                return null;
204
            }
205
        } else {
206
            if (is_null($value)) {
207
                setcookie($key, '', time() - 3600, $options['path'], $options['domain'], $options['secure'], $options['httponly']);
208
                unset($_COOKIE[$key]); // Delete Cookie
209
            } else {
210
                // Set Cookie
211
                if (is_array($value)) {
212
                    $value = 'kotori:' . json_encode(array_map('urlencode', $value));
213
                }
214
215
                $expire = !empty($options['expire']) ? time() + intval($options['expire']) : 0;
216
                setcookie($key, $value, $expire, $options['path'], $options['domain'], $options['secure'], $options['httponly']);
217
                $_COOKIE[$key] = $value;
218
            }
219
        }
220
221
        return null;
222
    }
223
224
    /**
225
     * Is HTTPS?
226
     *
227
     * Determines if the application is accessed via an encrypted
228
     * (HTTPS) connection.
229
     *
230
     * @return  boolean
231
     */
232
    public function isSecure()
0 ignored issues
show
Coding Style introduced by
isSecure 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...
233
    {
234
        if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') {
235
            return true;
236
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO']) {
237
            return true;
238
        } elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
239
            return true;
240
        }
241
242
        return false;
243
    }
244
245
    /**
246
     * Base URL
247
     *
248
     * Returns base url
249
     *
250
     * @return string
251
     */
252
    public function getBaseUrl()
0 ignored issues
show
Coding Style introduced by
getBaseUrl 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...
253
    {
254
        if (isset($_SERVER['HTTP_HOST']) && preg_match('/^((\[[0-9a-f:]+\])|(\d{1,3}(\.\d{1,3}){3})|[a-z0-9\-\.]+)(:\d+)?$/i', $_SERVER['HTTP_HOST'])) {
255
            $base_url = (Request::getSoul()->isSecure() ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']
256
            . substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME'])));
257
        } else {
258
            $base_url = 'http://localhost/';
259
        }
260
261
        return rtrim($base_url, '/') . '/';
262
    }
263
264
    /**
265
     * Returns Client Ip Address
266
     *
267
     * @param  integer $type Ip address or ipv4 address
268
     * @return string
269
     */
270
    public function getClientIp($type = 0)
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...
271
    {
272
        $type = $type ? 1 : 0;
273
274
        if ($this->_ip !== null) {
275
            return $this->_ip[$type];
276
        }
277
278
        if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
279
            $this->_ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
280
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
281
            $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
282
            $pos = array_search('unknown', $arr);
283
            if (false !== $pos) {
284
                unset($arr[$pos]);
285
            }
286
287
            $this->_ip = trim($arr[0]);
0 ignored issues
show
Documentation Bug introduced by
It seems like trim($arr[0]) of type string is incompatible with the declared type array of property $_ip.

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...
288
        } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
289
            $this->_ip = $_SERVER['HTTP_CLIENT_IP'];
290
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
291
            $this->_ip = $_SERVER['REMOTE_ADDR'];
292
        }
293
294
        // Check ip
295
        $long = sprintf("%u", ip2long($this->_ip));
296
        $this->_ip = $long ? [$this->_ip, $long] : ['0.0.0.0', 0];
297
        return $this->_ip[$type];
298
    }
299
300
    /**
301
     * Returns Http Host
302
     *
303
     * @return string
304
     */
305
    public function getHostName()
0 ignored issues
show
Coding Style introduced by
getHostName 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...
306
    {
307
        $possibleHostSources = ['HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR'];
308
        $sourceTransformations = [
309
            "HTTP_X_FORWARDED_HOST" => function ($value) {
310
                $elements = explode(',', $value);
311
                return trim(end($elements));
312
            },
313
        ];
314
        $host = '';
315
        foreach ($possibleHostSources as $source) {
316
            if (!empty($host)) {
317
                break;
318
            }
319
320
            if (empty($_SERVER[$source])) {
321
                continue;
322
            }
323
324
            $host = $_SERVER[$source];
325
            if (array_key_exists($source, $sourceTransformations)) {
326
                $host = $sourceTransformations[$source]($host);
327
            }
328
        }
329
330
        // Remove port number from host
331
        $host = preg_replace('/:\d+$/', '', $host);
332
333
        return trim($host);
334
    }
335
336
    /**
337
     * Detect whether request method is GET
338
     *
339
     * @return boolean
340
     */
341
    public function isGet()
0 ignored issues
show
Coding Style introduced by
isGet 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...
342
    {
343
        return 'GET' == $_SERVER['REQUEST_METHOD'];
344
    }
345
346
    /**
347
     * Detect whether request method is POST
348
     *
349
     * @return boolean
350
     */
351
    public function isPost()
0 ignored issues
show
Coding Style introduced by
isPost 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...
352
    {
353
        return 'POST' == $_SERVER['REQUEST_METHOD'];
354
    }
355
356
    /**
357
     * Detect whether request method is PUT
358
     *
359
     * @return boolean
360
     */
361
    public function isPut()
0 ignored issues
show
Coding Style introduced by
isPut 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...
362
    {
363
        return 'PUT' == $_SERVER['REQUEST_METHOD'];
364
    }
365
366
    /**
367
     * Detect whether request method is AJAX
368
     *
369
     * @return boolean
370
     */
371
    public function isAjax()
0 ignored issues
show
Coding Style introduced by
isAjax 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...
372
    {
373
        return ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')) ? true : false;
374
    }
375
376
    /**
377
     * Is CLI?
378
     *
379
     * Test to see if a request was made from the command line.
380
     *
381
     * @return  boolean
382
     */
383
    public function isCli()
384
    {
385
        return PHP_SAPI === 'cli';
386
    }
387
388
    /**
389
     * Detect whether user agent is Mobile
390
     *
391
     * @return boolean
392
     */
393
    public function isMobile()
0 ignored issues
show
Coding Style introduced by
isMobile 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...
394
    {
395
        $userAgent = isset($_SERVER['USER_AGENT']) ? $_SERVER['USER_AGENT'] : null;
396
        if ($userAgent == null) {
397
            return false;
398
        }
399
400
        return preg_match('/android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i', $userAgent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr($userAgent, 0, 4));
401
    }
402
}
403