In an attempt to get more familiar with cookies I've decided to set up a simple cookie management system to have more control of the information that I can store and retrieve from a user.
The idea is to set a cookie if it does not exist, and update a cookie if it already exists on the user.
Once the cookie is set, it will also be stored in a database that will keep track on when the session started and when it was last accessed.
Creating a cookie worked well at first. But suddenly it stopped working and wouldn't set anything at all. This is the current code of the createSession() function:
function createSession() {
// check to see if cookie exists
if(isset($_COOKIE["test"])) {
// update time
$expire = time()+81400;
setcookie("test","$cookiekey",$expire,"/",false,0);
} else {
// assign unique cookie id
list($msec,$sec)=explode(" ",microtime());
$cookiekey = preg_replace("/./","",($msec+$sec));
// set time
$expire = time()+81400;
// set cookie
setcookie("test","$cookiekey",$expire,"/",false,0);
// assign the unqiue id to $_COOKIE[]
$_COOKIE["test"]=$cookiekey;
unset($cookiekey);unset($msec);unset($sec);unset($expire);
}
}
Is my approach heading in the right direction or have I done something way wrong?
Doing $_COOKIE["test"] = something; doesn't make a "test" cookie. You need to use setcookie again.
I don't know why you'd want to do that though. Why not just check for $_COOKIE["name"] (the cookie that you are making).
Cookies are only available once another request was done. So don’t modify $_COOKIE on your own.
Furthermore, when in your case the cookie exists (i.e. $_COOKIE['test'] is set) you call setcookie again with $cookiekey as its value. But $cookiekey is not defined at that moment so the cookie will be overwritten with an empty string. I guess you want to use $_COOKIE['test'] instead:
if (isset($_COOKIE["test"])) {
// update time
$expire = time()+81400;
setcookie("test", $_COOKIE["test"], $expire, "/", false, 0);
}
You could also save yourself all that pain by using PHP's built in session management (examples here) to handle all of this cookie stuff for you.
Related
I have the following PHP function:
function validateUser($username){
session_regenerate_id ();
$_SESSION['valid'] = 1;
$_SESSION['username'] = $username;
setcookie('username2',$username,time()+60*60*24*365);
header("Location: ../new.php");
}
And then I fetch the cookie:
echo $_COOKIE['username2']; exit();
(I only put exit() for debugging purposes)
Only problem, it's coming out blank. Any ideas?
UPDATE:
This is how the function is called:
if(mysql_num_rows($queryreg) != 0){
$row = mysql_fetch_array($queryreg,MYSQL_ASSOC);
$hash = hash('sha256', $row['salt'] . hash('sha256', $password));
if($hash == $row['password']) {
if($row['confirm'] == 1){
if(isset($remember)){
setcookie('username',$username,time()+60*60*24*365);
setcookie('password',$password,time()+60*60*24*365);
} else {
setcookie('username','',time()-3600);
setcookie('password','',time()-3600);
}
validateUser($username);
I didn't include all the if() statements to save some space.
try adding the path = /, so that the cookie works for the whole site not just the current directory (that has caught me out before)
example
setcookie('password',$password,time()+60*60*24*365, '/');
also make sure the cookie is the first thing being output
as advised in the php manual (this has caught me out before too)
Like other headers, cookies must be sent before any output from your
script (this is a protocol restriction).
Why you are having this problem
The problem comes from the fact that setcookie() doesn't set the cookies immediately, it sends the headers so the browser sets the cookies. This means that, for the current page load, setcookie() will no generate any $_COOKIE.
When the browser later on requests a page, it sends the cookies in the headers so the PHP can retrieve them in the form of $_COOKIE.
Simple, old solution
About solutions, the obvious one:
setcookie('username',$username,time()+60*60*24*365);
// 'Force' the cookie to exists
$_COOKIE['username'] = $username;
A better solution
I created a class, Cookie, that addresses the problems that setcookie() and $_COOKIE share:
// Class that abstracts both the $_COOKIE and setcookie()
class Cookie
{
// The array that stores the cookie
protected $data = array();
// Expiration time from now
protected $expire;
// Domain for the website
protected $domain;
// Default expiration is 28 days (28 * 3600 * 24 = 2419200).
// Parameters:
// $cookie: $_COOKIE variable
// $expire: expiration time for the cookie in seconds
// $domain: domain for the application `example.com`, `test.com`
public function __construct($cookie, $expire = 2419200, $domain = null)
{
// Set up the data of this cookie
$this->data = $cookie;
$this->expire = $expire;
if ($domain)
$this->domain = $domain;
else
{
$this->domain =
isset($_SERVER['HTTP_X_FORWARDED_HOST']) ?
$_SERVER['HTTP_X_FORWARDED_HOST'] :
isset($_SERVER['HTTP_HOST']) ?
$_SERVER['HTTP_HOST'] :
$_SERVER['SERVER_NAME'];
}
}
public function __get($name)
{
return (isset($this->data[$name])) ?
$this->data[$name] :
"";
}
public function __set($name, $value = null)
{
// Check whether the headers are already sent or not
if (headers_sent())
throw new Exception("Can't change cookie " . $name . " after sending headers.");
// Delete the cookie
if (!$value)
{
setcookie($name, null, time() - 10, '/', '.' . $this->domain, false, true);
unset($this->data[$name]);
unset($_COOKIE[$name]);
}
else
{
// Set the actual cookie
setcookie($name, $value, time() + $this->expire, '/', $this->domain, false, true);
$this->data[$name] = $value;
$_COOKIE[$name] = $value;
}
}
}
Then you can use it like this:
$Cookie = new Cookie($_COOKIE);
$User = $Cookie->user;
$LastVisit = $Cookie->last;
$Cookie->last = time();
And of course, you have to pass it around. Much better than having globals.
Here is the general syntax of setcookie
setcookie(name,value,expire,path,domain,secure);
Look at third argument, if you do not set it the script will take it to current working directory. So if you set a cookie without setting path at a.com/b/setcookie.php the cookie will not be available to a.com/checkcookie.php. What you are doing is setting cookie in a subfolder and the redirecting to a parent folder, look at ../, where it is not available hence the issue. How to avoid this? Normal procedure is to supply a path that is /, in your case supply / as fourth param. The fifth argument for your cookie will set it secure. http://www.php.net/setcookie has more explanation. This should fix your problem. Setting domain path to domain.com, will make the cookie available to everything under domain.com but not to something.domain.com. Set domain value to .domain.com, look at the dot preceding domain.com, will make it available across anything.domain.com. HTH!
Thought I would add another possible reason why a cookie may not be either setting or showing random functional behavior.
The following case may be applicable to some programmers having what appears to be an illusive cookie setting issue as a result of the incorrect usage of header_remove()
If you try to set a cookie before calling header_remove(), the cookie will never be created because you have also immediately destroyed the header that was set in order to create the cookie before it was buffered out to the client.
You may find when fiddling around that your cookie suddenly works for an unknown reason, so you need to understand the race-conditions around headers:
On first run you set a cookie and don't call header_remove() at all.
On a second run you do call header_remove()
You will find your cookie is now always set regardless of condition (2) and the number of times it is called because (1) happened first at least once.
The cookie will remain set until it either expires, is overwritten or unset()
The same will apply when modifying headers like a cookie value before the eventual call of header_remove(), you again will fail to set new values because they will be wiped before the response is buffered out to the user.
You need to set cookies and any other headers for that matter after a header_remove() not before.
Use header_remove() to cleanup ALL previously set headers in order to set new headers for a final output.
An example of scenario for such a case may be as follows:
Use header_remove() to alter a hierarchy of HTTP Response codes for a RESTFUL API where you are using axios with interceptors.
Your application sets a 400+ header error first, should the application error out at any point of execution.
Modify the header to a 200 when final desired execution point has been reached & a valid response is expected.
In such an event, it is likely you want to preserve all other previously set headers but clear out the HTTP Status (400?) code in order to set a new (200?) code for the final response.
If you try to set the header again in order to change the status code before removing the previously set header then you will get the "Headers already sent" error.
You can remove specific headers with header_remove, here is how to unset the status code and set a new code in stages:
// Set a default status code
http_response_code(500);
// Boot Logic runs - if fails here 500 is returned
// Authentication Logic - If unauthorized ?
header_remove('HTTP/1.0'); // Clear previous 500
http_response_code(401); // Set new status code
// else ?
// Return Data Logic - Success
header_remove('HTTP/1.0'); // Clear previous 500
http_response_code(200) // Set new status code
This requires that you place calls to this function prior to any output, including and tags as well as any whitespace.
this is how the structure looks
<?php
$cookie_name = "user";
$cookie_value = "Ahmed Moftah";
setcookie($cookie_name, $cookie_value, time() + (86400 * 30), "/"); // 86400 = 1 day
?>
<?php
if(!isset($_COOKIE[$cookie_name])) {
echo "Cookie named '" . $cookie_name . "' is not set!";
} else {
echo "Cookie '" . $cookie_name . "' is set!<br>";
echo "Value is: " . $_COOKIE[$cookie_name];
}
?>
<html>
<body>
</body>
</html>
It might be a cache problem. Try closing the browser and opening a new one with the localhost file path. I had the same issue and my page was cached so the cookies weren't working, even though I could put in new code and see a change on the page. Very weird... Cleaning your cache might help, try that first. Then try a new browser, then try to go to your localhost:8080 index and hit refresh to see when the last page was modified.
If that doesn't fix it, try restarting LAAMP or XAAMP or whatever you are using.
This happens with the session cookies are disabled.
You can navigate to your php.ini file(changes depending on server. Ubuntu 20.04's default is /etc/php/{X.x}/{apache2|[others]}/php.ini) and ensure that session.use_cookies=1
Restart your server and then try to set the cookie. They should immediately be available.
You probably have sent header hereby making it impossible to set header for cookie.
It might be a simple solution of ob_start() at the start of your page.
[Solution tested in XAMPP for PHP 8.0.19]
I modified the file php.ini and set session.auto_start=1. Keep in mind that i'm calling session_set_cookie_params([param => value]) just before session_start() every time this functions appears in my code, in every file.
session.auto_star: Initialize session on request startup.
http://php.net/session.auto-start
Still studying and analysing the reason and functionality of this, it was kind of a serendipity.
Probably not the most secure solution.
You can't get the $_COOKIE on the same request but you can get $_SESSION on the same request.
So the idea is
Set the $username in both the session & cookie.
Get the username from the session for the first time (if the same request)
Unset session
Always get the cookie from $_COOKIE from next request.
// Set Cookie
setcookie('username',$username,time()+60*60*24*365);
$_SESSION['username'] = $username;
//GET Cookies
if(!$_COOKIE['username']){
$username = $_SESSION['username'];
unset($_SESSION['username']);
}else{
$username = $_COOKIE['username'];
}
I have the following PHP function:
function validateUser($username){
session_regenerate_id ();
$_SESSION['valid'] = 1;
$_SESSION['username'] = $username;
setcookie('username2',$username,time()+60*60*24*365);
header("Location: ../new.php");
}
And then I fetch the cookie:
echo $_COOKIE['username2']; exit();
(I only put exit() for debugging purposes)
Only problem, it's coming out blank. Any ideas?
UPDATE:
This is how the function is called:
if(mysql_num_rows($queryreg) != 0){
$row = mysql_fetch_array($queryreg,MYSQL_ASSOC);
$hash = hash('sha256', $row['salt'] . hash('sha256', $password));
if($hash == $row['password']) {
if($row['confirm'] == 1){
if(isset($remember)){
setcookie('username',$username,time()+60*60*24*365);
setcookie('password',$password,time()+60*60*24*365);
} else {
setcookie('username','',time()-3600);
setcookie('password','',time()-3600);
}
validateUser($username);
I didn't include all the if() statements to save some space.
try adding the path = /, so that the cookie works for the whole site not just the current directory (that has caught me out before)
example
setcookie('password',$password,time()+60*60*24*365, '/');
also make sure the cookie is the first thing being output
as advised in the php manual (this has caught me out before too)
Like other headers, cookies must be sent before any output from your
script (this is a protocol restriction).
Why you are having this problem
The problem comes from the fact that setcookie() doesn't set the cookies immediately, it sends the headers so the browser sets the cookies. This means that, for the current page load, setcookie() will no generate any $_COOKIE.
When the browser later on requests a page, it sends the cookies in the headers so the PHP can retrieve them in the form of $_COOKIE.
Simple, old solution
About solutions, the obvious one:
setcookie('username',$username,time()+60*60*24*365);
// 'Force' the cookie to exists
$_COOKIE['username'] = $username;
A better solution
I created a class, Cookie, that addresses the problems that setcookie() and $_COOKIE share:
// Class that abstracts both the $_COOKIE and setcookie()
class Cookie
{
// The array that stores the cookie
protected $data = array();
// Expiration time from now
protected $expire;
// Domain for the website
protected $domain;
// Default expiration is 28 days (28 * 3600 * 24 = 2419200).
// Parameters:
// $cookie: $_COOKIE variable
// $expire: expiration time for the cookie in seconds
// $domain: domain for the application `example.com`, `test.com`
public function __construct($cookie, $expire = 2419200, $domain = null)
{
// Set up the data of this cookie
$this->data = $cookie;
$this->expire = $expire;
if ($domain)
$this->domain = $domain;
else
{
$this->domain =
isset($_SERVER['HTTP_X_FORWARDED_HOST']) ?
$_SERVER['HTTP_X_FORWARDED_HOST'] :
isset($_SERVER['HTTP_HOST']) ?
$_SERVER['HTTP_HOST'] :
$_SERVER['SERVER_NAME'];
}
}
public function __get($name)
{
return (isset($this->data[$name])) ?
$this->data[$name] :
"";
}
public function __set($name, $value = null)
{
// Check whether the headers are already sent or not
if (headers_sent())
throw new Exception("Can't change cookie " . $name . " after sending headers.");
// Delete the cookie
if (!$value)
{
setcookie($name, null, time() - 10, '/', '.' . $this->domain, false, true);
unset($this->data[$name]);
unset($_COOKIE[$name]);
}
else
{
// Set the actual cookie
setcookie($name, $value, time() + $this->expire, '/', $this->domain, false, true);
$this->data[$name] = $value;
$_COOKIE[$name] = $value;
}
}
}
Then you can use it like this:
$Cookie = new Cookie($_COOKIE);
$User = $Cookie->user;
$LastVisit = $Cookie->last;
$Cookie->last = time();
And of course, you have to pass it around. Much better than having globals.
Here is the general syntax of setcookie
setcookie(name,value,expire,path,domain,secure);
Look at third argument, if you do not set it the script will take it to current working directory. So if you set a cookie without setting path at a.com/b/setcookie.php the cookie will not be available to a.com/checkcookie.php. What you are doing is setting cookie in a subfolder and the redirecting to a parent folder, look at ../, where it is not available hence the issue. How to avoid this? Normal procedure is to supply a path that is /, in your case supply / as fourth param. The fifth argument for your cookie will set it secure. http://www.php.net/setcookie has more explanation. This should fix your problem. Setting domain path to domain.com, will make the cookie available to everything under domain.com but not to something.domain.com. Set domain value to .domain.com, look at the dot preceding domain.com, will make it available across anything.domain.com. HTH!
Thought I would add another possible reason why a cookie may not be either setting or showing random functional behavior.
The following case may be applicable to some programmers having what appears to be an illusive cookie setting issue as a result of the incorrect usage of header_remove()
If you try to set a cookie before calling header_remove(), the cookie will never be created because you have also immediately destroyed the header that was set in order to create the cookie before it was buffered out to the client.
You may find when fiddling around that your cookie suddenly works for an unknown reason, so you need to understand the race-conditions around headers:
On first run you set a cookie and don't call header_remove() at all.
On a second run you do call header_remove()
You will find your cookie is now always set regardless of condition (2) and the number of times it is called because (1) happened first at least once.
The cookie will remain set until it either expires, is overwritten or unset()
The same will apply when modifying headers like a cookie value before the eventual call of header_remove(), you again will fail to set new values because they will be wiped before the response is buffered out to the user.
You need to set cookies and any other headers for that matter after a header_remove() not before.
Use header_remove() to cleanup ALL previously set headers in order to set new headers for a final output.
An example of scenario for such a case may be as follows:
Use header_remove() to alter a hierarchy of HTTP Response codes for a RESTFUL API where you are using axios with interceptors.
Your application sets a 400+ header error first, should the application error out at any point of execution.
Modify the header to a 200 when final desired execution point has been reached & a valid response is expected.
In such an event, it is likely you want to preserve all other previously set headers but clear out the HTTP Status (400?) code in order to set a new (200?) code for the final response.
If you try to set the header again in order to change the status code before removing the previously set header then you will get the "Headers already sent" error.
You can remove specific headers with header_remove, here is how to unset the status code and set a new code in stages:
// Set a default status code
http_response_code(500);
// Boot Logic runs - if fails here 500 is returned
// Authentication Logic - If unauthorized ?
header_remove('HTTP/1.0'); // Clear previous 500
http_response_code(401); // Set new status code
// else ?
// Return Data Logic - Success
header_remove('HTTP/1.0'); // Clear previous 500
http_response_code(200) // Set new status code
This requires that you place calls to this function prior to any output, including and tags as well as any whitespace.
this is how the structure looks
<?php
$cookie_name = "user";
$cookie_value = "Ahmed Moftah";
setcookie($cookie_name, $cookie_value, time() + (86400 * 30), "/"); // 86400 = 1 day
?>
<?php
if(!isset($_COOKIE[$cookie_name])) {
echo "Cookie named '" . $cookie_name . "' is not set!";
} else {
echo "Cookie '" . $cookie_name . "' is set!<br>";
echo "Value is: " . $_COOKIE[$cookie_name];
}
?>
<html>
<body>
</body>
</html>
It might be a cache problem. Try closing the browser and opening a new one with the localhost file path. I had the same issue and my page was cached so the cookies weren't working, even though I could put in new code and see a change on the page. Very weird... Cleaning your cache might help, try that first. Then try a new browser, then try to go to your localhost:8080 index and hit refresh to see when the last page was modified.
If that doesn't fix it, try restarting LAAMP or XAAMP or whatever you are using.
This happens with the session cookies are disabled.
You can navigate to your php.ini file(changes depending on server. Ubuntu 20.04's default is /etc/php/{X.x}/{apache2|[others]}/php.ini) and ensure that session.use_cookies=1
Restart your server and then try to set the cookie. They should immediately be available.
You probably have sent header hereby making it impossible to set header for cookie.
It might be a simple solution of ob_start() at the start of your page.
[Solution tested in XAMPP for PHP 8.0.19]
I modified the file php.ini and set session.auto_start=1. Keep in mind that i'm calling session_set_cookie_params([param => value]) just before session_start() every time this functions appears in my code, in every file.
session.auto_star: Initialize session on request startup.
http://php.net/session.auto-start
Still studying and analysing the reason and functionality of this, it was kind of a serendipity.
Probably not the most secure solution.
You can't get the $_COOKIE on the same request but you can get $_SESSION on the same request.
So the idea is
Set the $username in both the session & cookie.
Get the username from the session for the first time (if the same request)
Unset session
Always get the cookie from $_COOKIE from next request.
// Set Cookie
setcookie('username',$username,time()+60*60*24*365);
$_SESSION['username'] = $username;
//GET Cookies
if(!$_COOKIE['username']){
$username = $_SESSION['username'];
unset($_SESSION['username']);
}else{
$username = $_COOKIE['username'];
}
Previously i was creating additional cookie "rememberme" with unique hash, that was stored in the database, mapped to the user id.
If user had such cookie - website tried to find it's value in database, and if it was found session was setting up.
Later, developing new project i thought that it is maybe not very secure to generate this unique hash by myself, and keeping two cookies (native "PHPSESSID" + my "rememberme") for one operation (user identification) is overkill.
Maybe there is a way to setup not global session lifetime, but to setup it individually for different user sessions... or maybe it is better to keep user sessions in the database, mapped to the userid?
UPDATE 1
I thought if it is so hard to make "remember me" button, we can go another way - to make "Not my computer button". Idea is to set default cookie_lifetime for a week in php.ini (for example), and if user checkes this checkbox - we will set cookie_lifetime into zero using session_set_cookie_params function.
So, 1st question is - will session_set_cookie_params affect other users cookies (in documentation it is said, that session_set_cookie_params options will have effect until php process will be executing)
2d question is that if session_set_cookie_params is not affecting global settings, will session regeneration affect users, that don't want to keep a long-life cookie?
UPDATE 2: [Question 1 answer]
Just tested session_set_cookie_params function.
I wrote a script, that sets session cookie lifetime into zero using session_set_cookie_params and then executing for 30 seconds:
if ($_GET['test']) {
session_set_cookie_params (0);
while (true) {
sleep(1);
}
}
session_start();
So, in first browser i just started this script with ?test=1 parameter, just after that (while this script was executing) i started this script without parameters in the second browser. The answer is no - second browser's cookie was not affected. It had lifetime, that was specified in php.ini
UPDATE 3: [Question 2 answer]
Then, i've tried to check if regeneration affects session cookie lifetime, that was set by session_set_cookie_params.
Yes, it affects. If i set session cookie with customized lifetime, that was set by session_set_cookie_params, and then call session_regenerate_id(), cookie will have lifetime, set in php.ini
But, if we set session_set_cookie_params (0) before calling session_regenerate_id(), our cookie will have correct lifetime.
So, that's it! That was easy! 8)
Thank you, ladies and gentlemen!
If you want to do this only using sessions you can do the following if the user wants to be remembered:
if((isset($_POST['remember_me']) && $_POST['remember_me']) || ($_COOKIE['remember_me']) && $_COOKIE['remember_me'])) {
// store these cookies in an other directory to make sure they don't
// get deleted by the garbage collector when starting a "non-remeber-me"-session
$remember_me_dir = ini_get('session.save_path') . DS . "remember_me_sessions";
// create the directory if it doesn't exist
if (!is_dir($remember_me_dir)) {
mkdir($remember_me_dir);
}
// set the php.ini-directive (temporarily)
ini_set('session.save_path', $remember_me_dir);
// define lifetime of the cookie on client side
$expire_cookie = 60 * 60 * 24 * 30; // in seconds
session_set_cookie_params($expire_cookie);
// lifetime of the cookie on server side
// session file gets deleted after this timespan
// add a few seconds to make sure the browser deletes
// the cookie first.
$garbage_in = $expire_cookie + 600; // in seconds
// set the php-ini directive for the garbage collector of the session files.
ini_set('session.gc_maxlifetime', $garbage_in);
// send an additional cookie to keep track of the users
// which checked the 'remember_me' checkbox
setcookie('remember_me', 1, time() + $expire_cookie);
}
// now we are ready to start the session
// For all the users which didn't choose to check the 'remember_me' box
// the default settings in php.ini are used.
session_start();
Here you can read more about the session related php.ini-directives
As it was so hard to make "remember me" checkbox functionality, i came to another way, using only one cookie.
PREPARATION
1) I've prepared a form with three inputs:
"login" input [type=text]: user's login
"password" input [type=password]: user's password
"not my computer" input [type=checkbox]: that will tell us to use session cookie with lifetime = 0 (cookie must be deleted when browser will be closed)
2) I've set session.cookie_lifetime = 100500 to keep long-life cookies by default.
COOKIE SETUP
So, after user submits the form, we check - if he has selected to use short sessions - we call session_set_cookie_params(0) before setting session cookie to him (before actually using session_start()).
COOKIE REGENERATION
Then, when we need to regenerate session cookie, we can also do this easily with session_regenerate_id() function.
But we need to remember, that this function will re-set session cookie lifetime from php.ini by default.
So, we need also to call session_set_cookie_params() before regenerating a cookie.
BTW, You can store custom session cookie lifetime in $_SESSION.
It will look like this:
// Form handling, session setup
if ($_POST['not-my-computer']) {
session_set_cookie_params(0);
session_start();
$_SESSION['expires'] = 0;
}
// Session regeneration
if (isset($_SESSION['expires'])) {
session_set_cookie_params(0);
session_regenerate_id();
}
Details for this answer (and more deep explanations) you can find in the question text (while i was testing, i added answers/tests results there)
I'm having trouble setting cookies on the same page. I used cookies on my site and it works fine, I tend to set make the php in separate file. Now, I'm setting a cookie on the same page but it doesn't seem to work.
$expire = time()+5;
setcookie("rb_vote", 1, $expire);
then check if it is set
if(isset($_COOKIE["rb_vote"])) {
echo "IS SET";}
else {
echo "IS NOT SET"; }
It always says is not set. I tried doing this in page load but still doesn't work.
See the manual on setcookie() (emphasis mine):
Once the cookies have been set, they can be accessed on the next page load with the $_COOKIE or $HTTP_COOKIE_VARS arrays. Note, superglobals such as $_COOKIE became available in PHP 4.1.0. Cookie values also exist in $_REQUEST
Here is a workaround suggestion. It's imperfect because it can't guarantee the cookie actually gets set, but might do in your case.
I've just encountered this issue in Vanilla Forum. On the first page load, before a session has been established, a session cookie is created, but then every time the application wants to access the session variables (to add to them) it looks for the current session ID in $_COOKIE, which is not set until the next page load.
My workaround is to set the $_COOKIE element manually when the cookie is created.
// Create a cookie to identify the session.
// This line already exists. $Name is the cookie name.
// $SessionID is a random md5 ID that has just been generated.
setcookie($Name, $SessionID, $Expire, $Path, $Domain);
// Set the cookie for the remainder of the page. This is a workaround.
if (!isset($_COOKIE[$Name])) $_COOKIE[$Name] = $SessionID;
I've raised this as a fault with Vanilla (https://github.com/vanillaforums/Garden/issues/1568), as this workaround feels like a bit of a hack, but it certainly gets around the problem for now.
PHP5.3 Vanilla Forum Version 2.0.18.4
I want to check if a person has an active session and redirect them to another page when they have one. However, I do not want to use session_start(), as that will place a cookie on the persons PC (I do not want to place cookies on peoples' PC when they're not logged in). Is there a way to check for an existing session, without placing a cookie on their PC?
You can check for the existence of the session ID cookie, which the client would send back if it had been previous set elsewhere in your site:
if (isset($_COOKIE[session_name()])) {
... most likely there's a session available to be loaded ...
}
For added safety, you could then check for the existence of the session file (assuming you're using the default file-based handler) using session_save_path() and the session_name() to build up a path to pass into file_exists()
You can either check against the function session_id(), which will return the current session ID for the user, or an empty string if no session exists:
if (empty(session_id())) {
/* redirect or logic here here, example: */
header('location:path/to/your/session/start/page');
exit();
}
Or you can check that the session cookie/global variable is set (isset($_SESSION) or isset($_COOKIE[session_name()]. Doc for session_id() here
Test this first, but I think session_id() != "" will give true if there's a session and false if not.