Issue with registration function using email template layout - cakephp - cakephp

A strange one to be honest. I have got this working completely fine on my local machine but on the production server (CENTOS), the redirect after registering is hitting the email template..
Is there something I am missing here?
function register() {
$this->layout = 'login';
$this->set('title_for_layout', 'Register');
if(!empty($this->data)) {
$this->User->create();
if($this->User->save($this->data)) {
$this->data['User']['group_id'] = 4;
$this->_sendNewUserMail( $this->User->id );
$this->redirect(array('action' => 'approval'));
} else {
$this->Session->setFlash(__('There were errors found in your registration. Please check the highlighted fields', true));
}
}
}
function _sendNewUserMail($id) {
$this->Email->smtpOptions = array(
'port'=>'25',
'timeout'=>'30',
'host' => 'localhost',
'username'=>'username',
'password'=>'password',
);
$this->Email->delivery = 'smtp';
$User = $this->User->read(null,$id);
$this->Email->to = array('someone#blah.com');
$this->Email->subject = 'A new registration has been submitted';
$this->Email->from = 'Me#blah.com';
$this->Email->template = 'default';
$this->Email->sendAs = 'html';
$this->set('User', $User);
$this->Email->send();
}
I am completely stumped with this..
Many thanks for your help in advance!

I would guess php_openssl is not enabled. Also, you should move the smtpOptions and delivery setting into _sendNewUserMail

[From the comments]
It seems that there was an error in the production server (maybe due to a different configuration in the SMTP server) I assume that in your production server you have the debug set to 0. So the errors are not displayed, That's why instead of redirecting, it renders the email template.
You'll need to debug the smtp errors in production. To do that, you could add:
Configure::write('debug', 1);
in the action/controller that sends the email, so you'd be able to see the error. Also, you could check the smtp errors in the $this->Email->smtpError variable.
That way you'll be able to see what's wrong. I don't know much about smtp server's configurations so that might be another S.O. question.
Hope this helps

Related

I can not send mail in drupal-7

I began to learn about drupal, I perform the function send mail but failed. Please could help me:
$params = array(
'subject' => 'hello',
'body' => 'test',);
$from='nguyen.xuan.luan#vinicorp.com.vn';
$to = 'nguyen.xuan.luan#vinicorp.com.vn';
$mail = drupal_mail('exampe', 'notice', $to, language_default(), $params, $from, TRUE);
error message: Unable to send e-mail. Contact the site administrator if the problem persists.
I think that must have information of mail password but I do not know how. Please can help me?
You need to create one hook i.e. hook_mail in your .module file and set message subject and body there. Below is the working hook_mail() implementation for your code -
function exampe_mail($key, &$message, $params) {
switch($key) {
//switching on $key lets you create variations of the email based on the $key parameter
case 'notice':
$message['subject'] = t('Subject');
//the email body is here, inside the $message array
$message['body'][] = 'This is the body of the email';
break;
}
}

how to send an email to a user in cakephp 2.x

