bryan52803 Posted March 28, 2008 Share Posted March 28, 2008 My website has been plagued by a session problem that I've been unable to resolve. Let me quickly rundown my setup: * All sessions are stored/manipulated using user defined functions so that it stores everything in a MySQL table * I force the use of cookies only * Here is a clip of my php.ini that is relative to the topic: session.bug_compat_42 = 0 session.gc_divisor = 100 session.hash_bits_per_character = 5 session.use_cookies = 1 session.use_only_cookies = 1 session.name = COOKIENAME //censored for security purposes session.auto_start = 0 session.cookie_lifetime = 3600 session.cookie_path = / session.cookie_domain = www.mydomain.com //censored for security purposes session.gc_maxlifetime = 3600 * Now for the session handling code: <?php function mysql_session_open($session_path, $session_name) { mysql_pconnect("localhost", "USER", "PASS") or die(mysql_error()); //censored for security purposes mysql_select_db("DBNAME") or die (mysql_error()); //censored for security purposes return true; } function mysql_session_close() { return true; } function mysql_session_select($SID) { $query = "SELECT variables FROM sessions WHERE SID='".mysql_real_escape_string($SID)."' AND expiration > ".time(); $result = mysql_query($query) or die(mysql_error()); if(mysql_num_rows($result)) { $row = mysql_fetch_assoc($result); $value = $row['variables']; return $value; } else { return ""; } } function mysql_session_write($SID, $value) { $value = mysql_real_escape_string($value); $lifetime = get_cfg_var("session.gc_maxlifetime"); $expiration = time() + $lifetime; $query = "INSERT INTO sessions VALUES('".mysql_real_escape_string($SID)."', '$expiration', '$value')"; $result = mysql_query($query); if(!$result) { $query = "UPDATE sessions SET expiration='$expiration', variables='$value' WHERE SID = '".mysql_real_escape_string($SID)."' AND expiration > ".time(); $result = mysql_query($query) or die(mysql_error()); } return true; } function mysql_session_destroy($SID) { $query = "DELETE FROM sessions WHERE SID='".mysql_real_escape_string($SID)."' LIMIT 1"; $result = mysql_query($query); return true; } function mysql_session_garbage_collect($lifetime) { $query = "DELETE FROM sessions WHERE expiration <= ".time(); $result = mysql_query($query); return mysql_affected_rows($result); } session_set_save_handler("mysql_session_open", "mysql_session_close", "mysql_session_select", "mysql_session_write", "mysql_session_destroy", "mysql_session_garbage_collect"); ?> * And finally what prefaces every page: <?php INCLUDE "session.php"; session_start(); ?> Now my problem. After viewing my webpage, and deciding to login to make a post, everything works fine, but alot of times when I go to submit a post, or any interim action that requires me to be logged in, the session data is lost and I'm prompted to login again. Here's what I think is happening. My session as stored in mysql is being persisted whenever session data is written (as can be seen in my session write handler). So the session persists correctly in the database. Because forced cookies is enabled, a cookie is generated with the start of every page, but only to the lifetime of 3600. So perhaps when making a post, and dealing with session data, the session is persisted in mysql, but when I go to perform an action that requires me to be logged in, the cookie, which started before I logged in when browsing, expires, and thus the SID is not properly channeled and is lost. This forces my session handlers to create a new session, devoid of the data once stored. So, that said, if this is indeed the case, how can I persist the cookie, or at least 'sync' the cookie expiration with the database expiration? This has been causing me problems for quite some time, and any help on the matter would be greatly appreciated. Thank you in advance for your time and consideration! Bryan Paul PS: In case it is of concern, here is my code to logout: <?php INCLUDE "session.php"; session_start(); setcookie("COOKIENAME", "", time()-3600, "/", "", FALSE, TRUE); //censored for security session_destroy(); header('Location: index.php?logout'); exit; ?> Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/ Share on other sites More sharing options...
PFMaBiSmAd Posted March 28, 2008 Share Posted March 28, 2008 session.cookie_domain = www.mydomain.com Your cookie domain setting requires the www. If you are using any url's that goto mydomain.com (without the www.), then the session cookie does not match and won't be sent to the server. You should actually use .mydomain.com (with the leading dot) to match all host/sub-domain names. The cookie lifetime is only the amount of time after the browser is closed. As long as the browser is not closed, then the cookie is kept in the browser's cookie cache and you can navigate anywhere, even off site, and the session cookie will be sent to the server (providing the domain/path settings match the current url.) Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-503338 Share on other sites More sharing options...
bryan52803 Posted March 28, 2008 Author Share Posted March 28, 2008 Interesting. Thank you for the input. I've corrected the domain; I did not even think of that. However, I do not, at this time, use any subdomains so that is not where the issue lies. But what you mentioned about the cookie expiration means that, if this is the case, that the problem is somewhere other than the cookies perhaps. Now I'm really lost as to what is happening :-\. Maybe, for whatever reason, the expiration is not being updated in the database as it should. I'll double check the syntax and make sure, but then an error should have occurred, and the output would have been affected, as I have error outputting turned on currently. Thanks again. Bryan Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-503351 Share on other sites More sharing options...
bryan52803 Posted March 29, 2008 Author Share Posted March 29, 2008 I double checked my syntax and everything appears fine. I'm really hopeless on this one. :-\ I've gone over everything so many times! Bryan Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-503898 Share on other sites More sharing options...
PFMaBiSmAd Posted March 29, 2008 Share Posted March 29, 2008 Try putting the following two lines of code after your first opening <?php tag on all pages - ini_set ("display_errors", "1"); error_reporting(E_ALL); Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-503941 Share on other sites More sharing options...
bryan52803 Posted March 29, 2008 Author Share Posted March 29, 2008 Ok now for a bizarre new twist... My server time is GMT - 8. I noticed when quickly checking the session expiration after creating or updating a session, it set it not equal to the current time plus 3600seconds (1 hour), but it set it equal to THE CURRENT TIME. This is perplexing to me. How could the time() function in my session handlers be different from time() called anywhere else? Setting the expiration to time() + 3600 + 3600 finally yielded the correct session expiration. This makes no sense to me... When I make a new post, I call the time() function to insert the timestamp into mysql. This yields the proper timezone of GMT - 8. However, calling time() in the session handler, it's an hour behind, GMT - 9. ARGH! Is there any proper explanation for this behavior, and a way I can get everything on the same page!??! -Very Confused Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-503988 Share on other sites More sharing options...
PFMaBiSmAd Posted March 29, 2008 Share Posted March 29, 2008 You should store the current time in the database and then do any session.gc_maxlifetime checking in the mysql_session_garbage_collect routine, that is why that function receives the $lifetime as a parameter. The way it is now, if you change the session.gc_maxlifetime setting, it won't affect any existing sessions. One thing that is of some concern, you are calling the timestamp you are storing the "session expiration". The purpose of the garbage collection function is only to delete old session data files/records. It is not for the purpose of ending sessions. The garbage collection is truly a random function using the session.gc_probability/session.gc_divisor. Using the garbage collection function for any other purpose or setting the session.gc_probability so that GC runs on each session start will both prevent you from using sessions normally and will create an unnecessary server load. Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-504009 Share on other sites More sharing options...
bryan52803 Posted March 29, 2008 Author Share Posted March 29, 2008 Hmm. I see your first point. However, I'm not running the GC function upon every session start; I'm not sure what you're exactly referring to here. Back to the first point, I took your advice. Now it inserts the current time into the database, and no longer enforces an expiration at a PHP level. So the only way the session is ended is as follows: * The user logs out calling the mysql_session_destroy function * The cookie is destroyed and thus the SID is no longer persisted/channeled and a new session is created. This will happen 3600s after they close their browser, correct? * OR the session time in the database, when it was created, is lower than the current time plus the gc_lifetime variable (1 hour). Let me play around with this configuration and see if it works better. As a side note, I feel like most of my woes are extending from a lack of knowledge on the session_save_handler function. Is there a good set of documentation on this function? I have yet to come across one that really explains session handling in detail. Bryan EDIT: It seems like this might be my best bet; and as a side note, ignore the time difference thing. It appears the timestamp converter I was using online didn't take into account daylights savings time. Ugh, sometimes I hate my life.... Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-504048 Share on other sites More sharing options...
PFMaBiSmAd Posted March 29, 2008 Share Posted March 29, 2008 While you can delete the session cookie (your setcookie() code) to log someone out, you should not rely on that. Someone can simply make a copy of the cookie and put it back if they see you are changing it or deleting it to log them out. You should only rely on server side data to indicate if someone is logged in or logged out. Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-504080 Share on other sites More sharing options...
bryan52803 Posted April 1, 2008 Author Share Posted April 1, 2008 I'm well aware of that, which is why session_destroy() is called. Thank you. That said, I'm inclined to disagree with you. After several experiments, I noticed the cookie does NOT persist 3600s after browser closure as you indicated, but rather 3600s after creation, as I originally stated. Which leads me back to my original point and question: how do I persist a cookie to match a persisting session? Maybe it's firefox, but I'm positive this is what is happening: 1. User browses my site 2. Since cookies are forced, a cookie is created immediately at the first viewing of a page. 3. After 50min of browsing, the user decides to post a comment. 4. By logging in and writing session data, the expiration in the session (the mysql database) is augmented, thus restarting the expiration back to 1 hour from the present time. 5. If the user takes 15 minutes to write a comment and press submit, the cookie expires (being set to 60min). 6. A new session is created with NO data, the user is prompted to login. 7. Though the session data exists in the database with a proper, updated expiration time, the SID was not propagated through the cookie and thus all data is seemingly lost. Does anyone have a solution to this problem? Thank you for your time and consideration. Bryan Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-506200 Share on other sites More sharing options...
bryan52803 Posted April 2, 2008 Author Share Posted April 2, 2008 Anyone please? I don't want to start a new topic, especially since I'm back to where I started. I know the problem! I just need a solution... Bryan Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-507946 Share on other sites More sharing options...
bryan52803 Posted April 4, 2008 Author Share Posted April 4, 2008 SOLVED: To update the cookie, one needs to set the cookie again with the SAME PARAMETERS but different time. If cookies are automatic, its a such: setcookie(session_name(), session_id(), time()+3600, "PATH","DOMAIN"); //Augment Cookie expiration by 1 hour (3600s) Where PATH is path specified in your php.ini, and DOMAIN is the domain specified in your php.ini. Leaving any of these parameters blank or NULL as old documentation has suggested, the cookie will not update. I believe this is a security feature of modern browsers. So two lessons learned here: * Cookies expire on time, not 3600s after browser closure * To change the time of a cookie (to include time()-3600 to delete), setcookie must be called with ALL the same parameters except the different time. Bryan Link to comment https://forums.phpfreaks.com/topic/98339-solved-session-madness/#findComment-509397 Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.