I'm using the following code to set, and then read a cookie in CakePHP.
public $components = array('Cookie');
public function beforeFilter(){
parent::beforeFilter();
$this->Cookie->name = 'saved_times';
$this->Cookie->time = '1 year';
$this->Cookie->domain = 'localhost';
$this->Cookie->path = '/';
$this->Cookie->httpOnly = false;
$this->Cookie->key = '+%)asG_~s*SAr&bSIq34$#11qe#s!#v!#*(XSL#$XOw!a232d#HKis~#^';
$this->Cookie->secure = false;
}
public function save_position($time){
if($this->Auth->user('id')){
//save to the database
return true;
}else{
//set browser cookie
$this->Cookie->write('time', $time);
echo "set", $this->Cookie->read('time');
}
}
public function read(){
echo $this->Cookie->read('time'), "test";
print_r($this->Cookie->read('time'));
}
The problem is that when I set the cookie I see, "set" and the cookie value echoed out, but when I visit /read/ I'm only seeing "test" and no cookie value. Also I'm using a cookie viewer in chrome, but I only see the CAKEPHP cookie for my domain not saved_times. I don't think the cookie is even being set, but I don't know why
It turns out cookies arent set until the View is rendered. I had no view for my save_position action, so an error page was showing, which didnt set the cookie. Once I added a save_position.ctp file everything worked okay.
Related
In CakePHP 3.8 the segment of my controller looks like this:
// ...
public function beforeFilter(Event $event)
{
// ...
$this->Cookie->configKey('guestCookie', [
'expires' => '+1 days',
'httpOnly' => true,
'encryption' => false
]);
if(!$this->Cookie->check('guestCookie')) {
$guestID = Text::uuid();
$this->Cookie->write('guestCookie', $guestID);
}
$this->guestCookie = $this->Cookie->read('guestCookie');
// ...
}
public function error()
{
// ...
$this->Cookie->delete('guestCookie');
// ...
}
// ...
How to write the same thing in CakePHP4 version? My problem relates to defining Cookies.
Cookie settings are described here:
https://book.cakephp.org/4/en/controllers/request-response.html#cookie-collections
, but unfortunately this didn't help me at all.
I tried to solve the problem on this way:
public function beforeFilter(EventInterface $event)
{
//...
if(!$this->cookies->has('guestCookie')) {
$cookie = (new Cookie('guestCookie'))->withValue(Text::uuid())->withExpiry(new \DateTime('+20 days'))->withPath('/')->withSecure(false)->withHttpOnly(true);
$this->cookies = new CookieCollection([$cookie]);
}
$this->guestCookie = $this->cookies->get('guestCookie')->getValue();
//...
}
In my case $ this->cookies->has('guestCookie') is always 'false'.
The cookie value is never stored in the browser.
Please help.
There's rarely a need to touch cookie collections, most of the times simple reading of cookie values from the request object, and writing cookies to the response object is all you need, so I would suggest that you stick with that until the actual need for collections comes up.
The docs could probably do a better job here at explaining when to use what.
Reading, writing, and deleting cookies
As shown in the linked docs, cookie values can be read via:
$this->request->getCookie($cookieName)
and written via:
$this->response = $this->response->withCookie($cookieObject)
It's important to reassign the response object (unless you directly return it from the controller), as it is immutable, meaning withCookie() will return a new response object instead of modifying the current one.
Deleting cookies can be done by responding with an expired cookie, using withExpiredCookie() instead of withCookie(), or obtaining the expired version of a cookie via $cookie->withExpired() and passing it to withCookie().
Configuring cookie defaults
If you wanted to, cookie defaults can be set via Cookie::setDefaults():
\Cake\Cookie\Cookie::setDefaults([
'expires' => new DateTime('+1 days'),
'http' => true,
]);
However this will apply application wide to all cookie instances being created after this point, so you'd likely use it rather rarely, and if you do, do so with care!
Porting from the Cookie component
With the new API, your code could be written like this, with $this->guestCookie holding the cookie value, either the newly generated one, or the one obtained from the cookie received by your application:
use Cake\Http\Cookie\Cookie;
// ...
public function beforeFilter(Event $event)
{
// ...
$guestID = $this->request->getCookie('guestCookie');
if(!$guestID) {
$guestID = Text::uuid();
$cookie = Cookie::create('guestCookie', $guestID, [
'expires' => new DateTime('+1 days'),
'http' => true,
]);
$this->response = $this->response->withCookie($cookie);
}
$this->guestCookie = $guestID;
// ...
}
public function error()
{
// ...
$cookie = new Cookie('guestCookie');
$this->response = $this->response->withExpiredCookie($cookie);
// ...
}
// ...
See also
Cookbook > Request & Response Objects > Request > Cookies
Cookbook > Request & Response Objects > Response > Setting Cookies
I am working on MVC core 2 and IdentityServer4, External user logged in successfully, the problem i'm facing is this function always return null in HomeController.
var info = await _signInManager.GetExternalLoginInfoAsync();
But its working in AccountController, when user login and redirected back to client from IdentityServer.
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
var info = await _signInManager.GetExternalLoginInfoAsync();
}
Any kind of help will be appreciated.
My issue was in SignInScheme. When I commented the line below in Startup and use defaults it started to work.
services.AddAuthentication().AddGoogle("Google", opt =>
{
//opt.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
...
}
It's all based on cookies so check that the cookie is being picked up correctly. I think be default it will set the path of the cookie and that may mean it is not sent to your AccountController because the path differs.
I am using cakephp 2.0.4 (Doing Changes in existing project)
My controller function is..
class PagesController extends AppController {
public function getlocations($string = ''){
$this->autoRender = false;
$aResult = array(0=>'Florida', 1=>'London');
echo json_encode($aResult);
}
}
And also I have try $this->autoLayout = $this->autoRender = false;
When I am calling this action directly in browser mysite/app/pages/getlocations it will give following error
View file "/home/mysite/public_html/testing/app/View/Pages/g.ctp" is missing.
Create a /View/Ajax/json.ctp view:
<?php
if(!empty($data)) echo json_encode($data);
Then in the action:
$this->set('data', array(0=>'Florida', 1=>'London'));
$this->layout = false;
$this->render('/Ajax/json');
You could also make it work following the Cake way.
First you have to add the following code to your routes file:
Router::parseExtensions('json');
Next, in the controller add the 'RequestHandler' to your components array and serialize your result in your getlocations function:
public $components = array('RequestHandler');
public function getlocations($string = ''){
$this->set('aResult', array(0=>'Florida', 1=>'London'));
$this->set('_serialize', 'aResult');
}
Finally, you can see the results in your browser mysite/app/pages/getlocations.json
Doing this way CakePHP will add the application/json headers automatically.
More info: http://book.cakephp.org/2.0/en/views/json-and-xml-views.html
This is driving me crazy. In my AppController, I have the following:
public function beforeFilter() {
$this->Cookie->name = 'MyCookie';
$this->Cookie->time = '1 year';
$this->Cookie->domain = 'http://mydomain.com';
$firstVisit = $this->Cookie->read('foo');
if ( empty($firstVisit) ) {
$this->set('firstVisit', true);
$this->Cookie->write('foo', 'true');
} else {
$this->set('firstVisit', false);
}
}
This seems like it should work, but nothing is returned and the cookie is completely blank.
What could possible be preventing Cake from actually saving the Cookie?
The cookies are not set until the View is rendered. Maybe you do not have a view for your controller?
The http:// caused it to break. Removing that fixed the problem.
I'm looking for a way with the CakePHP-Facebook-Plugin log users out of my app, but not log them out of their own facebook.
If I call my apps logout() function no matter what I do I just keep getting logged back in via facebook. If I use the plugins facebook helper in the view to generate a logout button ($this->Facebook->logout()), it definetly logs the user out of my app...but it also logs them out of their own facebook which is kinda ridiculous.
So how do I work around this to log users out of my app, and but leave them logged into facebook.
To have them "logout" of your app (meaning the next time they try to use the app, they're going to be asked to authenticate your app again), then send an HTTP DELETE command to me/permissions using their user access token.
I know this is an old question, but I figured this one out just now, trying to figure this same thing out. Basically, although in the demos with webtechnick's examples, he puts "Facebook.Connect" in the AppController, but, if you want the selective logout piece, the Best place to put it is within the actual controllers that you want to use it in or put it in AppController and pass noAuth=> true into it. Either way, whichever way you choose, you set up one controller (facebook_controller.php?) to handle the logins, and set its component with the noauth set to false (which is default). That way, you have total control over whether or not the user is logged back into the site, and you can ACTUALLY log them out (with the regular redirect($this->Auth->logout());
Let me give you an idea:
app_controller.php
class AppController extends Controller {
var $components = array('Auth', 'Acl', 'Session');
//or if you want access to "$this->Connect" universally:
// array('Auth', 'Facebook.Connect' =>
// array('noauth'=>'true', 'Acl', 'Session');
}
users_controller.php:
class UsersController extends AppController{
var $helpers = array('Facebook.Facebook');
//an example of the users controller, enabling connect, but
// not authorizing the user (because logout() used by Auth is here)
var $components = array('Email', 'Session', 'Facebook.Connect' => array('createUser'=>false, 'noauth'=>true));
//login() doesnt need to be shown and can be left alone
function logout(){
if ($this->Connect->FB->getUser() == 0){
$this->redirect($this->Auth->logout());
}else{
//ditch FB data for safety
$this->Connect->FB->destroysession();
//hope its all gone with this
session_destroy();
//logout and redirect to the screen that you usually do.
$this->redirect($this->Auth->logout());
}
}
}
your "facebook_controller.php":
class FacebookaController extends AppController {
...
// i dont personally like to have his piece create my user so:
var $components = array('Facebook.Connect' => array('createUser'=>false));
...
function login(){
//just need this stub function for later
$this->autoRender = false;
}
//you also need this for deauths or they will still be able to get into the site after deauth (against policy or whatever)
function deauthorize(){
//get user id from facebook API
$uid = $this->Connect->FB->getUser();
$record = $this->User->findByFacebookId($uid);
$this->User->delete($record['id'], FALSE);
}
}
now your users/login.ctp file:
<script>
window.fbAsyncInit = function() {
FB.init({
appId : 'your app id', // App ID
channelUrl : '//'+window.location.hostname+'/facebook/channel', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional initialization code here
FB.Event.subscribe('auth.statusChange', function(response){
if (response.status == "connected"){
alert('redirecting you to auto facebook login');
//here is out default place for login
window.location.href = "http://"+window.location.hostname + "/facebook/login";
}
});
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
<?php e($this->Facebook->login(array('registration-url'=>'http://www.yoursite.com/facebook/signup'))); ?>
And that should be pretty much it. I hope this helps someone reading this who still needs the help.
You may want to take a look at $this->Facebook->disconnect();
It does exactly what you want.
http://projects.webtechnick.com/docs/facebook/default/FacebookHelper.html#disconnect
Have you tried killing the PHP session?
// this would destroy the session variables
session_destroy();