I will greatly appreciate with all my heart if an expert would help me on how to send an email to a user.
am building a registration system. after a user successfully applies for registration, the admin must approve and at the click of the approve button, an email is send to the user and user details are saved in the approved table.
Here is the approve action in the applicationsController.
public function approve($student_id = null) {
if ($this->request->is('post'))
$application = $this->Application->findById($student_id);
$approved['Approved'] = $application['Application'];
$approved['Approved']['student_id'] = $approved['Approved']['student_id'];
$status = array('Application.status' => 'approved');
unset($application['Application']['id']);
unset($application['Application']['receipts']);
$this->loadModel('Approved');
$this->Approved->create();
if ($this->Approved->save($approved)) {
if ($this->Approved->saveField('status', 'approved')){
$this->Session->setFlash(__('The student has been approved'));
$email=$this->request->data['Application']['email'];
$this->Email->to = $email;
$this->Email->subject = 'Registration request approval';
$this->Email->from = 'ernestmwesha#gmail.com';
$this->Email->template = 'template';
$this->Email->smtpOptions = array(
'port' => '465',
'timeout' => '30',
'host' => 'ssl://smtp.gmail.com',
'username' => 'ernestmwesha#gmail.com',
'password' => 'mweshaernest',
);
$this->Email->delivery = 'smtp';
if($this->Email->send()){
return true;
}
else{
echo $this->Email->smtpError;
}
$this->Application->delete($student_id);
$this->redirect(array('action' => 'index')); }
} else {
$this->Session->setFlash(__('The student could not be approved.'));
}
$this->set('title_for_layout', 'Approved Requests');
}
after clicking the approved button i get the following error:
Notice (8): Undefined index: Application [APP\Controller\ApplicationsController.php, line 120]
You need to specify at least one destination for to, cc or bcc.
Error: An Internal Error Has Occurred.
.....bot the student gets approved and placed in the approved table
Review u2460470's answer to point you in the right direction for generating emails with CakePHP.
Make sure you have a mail server setup to handle the processing of emails. You might already have one setup locally, something like SquirrelMail, or you may prefer to use a managed, hosted provider (like Gmail). You can find examples of configuring CakePHP to send mail through Gmail in the CakeEmail documentation.
I've had great experiences using Postmark to handle transactional emails. There is a nice plugin, maurymmarques/postmark-plugin, you can use to easily setup Postmark for your CakePHP app.
// in your controller
App::uses('CakeEmail', 'Network/Email');
function somrthing () {
$Email = new CakeEmail();
$Email->from(array('me#example.com' => 'My Site'));
$Email->to('you#example.com');
$Email->subject('About');
$Email->send('My message');
}
Have a look CakeEmail in CakePHP 2.x

CakePHP 2.3.2 BasicAuthentication not working

