Why cant I change cookie?
If you chose a language you cant change. You have to empty your cookies if you want to change language. Why is that?
if (isset($_GET['setLang']) && $_GET['setLang'] == 'en'
|| isset($_COOKIE['setLang']) && $_COOKIE['setLang'] == 'en') {
setcookie("setLang", 'en', time()+(3600*12)); //expires in 12 hours
include('language/en/common.php');
}
elseif (isset($_GET['setLang']) && $_GET['setLang'] == 'se'
|| isset($_COOKIE['setLang']) && $_COOKIE['setLang'] == 'se') {
setcookie("setLang", 'se', time()+(3600*12)); //expires in 12 hours
include('language/se/common.php');
}
else if (isset($_GET['setLang']) && $_GET['setLang'] == 'fr'
|| isset($_COOKIE['setLang']) && $_COOKIE['setLang'] == 'fr') {
setcookie("setLang", 'fr', time()+(3600*12)); //expires in 12 hours
include('language/fr/common.php');
}
// default language is english
else {
include('language/en/common.php');
}
You certainly can change cookies. You can't change languages using the logic you have there because the way you've written it, an existing setting in $_COOKIE will always override a setting in $_GET (except for en, where $_GET will be checked first, so right now you should be able to switch to en if you started with another language). You need to do all checks against $_GET first, then all checks against $_COOKIE, if you want to be able to change languages.
The logic hurt my brain, too.
$language = $_GET['setLang'] || $_COOKIE['setLang']) || 'en';
setcookie("setLang", $language, time()+(3600*12));
include('language/' . $language . '/common.php');
Should achieve the same effect and fix your cookie issues (untested, though).
setcookie() defines a cookie to be
sent along with the rest of the HTTP
headers. Like other headers, cookies
must be sent before any output from
your script (this is a protocol
restriction). This requires that you
place calls to this function prior to
any output, including and
tags as well as any whitespace.
http://in3.php.net/setcookie
Related
I would like to set the disabled state of a form field based on the combination of 4 variables: processed, process started, process ended, user id
If it is not going to be processed, the form field should be disabled
If the process has started OR ended, it should be also disabled, except if the user id == 1. So User 1 can still fill the form field, even if the process has started OR ended. And it should be also disabled for User 1 also if it is not going to be processed.
I was trying this way, but doesn't work as I expect, so there must be a flaw in my logic or understanding how PHP works:
'disabled' => !$proc || (($proc_started || $proc_ended) && !$user_id == 1)
This way other users see the form field also enabled, which I don't want. Is it the hierarchy of the Logical Operators ?
Can you please point me to the right direction? Thanks.
!$user_id == 1 is (!$user_id) == 1
$foo = 42;
!$foo == false;
You want to write !($user_id == 1) or $user_id != 1
Should work.
if($user_id === 1) {
if($state != "processed") {
$state = "Enabled" // or anything else of your choice
}
} else {
$state = "Disabled";
}
I need to redirect if the user is from United States or from any other country that does not speak Portuguese. My code:
require_once('geoplugin.class.php');
$geoplugin = new geoPlugin();
$geoplugin->locate();
// create a variable for the country code
$var_country_code = $geoplugin->countryCode;
$arrCountryCode = array('BR', 'PT', 'CV', 'GW', 'AO', 'MZ', 'TL', 'ST', 'GQ');
$hasEn = explode('', $_SERVER[REQUEST_URI]);
// $geoplugin = unserialize(file_get_contents("http://www.geoplugin.net/php.gp?ip=".$geoplugin->ip));
// redirect based on country code && if the url has not /en && if is the first view:
if(!in_array($var_country_code, $arrCountryCode) && $hasEn[1] != 'en' && $_COOKIE['redirect'] == '') {
setcookie('redirect', 'true'); //allow to delete /en
header('Location: http://'.$_SERVER[HTTP_HOST].'/en'.$_SERVER[REQUEST_URI]);
}
}
Everyone is being to redirect to /en, even if it is from Brazil. What is wrong with my code?
P.S. using the geoplugin library.
#1
Please turn on the display of PHP errors and warnings: error_reporting(E_ALL);
You may see an error from geoplugin, like:
Error geoPlugin class Error: Cannot retrieve data. Either compile PHP with cURL support or enable allow_url_fopen in php.ini on line number 137
#2
$hasEn = explode('', $_SERVER[REQUEST_URI]);
This code will set the variable $hasEn to false (and produce a warning) because you're using an empty delimiter.
Then, $hasEn[1] != 'en' will always evaluate to true. Thus, the users would be unnecessarily redirected once from the en site as well.
Your redirect is hard-coded to direct people to /en:
header('Location: http://'.$_SERVER[HTTP_HOST].'/en'.$_SERVER[REQUEST_URI]);
Instead of using the return value $var_country_code
Should probably look more like this:
header('Location: http://'.$_SERVER[HTTP_HOST].'/'.$var_country_code.'/'.$_SERVER[REQUEST_URI]);
I am trying to run a php script that says basically, whilst two cells in my MySQL database are empty (t_trailerarrival and t_endsort), do something.
My code is as follows:
<?php
// Start Session, include authentication and dBConnection script
session_start();
include 'dbcon.php';
include 'sql_actuals.php';
$current_time = date("G");
while($query9_row['a_trailerarrival'] == NULL && $query10_row['a_endsort'] == NULL) {
echo "Trailer Arrival";
}
The $queryx_row['abc'] are all in the sql_actuals script that is included into this script.
For some reason, every time i run this script - my browser wont load the result (just loads for ever) and then my website at windows azure seems to crash and take a few minutes to restart.
Could someone please advise if there is a massively obvious error with my script? or point me at what the possible issue could be.
Many thanks in advance.
FYI, i have tried adding a line sleep(1); so that it gave the server it runs off a delay before having to run the program again but no luck.
You are never closing the while loop.
while($query9_row['a_trailerarrival'] == NULL && $query10_row['a_endsort'] == NULL) {
echo "Trailer Arrival";
}
Without modifying the while conditions during a while statement, once you start, you'll never stop. Therefore hanging the script and server.
You are not actually doing anything in your while statement except echoing a line.
Therefore
$query9_row['a_trailerarrival'] == NULL
and
$query10_row['a_endsort'] == NULL
are always true and never changing, and it will never exit the while loop. You need to put exit criteria in the while loop, such as:
$i=0;
while(($query9_row['a_trailerarrival'] == NULL
&& $query10_row['a_endsort'] == NULL )
|| $i==10) {
$i++;
echo "Trailer Arrival";
}
Although, logically speaking, you still need to run the query data.
** Edit **
Based upon your feedback, this doesn't sound like a while loop at all, but rather an if statement you need (with multiple elseif s).
if ($query9_row['a_trailerarrival'] == NULL && $query10_row['a_endsort'] == NULL){
echo "Trailer Arrival";
} elseif ($query9_row['a_trailerarrival'] == NULL && $query10_row['a_endsort']){
echo "End Sort";
} elseif ($query9_row['a_trailerarrival'] && $query10_row['a_endsort']){
echo "First Van";
}else {
// fourth condition:
// $query9_row['a_trailerarrival'] != NULL && $query10_row['a_endsort'] == NULL
}
I included a fourth condition when $query9_row isn't null, and $query10_row is null.
In a system we will be using, there is a function called "uses". If you are familiar with pascal, the uses clause is where you tell your program what dependencies it has (similar to C and PHP includes).
This function is being used in order to further control file inclusion other than include(_once) or require(_once).
As part of testing procedures, I need to write a dependency visualization tool for statically loaded files.
Statically Loaded Example: uses('core/core.php','core/security.php');
Dynamically Loaded Example: uses('exts/database.'.$driver.'.php');
I need to filter out dynamic load cases because the code is tested statically, not while running.
This is the code I'm using at this time:
$inuses=false; // whether currently in uses function or not
$uses=array(); // holds dependencies (line=>file)
$tknbuf=array(); // last token
foreach(token_get_all(file_get_contents($file)) as $token){
// detect uses function
if(!$inuses && is_array($token) && $token[0]==T_STRING && $token[1]=='uses')$inuses=true;
// detect uses argument (dependency file)
if($inuses && is_array($token) && $token[0]==T_CONSTANT_ENCAPSED_STRING)$tknbuf=$token;
// detect the end of uses function
if($inuses && is_string($token) && $token==')'){
$inuses=false;
isset($uses[$tknbuf[2]])
? $uses[$tknbuf[2]][]=$tknbuf[1]
: $uses[$tknbuf[2]]=array($tknbuf[1]);
}
// a new argument (dependency) is found
if($inuses && is_string($token) && $token==',')
isset($uses[$tknbuf[2]])
? $uses[$tknbuf[2]][]=$tknbuf[1]
: $uses[$tknbuf[2]]=array($tknbuf[1]);
}
Note: It may help to know that I'm using a state engine to detect the arguments.
My issue? Since there are all sorts of arguments that can go in the function, it is very difficult getting it right.
Maybe I'm not using the right approach, however, I'm pretty sure using token_get_all is the best in this case. So maybe the issue is my state engine which really isn't that good.
I might be missing the easy way out, thought I'd get some peer review off it.
Edit: I took the approach of explaining what I'm doing this time, but not exactly what I want.
Put in simple words, I need to get an array of the arguments being passed to a function named "uses". The thing is I'm a bit specific about the arguments; I only need an array of straight strings, no dynamic code at all (constants, variables, function calls...).
Using regular expressions:
<?php
preg_match_all('/uses\s*\((.+)\s*\)/',
file_get_contents('uses.php'), $matches, PREG_SET_ORDER);
foreach ($matches as $set) {
list($full, $match) = $set;
echo "$full\n";
// try to remove function arguments
$new = $match;
do {
$match = $new;
$new = preg_replace('/\([^()]*\)/', '', $match);
} while ($new != $match);
// iterate over each of the uses() args
foreach (explode(',', $match) as $arg) {
$arg = trim($arg);
if (($arg[0] == "'" || $arg[0] == '"') && substr($arg,-1) == $arg[0])
echo " ".substr($arg,1,-1)."\n";
}
}
?>
Running against:
uses('bar.php', 'test.php', $foo->bar());
uses(bar('test.php'), 'file.php');
uses(bar(foo('a','b','c')), zed());
Yields:
uses('bar.php', 'test.php', $foo->bar())
bar.php
test.php
uses(bar('test.php'), 'file.php')
file.php
uses(bar(foo('a','b','c')), zed())
Obviously it has limitations and assumptions, but if you know how the code is called, it could be sufficient.
OK I got it working. Just some minor fixes to the state engine. In short, argument tokens are buffered instead of put in the uses array directly. Next, at each ',' or ')' I check if the token is valid or not and add it to the uses array.
$inuses=false; // whether currently in uses function or not
$uses=array(); // holds dependencies (line=>file)
$tknbuf=array(); // last token
$tknbad=false; // whether last token is good or not
foreach(token_get_all(file_get_contents($file)) as $token){
// detect uses function
if(!$inuses && is_array($token) && $token[0]==T_STRING && $token[1]=='uses')$inuses=true;
// token found, put it in buffer
if($inuses && is_array($token) && $token[0]==T_CONSTANT_ENCAPSED_STRING)$tknbuf=$token;
// end-of-function found check buffer and throw into $uses
if($inuses && is_string($token) && $token==')'){
$inuses=false;
if(count($tknbuf)==3 && !$tknbad)isset($GLOBALS['uses'][$file][$tknbuf[2]])
? $GLOBALS['uses'][$file][$tknbuf[2]][]=$tknbuf[1]
: $GLOBALS['uses'][$file][$tknbuf[2]]=array($tknbuf[1]);
$tknbuf=array(); $tknbad=false;
}
// end-of-argument check token and add to $uses
if($inuses && is_string($token) && $token==','){
if(count($tknbuf)==3 && !$tknbad)isset($GLOBALS['uses'][$file][$tknbuf[2]])
? $GLOBALS['uses'][$file][$tknbuf[2]][]=$tknbuf[1]
: $GLOBALS['uses'][$file][$tknbuf[2]]=array($tknbuf[1]);
$tknbuf=array(); $tknbad=false;
}
// if current token is not an a simple string, flag all tokens as bad
if($inuses && is_array($token) && $token[0]!=T_CONSTANT_ENCAPSED_STRING)$tknbad=true;
}
Edit: Actually it is still faulty (a different issue though). But the new idea I've had ought to work out nicely.
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);
}