user.module 80.6 KB
Newer Older
Dries Buytaert's avatar
   
Dries Buytaert committed
1
2
3
<?php
// $Id$

4
5
6
7
8
9
/**
 * Invokes hook_user() in every module.
 *
 * We cannot use module_invoke() for this, becuse the arguments need to
 * be passed by reference.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
10
11
12
function user_module_invoke($type, &$array, &$user) {
  foreach (module_list() as $module) {
    $function = $module .'_user';
Dries Buytaert's avatar
   
Dries Buytaert committed
13
    if (function_exists($function)) $function($type, $array, $user);
Dries Buytaert's avatar
   
Dries Buytaert committed
14
15
16
  }
}

Dries Buytaert's avatar
   
Dries Buytaert committed
17
function user_external_load($authname) {
Dries Buytaert's avatar
   
Dries Buytaert committed
18
  $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname);
Dries Buytaert's avatar
   
Dries Buytaert committed
19

Dries Buytaert's avatar
   
Dries Buytaert committed
20
21
  if ($user = db_fetch_object($result)) {
    return user_load($user);
Dries Buytaert's avatar
   
Dries Buytaert committed
22
23
24
25
26
27
  }
  else {
    return 0;
  }
}

28
29
30
31
32
33
34
35
36
37
/**
 * Fetch a user object.
 *
 * @param $array
 *   An associative array of attributes to search for in selecting the
 *   user, such as user name or email address.
 *
 * @return
 *   A fully-loaded $user object.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
38
function user_load($array = array()) {
39
40
  // Dynamically compose a SQL query:
  $query = '';
Dries Buytaert's avatar
   
Dries Buytaert committed
41

Dries Buytaert's avatar
   
Dries Buytaert committed
42
  foreach ($array as $key => $value) {
Dries Buytaert's avatar
   
Dries Buytaert committed
43
    if ($key == 'pass') {
Kjartan Mannes's avatar
Kjartan Mannes committed
44
      $query .= "u.$key = '". md5($value) ."' AND ";
45
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
46
    else {
47
      $query .= "LOWER(u.$key) = '". strtolower(check_query($value)) ."' AND ";
Dries Buytaert's avatar
   
Dries Buytaert committed
48
49
    }
  }
50
  $result = db_query_range("SELECT u.* FROM {users} u WHERE $query u.status < 3", 0, 1);
Dries Buytaert's avatar
   
Dries Buytaert committed
51
52

  $user = db_fetch_object($result);
Dries Buytaert's avatar
   
Dries Buytaert committed
53
  $user = drupal_unpack($user);
54
  user_module_invoke('load', $array, $user);
Dries Buytaert's avatar
   
Dries Buytaert committed
55

Dries Buytaert's avatar
   
Dries Buytaert committed
56
  $user->roles = array();
57
  $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid);
Dries Buytaert's avatar
   
Dries Buytaert committed
58
59
60
  while ($role = db_fetch_object($result)) {
    $user->roles[$role->rid] = $role->name;
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
61
62
63
64
65

  return $user;
}

function user_save($account, $array = array()) {
66
  // Dynamically compose a SQL query:
67
  $user_fields = user_fields();
Dries Buytaert's avatar
   
Dries Buytaert committed
68
  if ($account->uid) {
69
    user_module_invoke('update', $array, $account);
Dries Buytaert's avatar
   
Dries Buytaert committed
70

71
    $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid)));
Dries Buytaert's avatar
   
Dries Buytaert committed
72
    foreach ($array as $key => $value) {
Dries Buytaert's avatar
   
Dries Buytaert committed
73
      if ($key == 'pass') {
Dries Buytaert's avatar
   
Dries Buytaert committed
74
75
        $query .= "$key = '%s', ";
        $v[] = md5($value);
Dries Buytaert's avatar
   
Dries Buytaert committed
76
      }
77
      else if (substr($key, 0, 4) !== 'auth') {
78
        if (in_array($key, $user_fields)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
79
          // escape '%'s:
80
          $value = str_replace('%', '%%', $value);
Dries Buytaert's avatar
   
Dries Buytaert committed
81
82
          $query .= "$key = '%s', ";
          $v[] = $value;
Dries Buytaert's avatar
   
Dries Buytaert committed
83
84
85
86
        }
        else {
          $data[$key] = $value;
        }
Dries Buytaert's avatar
   
Dries Buytaert committed
87
88
      }
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
89
90
    $query .= "data = '%s', ";
    $v[] = serialize($data);
Dries Buytaert's avatar
   
Dries Buytaert committed
91

Dries Buytaert's avatar
   
Dries Buytaert committed
92
    db_query("UPDATE {users} SET $query changed = %d WHERE uid = %d", array_merge($v, array(time(), $account->uid)));
Dries Buytaert's avatar
   
Dries Buytaert committed
93

94
95
    // reload user roles if provided
    if (is_array($array['rid'])) {
96
      db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid);
Dries Buytaert's avatar
   
Dries Buytaert committed
97

98
      foreach ($array['rid'] as $rid) {
99
        db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $account->uid, $rid);
100
      }
Dries Buytaert's avatar
   
Dries Buytaert committed
101
102
    }

Dries Buytaert's avatar
   
Dries Buytaert committed
103
    $user = user_load(array('uid' => $account->uid));
Dries Buytaert's avatar
   
Dries Buytaert committed
104
105
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
106
107
    $array['created'] = time();
    $array['changed'] = time();
108
    $array['uid'] = db_next_id('{users}_uid');
Dries Buytaert's avatar
   
Dries Buytaert committed
109
110

    foreach ($array as $key => $value) {
Dries Buytaert's avatar
   
Dries Buytaert committed
111
      if ($key == 'pass') {
Dries Buytaert's avatar
   
Dries Buytaert committed
112
        $fields[] = check_query($key);
Dries Buytaert's avatar
   
Dries Buytaert committed
113
114
        $values[] = md5($value);
        $s[] = "'%s'";
Dries Buytaert's avatar
   
Dries Buytaert committed
115
      }
116
      else if (substr($key, 0, 4) !== 'auth') {
117
        if (in_array($key, $user_fields)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
118
          $fields[] = check_query($key);
Dries Buytaert's avatar
   
Dries Buytaert committed
119
120
          $values[] = $value;
          $s[] = "'%s'";
Dries Buytaert's avatar
   
Dries Buytaert committed
121
122
123
124
        }
        else {
          $data[$key] = $value;
        }
Dries Buytaert's avatar
   
Dries Buytaert committed
125
126
127
      }
    }

128
    $fields[] = 'data';
Dries Buytaert's avatar
   
Dries Buytaert committed
129
130
    $values[] = serialize($data);
    $s[] = "'%s'";
Dries Buytaert's avatar
   
Dries Buytaert committed
131

132
    db_query('INSERT INTO {users} ('. implode(', ', $fields) .') VALUES ('. implode(', ', $s) .')', $values);
Dries Buytaert's avatar
   
Dries Buytaert committed
133

134
135
    // Reload user roles (delete just to be safe).
    db_query('DELETE FROM {users_roles} WHERE uid = %d', $array['uid']);
Dries Buytaert's avatar
   
Dries Buytaert committed
136
137

    foreach ($array['rid'] as $rid) {
138
      db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $array['uid'], $rid);
Dries Buytaert's avatar
   
Dries Buytaert committed
139
140
    }

Dries Buytaert's avatar
   
Dries Buytaert committed
141
    $user = user_load(array('name' => $array['name']));
Dries Buytaert's avatar
   
Dries Buytaert committed
142

Dries Buytaert's avatar
   
Dries Buytaert committed
143
    module_invoke_all('user', 'insert', $array, $user);
Dries Buytaert's avatar
   
Dries Buytaert committed
144
145
146
  }

  foreach ($array as $key => $value) {
Dries Buytaert's avatar
   
Dries Buytaert committed
147
    if (substr($key, 0, 4) == 'auth') {
Dries Buytaert's avatar
   
Dries Buytaert committed
148
149
150
151
152
      $authmaps[$key] = $value;
    }
  }

  if ($authmaps) {
Dries Buytaert's avatar
   
Dries Buytaert committed
153
    user_set_authmaps($user, $authmaps);
Dries Buytaert's avatar
   
Dries Buytaert committed
154
155
156
157
158
  }

  return $user;
}

159
160
161
/**
 * Verify the syntax of the given name.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
162
function user_validate_name($name) {
163
164
165
166
167
168
169
  if (!$name) return t('You must enter a username.');
  if (substr($name, 0, 1) == ' ') return t('The username cannot begin with a space.');
  if (substr($name, -1) == ' ') return t('The username cannot end with a space.');
  if (ereg('  ', $name)) return t('The username cannot contain multiple spaces in a row.');
  if (ereg('[^ [:alnum:]@_.-]', $name)) return t('The username contains an illegal character.');
  if (ereg('@', $name) && !eregi('@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$', $name)) return t('The username is not a valid authentication ID.');
  if (strlen($name) > 56) return t('The username "%name" is too long: it must be less than 56 characters.', array('%name' => $name));
Dries Buytaert's avatar
   
Dries Buytaert committed
170
171
172
}

function user_validate_mail($mail) {
173
  if (!$mail) return t('You must enter an e-mail address.');
Dries Buytaert's avatar
   
Dries Buytaert committed
174
  if ($mail && !valid_email_address($mail)) {
175
    return t('The e-mail address "%mail" is not valid.', array('%mail' => $mail));
Dries Buytaert's avatar
   
Dries Buytaert committed
176
177
178
  }
}

Dries Buytaert's avatar
   
Dries Buytaert committed
179
function user_validate_picture($file, &$edit, $user) {
180
  // Initialize the picture:
Dries Buytaert's avatar
   
Dries Buytaert committed
181
182
  $edit['picture'] = $user->picture;

183
184
185
  // Check that uploaded file is an image, with a maximum file size
  // and maximum height/width.
  $extension = strtolower(strrchr($file->name, '.'));
Dries Buytaert's avatar
   
Dries Buytaert committed
186
  $size = getimagesize($file->path);
187
  list($maxwidth, $maxheight) = explode('x', variable_get('user_picture_dimensions', '85x85'));
Dries Buytaert's avatar
   
Dries Buytaert committed
188

189
  if ((!in_array($size[2], array(1, 2, 3))) || (!in_array($extension, array('.gif', '.jpg', '.png', '.jpeg')))) {
Dries Buytaert's avatar
   
Dries Buytaert committed
190
    form_set_error('picture', t('The uploaded file was not an image.'));
Dries Buytaert's avatar
   
Dries Buytaert committed
191
  }
192
  else if ($file->size > (variable_get('user_picture_file_size', '30') * 1000)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
193
    form_set_error('picture', t('The uploaded image is too large; the maximum file size is %a kB.', array('%a' => variable_get('user_picture_file_size', '30'))));
Dries Buytaert's avatar
   
Dries Buytaert committed
194
195
  }
  else if ($size[0] > $maxwidth || $size[1] > $maxheight) {
Dries Buytaert's avatar
   
Dries Buytaert committed
196
    form_set_error('picture', t('The uploaded image is too large; the maximum dimensions are %a pixels.', array('%a' => variable_get('user_picture_dimensions', '85x85'))));
Dries Buytaert's avatar
   
Dries Buytaert committed
197
  }
198
  else if ($file = file_save_upload('picture', variable_get('user_picture_path', 'pictures') . FILE_SEPARATOR .'picture-'. $user->uid . $extension, 1)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
199
200
201
    $edit['picture'] = $file->path;
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
202
    form_set_error('picture', t('Failed to upload the picture image; the "%directory" directory doesn\'t exist.', array('%directory' => variable_get('user_picture_path', 'pictures'))));
Dries Buytaert's avatar
   
Dries Buytaert committed
203
204
205
  }
}

206
function user_validate_authmap($account, $authname, $module) {
Dries Buytaert's avatar
   
Dries Buytaert committed
207
  $result = db_query("SELECT COUNT(*) from {authmap} WHERE uid != %d AND authname = '%s'", $account->uid, $authname);
Dries Buytaert's avatar
   
Dries Buytaert committed
208
  if (db_result($result) > 0) {
Dries Buytaert's avatar
   
Dries Buytaert committed
209
    $name = module_invoke($module, 'info', 'name');
210
    return t('The %u ID %s is already taken.', array('%u' => ucfirst($name), '%s' => "<i>$authname</i>"));
Dries Buytaert's avatar
   
Dries Buytaert committed
211
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
212
213
}

214
215
216
/**
 * Generate a random alphanumeric password.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
217
218
219
220
221
function user_password($length = 10) {
  // This variable contains the list of allowable characters for the
  // password.  Note that the number 0 and the letter 'O' have been
  // removed to avoid confusion between the two.  The same is true
  // of 'I' and 1.
222
223
  $allowable_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';

Dries Buytaert's avatar
   
Dries Buytaert committed
224
225
226
  // We see how many characters are in the allowable list:
  $len = strlen($allowable_characters);

227
  // Seed the random number generator with the microtime stamp.
Dries Buytaert's avatar
   
Dries Buytaert committed
228
  mt_srand((double)microtime() * 1000000);
Dries Buytaert's avatar
   
Dries Buytaert committed
229

230
231
  // Declare the password as a blank string.
  $pass = '';
Dries Buytaert's avatar
   
Dries Buytaert committed
232

233
  // Loop the number of times specified by $length.
Dries Buytaert's avatar
   
Dries Buytaert committed
234
235
236
237
238
239
240
241
  for ($i = 0; $i < $length; $i++) {

    // Each iteration, pick a random character from the
    // allowable string and append it to the password:
    $pass .= $allowable_characters[mt_rand(0, $len - 1)];
  }

  return $pass;
Dries Buytaert's avatar
   
Dries Buytaert committed
242
243
}

244
245
246
247
248
249
250
251
252
253
254
255
256
/**
 * Determine whether the user has a given privilege.
 *
 * @param $string
 *   The permission, such as "administer nodes", being checked for.
 *
 * @return
 *   TRUE iff the current user has the requested permission.
 *
 * All permission checks in Drupal should go through this function. This
 * way, we guarantee consistent behavior, and ensure that the superuser
 * can perform all actions.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
257
258
function user_access($string) {
  global $user;
Dries Buytaert's avatar
   
Dries Buytaert committed
259
  static $perm = 0;
Dries Buytaert's avatar
   
Dries Buytaert committed
260

Dries Buytaert's avatar
   
Dries Buytaert committed
261
  // User #1 has all priveleges:
Dries Buytaert's avatar
   
Dries Buytaert committed
262
263
264
265
  if ($user->uid == 1) {
    return 1;
  }

266
267
  // To reduce the number of SQL queries, we cache the user's permissions
  // in a static variable.
Dries Buytaert's avatar
   
Dries Buytaert committed
268
  if ($perm === 0) {
269
    $result = db_query('SELECT DISTINCT p.perm FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid);
Dries Buytaert's avatar
   
Dries Buytaert committed
270
271
272
273

    while ($row = db_fetch_object($result)) {
      $perm .= "$row->perm, ";
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
274
275
  }

Dries Buytaert's avatar
   
Dries Buytaert committed
276
  return strstr($perm, "$string, ");
Dries Buytaert's avatar
   
Dries Buytaert committed
277
278
}

279
280
281
/**
 * Send an e-mail message.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
282
function user_mail($mail, $subject, $message, $header) {
283
284
  if (variable_get('smtp_library', '') && file_exists(variable_get('smtp_library', ''))) {
    include_once variable_get('smtp_library', '');
285
    return user_mail_wrapper($mail, $subject, $message, $header);
Dries Buytaert's avatar
   
Dries Buytaert committed
286
287
  }
  else {
288
289
290
291
292
293
294
    /*
    ** Note: if you are having problems with sending mail, or mails look wrong
    ** when they are recieved you may have to modify the str_replace to suit
    ** your systems.
    **  - \r\n will work under dos and windows.
    **  - \n will work for linux, unix and BSDs.
    **  - \r will work for macs.
Dries Buytaert's avatar
   
Dries Buytaert committed
295
296
297
298
299
300
301
302
303
304
305
306
    **
    ** According to RFC 2646, it's quite rude to not wrap your e-mails:
    **
    ** "The Text/Plain media type is the lowest common denominator of
    ** Internet email, with lines of no more than 997 characters (by
    ** convention usually no more than 80), and where the CRLF sequence
    ** represents a line break [MIME-IMT]."
    **
    ** CRLF === \r\n
    **
    ** http://www.rfc-editor.org/rfc/rfc2646.txt
    **
307
    */
