Last active
December 15, 2015 20:09
-
-
Save JaceTan/5316096 to your computer and use it in GitHub Desktop.
The ultimate forget_password pieces
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// define whether we really want to send emails | |
define('EMAIL_ON', true); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
echo $this->Form->create('User', array('action' => 'forget_password')); | |
echo $this->Form->inputs(array( | |
'legend' => __('Reset password'), | |
'User.email' => array('type' => 'email'), | |
)); | |
echo $this->Form->end('Submit'); | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
//add this file to Lib/Email folder | |
App::uses('CakeEmail', 'Network/Email'); | |
class PasswordEmail { | |
private $emailConfig = 'gmail'; | |
private $sender = 'do-not-reply@example.com'; | |
private $from; | |
private $to; | |
private $email; | |
public function __construct($to) { | |
$this->from = array('full_name' => 'Example', 'email' => $this->sender); | |
$this->to = $to; | |
$this->_prepareAddressFields(); | |
} | |
protected function _prepareAddressFields() { | |
$fromEmail = $this->from['email']; | |
$fromFullName = $this->from['full_name']; | |
$toEmail = $this->to['email']; | |
$toFullName = $this->to['full_name']; | |
$email = new CakeEmail($this->emailConfig); | |
$email->from(array($fromEmail => $fromFullName)); | |
$email->to(array($toEmail => $toFullName)); | |
$email->sender($this->sender); | |
$email->replyTo($fromEmail, $fromFullName); | |
$this->email = $email; | |
return $email; | |
} | |
public function sendNewPassword($newPassword) { | |
$email = $this->email; | |
$email->subject('[Password Reset] Do NOT reply to this email'); | |
if (EMAIL_ON) { | |
$result = $email->send("This is your new password $newPassword."); | |
} else { | |
$result = $email; | |
} | |
return $result; | |
} | |
public function sendToken($token) { | |
$email = $this->email; | |
$email->subject('[Password Reset] Do NOT reply to this email'); | |
$baseURL = Router::url('/users/reset_password?token=' . $token, true); | |
if (EMAIL_ON) { | |
$result = $email->send("Please click this link to reset your password. $baseURL"); | |
} else { | |
$result = $email; | |
} | |
return $result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
echo $this->Form->create('User', array( | |
'url' => Router::url(array( | |
'action' => 'reset_password', | |
'controller' => 'users', | |
'?' => array('token' => $token) | |
)) | |
)); | |
echo $this->Form->inputs(array( | |
'legend' => __('Please choose a new password'), | |
'User.id' => array('type' => 'hidden'), | |
'User.new_password' => array('type' => 'password'), | |
'User.confirm_new_password' => array('type' => 'password'), | |
)); | |
echo $this->Form->end('Submit'); | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
App::uses('PasswordEmail', 'Lib/Email'); | |
/** | |
* | |
* Checks the database to see if the email provided exists. If there is, return true. | |
* | |
* @param String $email Email Provided | |
* @return Boolean True if email exists, else return false | |
*/ | |
public function checkEmailExists($email) { | |
$emailExists = $this->find('count', array( | |
'conditions' => array( | |
'email' => $email) | |
) | |
); | |
return ($emailExists === 1); | |
} | |
/** | |
* | |
* Makes a token using the email given and the current dateTime | |
* | |
* @param String $email Email Provided | |
* @return String $token The token | |
*/ | |
public function createToken($email) { | |
$dateTime = date('Y-m-d H:i:s'); | |
$plaintext = $email . $dateTime; | |
$token = Security::hash($plaintext, 'sha1', true); | |
return $token; | |
} | |
/** | |
* | |
* searches the users table for a token, given the email. If token is empty, create a new one and return it. | |
* | |
* @param String $email Email Provided | |
* @return Array $userData containing full_name, email and token | |
*/ | |
public function findXORCreateToken($email){ | |
$userData = $this->find('first', array( | |
'conditions' => array('User.email' => $email), | |
'fields' => array('User.id', 'User.full_name', 'User.token', 'User.email') | |
)); | |
if ($userData['User']['token'] === null || empty($userData['User']['token'])) { | |
$token = $this->createToken($email); | |
$this->id = $userData['User']['id']; | |
$this->saveField('token', $token, array( | |
'callbacks' => false, | |
'validate' => false | |
)); | |
$userData['User']['token'] = $token; | |
} | |
$userData = Hash::extract($userData, 'User'); | |
return $userData; | |
} | |
/** | |
* | |
* Sends the user a token to reset password | |
* | |
* @param Array $userData Array containing full_name, email and token | |
* @return void | |
*/ | |
public function sendToken($userData){ | |
$recipient = array( | |
'full_name' => $userData['full_name'], | |
'email' => $userData['email'], | |
); | |
$email = new PasswordEmail($recipient); | |
$email->sendToken($userData['token']); | |
} | |
/** | |
* | |
* Resets the password | |
* | |
* @param Array $data Array containing id, new_password, confirm_new_password | |
* @return mixed return user data array or true if successful. false otherwise | |
* @throws CakeException when passwords don't match | |
*/ | |
public function resetPassword($data){ | |
//check if new pwd matches confirm pwd | |
if ($data['User']['new_password'] == $data['User']['confirm_new_password']) { | |
//save the pwd if successful | |
$data['User']['password'] = $data['User']['new_password']; | |
$data['User']['token'] = null; | |
$result = $this->save($data); | |
return $result; | |
} else { | |
throw new CakeException ('Your new passwords do not match.'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* forget_password method | |
* | |
* @return void | |
*/ | |
public function forget_password() { | |
if ($this->request->is('post')) { | |
$email = $this->request->data['User']['email']; | |
$emailExist = $this->User->checkEmailExists($email); | |
if ($emailExist === true) { | |
//concat datetime and email, and hash them to create token | |
$userData = $this->User->findXORCreateToken($email); | |
//send email with token | |
$this->User->sendToken($userData); | |
$this->Session->setFlash('The reset link has been sent to your email. Please check your email and click the link.'); | |
$this->redirect(array('action' => 'login')); | |
} else { | |
$this->Session->setFlash('Did you enter a valid email address?'); | |
} | |
} | |
} | |
/** | |
* reset_password method | |
* | |
* @return void | |
*/ | |
public function reset_password() { | |
if(isset($_GET['token'])){ | |
$userData = $this->User->findByToken($_GET['token']); | |
$validToken = $userData; | |
$this->set('token', $_GET['token']); | |
} else { | |
$validToken = false; | |
} | |
if (!$validToken) { | |
$this->Session->setFlash('Invalid link. Please Login.'); | |
$this->redirect(array('action' => 'login')); | |
} | |
if ($this->request->is('get')) { | |
if ($validToken) { | |
$this->request->data = $userData; | |
} | |
} else if ($this->request->is('post') || $this->request->is('put')) { | |
try { | |
$result = $this->User->resetPassword($this->request->data); | |
$errorMessage = "Not successful"; | |
} catch(CakeException $error) { | |
$result = false; | |
$errorMessage = $error->getMessage(); | |
} | |
if ($result) { | |
$this->Session->setFlash('Password successfully changed'); | |
$this->redirect(array('action' => 'login')); | |
} else { | |
$this->Session->setFlash($errorMessage); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note the following assumptions in this code:
we are using an email config named gmail.
User models have the following fields, real or virtual: 'User.id', 'User.full_name', 'User.token', 'User.email'