How can I use cookies in a Joomla component?
setcookie( JUtility::getHash('JLOGIN_REMEMBER'), false, time() - 86400, '/' );
Can anybody describe how this works?
// Get input cookie object
$inputCookie = JFactory::getApplication()->input->cookie;
// Get cookie data
$value = $inputCookie->get($name = 'myCookie', $defaultValue = null);
// Check that cookie exists
$cookieExists = ($value !== null);
// Set cookie data
$inputCookie->set($name = 'myCookie', $value = '123', $expire = 0);
// Remove cookie
$inputCookie->set('myCookie', null, time() - 1);
Some rules about $expire value
its a Unix tinestamp in seconds, like return value of time().
$expire == 0: cookie lifetime is of browser session.
$expire < time(): cookie is being deleted (expire set to past).
You could remove cookie by setting it's value to null, but apparently IE fails to do so.
Notes
Keep in mind that cookies should be set before headers are sent (usually before output is echoed).
Cookie key and value should be properly escaped
Non-string values
When serializing the value on set (like json_encode($dataNode)), remember to use proper filter to retrieve it later on. Default is cmd, which filters out pretty much anything but a-Z, 0-9 and cracks JSON structure.
// Get cookie data
$encodedString = $inputCookie->get('myCookie', null, $filter = 'string');
// Decode
$values = json_decode($encodedString);
// Encode and Set
$inputCookie->set('myCookie', json_encode($values));
Rererences
Joomla CMS github repository: JInputCookie::set (very well documented)
php docs: php.net/setcookie (developer experiences)
Wikipedia: HTTP Cookies (theory)
Related
I am binding a cookie with a post request using the code
#CookieValue(value = "foo", defaultValue = "hello") String fooCookie .
Is this code in the controller along with get/post enough for setting a default cookie with name as "foo", and value as "hello"?
I want to see the cookie in the response sent back by the server through postman and postman intercepter. I am using the test script
var myval = postman.getresponseCookie("foo").value;
postman.setGlobalVariable("foo",myval.value);
or
tests['cookiesets'] = postman.getResponseCookie("name").value; .
I am beginner, hence please correct me if I am wrong.
Below should work in Postman Test and should print cookie value in Tests tab of response.
var cookieValue = postman.getResponseCookie("foo").value;
tests["cookie-value = " + cookieValue] = true;
And if you want to verify returned cookie value then use something like
tests["cookie-value-correct"] = cookieValue === "hello";
I'm using Hybridauth social login, and upon a user authenticating with Facebook, I receive the following error:
Warning: array_key_exists() [function.array-key-exists]: The second
argument should be either an array or an object in
/hybridauth/Hybrid/thirdparty/Facebook/base_facebook.php on line 1328
My guess (probably wrong) to why this may be happening is because the parameters used to pass to Hybridauth come from the browser URL, and I have two - page=register & connected_with=facebook. Hybridauth only requires the second one...
It actually authenticates, but I want rid of this error. Why does this warning occur? Is there a way to hide it?
This is the bit that errors:
/**
* Get the base domain used for the cookie.
*/
protected function getBaseDomain() {
// The base domain is stored in the metadata cookie
// if not we fallback to the current hostname
$metadata = $this->getMetadataCookie();
if (array_key_exists('base_domain', $metadata) &&
!empty($metadata['base_domain'])) {
return trim($metadata['base_domain'], '.');
}
return $this->getHttpHost();
}
It's this code the warning comes from:
/**
* Destroy the current session
*/
public function destroySession() {
$this->accessToken = null;
$this->signedRequest = null;
$this->user = null;
$this->clearAllPersistentData();
// JavaScript sets a cookie that will be used in getSignedRequest
// that we need to clear if we can
$cookie_name = $this->getSignedRequestCookieName();
if (array_key_exists($cookie_name, $_COOKIE)) {
unset($_COOKIE[$cookie_name]);
if (!headers_sent()) {
$base_domain = $this->getBaseDomain();
setcookie($cookie_name, '', 1, '/', '.'.$base_domain);
} else {
// #codeCoverageIgnoreStart
self::errorLog(
'There exists a cookie that we wanted to clear that we couldn\'t '.
'clear because headers was already sent. Make sure to do the first '.
'API call before outputting anything.'
);
// #codeCoverageIgnoreEnd
}
}
}
It looks like getMetadataCookie() does not always return an array, possibly because the cookie has not yet been set. You may want to check that it's actually an array before using it as such;
if (is_array($metadata) && array_key_exists('base_domain', $metadata) &&
For the added code, the same would apply to array_key_exists() in the new code. If you're unsure if it's actually set to an array if the cookie is not set, check first.
I am implementing Anti-Forgery framework as described here:
http://weblogs.asp.net/srkirkland/archive/2010/04/14/guarding-against-csrf-attacks-in-asp-net-mvc2.aspx
Plus, to minimize the coding effort, I did the token insertion part at client side handling form.onsumit and ajaxsend events. Everything works fine – until the session expires.
In my application, I display a popup when the user session gets timed out where the user can re-login and continue without refreshing the current page so that the work-in-progress will be safe. But this doesn't go well with the Anti-CSRF logic. When the user tries to re-login after a timed-out session, this throws a CSRF exception as the cookie (__RequestVerificationToken_Lw__) is already expired and all the future POSTs will be invalid until next page refresh.
Is there any way to set the cookie end time to a future date rather than 'session'? I tried to edit Response.Cookie but that made the cookie invalid.
Any help would be appreciated.
Thanks
At the time of user session out (when displaying a popup) is it possible for you to set the httpcookie with expiry in server side.
I have extracted some code from the microsofts antiforgery token implementation.
internal static string GetAntiForgeryTokenName(string appPath)
{
if (string.IsNullOrEmpty(appPath))
{
return "__RequestVerificationToken";
}
return "__RequestVerificationToken_" + Base64EncodeForCookieName(appPath);
}
private static string Base64EncodeForCookieName(string s)
{
byte[] bytes = Encoding.UTF8.GetBytes(s);
string text = Convert.ToBase64String(bytes);
return text.Replace('+', '.').Replace('/', '-').Replace('=', '_');
}
Below code which set the cookie in server side.
string antiForgeryTokenName = GetAntiForgeryTokenName(HttpContext.Request.ApplicationPath);
HttpCookie httpCookie = HttpContext.Request.Cookies[antiForgeryTokenName];
HttpCookie httpCookie2 = new HttpCookie(antiForgeryTokenName, httpCookie.Value)
{
HttpOnly = true
//// your domain Domain = ,
//// path Path = ,
//// set path Expires =
};
HttpContext.Response.Cookies.Set(httpCookie2);
Please note that I haven't tested this code, just give a try if you dont have any other options.
I have an app using Struts2 jsp and java..sessionid is created by container.I want to create my own session id and set to that particular session...just want to overwrite.I have aslo created a filter. session id.any clue
something like
session.setSessionId()
thanks..
You can do this using CookieInterceptor which can implement CookiesAware and then intercept the call to set your own sessionId.
Edit:
Just realized CookieInterceptor doesnt allow you to set a cookie, so I did something like this
In my execute method of my Action I did this:
public String execute() {
String jSessionId = null;
for (Cookie c : httpServletRequest.getCookies()) {
if (c.getName().equals("JSESSIONID"))
jSessionId = c.getValue();
}
System.out.println("Value Found In Request = " + jSessionId);
jSessionId = "TestingOverrideOfJSessionId";
Cookie myCookie = new Cookie("JSESSIONID", jSessionId);
myCookie.setMaxAge(60 * 60 * 24 * 365); // Make the cookie last a year
httpServletResponse.addCookie(myCookie);
return SUCCESS;
}
Result
EDIT
I tried debugging this with xdebug and netbeans. It's weird that the exports will work during the debug session if I put in some breakpoints. However, with no break points, a more realistic environment, the exports don't work.
I've tried adding sleeps into some parts of the code.
I think that maybe PHP is ending before the Redis commit is completed. Maybe the Redis connections are being done asynchronously, but I checked PRedis and the default is a synchronous connection.
I am working on a reporting tool.
Here is the basic issue.
We store a report into the session object but on later requests when we try to get to the report in the session object it's gone.
Here is a more detailed version.
I store a 'report' object into the session like so
$_SESSION['report_name_unixtimestamp'] = gzcompress( serialize( $reportObject ) );
The user sees the report in some table form and then if they want they can export it. The report could change so the idea behind storing it in the session like this is that when the user exports it to PDF, Excel, etc, they'll be getting a report identical to the one they are viewing.
The user clicks on an export button and on the PHP side it will go into the session, fetch the report via the key provided as a get parameter (uncompresses and unserializes it), create the export and send it to the user for download.
This has worked well up until the point that we tried to introduce the Redis caching server as a tool for better session management.
What happens now is the following:
The first time we run the report it will get stored into the cache and the export will work successfully.
We will run the report again, with the same user account in the same session. This changes the unixtimestamp and so there should be two entries in the $_SESSION. ( $_SESSION['report_name_oldertimetamp'] and $_SESSION['report_name_newertimestamp'] ). When we click on the export button again we get an error saying that the file doesn't exist ( because it hasn't been sent by the server ).
If we check the redis server for the newer version of the report it isn't there, but the old timestamp is still there.
Now, this worked with the file session management but not with Redis. we've tried the redis module for php as well as the pure php client Predis.
Does anyone have any ideas?
Here are a few more details :
Redis has NOT run out of memory. We've checked this many times.
We already know that to unserialize the report object in the session the report class has to be included already. ( remember, the first export works fine but anything after that fails )
If we check the php session object during the request that the report is running on, it WILL contain the newer report but it never makes it to Redis.
Below is the save handler that is being used with Predis.
The redis_session_init is the function I call right before session_start() so that it gets registered. I'm not sure how the redis_session_write function works though so maybe someone can help me with that.
<?php
namespace RedisSession
{
$redisTargetPrefix = "PHPREDIS_SESSION:";
$unpackItems = array( );
$redisServer = "tcp://cache.emcweb.com";
function redis_session_init( $unpack = null, $server = null, $prefix = null )
{
global $unpackItems, $redisServer, $redisTargetPrefix;
if( $unpack !== null )
{
$unpackItems = $unpack;
}
if( $server !== null )
{
$redisServer = $server;
}
if( $prefix !== null )
{
$redisTargetPrefix = $prefix;
}
session_set_save_handler( 'RedisSession\redis_session_open', 'RedisSession\redis_session_close', 'RedisSession\redis_session_read', 'RedisSession\redis_session_write', 'RedisSession\redis_session_destroy', 'RedisSession\redis_session_gc' );
}
function redis_session_read( $id )
{
global $redisServer, $redisTargetPrefix;
$redisConnection = new \Predis\Client( $redisServer );
return base64_decode( $redisConnection->get( $redisTargetPrefix . $id ) );
}
function redis_session_write( $id, $data )
{
global $unpackItems, $redisServer, $redisTargetPrefix;
$redisConnection = new \Predis\Client( $redisServer );
$ttl = ini_get( "session.gc_maxlifetime" );
$redisConnection->pipeline( function ($r) use (&$id, &$data, &$redisTargetPrefix, &$ttl, &$unpackItems)
{
$r->setex( $redisTargetPrefix . $id, $ttl, base64_encode( $data ) );
foreach( $unpackItems as $item )
{
$keyname = $redisTargetPrefix . $id . ":" . $item;
if( isset( $_SESSION[ $item ] ) )
{
$r->setex( $keyname, $ttl, $_SESSION[ $item ] );
}
else
{
$r->del( $keyname );
}
}
} );
}
function redis_session_destroy( $id )
{
global $redisServer, $redisTargetPrefix;
$redisConnection = new \Predis\Client( $redisServer );
$redisConnection->del( $redisTargetPrefix . $id );
$unpacked = $redisConnection->keys( $redisTargetPrefix . $id . ":*" );
foreach( $unpacked as $unp )
{
$redisConnection->del( $unp );
}
}
// These functions are all noops for various reasons... opening has no practical meaning in
// terms of non-shared Redis connections, the same for closing. Garbage collection is handled by
// Redis anyway.
function redis_session_open( $path, $name )
{
}
function redis_session_close()
{
}
function redis_session_gc( $age )
{
}
}
The issue was solved and it was much dumber than I thought.
The save handler doesn't implement locking in any way. On the report pages there are multiple requests being made to the server via ajax and the like. One of the ajax requests starts before the report gets saved to session space. Thus, it reads the session, then writes the session at the end.
Since the reports executes faster every time, the report would get cached to the session in Redis but would then be overwritten by the other script that had an older version of the sessien.
I had help from one of my co-workers. Ugh! This was a headache I'm glad to be over.