Dries Buytaert's avatar
   
Dries Buytaert committed
308
309
310
    return mail(
      $mail,
      user_mail_encode($subject),
311
      str_replace("\r", '', $message),
Dries Buytaert's avatar
   
Dries Buytaert committed
312
      "MIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8; format=flowed\nContent-transfer-encoding: 8Bit\n" . $header
Dries Buytaert's avatar
   
Dries Buytaert committed
313
    );
Dries Buytaert's avatar
   
Dries Buytaert committed
314
315
316
  }
}

317
function user_mail_encode($string, $charset = 'UTF-8') {
318
319
320
321
  /*
  ** Used to encodes mail headers that contain non US- ASCII
  ** characters.
  ** http://www.rfc-editor.org/rfc/rfc2047.txt
Kjartan Mannes's avatar
Kjartan Mannes committed
322
323
  **
  ** Notes:
324
  **   - Only encode strings that contain non-ASCII characters.
Kjartan Mannes's avatar
Kjartan Mannes committed
325
326
327
328
329
330
  **   - The chunks come in groupings of 4 bytes when using base64
  **     encoded.
  **   - trim() is used to ensure that no extra spacing is added by
  **     chunk_split() or preg_replace().
  **   - Using \n as the chunk separator may cause problems on some
  **     systems and may have to be changed to \r\n or \r.
331
  */
332
333
334
335
336
337
  if (!preg_match('/^[\x20-\x7E]*$/', $string)) {
    $chunk_size = 75 - 7 - strlen($charset);
    $chunk_size -= $chunk_size % 4;
    $string = trim(chunk_split(base64_encode($string), $chunk_size, "\n"));
    $string = trim(preg_replace('/^(.*)$/m', " =?$charset?B?\\1?=", $string));
  }
338
  return $string;
Dries Buytaert's avatar
   
Dries Buytaert committed
339
340
}

