As the title suggests,
Here's the code...
public function index(Request $request, Application $app)
{
$cookies = $request->cookies;
print_r($request->cookies);
if(!$cookies->has("recordsPerPage"))
{
$response = new Response();
$cookie = new Cookie("recordsPerPage", $app['defaultRecordsPerPage']);
$response->headers->setCookie($cookie);
}
print_r($request->cookies);exit; //prints nothing here !!
}
I also tried to set it in a $app->after() but failed. do you have any other ways to set cookies other than in controller.
Thank you.
Cookies are set with response and available on next request. So you have to return the response with this cookie, and if you want it to be available on the request, make it a redirect response so the browser will set cookie and issue next request with this newly created cookie:
$cookies = $request->cookies;
if(!$cookies->has("recordsPerPage"))
{
$cookie = new Cookie("recordsPerPage", $app['defaultRecordsPerPage']);
$response = Response::create('', 302, array("Location" => "http://127.0.0.1/whatever/"));
$response->headers->setCookie($cookie);
return $response;
}else{
return print_r($cookies, 1);
}
Other possibility is to set this cookie directly in the request ($request->cookies->set('recordsPerPage', $app['defaultRecordsPerPage']);) but you still have to return response with this cookie to set it in the browser.
Related
I am integrating Laravel into a legacy php app. The login page used to directly post to verifyUser.php which also started a Symfony Session.
The new architecture now posts to a laravel api which makes a Guzzle post to verifyUser.php.
javascript:
$(document).ready(function(){
$('#signIn').submit(function(){
var a = $('#email').val();
$.post('/api/login', { //this used to post to verifyUser.php
Username: $('#email').val(),
Password: $('#password').val()
}, function(data){
if(data['credentials'] == true){
console.log('credentials true');
console.log(data['uri']);
window.location.href=data['uri'];
} else {
$('#errMsg').html(data['errMsg']);
$('.alert').show();
}
}, 'json');
return false;
});
controller functions:
public function authenticate(Request $request) //aka api/login endpoint
{
//...
$legacyRes = $this->authenticateLegacy($request);
//...
}
private function authenticateLegacy(Request $request)
{
$response = null;
try {
$response = $this->client->post('/admin/verifyUser.php', [
'form_params' => ['Username' => $request->get('Username'),
'Password' => $request->get('Password')]
]);
}
catch(Exception $exception){
Log::error('Errrererererer', [$exception->getMessage()]);
}
$body = (string)$response->getBody();
Log::info('BODY:', [$body]);
return $body;
}
I have left out verifyUser.php because I have tested it and it returns the expected results.
When using the browser, the session information doesn't seem to get set. But according to my post responses, everything should be working.
Is this because I am routing the request through guzzle?
Posting under my answer to show updated code:
private function authenticateLegacy(Request $request)
{
//...
//parse cookie id from guzzle response
$body = (string)$response->getBody();
$cookie = $response->getHeader('Set-Cookie'); //PHPSESSID=SOMEID; path=/
$cookieBite = explode(';', $cookie)[0]; ////PHPSESSID=SOMEID
$cookieId = explode('=', $cookieBite)[1];
$data = json_decode($body, true);
$data['session'] = $cookieId;
return $data;
}
In the action:
public function authenticate(Request $request)
{
//...
$legacyRes = $this->authenticateLegacy($request);
//...
// this will have the session id in the body but will also
// set the cookie for the client so I don't have
// to set document.cookie w/ js
return response($legacyRes, 200)
->withCookie('PHPSESSID', $legacyRes['session']);
}
I assume your legacy endpoint uses cookies to identify a user's session.
A successfull request to the legacy endpoint returns a Set-Cookie header.
Guzzle doesn't forward this Set-Cookie header from the API response to the browser - you'll have to program this behaviour into the "wrapping" application.
You will need to tell guzzle to explicitly pass the corresponding Cookie header to the legacy api (to maintain the user's login state) when sending any further requests.
In order to achieve this you'll need to save this cookie within your new application (i.e. in the user's session or in database) and then pass it within a Cookie header along with all further requests you make to the legacy API.
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 have minor security in place to not allow users to download MP3s off my site. Ajax sends a request for a token which is a one time download, this token is attached to the URL I feed into soundmanager2. This security works fine except in Safari.
Front End Request
streamSong: function(song)
{
$.ajax({
url: '/streamsong/'+song.id,
type: 'get',
success: function(token) {
var stream = '/streamsong/'+song.id+'/'+token;
Player.sendSongToPlayer(song, stream);
}
});
}
Route
Route::get('/streamsong/{id}/{token?}', 'StreamController#setupStream');
Controller
class StreamController extends Controller {
public function setupStream($id, $token = null)
{
$stream = new Stream();
if ($token == null) {
if (Request::ajax()) {
$sessionToken = $stream->setToken(str_random(40));
return response($sessionToken);
} else {
return 'no way jose';
}
}
if ($token == $stream->getToken() ) {
return($stream->sendStream($id));
}
}
}
Stream class
public function setToken($token)
{
Session::flash('songToken', $token);
return($token);
}
public function getToken()
{
$token = Session::get('songToken');
return($token);
}
public function sendStream($id)
{
$post = Post::find($id);
$pathToFile = base_path().'/storage/app/mp3/'.$post->song_path;
$fileSize = filesize($pathToFile);
$name = $post->song_path;
$headers = array(
'Content-Type'=>'audio/mpeg',
'Pragma'=>'public',
'Content-Transfer-Encoding' => 'binary',
'Expires'=> 0,
'Cache-Control'=> 'must-revalidate, post-check=0, pre-check=0',
'Filename'=>$name,
'Content-Length'=>$fileSize,
'Connection'=> 'keep-alive'
);
return response()->download($pathToFile, $name, $headers);
}
The only conclusion I've come to is that Safari makes more than one request for the file download so the token is being destroyed on the first attempt. However I only see one GET request in the timeline console. If I set the Session::flash to Session::set it works fine in Safari but this bypasses the security measures. Even with Session::set I can't remove the session token variable until after the response to download has been sent out, which seems very strange.
Has anyone else experience behavior like this in Safari? I'm pretty stumped on this.
Can you check if the browser does an OPTIONS request before it does the actual request? Sometimes this request is performed to check the capabilities of a service.
Session might also not be your best option here, you could create a JWT that hold all the information you need in its payload to stream a song once. It's easy and solid.
I have written this code, that sets a cookie in client's browser, and after that must redirect the client to 'home' route,
$response = new Response();
$response->withCookie(cookie()->forever('language', $language));
$response->header('Location' , url('/home')) ;
return $response ;
the client receives these headers but the client doesn't make request for the "home" route
how should I do both, setting the cookie and redirect the user?
Why don't you do return Redirect::to('home');
Of course you can use chaining to do more things, both in L4 and L5.
L4: return Redirect::to('home')->withCookie($cookie);
L5: return redirect('home')->withCookie($cookie);
just use the javascript method of redirecting
<script>window.location = "home";
and add it to your
$response = new Response('')
like this
$response = new Response('<script> window.location = "home";</script>'); $response->withCookie(cookie()->forever('language', $language)); return $response;
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.