New cookie value not taken into account without refreshing page [duplicate] - php

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'];
}

Related

How to change Cookies value at runtime [duplicate]

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'];
}

Cookies do not work on my server

I have a problem with the cookies.
I have created a simple cookie and tried to echo it on my server.
setcookie('user', 'John', time() + 4800);
echo $_COOKIE['user'];
I also checked the value using the function var_dump() and the result is NULL.
I do not understand why :-(
Note that you cannot set a cookie in PHP and hope to retrieve the cookie immediately in that same script session. It will be available on the next request.
This doesn't mean that the cookie has not been sent, it just means you can't test it in the same script run.
Of course, before that, make sure that your cookies are turned on.
if(!isset($_COOKIE['user'])) {
setcookie('user', 'John', time() + 4800, '/');
// set the cookie with the fourth parameter with root
// so that its sitewide
} else {
echo $_COOKIE['user'];
}

php cookie does not work at the first time reading

I am a beginner for PHP and studying to use cookie for login. Would any body please check my code to see what is my problem, or let me how to fix this problem.
When I open the page at the first time, the cookie will not work. It will work when I repeated to open that link. However, I still could not make it work after I use function include and header One of codes is :
One code cookie.php is :
<?php
setcookie("cookiename",$_REQUEST['name']);
if(isset($_COOKIE['cookiename'])){
$cookieSet = ' The Cookie is ' . $_COOKIE['cookiename'];
} else {
$cookieset = ' No Cookie has been set';
}
setcookie("cookiepwd",$_REQUEST['pwd']);
print_r($_COOKIE);
?>
When I run this code first time, it will does not show any thing. I can see cookie data at second time. From some website it is said that cookie would not be read at the same page.
So I moved print_r($_COOKIE) to second php file as well as added function include() or header() to above file, but both neither works.
Cookie2.php:
<?php
setcookie("cookiename",$_REQUEST['name']);
if(isset($_COOKIE['cookiename'])){
$cookieSet = ' The Cookie is ' . $_COOKIE['cookiename'];
} else {
$cookieset = ' No Cookie has been set';
}
setcookie("cookiepwd",$_REQUEST['pwd']);
include(‘printcookie.php’);
//or header("Location: printcookie.php")
?>
printcookie.php:
<?php
print_r($_COOKIE);
?>
Thank you very much for answering in advance!
Michelle
setcookie only sets up the header, that is being sent to the client. It doesn't change the $_COOKIE superglobal.
In other hand - $_COOKIE is filled up with the cookies sent from the client
So at first step - you set the cookie with setcookie and have nothing in $_COOKIE because client hasn't sent it yet, and will only on the next request.
And there is no way of doing what you want, rather than modifying $_COOKIE manually
PS: it is a bad idea to put user's password in the cookie
Give zerkms the answer, but I just want to reiterate:
Cookies are not bad for storing bits of info like the user's theme preferences or preferred start page, etc. They get their bad rep from being used for identity and authentication handling. There are cookies out there that basically have "isAdmin=0" in order to control user access. It is very easy to change that to isAdmin=1 and have a field day. Since you are new to PHP, take the time to learn about sessions now while it's all new to you.
When you set a cookie using setcookie, you are sending an HTTP header to the browser with the cookie info. The browser will then pass back that cookie in any future requests to the server. The $_COOKIE global variable holds the cookie info passed in from the browser to the server.
Since you are using $_REQUEST to get the cookie name, you don't need to check the cookie (otherwise you wouldn't have the data to set it right?). So consider going this route:
if(!isset($_COOKIE['cookiename'])) {
$name = $_POST['name']);
setcookie("cookiename",$name);
} else {
$name = $_COOKIE['cookiename']);
}
echo "Welcome back $name!";
This will also help out if they clear cookies, etc.
But really, the safer route is:
session_start();
if(!isset($_SESSION['name'])){
$_SESSION['name'] = $_POST['name']);
}
if(!isset($_SESSION['pwd'])){
$_SESSION['pwd'] = $_POST['pwd']);
}
$name = $_SESSION['name'];
$pwd = $_SESSION['pwd'];
And even this would be frowned upon for serious web security, where you should simply check the password against a stored hash and then delete it, using other global variables to confirm session integrity. But there's now a whole StackExchange for that.
As a workaround you could use location() after checking the cookie to have access to the stored data.
But be aware that location() fails, if anything (including breaks and blanks in your script) already sent to the browser.

cookie delete problem

I have two simple functions to set and clear cookie.
private function _setCookie($value = null) {
$value = $value === null ? $this->getRandomId() : $value;
setcookie($this->getName(), $value, time()+10800, '/');
}
private function _clearCookie() {
setcookie($this->getName(), '', time()-10800, '/');
}
There is a page when accessed starts session and create a cookie as desired. When redirect call happens from different server to my page , delete cookie function calls internally above _clearCookie funtion.I checked setcookie returns true and I also tried to unset cookie in same method but cookie is still available when I reload page. I still can find that cookie in browser as well as firebug and print_r($_COOKIE)
Also I changed expire time to time()-(3600*24) as mentioned is some others threads but no change in my case. What am I missing here?
so when I mentioned 'redirect call happens from different server to my page' I was trying to mention it as back channel call. And being a back channel call, browser cookies were not getting identified I suppose and that is the main reason even if setcookie returns me true, actual cookie deletion from browser would never happen in such cases.

Set cookie and update cookie problem - Php

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.

Categories