PHP get current client OS language - php

I wanted to know, is there any way from PHP/javascript to get current client OS language. I tried to use $_SERVER["HTTP_ACCEPT_LANGUAGE"] but sometimes it get the wrong language.
For example in Google Chrome:
My OS: Windows 7
Language: English
Using $_SERVER["HTTP_ACCEPT_LANGUAGE"] I got this result:
HTTP_ACCEPT_LANGUAGE: zh,en-US;q=0.8,en;q=0.6
It said "zh" is my primary language.
Is there any other way to get client OS language? Because that's what I wanted, not the browser language setting. Thanks

try this function
function getUserLanguage() {
$langs = array();
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// break up string into pieces (languages and q factors)
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
if (count($lang_parse[1])) {
// create a list like â??enâ?? => 0.8
$langs = array_combine($lang_parse[1], $lang_parse[4]);
// set default to 1 for any without q factor
foreach ($langs as $lang => $val) {
if ($val === '') $langs[$lang] = 1;
}
// sort list based on value
arsort($langs, SORT_NUMERIC);
}
}
//extract most important (first)
foreach ($langs as $lang => $val) { break; }
//if complex language simplify it
if (stristr($lang,"-")) {$tmp = explode("-",$lang); $lang = $tmp[0]; }
return $lang;
}

