I am trying to set a cookie on every page load. I did some research and found that event subscribers are the way to go.
I created a custom module with event. It starts the event on every page load but the problem is with the cookies.
The $event object has property called response but it is always null.
Therefore i cannot set any cookies.
class LanguageCookieSubscriber implements EventSubscriberInterface
{
protected $event;
protected $cookieValue;
public function init(GetResponseEvent $event) {
$this->event = $event;
$cookie = new Cookie("client_language_cookie", $this->cookieValue, 0, '/', NULL, FALSE);
$this->event->getResponse()->headers->setCookie($cookie);
}
}
I also tried to set the response object. Then I can set the cookie but the page will come blank.
$response = new Response();
$this->event->setResponse($response);
$cookie = new Cookie("client_language_cookie", $this->cookieValue, 0, '/', NULL, FALSE);
$this->event->getResponse()->headers->setCookie($cookie);
Any ideas how can i solve this? I need to display the page user has requested and only set cookie.
Thanks in advance.
Example:
public function onKernelResponse(ResponseEvent $event) {
$response = $event->getResponse();
$cookie = new Cookie('cookie name', 'my_cookie value', time() + 60 * 60 * 24 * 7);
$response->headers->setCookie($cookie);
$event->setResponse($response);
}
I can't understand why my cookie isn't sent.
I've check all the thread about it and it seems that I'm doing it right.
I can't see the cookies in the Symfony debug, but not on my browser.
public function indexAction(Request $request)
{
$response = new Response();
$userID = $request->cookies->get('myCookie123');
if (empty($userID)) {
$uniqueID = $this->generateIDUtil();
$response->headers->setCookie(new Cookie('myCookie123', $uniqueID, 2147483647));
$response->sendHeaders();
}else{
var_dump('USER ALREADY KNOW <br>' );
}
var_dump($response->headers->getCookies()); //GIVES CORRECT COOKIE OBJECT
var_dump('<br>');
var_dump($request->cookies->all()); //GIVES ONLY PHPSESSID, BUT NOT THE ONE CREATED
var_dump('<br>');
var_dump($request->cookies->get('myCookie123')); //GIVES NULL
return $response->setContent($this->render('MyBundle:Core:index.html.twig'));
}
So here a working piece of code for anyone that want to get a userId from a cookie. With all the use statement and the twig rendering template.
The problem with the solution above is that it will give you a blank page as you send the header without rendering the view.
As it's really badly documented, here is a working solution.
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class tempController extends Controller
{
public function indexAction(Request $request)
{
$user = $request->cookies->get('myCookie'); // $user is a string (the userID) or null if there is no cookie.
if (!empty($user)) {
//Fetch user data in the DB
}
// some code ...
$response = new Response();
if ($user instanceof User) {
// do some stuff like pre fill a form
}else{
// We don't know the user we send a cookie.
$cookie = new Cookie('myCookie', $this->generateIDUtil(), time() + (365 * 24 * 60 * 60)); // Expires 1 years
$response->headers->setCookie($cookie);
$response->sendHeaders();
}
//Render the view WITH the response (It's very important to put $response as 3rd parameter)
return $this->render('MyBundle:Core:index.html.twig', array(/* view param */), $response);
}
}
Here is how you properly create a cookie and send as a Response to a client:
$res = new Response();
$cookie = new Cookie(
'my_cookie',
$student->getStuId(),
time() + ( 2 * 365 * 24 * 60 * 60) // Expires 2 years.
);
$res->headers->setCookie( $cookie );
$res->send();
I use it all the time, so please let us know if you still have problems.
I've been using Slim Framework 2 for a while but want to switch to the newest version 3. When reading the upgrade guide, I was a bit bummed about them simply stating that "cookies has been removed from the core" and referring to the FIG Cookies github repo that contains code snippets that simply don't work with Slim.
Could anyone share some working code snippets that set and get some dummy cookies using Slim 3? Thanks.
If you don't want to use the tested PSR-7 library FIG Cookies you can use this:
namespace Your\App;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class Cookie
{
/**
* #param Response $response
* #param string $key
* #param string $value
* #return Response
*/
public function deleteCookie(Response $response, $key)
{
$cookie = urlencode($key).'='.
urlencode('deleted').'; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; secure; httponly';
$response = $response->withAddedHeader('Set-Cookie', $cookie);
return $response;
}
/**
* #param Response $response
* #param string $cookieName
* #param string $cookieValue
* #return Response
*/
public function addCookie(Response $response, $cookieName, $cookieValue)
{
$expirationMinutes = 10;
$expiry = new \DateTimeImmutable('now + '.$expirationMinutes.'minutes');
$cookie = urlencode($cookieName).'='.
urlencode($cookieValue).'; expires='.$expiry->format(\DateTime::COOKIE).'; Max-Age=' .
$expirationMinutes * 60 . '; path=/; secure; httponly';
$response = $response->withAddedHeader('Set-Cookie', $cookie);
return $response;
}
/**
* #param Request $request
* #param string $cookieName
* #return string
*/
public function getCookieValue(Request $request, $cookieName)
{
$cookies = $request->getCookieParams();
return isset($cookies[$cookieName]) ? $cookies[$cookieName] : null;
}
}
Slim 3 has Cookies class. you are not forced to use external library for setting cookie:
$setcookies = new Slim\Http\Cookies();
$setcookies->set('auth',['value' => $jwt, 'expires' => time() + $expire, 'path' => '/','domain' => 'example.com','httponly' => true,'hostonly' => false,'secure' => true,'samesite' => 'lax']);
$setcookies->set('tracking', "$value");
$response = $response->withHeader('Set-Cookie', $setcookies->toHeaders());
And for getting cookie :
$jwt = $request->getCookieParam('auth');
I'was experiencing the same problem but, after a few tries, i figured out!
First you need to use :
$cookies = Dflydev\FigCookies\Cookies::fromRequest($request);
To get all the cookies sent by the client.
Or:
$cookie = FigRequestCookies::get($request, $cookiename);
To get a single cookie.
But the 'strange' part is how to set a cookie, so here's a little example:
function setCookie($response, $name, $value){
$response = FigResponseCookies::set($response, SetCookie::create($name)
->withValue($value)
->rememberForever()
);
return $response;
}
With :
$response = FigResponseCookies::set($response, SetCookie::create($name)
->withValue($value)
->rememberForever()
);
You'll add a new cookie to the request, this method returns a new request object with the new cookie in it.
So for all the other operations, you need to use the new request not the old one.
I hope this will help.
if you want post your code and we'll try to debug it.
I know I was asked to answer for cookies on slim 3, but since I could not find anywhere how to do this on slim 4, I was telling how to do it in case it could be useful to someone else.
If you are using Slim 4 with slim/psr7 you can set cookies from inside a middleware or a router, in this way:
To SET a cookie (put a cookie on a browser):
$cookies = new \Slim\Psr7\Cookies();
$cookies->setDefaults(['hostonly' => true, 'secure' => true, 'httponly' => true, 'samesite' => 'Lax']);
$cookies->set('MyCookieName', ['value' => '', 'samesite' => 'Strict']); // this way I can ovveride the samesite attribute for this cookie only
$response=$response->withHeader('Set-Cookie', $cookies->toHeaders());
unset($cookies);
To unset a cookie (delete a cookie from a browser)
$cookies = new \Slim\Psr7\Cookies();
$cookies->setDefaults(['hostonly' => true, 'secure' => true, 'httponly' => true, 'samesite' => 'Lax']);
$cookies->set('MyCookieName', ['value' => '', 'expires' => 1); // this way I can delete this cookie, setting it already expired the first sec in 1970
$response=$response->withHeader('Set-Cookie', $cookies->toHeaders());
unset($cookies);
To get the cookie (get the cookie sent from the browser)
$cookies = new \Slim\Psr7\Cookies($request->getCookieParams());
echo "cookie value is: " . $cookies->get('MyCookieName');
The easiest way I found to do this is as follows.
use Dflydev\FigCookies\SetCookie;
use Dflydev\FigCookies\FigResponseCookies;
$app->post('/login', function ($request, $response, $args) {
// Here you may check request data
$token = '123'; // Here you may use something like JWT::encode
return $this->response = FigResponseCookies::set($response, SetCookie::create('token')
->withValue($token)
->withDomain($_SERVER['HTTP_HOST'])
->withPath('/')
)->withJson([
'description' => 'Here goes your Json Body'
]);
});
Install vendor solution:
composer require sunrise/http-header-kit
Set the session cookie:
use Sunrise\Http\Header\HeaderSetCookie;
$header = new HeaderSetCookie('name', 'value', new \DateTime('+1 day'), [
'path' => '/',
'secure' => true,
'httponly' => true,
]);
$response = $header->addToMessage($response);
See the source code to learn more:
HTTP Header Kit for PHP 7.2+ based on PSR-7
I would recommend NOT using dflydev/dflydev-fig-cookies. It's broken and the documentation is either wrong or missing.
Based on LUXS's and Norman's answers, here's a working example with comments, for Slim 3:
/**
* Fig-cookies.
*
* Mind the required classes; mind the fact that (because PSR-7) this sets the
* cookie by modifying the response before returning it.
*
* Kudos to https://stackoverflow.com/a/55288070/1717535 and
* https://stackoverflow.com/a/42065030/1717535 for providing working examples.
*
* Memo about cookines in general:
* - if you don't set an expire date, it'll be a session cookie.
* - dot or no dot before the domain?
* - if no domain is specified, the cookie will be set without a dot.
* - if a domain is specified, it'll be the dotted version.
* - if both are set, seems the one set more recently will be used on read.
* - Seems the dotted/sub-domains version comes recommended.
* - But it forces to turn https://example.org into example.org, for all
* of local dev, ngrok, production, for no obvious benefit. So screw it.
* - Reconsider the day we'll use subdomains.
* - See https://stackoverflow.com/a/39708227/1717535
*
* Can use `->withDomain` to set the domain, without URL scheme and without
* trailing slash. e.g.: `->withDomain('clickandspeak.localhost')`
*/
use Dflydev\FigCookies\FigResponseCookies;
use Dflydev\FigCookies\SetCookie;
use Dflydev\FigCookies\FigRequestCookies;
$app->get('/tests/fig-cookies/set/', function ($request, $response, $args) {
$response = FigResponseCookies::set(
$response,
SetCookie::create('foo')
->withValue('bar')
->rememberForever()
->withPath('/')
);
// Do whatever else you need to do in your route…
// Then return the response.
return $response;
});
$app->get('/tests/fig-cookies/get/', function ($request, $response, $args) {
$cookie = FigRequestCookies::get($request, 'foo');
// but this is long and ugly and I would recommend Slim's (undocumented) built-in function instead:
// $request->getCookieParam('foo')
echo $cookie->getValue();
});
As for deleting/removing a cookie… Well:
$app->get('/tests/fig-cookies/delete/', function ($request, $response, $args) {
// $request = FigRequestCookies::remove($request, 'foo');
// $response = FigResponseCookies::expire($response, 'foo');
// Works. The cookie gets deleted.
// $response = FigResponseCookies::set(
// $response,
// SetCookie::create('foo')
// ->withExpires(new DateTime('-5 years'))
// ->withPath('/') // MUST use the same path as that used when creating the cookie.
// );
/**
* This is the example given in the README. But it does NOT work.
* It won't work because the path is missing; there's no option to set it!
* See https://github.com/dflydev/dflydev-fig-cookies/issues/23
*/
// $response = FigResponseCookies::expire($response, 'foo');
return $response;
});
I don't know if it will help anyone 4 years later but...
You can use the FIG Cookies library, turning it into a class with static functions. Like this:
namespace YourApp\Cookies;
use Dflydev\FigCookies\FigResponseCookies;
use Dflydev\FigCookies\SetCookie;
use Dflydev\FigCookies\FigRequestCookies;
use Dflydev\FigCookies\Modifier\SameSite;
use Carbon\Carbon; // I used Carbon as well
class Cookie
{
static function get(&$req, $key, $default = null)
{
$cookie = FigRequestCookies::get($req, $key, $default);
if (!$cookie->getValue()) {
return null;
}
return $cookie->getValue();
}
static function set(&$res, $key, $val, $expire_val, $expire_unit)
{
$now = Carbon::now();
$offset = Carbon::now()->add($expire_val, $expire_unit);
$res = FigResponseCookies::set($res, SetCookie::create($key)
->withValue($val)
->withExpires($offset->toCookieString())
->withMaxAge($offset->diffInSeconds($now))
->withPath('/')
->withDomain('appdomain.com')
->withSecure(false)
->withHttpOnly(true)
->withSameSite(SameSite::lax())
// You can learn more about the available options on the official GitHub page
);
return $res;
}
static function remove(&$res, $key)
{
$offset = Carbon::now()->sub(10, 'years');
$res = FigResponseCookies::set($res, SetCookie::create($key)
->withExpires($offset->toCookieString())
->withMaxAge(0)
->withPath('/')
->withDomain('appdomain.com')
);
return $res;
}
}
This way, it becomes really easy to deal with cookies.
You can use it like this:
use YourApp\Cookies\Cookie;
Cookie::set($response, 'name', 'value', 1, 'month') // To create a cookie
Cookie::get($request, 'name') // To get the value of a cookie
Cookie::remove($response, 'name') // To remove it
Or, if you prefer, like this:
\YourApp\Cookies\Cookie::set($response, 'name', 'value', 1, 'month')
\YourApp\Cookies\Cookie::get($request, 'name')
\YourApp\Cookies\Cookie::remove($response, 'name')
That's the way I use it.
I can't seem to get cookies set from my controller.
code:
/**
* #Route("", name="wx_exchange_default_index")
* #Template("WXExchangeBundle:Default:index.html.twig")
* #Method({"GET"})
*/
public function indexAction(Request $request)
{
$returnArray['parents'] = self::getCategories();
$cookieLocationSession = $request->cookies->get('locationidsession', 0);
$cookieLocation = $request->cookies->get('locationid', 0);
$securityContext = $this->container->get('security.context');
$hashids = $this->get("wxexchange_hashids_service");
if ($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED'))
{
$user = $securityContext->getToken()->getUser();
$returnArray['user'] = $user;
$location = $user->getTblProfile()->getTblLocation();
if(!$cookieLocation || $cookieLocation != $hashids->encrypt($location->getId()))
{
$cookieLocation = $hashids->encrypt($location->getId());
//TODO: cookies are not being set figure out whys
$response = new Response();
$response->headers->setCookie(new Cookie("locationid", $cookieLocation, 365, '/', null, false, false));
$response->sendHeaders();
}
}
if (!$cookieLocation && !$cookieLocationSession)
{
return $returnArray;
}
if ($cookieLocationSession)
{
$cookieLocation = $cookieLocationSession;
}
if (!isset($location) || $cookieLocationSession)
{
$locationService = $this->get("wxexchange_location_service");
$locationId = $hashids->decrypt($cookieLocation);
if(count($locationId) >= 1)
$location = $locationService->getLocationById($locationId[0]);
}
if(isset($location))
return $this->redirect($this->generateUrl('wx_exchange_location', array('slug' => $location->getSlug(), 'locationid' => $cookieLocation)));
return $returnArray;
}
Do I have to return the response? If I do how do I keep processing (I have a redirect further down in my code)?
Edit: Interestingly enough if the same cookie is already set (via JQuery) running the code above deletes it, but it won't set it.
Edit: Action code posted.
The cookie object has httpOnly set to true by default, http://api.symfony.com/2.0/Symfony/Component/HttpFoundation/Cookie.html
This means that the browser should not make the cookie visible to client-side scripts. If you need to see the cookie in your scripts you can pass the 7th parameter as false when you create the cookie.
$response->headers->setCookie(new Cookie('foo', 'bar',time() + 60, '/', null, false, false));
If you just need to view the cookie for debugging purposes you can use Chrome Dev tools. They are available under the 'Resources' tab.
Edit : Try $response->sendHeaders();
Oops, Sorry everyone.
It's my error.
In my javascript I'm using a Jquery cookie plugin and when you set a new cookie you tell it the number of days before expiry:
$.cookie('locationid', value, { expires: 365, path: '/' });
Unfortunately I used a part of this syntax in my controller:
$cookie = new Cookie("locationid", $cookieLocation, 365, '/', null, false, false);
The problem is the third parameter is supposed to be a DateTime so while I thought I was telling it to expire in 365 days I probably created a cookie that expired almost instantly after creation.
Thanks for all the answers and time spent on your part, this is why I love SO.
I would like to dynamically set the session expiration time in Codeigniter. I'm autoload the session class. I have a view that contains checkbox for users to click (remember me). Right now if they click the check box or not the expiration time stays the same :/
// Config.php
$config['sess_expiration'] = 7200;
// Controller
if ($this->input->post('remember_me') == 'TRUE')
{
$this->session->remember_me();
}
$newdata = array(
'failed_login' => 0,
'user_name' => $this->input->post('user_name'),
'logged_in' => TRUE
);
$this->session->set_userdata($newdata);
// MY_Session.php
class MY_Session extends CI_Session {
function remember_me()
{
$this->sess_expiration = 172800;
}
}
If you need to implement "Remember me" feature - then you've started it in a wrong way.
You need to create one more database table with fields user_id | token.
Then, after user has been logged in (with "remember me" checkbox checked on) - generate random token and insert a new row with current user_id and that token. Also - set remember cookie with the same token value.
Now, if user enters your site, not authenticated and has some token - you can always find that token and authenticate user (each token is unique and strognly related to specific user_id).
Here is my solution I've been playing with.
You can edit the function inside domain.com/system/libraries/Session.php
function _set_cookie($cookie_data = NULL)
Comment out
// $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
Then Add
if(isset($this->userdata['rememberme'])){
// If they want to stay connected
if( $this->userdata['rememberme'] == 1) {
$expire = 0;
} else {
$expire = time() + $this->sess_expiration;
}
} else {
$expire = time() + $this->sess_expiration;
}
Please let me know if this helps in anyway or modify my code to help me out. Thank you.
$data = array(
'username' => $this->input->post('username'),
'ADMIN_is_logged_in' => true
);
$this->session->sess_expiration = '14400';// expires in 4 hours
$this->session->set_userdata($data);// set session