3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
19 * Forgot password routine.
21 * Finds the user and calls the appropriate routine for their authentication type.
25 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 require('../config.php');
30 require_once($CFG->libdir
.'/authlib.php');
31 require_once('forgot_password_form.php');
33 $p_secret = optional_param('p', false, PARAM_RAW
);
34 $p_username = optional_param('s', false, PARAM_RAW
);
36 //HTTPS is required in this page when $CFG->loginhttps enabled
37 $PAGE->https_required();
39 $PAGE->set_url('/login/forgot_password.php');
40 $systemcontext = context_system
::instance();
41 $PAGE->set_context($systemcontext);
44 $strforgotten = get_string('passwordforgotten');
45 $strlogin = get_string('login');
47 $PAGE->navbar
->add($strlogin, get_login_url());
48 $PAGE->navbar
->add($strforgotten);
49 $PAGE->set_title($strforgotten);
50 $PAGE->set_heading($COURSE->fullname
);
52 // if alternatepasswordurl is defined, then we'll just head there
53 if (!empty($CFG->forgottenpasswordurl
)) {
54 redirect($CFG->forgottenpasswordurl
);
57 // if you are logged in then you shouldn't be here!
58 if (isloggedin() and !isguestuser()) {
59 redirect($CFG->wwwroot
.'/index.php', get_string('loginalready'), 5);
62 if ($p_secret !== false) {
63 ///=====================
64 /// user clicked on link in email message
65 ///=====================
67 $user = $DB->get_record('user', array('username'=>$p_username, 'mnethostid'=>$CFG->mnet_localhost_id
, 'deleted'=>0, 'suspended'=>0));
69 if ($user and ($user->auth
=== 'nologin' or !is_enabled_auth($user->auth
))) {
70 // bad luck - user is not able to login, do not let them reset password
74 if (!empty($user) and $user->secret
=== '') {
75 echo $OUTPUT->header();
76 print_error('secretalreadyused');
77 } else if (!empty($user) and $user->secret
== $p_secret) {
78 // make sure that url relates to a valid user
80 // check this isn't guest user
81 if (isguestuser($user)) {
82 print_error('cannotresetguestpwd');
85 // Reset login lockout even of the password reset fails.
86 login_unlock_account($user);
88 // make sure user is allowed to change password
89 require_capability('moodle/user:changeownpassword', $systemcontext, $user->id
);
91 if (!reset_password_and_mail($user)) {
92 print_error('cannotresetmail');
95 // Clear secret so that it can not be used again
97 $DB->set_field('user', 'secret', $user->secret
, array('id'=>$user->id
));
99 $changepasswordurl = "{$CFG->httpswwwroot}/login/change_password.php";
101 $a->email
= $user->email
;
102 $a->link
= $changepasswordurl;
104 echo $OUTPUT->header();
105 notice(get_string('emailpasswordsent', '', $a), $changepasswordurl);
108 if (!empty($user) and strlen($p_secret) === 15) {
109 // somebody probably tries to hack in by guessing secret - stop them!
110 $DB->set_field('user', 'secret', '', array('id'=>$user->id
));
112 echo $OUTPUT->header();
113 print_error('forgotteninvalidurl');
119 $mform = new login_forgot_password_form();
121 if ($mform->is_cancelled()) {
122 redirect(get_login_url());
124 } else if ($data = $mform->get_data()) {
125 /// find the user in the database and mail info
127 // first try the username
128 if (!empty($data->username
)) {
129 $username = textlib
::strtolower($data->username
); // mimic the login page process, if they forget username they need to use email for reset
130 $user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id
, 'deleted'=>0, 'suspended'=>0));
133 // this is tricky because
134 // 1/ the email is not guaranteed to be unique - TODO: send email with all usernames to select the correct account for pw reset
135 // 2/ mailbox may be case sensitive, the email domain is case insensitive - let's pretend it is all case-insensitive
137 $select = $DB->sql_like('email', ':email', false, true, false, '|'). " AND mnethostid = :mnethostid AND deleted=0 AND suspended=0";
138 $params = array('email'=>$DB->sql_like_escape($data->email
, '|'), 'mnethostid'=>$CFG->mnet_localhost_id
);
139 $user = $DB->get_record_select('user', $select, $params, '*', IGNORE_MULTIPLE
);
142 if ($user and !empty($user->confirmed
)) {
144 $userauth = get_auth_plugin($user->auth
);
145 if (has_capability('moodle/user:changeownpassword', $systemcontext, $user->id
)) {
149 if ($userauth->can_reset_password() and is_enabled_auth($user->auth
)
150 and has_capability('moodle/user:changeownpassword', $systemcontext, $user->id
)) {
151 // send reset password confirmation
153 // set 'secret' string
154 $user->secret
= random_string(15);
155 $DB->set_field('user', 'secret', $user->secret
, array('id'=>$user->id
));
157 if (!send_password_change_confirmation_email($user)) {
158 print_error('cannotmailconfirm');
162 if (!send_password_change_info($user)) {
163 print_error('cannotmailconfirm');
168 echo $OUTPUT->header();
170 if (empty($user->email
) or !empty($CFG->protectusernames
)) {
171 // Print general confirmation message
172 notice(get_string('emailpasswordconfirmmaybesent'), $CFG->wwwroot
.'/index.php');
175 // Confirm email sent
176 $protectedemail = preg_replace('/([^@]*)@(.*)/', '******@$2', $user->email
); // obfuscate the email address to protect privacy
177 $stremailpasswordconfirmsent = get_string('emailpasswordconfirmsent', '', $protectedemail);
178 notice($stremailpasswordconfirmsent, $CFG->wwwroot
.'/index.php');
181 die; // never reached
184 // make sure we really are on the https page when https login required
185 $PAGE->verify_https_required();
190 echo $OUTPUT->header();
191 echo $OUTPUT->box(get_string('passwordforgotteninstructions2'), 'generalbox boxwidthnormal boxaligncenter');
194 echo $OUTPUT->footer();