I tried out the "Simple Acl controlled Application 1&2" tutorial located at http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html .
After doing this, I tried to activate BasicAuth instead of FormAuth.
I reimplemented the login() function im my UsersController as follows:
public function login() {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash('Not able to login');
}
}
and changed the $components variable in my AppController to the following:
public $components = array(
'Acl',
'Auth' => array(
'authorize' => array(
'Actions' => array('actionPath' => 'controllers')
),
'authenticate' => array('Basic')
),
'DebugKit.Toolbar',
'Session'
);
The BasicAuth "popup" appears as expected, but when I'm trying to login, it reappers in an endless loop. I did not change anything after doing the tutorial except for including DebugKit.
What am I missing? I hope someone can help me, as I'd like to go with CakePHP coding my next Project!
Update
AppController
public function beforeFilter() {
//Configure AuthComponent
$this->Auth->allow('display');
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
$this->Auth->loginRedirect = array('controller' => 'posts', 'action' => 'add');
}
UsersController
public function beforeFilter() {
parent::beforeFilter();
}
I'm trying to access e.g. /users/ which works like a charm using the FormAuth described in the tutorial, so there can't be a permission problem. Logindata is pretty simple for testing (admin:admin) so there should be no problem either.
Update 2
In my Apache Log i get the following, so it says I'm not authorized:
IP - - [16/Apr/2013:18:08:37 +0200] "GET /users/login HTTP/1.0" 401 5179 "-" "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:23.0) Gecko/20130414 Firefox/23.0"
Update 3
For some reason it seems, that User and Password are either not sent or not saved in PHP. If I rewrite /lif/Cake/Controller/Auth/BasicAuthenticate to the following, it works!
public function authenticate(CakeRequest $request, CakeResponse $response) {
$_SERVER['PHP_AUTH_USER'] = $_SERVER['PHP_AUTH_PW'] = "admin";
$result = $this->getUser($request);
if (empty($result)) {
$response->header($this->loginHeaders());
$response->statusCode(401);
$response->send();
return false;
}
return $result;
}
Update 4
Don't know if thats helpful, but the Server is running Plesk 11, latest update, no special modifications.
Update 5
Okay, that answer of "thaJeztah" was useful, but now I'm getting more problems which can be subdivided.
Changed mode from fcgid to apache module
1.1. Results in working login, but logout does not work! After the redirect, the session seems to be cleared, but i can still access every restricted page until i clear my browsers "Active Logins" as it is called in Firefox.
var_dump($this->Session->read('Auth.User'));
NULL
When I access /users/login I am automatically logged in and redirected without having to enter login credentials.
print "<pre>";
print_r($this->Session->read('Auth.User'));
print "</pre>";
Array
(
[id] => 1
[username] => admin
[group_id] => 1
[created] => 2013-04-12 12:54:26
[modified] => 2013-04-16 14:27:24
[is_active] => 1
[Group] => Array
(
[id] => 1
[name] => Admin
[created] => 2013-04-12 12:46:42
[modified] => 2013-04-12 12:46:42
)
)
Using the .htaccess based solution works as well, it even looks like as if thats the only change needed (I removed the list() code as I did never get into it and it worked as well).
2.1. Same problem as above, no real logout possible.
Update 6
Probably the last or one of my last updates. :-)
Right now I'm trying to do a "fake logout" by logging the user in as a guest user I created who has only access to /users/login and /pages/home: http://guest:guest#my.domain/users/login
Accessing /users/logout might work too, as I'm using this piece of code there:
public function logout() {
$user = $this->User->find('first', array('conditions' => array('username' => 'guest')));
$this->Auth->login($user['User']['id']);
}
I simly don't believe, this will be consistent, since I believe the Session data will be deleted some time and the browser still got the active admin login and authenticates using these - am I right?
After that I can login a different User again using http://admin:admin#my.domain/users/login. Not perfect, but works at least for Firefox.
So basically one last question: Any suggestions on how to force a BasicAuth when accessing /users/login? This way I could easily switch users at any time using any client.
Update 7
I found a way to do exactly this with the idea in my accepted answer. I hope I caught all edge cases in this, feel free to correct me if not!
(P.s.: when using ACL and or basic authentication the isAuthorized() in at least the AppController seems to be ignored (it was recognized, but had no effect - when i deleted the method without changing $components, i got an error) which lead to me implementing this without using isAuthorized().)
AppController.php
public function beforeFilter($redirectlogin = true) {
//Configure AuthComponent
$this->Auth->allow('display', '/users/login');
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->logoutRedirect = array('controller' => 'pages', 'action' => 'home');
$this->Auth->loginRedirect = array('controller' => 'pages', 'action' => 'home');
$this->Auth->unauthorizedRedirect = array('controller' => 'HTTPCODE', 'action' => 'c403');
if($redirectlogin && $this->Session->read('Auth.needs_reauthenticate')) {
if(!($this->request->params['controller'] == $this->Auth->loginRedirect['controller'] && $this->request->params['pass'][0] == $this->Auth->loginRedirect['action'])) {
$this->redirect('/users/login');
}
}
}
UsersController.php
public function beforeFilter() {
parent::beforeFilter(false);
}
public function login() {
$this->autoRender = false;
$this->Session->write('Auth.needs_reauthenticate', true);
if(!$this->Session->check('Auth.count')) {
$count = 1;
} else {
$count = $this->Session->read('Auth.count') + 1;
}
$this->Session->write('Auth.count', $count);
if($this->Session->read('Auth.needs_reauthenticate')) {
if((isset($_SERVER['HTTP_AUTHORIZATION']) && $this->Session->read('Auth.count') == 1) || (!isset($_SERVER['HTTP_AUTHORIZATION']) || empty($_SERVER['HTTP_AUTHORIZATION']) || !$this->Session->check('Auth.sent_header_step') || $this->Session->read('Auth.sent_header_step') < 1)) {
unset($_SERVER['HTTP_AUTHORIZATION']);
$this->Session->write('Auth.redirectTo', $this->Auth->redirect());
$this->response->header(sprintf('WWW-Authenticate: Basic realm="%s"', env('SERVER_NAME')));
$this->response->statusCode(401);
$this->response->send();
$this->Session->write('Auth.sent_header_step', 1);
}
if(isset($_SERVER['HTTP_AUTHORIZATION'])) {
$this->Session->write('Auth.sent_header_step', 0);
$base64string = base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6));
if(!(strlen($base64string) > 1 && substr($base64string, -1, 1) != ":")) {
$_SERVER['PHP_AUTH_USER'] = "";
$_SERVER['PHP_AUTH_PW'] = "";
}
$data = true;
}
$this->Auth->logout();
if(isset($data) && $this->Session->read('Auth.count') > 1) {
if($this->Auth->login()) {
$this->Session->write('Auth.needs_reauthenticate', false);
if($this->Session->check('Auth.redirectTo')) {
$redirectTo = $this->Session->read('Auth.redirectTo');
$this->Session->delete('Auth.redirectTo');
$this->Session->delete('Auth.count');
return $this->redirect($redirectTo);
} else {
return $this->redirect($this->Auth->redirect());
}
} else {
$this->response->statusCode(403);
// my 403 message
}
} else {
if(!isset($_SERVER['HTTP_AUTHORIZATION']) && $this->Session->read('Auth.count') > 1 && isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']) && trim($_SERVER['PHP_AUTH_USER']) != "" && trim($_SERVER['PHP_AUTH_PW']) != "") {
if($this->Auth->login()) {
$this->Session->write('Auth.needs_reauthenticate', false);
if($this->Session->check('Auth.redirectTo')) {
$redirectTo = $this->Session->read('Auth.redirectTo');
$this->Session->delete('Auth.redirectTo');
$this->Session->delete('Auth.count');
unset($_SERVER['HTTP_AUTHORIZATION']);
unset($_SERVER['PHP_AUTH_USER']);
unset($_SERVER['PHP_AUTH_PW']);
return $this->redirect($redirectTo);
} else {
return $this->redirect($this->Auth->redirect());
}
} else {
$this->response->statusCode(403);
// my 403 message
}
}
$this->response->statusCode(403);
// my 403 message
}
}
}
Thanks in advance
Adrian
Using Basic Authentication when running PHP as (Fast)CGI
It's possible that your website is configured to run PHP as (Fast)CGI, in which case the PHP_AUTH_USER and PHP_AUTH_PWD keys are not present in the $_SERVER variable. The BasicAuthenticate AuthComponent relies on these keys.
Either change the domain/webhosting settings in Plesk to run php as 'apache module' for this website/domain or extend the BasicAuthenticate Component to get these variables some other way.
More information on this subject can be found in this question:
PHP_AUTH_USER not set?
And for the Symfony framework, somebody seems to have written a workaround that may be useful in this situation as well;
https://github.com/symfony/symfony/issues/1813
update: loging out when using basic authentication
Loging out when using basic authentication is not really possible. Basic authentication is a 'stateless' authentication mechanism, which basically means that the browser is sending the user-credentials with every request. In other words; the server does not keep a 'state', the browser does. With Basic Authentication, you require the browser to send user credentials and as long as the browser sends valid credentials, you allow the browser access to the protected pages.
The only way to log out, is to close the browser, or tell the browser to close active sessions/logins.
Read more information here:
http://en.wikipedia.org/wiki/Basic_access_authentication
http basic authentication "log out"
Notes
Base Authentication is not a secure authentication mechanism; the username and password is sent to the server with every request. The password is sent unencrypted (only base64 encoded to prevent problems with special characters).
Although Form authentication also sends the password unencrypted, it is (a bit more) secure as it will only send the username/password when logging in. Subsequent requests will only send the Session-id, which can be set to expire and limited to a specific IP and/or Browser type.
In all cases, securing the connection via SSL is obviously important.
Forcing re-authentication on the login page
This is just 'thinking out loud', untested and highly experimental :)
Try this;
If no session is active, proceed the normal way. There is no way to differentiate 'already logged in' users from 'new users' in Basic Authentication - it is stateless
If a session is active, a user apparently has an active session going on. Don't destroy the session, but change the rules;
If the credentials sent are for the same user as the username inside the session (or, better: $this->Auth->user('username');?, Then invalidate the session (not destroy) and force the user to re-authenticate, by sending login headers;
You may copy the headers from the BasicAuthenticate behavior; see the source here BasicAuthenticate::authenticate()
Regarding 'copying the headers'; Maybe extending the BasicAuthenticate is a cleaner approach; handle all your custom code inside your customized version.
Additionally, check if the session is still 'valid' inside AppController::isAuthorized()(see Using ControllerAuthorize)
Something like this (Mockup code):
Login page/action:
if ("usercredentials sent by browser" === "current logged in user in session") {
// Mark session as 'needs-to-reauthenticate'
$this->Session->write('Auth.needs_reauthenticate', true);
// Need to find a clean approach to get the BasicAuth loginHeaders()
// *including* the right settings (realm)
$this->response->header(/*BasicAuth::loginHeaders()*/);
// Access denied status
$this->response->statusCode(401);
return $this->response->send();
}
AppController::isAuthorized()
if ($this->Session->read('Auth.needs_reauthenticate')) {
return false;
} else {
// Normal 'isAuthorized()' checks here
}
NOTE:
Once a browser has visited the 'login' page during an active session, the user will either have to log-in with different credentials, or close the browser to log in again.
This may be problematic if the session-cookie is still present after closing and re-opening the browser. Try to force the session-cookie to be a "real" session-cookie and have it deleted on browser close by setting Session.cookieTimeout to 0 (see Session Configuration

webtechnick Facebook logout not working

I am using webtechnick facebook plugin, i have everything set and its FB login works perfectly.
I am using $fbc =$this->Connect->User(); to fetch FB details of logged in user
And using
<?php
echo $facebook->login(array('perms' => 'email,publish_stream','size'=>'small'));
?>
<?php
echo $this->Facebook->logout();
?>
for login,logout respectively. i am getting details of user after login, but it will not unset after performing a logout();
I am using webtechnick fb plugin version 3.1.1 . Please help me
My help isn't much help because I haven't really found a solution. The good news is that you are not alone:
https://github.com/webtechnick/CakePHP-Facebook-Plugin/issues/43
What I can tell you is that the facebook cookie (fbsr_{facebook_app_id}) is either not deleting or is being recreated and that is the root of the problem.
EDIT
I may have found out what's going on here. Until the other night I had not bothered to setup my .htaccess files and both http:/www.example.com and http:/example.com were valid.
In my facebook app, I had set up example.com as a domain and pointed the site URL to www.example.com.
With the fbsr_{app id} cookie, I noticed that it was sometimes on the http://example.com while my cakephp cookies were on www.
I played around with changing the URL in my facebook app (adding www, removing www) and then also started doing the rewrite rules in .htaccess to add or remove www. I just removed the appdomain entirely from my facebook app, forced www. to the domain, and now everything is kosher.
So I think the trick is to
Not have the app domain in the facebook app
Fix canonicalization of www via .htaccess
This ensures that both the cakephp and the facebook cookies are being saved to the identical domain, and when you logout they are removed from said domain.
Hope this makes sense...
I know it is too late for some suggestion for this post. Still feel it might help some one who later reading this post.
I too was facing the logout issue with the plugin , I have modified a function in ConnectComponent in the plugin to clear its session details if the action is "logout". Below is the modified function :
private function __syncFacebookUser(){
if($this->Controller->params['action'] == 'logout')
{
$this->Controller->Session->delete('FB');
$this->uid = null;
$this->Controller->Session->delete('Auth.User');
}
else
{
if(!isset($this->Controller->Auth)){
return false;
}
$Auth = $this->Controller->Auth;
if (!$this->__initUserModel()) {
return false;
}
// if you don't have a facebook_id field in your user table, throw an error
if(!$this->User->hasField('facebook_id')){
$this->__error("Facebook.Connect handleFacebookUser Error. facebook_id not found in {$Auth->userModel} table.");
return false;
}
// check if the user already has an account
// User is logged in but doesn't have a
if($Auth->user('id')){
$this->hasAccount = true;
$this->User->id = $Auth->user($this->User->primaryKey);
if (!$this->User->field('facebook_id')) {
$this->User->saveField('facebook_id', $this->uid);
}
return true;
}
else {
// attempt to find the user by their facebook id
$this->authUser = $this->User->findByFacebookId($this->uid);
//if we have a user, set hasAccount
if(!empty($this->authUser)){
$this->hasAccount = true;
}
//create the user if we don't have one
elseif(empty($this->authUser) && $this->createUser) {
$this->authUser[$this->User->alias]['facebook_id'] = $this->uid;
$this->authUser[$this->User->alias][$this->modelFields['password']] = $Auth->password(FacebookInfo::randPass());
if($this->__runCallback('beforeFacebookSave')){
$this->hasAccount = ($this->User->save($this->authUser, array('validate' => false)));
}
else {
$this->authUser = null;
}
}
//Login user if we have one
if($this->authUser){
$this->__runCallback('beforeFacebookLogin', $this->authUser);
$Auth->authenticate = array(
'Form' => array(
'fields' => array('username' => 'facebook_id', 'password' => $this->modelFields['password'])
)
);
if($Auth->login($this->authUser[$this->model])){
$this->__runCallback('afterFacebookLogin');
}
}
return true;
}
}
}
For me now the facebook plugin is working fine for facebook connect.

Cakephp User management plugin implementation

I had downloaded the plugin from link
https://github.com/CakeDC/users
followed the steps given in the page. I have created the tables 'users' and 'details'. I have also registered the user and verfied the user, but while accessing the link www.mydomain/users/users/login this page is getting redirected to www.mydomain/users/login
which shows missing controller. I am new to cake and for me it is difficult to debug. I would be thank if some one help me.
Thank you for the response.
Yes, I have added the code given in the "cake\libs\controller\app_controller.php" file. In order to test this I have freshly downloaded the core files and setup the files in my local system. I have placed the plugins 'utils', 'search' and 'users' to my app/plugins folder and created the tables.
Now also I am able to register the user but not able to see the login page. ie. "while accessing the link www.mydomain/users/users/login this page is getting redirected to www.mydomain/users/login which shows missing controller".
Please let me know if I am missing anything or I am wrong.
Thank you.
This looks like a problem in the login redirection.
Did you add the beforeFilter() configuration to your app_controller?
if not you may need to add it.
Here is an example of how your app_controller should look like:
<?php
class AppController extends Controller {
var $components = array('RequestHandler', 'Session', 'Auth');
function beforeFilter(){
$this->Auth->fields = array('username' => 'email', 'password' => 'passwd');
$this->Auth->loginAction = array('plugin' => 'users', 'controller' => 'users', 'action' => 'login', 'admin' => false);
$this->Auth->loginRedirect = '/';
$this->Auth->logoutRedirect = '/';
$this->Auth->authError = __('Sorry, but you need to login to access this location.', true);
$this->Auth->loginError = __('Invalid e-mail / password combination. Please try again', true);
$this->Auth->autoRedirect = false;
$this->Auth->userModel = 'Users.User';
$this->Auth->userScope = array('User.active' => 1);
}
}
?>
Remember that the $this->Auth->loginAction MOST contain the 'plugin'=>'users', without it it will go to www.mydomain/users/login instead of www.mydomain/users/users/login

Resources