Функция сброса пароля в Codeigniter 3

Я работаю над онлайн-газетой / приложением для ведения блога с 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 ответ
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 я возвращаю затронутые строки.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *