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.

LanguageNegotiator::__construct()   A
last analyzed

Complexity

Conditions 5
Paths 2

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 9.1448
c 0
b 0
f 0
cc 5
nc 2
nop 3
1
<?php
2
3
namespace Mcamara\LaravelLocalization;
4
5
use Illuminate\Config\Repository;
6
use Illuminate\Foundation\Application;
7
use Illuminate\Http\Request;
8
use Locale;
9
10
class LanguageNegotiator
11
{
12
13
    /**
14
     * Config repository.
15
     *
16
     * @var \Illuminate\Config\Repository
17
     */
18
    protected $configRepository;
19
20
    /**
21
     * Illuminate request class.
22
     *
23
     * @var Illuminate\Foundation\Application
24
     */
25
    protected $app;
26
27
    /**
28
     * @var string
29
     */
30
    private $defaultLocale;
31
32
    /**
33
     * @var array
34
     */
35
    private $supportedLanguages;
36
37
    /**
38
     * @var Request
39
     */
40
    private $request;
41
42
    /**
43
     * @var bool
44
     */
45
    private $use_intl = false;
46
47
    /**
48
     * @param string  $defaultLocale
49
     * @param array   $supportedLanguages
50
     * @param Request $request
51
     */
52
    public function __construct($defaultLocale, $supportedLanguages, Request $request)
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
53
    {
54
        $this->app = app();
55
56
        $this->configRepository = $this->app['config'];
57
58
        $this->defaultLocale = $defaultLocale;
59
60
        if (class_exists('Locale')) {
61
            $this->use_intl = true;
62
63
            foreach ($supportedLanguages as $key => $supportedLanguage) {
64
                if ( ! isset($supportedLanguage['lang'])) {
65
                    $supportedLanguage['lang'] = Locale::canonicalize($key);
66
                } else {
67
                    $supportedLanguage['lang'] = Locale::canonicalize($supportedLanguage['lang']);
68
                }
69
                if (isset($supportedLanguage['regional'])) {
70
                    $supportedLanguage['regional'] = Locale::canonicalize($supportedLanguage['regional']);
71
                }
72
73
                $this->supportedLanguages[$key] = $supportedLanguage;
74
            }
75
        } else {
76
            $this->supportedLanguages = $supportedLanguages;
77
        }
78
79
        $this->request = $request;
80
    }
81
82
    /**
83
     * Negotiates language with the user's browser through the Accept-Language
84
     * HTTP header or the user's host address.  Language codes are generally in
85
     * the form "ll" for a language spoken in only one country, or "ll-CC" for a
86
     * language spoken in a particular country.  For example, U.S. English is
87
     * "en-US", while British English is "en-UK".  Portuguese as spoken in
88
     * Portugal is "pt-PT", while Brazilian Portuguese is "pt-BR".
89
     *
90
     * This function is based on negotiateLanguage from Pear HTTP2
91
     * http://pear.php.net/package/HTTP2/
92
     *
93
     * Quality factors in the Accept-Language: header are supported, e.g.:
94
     *      Accept-Language: en-UK;q=0.7, en-US;q=0.6, no, dk;q=0.8
95
     *
96
     * @return string The negotiated language result or app.locale.
97
     */
98
    public function negotiateLanguage()
99
    {
100
        $matches = $this->getMatchesFromAcceptedLanguages();
101
        foreach ($matches as $key => $q) {
102
103
            $key = ($this->configRepository->get('laravellocalization.localesMapping')[$key]) ?? $key;
104
105
            if (!empty($this->supportedLanguages[$key])) {
106
                return $key;
107
            }
108
109
            if ($this->use_intl) {
110
                $key = Locale::canonicalize($key);
111
            }
112
113
            // Search for acceptable locale by 'regional' => 'af_ZA' or 'lang' => 'af-ZA' match.
114
            foreach ( $this->supportedLanguages as $key_supported => $locale ) {
115
                if ( (isset($locale['regional']) && $locale['regional'] == $key) || (isset($locale['lang']) && $locale['lang'] == $key) ) {
116
                    return $key_supported;
117
                }
118
            }
119
        }
120
        // If any (i.e. "*") is acceptable, return the first supported format
121
        if (isset($matches['*'])) {
122
            reset($this->supportedLanguages);
123
124
            return key($this->supportedLanguages);
125
        }
126
127
        if ($this->use_intl && !empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
128
            $http_accept_language = Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
129
130
            if (!empty($this->supportedLanguages[$http_accept_language])) {
131
                return $http_accept_language;
132
            }
133
        }
134
135
        if ($this->request->server('REMOTE_HOST')) {
136
            $remote_host = explode('.', $this->request->server('REMOTE_HOST'));
137
            $lang = strtolower(end($remote_host));
138
139
            if (!empty($this->supportedLanguages[$lang])) {
140
                return $lang;
141
            }
142
        }
143
144
        return $this->defaultLocale;
145
    }
146
147
    /**
148
     * Return all the accepted languages from the browser.
149
     *
150
     * @return array Matches from the header field Accept-Languages
151
     */
152
    private function getMatchesFromAcceptedLanguages()
153
    {
154
        $matches = [];
155
156
        if ($acceptLanguages = $this->request->header('Accept-Language')) {
157
            $acceptLanguages = explode(',', $acceptLanguages);
158
159
            $generic_matches = [];
160
            foreach ($acceptLanguages as $option) {
161
                $option = array_map('trim', explode(';', $option));
162
                $l = $option[0];
163
                if (isset($option[1])) {
164
                    $q = (float) str_replace('q=', '', $option[1]);
165
                } else {
166
                    $q = null;
167
                    // Assign default low weight for generic values
168
                    if ($l == '*/*') {
169
                        $q = 0.01;
170
                    } elseif (substr($l, -1) == '*') {
171
                        $q = 0.02;
172
                    }
173
                }
174
                // Unweighted values, get high weight by their position in the
175
                // list
176
                $q = $q ?? 1000 - \count($matches);
177
                $matches[$l] = $q;
178
179
                //If for some reason the Accept-Language header only sends language with country
180
                //we should make the language without country an accepted option, with a value
181
                //less than it's parent.
182
                $l_ops = explode('-', $l);
183
                array_pop($l_ops);
184
                while (!empty($l_ops)) {
185
                    //The new generic option needs to be slightly less important than it's base
186
                    $q -= 0.001;
187
                    $op = implode('-', $l_ops);
188
                    if (empty($generic_matches[$op]) || $generic_matches[$op] > $q) {
189
                        $generic_matches[$op] = $q;
190
                    }
191
                    array_pop($l_ops);
192
                }
193
            }
194
            $matches = array_merge($generic_matches, $matches);
195
196
            arsort($matches, SORT_NUMERIC);
197
        }
198
199
        return $matches;
200
    }
201
}
202