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 ( 975dad...2d62a5 )
by やかみ
05:10
created

Request::getBaseUrl()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4.0466

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 3
nop 0
dl 0
loc 11
ccs 6
cts 7
cp 0.8571
crap 4.0466
rs 9.2
c 0
b 0
f 0
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\Debug\Hook;
35
use Kotori\Interfaces\SoulInterface;
36
use Kotori\Traits\SoulTrait;
37
38
class Request implements SoulInterface
39
{
40
    use SoulTrait;
41
42
    /**
43
     * Ip address
44
     *
45
     * @var mixed
46
     */
47
    protected $_ip = null;
48
49
    /**
50
     * Class constructor
51
     *
52
     * Initialize Request.
53
     *
54
     * @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...
55
     */
56 7
    public function __construct()
57
    {
58 7
        Hook::listen(__CLASS__);
59 7
    }
60
61
    /**
62
     * Internal method used to retrieve values from given arrays.
63
     *
64
     * @param  array $source $_GET, $_POST, $_COOKIE, $_SERVER, etc.
65
     * @param  mixed $key Index for item to be fetched from $source
66
     * @return mixed
67
     */
68
    protected function getRequestParams(&$source, $key = null)
69
    {
70
        // If $key is NULL, it means that the whole $source is requested
71
        if (!isset($key) || $key == null) {
72
            $key = array_keys($source);
73
        }
74
75
        if (is_array($key)) {
76
            $output = [];
77
            foreach ($key as $k) {
78
                $output[$k] = $this->getRequestParams($source, $k);
79
            }
80
81
            return $output;
82
        }
83
84
        if (isset($source[$key])) {
85
            $value = $source[$key];
86
        } else {
87
            return null;
88
        }
89
90
        return $value;
91
92
    }
93
94
    /**
95
     * Fetch an item from the GET array
96
     *
97
     * @param  mixed $key Index for item to be fetched from $_GET
98
     * @return mixed
99
     */
100
    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...
101
    {
102
        return $this->getRequestParams($_GET, $key);
103
    }
104
105
    /**
106
     * Fetch an item from the POST array
107
     *
108
     * @param  mixed $key Index for item to be fetched from $_POST
109
     * @return mixed
110
     */
111
    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...
112
    {
113
        $rawPostData = file_get_contents('php://input');
114
        $source = json_decode($rawPostData, true);
115
        if (json_last_error() != JSON_ERROR_NONE) {
116
            $source = $_POST;
117
        }
118
119
        return $this->getRequestParams($source, $key);
120
    }
121
122
    /**
123
     * Fetch an item from the SERVER array
124
     *
125
     * @param  mixed $key Index for item to be fetched from $_SERVER
126
     * @return mixed
127
     */
128
    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...
129
    {
130
        return $this->getRequestParams($_SERVER, $key);
131
    }
132
133
    /**
134
     * Set or Get cookie
135
     *
136
     * @param  mixed $key Index for item for cookie
137
     * @param  string $value cookie value
138
     * @param  mixed  options for cookie setting
139
     * @return mixed
140
     */
141 2
    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...
142
    {
143
        $defaultOptions = [
144 2
            'prefix' => '',
145 2
            'expire' => 86400,
146 2
            'path' => '/',
147 2
            'secure' => false,
148 2
            'httponly' => false,
149 2
        ];
150
151 2
        if (!is_null($options)) {
152
            if (is_numeric($options)) {
153
                $options = ['expire' => $options];
154
            } elseif (is_string($options)) {
155
                parse_str($options, $options);
156
            }
157
158
            $options = array_merge($defaultOptions, array_change_key_case($options));
159
        }
160
161 2
        if (!empty($options['httponly'])) {
162
            ini_set('session.cookie_httponly', 1);
163
        }
164
165 2
        if (is_null($key)) {
166
            if (empty($_COOKIE)) {
167
                return null;
168
            }
169
170
            $prefix = empty($value) ? $options['prefix'] : $value;
171
            if (!empty($prefix)) {
172
                foreach ($_COOKIE as $key => $val) {
173
                    if (0 === stripos($key, $prefix)) {
174
                        setcookie($key, '', time() - 3600, $options['path'], $options['domain'], $options['secure'], $options['httponly']);
175
                        unset($_COOKIE[$key]);
176
                    }
177
                }
178
            }
179
180
            return null;
181 2
        } elseif ('' === $key) {
182
            // Get All Cookie
183
            return $_COOKIE;
184
        }
185
186 2
        $key = $options['prefix'] . str_replace('.', '_', $key);
187 2
        if ('' === $value) {
188 2
            if (isset($_COOKIE[$key])) {
189 1
                $value = $_COOKIE[$key];
190 1
                if (0 === strpos($value, 'kotori:')) {
191
                    $value = substr($value, 6);
192
                    return array_map('urldecode', json_decode(MAGIC_QUOTES_GPC ? stripslashes($value) : $value, true));
193
                } else {
194 1
                    return $value;
195
                }
196
            } else {
197 1
                return null;
198
            }
199
        } else {
200 2
            if (is_null($value)) {
201 1
                setcookie($key, '', time() - 3600, $options['path'], $options['domain'], $options['secure'], $options['httponly']);
202 1
                unset($_COOKIE[$key]); // Delete Cookie
203 1
            } else {
204
                // Set Cookie
205 2
                if (is_array($value)) {
206
                    $value = 'kotori:' . json_encode(array_map('urlencode', $value));
207
                }
208
209 2
                $expire = !empty($options['expire']) ? time() + intval($options['expire']) : 0;
210 2
                setcookie($key, $value, $expire, $options['path'], $options['domain'], $options['secure'], $options['httponly']);
211 2
                $_COOKIE[$key] = $value;
212
            }
213
        }
214
215 2
        return null;
216
    }
217
218
    /**
219
     * Is HTTPS?
220
     *
221
     * Determines if the application is accessed via an encrypted
222
     * (HTTPS) connection.
223
     *
224
     * @return  boolean
225
     */
226 2
    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...
227
    {
228 2
        if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') {
229
            return true;
230 2
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO']) {
231
            return true;
232 2
        } elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
233
            return true;
234
        }