Send it via javascript on IE?
navigator.browserLanguage: browser language
navigator.systemLanguage: Windows system language
navigator.userLanguage: Windows user-specific language
Thanks to: Is there anyway to detect OS language using javascript?
That's the only way besides the one you've mentioned to get the language of the client OS, PHP is run by the server and nothing else.
Build a PHP sorting function.
HTTP_ACCEPT_LANGUAGE: zh,en-US;q=0.8,en;q=0.6
zh and en-US share the same q= value, meaning that you can sort on the highest language value and default to en-US if the quality is the same on two languages.
Just noticed that #Quentin mentioned this in the comment section a minute before my edit, well done sir!
Mockup:
$languages = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$default = 'en-US';
/*
* magic split and structure the language into a array sorted by quality
*
* $languages_sorted_by_quality = array(0.8 => ('zh', 'en-US'));
*/
$top_languages = max($languages_sorted_by_quality);
if (isset($top_languages[$default])) {
$language = $default;
else
$language = $top_languages[0];

have your tried http_negotiate_language

Related

Is there a apache_request_headers alternatve for displaying HTTP Headers

I'm currently developing an app in a IGB (In-Game-Browser) for an Online MMO. For third party development the browser sends HTTP headers with in game information such as Locations, Item ID's, Items Type ID's, etc,.
It's a small script I've been using to practice with. This script works on my local server and like everyone else who's posted on this issue it does not work on my web server. I have come to the conclusion that this is due to Apache not being installed as a module. I spoke with my hosting provider. They said they could not tell me anything other than I need to find an alternative to "apache_request_headers". I've looked over all the previously posted issues on this topic on this site and I'm unable to see how it all fits together. How to use the examples on here to accomplish my end result. Like this [question]: Call to undefined function apache_request_headers()
My code:
<?php
$headers = apache_request_headers();
foreach ($headers as $header => $value) {
echo "$header: $value <br />\n";
}
?>
My error:
Fatal error: Call to undefined function apache_request_headers() in /home/ncgotggb/public_html/ezalternatives.com/index.php on line 2
I have been learning as I go this year and it's been self taught and at a fast pace so I'm still newbish to alot of these concepts. At this point tho I have no choice I'm heavily committed and need to complete it. When displaying your answer It would be greatly appreciated if you showed your solution in complete form.
It sounds like your local server is running Apache and your remote server is not, as this function only works with Apache (unless the server is running PHP 5.4.0, then it also works under FastCGI.
On the PHP Manual page for this function, one of the commenters included a replacement function that will be declared only if the built-in one doesn't exist. I haven't tested this, but I've seen the same function posted elsewhere.
if( !function_exists('apache_request_headers') ) {
function apache_request_headers() {
$arh = array();
$rx_http = '/\AHTTP_/';
foreach($_SERVER as $key => $val) {
if( preg_match($rx_http, $key) ) {
$arh_key = preg_replace($rx_http, '', $key);
$rx_matches = array();
// do some nasty string manipulations to restore the original letter case
// this should work in most cases
$rx_matches = explode('_', $arh_key);
if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) {
foreach($rx_matches as $ak_key => $ak_val) {
$rx_matches[$ak_key] = ucfirst($ak_val);
}
$arh_key = implode('-', $rx_matches);
}
$arh[$arh_key] = $val;
}
}
return( $arh );
}
}
I found that my site in ISP Config was set to have PHP as 'Fast-CGI' - changing this to 'MOD-PHP' fixed things nicely.

get_browser() array into variables?

Im currently playing around with browser detection mainly for statistics from the site and to better design the site in future. No ive been told the best way to go about this is to use the following code which shows all the browser info in an array if all my ini files are in place (which they are)
function list_array ($array) {
while (list ($key, $value) = each ($array)) {
$str .= "$brw = <b>$key:</b> $value<br>\n";
}
return $str;
}
echo "$HTTP_USER_AGENT<hr>\n";
$browser = get_browser();
echo list_array ((array) $browser);
The then displays this
browser_name_regex: �^mozilla/5\.0 \(.*windows nt 6\.2.*wow64.*\) applewebkit/.* \ (khtml, like gecko\).*chrome/28\..*safari/.*$�
= browser_name_pattern: Mozilla/5.0 (*Windows NT 6.2*WOW64*) AppleWebKit/* (KHTML, like Gecko)*Chrome/28.*Safari/*
= parent: Chrome 28.0
= platform: Win8
= platform_version: 6.2
= win32:
= win64: 1
= comment: Chrome 28.0
= browser: Chrome
= version: 28.0
= majorver: 28
= minorver: 0
= frames: 1
= iframes: 1
= tables: 1
= cookies: 1
= javascript: 1
= javaapplets: 1
= cssversion: 3
= alpha:
= beta:
= win16:
= backgroundsounds:
= vbscript:
= activexcontrols:
= ismobiledevice:
= issyndicationreader:
= crawler:
= aolversion: 0
Now heres were the problem lies all detect browser php plugings or download are overly complicated all im looking to do i seperate iphones ipads android blackberry apple and some of the most basic pieces of information. How can I turn this array into variables that can be used later. for example if i can grab the 2nd 3rd n 4th in the array i will have all the information i want as accurate as i need it all otherways and i seem to get problems with iphones showing as just a mobile device and what not Ive already tried for example
if (preg_match('/windows nt 6.2/i', $u_agent)) {
$platform = 'Windows 8';
}
and
$blackberry = strpos(&ua, 'Android') ? true : false;
and looked at
http://chrisschuld.com/projects/browser-php-detecting-a-users-browser-from-php.html
http://www.phpjabbers.com/php-snippet/detect-browser-php.php
http://www.killersites.com/community/index.php?/topic/2562-php-to-detect-browser-and-operating-system/
First of all, you should use foreach() instead of each + list. See http://www.php.net/manual/fr/function.each.php#63805
Second, you're casting the result of get_browser as an array for your list_array function when you do (array) $browser, that's why it works and why it doesn't create a fatal error.
If you want to use the result of get_browser as an array, you should however use the built in option to do so, ie :
$b = get_browser(null, true);
The second option here tells get_browser to return an array instead of an object, this should solve your problem of trying to use a class as an array.
You will then be able to use :
echo $b['browser'];
The default return type for get_browser beeing an object, you would have to use
$b = get_browser();
echo $b->browser;
if you wanted the same result.
Try reading the php manual http://php.net/manual/en/function.get-browser.php to get a better understanding of the functions you're using. You will find useful code in the comments aswell.
Finally, as you've been told, you should use an existing API for statistics.
Good luck with your coding.

Evaluate logic expression given as a string in PHP

I have an object which has a state property, for example state = 'state4' or state = 'state2'.
Now I also have an array of all available states that the state property can get, state1 to state8 (note: the states are not named stateN. They have eight different names, like payment or canceled. I just put stateN to describe the problem).
In addition to that, I have a logical expression like $expression = !state1||state4&&(!state2||state5) for example. This is the code for the above description:
$state = 'state4';
$expression = '!state1||state4&&(!state2||state5)';
Now I want to check if the logical expression is true or false. In the above case, it's true. In the following case it would be false:
$state = 'state1';
$expression = state4&&!state2||(!state1||state7);
How could this be solved in an elegant way?
//Initialize
$state = 'state4';
$expression = '!state1||state4&&(!state2||state5)';
//Adapt to your needs
$pattern='/state\d/';
//Replace
$e=str_replace($state,'true',$expression);
while (preg_match_all($pattern,$e,$matches)
$e=str_replace($matches[0],'false',$e);
//Eval
eval("\$result=$e;");
echo $result;
Edit:
Your update to the OQ necessitates some minor work:
//Initialize
$state = 'payed';
$expression = '!payed||cancelled&&(!whatever||shipped)';
//Adapt to your needs
$possiblestates=array(
'payed',
'cancelled',
'shipped',
'whatever'
);
//Replace
$e=str_replace($state,'true',$expression);
$e=str_replace($possiblestates,'false',$e);
//Eval
eval("\$result=$e;");
echo $result;
Edit 2
There has been concern about eval and PHP injection in the comments: The expression and the replacements are completly controlled by the application, no user input involved. As long as this holds, eval is safe.
I am using ExpressionLanguage, but there are few different solutions
ExpressionLanguage Symfony Component - https://symfony.com/doc/current/components/expression_language.html
cons - weird array syntax - array['key']. array.key works only for objects
cons - generate notice for array['key'] when key is not defined
pros - stable and well maintainer
https://github.com/mossadal/math-parser
https://github.com/optimistex/math-expression
Please remember that eval is NOT an option, under NO circumstances. We don't live an a static world. Any software always grows and evolves. What was once considered a safe input an one point may turn completely unsafe and uncontrolled.
I think you have a case which can be solved if you model each of your expressions as a rooted directed acyclic graph (DAG).
I assumed acyclic since your ultimate aim is to find the result of boolean algebra operations (if cycling occur in any of graph, then it'd be nonsense I think).
However, even if your graph structure—meaningfully—can be cyclic then your target search term will be cyclic graph, and it should still have a solution.
$expression = '!state1||state4&&(!state2||state5)';
And you have one root with two sub_DAGs in your example.
EXPRESSION as a Rooted DAG:
EXPRESSION
|
AND
___/ \___
OR OR
/ \ / \
! S_1 S_4 ! S_2 S5
Your adjacency list is:
expression_adj_list = [
expression => [ subExp_1, subExp_2 ] ,
subExp_1 => [ ! S_1, S_4 ],
subExp_2 => [ ! S_2, S5 ]
]
Now you can walk through this graph by BFS (breadth-first search algorithm) or DFS (depth-first search algorithm) or your custom, adjusted algorithm.
Of course you can just visit the adjacency list with keys and values as many times as you need if this suits and is easier for you.
You'll need a lookup table to teach your algorithm that. For example,
S2 && S5 = 1,
S1 or S4 = 0,
S3 && S7 = -1 (to throw an exception maybe)
After all, the algorithm below can solve your expression's result.
$adj_list = convert_expression_to_adj_list();
// can also be assigned by a function.
// root is the only node which has no incoming-edge in $adj_list.
$root = 'EXPRESSION';
q[] = $root; //queue to have expression & subexpressions
$results = [];
while ( ! empty(q)) {
$current = array_shift($q);
if ( ! in_array($current, $results)) {
if (isset($adj_list[$current])) { // if has children (sub/expression)
$children = $adj_list[$current];
// true if all children are states. false if any child is subexpression.
$bool = is_calculateable($children);
if ($bool) {
$results[$current] = calc($children);
}
else {
array_unshift($q, $current);
}
foreach ($children as $child) {
if (is_subexpresssion($child) && ! in_array($child, $results)) {
array_unshift($q, $child);
}
}
}
}
}
return $results[$root];
This approach has a great advantage also: if you save the results of the expressions in your database, if an expression is a child of the root expression then you won't need to recalculate it, just use the result from the database for the child subexpressions. In this way, you always have a two-level depth DAG (root and its children).

PHP or htaccess rewrite URL by Accept-Language?

I've my site set up so I just need to add "?lang=en" or "?lang=es" to change languages English / Spanish.
When I enter the site with, for ex, "http://domain.com/something/something_else?lang=es", a cookie is set so I continue to navigate the site in that language.
I would like to redirect my users first by the "Accept-Language" value of their browser, but then allow them to continue to navigate the site in other language if they want to.
What would be the best way to do it? Would .htaccess work along with the cookie that's set when the language is chosen?
EDIT: Here's my updated code with Paul answer:
EDIT2: Oh, I just have "en" and "es" languages. I'm not sure on how this code wpuld choose only between this two or set the default... :/
if (isset($_GET["lang"]))
$this->setLanguage($_GET["lang"]);
elseif (isset($_COOKIE["language"]))
$this->setLanguage($_COOKIE["language"]);
elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
{
// Parse the Accept-Language according to:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
preg_match_all(
'/([a-z]{1,8})' . // First part of language e.g en
'(-[a-z]{1,8})*\s*' . // other parts of language e.g -us
// Optional quality factor
'(;\s*q\s*=\s*((1(\.0{0,3}))|(0(\.[0-9]{0,3}))))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'],
$langParse);
$langs = $langParse[1];
$quals = $langParse[4];
$numLanguages = count($langs);
$langArr = array();
for ($num = 0; $num < $numLanguages; $num++)
{
$newLang = strtoupper($langs[$num]);
$newQual = isset($quals[$num]) ?
(empty($quals[$num]) ? 1.0 : floatval($quals[$num])) : 0.0;
// Choose whether to upgrade or set the quality factor for the
// primary language.
$langArr[$newLang] = (isset($langArr[$newLang])) ?
max($langArr[$newLang], $newQual) : $newQual;
}
// sort list based on value
arsort($langArr, SORT_NUMERIC);
$acceptedLanguages = array_keys($langArr);
$preferredLanguage = reset($acceptedLanguages);
$this->setLanguage($preferredLanguage);
}
else
$this->setLanguage("en");
I do this in PHP. Accept-Language is a complex thing. A browser can suggest more than one language that it would like to accept (each with a quality factor that shows which it prefers). For my site I have a default language to display (which is shown when none of the Accept-Languages is in my translation list). Otherwise if there is no language set (setLang) I choose it based on the most acceptable for the browser by parsing the Accept-Language. The function I use is below (it contains my session manager for setting cookies - but you could reimplement that with direct calls to $_SESSION[etc] = $foo;).
Edit: Unfortunately my website only has translations for the primary languages (EN, ES, FR) rather than (en_US, en_GB, es_MX, es_ES) so I choose the highest quality factor specified in these for the primary language.
public function setLanguage($setLang='')
{
if (!empty($setLang))
{
$this->setup['Session']->set($this->setup['Lang_Key'], $setLang);
}
else
{
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
{
// Parse the Accept-Language according to:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
preg_match_all(
'/([a-z]{1,8})' . // First part of language e.g en
'(-[a-z]{1,8})*\s*' . // other parts of language e.g -us
// Optional quality factor
'(;\s*q\s*=\s*((1(\.0{0,3}))|(0(\.[0-9]{0,3}))))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'],
$langParse);
$langs = $langParse[1];
$quals = $langParse[4];
$numLanguages = count($langs);
$langArr = array();
for ($num = 0; $num < $numLanguages; $num++)
{
$newLang = strtoupper($langs[$num]);
$newQual = isset($quals[$num]) ?
(empty($quals[$num]) ? 1.0 : floatval($quals[$num])) : 0.0;
// Choose whether to upgrade or set the quality factor for the
// primary language.
$langArr[$newLang] = (isset($langArr[$newLang])) ?
max($langArr[$newLang], $newQual) : $newQual;
}
// sort list based on value
arsort($langArr, SORT_NUMERIC);
$acceptedLanguages = array_keys($langArr);
$preferredLanguage = reset($acceptedLanguages);
$this->setup['Session']->set(
$this->setup['Lang_Key'], $preferredLanguage);
}
else
{
$this->setup['Session']->set(
$this->setup['Lang_Key'], $this->setup['Default_Language']);
}
}
return $this->setup['Session']->get($this->setup['Lang_Key']);
}
I do this in PHP. Accept-Language is a complex thing. A browser can suggest more than one language that it would like to accept (each with a quality factor that shows which it prefers).
Unfortunately my website only has translations for the primary languages (EN, ES, FR) rather than (en_US, en_GB, es_MX, es_ES) so I choose the highest quality factor specified in these for the primary language.
Below is an untested edit which should remove most or all of the dependencies from my code. Sorry, things were confusing with my previous answer. I had a few calls to my function with some checking of languages are done elsewhere. The code below should set the session language variable, which you should use elsewhere for determining the correct translation.
It seems a lot less complicated than my previous answer and I will have to implement this in my own code before long. For people who need specific translations (EN_US, EN_GB) then the below code should be modified to take account of Match 2 in the preg_match_all.
$websiteLanguages = array('EN', 'ES');
session_start();
// The user wants a specific language regardless of their accept settings.
if (isset($_GET["lang"]))
{
$_SESSION["language"] = $_GET["lang"];
return;
}
// A language has already been decided upon.
if (isset($_SESSION["language"]))
{
return;
}
// No language has been chosen we should choose from the accept language.
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
{
// Parse the Accept-Language according to:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
preg_match_all(
'/([a-z]{1,8})' . // M1 - First part of language e.g en
'(-[a-z]{1,8})*\s*' . // M2 -other parts of language e.g -us
// Optional quality factor M3 ;q=, M4 - Quality Factor
'(;\s*q\s*=\s*((1(\.0{0,3}))|(0(\.[0-9]{0,3}))))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'],
$langParse);
$langs = $langParse[1]; // M1 - First part of language
$quals = $langParse[4]; // M4 - Quality Factor
$numLanguages = count($langs);
$langArr = array();
for ($num = 0; $num < $numLanguages; $num++)
{
$newLang = strtoupper($langs[$num]);
$newQual = isset($quals[$num]) ?
(empty($quals[$num]) ? 1.0 : floatval($quals[$num])) : 0.0;
// Choose whether to upgrade or set the quality factor for the
// primary language.
$langArr[$newLang] = (isset($langArr[$newLang])) ?
max($langArr[$newLang], $newQual) : $newQual;
}
// sort list based on value
// langArr will now be an array like: array('EN' => 1, 'ES' => 0.5)
arsort($langArr, SORT_NUMERIC);
// The languages the client accepts in order of preference.
$acceptedLanguages = array_keys($langArr);
// Set the most preferred language that we have a translation for.
foreach ($acceptedLanguages as $preferredLanguage)
{
if (in_array($preferredLanguage, $websiteLanguages))
{
$_SESSION['Language'] = $preferredLanguage;
return;
}
}
}
// We will have returned by now if a language could be chosen, otherwise use
// our default language.
$_SESSION['Language'] = "EN";

PHP language detection

I'm trying to build multilangual site.
I use this piece of code to detect users language. If you havent chosen a language, it will include your language file based on HTTP_ACCEPT_LANGUAGE.
I don't know where it gets it from though:
session_start();
if (!isset($_SESSION['lang'])) {
$_SESSION['lang'] = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
}
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'en') $_SESSION['lang'] = "en";
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'sv') $_SESSION['lang'] = "sv";
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'pl') $_SESSION['lang'] = "pl";
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'fr') $_SESSION['lang'] = "fr";
include('languages/'.$_SESSION['lang'].'.php');
It works for me and includes the polish lang file. But is this code accurate? Or is there another way?
The browser generally sends a HTTP header, name Accept-Language, that indicates which languages the user is willing to get.
For instance, this header can be :
Accept-Language: en-us,en;q=0.5
There is notion of priority in it, btw ;-)
In PHP, you can get this in the $_SERVER super global :
var_dump($_SERVER['HTTP_ACCEPT_LANGUAGE']);
will get me :
string 'en-us,en;q=0.5' (length=14)
Now, you have to parse that ;-)
If I edit my preferences in the browser's option to say "I want french, and if you can't serve me french, get me english from the US ; and if you can't get me that either, just get me english), the header will be :
Accept-Language: fr-fr,en-us;q=0.7,en;q=0.3
And, from PHP :
string 'fr-fr,en-us;q=0.7,en;q=0.3' (length=26)
For more informations, you can take a look at [section 14.4 of the HTTP RFC][1].
And you probably can find lots of code example in PHP to parse that header ; for instance : Parse Accept-Language to detect a user's language
Have fun !
Here's the script I used for a bi-lingual site. It is to be used as index.php of mysite.com. Based on the user's browser's language preference, it would redirect to desired language version of the site or the default language site if the site in user's preferred langauge was not available.
<?php
// List of available localized versions as 'lang code' => 'url' map
$sites = array(
"en" => "http://en.mysite.com/",
"bn" => "http://bn.mysite.com/",
);
// Get 2 char lang code
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
// Set default language if a `$lang` version of site is not available
if (!in_array($lang, array_keys($sites)))
$lang = 'en';
// Finally redirect to desired location
header('Location: ' . $sites[$lang]);
?>
I know there already many good solutions, but have found my own way to solve this problem.
<?php
$prefLocales = array_reduce(
explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']),
function ($res, $el) {
list($l, $q) = array_merge(explode(';q=', $el), [1]);
$res[$l] = (float) $q;
return $res;
}, []);
arsort($prefLocales);
/*
This get you from headers like this
string 'en-US,en;q=0.8,uk;q=0.6,ru;q=0.4' (length=32)
array like this
array (size=4)
'en-US' => float 1
'en' => float 0.8
'uk' => float 0.6
'ru' => float 0.4
*/
Code will convert HTTP_ACCEPT_LANGUAGE string to array with locales as keys and weight as values, sorted from high value to low. So you can just get one by one with array_shift to get the best match with your site locales.
You can use: Locale::acceptFromHttp().
Tries to find locale that can satisfy the language list that is requested by the HTTP "Accept-Language" header.
Your code looks just fine. You might want to add a final else default choice if the visitor asks for a language you aren't providing.
Also, if the visitor himself selects a language you should save that choice in a persistent cookie and check its value, giving it precedence over HTTP_ACCEPT_LANGUAGE.
As far as I can tell Youtube does use HTTP_ACCEPT_LANGUAGE, but at the same time uses IP geolocation to suggest a change in language if the langauge of the visitor's country doesn't match that. Definitely annoying.
Just nitpicking: if you're gonna add languages to the list a switch() statement might be more readable.
Here's a function for selecting the best out of a group of supported languages. It extracts languages from Accept-Language, then sorts the given array of languages according to their priority.
function select_best_language($languages) {
if (!$_SERVER['HTTP_ACCEPT_LANGUAGE']) return $languages[0];
$default_q=100;
foreach (explode(",",$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lqpair) {
$lq=explode(";q=",$lqpair);
if ($lq[1]) $lq[1]=floatval($lq[1]); else $lq[1]=$default_q--;
$larr[$lq[0]]=$lq[1];
}
usort($languages,function($a,$b) use ($larr) { return $larr[$b]<=>$larr[$a]; });
return $languages[0];
}
$lang = select_best_language(['en','fr','it']);
Try This
function getUserLanguage() {
$langs = array();
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// break up string into pieces (languages and q factors)
preg_match_all(
'/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'],
$lang_parse
);
if (count($lang_parse[1])) {
// create a list like 'en' => 0.8
$langs = array_combine($lang_parse[1], $lang_parse[4]);
// set default to 1 for any without q factor
foreach ($langs as $lang => $val) {
if ($val === '') {
$langs[$lang] = 1;
}
}
// sort list based on value
arsort($langs, SORT_NUMERIC);
}
}
//extract most important (first)
reset($langs);
$lang = key($langs);
//if complex language simplify it
if (stristr($lang, '-')) {
list($lang) = explode('-', $lang);
}
return $lang;
}
This is also possible. It will use english as default if .php is not available.
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
(#include_once 'languages/'.$lang.'.php') or (#include_once 'languages/en.php');
I solved this issue for PHP7.4+ with the code below. It strips out the first two letters of the locale code, takes into account cases like 'en-US' and produces a map like:
$map = [
'en' => 1,
'de' => 0.8,
'uk' => 0.3
];
The code is as follows:
$header = 'en-US,de-DE;q=0.8,uk;q=0.3';
$pattern = '((?P<code>[a-z-_A-Z]{2,5})([;q=]+?(?P<prio>0.\d+))?)';
preg_match_all($pattern, $header, $matches);
['code' => $codes, 'prio' => $values] = $matches;
$map = \array_combine(
\array_map(fn(string $language) => strtolower(substr($language, 0, 2)), \array_values($codes)),
\array_map(fn(string $value) => empty($value) ? 1 : (float)$value, \array_values($values))
);
Please note that the regex is probably suboptimal, improvement suggestions are welcome.
Named capture groups are always in the order of matching, so we can use array_combine safely.
if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
$parts=explode(';',$_SERVER['HTTP_ACCEPT_LANGUAGE']);
$langs=explode(',',$parts[0]);
var_dump($langs);
}

Categories