Я работаю над онлайн-газетой / приложением для ведения блога с CodeIgniter 3.1.8 и Веточка. (Я использую шаблонизатор Twig только для интерфейсных представлений).
В приложении, конечно же, есть регистрация и вход система, которая включает функцию сброса пароля.
В Сброс пароля контроллер:
class Passwordreset extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
private $sender_email = "noreply@yourdomain.com";
private $sender_name = "Razvan Zamfir";
private $user_email="";
private $subject="Pasword reset link";
private $token = '';
private $reset_url="";
private $reset_link = '';
private $body = '';
public function index()
{
// Display form
$data = $this->Static_model->get_static_data();
$data['pages'] = $this->Pages_model->get_pages();
$data['tagline'] = 'Reset your password';
$data['categories'] = $this->Categories_model->get_categories();
// Form validation rules
$this->form_validation->set_rules('email', 'Email', 'required|trim|valid_email');
$this->form_validation->set_error_delimiters('<p class="error-message">', '</p>');
if (!$this->form_validation->run()) {
$this->load->view('dashboard/partials/header', $data);
$this->load->view('auth/passwordreset');
$this->load->view('dashboard/partials/footer');
} else {
if ($this->Usermodel->email_exists()) {
//Get user email
$this->user_email = $this->input->post('email');
//create token
$this->token = md5(str_shuffle($this->user_email));
//create url
$this->reset_url = base_url('newpassword/') . $this->token;
//create reset link
$this->reset_link = '<a href="'%20.%20$this->reset_url%20.%20'">password reset link</a>';
$this->body = "Here is your <strong>" . $this->reset_link . "</strong>. After clicking it you will be redirected to a page on the website where you will be able to set a new pasword.";
// Update paswword reset token
$this->updateToken($this->user_email, $this->token);
// Send mail and rediect
$this->sendResetMail();
} else {
$this->session->set_flashdata('email_non_existent', "The email you provided does not exist in our database");
}
redirect('newpassword');
}
}
public function updateToken($user_email, $token)
{
$user_email = $this->user_email;
$token = $this->token;
$this->Usermodel->update_token($user_email, $token);
}
public function sendResetMail()
{
$config = array();
$config['protocol'] = 'smtp';
$config['smtp_host'] = 'smtp.yourdomain.com';
$config['smtp_user'] = 'noreply@yourdomain.com';
$config['smtp_pass'] = '******';
$config['smtp_port'] = 25;
$config['charset'] = 'utf-8';
$config['mailtype'] = 'html';
$config['newline'] = "rn";
if (!$this->load->is_loaded('email')) {
$this->load->library('email', $config);
} else {
$this->email->initialize($config);
}
// Build the body and meta data of the email message
$this->email->from($this->sender_email, $this->sender_name);
$this->email->to($this->user_email);
$this->email->subject($this->subject);
$this->email->message($this->body);
if ($this->email->send()) {
$this->session->set_flashdata('reset_mail_confirm', "A pasword reset link was send to the email address $this->user_email");
} else {
$this->session->set_flashdata('reset_mail_fail', "Our atempt to send a pasword reset link to $this->user_email has failed");
}
}
}
В парольreset.php Посмотреть:
<?php echo form_open(base_url(' ')); ?>
<div class="form-group <?php if(form_error('email')) echo 'has-error';?>">
<input type="text" name="email" id="email" class="form-control" placeholder="Email" value="<?php echo set_value('email')?>">
<?php if(form_error('email')) echo form_error('email'); ?>
</div>
<div class="form-group mb-2">
<input type="submit" value="Reset password" class="btn btn-block btn-md btn-success">
</div>
<?php echo form_close(); ?>
В Новый пароль контроллер:
class Newpassword extends CI_Controller
{
public function index($token = NULL)
{
$data = $this->Static_model->get_static_data();
$data['pages'] = $this->Pages_model->get_pages();
$data['tagline'] = 'New password';
$data['categories'] = $this->Categories_model->get_categories();
$data['token'] = $token;
// Form validation rules
$this->form_validation->set_rules('password', 'Password', 'required|min_length[6]');
$this->form_validation->set_rules('cpassword', 'Confirm password', 'required|matches[password]');
$this->form_validation->set_error_delimiters('<p class="error-message">', '</p>');
if (!$this->form_validation->run()) {
$this->load->view('dashboard/partials/header', $data);
$this->load->view('auth/newpassword');
$this->load->view('dashboard/partials/footer');
} else {
// Encrypt new password
$enc_password = password_hash($this->input->post('password'), PASSWORD_DEFAULT);
if ($this->Usermodel->set_new_password($token, $enc_password)) {
$this->session->set_flashdata("new_password_success", "Your new password was set. You can login");
redirect('login');
} else {
$this->session->set_flashdata("new_password_fail", "We have failed updating your password");
redirect('/newpassword/' . $token);
}
}
}
}
В newpassword.php Посмотреть:
<?php echo form_open(base_url('newpassword/'. $token)); ?>
<div class="form-group <?php if(form_error('password')) echo 'has-error';?>">
<input type="password" name="password" id="password" class="form-control" placeholder="Password">
<?php if(form_error('password')) echo form_error('password'); ?>
</div>
<div class="form-group <?php if(form_error('cpassword')) echo 'has-error';?>">
<input type="password" name="cpassword" id="cpassword" class="form-control" placeholder="Confirm password">
<?php if(form_error('cpassword')) echo form_error('cpassword'); ?>
</div>
<div class="form-group mb-2">
<input type="submit" value="Set password" class="btn btn-block btn-md btn-success">
</div>
<?php echo form_close(); ?>
В модели у меня есть:
public function email_exists() {
$query = $this->db->get_where('authors', ['email' => $this->input->post('email')]);
return $query->num_rows() > 0;
}
//more code
public function update_token($user_email, $token) {
return $this->db
->where('email', $user_email)
// insert token (make it diffrent from NULL)
->update('authors', array('token' => $token));
}
public function set_new_password($token, $enc_password) {
return $this->db
->where('token', $token)
// set new password and reset token to NULL
->update('authors', array('password' => $enc_password, 'token' => NULL));
}
Моя главная забота — это безопасность, но я буду признателен любая конструктивная критика. Спасибо! 🙂
1 ответ
Немного пищи для размышлений:
Я не вижу пользы в
str_shuffle()
Зачем беспокоиться? Зачем вообще ссылаться на электронную почту? Если вам нужна случайная строка, заполните ее кратчайшим путем с удовлетворительной случайностью для задачи.Я обычно не рекомендую создавать разметку html где-либо, кроме представления. Я бы предпочел, чтобы свойства вашего контроллера содержали только необработанные данные.
updateToken()
нужно переосмыслить. Зачем вам передавать какие-либо значения в метод, если вы собираетесь немедленно и безоговорочно перезаписать их? Вы имеете в виду обратное этим заявлениям? Вам также следует избегать объявления одноразовых переменных, если это не дает очевидных преимуществ.Вы постоянно звоните
form_error()
(содержащий строку dame вместо того, чтобы вызывать ее один раз и использовать ее значение несколько раз. Дело не в производительности, а в том, чтобы не повторяться.email_exists()
никогда не должны напрямую получать суперглобальные переменные. Вам нужно оптимизировать свои методы для полезности. Представьте, что вам нужно вызвать этот метод в другом месте — у вас может быть или нет$_POST
элемент с таким точным именем. Итак, вам абсолютно необходимо собрать все отправленные значения в контроллере, и контроллер распределяет данные по моделям.public function email_exists(string $email): bool { return (bool)this->db->where(['email' => $email])->count_all_results('authors'); }
Применяйте этот совет последовательно на протяжении всего проекта.
CodeIgniter’s
update()
метод может получитьwhere
data в качестве третьего параметра. Используйте третий параметр, чтобы удалитьwhere()
вызов.Используйте объявления типов данных для всех входов и возвращаемых значений для всех методов — это действительно улучшает читаемость и удобство сопровождения проекта.
Я рекомендую всегда возвращаться что нибудь когда метод пытается изменить базу данных. Для INSERT я возвращаю автоматически сгенерированный идентификатор (первичный ключ). При выполнении UPDATE или DELETE я возвращаю затронутые строки.