Detecting a cookie set using setcookie without a page reload - php

I am maintaining the code for an eCommerce website, they use a highly modified version of osCommerce v2.2 RC2. Was noticing an issue where the session isn't started for a new user until they visit the 2nd page of the site.
Looking at the code, before starting the session, it tries to set a cookie. If it detects the cookie it starts the session. Something along this line:
setcookie('cookie_test', 'please_accept_for_session', time()+60*60*24*30, $cookie_path, $cookie_domain);
if (isset($_COOKIE['cookie_test'])) {
session_start();
...
I found an article here that talks about a situation like this, it states:
The first time you only tell the browser to set the cookie, at the time, there is no cookie data in the request header (which could get from $_COOKIE).
Which explains why it takes two page loads for the session to be started. One to set the cookie and one to get notification from the browser that the cookie is set.
My question is, is there anyway around having to go through two page loads to detect the cookie was successfully set on the users browser?
I found this question that didn't really answer my question completely. The highest voted solution was:
setcookie('uname', $uname, time()+60*30);
$_COOKIE['uname'] = $uname;
Which may make it "work" but it doesn't truely tell me that the script was able to set a cookie successfully.
I also found this question, that suggested accessing the headers_list to find the cookie information like so:
function getcookie($name) {
$cookies = [];
$headers = headers_list();
// see http://tools.ietf.org/html/rfc6265#section-4.1.1
foreach($headers as $header) {
if (strpos($header, 'Set-Cookie: ') === 0) {
$value = str_replace('&', urlencode('&'), substr($header, 12));
parse_str(current(explode(';', $value, 1)), $pair);
$cookies = array_merge_recursive($cookies, $pair);
}
}
return $cookies[$name];
}
// [...]
setcookie('uname', $uname, time() + 60 * 30);
echo "Cookie value: " . getcookie('uname');
Which, again, doesn't seem to be verifying that the cookie was set successfully. All this appears to do is search the headers being sent to the browser for the cookie value.
The only solution I can think of is to redirect on the first visit after setting the cookie. Is there any other way?

Here is the answer:
<?php
function set_cookie($name, $value) {
if (!isset($_COOKIE[$name]) || ($_COOKIE[$name] != $value)) {
$_COOKIE[$name] = $value;
}
setcookie($name, $value, strtotime('+1 week'), '/');
}
// Usage:
set_cookie('username', 'ABC'); //Modify the value to see the change
echo $_COOKIE['username'];

Related

PHP, Cookie theft

I store a basket cookie Id which is really uniq, a long random 20 characters string like that: "7irMz2cvpnXpSCkNkBAT"
It's stored on browser not directly in a single Cookie but in a Json global cookie containing multiple values.
I can see Baskets from an admin part and I have sometimes a Basket from let's say a client from New-Zealand falling into the Basket of a someone in India who created an account!
It's all the time the same user stealing the basket Cookie from someone else and putting in it 20 articles which had not been put originally by the client.
I don't know if it's a bot from India or a real person doing that!
How to prevent cookie theft?
I cannot associate a cookie to an IP, people with smartphones for example change sometimes of IP address.
To recover / create / update the cookie I do like that:
// Recovering the Cookies from the Datas Json Object
if(isset($_COOKIE['Datas'])) {
$cookie = json_decode($_COOKIE['Datas']);
if(is_object($cookie)) {
$expiry = $cookie->expiry;
$diff=$expiry-time();
$cookieDatasExpiresDays = floor($diff/(60*60*24));
foreach($cookie->Data as $key => $value) {
$_COOKIE[$key] = $value;
}
} else {
setcookie('Datas', '', -1, '/');
}
}
/**
* Cookie for basket used for non connected users
*/
if((!isset($_COOKIE['Basket']) || $_COOKIE['Basket'] == NULL) &&
!check_bot()) { //We check also if Cookies are enabled
$updateCookie = 'Basket';
$_COOKIE['Basket'] = get_stringSuffle(20, TRUE);
}
if(isset($_COOKIE['Basket'])) {
$cookiesInfos['Basket'] = $_COOKIE['Basket'];
}
...
if($updateCookie != '' && !check_bot()) { //We check also if Cookies are enabled
// Updating Cookie if needed
$cookiesArray = [];
$cookiesArray['Data'] = [];
foreach($cookiesInfos as $key => $val) {
$cookiesArray['Data'][$key] = $val;
}
setcookie('Datas', '', -1, '/');
setcookie('Datas', json_encode($cookiesArray), $expiry, '/');
}
EDIT
As advised by #nice_dev I added the secure options to my call on setcookie:
setcookie('Datas', json_encode($cookiesArray), $expiry, '/', $_SERVER['HTTP_HOST'], TRUE, TRUE);
Note: That's perfect, this modification on the server didn't made me loose any of my Cookie.

Determine whether a cookie was set

Is there a straightforward way to test whether a cookie has been set during the current request? I'm writing an extension to existing code, so I can't modify the current code to add something like $_COOKIE['something'] = $someValue;. Unfortunately, only setcookie is called, without the event being logged in any other way. I need to know before the client receives the headers, because I need to set the cookie if the existing code hasn't already done so.
Have you tried using isset?
if( ! isset($_COOKIE['something'])) {
$_COOKIE['something'] == $somevalue;
}
Here's my "brute force" solution for now. I'm hoping to find a better method, though. Note that headers_list() gets the headers that are going to be sent to the browser as part of the response, not the headers that were sent by the browser during the request.
foreach (headers_list() as $header) {
list($k, $v) = explode(': ', $header, 2);
if (strtolower($k) != 'set-cookie') {
continue;
}
$name = explode('=', $v, 2)[0];
if ($name == $cookieName) {
return true;
}
}
return false;

No method of un-setting cookies is working

I'm trying to unset/delete/expire cookies on a logout page. However, it doesn't seem to be working. My logout script reads as follows:
require_once("database.php"); // contains session_start()
$_SESSION = array();
session_destroy();
// attempts to unset cookies go here (see below)
var_dump($_SERVER['HTTP_COOKIE']);
header("Location: ./login.php");
exit();
My three attempts to remove a specific cookie login (or all of them), are as follows:
Attempt 1:
setcookie("login", "", time() -3600, "/");
Attempt 2:
$cookies = explode(";", $_SERVER['HTTP_COOKIE']);
foreach ($cookies as $cookie) {
$parts = explode("=", $cookie);
$name = trim($parts[0]);
setcookie($name, "", time() -3600);
setcookie($name, "", time() -3600, "/");
}
Attempt 3:
unset($_COOKIE);
However my var_dump() still contains the cookies!
Also, the page you're then redirected to, login.php contains the following code:
if (isset($_COOKIE['login'])) {
echo "Still set."
}
and low-and-behold, the page displays Still set.
First of all remove all cookies from any available Cookie tools or your browser's developer tool.
Always write COOKIES as '/' with respect to entire domain of site. Path play an important role when we set/unset cookies. Use
setcookie($cookie_name, "$cookie_value", time() +3600, "/") to set and setcookie($cookie_name, "$cookie_value", time() -360000, "/") to unset COOKIES.
Further read here for about COOKIES path: http://www.w3schools.com/php/func_http_setcookie.asp
Hope it helps you

Why won't my cookie go away? **UPDATE**

I'm setting an auth cookie like so:
$identifier = $this->createIdentifier($username);
$key = md5(uniqid(rand(), true));
$timeout = time() + 60 * 60 * 24 * 100;
setcookie('auth', "$identifier:$key", $timeout);
After logout I'm trying to invalidate it by doing this:
setcookie('auth', "", time() - 3600);
When I try to view a restricted page after logging out I'm checking to see if the cookie exists:
if (isset($_COOKIE['auth'])) {
error_log("COOKIE EXISTS: " . print_r($_COOKIE, true));
}
Here is my logout script:
if (!isset($_SESSION)) session_start();
$ref="index.php";
if (isset($_SESSION['username'])) {
unset($_SESSION['username']);
session_unset();
session_destroy();
// remove the auth cookie
setcookie('auth', "", time() - 3600);
}
header("Location: " . $ref);
exit();
I shouldn't be hitting this code but I am. After logging out I see the cookie has been removed from my browser. Any idea how it's finding it again after logging out?
UPDATE
This code get called from another class that checks user privs etc. The only files it doesn't work with are files that reference it from one directory above. For instance
Any file referencing it like this works OK:
<?php include_once('classes/check.class.php');
Any file referencing it like so DO NOT work:
<?php include_once('../classes/check.class.php');
Any thoughts what might be causing this?
After you log the user out you need to do a redirect to cause a new page load. Since cookies are sent with page requests until a new requests is made those cookies are still alive even after you "delete" them.

PHP - why can't I get rid of this session id cookie?

I'm trying to troubleshoot a logout function for a web app. When you're logged in, the app has several cookies set for its domain. Here's the current logout procedure:
You click a link, which sends you to a logout page
The logout page runs a function that calls session_destroy() and also loops through all the cookies for the domain and sets them to expire in the past (see code below)
The logout page then redirects to a login page, which is straight HTML.
At the end of this process, all the other cookies are unset, but the PHPSESSID cookie is still there, has the same value, and is still set to expire at the end of the session.
What am I missing here?
Here's the logout function I mentioned above:
function log_out_current_user() {
// Destroy the session
if (isset($_SESSION)) {
session_destroy();
}
// Expire all of the user's cookies for this domain:
// give them a blank value and set them to expire
// in the past
if (isset($_SERVER['HTTP_COOKIE'])) {
$cookies = explode(';', $_SERVER['HTTP_COOKIE']);
foreach($cookies as $cookie) {
$parts = explode('=', $cookie);
$name = trim($parts[0]);
setcookie($name, '', time()-1000);
setcookie($name, '', time()-1000, '/');
}
// Explicitly unset this cookie - shouldn't be redundant,
// but it doesn't hurt to try
setcookie('PHPSESSID', '', time()-1000);
}
}
You are not removing it with the same parameters as it was created. Use session_get_cookie_params to obtain those. To be portable you should get the name of the cookie via session_name. Here's a small script to do that:
$params = session_get_cookie_params();
setcookie(session_name(), '', 0, $params['path'], $params['domain'], $params['secure'], isset($params['httponly']));

Categories