Setting cookies on Zend Controller - php

We are trying to create a unique ID for each user that visits our site. I'm relatively new to Zend and to MVC patterns, so i'm unsure as to where the cookies should be set and how.
The php is very straight forward:
if(!isset($_COOKIE['mx_uid'])){
$expire = time()+60*60*24*30;
setcookie('mx_uid', uniqid('mx_'), $expire);
}
$lxid = $_COOKIE['mx_uid'];
I tried to place this into the View and ran into the issue that the cookie is regenerated on every new page that is loaded, so if they go to 20 pages on the site then they have 20 cookies.
Additionally, I need to use the "$lxid" variable inline on each page without refreshing, because a javascript snippet will be capturing the cookie contents.
Has anyone used cookies in this way on Zend?

If you need to set cookies once during one session place them in frontController plugin. Add to your app.ini
resources.frontController.plugins.a.class = "YourNamespace_Plugin_Cookies"
And then your plugin will look like
class YourNamespace_Plugin_Cookies extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$cookie = $request->getCookie('mx_uid');
if(empty($cookie)){
setcokkie('mx_uid',$lxid,$expire, '/');
}
}
}

You'll want to set the cookie path as well (4th param):
setcookie('mx_uid', uniqid('mx_'), $expire, '/');
Be aware that you may not be able to access the cookie within the same script in which you are setting it (i.e. it won't work until the next page they visit). So better logic might be:
if (isset($_COOKIE['mx_uid'])){
$lxid = $_COOKIE['mx_uid'];
} else {
$lxid = uniqid('mx_');
$expire = time()+60*60*24*30;
setcookie('mx_uid', $lxid, $expire, '/');
}
to ensure that $lxid will always contain a value.

Related

New cookie value not taken into account without refreshing page [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'];
}

cakephp : cookies not create after deleted

I have a question about cookies in cakephp. I create a cookies in cakephp view successfully, and I wrote a javascript function to delete that cookies if the page reloads, and that function is successfully deleted.
But after that cookies deleted, the same cookies cannot create anymore. Why does this happen?
This is my code that I have used to create that cookies :
$isiCookies=$awb['Awb']['id'].'^'.$awb['Awb']['awb_number'].'^'.$companies[$awb['Contract']['company_id']].'^'.$awb['Address']['address'].'^'.$types[$awb['ContractDetail']['content_type_id']].'^'.$awb['Awb']['colie'].'^'.$kilo.'^'.$manifestDetails[$awb['Awb']['id']];
if(!isset($_COOKIE['manifest_courier']))
{
setcookie("manifest_courier", $isiCookies, $date_of_expiry, "/");
}
else
{
setcookie("manifest_courier", rawurldecode($_COOKIE['manifest_courier']).'*'.$isiCookies, $date_of_expiry, "/" );
}
And this is the javascript function that I have used to deleted the cookies :
$(window).unload(function() {
Cookies.erase('manifest_courier');
});
Please tell me why the cookies are not created if the page reload. Thanks for your help.
You don't need to do everything in views.
First off, make sure the Cookie component is included in the controller.
var $components = array('Cookie');
Then, in your function,
$isiCookies = $awb['Awb']['id'].'^'.$awb['Awb']['awb_number'].'^'.$companies[$awb['Contract']['company_id']].'^'.$awb['Address']['address'].'^'.$types[$awb['ContractDetail']['content_type_id']].'^'.$awb['Awb']['colie'].'^'.$kilo.'^'.$manifestDetails[$awb['Awb']['id']];
if($this->Session->check('manifest_courier'))
{
$this->Cookie->write('manifest_courier',$isiCookies,false,$date_of_expiry);
}else{
$this->Cookie->write('manifest_courier',rawurldecode($_COOKIE['manifest_courier']).'*'.$isiCookies,false,$date_of_expiry);
}
In view, use that Js to delete the cookie if it still exists after refresh.

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.

how to test authentication system?

EDIT: After a complaint about assigning myself the answer, I want to update that the answers provided were not satisfactory. No one came out and explicitly said this is your problem, do this and you will have a resolution. Mere suggestions are not sufficient to merit a bounty award. Lastly, the problem was with server settings and after doing some research on server sessions and looking at Stackoverflow/Serverfault I was able to determine how to best resolve this problem. Therefore, I did not feel it was unjust to mark my own answer as the correct one.
I have a php based authentication system which relies on LDAP to verify identity and uses sessions to maintain users authenticated status.
Lately I noticed that it appears to be pushing me back to the login page like my session expired. The problem is that it does not appear to be for any specific reason that I have noticed and I am not sure how to debug/test something like this.
Here is my authentication function which starts the session:
function authenticateUser($user, $password){
//assuming ldap connection and verification of user login/pass
//this is what will happen with authenticate user which is called
//when user submits login/pass on authentication form.
$_SESSION['id'] = $uID;
$time = time();
$_SESSION['time'] = $time;
$_SESSION['lastActivity'] = $time;
$_SESSION['expiration'] = $time+$cookieExpiration;
$_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['secret'] = md5(rand());
$_SESSION['userHash'] = getSessionHash();
$_SESSION['firstLogin'] = isFirstLogin($user);
//assign cookie to user and log authentication
giveCookie("userHash", $_SESSION['userHash'],0);
logAuthenticationAttempt($user, $_SERVER['REMOTE_ADDR'], 1);
return true;
}//end authenticateUser
Give cookie function:
function giveCookie($name, $value, $expiration=0){
global $path, $site;
setcookie("userHash", $_SESSION['userHash'], $expiration, $path, $site, true, true);
}//end giveCookie
Here is my function which is called on each page to verify the user is authenticated before allowing them to proceed with action requiring authenticated status:
function isValidUser(){
global $links; global $userName; global $userID; global $cookieExpiration;
if(isset($_COOKIE['userHash']) and isset($_SESSION['userHash'])){
if($_COOKIE['userHash'] == $_SESSION['userHash']){
$userName = $_SESSION['nameN'];
$userID = $_SESSION['id'];
//update userHash cookie for additinoal expiration time this way session
$time = time();
$expiration = $time+$cookieExpiration;
$_SESSION['lastActivity'] = $time;
giveCookie("userHash", $_SESSION['userHash'],0);
$_SESSION['expiration'] = $expiration;
return true;
}
}
return false;
}//end isvalidUser()
Any advice or feedback on how to test this would be appreciated. I am looking to figure out why occasionally after performing some action I get pushed back to the login page.
On a page which request authentication what I do at the top is the following:
if(!isValidUser()){changePage($links['login']."?refer=".$links['requestHelp']);}
//note: changePage is just a function for header("location: somepage.php");
You seem to be confusing authentication, authorization and session management. If you want to test all 3 then you'll need some sort of automated test tool capable of scriptable, stateful HTTP session replay (e.g. http::recorder / www::mechaninze with Perl).
OTOH if you want to investigate the session management using your deployed application, then I'd recommend instrumenting the login page to capture information about the current session and how the user got routed there. You should also consider logging the session cookie on the webserver.
Not sure what testing software you use at the moment, but I'd strongly recommend Selenium. It allows you to run scripted tests through the browser, effectively simulating what an end user would do and see.
Write a functional test. You can use SimpleTest's WebTestCase for stuff like this. See the documentation at: http://www.simpletest.org/en/web_tester_documentation.html
Of course, you could also try to break the code down into smaller bits that can easier be tested individually. Right now, your authentication system is tightly coupled to the server state (eg. the session management). You could decouple the two and thus be able to test the authentication system in a unit test, rather than a functional test.
The server is probably overwriting their session cookie, which will change the session hash and then it won't equal the cookie they have clientside. You appear to be overthinking this. You don't need to set a cookie on their system to verify them. The $_SESSION var will handle it all for you.
If they pass the challenge, then they have a $_SESSION var that is set that gives them auth levels.
Don't pass $_SESSION off to other vars like you are. Don't go $username = $_SESSION['username'] because now you have a var that is nonsecure ($username) that could have secured data in it. But it might not.
Whenever you are displaying session info, make sure it came from the horse's mouth.
Take a deep look at session.configuration
i would (if your not willing to think over your concept) change the isValidUser to log what ever you can get before return false
function isValidUser(){
global $cookieExpiration; // since $links isn't used and $userName and $userId come from $_SESSION no need for global there
if( (isset($_COOKIE['userHash']) and isset($_SESSION['userHash']))
and ($_COOKIE['userHash'] == $_SESSION['userHash']) ){
$userName = $_SESSION['nameN']; // why these lines?
$userID = $_SESSION['id']; // see above
//update userHash cookie for additinoal expiration time this way session
$time = time();
$expiration = $time+$cookieExpiration;
$_SESSION['lastActivity'] = $time;
giveCookie("userHash", $_SESSION['userHash'],0);
$_SESSION['expiration'] = $expiration;
return true;
}
// $logger ist just an example an could be a p.e Zend_Logger Object
$logger->debug($_SESSION); // serialize if needed
$logger->debug($_COOKIE); // serialize if needed
$logger->err(error_get_last());
return false;
}//end isvalidUser()
And are you sure you called session_start() before isValidUser()
It appears that this was a simple misconfiguration of the server itself. Being that this server environment is a shared environment for hundreds of sites, I do not have ability to modify server wide settings in php.ini and the like.
What I was able to do though is...
session_set_cookie_params(time()+$expiration, $path, $domain, true, true);
This has resolved the issue, it appears before the session expiration was not set properly and this will set it accordingly for this specific application.

Why won't my cookie value change in PHP 5?

I have a website where the login info is optionally saved in a cookie (remember me checkbox at login) and when the user logs out, the value of the authentication cookie won't change to expire the cookie allowing logout.
The system does work correctly in both the dev and staging servers but for some reason will not work on our production server. We are running PHP 5 and Apache on all the servers.
Thanks.
Function to set cookie (minor edits for security):
function setCookieInfo($data,$expiry=0)
{
if($data === false)
{
//remove cookie!
$cookie = false;
$expiry = 100; //should be in the past enough!
}
else
{
$serial = base64_encode(serialize($data));
$hash = md5($XXX);
$cookie = $hash."---".$serial;
}
if($_SERVER['SERVER_NAME']=='localhost')
{
$domain = null;
}
else
{
$domain = '.'.$_SERVER['SERVER_NAME'];
}
return setcookie('Auth', $cookie, $expiry, $this->controller->base, $domain);
}
Posting some actual code might help, but I'll hazard a guess that it has something to do with the cookie domain being used.
Grab a traffic capture (e.g. www.fiddler2.com) of the SetCookie call that is intended to delete the cookie, and ensure that the Domain is valid and the expiration time/value is as expected.
Assuming you are using the PHP setcookie() function, make sure that the domain and path for the cookie are set correctly. Check PHP's documentation for the function for more information.
I might be able to tell you for sure if I had a little more info. Can you provide any more information without compromising too much about the project? How about the URLs of the dev, staging, and production servers, or at least examples of what they might be like?
Edit
Based upon the info you provided in your comment, I would recommend that you try using HTTP_HOST instead of SERVER_NAME. SERVER_NAME might be giving you a weird value depending upon your virtual server setup. Your path might not be quite right either - try a '/' and it should be available regardless of the subdirectory the user is in.
Also,
$this->controller->base
makes me think that you might be using CodeIgniter or Kohana. If so, you might consider using their cookie helpers.

Categories