Locale is switching/not loading properly (sometimes) - php

I have a very annoying problem with the language/locale for our site. I've been looking around here but haven't found anything similar.
So we support a few different languages and have everything set up with .po and .mo files which works fine most of the time. Sometimes it switches language when you load something or refresh a page. There's not really a pattern to it either, sometimes 6 'en' in a row and then 'sv' and sometimes every second 'sv' and 'en'.
Ex. If you want to edit a user you get a popup which starts by including authorize.php where we check the language and set it accordingly with this function:
function _set_locale ($lang){
switch($lang) {
case 'sv': $locale = "sv_SE"; break;
case 'en': $locale = "en_SG"; break;
case 'nl': $locale = "nl_NL"; break;
case 'dk': $locale = "da_DK"; break;
case 'vi': $locale = "vi_VN"; break;
case 'zh': $locale = "zh_CN"; break;
default: $locale = "en_SG"; break;
}
putenv("LANGUAGE=$locale");
setlocale(LC_ALL, "$locale.UTF-8");
bindtextdomain("messages", "./locale/");
textdomain("messages");
I was running an account with Swedish, 'sv' set and refreshed the edit user popup 10 times and debugged this function, $lang was 'sv' and I logged setlocale(LC_ALL, 0) which returned 'sv_SE.UTF-8' every time but the page was displayed in English 5-6 times.
It seems like it's only switching from the current language to English which is the original language, so I figure that it's not getting translated. It doesn't look like we're setting the wrong/default language, it just ignores/don't have time? to set the language.
The language is not saved in cookies and some accounts just have 1 language (which is not English) and still gets this.
In the above ex. when we return from authorize.php we don't use any language variable in the actual 'edit user' page. So it shouldn't be able to change it there. (I also debugged and checked the language when returning from auth. and it was Swedish every time).
I don't expect anyone to be able to solve this by the info I've given I'm just interested if someone has experienced this or have any idea why it sometimes 'switches' please let me know if I can attach some more code to sort this out.
Thanks!

I had a similar intermittent problem PHP gettext and vagrant running ubuntu, it was showing the right text on the 3rd request.
Try one of the following, I think it will depend how you have PHP running with Apache
sudo service php5-fpm restart
sudo service apache2 restart
I think it stemmed from me playing around with the value passed to setLocale()

Related

local file inclusion exploit when including the language file

i have a php code for my website and a friend told me that my code has a local file inclusion vulnerability because im using the " include " method.
can someone help me in fixing it or lead me to where i can find help? i tried a couple of possible ways of fixing it but that didn't work.
the problem is with including the language file in my code.
here is the code below to be more clear :
<?php
if(isSet($_GET['lang']))
$lang = $_GET['lang'];
else $lang='en';
include 'languages/'.$lang.'.php';
include("header.php");
?>
P.S i only have 2 language files and they are English = "en.php" and Arabic = "ar.php"
i would really appreciate it if someone could help.
Do not EVER trust user inputs!
<?php
if ( isset($_GET['lang']) && $_GET['lang'] == 'en') {
$lang = 'en';
} else {
$lang = 'ar';
}
include 'languages/'.$lang.'.php';
include("header.php");
?>
Or, preparing for possible additional languages, I would go like this:
<?php
$lang = !empty($_GET['lang']) ? $_GET['lang'] : 'en';
switch($lang) {
default:
case 'en':
include 'languages/en.php';
break;
case 'ar':
include 'languages/ar.php';
break;
}
include("header.php");
?>
This way you can easily add extra languages later on and also always make sure, that only the required file is included.
The vulnerability is that one could send any kind of relative path in $lang. This is especially dangerous if users can upload files and figure out their real path on the server.
Example:
A hacker may use some file upload functionality of your site to upload evil.php. The hacker may know/have found out/guess that it's stored at /var/www/uploads/evil.php, and that your application runs in /var/www/html.
Now, normally nobody could run this file if /var/www/uploads is not accessible through HTTP.
But, it would be possible to open http://example.com/index.php?lang=../../uploads/evil and guess what, it would include languages/../../uploads/evil.php which would resolve to /var/www/uploads/evil.php!
This of course also works without file upload if there are any other files which can be used for exploiting something by getting access to them and calling them, such as maybe files in a normally password-protected directory (phpMyAdmin for example).
And if you now think "that's quite a lot of assumptions and 'may's and 'if's in there, you would need to be very lucky to succeed with this" then watch out - although there are some obvious blatantly open vulnerabilities where you do one URL call and you can, let's say, overtake the server or delete the database, the most dangerous ones are the ones which require multiple puzzle pieces to make an exploit work, because they go undetected for a long time and it can be hard to understand how the server got actually hacked once it happens, and you will naturally have a more experienced and therefore more dangerous (possibly stealth) hacker at your doorstep. If somebody is determined to find a security hole (either because they have an actual goal attacking your site or you, or because they just enjoy owning poor webmasters to push their own ego), they will keep searching and puzzle together whatever is required to achieve what they want.
There are multiple solutions.
As suggested by u_mulder, if you have only ar and en then just check if it's either one.
If you have more languages, you could just create an array with a list of allowed values and check if the sent language is in that array, for example:
$languages = ['de', 'en', 'ar', 'jp', 'fr'];
if(in_array($_GET['lang'], $languages)) {
$selectedLanguage = $_GET['lang'];
} else {
$selectedLanguage = 'en'; // default
// Note that you could also show an error "invalid language" instead
}
If you want to control this by just allowing only the files existing in the folder, you could also just validate that the language contains only letters (or whatever you need, as long as you make sure it may not contain dots or slashes or such):
if(preg_match("/^[a-z]*$/", $_GET['lang'])) { ... }
Note that with this approach you should definitiely also check if the specified file exists, otherwise it would still be possible to have a language-less site by specifying an invalid language (especially since include doesn't throw an error on non-existing files, unlike require).

How to force PHP/Apache to use another year?

So, I was handed an old project by another employee. It's horribly coded and almost made me quit my job. Twice. Because I don't have that much time (I was given 2 weeks for this task), I can't rewrite the entire thing. I modified it as I was asked, and currently, I'm doing the testings. The problem is, the code should alter it's behavior in other years. The problem with this problem is, that there is no central location where the current year is set, it's all over the code using date("Y") which would force me to change around 200 files.
So, the easiest solution would be to tell PHP in the beginning: "Hey, it's year 20xx". I tried date_default_timezone_set(), but this didn't help me at all. So what I'm looking for is:
A PHP-command which changes the current year to the set value (likeSet_Date("Y", 2016);)
An Apache-Servercommand which changes the current time (likesetdate -Y 2016)
Is there any way or at least a workaround to make the script think it's another year?
You can redefine functions using runkit_function_redefine()
But you need to setup the runkit PECL extension
NOTE : i didn't test it !
<?php
print date("Y");
$date = 'print "Hello, it is a new definition of date function <" . $Y . ">"; return 2014; ';
runkit_function_redefine('date', '$Y', $date);
date("Y");
It's probably not suitable for your case but I thought I should share this abuse of namespaces:
<?php
namespace FakeTime;
function date($format, $time=null){
return 2001;
}
var_dump(date('Y'));
This is a combination of other users suggestion and how to I use libfaketime.
No need for a PECL extension.
You can very easily fake the time by modifying /etc/apache2/envvars
just add:
export FAKETIME="2015-12-04 12:41:15"
export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
Make sure LD_PRELOAD points to the git source.
Now restart your apache2 and you'll be back in time right at the point where you'd asked this question!
Frist compile libfaketime as suggested https://github.com/wolfcw/libfaketime
Dynamically load baked libfaketime into the scripts you need
if (!extension_loaded('libfaketime')) {
dl('libfaketime.so');
}
Optional:
Use auto_prepend_file configuration to prepend the dl(.. comand to every file.
Other possible way is to simply compile a second PHP installation and modify the date functions: https://github.com/php/php-src/blob/master/ext/date/php_date.c

how to get current locale in PHP

I would like to get the current system locale of a server (say windows 7 os). This is to ensure that different language setting uses different parts of code in PHP.
However, I could not find any API that does this.
Can anyone tell me the name of the function?
Having thought more about the problem and the particular setup I have, I came up with this solution, which seems to work. Note that I don't have control over what languages I need to support: there are translation files dropped into a predefined place and system locales installed by someone else. During runtime, I need to support a particular language if corresponding translation file exists and and system locale is installed. This got me to this solution:
Use below function
function getLocale($lang)
{
$locs = array();
exec('locale -a', $locs);
$locale = 'en-IN';
foreach($locs as $l)
{
$regex = "/$lang\_[A-Z]{2}$/";
if(preg_match($regex, $l) && file_exists(TRANSROOT . "/$lang.php"))
{
$locale = $l;
break;
}
}
return $locale;
}
I'm defaulting to en-IN if I cannot resolve a locale, because I know for certain that en-IN is installed.
Oddly, you get the locale for the PHP process by using the setlocale function like so:
setlocale (LC_ALL,"0");
The second parameter is "locales" and it says in the docs:
If locales is "0", the locale setting is not affected, only the current setting is returned.
So it always returns the locale, but you can tell it to set nothing and just return the current locale.
Note: This isn't the system locale, but the locale of the PHP process itself, which is usually derived from the system locale, but may be different if you previously called setlocale and changed it. I thought at first that that's what this question was looking for, but I think the answer from Gags is more correct, calling "locale -a" with "exec()" to get the actual system language independent of the PHP process.
Best answer above from Gags.
If you want the contents of the accept-language: header from the current request, if there is one, use:
$_SERVER['HTTP_ACCEPT_LANGUAGE']

Sublime Text 3 custom PHP auto-completion does not work

Here's the default auto-completion for "switch":
switch (variable) {
case 'value':
# code...
break;
default:
# code...
break;
}
but I wish to turn it into just:
switch ()
{
case '':
break;
case '':
break;
}
because I don't like to modify "#code here..." every time.
I navigated to
"C:\Users\USER\AppData\Roaming\Sublime Text 2\Packages\PHP"
and opened "switch(-).sublime-snippet" and modified it into:
<snippet>
<content><![CDATA[switch ($0)
{
case '$0':
break;
case '$0':
break;
}]]></content>
<tabTrigger>switch</tabTrigger>
<scope>source.php</scope>
<description>switch …</description>
But nothing works.
Is there any syntax error? Or do I modify the wrong file?
If you tagged your question correctly, you modified the wrong file - you need to edit the Sublime Text 3 version. This is a bit more difficult to do directly, since the file is wrapped up in a .sublime-package zip archive. To get around this, install Package Control (if you haven't already), then install the PackageResourceViewer plugin. Open the Command Palette, type prv to bring up the PackageResourceViewer options, select Open Resource, then navigate down to PHP and select the switch(-).sublime-snippet option. Edit it to your liking, save it, and you should be all set.
You probably also want to set your tab stops differently. Try this instead:
<snippet>
<content><![CDATA[switch ($1)
{
case '$2':
$3
break;
case '$4':
$5
break;
${0:default:}
}]]></content>
<tabTrigger>switch</tabTrigger>
<scope>source.php</scope>
<description>switch …</description>
</snippet>
Now, you can tab through the different areas, filling in the info as you go, ending up at the bottom with a default option, that you can just hit Delete on to erase if you don't want it. With your original version, after typeing switchTab, you would have ended up with 3 different cursors, one at each of the $0 locations. Check out the snippets reference for more information.

PHP SWITCH entering DEFAULT even if there is a valid CASE?

I have this SWITCH block:
switch ($_GET['page']) {
case "listaOferteTest":
include("php_views/lista_oferte_test.php");
break;
case "categorieOferte":
include("php_views/categorie_oferte.php");
break;
case "pagina":
include("php_views/pagina.php");
break;
default:
include("php_views/page_not_found_redirect.php");
break;
}
and some php links [they are dinamicaly generated, but i'll paste the html]:
<a href='/pagina/termeni-si-conditii/'>
Termeni si conditii
</a>
<a href='/pagina/informatii-utile/'>
Informatii utile
</a>
<a href='/pagina/contact/'>
Contact
</a>
I have a .htaccess where i treat the link like this:
RewriteRule (.*)/(.*)/(.*)/ index.php?page=$1&subPage=$2&subSubPage=$3 [L]
The problem: When I tested the links above I noticed a strange behavior - from about 10 clicks on random links one gets also the default. How is this possible? Thanks!
My first instinct would be to get the debugger out and step through the code so you can see exactly what's going on. If you don't have a debugger installed (why not? you should, it'll change your life!) or if you can't recreate the problem with a debugger given it's seemingly random nature, then next best thing would be to add some logging to the default block so you can work out why it's getting there. My guess would be that $glob['page'] doesn't match 'pagina' exactly; maybe it's got a leading/trailing space or slash, or maybe it's empty because there's a bug in how that value is being extracted. Something like Monolog would do the job in terms of logging.
Then u can use, if's instead of switch.
For ex.
if (isset($_GET['page'])) {
if($_GET['page']=='something') {...}
if($_GET['page']=='something2') {...}
...
}

Categories