Session Variables

Permalink
So I have seen a lot of discussion about the lack of persistence of Session variables but no clear cut solution as far as I can tell. Obviously, this is a major issue in terms of a professional grade CMS and I am hoping that there is a simple answer somewhere and I just don't know it.

So this is what I am doing:

In header.php I have code that checks if a user id session variable is set. If it isn't set, I set it with "NONE". Further down, I have a hidden input field that also contains the same value (as well as other session variables like the user's first name). Later I check to see if the input field holding the user id value is "NONE". If it is, I display a sign in form in a specific div. If it set to a different value, I display a "welcome <first name>" message in the div. Now if the user id = NONE (which always happens the first time), then the login fields are displayed. If the user logs in, javascript/JSON/PHP code is executed that checks if the login info is valid. If it is, the user's info is passed from the PHP program to the javascript program via a XMLHttpRequest(). The exact sequence is: user presses login button->javascript code gets data in input fields and issues a XMLHttpRequest->PHP code services request, sets the session variables, and sends back results->results are analyzed and if the login info was correct, the welcome message is displayed.

This all works fine. However, when if the user refreshes the page, instead of the session variable being set to the user_id, it is set to "NONE" again and the login fields appear again. I have debugged this and this is what is happening: when the PHP program is called, the session variable is not visible to the program unless the program contains a session_start() (I THOUGHT THIS WAS NOT NEEDED IN C5). Once I put in the session_start(), I can echo the user_id (first time it echoes "NONE" but again only if the session_start() is present). Now if the PHP program finds the user in the database (MySQL), it creates a return string with the user info and sets the session variables. The data is sent and the welcome message displayed and everything is fine, unless the user refreshes the page at which point the session variable for the user id is still set to NONE. At first I thought that the session variable was being reset in the code but I echo it out right at the top of the header file and it is still set to NONE (and though it was set in the PHP program). So what is happening is that it appears that when the PHP program sets the session variable, it is not working. Why can't I set the session variable? I would think since I can seeit, I should be able to set it. Any suggestions or ideas or straight out solutions would be appreciated. Sorry for the long post.

 
kellycunningham replied on at Permalink Reply
So no reply from the C5 folks. Does that mean session variables simply don't persist in C5 and the problem is going to be ignored? Maybe the long explanation was too convoluted so let me try again. I wrote a PHP file to check login info from a webpage. If the login info is valid, I want to set a session variable. When I do that, it does not persist! I've see a lot of discussion on this but no real answers. DOES THIS WORK IN C5 OR NOT? It's pretty good that this is the only real complaint I have about C5, but it is a big one and it is very limiting. I really believe (hope) I am doing something wrong (or not doing something I should be) but really there should exist straight forward documentation on this. Just point me to it! Any help would be appreciated.
goutnet replied on at Permalink Reply
I have delevopped quite a few addons that rely on the session for c5 (and besides the login itself does rely on it).

If the Session variables were reset nothing would work on c5 … so there might be something wrong in the way you are handling the session.

First of all is the code setting those variables in a proper c5 environment (within a tool or something like that, and called through the dispatcher?), having session_start() is an oddity I never had, so I would start from there … (to me it sounds like you are trying a direct load of the tool page without going through the dispatcher).
goutnet replied on at Permalink Reply
BTW, posting some code would + urls would help us understand your problem and the way you are trying to solve it.
kellycunningham replied on at Permalink Reply
So the file is not going through the dispatcher (I assume you mean being handled by index.php). what is happening is a javascript program talks to a PHP program (via JSON). The PHP program gets data from the javascript program which extracts the data from an HTML form. The PHP uses the data to verify the login. If the login is verified, the PHP program sets the session variables. These variables do not persist. If C5 needs to know about the PHP file, then how does that happen? Do I need to launch the PHP program through the dispatcher in some way? I can readily believe I am doing something wrong (or not doing something I should be) but with so many posts on this subject and NO really answer, I would think there would be some type of documentation. Here is the PHP code that does the user/pw lookup and sets the session variables (minus my security settings). Any help would be appreciated.

By the way, I know all the PHP/MySQL stuff works because I can do this with cookies on the client side. I just don't like that solution.

<?php
// connect to db
mysql_connect("mysql1002.ixwebhosting.com",$user,$password);
@mysql_select_db($database) or die( "Unable to select database");
//////////////////////
////////////////////// query BIM_sec for email & pw
$query = "SELECT * FROM BIM_sec WHERE email = '$_POST[uemail]' AND pw = '$_POST[upw]'";
$result = mysql_query($query) or die(mysql_error());
$num_rows = mysql_num_rows($result);
//////////////////////////////////////////
$retval = "INVALID";

