Completed
Push — master ( 593857...cd1c2d )
by Michael
29s queued 20s
created

HttpRequest::getEnv()   D

Complexity

Conditions 21
Paths 114

Size

Total Lines 64
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 21.441

Importance

Changes 0
Metric Value
cc 21
eloc 46
nc 114
nop 2
dl 0
loc 64
rs 4.05
c 0
b 0
f 0
ccs 36
cts 40
cp 0.9
crap 21.441

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
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()
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 24
    public static function getInstance()
181
    {
182 24
        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; you can either use self, or increase the visibility of $instance to at least protected.
Loading history...
183
            static::$instance = new static();
184
        }
185 24
        return static::$instance;
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 3
    public function getHeader($name = null)
196
    {
197 3
        if ($name === null) {
198
            return $name;
199
        }
200
201
        // Try to get it from the $_SERVER array first
202 3
        if ($res = $this->getEnv('HTTP_' . strtoupper(str_replace('-', '_', $name)))) {
203 3
            return $res;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $res also could return the type true which is incompatible with the documented return type null|string.
Loading history...
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 3
    public function getHost()
233
    {
234 3
        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()
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') : '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getEnv('HT...nv('HTTP_REFERER') : '' also could return the type boolean which is incompatible with the documented return type string.
Loading history...
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')
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getEnv('SC...ORIG_SCRIPT_NAME') : '' also could return the type boolean which is incompatible with the documented return type string.
Loading history...
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)
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 21
    public function getEnv($name, $default = null)
381
    {
382 21
        if ($name === 'HTTPS') {
383 2
            if (isset($_SERVER['HTTPS'])) {
384 2
                return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
385
            }
386 2
            return (strpos($this->getEnv('SCRIPT_URI'), 'https://') === 0);
387
        }
388
389 21
        if ($name === 'SCRIPT_NAME' && !isset($_SERVER[$name])) {
390 1
            if ($this->getEnv('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) {
391
                return $_ENV['SCRIPT_URL'];
392
            }
393
        }
394
395 21
        if ($name === 'REMOTE_ADDR' && !isset($_SERVER[$name])) {
396
            $address = $this->getEnv('HTTP_PC_REMOTE_ADDR');
397
            if ($address !== null) {
0 ignored issues
show
introduced by
The condition $address !== null is always true.
Loading history...
398
                return $address;
399
            }
400
        }
401
402 21
        $val = null;
403 21
        if (isset($_SERVER[$name])) {
404 19
            $val = $_SERVER[$name];
405 10
        } elseif (isset($_ENV[$name])) {
406 1
            $val = $_ENV[$name];
407
        }
408
409 21
        if ($val !== null) {
410 19
            return $val;
411
        }
412
413
        switch ($name) {
414 10
            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 9
            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;
427 8
            case 'PHP_SELF':
428 1
                return str_replace($this->getEnv('DOCUMENT_ROOT'), '', $this->getEnv('SCRIPT_FILENAME'));
429
                break;
430 7
            case 'CGI_MODE':
431 2
                return (PHP_SAPI === 'cgi');
432
                break;
433 6
            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;
442
        }
443 5
        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)
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
introduced by
The use of eval() is discouraged.
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 2
    public function getAcceptMediaTypes()
610
    {
611 2
        $types = array();
612 2
        $accept = $this->getHeader('ACCEPT');
613
614 2
        if (!empty($accept)) {
615 2
            $entries = explode(',', $accept);
616 2
            foreach ($entries as $e) {
617 2
                $mt = explode(';q=', $e);
618 2
                if (!isset($mt[1])) {
619 2
                    $mt[1] = 1.0;
620
                }
621 2
                $types[trim($mt[0])] = (float) $mt[1];
622
            }
623
624
            // sort list based on value
625 2
            arsort($types, SORT_NUMERIC);
626
        }
627
628 2
        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
    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