Dries Buytaert's avatar
   
Dries Buytaert committed
341
function user_deny($type, $mask) {
342
343
  $allow = db_fetch_object(db_query("SELECT * FROM {access} WHERE status = 1 AND type = '%s' AND LOWER('%s') LIKE LOWER(mask)", $type, $mask));
  $deny = db_fetch_object(db_query("SELECT * FROM {access} WHERE status = 0 AND type = '%s' AND LOWER('%s') LIKE LOWER(mask)", $type, $mask));
Dries Buytaert's avatar
   
Dries Buytaert committed
344

Dries Buytaert's avatar
   
Dries Buytaert committed
345
  return $deny && !$allow;
Dries Buytaert's avatar
   
Dries Buytaert committed
346
347
}

Dries Buytaert's avatar
   
Dries Buytaert committed
348
349
function user_fields() {
  static $fields;
Dries Buytaert's avatar
   
Dries Buytaert committed
350

Dries Buytaert's avatar
   
Dries Buytaert committed
351
  if (!$fields) {
352
    $result = db_query('SELECT * FROM {users} WHERE uid = 1');
353
354
355
    if (db_num_rows($result)) {
      $fields = array_keys(db_fetch_array($result));
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
356
357
    else {
      // Make sure we return the default fields at least
Dries Buytaert's avatar
   
Dries Buytaert committed
358
      $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'changed', 'status', 'timezone', 'language', 'init', 'data');
Dries Buytaert's avatar
   
Dries Buytaert committed
359
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
360
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
361

Dries Buytaert's avatar
   
Dries Buytaert committed
362
  return $fields;
Dries Buytaert's avatar
   
Dries Buytaert committed
363
364
}

365
366
367
/**
 * Implementation of hook_perm().
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
368
function user_perm() {
369
  return array('administer users', 'access user list');
Dries Buytaert's avatar
   
Dries Buytaert committed
370
371
}

372
373
374
375
376
/**
 * Implementation of hook_file_download().
 *
 * Ensure that user pictures (avatars) are always downloadable.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
377
function user_file_download($file) {
378
  if (strpos($file, variable_get('user_picture_path', 'pictures') . FILE_SEPARATOR . 'picture-') === 0) {
Dries Buytaert's avatar
   
Dries Buytaert committed
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
    list($width, $height, $type, $attr) = getimagesize(file_create_path($file));
    $types = array(
      IMAGETYPE_GIF => 'image/gif',
      IMAGETYPE_JPEG => 'image/jpeg',
      IMAGETYPE_PNG => 'image/png',
      IMAGETYPE_SWF => 'application/x-shockwave-flash',
      IMAGETYPE_PSD => 'image/psd',
      IMAGETYPE_BMP => 'image/bmp',
      IMAGETYPE_TIFF_II => 'image/tiff',
      IMAGETYPE_TIFF_MM  => 'image/tiff',
      IMAGETYPE_JPC => 'application/octet-stream',
      IMAGETYPE_JP2 => 'image/jp2',
      IMAGETYPE_JPX => 'application/octet-stream',
      IMAGETYPE_JB2 => 'application/octet-stream',
      IMAGETYPE_SWC => 'application/x-shockwave-flash',
      IMAGETYPE_IFF => 'image/iff',
      IMAGETYPE_WBMP => 'image/vnd.wap.wbmp',
      IMAGETYPE_XBM => 'image/xbm'
    );
    return array('Content-type: '. $types[$type]);
  }
}

402
403
404
/**
 * Implementation of hook_search().
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
405
function user_search($keys) {
Dries Buytaert's avatar
   
Dries Buytaert committed
406
  $find = array();
407

408
409
  // Replace wildcards with MySQL/PostgreSQL wildcards.
  $keys = str_replace('*', '%', $keys);
410

411
  $result = db_query_range("SELECT * FROM {users} WHERE LOWER(name) LIKE '%%%s%%'", strtolower($keys), 0, 20);
Dries Buytaert's avatar
   
Dries Buytaert committed
412
  while ($account = db_fetch_object($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
413
    $find[] = array('title' => $account->name, 'link' => url("user/$account->uid/view"), 'user' => $account->name);
Dries Buytaert's avatar
   
Dries Buytaert committed
414
  }
415
  return array(t('Matching users'), $find);
Dries Buytaert's avatar
   
Dries Buytaert committed
416
417
}

418
419
420
/**
 * Implementation of hook_user().
 */
Dries Buytaert's avatar
Dries Buytaert committed
421
function user_user($type, &$edit, &$user) {
422
  if ($type == 'view') {
Dries Buytaert's avatar
Dries Buytaert committed
423
    return array(t('History') => form_item(t('Member for'), format_interval(time() - $user->created)));
424
425
426
  }
}

427
428
429
430
/**
 * Implementation of hook_block().
 */
function user_block($op = 'list', $delta = 0) {
Dries Buytaert's avatar
   
Dries Buytaert committed
431
432
  global $user;

433
434
435
436
437
  if ($op == 'list') {
     $blocks[0]['info'] = t('User login');
     $blocks[1]['info'] = t('Navigation');
     $blocks[2]['info'] = t('Who\'s new');
     $blocks[3]['info'] = t('Who\'s online');
438

439
     return $blocks;
440
441
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
442
443
    $block = array();

Dries Buytaert's avatar
   
Dries Buytaert committed
444
445
    switch ($delta) {
      case 0:
Dries Buytaert's avatar
   
Dries Buytaert committed
446

447
        if (!$user->uid) {
448
449
          // For usability's sake, avoid showing two login forms on one page.
          if (arg(0) == 'user' && arg(1) != 'view') {
Dries Buytaert's avatar
   
Dries Buytaert committed
450
451
452
            return;
          }

453
          $edit = $_POST['edit'];
Dries Buytaert's avatar
   
Dries Buytaert committed
454

Dries Buytaert's avatar
   
Dries Buytaert committed
455
456
          $output = "<div class=\"user-login-block\">\n";

457
458
          // Save the referer.  We record where the user came from such
          // that we can redirect him after having completed the login form.
Dries Buytaert's avatar
Dries Buytaert committed
459

460
          if (empty($edit)) {
461
            $edit['destination'] = $_GET['q'];
462
          }
463
464
465
466
467
468
469
470
          // NOTE: special care needs to be taken because on pages with forms,
          // such as node and comment submission pages, the $edit variable
          // might already be set.

          $output .= form_hidden('destination', $edit['destination']);
          $output .= form_textfield(t('Username'), 'name', $edit['name'], 15, 64);
          $output .= form_password(t('Password'), 'pass', $pass, 15, 64);
          $output .= form_submit(t('Log in'));
Dries Buytaert's avatar
   
Dries Buytaert committed
471
          $output .= "</div>\n";
Dries Buytaert's avatar
   
Dries Buytaert committed
472

473
          $output  = form($output, 'post', url('user/login'));
Dries Buytaert's avatar
   
Dries Buytaert committed
474

475
476
          if (variable_get('user_register', 1)) {
            $items[] = l(t('Create new account'), 'user/register', array('title' => t('Create a new user account.')));
Dries Buytaert's avatar
   
Dries Buytaert committed
477
          }
478
          $items[] = l(t('Request new password'), 'user/password', array('title' => t('Request new password via e-mail.')));
Dries Buytaert's avatar
   
Dries Buytaert committed
479

480
          $output .= theme('item_list', $items);
481

482
483
          $block['subject'] = t('User login');
          $block['content'] = $output;
Dries Buytaert's avatar
   
Dries Buytaert committed
484
        }
Dries Buytaert's avatar
Dries Buytaert committed
485
        return $block;
486
      case 1:
Dries Buytaert's avatar
   
Dries Buytaert committed
487
        if ($menu = theme('menu_tree')) {
488
489
           $block['subject'] = $user->uid ? $user->name : t('Navigation');
           $block['content'] = '<div class="menu">'. $menu .'</div>';
Dries Buytaert's avatar
   
Dries Buytaert committed
490
        }
491
        return $block;
Dries Buytaert's avatar
   
Dries Buytaert committed
492
      case 2:
493
494
        if (user_access('access content')) {
          $result = db_query_range('SELECT uid, name FROM {users} WHERE status != 0 ORDER BY uid DESC', 0, 5);
495
          while ($account = db_fetch_object($result)) {
496
            $items[] = format_name($account);
497
          }
Dries Buytaert's avatar
   
Dries Buytaert committed
498

499
          $output = theme('user_list', $items);
Dries Buytaert's avatar
   
Dries Buytaert committed
500

501
502
          $block['subject'] = t('Who\'s new');
          $block['content'] = $output;
503
504
          return $block;
        }
Dries Buytaert's avatar
   
Dries Buytaert committed
505
      case 3:
506
507
508
        if (user_access('access content')) {
          // Count users with activity in the past defined period.
          $time_period = variable_get('user_block_seconds_online', 2700);
Dries Buytaert's avatar
   
Dries Buytaert committed
509

510
511
512
          // Perform database queries to gather online user lists.
          $guests = db_fetch_object(db_query('SELECT COUNT(DISTINCT sid) AS count FROM {sessions} WHERE timestamp >= %d AND uid = 0', time() - $time_period));
          $users = db_query('SELECT DISTINCT uid, MAX(timestamp) AS max_timestamp FROM {sessions} WHERE timestamp >= %d AND uid != 0 GROUP BY uid ORDER BY max_timestamp DESC', time() - $time_period );
Dries Buytaert's avatar
   
Dries Buytaert committed
513
          $total_users = db_num_rows($users);
Dries Buytaert's avatar
   
Dries Buytaert committed
514

515
          // Format the output with proper grammar.
Dries Buytaert's avatar
   
Dries Buytaert committed
516
          if ($total_users == 1 && $guests->count == 1) {
517
            $output = t('There is currently %members and %visitors online.', array('%members' => format_plural($total_users, '1 user', '%count users'), '%visitors' => format_plural($guests->count, '1 guest', '%count guests')));
Dries Buytaert's avatar
   
Dries Buytaert committed
518
519
          }
          else {
520
            $output = t('There are currently %members and %visitors online.', array('%members' => format_plural($total_users, '1 user', '%count users'), '%visitors' => format_plural($guests->count, '1 guest', '%count guests')));
Dries Buytaert's avatar
   
Dries Buytaert committed
521
522
          }

523
          if (user_access('access user list') && $total_users) {
Dries Buytaert's avatar
   
Dries Buytaert committed
524

525
526
            // Display a list of currently online users.
            $max_users = variable_get('user_block_max_list_count', 10);
Dries Buytaert's avatar
   
Dries Buytaert committed
527
528
            if ($max_users) {
              $items = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
529

Dries Buytaert's avatar
   
Dries Buytaert committed
530
              while ($max_users-- && $uid = db_fetch_object($users)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
531
                $items[] = format_name(user_load(array('uid' => $uid->uid)));
Dries Buytaert's avatar
   
Dries Buytaert committed
532
533
534
              }

              if ($items) {
Dries Buytaert's avatar
   
Dries Buytaert committed
535
                if (db_fetch_object($users)) {
536
                  $items[] = '...';
Dries Buytaert's avatar
   
Dries Buytaert committed
537
                }
538
                $output .= theme('item_list', $items, t('Online users:'));
Dries Buytaert's avatar
   
Dries Buytaert committed
539
              }
Dries Buytaert's avatar
   
Dries Buytaert committed
540
            }
Dries Buytaert's avatar
   
Dries Buytaert committed
541
          }
542
543
          $block['subject'] = t('Who\'s online');
          $block['content'] = $output;
Dries Buytaert's avatar
   
Dries Buytaert committed
544
        }
Dries Buytaert's avatar
   
Dries Buytaert committed
545
        return $block;
Dries Buytaert's avatar
   
Dries Buytaert committed
546
547
    }
  }
548
549
}

Dries Buytaert's avatar
   
Dries Buytaert committed
550
551
552
553
554
555
556
557
558
559
function theme_user_picture($account) {
  if (variable_get('user_pictures', 0)) {
    if ($account->picture && file_exists($account->picture)) {
      $picture = file_create_url($account->picture);
    }
    else if (variable_get('user_picture_default', '')) {
      $picture = variable_get('user_picture_default', '');
    }

    if ($picture) {
560
      $picture = "<img src=\"$picture\" alt=\"" . t('%user\'s picture', array('%user' => $account->name ? $account->name : t(variable_get('anonymous', 'Anonymous')))) . '" />';
Dries Buytaert's avatar
   
Dries Buytaert committed
561
      if ($account->uid) {
562
        $picture = l($picture, "user/view/$account->uid", array('title' => t('View user profile.')));
Dries Buytaert's avatar
   
Dries Buytaert committed
563
564
565
566
567
568
569
      }

      return "<div class=\"picture\">$picture</div>";
    }
  }
}

570
function theme_user_profile($account, $fields) {
Dries Buytaert's avatar
   
Dries Buytaert committed
571
572
  $output = "<div class=\"profile\">\n";
  $output .= theme('user_picture', $account);
573
574
575
  foreach ($fields as $category => $value) {
    $output .= "<h2>$category</h2>$value";
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
576
577
578
579
580
  $output .= "</div>\n";

  return $output;
}

Dries Buytaert's avatar
   
Dries Buytaert committed
581
function theme_user_list($items, $title = NULL) {
582
  return theme('item_list', $items, $title);
Dries Buytaert's avatar
   
Dries Buytaert committed
583
584
}

Dries Buytaert's avatar
   
Dries Buytaert committed
585
/**
Dries Buytaert's avatar
   
Dries Buytaert committed
586
 * Implementation of hook_menu().
Dries Buytaert's avatar
   
Dries Buytaert committed
587
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
588
function user_menu() {
Dries Buytaert's avatar
   
Dries Buytaert committed
589
  global $user;
Dries Buytaert's avatar
   
Dries Buytaert committed
590

Dries Buytaert's avatar
   
Dries Buytaert committed
591
  $items = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
592

Dries Buytaert's avatar
   
Dries Buytaert committed
593
594
595
596
597
598
599
  $access = user_access('administer users');

  if (arg(0) == 'user' && is_numeric(arg(1))) {
    $items[] = array('path' => 'user/'. arg(1), 'title' => t('user'),
      'callback' => 'user_page', 'access' => TRUE);
    // Add the edit menu:
    if ($access) $function = 'user_admin_edit';
Dries Buytaert's avatar
   
Dries Buytaert committed
600
    else $function = 'user_page';
Dries Buytaert's avatar
   
Dries Buytaert committed
601
602
603
    $items[] = array('path' => 'user/'. arg(1) .'/edit', 'title' => t('edit'),
      'callback' => $function, 'access' => $access || $user->uid == arg(1),
      'type' => MENU_LOCAL_TASK);
Dries Buytaert's avatar
   
Dries Buytaert committed
604
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

  if ($user->uid) {
    $items[] = array('path' => "user/$user->uid", 'title' => t('my account'),
      'callback' => 'user_page', 'access' => TRUE);
    $items[] = array('path' => 'logout', 'title' => t('log out'),
      'access' => TRUE,
      'callback' => 'user_logout',
      'weight' => 10);
  }
  else {
    $items[] = array('path' => 'logout', 'title' => t('log out'),
      'callback' => 'user_logout', 'access' => FALSE);
  }

  $items[] = array('path' => 'user', 'title' => t('user'),
    'callback' => 'user_page', 'access' => TRUE,
    'type' => MENU_CALLBACK);
  $items[] = array('path' => 'user/login', 'title' => t('log in'),
Dries Buytaert's avatar
   
Dries Buytaert committed
623
624
625
626
627
    'callback' => 'user_page', 'access' => TRUE, 'type' => MENU_CALLBACK);
  $items[] = array('path' => 'user/register', 'title' => t('register'),
    'callback' => 'user_page', 'access' => TRUE, 'type' => MENU_CALLBACK);
  $items[] = array('path' => 'user/password', 'title' => t('request new password'),
    'callback' => 'user_page', 'access' => TRUE, 'type' => MENU_CALLBACK);
Dries Buytaert's avatar
   
Dries Buytaert committed
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665

  $items[] = array('path' => 'admin/user', 'title' => t('users'),
    'callback' => 'user_admin', 'access' => $access);

  // Tabs:
  $items[] = array('path' => 'admin/user/create', 'title' => t('add user'),
    'callback' => 'user_admin', 'access' => $access,
    'type' => MENU_LOCAL_TASK);
  $items[] = array('path' => 'admin/user/configure', 'title' => t('configure'),
    'callback' => 'user_configure', 'access' => $access,
    'type' => MENU_LOCAL_TASK);
  if (module_exist('search')) {
    $items[] = array('path' => 'admin/user/search', 'title' => t('search'),
      'callback' => 'user_admin', 'access' => $access,
      'type' => MENU_LOCAL_TASK);
  }

  // Sub-tabs:
  $items[] = array('path' => 'admin/user/configure/settings', 'title' => t('settings'),
    'callback' => 'user_configure', 'access' => $access,
    'type' => MENU_LOCAL_SUBTASK);
  $items[] = array('path' => 'admin/user/configure/access', 'title' => t('access rules'),
    'callback' => 'user_configure', 'access' => $access,
    'type' => MENU_LOCAL_SUBTASK);
  $items[] = array('path' => 'admin/user/configure/access/mail', 'title' => t('e-mail rules'),
    'callback' => 'user_configure', 'access' => $access,
    'type' => MENU_LOCAL_SUBTASK);
  $items[] = array('path' => 'admin/user/configure/access/user', 'title' => t('name rules'),
    'callback' => 'user_configure', 'access' => $access,
    'type' => MENU_LOCAL_SUBTASK);
  $items[] = array('path' => 'admin/user/configure/role', 'title' => t('roles'),
    'callback' => 'user_configure', 'access' => $access,
    'type' => MENU_LOCAL_SUBTASK);
  $items[] = array('path' => 'admin/user/configure/permission', 'title' => t('permissions'),
    'callback' => 'user_configure', 'access' => $access,
    'type' => MENU_LOCAL_SUBTASK);

  return $items;
Dries Buytaert's avatar
   
Dries Buytaert committed
666
667
}

668
669
670
/**
 * Called by authentication modules in order to edit/view their authmap information.
 */
671
function user_get_authname($account, $module) {
Dries Buytaert's avatar
   
Dries Buytaert committed
672
  $result = db_query("SELECT authname FROM {authmap} WHERE uid = %d AND module = '%s'", $account->uid, $module);
673
674
675
  return db_result($result);
}

676
677
678
679
/**
 * Accepts an user object, $account, or a DA name and returns an associative
 * array of modules and DA names. Called at external login.
 */
680
function user_get_authmaps($authname = NULL) {
Dries Buytaert's avatar
   
Dries Buytaert committed
681
  $result = db_query("SELECT authname, module FROM {authmap} WHERE authname = '%s'", $authname);
Dries Buytaert's avatar
   
Dries Buytaert committed
682
683
684
685
686
687
688
689
690
691
692
693
694
  if (db_num_rows($result) > 0) {
    while ($authmap = db_fetch_object($result)) {
      $authmaps[$authmap->module] = $authmap->authname;
    }
    return $authmaps;
  }
  else {
    return 0;
  }
}

function user_set_authmaps($account, $authmaps) {
  foreach ($authmaps as $key => $value) {
695
    $module = explode('_', $key, 2);
Dries Buytaert's avatar
   
Dries Buytaert committed
696
    if ($value) {
697
      db_query("UPDATE {authmap} SET authname = '%s' WHERE uid = %d AND module = '%s'", $value, $account->uid, $module['1']);
Dries Buytaert's avatar
   
Dries Buytaert committed
698
699
      if (!db_affected_rows()) {
        db_query("INSERT INTO {authmap} (authname, uid, module) VALUES ('%s', %d, '%s')", $value, $account->uid, $module[1]);
Dries Buytaert's avatar
   
Dries Buytaert committed
700
701
702
      }
    }
    else {
703
      db_query("DELETE FROM {authmap} WHERE uid = %d AND module = '%s'", $account->uid, $module['1']);
Dries Buytaert's avatar
   
Dries Buytaert committed
704
705
706
707
708
    }
  }
}

function user_auth_help_links() {
709
  $links = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
710
  foreach (module_list() as $module) {
711
    if (module_hook($module, 'auth')) {
Dries Buytaert's avatar
   
Dries Buytaert committed
712
      $links[] = l(module_invoke($module, 'info', 'name'), "user/help#$module");
Dries Buytaert's avatar
   
Dries Buytaert committed
713
714
715
716
717
718
719
    }
  }
  return $links;
}

/*** User features *********************************************************/

720
function user_login($edit = array(), $msg = '') {
Dries Buytaert's avatar
   
Dries Buytaert committed
721
  global $user, $base_url;
Dries Buytaert's avatar
   
Dries Buytaert committed
722

723
  // If we are already logged on, go to the user page instead.
Dries Buytaert's avatar
   
Dries Buytaert committed
724
  if ($user->uid) {
Dries Buytaert's avatar
Dries Buytaert committed
725
    drupal_goto('user');
Dries Buytaert's avatar
   
Dries Buytaert committed
726
727
  }

Dries Buytaert's avatar
   
Dries Buytaert committed
728
  if (user_deny('user', $edit['name'])) {
729
    $error = t('The name "%s" has been denied access.', array('%s' => $edit['name']));
Dries Buytaert's avatar
   
Dries Buytaert committed
730
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
731
  else if ($edit['name'] && $edit['pass']) {
Dries Buytaert's avatar
   
Dries Buytaert committed
732

733
    // Try to log in the user locally:
Dries Buytaert's avatar
   
Dries Buytaert committed
734
    if (!$user->uid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
735
736
      $name = $edit['name'];
      $pass = $edit['pass'];
737
      $user = user_load(array('name' => $name, 'pass' => $pass, 'status' => 1));
Dries Buytaert's avatar
   
Dries Buytaert committed
738
739
    }

740
741
    // Strip name and server from ID:
    if ($server = strrchr($edit['name'], '@')) {
Dries Buytaert's avatar
   
Dries Buytaert committed
742
      $name = substr($edit['name'], 0, strlen($edit['name']) - strlen($server));
743
      $server = substr($server, 1);
Dries Buytaert's avatar
   
Dries Buytaert committed
744
      $pass = $edit['pass'];
Dries Buytaert's avatar
   
Dries Buytaert committed
745
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
746

747
748
    // When possible, determine corresponding external auth source. Invoke
    // source, and log in user if successful:
Dries Buytaert's avatar
   
Dries Buytaert committed
749
    if (!$user->uid && $server && $result = user_get_authmaps("$name@$server")) {
750
      if (module_invoke(key($result), 'auth', $name, $pass, $server)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
751
        $user = user_external_load("$name@$server");
Dries Buytaert's avatar
   
Dries Buytaert committed
752
        watchdog('user', "external load: $name@$server, module: ". key($result));
Dries Buytaert's avatar
   
Dries Buytaert committed
753
754
      }
      else {
755
        $error = t('Invalid password for %s.', array('%s' => "<i>$name@$server</i>"));
Dries Buytaert's avatar
   
Dries Buytaert committed
756
757
758
      }
    }

759
760
    // Try each external authentication source in series. Register user if
    // successful.
Dries Buytaert's avatar
   
Dries Buytaert committed
761
    else if (!$user->uid && $server) {
Dries Buytaert's avatar
   
Dries Buytaert committed
762
      foreach (module_list() as $module) {
763
764
765
        if (module_hook($module, 'auth')) {
          if (module_invoke($module, 'auth', $name, $pass, $server)) {
            if (variable_get('user_register', 1) == 1 && !user_load(array('name' => "$name@$server"))) { // Register this new user.
Dries Buytaert's avatar
   
Dries Buytaert committed
766
              $user = user_save('', array('name' => "$name@$server", 'pass' => user_password(), 'init' => "$name@$server", 'status' => 1, "authname_$module" => "$name@$server", 'rid' => array(_user_authenticated_id())));
Dries Buytaert's avatar
   
Dries Buytaert committed
767
              watchdog('user', "new user: $name@$server ($module ID)", l(t('edit user'), "user/$user->uid/edit"));
Dries Buytaert's avatar
   
Dries Buytaert committed
768
769
770
771
772
773
774
775
              break;
            }
          }
        }
      }
    }

    if ($user->uid) {
776
      watchdog('user', 'session opened for "'. $user->name .'"');
Dries Buytaert's avatar
   
Dries Buytaert committed
777

778
      // Update the user table timestamp noting user has logged in.
Dries Buytaert's avatar
   
Dries Buytaert committed
779
      db_query("UPDATE {users} SET changed = '%d' WHERE uid = '%s'", time(), $user->uid);
Dries Buytaert's avatar
   
Dries Buytaert committed
780

781
      user_module_invoke('login', $edit, $user);
Dries Buytaert's avatar
   
Dries Buytaert committed
782

783
784
      // If the user wants to be remembered, set the proper cookie such
      // that the session won't expire.
Dries Buytaert's avatar
   
Dries Buytaert committed
785
      $path = preg_replace("/.+\/\/[^\/]+(.*)/", "\$1/", $base_url);
Dries Buytaert's avatar
   
Dries Buytaert committed
786
      setcookie(session_name(), session_id(), FALSE, $path);
Dries Buytaert's avatar
   
Dries Buytaert committed
787

788
789
      // Redirect the user to the page he logged on from.
      drupal_goto($edit['destination']);
Dries Buytaert's avatar
   
Dries Buytaert committed
790
791
792
    }
    else {
      if (!$error) {
793
        $error = t('Sorry.  Unrecognized username or password.') .' '. l(t('Have you forgotten your password?'), 'user/password');
Dries Buytaert's avatar
   
Dries Buytaert committed
794
795
      }
      if ($server) {
Dries Buytaert's avatar
   
Dries Buytaert committed
796
        watchdog('user', "failed login for '$name@$server': $error");
Dries Buytaert's avatar
   
Dries Buytaert committed
797
798
      }
      else {
Dries Buytaert's avatar
   
Dries Buytaert committed
799
        watchdog('user', "failed login for '$name': $error");
Dries Buytaert's avatar
   
Dries Buytaert committed
800
801
802
803
      }
    }
  }

804
  // Display error message (if any):
Dries Buytaert's avatar
   
Dries Buytaert committed
805
  if ($error) {
Dries Buytaert's avatar
   
Dries Buytaert committed
806
    drupal_set_message($error, 'error');
Dries Buytaert's avatar
   
Dries Buytaert committed
807
808
  }

809
810
  // Save the referrer.  We record where the user came from such that we
  // can redirect him after having completed the login form.
811
  if (empty($edit)) {
812
    $edit['destination'] = $_GET['q'];
Dries Buytaert's avatar
   
Dries Buytaert committed
813
  }
814
  $output .= form_hidden('destination', $edit['destination']);
Dries Buytaert's avatar
   
Dries Buytaert committed
815

816
  // Display login form:
Dries Buytaert's avatar
   
Dries Buytaert committed
817
818
819
  if ($msg) {
    $output .= "<p>$msg</p>";
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
820
  if (count(user_auth_help_links()) > 0) {
821
    $output .= form_textfield(t('Username'), 'name', $edit['name'], 30, 64, t('Enter your %s username, or an ID from one of our affiliates: %a.', array('%s' => variable_get('site_name', 'local'), '%a' => implode(', ', user_auth_help_links()))));
Dries Buytaert's avatar
   
Dries Buytaert committed
822
823
  }
  else {
824
    $output .= form_textfield(t('Username'), 'name', $edit['name'], 30, 64, t('Enter your %s username.', array('%s' => variable_get('site_name', 'local'))));
Dries Buytaert's avatar
   
Dries Buytaert committed
825
  }
826
827
828
829
830
  $output .= form_password(t('Password'), 'pass', $pass, 30, 64, t('Enter the password that accompanies your username.'));
  $output .= form_submit(t('Log in'));
  $items[] = l(t('Request new password'), 'user/password');
  if (variable_get('user_register', 1)) {
    $items[] = l(t('Create new account'), 'user/register');
831
  }
832
  $output .= theme('item_list', $items);
Dries Buytaert's avatar
   
Dries Buytaert committed
833

Dries Buytaert's avatar
   
Dries Buytaert committed
834
835
  $output  = form_group(t('User login'), $output);

836
  return form($output, 'post', url('user/login'));
Dries Buytaert's avatar
   
Dries Buytaert committed
837
838
}

839
function _user_authenticated_id() {
Dries Buytaert's avatar
   
Dries Buytaert committed
840
  return db_result(db_query("SELECT rid FROM {role} WHERE name = 'authenticated user'"));
841
842
}

843
844
845
/**
 * Menu callback; logs the current user out, and redirects to the home page.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
846
847
848
849
function user_logout() {
  global $user;

  if ($user->uid) {
850
    watchdog('user', 'session closed for "'. $user->name .'"');
Dries Buytaert's avatar
   
Dries Buytaert committed
851

852
    // Destroy the current session:
Dries Buytaert's avatar
   
Dries Buytaert committed
853
    session_destroy();
Dries Buytaert's avatar
   
Dries Buytaert committed
854
    module_invoke_all('user', 'logout', NULL, $user);
Dries Buytaert's avatar
   
Dries Buytaert committed
855
856
857
    unset($user);
  }

Dries Buytaert's avatar
Dries Buytaert committed
858
  drupal_goto();
Dries Buytaert's avatar
   
Dries Buytaert committed
859
860
861
}

function user_pass($edit = array()) {
Dries Buytaert's avatar
   
Dries Buytaert committed
862
863
  global $base_url;

Dries Buytaert's avatar
   
Dries Buytaert committed
864
  if ($edit['name']) {
865
    $account = db_fetch_object(db_query("SELECT uid, name, mail FROM {users} WHERE status = 1 AND LOWER(name) = '%s'", strtolower($edit['name'])));
Dries Buytaert's avatar
   
Dries Buytaert committed
866
    if (!$account) form_set_error('name', t('Sorry. The username "<i>%s</i>" is not recognized.', array('%s' => $edit['name'])));
867
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
868
  else if ($edit['mail']) {
869
    $account = db_fetch_object(db_query("SELECT uid, name, mail FROM {users} WHERE status = 1 AND LOWER(mail) = '%s'", strtolower($edit['mail'])));
Dries Buytaert's avatar
   
Dries Buytaert committed
870
    if (!$account) form_set_error('name', t('Sorry. The e-mail address "<i>%s</i>" is not recognized.', array('%s' => $edit['mail'])));
Kjartan Mannes's avatar
Kjartan Mannes committed
871
872
  }
  if ($account) {
Dries Buytaert's avatar
   
Dries Buytaert committed
873

874
      $from = variable_get('site_mail', ini_get('sendmail_from'));
Dries Buytaert's avatar
   
Dries Buytaert committed
875
876
      $pass = user_password();

877
      // Save new password:
Dries Buytaert's avatar
   
Dries Buytaert committed
878
      user_save($account, array('pass' => $pass));
Dries Buytaert's avatar
   
Dries Buytaert committed
879

880
881
882
883
      // Mail new password:
      $variables = array('%username' => $account->name, '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $account->mail, '%date' => format_date(time()), '%login_uri' => url('user/login', NULL, NULL, TRUE), '%edit_uri' => url('user/edit', NULL, NULL, TRUE));
      $subject = _user_mail_text('pass_subject', $variables);
      $body = _user_mail_text('pass_body', $variables);
884
      $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from";
Dries Buytaert's avatar
   
Dries Buytaert committed
885
      $mail_success = user_mail($account->mail, $subject, $body, $headers);
Dries Buytaert's avatar
   
Dries Buytaert committed
886

Dries Buytaert's avatar
   
Dries Buytaert committed
887
      if ($mail_success) {
888
889
        watchdog('user', 'mail password: "'. $account->name .'" &lt;'. $account->mail .'&gt;');
        return t('Your password and further instructions have been sent to your e-mail address.');
Dries Buytaert's avatar
   
Dries Buytaert committed
890
891
      }
      else {
892
893
        watchdog('error', 'error mailing new password: "'. $account->name .'" &lt;'. $account->mail .'&gt;');
        return t('Unable to send mail. Please contact the site admin.');
Dries Buytaert's avatar
   
Dries Buytaert committed
894
      }
Dries Buytaert's avatar
   
Dries Buytaert committed
895
896
    }
    else {
897

898
899
900
901
902
903
904
905
    // Display form:
    $output .= '<p>'. t('Enter your username <strong><em>or</em></strong> your e-mail address.') .'</p>';
    $output .= form_textfield(t('Username'), 'name', $edit['name'], 30, 64);
    $output .= form_textfield(t('E-mail address'), 'mail', $edit['mail'], 30, 64);
    $output .= form_submit(t('E-mail new password'));
    $items[] = l(t('Log in'), 'user/login');
    if (variable_get('user_register', 1)) {
      $items[] = l(t('Create new account'), 'user/register');
906
    }
907
    $output .= theme('item_list', $items);
Dries Buytaert's avatar
   
Dries Buytaert committed
908
    $output  = form_group(t('Request new password'), $output);
909
    return form($output, 'post', url('user/password'));
Dries Buytaert's avatar
   
Dries Buytaert committed
910
911
912
913
  }
}

function user_register($edit = array()) {
Dries Buytaert's avatar
   
Dries Buytaert committed
914
  global $user, $base_url;
915

916
  // If we are already logged on, go to the user page instead.
917
  if ($user->uid) {
918
    drupal_goto('user/edit');
919
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
920

921
  if ($edit) {
Dries Buytaert's avatar
   
Dries Buytaert committed
922
    if ($error = user_validate_name($edit['name'])) {
Dries Buytaert's avatar
   
Dries Buytaert committed
923
      form_set_error('name', $error);
Dries Buytaert's avatar
   
Dries Buytaert committed
924
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
925
    else if ($error = user_validate_mail($edit['mail'])) {
Dries Buytaert's avatar
   
Dries Buytaert committed
926
      form_set_error('mail', $error);
Dries Buytaert's avatar
   
Dries Buytaert committed
927
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
928
    else if (user_deny('user', $edit['name'])) {
Dries Buytaert's avatar
   
Dries Buytaert committed
929
      form_set_error('name', t('The name "%s" has been denied access.', array('%s' => $edit['name'])));
Dries Buytaert's avatar
   
Dries Buytaert committed
930
    }
931
    else if (user_deny('mail', $edit['mail'])) {
Dries Buytaert's avatar
   
Dries Buytaert committed
932
      form_set_error('mail', t('The e-mail address "%s" has been denied access.', array('%s' => $edit['mail'])));
Dries Buytaert's avatar
   
Dries Buytaert committed
933
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
934
    else if (db_num_rows(db_query("SELECT name FROM {users} WHERE LOWER(name) = LOWER('%s')", $edit['name'])) > 0) {
Dries Buytaert's avatar
   
Dries Buytaert committed
935
      form_set_error('name', t('The name "%s" is already taken.', array('%s' => $edit['name'])));
Dries Buytaert's avatar
   
Dries Buytaert committed
936
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
937
    else if (db_num_rows(db_query("SELECT mail FROM {users} WHERE LOWER(mail) = LOWER('%s') OR LOWER(init) = LOWER('%s')", $edit['mail'], $edit['mail'])) > 0) {
Dries Buytaert's avatar
   
Dries Buytaert committed
938
      form_set_error('mail', t('The e-mail address "%s" is already taken.', array('%s' => $edit['mail'])));
Dries Buytaert's avatar
   
Dries Buytaert committed
939
    }
940
    else {
941
942
943
944
945
946
947
948
      foreach (module_list() as $module) {
        if (module_hook($module, 'user')) {
          $result = module_invoke($module, 'user', 'validate', $edit, $user);
          if (is_array($result)) {
            $data = array_merge($data, $result);
          }
        }
      }
949
    }
950

951
952
953
    if (!form_has_errors()) {
      $from = variable_get('site_mail', ini_get('sendmail_from'));
      $pass = user_password();
954

955
956
957
958
      // TODO: Is this necessary? Won't session_write() replicate this?
      unset($edit['session']);
      $account = user_save('', array_merge(array('name' => $edit['name'], 'pass' => $pass, 'init' => $edit['mail'], 'mail' => $edit['mail'], 'rid' => array(_user_authenticated_id()), 'status' => (variable_get('user_register', 1) == 1 ? 1 : 0)), $data));
      watchdog('user', 'new user: "'. $edit['name'] .'" &lt;'. $edit['mail'] .'&gt;', l(t('edit user'), "admin/user/edit/$account->uid"));
959

960
      $variables = array('%username' => $edit['name'], '%site' => variable_get('site_name', 'drupal'), '%password' => $pass, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $edit['mail'], '%date' => format_date(time()), '%login_uri' => url('user/login', NULL, NULL, TRUE), '%edit_uri' => url('user/edit', NULL, NULL, TRUE));
961

962
963
964
965
966
967
968
969
970
971
      // The first user may login immediately, and receives a customized welcome e-mail.
      if ($account->uid == 1) {
        user_mail($edit['mail'], t('drupal user account details for %s', array('%s' => $edit['name'])), strtr(t("%username,\n\nYou may now login to %uri using the following username and password:\n\n  username: %username\n  password: %password\n\n%edit_uri\n\n--drupal"), $variables), "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
        // This should not be t()'ed. No point as its only shown once in the sites lifetime, and it would be bad to store the password.
        $output .= "<p>Welcome to Drupal. You are user #1, which gives you full and immediate access.  All future registrants will receive their passwords via e-mail, so please configure your e-mail settings using the Administration pages.</p><p> Your password is <strong>$pass</strong>. You may change your password on the next page.</p><p>Please login below.</p>";
        $output .= form_hidden('destination', 'user/edit');
        $output .= form_hidden('name', $account->name);
        $output .= form_hidden('pass', $pass);
        $output .= form_submit(t('Log in'));
        return form($output);
972
973
      }
      else {
974
975
976
977
978
979
980
981
982
983
984
        if ($account->status) {
          // Create new user account, no administrator approval required.
          $subject = _user_mail_text('welcome_subject', $variables);
          $body = _user_mail_text('welcome_body', $variables);
          user_mail($edit['mail'], $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
          return t('Your password and further instructions have been sent to your e-mail address.');
        }
        else {
          // Create new user account, administrator approval required.
          $subject = _user_mail_text('approval_subject', $variables);
          $body = _user_mail_text('approval_body', $variables);
Dries Buytaert's avatar
   
Dries Buytaert committed
985

986
987
988
989
          user_mail($edit['mail'], $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
          user_mail(variable_get('site_mail', ini_get('sendmail_from')), $subject, t("%u has applied for an account.\n\n%uri", array('%u' => $account->name, '%uri' => url("admin/user/edit/$account->uid", NULL, NULL, TRUE))), "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
          return t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, your password and further instructions have been sent to your e-mail address.');
        }
990
      }
991
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
992
993
  }

994
995
  // Display the registration form.
  $output .= variable_get('user_registration_help', '');
996
  $affiliates = user_auth_help_links();
Dries Buytaert's avatar
   
Dries Buytaert committed
997
  if (count($affiliates) > 0) {
998
999
    $affiliates = implode(', ', $affiliates);
    $output .= '<p>'. t('Note: if you have an account with one of our affiliates (%s), you may <a href="%login_uri">login now</a> instead of registering.', array('%s' => $affiliates, '%login_uri' => url('user/login'))) .'</p>';
1000
  }
For faster browsing, not all history is shown. View entire blame