yf_get_pswd user module

Fileplugins/user/modules/yf_get_pswd.class.php
Usemodule('get_pswd'), URL ?object=get_pswd

Public properties

A site sets them in its config with $PROJECT_CONF['get_pswd']['NAME'] = ...;

PropertyDefaultDescription
$RESET_BY_TOKEN
bool
false Mail a single-use reset link instead of the stored password (previous behaviour: mail the password). Forced when the stored password is a hash
$TOKEN_TTL
int
3600 Reset link lifetime, seconds
$_my_site_title null

Public methods 7

reset

public function reset()

/get_pswd/reset/<token>: choose a new password.

    public function reset()
    {
        $row = $this->_find_reset($_GET['id'] ?? '');
        if ( ! $row) {
            return _e(t('This password reset link is invalid or has expired. Request a new one.'));
        }
        $user_id = (int) $row['user_id'];
        $stored = (string) db()->get_one('SELECT password FROM ' . db('user') . ' WHERE id = ' . $user_id);
        $password = _class('password');
        // an account that already holds a hash never goes back to the legacy form
        $hash_it = $password->HASH_ON_WRITE || $password->is_hash($stored);
        if ($hash_it && ! $password->column_fits('user')) {
            return _e(t('Password reset is not available: contact the site administrator'));
        }
        $rule = $hash_it ? 'hash_password' : 'password_store';
        $a = $_POST;
        $a['redirect_link'] = url('/login_form');
        return form($a, ['legend' => t('Choose a new password'), 'class' => 'form-vertical'])
            ->validate([
                '__form_id__' => 'pswd_reset_form',
                'password' => 'trim|required|min_length[6]|max_length[72]|' . $rule,
                'pswdconf' => 'trim|required|matches[password]',
            ])
            ->on_validate_ok(function ($data, $extra, $form) use ($row) {
                // single use, claimed before the write so two parallel posts cannot both succeed
                db()->query('UPDATE ' . db('user_pswd_reset') . ' SET used = 1 WHERE id = ' . (int) $row['id'] . ' AND used = 0');
                if (db()->affected_rows() < 1) {
                    $form->_validate_ok = false;
                    _re(t('This password reset link was already used'));
                }
            })
            ->db_update_if_ok('user', ['password'], 'id=' . $user_id, ['on_after_update' => function () use ($user_id) {
                db()->query('UPDATE ' . db('user_pswd_reset') . ' SET used = 1 WHERE user_id = ' . $user_id);
                // remembered browsers must not outlive the password they were issued with
                _class('auth_user', 'classes/auth/')->_remember_revoke_user($user_id);
                common()->message_success(t('Your password has been changed, you can log in now'));
            }])
            ->password('password', t('New password'))
            ->password('pswdconf', t('Repeat the new password'))
            ->save();
    }

show

public function show()
    public function show()
    {
        conf('_login_form_displayed', true);
        if ( ! empty($_POST)) {
            if (empty($_POST['login']) && empty($_POST['email'])) {
                _re('Login or Email required');
            }
            // Check if user with such login exists
            if ( ! empty($_POST['login'])) {
                $A = db()->query_fetch('SELECT id,name,login,password,email,nick FROM ' . db('user') . ' WHERE login="' . _es($_POST['login'] ?? null) . '"');
                if (empty($A['id'])) {
                    _re('Login was not found', 'login');
                }
                if ( ! common()->_error_exists()) {
                    $result = $this->_send_info_to_user($A);
                    if ( ! $result) {
                        _re('Server mail error');
                    }
                }
                // Check if user with such email exists
            } elseif ( ! empty($_POST['email'])) {
                $Q = db()->query('SELECT id,name,login,password,email,nick FROM ' . db('user') . ' WHERE email="' . _es($_POST['email'] ?? null) . '"');
                if ( ! db()->num_rows($Q)) {
                    _re('Email was not found', 'email');
                }
                // Check if errors exists and send all found accounts
                if ( ! common()->_error_exists()) {
                    while ($A = db()->fetch_assoc($Q)) {
                        $result = $this->_send_info_to_user($A);
                        if ( ! $result) {
                            _re('Server mail error');
                        }
                    }
                }
            }
            if ( ! common()->_error_exists()) {
                $success_msg = $this->_sent_reset_link
                    ? t('A link to choose a new password has been sent to your email address. It works once and expires soon.')
                    : t('Password has been sent to your email address. It should arrive in a couple of minutes.');
            }
        }
        $replace = [
            'form_action' => './?object=' . ($_GET['object'] ?? null),
        ];
        $login_form = form($replace, ['legend' => 'Enter your login', 'class' => 'form-vertical'])
            ->validate(['login' => 'trim|required'])
            ->text('login', 'Enter your login')
            ->submit('', 'Get Password', ['class' => 'btn btn-small']);
        $email_form = form($replace, ['legend' => 'Enter your email', 'class' => 'form-vertical'])
            ->validate(['email' => 'trim|required'])
            ->email('email', 'Enter your email')
            ->submit('', 'Get Password', ['class' => 'btn btn-small']);
        return tpl()->parse(__CLASS__ . '/main', [
            'error' => _e(),
            'success' => ! empty($success_msg) ? $success_msg : '',
            'login_form' => $login_form,
            'email_form' => $email_form,
        ]);
    }

Methods starting with _ hooks and helpers; not routable as page actions

_find_reset

public function _find_reset($token)

Row of a valid (unused, unexpired) reset token, or false.

    public function _find_reset($token)
    {
        $token = (string) $token;
        if ( ! preg_match('~^[0-9a-f]{64}$~', $token)) {
            return false;
        }
        $row = db()->get('SELECT * FROM ' . db('user_pswd_reset') . ' WHERE token_hash="' . _es(_class('password')->hash_token($token)) . '" AND used=0 AND expires > ' . time());
        return ! empty($row['id']) ? $row : false;
    }

_init

public function _init()
    public function _init()
    {
        $this->_my_site_title = t('Password Reminder');
    }
public function _send_info_to_user($user = [])
    public function _send_info_to_user($user = [])
    {
        if (empty($user)) {
            return false;
        }
        if ($this->RESET_BY_TOKEN || _class('password')->is_hash($user['password'] ?? '')) {
            return $this->_send_reset_link($user);
        }
        $html = tpl()->parse('@object/email', [
            'user_name' => _display_name($user),
            'password' => $user['password'],
            'login' => $user['login'],
            'advert_name' => SITE_ADVERT_NAME,
            'home_url' => url('/'),
            'login_url' => url('/login_form'),
            'faq_url' => url('/faq'),
        ]);
        return common()->send_mail([
            'from_mail' => SITE_ADMIN_EMAIL,
            'from_name' => SITE_ADVERT_NAME,
            'to_mail' => $user['email'],
            'to_name' => _display_name($user),
            'subj' => t('Password Found'),
            'html' => $html,
            'text' => nl2br(strip_tags($html)),
// TODO: implement these inside send_mail
            'on_error' => function ($params) {
                common()->message_error('Server cannot send email to you, please contact support');
            },
// TODO: implement these inside send_mail
            'on_success' => function ($params) {
                common()->message_success('Email was sent successfully');
            },
        ]);
    }

_site_title

public function _site_title($title)
    public function _site_title($title)
    {
        return $this->_my_site_title;
    }