Hey all,
I am trying to internationalise my website with php. I am very new to PHP!
The index.php starts with this:
<?php session_start(); ?>
<?php include 'api/locale.php'; ?>
<html>
<!-- ... -->
<div><?php loc('foo') ?></div>
The locale.php looks like this:
<?php
if(isset($_GET['lang']) {
$_SESSION['lang'] = $_GET['lang'];
} else {
$_SESSION['lang'] = 'en'; // default value
}
// use the necessary language file
include('/locale/' . $_SESSION['lang'] . '.php');
// get phrase from URL
if (isset($_GET["phrase"]))
loc($_GET["phrase"];);
function loc($phrase)
{
global $lang;
if(array_key_exists($phrase, $lang)) {
echo $lang[$phrase];
} else {
echo $phrase;
}
}
?>
The idea is I want to use the function loc($phrase) to get the content either in German or English. But here is the problem:
If I have the code like this, I always get the english version, because in locale.php I can not get the lang from the URL: $_GET['lang'] is undefined. Therefore, the session language is always set to the default language (en).
However, if I move the session_start(); into the file locale.php, the internationalisation works:
index.php:
<?php include 'api/locale.php'; ?>
<html>
<!-- ... -->
<div><?php loc('foo') ?></div>
locale.php:
<?php
session_start();
if(isset($_GET['lang']) {
$_SESSION['lang'] = $_GET['lang'];
// ... rest the same as above
Why is it like this? Am I doing something conceptually wrong? The problem is I am also using this locale.php in ajax calls to get international content for dynamically generated HTML elements:
function loc(phrase)
{
var locString;
$.ajax({
// force synchronous ajax call, to return with locString
async: false,
// url with to be translated id
url: "api/locale.php?phrase=" + phrase,
// "get" for small data (otherwise post)
method: "get",
// callback function after server has reveiced information
success: function (data)
{
locString = data;
}
});
return locString;
}
So if I call locale.php over and over again with this AJAX call, aren't there new sessions starting over and over again? I am not sure if I designed my functions correctly. I am happy about any comments!
Thank you!
=============== EDIT ===============
ok, I tried a new way now:
session.php
// session starts at this point
session_start();
// internationalisation in EN and DE
$allowedLangs = array('en', 'de');
// check lang-parameter given in URL and set language from there
if(isset($_GET['lang']) && in_array($_GET['lang'], $allowedLangs))
$_SESSION['lang'] = $_GET['lang'];
if(!isset($_SESSION['lang']))
$_SESSION['lang'] = 'en'; // default value
locale.php
// include correct languguage file
$root = realpath($_SERVER["DOCUMENT_ROOT"]) ;
include($root . '/locale/' . $_SESSION['lang'] . '.php');
// get phrase from URL and translate it
if (isset($_GET["phrase"]))
{
$phrase = $_GET["phrase"];
global $lang;
if (array_key_exists($phrase, $lang))
echo $lang[$phrase];
else
echo $phrase;
}
both files get included in index.php
<?php include 'api/session.php'; ?>
<?php include 'api/locale.php'; ?>
However, if I locale a phrase with ajax now, the following error message appears:
Notice: Undefined variable: _SESSION in ... /locale.php on line 4
How can that be? I thought $_SESSION is superglobal ?!?
When you call the version of api/locale.php with the session_start via ajax, not a new but the same session will start, which is the correct behaviour.
Word start maybe confusing you but the session start will supply the information of the current session correctly, not a new one. So nothing to worry about.
Also you may consider looking at
$_SERVER['HTTP_ACCEPT_LANGUAGE']
before starting to ajax ping-pong of the server and client for an initial language quick guess...
For the two versions of your code, it is not a mystery why it works when session_start is
in locale.php.
The cause is:
Your ajax call is not entering your script from index.php, it enters directly to api/locale.php.
If you do not session_start in api/locale.php, the ajax call will enter into a sessionless php invocation.
So it will keep the default value since session data is neither can be fetched or can be recorded.
I think there is something conceptually wrong in your locale.php file.
The fact that you always set $_SESSION['lang'] is a bad smell.
There should be a case when you dont set the value of $_SESSION['lang']and just use the value of$_SESSION['lang']without modifying it.
With your locale file as it is , and your ajax call that does not pass 'lang' as a parameter, you will always get the default language.
But anyway your local.php file should start with session_start(); as explained by ishan.
By the way you should not use 'echo' inside your function loc. Instead return the result and do
echo loc('foo');
It would do the same job, but your loc function would be more reusable.
Hi Marcus I will try to answer your question in the comments.
$_SESSION id indeed a super global. But you need to call session_start() for it to works.
That's why it does not work anymore in locale.php
The problem is that your locale.php file is serving two purposes at the same time.
It should just translate but not be reachable directly from an url.
So you should do something like this :
session.php
`
//here you define a default value. So whatever happens, you know that $_session['lang']
//will always be set.
if(! isset ($_SESSION['lang'] {
$_SESSION['lang'] = 'en'; // default value
}
// internationalisation in EN and DE
$allowedLangs = array('en', 'de');
// check lang-parameter given in URL and set language from there
//if necessary, the default value will be overwritten.
if(isset($_GET['lang']) && in_array($_GET['lang'], $allowedLangs)) {
$_SESSION['lang'] = $_GET['lang'];
}
`translate.php
function getTranslation ($phrase, $lang='en') {
$root = realpath($_SERVER["DOCUMENT_ROOT"]) ;
include($root . '/locale/' . $lang . '.php');
//the array with the phrases and their translations should not be called $lang
//to avoid confusion. Let's call it $translations
if (array_key_exists($phrase, $translations))
return $translations[$phrase];
else
return $phrase;
}
}
locale.php
`
This file is to be called in ajax.
It will works providing $_SESSION['lang'] as already been defined
(in index.php for example). Otherwise you fall back to the default lang.
include 'path_to_translate/translate.php';
session_start();
if(isset($_SESSION['lang'] {
$lang = $_SESSION['lang'];
} else {
$lang = 'en';
}
$phrase = $_GET['phrase'];
echo getTranslation($phrase, $lang);
index.php
session_start();
include 'api/session.php';
include 'path_to_translate/translate.php';
$lang = $_SESSION['lang'];
<some html>
//to translate anything
<?php echo getTranslation($anything, $lang) ?>
</some html>
Hope this will help. Off course I can not test all this code , so their might be some mistake. But that's the general idea.
I tried not to change to much what you' have done. But there is still a problem. You should not define the lang in index.php. If there is a form in your index to choose the lang. Make a call in ajax to set_lang.php. It is not for the index to set the lang in session.
Related
I've got this session variable, which was initiated in index.php
<?php
$sid = session_id();
if (empty($sid) {
session_start();
}
//value of the variable can be changed and saved before coming back to the index
if(!isset($_SESSION['context'])){
$_SESSION['context'] = 1;
}
//...
?>
Later a script is used to create or update a database entry.
entryupdate.php:
<?php
include_once("template.php");
/*....*/
$sid = session_id();
if (empty($sid)) {
session_start();
}
/*....*/
//Create a new entry, context is not given in the $input_object at this point.
$template = new Template($input_object);
$context = $template->getContext();
?>
template.php is a script where only the Template Object is defined, so I don't call $session_start in it, my rationale being that it would always be called by the scripts including it, as it is in the case I'm describing here. Here is the relevant code:
<?php
class Template
{
private $m_context;
//other private parameters
function __construct($arguments_object){
if(!is_null($arguments_object)){
/*....*/
$this->m_context = $arguments_object->context;
/*....*/
}
}
/*....*/
function getContext(){
if(!empty($this->m_context)){
return $this->m_context;
}else{
//this would be our case, as the parameter was not initialized yet.
return $_SESSION['context'];
}
}
/*....*/
}
?>
Now, a colleague stumbled on an error and upon investigation, I found out that the $context was set to NULL. When I tried to reproduce the issue, the context was correctly initialized. And to be honest, for the few years the tool has been used, it is the first time this kind of issue was encountered.
I've also checked, at no point I am unsetting this particular session variable.
Am I making a false assumption there, in thinking that template.php would find the session variable when the session was started in entryupdate.php where it was included and used?
I am working on a website. I would like the website to redirect from index.php to index.php?lang=En.
This is because the site is multi-lingual and the default language needs to be set to English on the home page. I used the header() method to do this but that causes a redirect loop as the site keeps reloading forever.
How can I overcome this barrier?
In your PHP:
<?php
// Default to English if $_GET['lang'] isn't set
$lang = isset($_GET['lang']) ? $_GET['lang'] : 'En';
// If language not in array of available languages, reset to English
if (!in_array($lang, array('En', 'Es', 'Fr'))) {
$lang = 'En';
}
header('Location: index.php?lang=' . $lang);
?>
In your HTML:
English,
Español,
Français
I would do like this:
if(!isset($_GET['lang']) {
header('location: http://www.example.com/index.php?lang=En');
}
Check if the lang parameter exists in the URL, and do the redirect only if it doesn't:
if (!isset($_GET['lang']) {
header('Location: http://www.example.com/index.php?lang=En');
}
I have a problem with the Mobile Detection Script.
There are two scenarios:
First the script should detect if it's a mobile or not. If mobile, than redirect to another page (this works fine).
The second query should determine, if the person is on the root page or not. If it's not the root page, the layout should be the classic one. (no redirection)
But when I add this line there won't be anymore redirection, even if I open the root page on a mobile.
I also tried to destroy the session on the google_mobile.php (redirected page) and set the $_SESSION['layoutType'] = 'mobile', but anyway the session is set to classic when I open the root page.
Thanks for your help!
Here is the script:
session_start();
require_once 'Mobile_Detect.php';
function layoutTypes() {
return array('classic', 'mobile');
}
function initLayoutType() {
// Safety check.
if (!class_exists('Mobile_Detect'))
return 'classic';
$detect = new Mobile_Detect;
$isMobile = $detect->isMobile();
$layoutTypes = layoutTypes();
// Set the layout type.
if (isset($_GET['layoutType'])) {
$layoutType = $_GET['layoutType'];
} else {
if (empty($_SESSION['layoutType'])) {
$layoutType = ($isMobile ? 'mobile' : 'classic');
} else {
$layoutType = $_SESSION['layoutType'];
}
//check if it's the root page
if ($_SERVER['REQUEST_URI'] != "/")
$layoutType = 'classic';
}
// Fallback. If everything fails choose classic layout.
if (!in_array($layoutType, $layoutTypes))
$layoutType = 'classic';
// Store the layout type for future use.
$_SESSION['layoutType'] = $layoutType;
return $layoutType;
}
$layoutType = initLayoutType();
if ($_SESSION['layoutType'] == 'mobile') {
header("Location: www.example.com/google_mobile.php");
exit;
}
I've tested your code, it seems to work as you described. I'd guess it is a session issue.
session_destroy() does not clear your previous session state in the immediate session. That means your $_SESSION would still be "dirty" in a script even if session_destroy() is the first line in it. It's safer to clear cookies from your browser instead.
One other possible problem would be query string. You're checking the REQUEST_URI and it includes any query string on URI. "/?foo=bar" is certainly not "/". You may want to check SCRIPT_NAME (i.e. $_SERVER['SCRIPT_NAME'] == 'index.php) instead.
I've built a mobile detection with Mobile_Detect.php and it works great. Now if a User does not want to stay on the mobile site he can click on "Desktop-Version" and goes back to the main page via a 'mobile_off.php' which sets $_SESSION['mobile'] = 'off'.
The main Site executes the following code:
<?php
session_start();
// Did the User come back from mobile.php?
if ($_SESSION['mobile'] != 'off') {
include 'Mobile_Detect/Mobile_Detect.php';
$detect = new Mobile_Detect();
// Smartphone?
if ($detect->isMobile() && !$detect->isTablet()) {
// Redirection --> echo 'JS'
echo "<script>window.location='mobile.php'</script>";
}
}
?>
The Problem seems to be that if ($_SESSION['mobile'] != 'off') is ignored or wrong. My iPhone always sends me straight back to 'mobile.php'.
Can anyone help?
Perhaps I should show you the code from 'mobile_off.php':
<?php
session_start();
$_SESSION['mobile'] = 'off';
?>
You need to first check the session variable exists or not before checking the value of session variable.
For checking if session variable is set or not try this code
if(isset($_SESSION['mobile'])
After that check the value of session variable
I have problems with php multilanguage. I'm using function *check_lang* and it works fine in one page, but once I go to another page the $_SESSION['lang'] variable $lang turns back into default (en). What is the problem?
<?php
function check_lang() {
if(isset($_GET['lang'])
{
$lang = $_GET['lang'];
$_SESSION['lang'] = $lang
}
if (!isset($_SESSION['lang'])) {
$lang = 'en';
} else {
$_SESSION['lang']=$lang;
}
//directory name
$dir = 'languages';
return "$dir/$lang.lng";
}
?>
You have to:
session_start();
At the top of each of your scripts in which you want to use session variables.
You need to call session_start() on each page you're planning on using the $_SESSION[] global in. That's what tells PHP that it should look up the session_id from the user's cookies or the query string so that PHP knows which session's values to use.
Reference.