if ($num_rows == 1){
$row = mysql_fetch_array($result) or die(mysql_error());
$sec_key = $row['sec_key'];
$usertype = $row['usertype'];
//////////////////////////////////////////////////////
if ($usertype == "P") {
$queryPro = "SELECT * FROM BIM_provider WHERE sec_key = '$sec_key'";
$resultPro = mysql_query($queryPro) or die(mysql_error());
$pro_rowcount = mysql_num_rows($resultPro);
if ($pro_rowcount == 1) {
$prorow = mysql_fetch_array($resultPro) or die(mysql_error());
$firstname = $prorow['first_name'];
$lastname = $prorow['last_name'];
$retval = $sec_key."/".$firstname."/".$lastname."/"."P";
} else {
$retval = "INVALID";
}

} else {
if ($usertype == "C") {
$queryCon = "SELECT * FROM BIM_customer WHERE sec_key = '$sec_key'";
$resultCon = mysql_query($queryCon) or die(mysql_error());
$con_rowcount = mysql_num_rows($resultCon);
if ($con_rowcount == 1) {
$conrow = mysql_fetch_array($resultCon) or die(mysql_error());
$firstname = $conrow['first_name'];
$lastname = $conrow['last_name'];
$retval = $sec_key."/".$firstname."/".$lastname."/"."C";
} else {
$retval = "INVALID";
}
}
}
if ($retval == "INVALID") {
$_SESSION['BIMuser'] = "NONE";
$_SESSION['BIMfirstname'] = "";
$_SESSION['BIMlastname'] = "";
$_SESSION['BIMusertype'] = "U";
$_SESSION['BMIneedlogin'] = true;
echo ($retval);
} else {
$_SESSION['BIMuser'] = $sec_key;
$_SESSION['BIMfirstname'] = $firstname;
$_SESSION['BIMlastname'] = $lastname;
$_SESSION['BIMusertype'] = $usertype;
$_SESSION['BMIneedlogin'] = false;
if ($_SESSION['BMIneedlogin'] == false) {
echo ($retval."/"."FALSE");
} else {
echo ($retval."/"."TRUE");
}

}
//echo ("18/k/c/C/".$_SESSION['BIMuser']);
//echo ($retval);
} else {
$_SESSION['BIMuser'] = "NONE";
$_SESSION['BIMfirstname'] = "";
$_SESSION['BIMlastname'] = "";
$_SESSION['BIMusertype'] = "U";
$_SESSION['BMIneedlogin'] = true;
echo ($retval."/".$_SESSION['BMIneedlogin']);
}

?>
JohntheFish replied on at Permalink Reply
JohntheFish
I find session variables work most reliably if I create my own personal or package namespace.

$_SESSION[my_namespace][my_first_variable] = 'A';
$_SESSION[my_namespace][my_second_variable] = 'B';


In the past, a number of session users have come across hard to track bugs because they didn't namespace and experienced collisions.

Als have a look at my Quick Param View block. It can be set to dump the session to the page. Useful for diagnostics.

[PS]
Another thought - unless you have good reason not to, al;ways connect to the db through the c5 interface and not directly through php calls.
kellycunningham replied on at Permalink Reply
Thanks for the reply. I'm just at the beginning on this project and I think I'm just going to forget about C5. It is great for most of my sites but anytime I have had to work with Session variables, I get absolutely no good information on why they don't just work. I don't like doing something where I don't understand the underlying mechanism -- even if only conceptually - and I don't understand why the C5 folks can't provide better guidance on this. If C5 ever hopes to play in the big leagues -- and believe me I think it can -- the session variable thing needs to be addressed not in the forums but in the documentation. I build 80-90% of my sites with it so I obviously think it has a lot of pluses, but the session problem is not one of them.
A3020 replied on at Permalink Reply
A3020
Hi John, how would you handle undefined session keys if you're using this approach? I remember having such variables and ended up having lot's of if / else and isset. It doesn't look very neat. Any ideas?

if(isset($_SESSION['booking_system']['be'][$accommodationID]['options'][$optionID])){
$_SESSION['booking_system']['be'][$accommodationID]['options'][$optionID] = 'foo';
}
JohntheFish replied on at Permalink Reply
JohntheFish
@akodde. Pretty much as you have done, but all encapsulated in a model class to simplify the keys.

@kellycunningham
$_SESSION is a php thing and nothing to do with c5. If a particular host account has problems, it will be because of the way php and apache are set up and will have problems regardless of whether we run code that uses $_SESSION within c5 or directly.

The difference c5 makes is to introduce the possibility of other c5 code also using $_SESSION. So while a self sufficient script can often ignore the risk of name collisions, within c5 we have to be very aware that such collisions are possible and establish a namespace.
goutnet replied on at Permalink Reply
Hum, using the [ code ] block would have made that post readable …

Nevertheless, since you are not building your code into a tool or any c5 environment, it is possible that the Session is not shared between c5 and your application.

Session can be named, as you might expect, since you are not naming yours … you are basically placing your variables in a different session. Take a look at concrete/startup/session.php for more information :

<?php  
defined('C5_EXECUTE') or die("Access Denied.");
// Start the session
if(@ini_get('session.auto_start')) {
   @session_destroy();
}
ini_set('session.use_trans_sid',0);  
session_set_cookie_params(
   (defined('SESSION_COOKIE_PARAM_LIFETIME')?SESSION_COOKIE_PARAM_LIFETIME:0),
   (defined('SESSION_COOKIE_PARAM_PATH')?SESSION_COOKIE_PARAM_PATH:str_replace(' ', '%20', DIR_REL) . '/'),
   (defined('SESSION_COOKIE_PARAM_DOMAIN')?SESSION_COOKIE_PARAM_DOMAIN:''),
   (defined('SESSION_COOKIE_PARAM_SECURE')?SESSION_COOKIE_PARAM_SECURE:false),
   (defined('SESSION_COOKIE_PARAM_HTTPONLY')?SESSION_COOKIE_PARAM_HTTPONLY:false)
   );
if (ini_get('session.save_handler') == 'files') {


SESSION is defined in concrete/config/base.php (and can be overriden by any other configuration file of your site if you need) :

# The name of the session cookie used.
if (!defined('SESSION')) {
   define('SESSION', 'CONCRETE5');
}


Nevertheless, you really should not add a random php file like that, instead you should add a tool or a single page and have c5 dispatcher serve it. That way you would not have to bother with the session_start etc… Executing code outside the c5 environemnt like you do and expecting it to work with no problem with the rest of c5 is pretty much a bad idea.

So, to answer your question, a good grep for session_start in c5 installation would have led you to read the file I mentionned and understand what you are doing wrong …

To ensure that you are running your script within c5, you should place that at the beginning of your file:

<?php  
defined('C5_EXECUTE') or die("Access Denied.");