235
236 2
        return false;
237
    }
238
239
    /**
240
     * Base URL
241
     *
242
     * Returns base url
243
     *
244
     * @return string
245
     */
246 1
    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...
247
    {
248 1
        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'])) {
249 1
            $base_url = (Request::getSoul()->isSecure() ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']
250 1
            . substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME'])));
251 1
        } else {
252
            $base_url = 'http://localhost/';
253
        }
254
255 1
        return rtrim($base_url, '/') . '/';
256
    }
257
258
    /**
259
     * Returns Client Ip Address
260
     *
261
     * @param  integer $type Ip address or ipv4 address
262
     * @return string
263
     */
264 1
    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...
265
    {
266 1
        $type = $type ? 1 : 0;
267
268 1
        if ($this->_ip !== null) {
269
            return $this->_ip[$type];
270
        }
271
272 1
        if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
273
            $this->_ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
274 1
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
275
            $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
276
            $pos = array_search('unknown', $arr);
277
            if (false !== $pos) {
278
                unset($arr[$pos]);
279
            }
280
281
            $this->_ip = trim($arr[0]);
282 1
        } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
283
            $this->_ip = $_SERVER['HTTP_CLIENT_IP'];
284 1
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
285 1
            $this->_ip = $_SERVER['REMOTE_ADDR'];
286 1
        }
287
288
        // Check ip
289 1
        $long = sprintf("%u", ip2long($this->_ip));
290 1
        $this->_ip = $long ? [$this->_ip, $long] : ['0.0.0.0', 0];
291 1
        return $this->_ip[$type];
292
    }
293
294
    /**
295
     * Returns Http Host
296
     *
297
     * @return string
298
     */
299 1
    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...
300
    {
301 1
        $possibleHostSources = ['HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR'];
302
        $sourceTransformations = [
303 1
            "HTTP_X_FORWARDED_HOST" => function ($value) {
304
                $elements = explode(',', $value);
305
                return trim(end($elements));
306 1
            },
307 1
        ];
308 1
        $host = '';
309 1
        foreach ($possibleHostSources as $source) {
310 1
            if (!empty($host)) {
311 1
                break;
312
            }
313
314 1
            if (empty($_SERVER[$source])) {
315 1
                continue;
316
            }
317
318 1
            $host = $_SERVER[$source];
319 1
            if (array_key_exists($source, $sourceTransformations)) {
320
                $host = $sourceTransformations[$source]($host);
321
            }
322 1
        }
323
324
        // Remove port number from host
325 1
        $host = preg_replace('/:\d+$/', '', $host);
326
327 1
        return trim($host);
328
    }
329
330
    /**
331
     * Detect whether request method is GET
332
     *
333
     * @return boolean
334
     */
335
    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...
336
    {
337
        return 'GET' == $_SERVER['REQUEST_METHOD'];
338
    }
339
340
    /**
341
     * Detect whether request method is POST
342
     *
343
     * @return boolean
344
     */
345
    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...
346
    {
347
        return 'POST' == $_SERVER['REQUEST_METHOD'];
348
    }
349
350
    /**
351
     * Detect whether request method is PUT
352
     *
353
     * @return boolean
354
     */
355
    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...
356
    {
357
        return 'PUT' == $_SERVER['REQUEST_METHOD'];
358
    }
359
360
    /**
361
     * Detect whether request method is AJAX
362
     *
363
     * @return boolean
364
     */
365
    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...
366
    {
367
        return ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')) ? true : false;
368
    }
369
370
    /**
371
     * Is CLI?
372
     *
373
     * Test to see if a request was made from the command line.
374
     *
375
     * @return  boolean
376
     */
377
    public function isCli()
378
    {
379
        return PHP_SAPI === 'cli';
380
    }
381
382
    /**
383
     * Detect whether user agent is Mobile
384
     *
385
     * @return boolean
386
     */
387 1
    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...
388
    {
389 1
        $userAgent = isset($_SERVER['USER_AGENT']) ? $_SERVER['USER_AGENT'] : null;
390 1
        if ($userAgent == null) {
391 1
            return false;
392
        }
393
394
        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));
395
    }
396
}
397