Passed
Pull Request — master (#17)
by Michael
03:16 queued 42s
created

Utility::detectLang()   A

Complexity

Conditions 6
Paths 16

Size

Total Lines 43
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 13
nc 16
nop 0
dl 0
loc 43
rs 9.2222
c 1
b 0
f 0
1
<?php
2
3
namespace XoopsModules\Xlanguage;
4
5
use XoopsModules\Xlanguage\{Common
6
};
7
use Xmf\Request;
8
9
10
11
/** @var Helper $helper */
12
/** @var LanguageHandler $languageHandler */
13
14
/**
15
 * Class Utility
16
 */
17
class Utility extends Common\SysUtility
18
{
19
    //--------------- Custom module methods -----------------------------
20
    /**
21
     * @param $value
22
     * @param $out_charset
23
     * @param $in_charset
24
     * @return array|string
25
     */
26
    public static function convertEncoding($value, $out_charset, $in_charset)
27
    {
28
        if (\is_array($value)) {
29
            foreach ($value as $key => $val) {
30
                $value[$key] = static::convertEncoding($val, $out_charset, $in_charset);
31
            }
32
        } else {
33
            $value = static::convertItem($value, $out_charset, $in_charset);
34
        }
35
36
        return $value;
37
    }
38
39
    /**
40
     * @param $value
41
     * @param $out_charset
42
     * @param $in_charset
43
     * @return string
44
     */
45
    public static function convertItem($value, $out_charset, $in_charset)
46
    {
47
        if (mb_strtolower($in_charset) == mb_strtolower($out_charset)) {
48
            return $value;
49
        }
50
51
        $xconvHandler = @\xoops_getModuleHandler('xconv', 'xconv', true);
52
        if (\is_object($xconvHandler) && $convertedValue = @$xconvHandler->convert_encoding($value, $out_charset, $in_charset)) {
0 ignored issues
show
Bug introduced by
The method convert_encoding() does not exist on XoopsObjectHandler. It seems like you code against a sub-type of XoopsObjectHandler such as XoopsPersistableObjectHandler. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
        if (\is_object($xconvHandler) && $convertedValue = @$xconvHandler->/** @scrutinizer ignore-call */ convert_encoding($value, $out_charset, $in_charset)) {
Loading history...
53
            return $convertedValue;
54
        }
55
        if (XOOPS_USE_MULTIBYTES && \function_exists('mb_convert_encoding')) {
56
            $convertedValue = @mb_convert_encoding($value, $out_charset, $in_charset);
57
        } elseif (\function_exists('iconv')) {
58
            $convertedValue = @\iconv($in_charset, $out_charset, $value);
59
        }
60
        $value = empty($convertedValue) ? $value : $convertedValue;
61
62
        return $value;
63
    }
64
65
    /**
66
     * @return mixed
67
     */
68
    public static function createConfig()
69
    {
70
        $helper          = Helper::getInstance();
71
        $languageHandler = $helper->getHandler('Language');
72
73
        return $languageHandler->createConfig();
74
    }
75
76
    /**
77
     * @return mixed
78
     */
79
    public static function loadConfig()
80
    {
81
        $helper          = Helper::getInstance();
82
        $languageHandler = $helper->getHandler('Language');
83
        $config          = $languageHandler->loadFileConfig();
84
85
        return $config;
86
    }
87
88
    /**
89
     * Analyzes some PHP environment variables to find the most probable language
90
     * that should be used
91
     *
92
     * @param string $str
93
     * @param string $envType
94
     * @return int|string
95
     * @internal param $string $ string to analyze
96
     * @internal param $integer $ type of the PHP environment variable which value is $str
97
     *
98
     * @global        array    the list of available translations
99
     * @global        string   the retained translation keyword
100
     * @access   private
101
     */
102
    public static function langDetect($str = '', $envType = '')
103
    {
104
        global $available_languages;
105
        $lang = '';
106
107
        if (!empty($available_languages)) {
108
            foreach ($available_languages as $key => $value) {
109
                // $envType =  1 for the 'HTTP_ACCEPT_LANGUAGE' environment variable,
110
                //             2 for the 'HTTP_USER_AGENT' one
111
                $expr = $value[0];
112
                if (false === mb_strpos($expr, '[-_]')) {
113
                    $expr = \str_replace('|', '([-_][[:alpha:]]{2,3})?|', $expr);
114
                }
115
                //        if (($envType == 1 && eregi('^(' . $expr . ')(;q=[0-9]\\.[0-9])?$', $str))
116
                //            || ($envType == 2 && eregi('(\(|\[|;[[:space:]])(' . $expr . ')(;|\]|\))', $str))) {
117
                if ((1 == $envType && \preg_match('#^(' . $expr . ')(;q=[0-9]\\.[0-9])?$#i', $str)) || (2 == $envType && \preg_match('#(\(|\[|;[[:space:]])(' . $expr . ')(;|\]|\))#i', $str))) {
118
                    $lang = $key;
119
                    //if($lang != 'en')
120
                    break;
121
                }
122
            }
123
        }
124
125
        return $lang;
126
    }
127
128
    /**
129
     * @return string
130
     */
131
    public static function detectLang()
132
    {
133
        global $available_languages, $_SERVER;
134
135
        //      if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
136
        if (Request::hasVar('HTTP_ACCEPT_LANGUAGE', 'SERVER')) {
137
            $HTTP_ACCEPT_LANGUAGE = Request::getString('HTTP_ACCEPT_LANGUAGE', '', 'SERVER');
0 ignored issues
show
Unused Code introduced by
The assignment to $HTTP_ACCEPT_LANGUAGE is dead and can be removed.
Loading history...
138
        }
139
140
        //if (!empty($_SERVER['HTTP_USER_AGENT'])) {
141
        if (Request::hasVar('HTTP_USER_AGENT', 'SERVER')) {
142
            $HTTP_USER_AGENT = Request::getString('HTTP_USER_AGENT', '', 'SERVER');
143
        }
144
145
        $lang       = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
146
        $xoops_lang = '';
147
        // 1. try to findout user's language by checking its HTTP_ACCEPT_LANGUAGE variable
148
149
        //    if (empty($lang) && !empty($HTTP_ACCEPT_LANGUAGE)) {
150
        //        $accepted    = explode(',', $HTTP_ACCEPT_LANGUAGE);
151
        //        $acceptedCnt = count($accepted);
152
        //        reset($accepted);
153
        //        for ($i = 0; $i < $acceptedCnt; ++$i) {
154
        //            $lang = static::langDetect($accepted[$i], 1);
155
        //            if (strncasecmp($lang, 'en', 2)) {
156
        //                break;
157
        //            }
158
        //        }
159
        //    }
160
161
        //This returns the most preferred language "q=1"
162
        $lang = static::getPreferredLanguage();
163
164
        // 2. if not found in HTTP_ACCEPT_LANGUAGE, try to find user's language by checking its HTTP_USER_AGENT variable
165
        if (empty($lang) && !empty($HTTP_USER_AGENT)) {
166
            $lang = static::langDetect($HTTP_USER_AGENT, 2);
167
        }
168
        // 3. If we catch a valid language, configure it
169
        if (!empty($lang)) {
170
            $xoops_lang = $available_languages[$lang][1];
171
        }
172
173
        return $xoops_lang;
174
    }
175
176
    /**
177
     * @param $output
178
     * @return array|mixed|string
179
     */
180
    public static function encodeCharSet($output)
181
    {
182
        global $xlanguage;
183
        $output = static::cleanMultiLang($output);
184
        // escape XML doc
185
        if (\preg_match("/^\<\?[\s]?xml[\s]+version=([\"'])[^\>]+\\1[\s]+encoding=([\"'])[^\>]+\\2[\s]?\?\>/i", $output)) {
0 ignored issues
show
Bug introduced by
It seems like $output can also be of type array and null and string[]; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

185
        if (\preg_match("/^\<\?[\s]?xml[\s]+version=([\"'])[^\>]+\\1[\s]+encoding=([\"'])[^\>]+\\2[\s]?\?\>/i", /** @scrutinizer ignore-type */ $output)) {
Loading history...
186
            return $output;
187
        }
188
        $in_charset  = $xlanguage['charset_base'];
189
        $out_charset = $xlanguage['charset'];
190
191
        $output = static::convertEncoding($output, $out_charset, $in_charset);
192
193
        return $output;
194
    }
195
196
    /**
197
     * @param string $text
198
     * @return array|string|string[]|null
199
     */
200
    public static function cleanMultiLang($text)
201
    {
202
        global $xoopsConfig;
203
        global $xlanguage_langs;
204
        $patterns = [];
205
        if (!isset($xlanguage_langs)) {
206
            $xlanguage_langs = [];
207
            $helper          = Helper::getInstance();
208
            $languageHandler = $helper->getHandler('Language');
209
            $langs           = $languageHandler->getAll(true);
210
            //        $langs = $GLOBALS['xlanguageHandler']->getAll(true); //mb
211
            if (false !== $langs) {
212
                foreach (\array_keys($langs) as $_lang) {
213
                    $xlanguage_langs[$_lang] = $langs[$_lang]->getVar('lang_code');
214
                }
215
            }
216
            unset($langs);
217
        }
218
        if (empty($xlanguage_langs) || 0 == \count($xlanguage_langs)) {
219
            return $text;
220
        }
221
222
        // escape brackets inside of <code>...</code>
223
        $patterns[] = '/(\<code>.*\<\/code>)/isU';
224
225
        // escape brackets inside of <input type="..." value="...">
226
        $patterns[] = '/(\<input\b(?![^\>]*\btype=([\'"]?)(submit|image|reset|button))[^\>]*\>)/isU';
227
228
        // escape brackets inside of <textarea></textarea>
229
        $patterns[] = '/(\<textarea\b[^>]*>[^\<]*\<\/textarea>)/isU';
230
231
        $text = \preg_replace_callback($patterns, 'static::escapeBracketMultiLang', $text);
232
233
        // create the pattern between language tags
234
        $pqhtmltags  = \explode(',', preg_quote(\XLANGUAGE_TAGS_RESERVED, '/'));
0 ignored issues
show
Unused Code introduced by
The assignment to $pqhtmltags is dead and can be removed.
Loading history...
235
        $mid_pattern = '(?:(?!(' . \str_replace(',', '|', preg_quote(\XLANGUAGE_TAGS_RESERVED, '/')) . ')).)*';
236
237
        $patterns = [];
238
        $replaces = [];
239
240
        if (isset($xlanguage_langs[$xoopsConfig['language']])) {
241
            $lang       = $xlanguage_langs[$xoopsConfig['language']];
242
            $patterns[] = '/(\[([^\]]*\|)?' . preg_quote($lang, '~') . '(\|[^\]]*)?\])(' . $mid_pattern . ')(\[\/([^\]]*\|)?' . preg_quote($lang, '~') . '(\|[^\]]*)?\])/isU';
243
            $replaces[] = '$4';
244
        }
245
246
        foreach (\array_keys($xlanguage_langs) as $_lang) {
247
            if ($_lang == @$xoopsConfig['language']) {
248
                continue;
249
            }
250
            $name       = $xlanguage_langs[$_lang];
251
            $patterns[] = '/(\[([^\]]*\|)?' . preg_quote($name, '~') . '(\|[^\]]*)?\])(' . $mid_pattern . ')(\[\/([^\]]*\|)?' . preg_quote($name, '~') . '(\|[^\]]*)?(\]\<br[\s]?[\/]?\>|\]))/isU';
252
            $replaces[] = '';
253
        }
254
        if (!empty($xoopsConfig['language'])) {
255
            $text = \preg_replace('/\[[\/]?[\|]?' . preg_quote($xoopsConfig['language'], '~') . '[\|]?\](\<br \/\>)?/i', '', $text);
256
        }
257
        if (\count($replaces) > 0) {
258
            $text = \preg_replace($patterns, $replaces, $text);
259
        }
260
261
        return $text;
262
    }
263
264
    /**
265
     * @param $matches
266
     * @return mixed
267
     */
268
    public static function escapeBracketMultiLang($matches)
269
    {
270
        global $xlanguage_langs;
271
        $ret = $matches[1];
272
        if (!empty($xlanguage_langs)) {
273
            $pattern = '/(\[([\/])?(' . \implode('|', \array_map('\preg_quote', \array_values($xlanguage_langs))) . ')([\|\]]))/isU';
274
            $ret     = \preg_replace($pattern, '&#91;\\2\\3\\4', $ret);
275
        }
276
277
        return $ret;
278
    }
279
280
    /**
281
     * @param null|array $options
282
     * @return bool
283
     */
284
    public static function showSelectedLanguage($options = null)
285
    {
286
        require_once XOOPS_ROOT_PATH . '/modules/xlanguage/blocks/xlanguage_blocks.php';
287
        if (empty($options)) {
288
            $options[0] = 'images'; // display style: image, text, select
289
            $options[1] = ' '; // delimitor
290
            $options[2] = 5; // items per line
291
        }
292
293
        $block        = \b_xlanguage_select_show($options);
294
        $block['tag'] = 'xlanguage';
295
296
        $content = '';
297
        $i       = 1;
298
        if (!empty($block['display'])) { //mb
299
            if (\in_array($block['display'], ['images', 'text'])) {
300
                foreach ($block['languages'] as $name => $lang) {
301
                    $content .= '<a href="' . $block['url'] . $lang['name'] . '" title="' . $lang['desc'] . '">';
302
                    if ('images' === $block['display']) {
303
                        $content .= '<img src="' . $lang['image'] . '" alt="' . $lang['desc'] . '"';
304
                        if ($block['selected'] != $lang['name']) {
305
                            $content .= ' style="MozOpacity: .8; opacity: .8; filter:Alpha(opacity=80);"';
306
                        }
307
                        $content .= '>';
308
                    } else {
309
                        $content .= $lang['desc'];
310
                    }
311
                    $content .= '</a>';
312
                    if (0 == (++$i % $block['number'])) {
313
                        $content .= '<br>';
314
                    }
315
                }
316
            } else {
317
                $content .= '<select name="' . $block['tag'] . '"
318
                onChange="if (this.options[this.selectedIndex].value.length >0) { window.document.location=this.options[this.selectedIndex].value;}"
319
                >';
320
                if (!empty($block['languages'])) { //mb
321
                    foreach ($block['languages'] as $name => $lang) {
322
                        $content .= '<option value="' . $block['url'] . $lang['name'] . '"';
323
                        if ($block['selected'] == $lang['name']) {
324
                            $content .= ' selected ';
325
                        }
326
                        $content .= '>' . $lang['desc'] . '</option>';
327
                    }
328
                }
329
                $content .= '</select>';
330
            }
331
        }
332
333
        \define('XLANGUAGE_SWITCH_CODE', $content);
334
335
        return true;
336
    }
337
338
    /**
339
     * @return int|string
340
     */
341
    public static function getPreferredLanguage()
342
    {
343
        $langs = [];
344
        $lang  = '';
345
        //        if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
346
        if (Request::hasVar('HTTP_ACCEPT_LANGUAGE', 'SERVER')) {
347
            // break up string into pieces (languages and q factors)
348
            $temp = Request::getString('HTTP_ACCEPT_LANGUAGE', '', 'SERVER');
349
            \preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.\d+))?/i', $temp, $lang_parse);
350
            if (\count($lang_parse[1])) {
351
                // create a list like "en" => 0.8
352
                $langs = \array_combine($lang_parse[1], $lang_parse[4]);
353
                // set default to 1 for any without q factor
354
                foreach ($langs as $lang => $val) {
355
                    if ('' === $val) {
356
                        $langs[$lang] = 1;
357
                    }
358
                }
359
                // sort list based on value
360
                \arsort($langs, \SORT_NUMERIC);
361
            }
362
        }
363
        //extract most important (first)
364
        foreach ($langs as $lang => $val) {
365
            break;
366
        }
367
        //if complex language simplify it
368
        if (false !== mb_strpos($lang, '-')) {
369
            $tmp  = \explode('-', $lang);
370
            $lang = $tmp[0];
371
        }
372
373
        return $lang;
374
    }
375
}
376