source: trunk/password.php @ 12332

Last change on this file since 12332 was 11992, checked in by plg, 13 years ago

feature 2027 implemented: the "lost password" feature was rewritten.

The algorithm is highly inspired from WordPress :

1) in a single field, you give a username or an email
2) Piwigo sends an email with the activation key
3) the user clicks on the link in the email (with the activation key) and is able to set a new password

The "lost password" feature is no longer limited to "classic" users:
administrators and webmasters can use it too (no need to tell webmasters
that they can only change their password in the database)

  • Property svn:eol-style set to LF
File size: 10.7 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24// +-----------------------------------------------------------------------+
25// |                           initialization                              |
26// +-----------------------------------------------------------------------+
27
28define('PHPWG_ROOT_PATH','./');
29include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
30include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
31
32// +-----------------------------------------------------------------------+
33// | Check Access and exit when user status is not ok                      |
34// +-----------------------------------------------------------------------+
35
36check_status(ACCESS_FREE);
37
38// +-----------------------------------------------------------------------+
39// | Functions                                                             |
40// +-----------------------------------------------------------------------+
41
42/**
43 * checks the validity of input parameters, fills $page['errors'] and
44 * $page['infos'] and send an email with confirmation link
45 *
46 * @return bool (true if email was sent, false otherwise)
47 */
48function process_password_request()
49{
50  global $page, $conf;
51 
52  if (empty($_POST['username_or_email']))
53  {
54    array_push($page['errors'], l10n('Enter a username or email address'));
55    return false;
56  }
57 
58  $user_id = get_userid_by_email($_POST['username_or_email']);
59   
60  if (!is_numeric($user_id))
61  {
62    $user_id = get_userid($_POST['username_or_email']);
63  }
64
65  if (!is_numeric($user_id))
66  {
67    array_push($page['errors'], l10n('Invalid username or email'));
68    return false;
69  }
70
71  $userdata = getuserdata($user_id, false);
72
73  // password request is not possible for guest/generic users
74  $status = $userdata['status'];
75  if (is_a_guest($status) or is_generic($status))
76  {
77    array_push($page['errors'], l10n('Password reset is not allowed for this user'));
78    return false;
79  }
80
81  if (empty($userdata['email']))
82  {
83    array_push(
84      $page['errors'],
85      sprintf(
86        l10n('User "%s" has no email address, password reset is not possible'),
87        $userdata['username']
88        )
89      );
90    return false;
91  }
92
93  if (empty($userdata['activation_key']))
94  {
95    $activation_key = get_user_activation_key();
96
97    single_update(
98      USER_INFOS_TABLE,
99      array('activation_key' => $activation_key),
100      array('user_id' => $user_id)
101      );
102
103    $userdata['activation_key'] = $activation_key;
104  }
105
106  set_make_full_url();
107 
108  $message = l10n('Someone requested that the password be reset for the following user account:') . "\r\n\r\n";
109  $message.= sprintf(
110    l10n('Username "%s" on gallery %s'),
111    $userdata['username'],
112    get_gallery_home_url()
113    );
114  $message.= "\r\n\r\n";
115  $message.= l10n('To reset your password, visit the following address:') . "\r\n";
116  $message.= get_gallery_home_url().'/password.php?key='.$userdata['activation_key']."\r\n\r\n";
117  $message.= l10n('If this was a mistake, just ignore this email and nothing will happen.')."\r\n";
118
119  unset_make_full_url();
120
121  $message = trigger_event('render_lost_password_mail_content', $message);
122
123  $email_params = array(
124    'subject' => '['.$conf['gallery_title'].'] '.l10n('Password Reset'),
125    'content' => $message,
126    'email_format' => 'text/plain',
127    );
128
129  if (pwg_mail($userdata['email'], $email_params))
130  {
131    array_push($page['infos'], l10n('Check your email for the confirmation link'));
132    return true;
133  }
134  else
135  {
136    array_push($page['errors'], l10n('Error sending email'));
137    return false;
138  }
139}
140
141/**
142 *  checks the activation key: does it match the expected pattern? is it
143 *  linked to a user? is this user allowed to reset his password?
144 *
145 * @return mixed (user_id if OK, false otherwise)
146 */
147function check_password_reset_key($key)
148{
149  global $page;
150 
151  if (!preg_match('/^[a-z0-9]{20}$/i', $key))
152  {
153    array_push($page['errors'], l10n('Invalid key'));
154    return false;
155  }
156
157  $query = '
158SELECT
159    user_id,
160    status
161  FROM '.USER_INFOS_TABLE.'
162  WHERE activation_key = \''.$key.'\'
163;';
164  $result = pwg_query($query);
165
166  if (pwg_db_num_rows($result) == 0)
167  {
168    array_push($page['errors'], l10n('Invalid key'));
169    return false;
170  }
171 
172  $userdata = pwg_db_fetch_assoc($result);
173
174  if (is_a_guest($userdata['status']) or is_generic($userdata['status']))
175  {
176    array_push($page['errors'], l10n('Password reset is not allowed for this user'));
177    return false;
178  }
179
180  return $userdata['user_id'];
181}
182
183/**
184 * checks the passwords, checks that user is allowed to reset his password,
185 * update password, fills $page['errors'] and $page['infos'].
186 *
187 * @return bool (true if password was reset, false otherwise)
188 */
189function reset_password()
190{
191  global $page, $user, $conf;
192
193  if ($_POST['use_new_pwd'] != $_POST['passwordConf'])
194  {
195    array_push($page['errors'], l10n('The passwords do not match'));
196    return false;
197  }
198
199  if (isset($_GET['key']))
200  {
201    $user_id = check_password_reset_key($_GET['key']);
202    if (!is_numeric($user_id))
203    {
204      array_push($page['errors'], l10n('Invalid key'));
205      return false;
206    }
207  }
208  else
209  {
210    // we check the currently logged in user
211    if (is_a_guest() or is_generic())
212    {
213      array_push($page['errors'], l10n('Password reset is not allowed for this user'));
214      return false;
215    }
216
217    $user_id = $user['id'];
218  }
219   
220  single_update(
221    USERS_TABLE,
222    array($conf['user_fields']['password'] => $conf['pass_convert']($_POST['use_new_pwd'])),
223    array($conf['user_fields']['id'] => $user_id)
224    );
225
226  array_push($page['infos'], l10n('Your password has been reset'));
227
228  if (isset($_GET['key']))
229  {
230    array_push($page['infos'], '<a href="'.get_root_url().'identification.php">'.l10n('Login').'</a>');
231  }
232  else
233  {
234    array_push($page['infos'], '<a href="'.get_gallery_home_url().'">'.l10n('Return to home page').'</a>');
235  }
236
237  return true;
238}
239
240// +-----------------------------------------------------------------------+
241// | Process form                                                          |
242// +-----------------------------------------------------------------------+
243
244$page['errors'] = array();
245$page['infos'] = array();
246
247if (isset($_POST['submit']))
248{
249  check_pwg_token();
250 
251  if ('lost' == $_GET['action'])
252  {
253    if (process_password_request())
254    {
255      $page['action'] = 'none';
256    }
257  }
258
259  if ('reset' == $_GET['action'])
260  {
261    if (reset_password())
262    {
263      $page['action'] = 'none';
264    }
265  }
266}
267
268// +-----------------------------------------------------------------------+
269// | key and action                                                        |
270// +-----------------------------------------------------------------------+
271
272// a connected user can't reset the password from a mail
273if (isset($_GET['key']) and !is_a_guest())
274{
275  unset($_GET['key']);
276}
277
278if (isset($_GET['key']))
279{
280  $user_id = check_password_reset_key($_GET['key']);
281  if (is_numeric($user_id))
282  {
283    $userdata = getuserdata($user_id, false);
284    $page['username'] = $userdata['username'];
285    $template->assign('key', $_GET['key']);
286
287    if (!isset($page['action']))
288    {
289      $page['action'] = 'reset';
290    }
291  }
292  else
293  {
294    $page['action'] = 'none';
295  }
296}
297
298if (!isset($page['action']))
299{
300  if (!isset($_GET['action']))
301  {
302    $page['action'] = 'lost';
303  }
304  elseif (in_array($_GET['action'], array('lost', 'reset', 'none')))
305  {
306    $page['action'] = $_GET['action'];
307  }
308}
309
310if ('reset' == $page['action'] and !isset($_GET['key']) and (is_a_guest() or is_generic()))
311{
312  redirect(get_gallery_home_url());
313}
314
315if ('lost' == $page['action'] and !is_a_guest())
316{
317  redirect(get_gallery_home_url());
318}
319
320// +-----------------------------------------------------------------------+
321// | template initialization                                               |
322// +-----------------------------------------------------------------------+
323
324$title = l10n('Reset Password');
325if ('lost' == $page['action'])
326{
327  $title = l10n('Forgot your password?');
328
329  if (isset($_POST['username_or_email']))
330  {
331    $template->assign('username_or_email', stripslashes($_POST['username_or_email']));
332  }
333}
334
335$page['body_id'] = 'thePasswordPage';
336
337$template->set_filenames(array('password'=>'password.tpl'));
338$template->assign(
339  array(
340    'title' => $title,
341    'form_action'=> get_root_url().'password.php',
342    'action' => $page['action'],
343    'username' => isset($page['username']) ? $page['username'] : $user['username'],
344    'PWG_TOKEN' => get_pwg_token(),
345    )
346  );
347
348// +-----------------------------------------------------------------------+
349// |                        infos & errors display                         |
350// +-----------------------------------------------------------------------+
351
352$template->assign('errors', $page['errors']);
353$template->assign('infos', $page['infos']);
354
355// include menubar
356$themeconf = $template->get_template_vars('themeconf');
357if (!isset($themeconf['hide_menu_on']) OR !in_array('thePasswordPage', $themeconf['hide_menu_on']))
358{
359  include( PHPWG_ROOT_PATH.'include/menubar.inc.php');
360}
361
362// +-----------------------------------------------------------------------+
363// |                           html code display                           |
364// +-----------------------------------------------------------------------+
365
366include(PHPWG_ROOT_PATH.'include/page_header.php');
367$template->pparse('password');
368include(PHPWG_ROOT_PATH.'include/page_tail.php');
369
370?>
Note: See TracBrowser for help on using the repository browser.