|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Enables the user registration and login system. |
|
6 */ |
|
7 |
|
8 /** |
|
9 * Maximum length of username text field. |
|
10 */ |
|
11 define('USERNAME_MAX_LENGTH', 60); |
|
12 |
|
13 /** |
|
14 * Maximum length of user e-mail text field. |
|
15 */ |
|
16 define('EMAIL_MAX_LENGTH', 254); |
|
17 |
|
18 /** |
|
19 * Only administrators can create user accounts. |
|
20 */ |
|
21 define('USER_REGISTER_ADMINISTRATORS_ONLY', 0); |
|
22 |
|
23 /** |
|
24 * Visitors can create their own accounts. |
|
25 */ |
|
26 define('USER_REGISTER_VISITORS', 1); |
|
27 |
|
28 /** |
|
29 * Visitors can create accounts, but they don't become active without |
|
30 * administrative approval. |
|
31 */ |
|
32 define('USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL', 2); |
|
33 |
|
34 /** |
|
35 * Implements hook_help(). |
|
36 */ |
|
37 function user_help($path, $arg) { |
|
38 global $user; |
|
39 |
|
40 switch ($path) { |
|
41 case 'admin/help#user': |
|
42 $output = ''; |
|
43 $output .= '<h3>' . t('About') . '</h3>'; |
|
44 $output .= '<p>' . t('The User module allows users to register, log in, and log out. It also allows users with proper permissions to manage user roles (used to classify users) and permissions associated with those roles. For more information, see the online handbook entry for <a href="@user">User module</a>.', array('@user' => 'http://drupal.org/documentation/modules/user')) . '</p>'; |
|
45 $output .= '<h3>' . t('Uses') . '</h3>'; |
|
46 $output .= '<dl>'; |
|
47 $output .= '<dt>' . t('Creating and managing users') . '</dt>'; |
|
48 $output .= '<dd>' . t('The User module allows users with the appropriate <a href="@permissions">permissions</a> to create user accounts through the <a href="@people">People administration page</a>, where they can also assign users to one or more roles, and block or delete user accounts. If allowed, users without accounts (anonymous users) can create their own accounts on the <a href="@register">Create new account</a> page.', array('@permissions' => url('admin/people/permissions', array('fragment' => 'module-user')), '@people' => url('admin/people'), '@register' => url('user/register'))) . '</dd>'; |
|
49 $output .= '<dt>' . t('User roles and permissions') . '</dt>'; |
|
50 $output .= '<dd>' . t('<em>Roles</em> are used to group and classify users; each user can be assigned one or more roles. By default there are two roles: <em>anonymous user</em> (users that are not logged in) and <em>authenticated user</em> (users that are registered and logged in). Depending on choices you made when you installed Drupal, the installation process may have defined more roles, and you can create additional custom roles on the <a href="@roles">Roles page</a>. After creating roles, you can set permissions for each role on the <a href="@permissions_user">Permissions page</a>. Granting a permission allows users who have been assigned a particular role to perform an action on the site, such as viewing a particular type of content, editing or creating content, administering settings for a particular module, or using a particular function of the site (such as search).', array('@permissions_user' => url('admin/people/permissions'), '@roles' => url('admin/people/permissions/roles'))) . '</dd>'; |
|
51 $output .= '<dt>' . t('Account settings') . '</dt>'; |
|
52 $output .= '<dd>' . t('The <a href="@accounts">Account settings page</a> allows you to manage settings for the displayed name of the anonymous user role, personal contact forms, user registration, and account cancellation. On this page you can also manage settings for account personalization (including signatures and user pictures), and adapt the text for the e-mail messages that are sent automatically during the user registration process.', array('@accounts' => url('admin/config/people/accounts'))) . '</dd>'; |
|
53 $output .= '</dl>'; |
|
54 return $output; |
|
55 case 'admin/people/create': |
|
56 return '<p>' . t("This web page allows administrators to register new users. Users' e-mail addresses and usernames must be unique.") . '</p>'; |
|
57 case 'admin/people/permissions': |
|
58 return '<p>' . t('Permissions let you control what users can do and see on your site. You can define a specific set of permissions for each role. (See the <a href="@role">Roles</a> page to create a role). Two important roles to consider are Authenticated Users and Administrators. Any permissions granted to the Authenticated Users role will be given to any user who can log into your site. You can make any role the Administrator role for the site, meaning this will be granted all new permissions automatically. You can do this on the <a href="@settings">User Settings</a> page. You should be careful to ensure that only trusted users are given this access and level of control of your site.', array('@role' => url('admin/people/permissions/roles'), '@settings' => url('admin/config/people/accounts'))) . '</p>'; |
|
59 case 'admin/people/permissions/roles': |
|
60 $output = '<p>' . t('Roles allow you to fine tune the security and administration of Drupal. A role defines a group of users that have certain privileges as defined on the <a href="@permissions">permissions page</a>. Examples of roles include: anonymous user, authenticated user, moderator, administrator and so on. In this area you will define the names and order of the roles on your site. It is recommended to order your roles from least permissive (anonymous user) to most permissive (administrator). To delete a role choose "edit role".', array('@permissions' => url('admin/people/permissions'))) . '</p>'; |
|
61 $output .= '<p>' . t('By default, Drupal comes with two user roles:') . '</p>'; |
|
62 $output .= '<ul>'; |
|
63 $output .= '<li>' . t("Anonymous user: this role is used for users that don't have a user account or that are not authenticated.") . '</li>'; |
|
64 $output .= '<li>' . t('Authenticated user: this role is automatically granted to all logged in users.') . '</li>'; |
|
65 $output .= '</ul>'; |
|
66 return $output; |
|
67 case 'admin/config/people/accounts/fields': |
|
68 return '<p>' . t('This form lets administrators add, edit, and arrange fields for storing user data.') . '</p>'; |
|
69 case 'admin/config/people/accounts/display': |
|
70 return '<p>' . t('This form lets administrators configure how fields should be displayed when rendering a user profile page.') . '</p>'; |
|
71 case 'admin/people/search': |
|
72 return '<p>' . t('Enter a simple pattern ("*" may be used as a wildcard match) to search for a username or e-mail address. For example, one may search for "br" and Drupal might return "brian", "brad", and "brenda@example.com".') . '</p>'; |
|
73 } |
|
74 } |
|
75 |
|
76 /** |
|
77 * Invokes a user hook in every module. |
|
78 * |
|
79 * We cannot use module_invoke() for this, because the arguments need to |
|
80 * be passed by reference. |
|
81 * |
|
82 * @param $type |
|
83 * A text string that controls which user hook to invoke. Valid choices are: |
|
84 * - cancel: Invokes hook_user_cancel(). |
|
85 * - insert: Invokes hook_user_insert(). |
|
86 * - login: Invokes hook_user_login(). |
|
87 * - presave: Invokes hook_user_presave(). |
|
88 * - update: Invokes hook_user_update(). |
|
89 * @param $edit |
|
90 * An associative array variable containing form values to be passed |
|
91 * as the first parameter of the hook function. |
|
92 * @param $account |
|
93 * The user account object to be passed as the second parameter of the hook |
|
94 * function. |
|
95 * @param $category |
|
96 * The category of user information being acted upon. |
|
97 */ |
|
98 function user_module_invoke($type, &$edit, $account, $category = NULL) { |
|
99 foreach (module_implements('user_' . $type) as $module) { |
|
100 $function = $module . '_user_' . $type; |
|
101 $function($edit, $account, $category); |
|
102 } |
|
103 } |
|
104 |
|
105 /** |
|
106 * Implements hook_theme(). |
|
107 */ |
|
108 function user_theme() { |
|
109 return array( |
|
110 'user_picture' => array( |
|
111 'variables' => array('account' => NULL), |
|
112 'template' => 'user-picture', |
|
113 ), |
|
114 'user_profile' => array( |
|
115 'render element' => 'elements', |
|
116 'template' => 'user-profile', |
|
117 'file' => 'user.pages.inc', |
|
118 ), |
|
119 'user_profile_category' => array( |
|
120 'render element' => 'element', |
|
121 'template' => 'user-profile-category', |
|
122 'file' => 'user.pages.inc', |
|
123 ), |
|
124 'user_profile_item' => array( |
|
125 'render element' => 'element', |
|
126 'template' => 'user-profile-item', |
|
127 'file' => 'user.pages.inc', |
|
128 ), |
|
129 'user_list' => array( |
|
130 'variables' => array('users' => NULL, 'title' => NULL), |
|
131 ), |
|
132 'user_admin_permissions' => array( |
|
133 'render element' => 'form', |
|
134 'file' => 'user.admin.inc', |
|
135 ), |
|
136 'user_admin_roles' => array( |
|
137 'render element' => 'form', |
|
138 'file' => 'user.admin.inc', |
|
139 ), |
|
140 'user_permission_description' => array( |
|
141 'variables' => array('permission_item' => NULL, 'hide' => NULL), |
|
142 'file' => 'user.admin.inc', |
|
143 ), |
|
144 'user_signature' => array( |
|
145 'variables' => array('signature' => NULL), |
|
146 ), |
|
147 ); |
|
148 } |
|
149 |
|
150 /** |
|
151 * Implements hook_entity_info(). |
|
152 */ |
|
153 function user_entity_info() { |
|
154 $return = array( |
|
155 'user' => array( |
|
156 'label' => t('User'), |
|
157 'controller class' => 'UserController', |
|
158 'base table' => 'users', |
|
159 'uri callback' => 'user_uri', |
|
160 'label callback' => 'format_username', |
|
161 'fieldable' => TRUE, |
|
162 // $user->language is only the preferred user language for the user |
|
163 // interface textual elements. As it is not necessarily related to the |
|
164 // language assigned to fields, we do not define it as the entity language |
|
165 // key. |
|
166 'entity keys' => array( |
|
167 'id' => 'uid', |
|
168 ), |
|
169 'bundles' => array( |
|
170 'user' => array( |
|
171 'label' => t('User'), |
|
172 'admin' => array( |
|
173 'path' => 'admin/config/people/accounts', |
|
174 'access arguments' => array('administer users'), |
|
175 ), |
|
176 ), |
|
177 ), |
|
178 'view modes' => array( |
|
179 'full' => array( |
|
180 'label' => t('User account'), |
|
181 'custom settings' => FALSE, |
|
182 ), |
|
183 ), |
|
184 ), |
|
185 ); |
|
186 return $return; |
|
187 } |
|
188 |
|
189 /** |
|
190 * Implements callback_entity_info_uri(). |
|
191 */ |
|
192 function user_uri($user) { |
|
193 return array( |
|
194 'path' => 'user/' . $user->uid, |
|
195 ); |
|
196 } |
|
197 |
|
198 /** |
|
199 * Implements hook_field_info_alter(). |
|
200 */ |
|
201 function user_field_info_alter(&$info) { |
|
202 // Add the 'user_register_form' instance setting to all field types. |
|
203 foreach ($info as $field_type => &$field_type_info) { |
|
204 $field_type_info += array('instance_settings' => array()); |
|
205 $field_type_info['instance_settings'] += array( |
|
206 'user_register_form' => FALSE, |
|
207 ); |
|
208 } |
|
209 } |
|
210 |
|
211 /** |
|
212 * Implements hook_field_extra_fields(). |
|
213 */ |
|
214 function user_field_extra_fields() { |
|
215 $return['user']['user'] = array( |
|
216 'form' => array( |
|
217 'account' => array( |
|
218 'label' => t('User name and password'), |
|
219 'description' => t('User module account form elements.'), |
|
220 'weight' => -10, |
|
221 ), |
|
222 'timezone' => array( |
|
223 'label' => t('Timezone'), |
|
224 'description' => t('User module timezone form element.'), |
|
225 'weight' => 6, |
|
226 ), |
|
227 ), |
|
228 'display' => array( |
|
229 'summary' => array( |
|
230 'label' => t('History'), |
|
231 'description' => t('User module history view element.'), |
|
232 'weight' => 5, |
|
233 ), |
|
234 ), |
|
235 ); |
|
236 |
|
237 return $return; |
|
238 } |
|
239 |
|
240 /** |
|
241 * Fetches a user object based on an external authentication source. |
|
242 * |
|
243 * @param string $authname |
|
244 * The external authentication username. |
|
245 * |
|
246 * @return |
|
247 * A fully-loaded user object if the user is found or FALSE if not found. |
|
248 */ |
|
249 function user_external_load($authname) { |
|
250 $uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchField(); |
|
251 |
|
252 if ($uid) { |
|
253 return user_load($uid); |
|
254 } |
|
255 else { |
|
256 return FALSE; |
|
257 } |
|
258 } |
|
259 |
|
260 /** |
|
261 * Load multiple users based on certain conditions. |
|
262 * |
|
263 * This function should be used whenever you need to load more than one user |
|
264 * from the database. Users are loaded into memory and will not require |
|
265 * database access if loaded again during the same page request. |
|
266 * |
|
267 * @param $uids |
|
268 * An array of user IDs. |
|
269 * @param $conditions |
|
270 * (deprecated) An associative array of conditions on the {users} |
|
271 * table, where the keys are the database fields and the values are the |
|
272 * values those fields must have. Instead, it is preferable to use |
|
273 * EntityFieldQuery to retrieve a list of entity IDs loadable by |
|
274 * this function. |
|
275 * @param $reset |
|
276 * A boolean indicating that the internal cache should be reset. Use this if |
|
277 * loading a user object which has been altered during the page request. |
|
278 * |
|
279 * @return |
|
280 * An array of user objects, indexed by uid. |
|
281 * |
|
282 * @see entity_load() |
|
283 * @see user_load() |
|
284 * @see user_load_by_mail() |
|
285 * @see user_load_by_name() |
|
286 * @see EntityFieldQuery |
|
287 * |
|
288 * @todo Remove $conditions in Drupal 8. |
|
289 */ |
|
290 function user_load_multiple($uids = array(), $conditions = array(), $reset = FALSE) { |
|
291 return entity_load('user', $uids, $conditions, $reset); |
|
292 } |
|
293 |
|
294 /** |
|
295 * Controller class for users. |
|
296 * |
|
297 * This extends the DrupalDefaultEntityController class, adding required |
|
298 * special handling for user objects. |
|
299 */ |
|
300 class UserController extends DrupalDefaultEntityController { |
|
301 |
|
302 function attachLoad(&$queried_users, $revision_id = FALSE) { |
|
303 // Build an array of user picture IDs so that these can be fetched later. |
|
304 $picture_fids = array(); |
|
305 foreach ($queried_users as $key => $record) { |
|
306 $picture_fids[] = $record->picture; |
|
307 $queried_users[$key]->data = unserialize($record->data); |
|
308 $queried_users[$key]->roles = array(); |
|
309 if ($record->uid) { |
|
310 $queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; |
|
311 } |
|
312 else { |
|
313 $queried_users[$record->uid]->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; |
|
314 } |
|
315 } |
|
316 |
|
317 // Add any additional roles from the database. |
|
318 $result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users))); |
|
319 foreach ($result as $record) { |
|
320 $queried_users[$record->uid]->roles[$record->rid] = $record->name; |
|
321 } |
|
322 |
|
323 // Add the full file objects for user pictures if enabled. |
|
324 if (!empty($picture_fids) && variable_get('user_pictures', 0)) { |
|
325 $pictures = file_load_multiple($picture_fids); |
|
326 foreach ($queried_users as $account) { |
|
327 if (!empty($account->picture) && isset($pictures[$account->picture])) { |
|
328 $account->picture = $pictures[$account->picture]; |
|
329 } |
|
330 else { |
|
331 $account->picture = NULL; |
|
332 } |
|
333 } |
|
334 } |
|
335 // Call the default attachLoad() method. This will add fields and call |
|
336 // hook_user_load(). |
|
337 parent::attachLoad($queried_users, $revision_id); |
|
338 } |
|
339 } |
|
340 |
|
341 /** |
|
342 * Loads a user object. |
|
343 * |
|
344 * Drupal has a global $user object, which represents the currently-logged-in |
|
345 * user. So to avoid confusion and to avoid clobbering the global $user object, |
|
346 * it is a good idea to assign the result of this function to a different local |
|
347 * variable, generally $account. If you actually do want to act as the user you |
|
348 * are loading, it is essential to call drupal_save_session(FALSE); first. |
|
349 * See |
|
350 * @link http://drupal.org/node/218104 Safely impersonating another user @endlink |
|
351 * for more information. |
|
352 * |
|
353 * @param $uid |
|
354 * Integer specifying the user ID to load. |
|
355 * @param $reset |
|
356 * TRUE to reset the internal cache and load from the database; FALSE |
|
357 * (default) to load from the internal cache, if set. |
|
358 * |
|
359 * @return |
|
360 * A fully-loaded user object upon successful user load, or FALSE if the user |
|
361 * cannot be loaded. |
|
362 * |
|
363 * @see user_load_multiple() |
|
364 */ |
|
365 function user_load($uid, $reset = FALSE) { |
|
366 $users = user_load_multiple(array($uid), array(), $reset); |
|
367 return reset($users); |
|
368 } |
|
369 |
|
370 /** |
|
371 * Fetch a user object by email address. |
|
372 * |
|
373 * @param $mail |
|
374 * String with the account's e-mail address. |
|
375 * @return |
|
376 * A fully-loaded $user object upon successful user load or FALSE if user |
|
377 * cannot be loaded. |
|
378 * |
|
379 * @see user_load_multiple() |
|
380 */ |
|
381 function user_load_by_mail($mail) { |
|
382 $users = user_load_multiple(array(), array('mail' => $mail)); |
|
383 return reset($users); |
|
384 } |
|
385 |
|
386 /** |
|
387 * Fetch a user object by account name. |
|
388 * |
|
389 * @param $name |
|
390 * String with the account's user name. |
|
391 * @return |
|
392 * A fully-loaded $user object upon successful user load or FALSE if user |
|
393 * cannot be loaded. |
|
394 * |
|
395 * @see user_load_multiple() |
|
396 */ |
|
397 function user_load_by_name($name) { |
|
398 $users = user_load_multiple(array(), array('name' => $name)); |
|
399 return reset($users); |
|
400 } |
|
401 |
|
402 /** |
|
403 * Save changes to a user account or add a new user. |
|
404 * |
|
405 * @param $account |
|
406 * (optional) The user object to modify or add. If you want to modify |
|
407 * an existing user account, you will need to ensure that (a) $account |
|
408 * is an object, and (b) you have set $account->uid to the numeric |
|
409 * user ID of the user account you wish to modify. If you |
|
410 * want to create a new user account, you can set $account->is_new to |
|
411 * TRUE or omit the $account->uid field. |
|
412 * @param $edit |
|
413 * An array of fields and values to save. For example array('name' |
|
414 * => 'My name'). Key / value pairs added to the $edit['data'] will be |
|
415 * serialized and saved in the {users.data} column. |
|
416 * @param $category |
|
417 * (optional) The category for storing profile information in. |
|
418 * |
|
419 * @return |
|
420 * A fully-loaded $user object upon successful save or FALSE if the save failed. |
|
421 */ |
|
422 function user_save($account, $edit = array(), $category = 'account') { |
|
423 $transaction = db_transaction(); |
|
424 try { |
|
425 if (isset($edit['pass']) && strlen(trim($edit['pass'])) > 0) { |
|
426 // Allow alternate password hashing schemes. |
|
427 require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc'); |
|
428 $edit['pass'] = user_hash_password(trim($edit['pass'])); |
|
429 // Abort if the hashing failed and returned FALSE. |
|
430 if (!$edit['pass']) { |
|
431 return FALSE; |
|
432 } |
|
433 } |
|
434 else { |
|
435 // Avoid overwriting an existing password with a blank password. |
|
436 unset($edit['pass']); |
|
437 } |
|
438 if (isset($edit['mail'])) { |
|
439 $edit['mail'] = trim($edit['mail']); |
|
440 } |
|
441 |
|
442 // Load the stored entity, if any. |
|
443 if (!empty($account->uid) && !isset($account->original)) { |
|
444 $account->original = entity_load_unchanged('user', $account->uid); |
|
445 } |
|
446 |
|
447 if (empty($account)) { |
|
448 $account = new stdClass(); |
|
449 } |
|
450 if (!isset($account->is_new)) { |
|
451 $account->is_new = empty($account->uid); |
|
452 } |
|
453 // Prepopulate $edit['data'] with the current value of $account->data. |
|
454 // Modules can add to or remove from this array in hook_user_presave(). |
|
455 if (!empty($account->data)) { |
|
456 $edit['data'] = !empty($edit['data']) ? array_merge($account->data, $edit['data']) : $account->data; |
|
457 } |
|
458 |
|
459 // Invoke hook_user_presave() for all modules. |
|
460 user_module_invoke('presave', $edit, $account, $category); |
|
461 |
|
462 // Invoke presave operations of Field Attach API and Entity API. Those APIs |
|
463 // require a fully-fledged and updated entity object. Therefore, we need to |
|
464 // copy any new property values of $edit into it. |
|
465 foreach ($edit as $key => $value) { |
|
466 $account->$key = $value; |
|
467 } |
|
468 field_attach_presave('user', $account); |
|
469 module_invoke_all('entity_presave', $account, 'user'); |
|
470 |
|
471 if (is_object($account) && !$account->is_new) { |
|
472 // Process picture uploads. |
|
473 if (!empty($account->picture->fid) && (!isset($account->original->picture->fid) || $account->picture->fid != $account->original->picture->fid)) { |
|
474 $picture = $account->picture; |
|
475 // If the picture is a temporary file move it to its final location and |
|
476 // make it permanent. |
|
477 if (!$picture->status) { |
|
478 $info = image_get_info($picture->uri); |
|
479 $picture_directory = file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures'); |
|
480 |
|
481 // Prepare the pictures directory. |
|
482 file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY); |
|
483 $destination = file_stream_wrapper_uri_normalize($picture_directory . '/picture-' . $account->uid . '-' . REQUEST_TIME . '.' . $info['extension']); |
|
484 |
|
485 // Move the temporary file into the final location. |
|
486 if ($picture = file_move($picture, $destination, FILE_EXISTS_RENAME)) { |
|
487 $picture->status = FILE_STATUS_PERMANENT; |
|
488 $account->picture = file_save($picture); |
|
489 file_usage_add($picture, 'user', 'user', $account->uid); |
|
490 } |
|
491 } |
|
492 // Delete the previous picture if it was deleted or replaced. |
|
493 if (!empty($account->original->picture->fid)) { |
|
494 file_usage_delete($account->original->picture, 'user', 'user', $account->uid); |
|
495 file_delete($account->original->picture); |
|
496 } |
|
497 } |
|
498 elseif (isset($edit['picture_delete']) && $edit['picture_delete']) { |
|
499 file_usage_delete($account->original->picture, 'user', 'user', $account->uid); |
|
500 file_delete($account->original->picture); |
|
501 } |
|
502 // Save the picture object, if it is set. drupal_write_record() expects |
|
503 // $account->picture to be a FID. |
|
504 $picture = empty($account->picture) ? NULL : $account->picture; |
|
505 $account->picture = empty($account->picture->fid) ? 0 : $account->picture->fid; |
|
506 |
|
507 // Do not allow 'uid' to be changed. |
|
508 $account->uid = $account->original->uid; |
|
509 // Save changes to the user table. |
|
510 $success = drupal_write_record('users', $account, 'uid'); |
|
511 // Restore the picture object. |
|
512 $account->picture = $picture; |
|
513 if ($success === FALSE) { |
|
514 // The query failed - better to abort the save than risk further |
|
515 // data loss. |
|
516 return FALSE; |
|
517 } |
|
518 |
|
519 // Reload user roles if provided. |
|
520 if ($account->roles != $account->original->roles) { |
|
521 db_delete('users_roles') |
|
522 ->condition('uid', $account->uid) |
|
523 ->execute(); |
|
524 |
|
525 $query = db_insert('users_roles')->fields(array('uid', 'rid')); |
|
526 foreach (array_keys($account->roles) as $rid) { |
|
527 if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { |
|
528 $query->values(array( |
|
529 'uid' => $account->uid, |
|
530 'rid' => $rid, |
|
531 )); |
|
532 } |
|
533 } |
|
534 $query->execute(); |
|
535 } |
|
536 |
|
537 // Delete a blocked user's sessions to kick them if they are online. |
|
538 if ($account->original->status != $account->status && $account->status == 0) { |
|
539 drupal_session_destroy_uid($account->uid); |
|
540 } |
|
541 |
|
542 // If the password changed, delete all open sessions and recreate |
|
543 // the current one. |
|
544 if ($account->pass != $account->original->pass) { |
|
545 drupal_session_destroy_uid($account->uid); |
|
546 if ($account->uid == $GLOBALS['user']->uid) { |
|
547 drupal_session_regenerate(); |
|
548 } |
|
549 } |
|
550 |
|
551 // Save Field data. |
|
552 field_attach_update('user', $account); |
|
553 |
|
554 // Send emails after we have the new user object. |
|
555 if ($account->status != $account->original->status) { |
|
556 // The user's status is changing; conditionally send notification email. |
|
557 $op = $account->status == 1 ? 'status_activated' : 'status_blocked'; |
|
558 _user_mail_notify($op, $account); |
|
559 } |
|
560 |
|
561 // Update $edit with any interim changes to $account. |
|
562 foreach ($account as $key => $value) { |
|
563 if (!property_exists($account->original, $key) || $value !== $account->original->$key) { |
|
564 $edit[$key] = $value; |
|
565 } |
|
566 } |
|
567 user_module_invoke('update', $edit, $account, $category); |
|
568 module_invoke_all('entity_update', $account, 'user'); |
|
569 } |
|
570 else { |
|
571 // Allow 'uid' to be set by the caller. There is no danger of writing an |
|
572 // existing user as drupal_write_record will do an INSERT. |
|
573 if (empty($account->uid)) { |
|
574 $account->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField()); |
|
575 } |
|
576 // Allow 'created' to be set by the caller. |
|
577 if (!isset($account->created)) { |
|
578 $account->created = REQUEST_TIME; |
|
579 } |
|
580 $success = drupal_write_record('users', $account); |
|
581 if ($success === FALSE) { |
|
582 // On a failed INSERT some other existing user's uid may be returned. |
|
583 // We must abort to avoid overwriting their account. |
|
584 return FALSE; |
|
585 } |
|
586 |
|
587 // Make sure $account is properly initialized. |
|
588 $account->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; |
|
589 |
|
590 field_attach_insert('user', $account); |
|
591 $edit = (array) $account; |
|
592 user_module_invoke('insert', $edit, $account, $category); |
|
593 module_invoke_all('entity_insert', $account, 'user'); |
|
594 |
|
595 // Save user roles. Skip built-in roles, and ones that were already saved |
|
596 // to the database during hook calls. |
|
597 $rids_to_skip = array_merge(array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID), db_query('SELECT rid FROM {users_roles} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol()); |
|
598 if ($rids_to_save = array_diff(array_keys($account->roles), $rids_to_skip)) { |
|
599 $query = db_insert('users_roles')->fields(array('uid', 'rid')); |
|
600 foreach ($rids_to_save as $rid) { |
|
601 $query->values(array( |
|
602 'uid' => $account->uid, |
|
603 'rid' => $rid, |
|
604 )); |
|
605 } |
|
606 $query->execute(); |
|
607 } |
|
608 } |
|
609 // Clear internal properties. |
|
610 unset($account->is_new); |
|
611 unset($account->original); |
|
612 // Clear the static loading cache. |
|
613 entity_get_controller('user')->resetCache(array($account->uid)); |
|
614 |
|
615 return $account; |
|
616 } |
|
617 catch (Exception $e) { |
|
618 $transaction->rollback(); |
|
619 watchdog_exception('user', $e); |
|
620 throw $e; |
|
621 } |
|
622 } |
|
623 |
|
624 /** |
|
625 * Verify the syntax of the given name. |
|
626 */ |
|
627 function user_validate_name($name) { |
|
628 if (!$name) { |
|
629 return t('You must enter a username.'); |
|
630 } |
|
631 if (substr($name, 0, 1) == ' ') { |
|
632 return t('The username cannot begin with a space.'); |
|
633 } |
|
634 if (substr($name, -1) == ' ') { |
|
635 return t('The username cannot end with a space.'); |
|
636 } |
|
637 if (strpos($name, ' ') !== FALSE) { |
|
638 return t('The username cannot contain multiple spaces in a row.'); |
|
639 } |
|
640 if (preg_match('/[^\x{80}-\x{F7} a-z0-9@_.\'-]/i', $name)) { |
|
641 return t('The username contains an illegal character.'); |
|
642 } |
|
643 if (preg_match('/[\x{80}-\x{A0}' . // Non-printable ISO-8859-1 + NBSP |
|
644 '\x{AD}' . // Soft-hyphen |
|
645 '\x{2000}-\x{200F}' . // Various space characters |
|
646 '\x{2028}-\x{202F}' . // Bidirectional text overrides |
|
647 '\x{205F}-\x{206F}' . // Various text hinting characters |
|
648 '\x{FEFF}' . // Byte order mark |
|
649 '\x{FF01}-\x{FF60}' . // Full-width latin |
|
650 '\x{FFF9}-\x{FFFD}' . // Replacement characters |
|
651 '\x{0}-\x{1F}]/u', // NULL byte and control characters |
|
652 $name)) { |
|
653 return t('The username contains an illegal character.'); |
|
654 } |
|
655 if (drupal_strlen($name) > USERNAME_MAX_LENGTH) { |
|
656 return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH)); |
|
657 } |
|
658 } |
|
659 |
|
660 /** |
|
661 * Validates a user's email address. |
|
662 * |
|
663 * Checks that a user's email address exists and follows all standard |
|
664 * validation rules. Returns error messages when the address is invalid. |
|
665 * |
|
666 * @param $mail |
|
667 * A user's email address. |
|
668 * |
|
669 * @return |
|
670 * If the address is invalid, a human-readable error message is returned. |
|
671 * If the address is valid, nothing is returned. |
|
672 */ |
|
673 function user_validate_mail($mail) { |
|
674 if (!$mail) { |
|
675 return t('You must enter an e-mail address.'); |
|
676 } |
|
677 if (!valid_email_address($mail)) { |
|
678 return t('The e-mail address %mail is not valid.', array('%mail' => $mail)); |
|
679 } |
|
680 } |
|
681 |
|
682 /** |
|
683 * Validates an image uploaded by a user. |
|
684 * |
|
685 * @see user_account_form() |
|
686 */ |
|
687 function user_validate_picture(&$form, &$form_state) { |
|
688 // If required, validate the uploaded picture. |
|
689 $validators = array( |
|
690 'file_validate_is_image' => array(), |
|
691 'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')), |
|
692 'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024), |
|
693 ); |
|
694 |
|
695 // Save the file as a temporary file. |
|
696 $file = file_save_upload('picture_upload', $validators); |
|
697 if ($file === FALSE) { |
|
698 form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures')))); |
|
699 } |
|
700 elseif ($file !== NULL) { |
|
701 $form_state['values']['picture_upload'] = $file; |
|
702 } |
|
703 } |
|
704 |
|
705 /** |
|
706 * Generate a random alphanumeric password. |
|
707 */ |
|
708 function user_password($length = 10) { |
|
709 // This variable contains the list of allowable characters for the |
|
710 // password. Note that the number 0 and the letter 'O' have been |
|
711 // removed to avoid confusion between the two. The same is true |
|
712 // of 'I', 1, and 'l'. |
|
713 $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'; |
|
714 |
|
715 // Zero-based count of characters in the allowable list: |
|
716 $len = strlen($allowable_characters) - 1; |
|
717 |
|
718 // Declare the password as a blank string. |
|
719 $pass = ''; |
|
720 |
|
721 // Loop the number of times specified by $length. |
|
722 for ($i = 0; $i < $length; $i++) { |
|
723 do { |
|
724 // Find a secure random number within the range needed. |
|
725 $index = ord(drupal_random_bytes(1)); |
|
726 } while ($index > $len); |
|
727 |
|
728 // Each iteration, pick a random character from the |
|
729 // allowable string and append it to the password: |
|
730 $pass .= $allowable_characters[$index]; |
|
731 } |
|
732 |
|
733 return $pass; |
|
734 } |
|
735 |
|
736 /** |
|
737 * Determine the permissions for one or more roles. |
|
738 * |
|
739 * @param $roles |
|
740 * An array whose keys are the role IDs of interest, such as $user->roles. |
|
741 * |
|
742 * @return |
|
743 * If $roles is a non-empty array, an array indexed by role ID is returned. |
|
744 * Each value is an array whose keys are the permission strings for the given |
|
745 * role ID. If $roles is empty nothing is returned. |
|
746 */ |
|
747 function user_role_permissions($roles = array()) { |
|
748 $cache = &drupal_static(__FUNCTION__, array()); |
|
749 |
|
750 $role_permissions = $fetch = array(); |
|
751 |
|
752 if ($roles) { |
|
753 foreach ($roles as $rid => $name) { |
|
754 if (isset($cache[$rid])) { |
|
755 $role_permissions[$rid] = $cache[$rid]; |
|
756 } |
|
757 else { |
|
758 // Add this rid to the list of those needing to be fetched. |
|
759 $fetch[] = $rid; |
|
760 // Prepare in case no permissions are returned. |
|
761 $cache[$rid] = array(); |
|
762 } |
|
763 } |
|
764 |
|
765 if ($fetch) { |
|
766 // Get from the database permissions that were not in the static variable. |
|
767 // Only role IDs with at least one permission assigned will return rows. |
|
768 $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch)); |
|
769 |
|
770 foreach ($result as $row) { |
|
771 $cache[$row->rid][$row->permission] = TRUE; |
|
772 } |
|
773 foreach ($fetch as $rid) { |
|
774 // For every rid, we know we at least assigned an empty array. |
|
775 $role_permissions[$rid] = $cache[$rid]; |
|
776 } |
|
777 } |
|
778 } |
|
779 |
|
780 return $role_permissions; |
|
781 } |
|
782 |
|
783 /** |
|
784 * Determine whether the user has a given privilege. |
|
785 * |
|
786 * @param $string |
|
787 * The permission, such as "administer nodes", being checked for. |
|
788 * @param $account |
|
789 * (optional) The account to check, if not given use currently logged in user. |
|
790 * |
|
791 * @return |
|
792 * Boolean TRUE if the user has the requested permission. |
|
793 * |
|
794 * All permission checks in Drupal should go through this function. This |
|
795 * way, we guarantee consistent behavior, and ensure that the superuser |
|
796 * can perform all actions. |
|
797 */ |
|
798 function user_access($string, $account = NULL) { |
|
799 global $user; |
|
800 |
|
801 if (!isset($account)) { |
|
802 $account = $user; |
|
803 } |
|
804 |
|
805 // User #1 has all privileges: |
|
806 if ($account->uid == 1) { |
|
807 return TRUE; |
|
808 } |
|
809 |
|
810 // To reduce the number of SQL queries, we cache the user's permissions |
|
811 // in a static variable. |
|
812 // Use the advanced drupal_static() pattern, since this is called very often. |
|
813 static $drupal_static_fast; |
|
814 if (!isset($drupal_static_fast)) { |
|
815 $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__); |
|
816 } |
|
817 $perm = &$drupal_static_fast['perm']; |
|
818 if (!isset($perm[$account->uid])) { |
|
819 $role_permissions = user_role_permissions($account->roles); |
|
820 |
|
821 $perms = array(); |
|
822 foreach ($role_permissions as $one_role) { |
|
823 $perms += $one_role; |
|
824 } |
|
825 $perm[$account->uid] = $perms; |
|
826 } |
|
827 |
|
828 return isset($perm[$account->uid][$string]); |
|
829 } |
|
830 |
|
831 /** |
|
832 * Checks for usernames blocked by user administration. |
|
833 * |
|
834 * @param $name |
|
835 * A string containing a name of the user. |
|
836 * |
|
837 * @return |
|
838 * Object with property 'name' (the user name), if the user is blocked; |
|
839 * FALSE if the user is not blocked. |
|
840 */ |
|
841 function user_is_blocked($name) { |
|
842 return db_select('users') |
|
843 ->fields('users', array('name')) |
|
844 ->condition('name', db_like($name), 'LIKE') |
|
845 ->condition('status', 0) |
|
846 ->execute()->fetchObject(); |
|
847 } |
|
848 |
|
849 /** |
|
850 * Checks if a user has a role. |
|
851 * |
|
852 * @param int $rid |
|
853 * A role ID. |
|
854 * |
|
855 * @param object|null $account |
|
856 * (optional) A user account. Defaults to the current user. |
|
857 * |
|
858 * @return bool |
|
859 * TRUE if the user has the role, or FALSE if not. |
|
860 */ |
|
861 function user_has_role($rid, $account = NULL) { |
|
862 if (!$account) { |
|
863 $account = $GLOBALS['user']; |
|
864 } |
|
865 |
|
866 return isset($account->roles[$rid]); |
|
867 } |
|
868 |
|
869 /** |
|
870 * Implements hook_permission(). |
|
871 */ |
|
872 function user_permission() { |
|
873 return array( |
|
874 'administer permissions' => array( |
|
875 'title' => t('Administer permissions'), |
|
876 'restrict access' => TRUE, |
|
877 ), |
|
878 'administer users' => array( |
|
879 'title' => t('Administer users'), |
|
880 'restrict access' => TRUE, |
|
881 ), |
|
882 'access user profiles' => array( |
|
883 'title' => t('View user profiles'), |
|
884 ), |
|
885 'change own username' => array( |
|
886 'title' => t('Change own username'), |
|
887 ), |
|
888 'cancel account' => array( |
|
889 'title' => t('Cancel own user account'), |
|
890 'description' => t('Note: content may be kept, unpublished, deleted or transferred to the %anonymous-name user depending on the configured <a href="@user-settings-url">user settings</a>.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')), '@user-settings-url' => url('admin/config/people/accounts'))), |
|
891 ), |
|
892 'select account cancellation method' => array( |
|
893 'title' => t('Select method for cancelling own account'), |
|
894 'restrict access' => TRUE, |
|
895 ), |
|
896 ); |
|
897 } |
|
898 |
|
899 /** |
|
900 * Implements hook_file_download(). |
|
901 * |
|
902 * Ensure that user pictures (avatars) are always downloadable. |
|
903 */ |
|
904 function user_file_download($uri) { |
|
905 if (strpos(file_uri_target($uri), variable_get('user_picture_path', 'pictures') . '/picture-') === 0) { |
|
906 $info = image_get_info($uri); |
|
907 return array('Content-Type' => $info['mime_type']); |
|
908 } |
|
909 } |
|
910 |
|
911 /** |
|
912 * Implements hook_file_move(). |
|
913 */ |
|
914 function user_file_move($file, $source) { |
|
915 // If a user's picture is replaced with a new one, update the record in |
|
916 // the users table. |
|
917 if (isset($file->fid) && isset($source->fid) && $file->fid != $source->fid) { |
|
918 db_update('users') |
|
919 ->fields(array( |
|
920 'picture' => $file->fid, |
|
921 )) |
|
922 ->condition('picture', $source->fid) |
|
923 ->execute(); |
|
924 } |
|
925 } |
|
926 |
|
927 /** |
|
928 * Implements hook_file_delete(). |
|
929 */ |
|
930 function user_file_delete($file) { |
|
931 // Remove any references to the file. |
|
932 db_update('users') |
|
933 ->fields(array('picture' => 0)) |
|
934 ->condition('picture', $file->fid) |
|
935 ->execute(); |
|
936 } |
|
937 |
|
938 /** |
|
939 * Implements hook_search_info(). |
|
940 */ |
|
941 function user_search_info() { |
|
942 return array( |
|
943 'title' => 'Users', |
|
944 ); |
|
945 } |
|
946 |
|
947 /** |
|
948 * Implements hook_search_access(). |
|
949 */ |
|
950 function user_search_access() { |
|
951 return user_access('access user profiles'); |
|
952 } |
|
953 |
|
954 /** |
|
955 * Implements hook_search_execute(). |
|
956 */ |
|
957 function user_search_execute($keys = NULL, $conditions = NULL) { |
|
958 $find = array(); |
|
959 // Escape for LIKE matching. |
|
960 $keys = db_like($keys); |
|
961 // Replace wildcards with MySQL/PostgreSQL wildcards. |
|
962 $keys = preg_replace('!\*+!', '%', $keys); |
|
963 $query = db_select('users')->extend('PagerDefault'); |
|
964 $query->fields('users', array('uid')); |
|
965 if (user_access('administer users')) { |
|
966 // Administrators can also search in the otherwise private email field, |
|
967 // and they don't need to be restricted to only active users. |
|
968 $query->fields('users', array('mail')); |
|
969 $query->condition(db_or()-> |
|
970 condition('name', '%' . $keys . '%', 'LIKE')-> |
|
971 condition('mail', '%' . $keys . '%', 'LIKE')); |
|
972 } |
|
973 else { |
|
974 // Regular users can only search via usernames, and we do not show them |
|
975 // blocked accounts. |
|
976 $query->condition('name', '%' . $keys . '%', 'LIKE') |
|
977 ->condition('status', 1); |
|
978 } |
|
979 $uids = $query |
|
980 ->limit(15) |
|
981 ->execute() |
|
982 ->fetchCol(); |
|
983 $accounts = user_load_multiple($uids); |
|
984 |
|
985 $results = array(); |
|
986 foreach ($accounts as $account) { |
|
987 $result = array( |
|
988 'title' => format_username($account), |
|
989 'link' => url('user/' . $account->uid, array('absolute' => TRUE)), |
|
990 ); |
|
991 if (user_access('administer users')) { |
|
992 $result['title'] .= ' (' . $account->mail . ')'; |
|
993 } |
|
994 $results[] = $result; |
|
995 } |
|
996 |
|
997 return $results; |
|
998 } |
|
999 |
|
1000 /** |
|
1001 * Implements hook_element_info(). |
|
1002 */ |
|
1003 function user_element_info() { |
|
1004 $types['user_profile_category'] = array( |
|
1005 '#theme_wrappers' => array('user_profile_category'), |
|
1006 ); |
|
1007 $types['user_profile_item'] = array( |
|
1008 '#theme' => 'user_profile_item', |
|
1009 ); |
|
1010 return $types; |
|
1011 } |
|
1012 |
|
1013 /** |
|
1014 * Implements hook_user_view(). |
|
1015 */ |
|
1016 function user_user_view($account) { |
|
1017 $account->content['user_picture'] = array( |
|
1018 '#markup' => theme('user_picture', array('account' => $account)), |
|
1019 '#weight' => -10, |
|
1020 ); |
|
1021 if (!isset($account->content['summary'])) { |
|
1022 $account->content['summary'] = array(); |
|
1023 } |
|
1024 $account->content['summary'] += array( |
|
1025 '#type' => 'user_profile_category', |
|
1026 '#attributes' => array('class' => array('user-member')), |
|
1027 '#weight' => 5, |
|
1028 '#title' => t('History'), |
|
1029 ); |
|
1030 $account->content['summary']['member_for'] = array( |
|
1031 '#type' => 'user_profile_item', |
|
1032 '#title' => t('Member for'), |
|
1033 '#markup' => format_interval(REQUEST_TIME - $account->created), |
|
1034 ); |
|
1035 } |
|
1036 |
|
1037 /** |
|
1038 * Helper function to add default user account fields to user registration and edit form. |
|
1039 * |
|
1040 * @see user_account_form_validate() |
|
1041 * @see user_validate_current_pass() |
|
1042 * @see user_validate_picture() |
|
1043 * @see user_validate_mail() |
|
1044 */ |
|
1045 function user_account_form(&$form, &$form_state) { |
|
1046 global $user; |
|
1047 |
|
1048 $account = $form['#user']; |
|
1049 $register = ($form['#user']->uid > 0 ? FALSE : TRUE); |
|
1050 |
|
1051 $admin = user_access('administer users'); |
|
1052 |
|
1053 $form['#validate'][] = 'user_account_form_validate'; |
|
1054 |
|
1055 // Account information. |
|
1056 $form['account'] = array( |
|
1057 '#type' => 'container', |
|
1058 '#weight' => -10, |
|
1059 ); |
|
1060 // Only show name field on registration form or user can change own username. |
|
1061 $form['account']['name'] = array( |
|
1062 '#type' => 'textfield', |
|
1063 '#title' => t('Username'), |
|
1064 '#maxlength' => USERNAME_MAX_LENGTH, |
|
1065 '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'), |
|
1066 '#required' => TRUE, |
|
1067 '#attributes' => array('class' => array('username')), |
|
1068 '#default_value' => (!$register ? $account->name : ''), |
|
1069 '#access' => ($register || ($user->uid == $account->uid && user_access('change own username')) || $admin), |
|
1070 '#weight' => -10, |
|
1071 ); |
|
1072 |
|
1073 $form['account']['mail'] = array( |
|
1074 '#type' => 'textfield', |
|
1075 '#title' => t('E-mail address'), |
|
1076 '#maxlength' => EMAIL_MAX_LENGTH, |
|
1077 '#description' => t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'), |
|
1078 '#required' => TRUE, |
|
1079 '#default_value' => (!$register ? $account->mail : ''), |
|
1080 ); |
|
1081 |
|
1082 // Display password field only for existing users or when user is allowed to |
|
1083 // assign a password during registration. |
|
1084 if (!$register) { |
|
1085 $form['account']['pass'] = array( |
|
1086 '#type' => 'password_confirm', |
|
1087 '#size' => 25, |
|
1088 '#description' => t('To change the current user password, enter the new password in both fields.'), |
|
1089 ); |
|
1090 // To skip the current password field, the user must have logged in via a |
|
1091 // one-time link and have the token in the URL. Store this in $form_state |
|
1092 // so it persists even on subsequent Ajax requests. |
|
1093 if (!isset($form_state['user_pass_reset'])) { |
|
1094 $form_state['user_pass_reset'] = isset($_SESSION['pass_reset_' . $account->uid]) && isset($_GET['pass-reset-token']) && ($_GET['pass-reset-token'] == $_SESSION['pass_reset_' . $account->uid]); |
|
1095 } |
|
1096 $protected_values = array(); |
|
1097 $current_pass_description = ''; |
|
1098 // The user may only change their own password without their current |
|
1099 // password if they logged in via a one-time login link. |
|
1100 if (!$form_state['user_pass_reset']) { |
|
1101 $protected_values['mail'] = $form['account']['mail']['#title']; |
|
1102 $protected_values['pass'] = t('Password'); |
|
1103 $request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.')))); |
|
1104 $current_pass_description = t('Enter your current password to change the %mail or %pass. !request_new.', array('%mail' => $protected_values['mail'], '%pass' => $protected_values['pass'], '!request_new' => $request_new)); |
|
1105 } |
|
1106 // The user must enter their current password to change to a new one. |
|
1107 if ($user->uid == $account->uid) { |
|
1108 $form['account']['current_pass_required_values'] = array( |
|
1109 '#type' => 'value', |
|
1110 '#value' => $protected_values, |
|
1111 ); |
|
1112 $form['account']['current_pass'] = array( |
|
1113 '#type' => 'password', |
|
1114 '#title' => t('Current password'), |
|
1115 '#size' => 25, |
|
1116 '#access' => !empty($protected_values), |
|
1117 '#description' => $current_pass_description, |
|
1118 '#weight' => -5, |
|
1119 // Do not let web browsers remember this password, since we are trying |
|
1120 // to confirm that the person submitting the form actually knows the |
|
1121 // current one. |
|
1122 '#attributes' => array('autocomplete' => 'off'), |
|
1123 ); |
|
1124 $form['#validate'][] = 'user_validate_current_pass'; |
|
1125 } |
|
1126 } |
|
1127 elseif (!variable_get('user_email_verification', TRUE) || $admin) { |
|
1128 $form['account']['pass'] = array( |
|
1129 '#type' => 'password_confirm', |
|
1130 '#size' => 25, |
|
1131 '#description' => t('Provide a password for the new account in both fields.'), |
|
1132 '#required' => TRUE, |
|
1133 ); |
|
1134 } |
|
1135 |
|
1136 if ($admin) { |
|
1137 $status = isset($account->status) ? $account->status : 1; |
|
1138 } |
|
1139 else { |
|
1140 $status = $register ? variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS : $account->status; |
|
1141 } |
|
1142 $form['account']['status'] = array( |
|
1143 '#type' => 'radios', |
|
1144 '#title' => t('Status'), |
|
1145 '#default_value' => $status, |
|
1146 '#options' => array(t('Blocked'), t('Active')), |
|
1147 '#access' => $admin, |
|
1148 ); |
|
1149 |
|
1150 $roles = array_map('check_plain', user_roles(TRUE)); |
|
1151 // The disabled checkbox subelement for the 'authenticated user' role |
|
1152 // must be generated separately and added to the checkboxes element, |
|
1153 // because of a limitation in Form API not supporting a single disabled |
|
1154 // checkbox within a set of checkboxes. |
|
1155 // @todo This should be solved more elegantly. See issue #119038. |
|
1156 $checkbox_authenticated = array( |
|
1157 '#type' => 'checkbox', |
|
1158 '#title' => $roles[DRUPAL_AUTHENTICATED_RID], |
|
1159 '#default_value' => TRUE, |
|
1160 '#disabled' => TRUE, |
|
1161 ); |
|
1162 unset($roles[DRUPAL_AUTHENTICATED_RID]); |
|
1163 $form['account']['roles'] = array( |
|
1164 '#type' => 'checkboxes', |
|
1165 '#title' => t('Roles'), |
|
1166 '#default_value' => (!$register && !empty($account->roles) ? array_keys(array_filter($account->roles)) : array()), |
|
1167 '#options' => $roles, |
|
1168 '#access' => $roles && user_access('administer permissions'), |
|
1169 DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated, |
|
1170 ); |
|
1171 |
|
1172 $form['account']['notify'] = array( |
|
1173 '#type' => 'checkbox', |
|
1174 '#title' => t('Notify user of new account'), |
|
1175 '#access' => $register && $admin, |
|
1176 ); |
|
1177 |
|
1178 // Signature. |
|
1179 $form['signature_settings'] = array( |
|
1180 '#type' => 'fieldset', |
|
1181 '#title' => t('Signature settings'), |
|
1182 '#weight' => 1, |
|
1183 '#access' => (!$register && variable_get('user_signatures', 0)), |
|
1184 ); |
|
1185 |
|
1186 $form['signature_settings']['signature'] = array( |
|
1187 '#type' => 'text_format', |
|
1188 '#title' => t('Signature'), |
|
1189 '#default_value' => isset($account->signature) ? $account->signature : '', |
|
1190 '#description' => t('Your signature will be publicly displayed at the end of your comments.'), |
|
1191 '#format' => isset($account->signature_format) ? $account->signature_format : NULL, |
|
1192 ); |
|
1193 |
|
1194 // Picture/avatar. |
|
1195 $form['picture'] = array( |
|
1196 '#type' => 'fieldset', |
|
1197 '#title' => t('Picture'), |
|
1198 '#weight' => 1, |
|
1199 '#access' => (!$register && variable_get('user_pictures', 0)), |
|
1200 ); |
|
1201 $form['picture']['picture'] = array( |
|
1202 '#type' => 'value', |
|
1203 '#value' => isset($account->picture) ? $account->picture : NULL, |
|
1204 ); |
|
1205 $form['picture']['picture_current'] = array( |
|
1206 '#markup' => theme('user_picture', array('account' => $account)), |
|
1207 ); |
|
1208 $form['picture']['picture_delete'] = array( |
|
1209 '#type' => 'checkbox', |
|
1210 '#title' => t('Delete picture'), |
|
1211 '#access' => !empty($account->picture->fid), |
|
1212 '#description' => t('Check this box to delete your current picture.'), |
|
1213 ); |
|
1214 $form['picture']['picture_upload'] = array( |
|
1215 '#type' => 'file', |
|
1216 '#title' => t('Upload picture'), |
|
1217 '#size' => 48, |
|
1218 '#description' => t('Your virtual face or picture. Pictures larger than @dimensions pixels will be scaled down.', array('@dimensions' => variable_get('user_picture_dimensions', '85x85'))) . ' ' . filter_xss_admin(variable_get('user_picture_guidelines', '')), |
|
1219 ); |
|
1220 $form['#validate'][] = 'user_validate_picture'; |
|
1221 } |
|
1222 |
|
1223 /** |
|
1224 * Form validation handler for the current password on the user_account_form(). |
|
1225 * |
|
1226 * @see user_account_form() |
|
1227 */ |
|
1228 function user_validate_current_pass(&$form, &$form_state) { |
|
1229 $account = $form['#user']; |
|
1230 foreach ($form_state['values']['current_pass_required_values'] as $key => $name) { |
|
1231 // This validation only works for required textfields (like mail) or |
|
1232 // form values like password_confirm that have their own validation |
|
1233 // that prevent them from being empty if they are changed. |
|
1234 if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $account->$key)) { |
|
1235 require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc'); |
|
1236 $current_pass_failed = strlen(trim($form_state['values']['current_pass'])) == 0 || !user_check_password($form_state['values']['current_pass'], $account); |
|
1237 if ($current_pass_failed) { |
|
1238 form_set_error('current_pass', t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name))); |
|
1239 form_set_error($key); |
|
1240 } |
|
1241 // We only need to check the password once. |
|
1242 break; |
|
1243 } |
|
1244 } |
|
1245 } |
|
1246 |
|
1247 /** |
|
1248 * Form validation handler for user_account_form(). |
|
1249 * |
|
1250 * @see user_account_form() |
|
1251 */ |
|
1252 function user_account_form_validate($form, &$form_state) { |
|
1253 if ($form['#user_category'] == 'account' || $form['#user_category'] == 'register') { |
|
1254 $account = $form['#user']; |
|
1255 // Validate new or changing username. |
|
1256 if (isset($form_state['values']['name'])) { |
|
1257 if ($error = user_validate_name($form_state['values']['name'])) { |
|
1258 form_set_error('name', $error); |
|
1259 } |
|
1260 elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('name', db_like($form_state['values']['name']), 'LIKE')->range(0, 1)->execute()->fetchField()) { |
|
1261 form_set_error('name', t('The name %name is already taken.', array('%name' => $form_state['values']['name']))); |
|
1262 } |
|
1263 } |
|
1264 |
|
1265 // Trim whitespace from mail, to prevent confusing 'e-mail not valid' |
|
1266 // warnings often caused by cutting and pasting. |
|
1267 $mail = trim($form_state['values']['mail']); |
|
1268 form_set_value($form['account']['mail'], $mail, $form_state); |
|
1269 |
|
1270 // Validate the e-mail address, and check if it is taken by an existing user. |
|
1271 if ($error = user_validate_mail($form_state['values']['mail'])) { |
|
1272 form_set_error('mail', $error); |
|
1273 } |
|
1274 elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($form_state['values']['mail']), 'LIKE')->range(0, 1)->execute()->fetchField()) { |
|
1275 // Format error message dependent on whether the user is logged in or not. |
|
1276 if ($GLOBALS['user']->uid) { |
|
1277 form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $form_state['values']['mail']))); |
|
1278 } |
|
1279 else { |
|
1280 form_set_error('mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $form_state['values']['mail'], '@password' => url('user/password')))); |
|
1281 } |
|
1282 } |
|
1283 |
|
1284 // Make sure the signature isn't longer than the size of the database field. |
|
1285 // Signatures are disabled by default, so make sure it exists first. |
|
1286 if (isset($form_state['values']['signature'])) { |
|
1287 // Move text format for user signature into 'signature_format'. |
|
1288 $form_state['values']['signature_format'] = $form_state['values']['signature']['format']; |
|
1289 // Move text value for user signature into 'signature'. |
|
1290 $form_state['values']['signature'] = $form_state['values']['signature']['value']; |
|
1291 |
|
1292 $user_schema = drupal_get_schema('users'); |
|
1293 if (drupal_strlen($form_state['values']['signature']) > $user_schema['fields']['signature']['length']) { |
|
1294 form_set_error('signature', t('The signature is too long: it must be %max characters or less.', array('%max' => $user_schema['fields']['signature']['length']))); |
|
1295 } |
|
1296 } |
|
1297 } |
|
1298 } |
|
1299 |
|
1300 /** |
|
1301 * Implements hook_user_presave(). |
|
1302 */ |
|
1303 function user_user_presave(&$edit, $account, $category) { |
|
1304 if ($category == 'account' || $category == 'register') { |
|
1305 if (!empty($edit['picture_upload'])) { |
|
1306 $edit['picture'] = $edit['picture_upload']; |
|
1307 } |
|
1308 // Delete picture if requested, and if no replacement picture was given. |
|
1309 elseif (!empty($edit['picture_delete'])) { |
|
1310 $edit['picture'] = NULL; |
|
1311 } |
|
1312 } |
|
1313 |
|
1314 // Filter out roles with empty values to avoid granting extra roles when |
|
1315 // processing custom form submissions. |
|
1316 if (isset($edit['roles'])) { |
|
1317 $edit['roles'] = array_filter($edit['roles']); |
|
1318 } |
|
1319 |
|
1320 // Move account cancellation information into $user->data. |
|
1321 foreach (array('user_cancel_method', 'user_cancel_notify') as $key) { |
|
1322 if (isset($edit[$key])) { |
|
1323 $edit['data'][$key] = $edit[$key]; |
|
1324 } |
|
1325 } |
|
1326 } |
|
1327 |
|
1328 /** |
|
1329 * Implements hook_user_categories(). |
|
1330 */ |
|
1331 function user_user_categories() { |
|
1332 return array(array( |
|
1333 'name' => 'account', |
|
1334 'title' => t('Account settings'), |
|
1335 'weight' => 1, |
|
1336 )); |
|
1337 } |
|
1338 |
|
1339 function user_login_block($form) { |
|
1340 $form['#action'] = url(current_path(), array('query' => drupal_get_destination(), 'external' => FALSE)); |
|
1341 $form['#id'] = 'user-login-form'; |
|
1342 $form['#validate'] = user_login_default_validators(); |
|
1343 $form['#submit'][] = 'user_login_submit'; |
|
1344 $form['name'] = array('#type' => 'textfield', |
|
1345 '#title' => t('Username'), |
|
1346 '#maxlength' => USERNAME_MAX_LENGTH, |
|
1347 '#size' => 15, |
|
1348 '#required' => TRUE, |
|
1349 ); |
|
1350 $form['pass'] = array('#type' => 'password', |
|
1351 '#title' => t('Password'), |
|
1352 '#size' => 15, |
|
1353 '#required' => TRUE, |
|
1354 ); |
|
1355 $form['actions'] = array('#type' => 'actions'); |
|
1356 $form['actions']['submit'] = array('#type' => 'submit', |
|
1357 '#value' => t('Log in'), |
|
1358 ); |
|
1359 $items = array(); |
|
1360 if (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)) { |
|
1361 $items[] = l(t('Create new account'), 'user/register', array('attributes' => array('title' => t('Create a new user account.')))); |
|
1362 } |
|
1363 $items[] = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.')))); |
|
1364 $form['links'] = array('#markup' => theme('item_list', array('items' => $items))); |
|
1365 return $form; |
|
1366 } |
|
1367 |
|
1368 /** |
|
1369 * Implements hook_block_info(). |
|
1370 */ |
|
1371 function user_block_info() { |
|
1372 global $user; |
|
1373 |
|
1374 $blocks['login']['info'] = t('User login'); |
|
1375 // Not worth caching. |
|
1376 $blocks['login']['cache'] = DRUPAL_NO_CACHE; |
|
1377 |
|
1378 $blocks['new']['info'] = t('Who\'s new'); |
|
1379 $blocks['new']['properties']['administrative'] = TRUE; |
|
1380 |
|
1381 // Too dynamic to cache. |
|
1382 $blocks['online']['info'] = t('Who\'s online'); |
|
1383 $blocks['online']['cache'] = DRUPAL_NO_CACHE; |
|
1384 $blocks['online']['properties']['administrative'] = TRUE; |
|
1385 |
|
1386 return $blocks; |
|
1387 } |
|
1388 |
|
1389 /** |
|
1390 * Implements hook_block_configure(). |
|
1391 */ |
|
1392 function user_block_configure($delta = '') { |
|
1393 global $user; |
|
1394 |
|
1395 switch ($delta) { |
|
1396 case 'new': |
|
1397 $form['user_block_whois_new_count'] = array( |
|
1398 '#type' => 'select', |
|
1399 '#title' => t('Number of users to display'), |
|
1400 '#default_value' => variable_get('user_block_whois_new_count', 5), |
|
1401 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), |
|
1402 ); |
|
1403 return $form; |
|
1404 |
|
1405 case 'online': |
|
1406 $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval'); |
|
1407 $form['user_block_seconds_online'] = array('#type' => 'select', '#title' => t('User activity'), '#default_value' => variable_get('user_block_seconds_online', 900), '#options' => $period, '#description' => t('A user is considered online for this long after they have last viewed a page.')); |
|
1408 $form['user_block_max_list_count'] = array('#type' => 'select', '#title' => t('User list length'), '#default_value' => variable_get('user_block_max_list_count', 10), '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100)), '#description' => t('Maximum number of currently online users to display.')); |
|
1409 return $form; |
|
1410 } |
|
1411 } |
|
1412 |
|
1413 /** |
|
1414 * Implements hook_block_save(). |
|
1415 */ |
|
1416 function user_block_save($delta = '', $edit = array()) { |
|
1417 global $user; |
|
1418 |
|
1419 switch ($delta) { |
|
1420 case 'new': |
|
1421 variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']); |
|
1422 break; |
|
1423 |
|
1424 case 'online': |
|
1425 variable_set('user_block_seconds_online', $edit['user_block_seconds_online']); |
|
1426 variable_set('user_block_max_list_count', $edit['user_block_max_list_count']); |
|
1427 break; |
|
1428 } |
|
1429 } |
|
1430 |
|
1431 /** |
|
1432 * Implements hook_block_view(). |
|
1433 */ |
|
1434 function user_block_view($delta = '') { |
|
1435 global $user; |
|
1436 |
|
1437 $block = array(); |
|
1438 |
|
1439 switch ($delta) { |
|
1440 case 'login': |
|
1441 // For usability's sake, avoid showing two login forms on one page. |
|
1442 if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) { |
|
1443 |
|
1444 $block['subject'] = t('User login'); |
|
1445 $block['content'] = drupal_get_form('user_login_block'); |
|
1446 } |
|
1447 return $block; |
|
1448 |
|
1449 case 'new': |
|
1450 if (user_access('access content')) { |
|
1451 // Retrieve a list of new users who have subsequently accessed the site successfully. |
|
1452 $items = db_query_range('SELECT uid, name FROM {users} WHERE status <> 0 AND access <> 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5))->fetchAll(); |
|
1453 $output = theme('user_list', array('users' => $items)); |
|
1454 |
|
1455 $block['subject'] = t('Who\'s new'); |
|
1456 $block['content'] = $output; |
|
1457 } |
|
1458 return $block; |
|
1459 |
|
1460 case 'online': |
|
1461 if (user_access('access content')) { |
|
1462 // Count users active within the defined period. |
|
1463 $interval = REQUEST_TIME - variable_get('user_block_seconds_online', 900); |
|
1464 |
|
1465 // Perform database queries to gather online user lists. We use s.timestamp |
|
1466 // rather than u.access because it is much faster. |
|
1467 $authenticated_count = db_query("SELECT COUNT(DISTINCT s.uid) FROM {sessions} s WHERE s.timestamp >= :timestamp AND s.uid > 0", array(':timestamp' => $interval))->fetchField(); |
|
1468 |
|
1469 $output = '<p>' . format_plural($authenticated_count, 'There is currently 1 user online.', 'There are currently @count users online.') . '</p>'; |
|
1470 |
|
1471 // Display a list of currently online users. |
|
1472 $max_users = variable_get('user_block_max_list_count', 10); |
|
1473 if ($authenticated_count && $max_users) { |
|
1474 $items = db_query_range('SELECT u.uid, u.name, MAX(s.timestamp) AS max_timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= :interval AND s.uid > 0 GROUP BY u.uid, u.name ORDER BY max_timestamp DESC', 0, $max_users, array(':interval' => $interval))->fetchAll(); |
|
1475 $output .= theme('user_list', array('users' => $items)); |
|
1476 } |
|
1477 |
|
1478 $block['subject'] = t('Who\'s online'); |
|
1479 $block['content'] = $output; |
|
1480 } |
|
1481 return $block; |
|
1482 } |
|
1483 } |
|
1484 |
|
1485 /** |
|
1486 * Process variables for user-picture.tpl.php. |
|
1487 * |
|
1488 * The $variables array contains the following arguments: |
|
1489 * - $account: A user, node or comment object with 'name', 'uid' and 'picture' |
|
1490 * fields. |
|
1491 * |
|
1492 * @see user-picture.tpl.php |
|
1493 */ |
|
1494 function template_preprocess_user_picture(&$variables) { |
|
1495 $variables['user_picture'] = ''; |
|
1496 if (variable_get('user_pictures', 0)) { |
|
1497 $account = $variables['account']; |
|
1498 if (!empty($account->picture)) { |
|
1499 // @TODO: Ideally this function would only be passed file objects, but |
|
1500 // since there's a lot of legacy code that JOINs the {users} table to |
|
1501 // {node} or {comments} and passes the results into this function if we |
|
1502 // a numeric value in the picture field we'll assume it's a file id |
|
1503 // and load it for them. Once we've got user_load_multiple() and |
|
1504 // comment_load_multiple() functions the user module will be able to load |
|
1505 // the picture files in mass during the object's load process. |
|
1506 if (is_numeric($account->picture)) { |
|
1507 $account->picture = file_load($account->picture); |
|
1508 } |
|
1509 if (!empty($account->picture->uri)) { |
|
1510 $filepath = $account->picture->uri; |
|
1511 } |
|
1512 } |
|
1513 elseif (variable_get('user_picture_default', '')) { |
|
1514 $filepath = variable_get('user_picture_default', ''); |
|
1515 } |
|
1516 if (isset($filepath)) { |
|
1517 $alt = t("@user's picture", array('@user' => format_username($account))); |
|
1518 // If the image does not have a valid Drupal scheme (for eg. HTTP), |
|
1519 // don't load image styles. |
|
1520 if (module_exists('image') && file_valid_uri($filepath) && $style = variable_get('user_picture_style', '')) { |
|
1521 $variables['user_picture'] = theme('image_style', array('style_name' => $style, 'path' => $filepath, 'alt' => $alt, 'title' => $alt)); |
|
1522 } |
|
1523 else { |
|
1524 $variables['user_picture'] = theme('image', array('path' => $filepath, 'alt' => $alt, 'title' => $alt)); |
|
1525 } |
|
1526 if (!empty($account->uid) && user_access('access user profiles')) { |
|
1527 $attributes = array('attributes' => array('title' => t('View user profile.')), 'html' => TRUE); |
|
1528 $variables['user_picture'] = l($variables['user_picture'], "user/$account->uid", $attributes); |
|
1529 } |
|
1530 } |
|
1531 } |
|
1532 } |
|
1533 |
|
1534 /** |
|
1535 * Returns HTML for a list of users. |
|
1536 * |
|
1537 * @param $variables |
|
1538 * An associative array containing: |
|
1539 * - users: An array with user objects. Should contain at least the name and |
|
1540 * uid. |
|
1541 * - title: (optional) Title to pass on to theme_item_list(). |
|
1542 * |
|
1543 * @ingroup themeable |
|
1544 */ |
|
1545 function theme_user_list($variables) { |
|
1546 $users = $variables['users']; |
|
1547 $title = $variables['title']; |
|
1548 $items = array(); |
|
1549 |
|
1550 if (!empty($users)) { |
|
1551 foreach ($users as $user) { |
|
1552 $items[] = theme('username', array('account' => $user)); |
|
1553 } |
|
1554 } |
|
1555 return theme('item_list', array('items' => $items, 'title' => $title)); |
|
1556 } |
|
1557 |
|
1558 /** |
|
1559 * Determines if the current user is anonymous. |
|
1560 * |
|
1561 * @return bool |
|
1562 * TRUE if the user is anonymous, FALSE if the user is authenticated. |
|
1563 */ |
|
1564 function user_is_anonymous() { |
|
1565 // Menu administrators can see items for anonymous when administering. |
|
1566 return !$GLOBALS['user']->uid || !empty($GLOBALS['menu_admin']); |
|
1567 } |
|
1568 |
|
1569 /** |
|
1570 * Determines if the current user is logged in. |
|
1571 * |
|
1572 * @return bool |
|
1573 * TRUE if the user is logged in, FALSE if the user is anonymous. |
|
1574 */ |
|
1575 function user_is_logged_in() { |
|
1576 return (bool) $GLOBALS['user']->uid; |
|
1577 } |
|
1578 |
|
1579 /** |
|
1580 * Determines if the current user has access to the user registration page. |
|
1581 * |
|
1582 * @return bool |
|
1583 * TRUE if the user is not already logged in and can register for an account. |
|
1584 */ |
|
1585 function user_register_access() { |
|
1586 return user_is_anonymous() && variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL); |
|
1587 } |
|
1588 |
|
1589 /** |
|
1590 * User view access callback. |
|
1591 * |
|
1592 * @param $account |
|
1593 * Can either be a full user object or a $uid. |
|
1594 */ |
|
1595 function user_view_access($account) { |
|
1596 $uid = is_object($account) ? $account->uid : (int) $account; |
|
1597 |
|
1598 // Never allow access to view the anonymous user account. |
|
1599 if ($uid) { |
|
1600 // Admins can view all, users can view own profiles at all times. |
|
1601 if ($GLOBALS['user']->uid == $uid || user_access('administer users')) { |
|
1602 return TRUE; |
|
1603 } |
|
1604 elseif (user_access('access user profiles')) { |
|
1605 // At this point, load the complete account object. |
|
1606 if (!is_object($account)) { |
|
1607 $account = user_load($uid); |
|
1608 } |
|
1609 return (is_object($account) && $account->status); |
|
1610 } |
|
1611 } |
|
1612 return FALSE; |
|
1613 } |
|
1614 |
|
1615 /** |
|
1616 * Access callback for user account editing. |
|
1617 */ |
|
1618 function user_edit_access($account) { |
|
1619 return (($GLOBALS['user']->uid == $account->uid) || user_access('administer users')) && $account->uid > 0; |
|
1620 } |
|
1621 |
|
1622 /** |
|
1623 * Menu access callback; limit access to account cancellation pages. |
|
1624 * |
|
1625 * Limit access to users with the 'cancel account' permission or administrative |
|
1626 * users, and prevent the anonymous user from cancelling the account. |
|
1627 */ |
|
1628 function user_cancel_access($account) { |
|
1629 return ((($GLOBALS['user']->uid == $account->uid) && user_access('cancel account')) || user_access('administer users')) && $account->uid > 0; |
|
1630 } |
|
1631 |
|
1632 /** |
|
1633 * Implements hook_menu(). |
|
1634 */ |
|
1635 function user_menu() { |
|
1636 $items['user/autocomplete'] = array( |
|
1637 'title' => 'User autocomplete', |
|
1638 'page callback' => 'user_autocomplete', |
|
1639 'access callback' => 'user_access', |
|
1640 'access arguments' => array('access user profiles'), |
|
1641 'type' => MENU_CALLBACK, |
|
1642 'file' => 'user.pages.inc', |
|
1643 ); |
|
1644 |
|
1645 // Registration and login pages. |
|
1646 $items['user'] = array( |
|
1647 'title' => 'User account', |
|
1648 'title callback' => 'user_menu_title', |
|
1649 'page callback' => 'user_page', |
|
1650 'access callback' => TRUE, |
|
1651 'file' => 'user.pages.inc', |
|
1652 'weight' => -10, |
|
1653 'menu_name' => 'user-menu', |
|
1654 ); |
|
1655 |
|
1656 $items['user/login'] = array( |
|
1657 'title' => 'Log in', |
|
1658 'access callback' => 'user_is_anonymous', |
|
1659 'type' => MENU_DEFAULT_LOCAL_TASK, |
|
1660 ); |
|
1661 |
|
1662 $items['user/register'] = array( |
|
1663 'title' => 'Create new account', |
|
1664 'page callback' => 'drupal_get_form', |
|
1665 'page arguments' => array('user_register_form'), |
|
1666 'access callback' => 'user_register_access', |
|
1667 'type' => MENU_LOCAL_TASK, |
|
1668 ); |
|
1669 |
|
1670 $items['user/password'] = array( |
|
1671 'title' => 'Request new password', |
|
1672 'page callback' => 'drupal_get_form', |
|
1673 'page arguments' => array('user_pass'), |
|
1674 'access callback' => TRUE, |
|
1675 'type' => MENU_LOCAL_TASK, |
|
1676 'file' => 'user.pages.inc', |
|
1677 ); |
|
1678 $items['user/reset/%/%/%'] = array( |
|
1679 'title' => 'Reset password', |
|
1680 'page callback' => 'drupal_get_form', |
|
1681 'page arguments' => array('user_pass_reset', 2, 3, 4), |
|
1682 'access callback' => TRUE, |
|
1683 'type' => MENU_CALLBACK, |
|
1684 'file' => 'user.pages.inc', |
|
1685 ); |
|
1686 |
|
1687 $items['user/logout'] = array( |
|
1688 'title' => 'Log out', |
|
1689 'access callback' => 'user_is_logged_in', |
|
1690 'page callback' => 'user_logout', |
|
1691 'weight' => 10, |
|
1692 'menu_name' => 'user-menu', |
|
1693 'file' => 'user.pages.inc', |
|
1694 ); |
|
1695 |
|
1696 // User listing pages. |
|
1697 $items['admin/people'] = array( |
|
1698 'title' => 'People', |
|
1699 'description' => 'Manage user accounts, roles, and permissions.', |
|
1700 'page callback' => 'user_admin', |
|
1701 'page arguments' => array('list'), |
|
1702 'access arguments' => array('administer users'), |
|
1703 'position' => 'left', |
|
1704 'weight' => -4, |
|
1705 'file' => 'user.admin.inc', |
|
1706 ); |
|
1707 $items['admin/people/people'] = array( |
|
1708 'title' => 'List', |
|
1709 'description' => 'Find and manage people interacting with your site.', |
|
1710 'access arguments' => array('administer users'), |
|
1711 'type' => MENU_DEFAULT_LOCAL_TASK, |
|
1712 'weight' => -10, |
|
1713 'file' => 'user.admin.inc', |
|
1714 ); |
|
1715 |
|
1716 // Permissions and role forms. |
|
1717 $items['admin/people/permissions'] = array( |
|
1718 'title' => 'Permissions', |
|
1719 'description' => 'Determine access to features by selecting permissions for roles.', |
|
1720 'page callback' => 'drupal_get_form', |
|
1721 'page arguments' => array('user_admin_permissions'), |
|
1722 'access arguments' => array('administer permissions'), |
|
1723 'file' => 'user.admin.inc', |
|
1724 'type' => MENU_LOCAL_TASK, |
|
1725 ); |
|
1726 $items['admin/people/permissions/list'] = array( |
|
1727 'title' => 'Permissions', |
|
1728 'description' => 'Determine access to features by selecting permissions for roles.', |
|
1729 'type' => MENU_DEFAULT_LOCAL_TASK, |
|
1730 'weight' => -8, |
|
1731 ); |
|
1732 $items['admin/people/permissions/roles'] = array( |
|
1733 'title' => 'Roles', |
|
1734 'description' => 'List, edit, or add user roles.', |
|
1735 'page callback' => 'drupal_get_form', |
|
1736 'page arguments' => array('user_admin_roles'), |
|
1737 'access arguments' => array('administer permissions'), |
|
1738 'file' => 'user.admin.inc', |
|
1739 'type' => MENU_LOCAL_TASK, |
|
1740 'weight' => -5, |
|
1741 ); |
|
1742 $items['admin/people/permissions/roles/edit/%user_role'] = array( |
|
1743 'title' => 'Edit role', |
|
1744 'page arguments' => array('user_admin_role', 5), |
|
1745 'access callback' => 'user_role_edit_access', |
|
1746 'access arguments' => array(5), |
|
1747 ); |
|
1748 $items['admin/people/permissions/roles/delete/%user_role'] = array( |
|
1749 'title' => 'Delete role', |
|
1750 'page callback' => 'drupal_get_form', |
|
1751 'page arguments' => array('user_admin_role_delete_confirm', 5), |
|
1752 'access callback' => 'user_role_edit_access', |
|
1753 'access arguments' => array(5), |
|
1754 'file' => 'user.admin.inc', |
|
1755 ); |
|
1756 |
|
1757 $items['admin/people/create'] = array( |
|
1758 'title' => 'Add user', |
|
1759 'page callback' => 'user_admin', |
|
1760 'page arguments' => array('create'), |
|
1761 'access arguments' => array('administer users'), |
|
1762 'type' => MENU_LOCAL_ACTION, |
|
1763 'file' => 'user.admin.inc', |
|
1764 ); |
|
1765 |
|
1766 // Administration pages. |
|
1767 $items['admin/config/people'] = array( |
|
1768 'title' => 'People', |
|
1769 'description' => 'Configure user accounts.', |
|
1770 'position' => 'left', |
|
1771 'weight' => -20, |
|
1772 'page callback' => 'system_admin_menu_block_page', |
|
1773 'access arguments' => array('access administration pages'), |
|
1774 'file' => 'system.admin.inc', |
|
1775 'file path' => drupal_get_path('module', 'system'), |
|
1776 ); |
|
1777 $items['admin/config/people/accounts'] = array( |
|
1778 'title' => 'Account settings', |
|
1779 'description' => 'Configure default behavior of users, including registration requirements, e-mails, fields, and user pictures.', |
|
1780 'page callback' => 'drupal_get_form', |
|
1781 'page arguments' => array('user_admin_settings'), |
|
1782 'access arguments' => array('administer users'), |
|
1783 'file' => 'user.admin.inc', |
|
1784 'weight' => -10, |
|
1785 ); |
|
1786 $items['admin/config/people/accounts/settings'] = array( |
|
1787 'title' => 'Settings', |
|
1788 'type' => MENU_DEFAULT_LOCAL_TASK, |
|
1789 'weight' => -10, |
|
1790 ); |
|
1791 |
|
1792 $items['user/%user'] = array( |
|
1793 'title' => 'My account', |
|
1794 'title callback' => 'user_page_title', |
|
1795 'title arguments' => array(1), |
|
1796 'page callback' => 'user_view_page', |
|
1797 'page arguments' => array(1), |
|
1798 'access callback' => 'user_view_access', |
|
1799 'access arguments' => array(1), |
|
1800 // By assigning a different menu name, this item (and all registered child |
|
1801 // paths) are no longer considered as children of 'user'. When accessing the |
|
1802 // user account pages, the preferred menu link that is used to build the |
|
1803 // active trail (breadcrumb) will be found in this menu (unless there is |
|
1804 // more specific link), so the link to 'user' will not be in the breadcrumb. |
|
1805 'menu_name' => 'navigation', |
|
1806 ); |
|
1807 |
|
1808 $items['user/%user/view'] = array( |
|
1809 'title' => 'View', |
|
1810 'type' => MENU_DEFAULT_LOCAL_TASK, |
|
1811 'weight' => -10, |
|
1812 ); |
|
1813 |
|
1814 $items['user/%user/cancel'] = array( |
|
1815 'title' => 'Cancel account', |
|
1816 'page callback' => 'drupal_get_form', |
|
1817 'page arguments' => array('user_cancel_confirm_form', 1), |
|
1818 'access callback' => 'user_cancel_access', |
|
1819 'access arguments' => array(1), |
|
1820 'file' => 'user.pages.inc', |
|
1821 ); |
|
1822 |
|
1823 $items['user/%user/cancel/confirm/%/%'] = array( |
|
1824 'title' => 'Confirm account cancellation', |
|
1825 'page callback' => 'user_cancel_confirm', |
|
1826 'page arguments' => array(1, 4, 5), |
|
1827 'access callback' => 'user_cancel_access', |
|
1828 'access arguments' => array(1), |
|
1829 'file' => 'user.pages.inc', |
|
1830 ); |
|
1831 |
|
1832 $items['user/%user/edit'] = array( |
|
1833 'title' => 'Edit', |
|
1834 'page callback' => 'drupal_get_form', |
|
1835 'page arguments' => array('user_profile_form', 1), |
|
1836 'access callback' => 'user_edit_access', |
|
1837 'access arguments' => array(1), |
|
1838 'type' => MENU_LOCAL_TASK, |
|
1839 'file' => 'user.pages.inc', |
|
1840 ); |
|
1841 |
|
1842 $items['user/%user_category/edit/account'] = array( |
|
1843 'title' => 'Account', |
|
1844 'type' => MENU_DEFAULT_LOCAL_TASK, |
|
1845 'load arguments' => array('%map', '%index'), |
|
1846 ); |
|
1847 |
|
1848 if (($categories = _user_categories()) && (count($categories) > 1)) { |
|
1849 foreach ($categories as $key => $category) { |
|
1850 // 'account' is already handled by the MENU_DEFAULT_LOCAL_TASK. |
|
1851 if ($category['name'] != 'account') { |
|
1852 $items['user/%user_category/edit/' . $category['name']] = array( |
|
1853 'title callback' => 'check_plain', |
|
1854 'title arguments' => array($category['title']), |
|
1855 'page callback' => 'drupal_get_form', |
|
1856 'page arguments' => array('user_profile_form', 1, 3), |
|
1857 'access callback' => isset($category['access callback']) ? $category['access callback'] : 'user_edit_access', |
|
1858 'access arguments' => isset($category['access arguments']) ? $category['access arguments'] : array(1), |
|
1859 'type' => MENU_LOCAL_TASK, |
|
1860 'weight' => $category['weight'], |
|
1861 'load arguments' => array('%map', '%index'), |
|
1862 'tab_parent' => 'user/%/edit', |
|
1863 'file' => 'user.pages.inc', |
|
1864 ); |
|
1865 } |
|
1866 } |
|
1867 } |
|
1868 return $items; |
|
1869 } |
|
1870 |
|
1871 /** |
|
1872 * Implements hook_menu_site_status_alter(). |
|
1873 */ |
|
1874 function user_menu_site_status_alter(&$menu_site_status, $path) { |
|
1875 if ($menu_site_status == MENU_SITE_OFFLINE) { |
|
1876 // If the site is offline, log out unprivileged users. |
|
1877 if (user_is_logged_in() && !user_access('access site in maintenance mode')) { |
|
1878 module_load_include('pages.inc', 'user', 'user'); |
|
1879 user_logout(); |
|
1880 } |
|
1881 |
|
1882 if (user_is_anonymous()) { |
|
1883 switch ($path) { |
|
1884 case 'user': |
|
1885 // Forward anonymous user to login page. |
|
1886 drupal_goto('user/login'); |
|
1887 case 'user/login': |
|
1888 case 'user/password': |
|
1889 // Disable offline mode. |
|
1890 $menu_site_status = MENU_SITE_ONLINE; |
|
1891 break; |
|
1892 default: |
|
1893 if (strpos($path, 'user/reset/') === 0) { |
|
1894 // Disable offline mode. |
|
1895 $menu_site_status = MENU_SITE_ONLINE; |
|
1896 } |
|
1897 break; |
|
1898 } |
|
1899 } |
|
1900 } |
|
1901 if (user_is_logged_in()) { |
|
1902 if ($path == 'user/login') { |
|
1903 // If user is logged in, redirect to 'user' instead of giving 403. |
|
1904 drupal_goto('user'); |
|
1905 } |
|
1906 if ($path == 'user/register') { |
|
1907 // Authenticated user should be redirected to user edit page. |
|
1908 drupal_goto('user/' . $GLOBALS['user']->uid . '/edit'); |
|
1909 } |
|
1910 } |
|
1911 } |
|
1912 |
|
1913 /** |
|
1914 * Implements hook_menu_link_alter(). |
|
1915 */ |
|
1916 function user_menu_link_alter(&$link) { |
|
1917 // The path 'user' must be accessible for anonymous users, but only visible |
|
1918 // for authenticated users. Authenticated users should see "My account", but |
|
1919 // anonymous users should not see it at all. Therefore, invoke |
|
1920 // user_translated_menu_link_alter() to conditionally hide the link. |
|
1921 if ($link['link_path'] == 'user' && isset($link['module']) && $link['module'] == 'system') { |
|
1922 $link['options']['alter'] = TRUE; |
|
1923 } |
|
1924 |
|
1925 // Force the Logout link to appear on the top-level of 'user-menu' menu by |
|
1926 // default (i.e., unless it has been customized). |
|
1927 if ($link['link_path'] == 'user/logout' && isset($link['module']) && $link['module'] == 'system' && empty($link['customized'])) { |
|
1928 $link['plid'] = 0; |
|
1929 } |
|
1930 } |
|
1931 |
|
1932 /** |
|
1933 * Implements hook_translated_menu_link_alter(). |
|
1934 */ |
|
1935 function user_translated_menu_link_alter(&$link) { |
|
1936 // Hide the "User account" link for anonymous users. |
|
1937 if ($link['link_path'] == 'user' && $link['module'] == 'system' && !$GLOBALS['user']->uid) { |
|
1938 $link['hidden'] = 1; |
|
1939 } |
|
1940 } |
|
1941 |
|
1942 /** |
|
1943 * Implements hook_admin_paths(). |
|
1944 */ |
|
1945 function user_admin_paths() { |
|
1946 $paths = array( |
|
1947 'user/*/cancel' => TRUE, |
|
1948 'user/*/edit' => TRUE, |
|
1949 'user/*/edit/*' => TRUE, |
|
1950 ); |
|
1951 return $paths; |
|
1952 } |
|
1953 |
|
1954 /** |
|
1955 * Returns $arg or the user ID of the current user if $arg is '%' or empty. |
|
1956 * |
|
1957 * Deprecated. Use %user_uid_optional instead. |
|
1958 * |
|
1959 * @todo D8: Remove. |
|
1960 */ |
|
1961 function user_uid_only_optional_to_arg($arg) { |
|
1962 return user_uid_optional_to_arg($arg); |
|
1963 } |
|
1964 |
|
1965 /** |
|
1966 * Load either a specified or the current user account. |
|
1967 * |
|
1968 * @param $uid |
|
1969 * An optional user ID of the user to load. If not provided, the current |
|
1970 * user's ID will be used. |
|
1971 * @return |
|
1972 * A fully-loaded $user object upon successful user load, FALSE if user |
|
1973 * cannot be loaded. |
|
1974 * |
|
1975 * @see user_load() |
|
1976 * @todo rethink the naming of this in Drupal 8. |
|
1977 */ |
|
1978 function user_uid_optional_load($uid = NULL) { |
|
1979 if (!isset($uid)) { |
|
1980 $uid = $GLOBALS['user']->uid; |
|
1981 } |
|
1982 return user_load($uid); |
|
1983 } |
|
1984 |
|
1985 /** |
|
1986 * Return a user object after checking if any profile category in the path exists. |
|
1987 */ |
|
1988 function user_category_load($uid, &$map, $index) { |
|
1989 static $user_categories, $accounts; |
|
1990 |
|
1991 // Cache $account - this load function will get called for each profile tab. |
|
1992 if (!isset($accounts[$uid])) { |
|
1993 $accounts[$uid] = user_load($uid); |
|
1994 } |
|
1995 $valid = TRUE; |
|
1996 if ($account = $accounts[$uid]) { |
|
1997 // Since the path is like user/%/edit/category_name, the category name will |
|
1998 // be at a position 2 beyond the index corresponding to the % wildcard. |
|
1999 $category_index = $index + 2; |
|
2000 // Valid categories may contain slashes, and hence need to be imploded. |
|
2001 $category_path = implode('/', array_slice($map, $category_index)); |
|
2002 if ($category_path) { |
|
2003 // Check that the requested category exists. |
|
2004 $valid = FALSE; |
|
2005 if (!isset($user_categories)) { |
|
2006 $user_categories = _user_categories(); |
|
2007 } |
|
2008 foreach ($user_categories as $category) { |
|
2009 if ($category['name'] == $category_path) { |
|
2010 $valid = TRUE; |
|
2011 // Truncate the map array in case the category name had slashes. |
|
2012 $map = array_slice($map, 0, $category_index); |
|
2013 // Assign the imploded category name to the last map element. |
|
2014 $map[$category_index] = $category_path; |
|
2015 break; |
|
2016 } |
|
2017 } |
|
2018 } |
|
2019 } |
|
2020 return $valid ? $account : FALSE; |
|
2021 } |
|
2022 |
|
2023 /** |
|
2024 * Returns $arg or the user ID of the current user if $arg is '%' or empty. |
|
2025 * |
|
2026 * @todo rethink the naming of this in Drupal 8. |
|
2027 */ |
|
2028 function user_uid_optional_to_arg($arg) { |
|
2029 // Give back the current user uid when called from eg. tracker, aka. |
|
2030 // with an empty arg. Also use the current user uid when called from |
|
2031 // the menu with a % for the current account link. |
|
2032 return empty($arg) || $arg == '%' ? $GLOBALS['user']->uid : $arg; |
|
2033 } |
|
2034 |
|
2035 /** |
|
2036 * Menu item title callback for the 'user' path. |
|
2037 * |
|
2038 * Anonymous users should see "User account", but authenticated users are |
|
2039 * expected to see "My account". |
|
2040 */ |
|
2041 function user_menu_title() { |
|
2042 return user_is_logged_in() ? t('My account') : t('User account'); |
|
2043 } |
|
2044 |
|
2045 /** |
|
2046 * Menu item title callback - use the user name. |
|
2047 */ |
|
2048 function user_page_title($account) { |
|
2049 return is_object($account) ? format_username($account) : ''; |
|
2050 } |
|
2051 |
|
2052 /** |
|
2053 * Discover which external authentication module(s) authenticated a username. |
|
2054 * |
|
2055 * @param $authname |
|
2056 * A username used by an external authentication module. |
|
2057 * @return |
|
2058 * An associative array with module as key and username as value. |
|
2059 */ |
|
2060 function user_get_authmaps($authname = NULL) { |
|
2061 $authmaps = db_query("SELECT module, authname FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchAllKeyed(); |
|
2062 return count($authmaps) ? $authmaps : 0; |
|
2063 } |
|
2064 |
|
2065 /** |
|
2066 * Save mappings of which external authentication module(s) authenticated |
|
2067 * a user. Maps external usernames to user ids in the users table. |
|
2068 * |
|
2069 * @param $account |
|
2070 * A user object. |
|
2071 * @param $authmaps |
|
2072 * An associative array with a compound key and the username as the value. |
|
2073 * The key is made up of 'authname_' plus the name of the external authentication |
|
2074 * module. |
|
2075 * @see user_external_login_register() |
|
2076 */ |
|
2077 function user_set_authmaps($account, $authmaps) { |
|
2078 foreach ($authmaps as $key => $value) { |
|
2079 $module = explode('_', $key, 2); |
|
2080 if ($value) { |
|
2081 db_merge('authmap') |
|
2082 ->key(array( |
|
2083 'uid' => $account->uid, |
|
2084 'module' => $module[1], |
|
2085 )) |
|
2086 ->fields(array('authname' => $value)) |
|
2087 ->execute(); |
|
2088 } |
|
2089 else { |
|
2090 db_delete('authmap') |
|
2091 ->condition('uid', $account->uid) |
|
2092 ->condition('module', $module[1]) |
|
2093 ->execute(); |
|
2094 } |
|
2095 } |
|
2096 } |
|
2097 |
|
2098 /** |
|
2099 * Form builder; the main user login form. |
|
2100 * |
|
2101 * @ingroup forms |
|
2102 */ |
|
2103 function user_login($form, &$form_state) { |
|
2104 global $user; |
|
2105 |
|
2106 // If we are already logged on, go to the user page instead. |
|
2107 if ($user->uid) { |
|
2108 drupal_goto('user/' . $user->uid); |
|
2109 } |
|
2110 |
|
2111 // Display login form: |
|
2112 $form['name'] = array('#type' => 'textfield', |
|
2113 '#title' => t('Username'), |
|
2114 '#size' => 60, |
|
2115 '#maxlength' => USERNAME_MAX_LENGTH, |
|
2116 '#required' => TRUE, |
|
2117 ); |
|
2118 |
|
2119 $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal'))); |
|
2120 $form['pass'] = array('#type' => 'password', |
|
2121 '#title' => t('Password'), |
|
2122 '#description' => t('Enter the password that accompanies your username.'), |
|
2123 '#required' => TRUE, |
|
2124 ); |
|
2125 $form['#validate'] = user_login_default_validators(); |
|
2126 $form['actions'] = array('#type' => 'actions'); |
|
2127 $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in')); |
|
2128 |
|
2129 return $form; |
|
2130 } |
|
2131 |
|
2132 /** |
|
2133 * Set up a series for validators which check for blocked users, |
|
2134 * then authenticate against local database, then return an error if |
|
2135 * authentication fails. Distributed authentication modules are welcome |
|
2136 * to use hook_form_alter() to change this series in order to |
|
2137 * authenticate against their user database instead of the local users |
|
2138 * table. If a distributed authentication module is successful, it |
|
2139 * should set $form_state['uid'] to a user ID. |
|
2140 * |
|
2141 * We use three validators instead of one since external authentication |
|
2142 * modules usually only need to alter the second validator. |
|
2143 * |
|
2144 * @see user_login_name_validate() |
|
2145 * @see user_login_authenticate_validate() |
|
2146 * @see user_login_final_validate() |
|
2147 * @return array |
|
2148 * A simple list of validate functions. |
|
2149 */ |
|
2150 function user_login_default_validators() { |
|
2151 return array('user_login_name_validate', 'user_login_authenticate_validate', 'user_login_final_validate'); |
|
2152 } |
|
2153 |
|
2154 /** |
|
2155 * A FAPI validate handler. Sets an error if supplied username has been blocked. |
|
2156 */ |
|
2157 function user_login_name_validate($form, &$form_state) { |
|
2158 if (!empty($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) { |
|
2159 // Blocked in user administration. |
|
2160 form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name']))); |
|
2161 } |
|
2162 } |
|
2163 |
|
2164 /** |
|
2165 * A validate handler on the login form. Check supplied username/password |
|
2166 * against local users table. If successful, $form_state['uid'] |
|
2167 * is set to the matching user ID. |
|
2168 */ |
|
2169 function user_login_authenticate_validate($form, &$form_state) { |
|
2170 $password = trim($form_state['values']['pass']); |
|
2171 if (!empty($form_state['values']['name']) && strlen(trim($password)) > 0) { |
|
2172 // Do not allow any login from the current user's IP if the limit has been |
|
2173 // reached. Default is 50 failed attempts allowed in one hour. This is |
|
2174 // independent of the per-user limit to catch attempts from one IP to log |
|
2175 // in to many different user accounts. We have a reasonably high limit |
|
2176 // since there may be only one apparent IP for all users at an institution. |
|
2177 if (!flood_is_allowed('failed_login_attempt_ip', variable_get('user_failed_login_ip_limit', 50), variable_get('user_failed_login_ip_window', 3600))) { |
|
2178 $form_state['flood_control_triggered'] = 'ip'; |
|
2179 return; |
|
2180 } |
|
2181 $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject(); |
|
2182 if ($account) { |
|
2183 if (variable_get('user_failed_login_identifier_uid_only', FALSE)) { |
|
2184 // Register flood events based on the uid only, so they apply for any |
|
2185 // IP address. This is the most secure option. |
|
2186 $identifier = $account->uid; |
|
2187 } |
|
2188 else { |
|
2189 // The default identifier is a combination of uid and IP address. This |
|
2190 // is less secure but more resistant to denial-of-service attacks that |
|
2191 // could lock out all users with public user names. |
|
2192 $identifier = $account->uid . '-' . ip_address(); |
|
2193 } |
|
2194 $form_state['flood_control_user_identifier'] = $identifier; |
|
2195 |
|
2196 // Don't allow login if the limit for this user has been reached. |
|
2197 // Default is to allow 5 failed attempts every 6 hours. |
|
2198 if (!flood_is_allowed('failed_login_attempt_user', variable_get('user_failed_login_user_limit', 5), variable_get('user_failed_login_user_window', 21600), $identifier)) { |
|
2199 $form_state['flood_control_triggered'] = 'user'; |
|
2200 return; |
|
2201 } |
|
2202 } |
|
2203 // We are not limited by flood control, so try to authenticate. |
|
2204 // Set $form_state['uid'] as a flag for user_login_final_validate(). |
|
2205 $form_state['uid'] = user_authenticate($form_state['values']['name'], $password); |
|
2206 } |
|
2207 } |
|
2208 |
|
2209 /** |
|
2210 * The final validation handler on the login form. |
|
2211 * |
|
2212 * Sets a form error if user has not been authenticated, or if too many |
|
2213 * logins have been attempted. This validation function should always |
|
2214 * be the last one. |
|
2215 */ |
|
2216 function user_login_final_validate($form, &$form_state) { |
|
2217 if (empty($form_state['uid'])) { |
|
2218 // Always register an IP-based failed login event. |
|
2219 flood_register_event('failed_login_attempt_ip', variable_get('user_failed_login_ip_window', 3600)); |
|
2220 // Register a per-user failed login event. |
|
2221 if (isset($form_state['flood_control_user_identifier'])) { |
|
2222 flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 21600), $form_state['flood_control_user_identifier']); |
|
2223 } |
|
2224 |
|
2225 if (isset($form_state['flood_control_triggered'])) { |
|
2226 if ($form_state['flood_control_triggered'] == 'user') { |
|
2227 form_set_error('name', format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password')))); |
|
2228 } |
|
2229 else { |
|
2230 // We did not find a uid, so the limit is IP-based. |
|
2231 form_set_error('name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password')))); |
|
2232 } |
|
2233 } |
|
2234 else { |
|
2235 // Use $form_state['input']['name'] here to guarantee that we send |
|
2236 // exactly what the user typed in. $form_state['values']['name'] may have |
|
2237 // been modified by validation handlers that ran earlier than this one. |
|
2238 $query = isset($form_state['input']['name']) ? array('name' => $form_state['input']['name']) : array(); |
|
2239 form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password', array('query' => $query))))); |
|
2240 watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name'])); |
|
2241 } |
|
2242 } |
|
2243 elseif (isset($form_state['flood_control_user_identifier'])) { |
|
2244 // Clear past failures for this user so as not to block a user who might |
|
2245 // log in and out more than once in an hour. |
|
2246 flood_clear_event('failed_login_attempt_user', $form_state['flood_control_user_identifier']); |
|
2247 } |
|
2248 } |
|
2249 |
|
2250 /** |
|
2251 * Try to validate the user's login credentials locally. |
|
2252 * |
|
2253 * @param $name |
|
2254 * User name to authenticate. |
|
2255 * @param $password |
|
2256 * A plain-text password, such as trimmed text from form values. |
|
2257 * @return |
|
2258 * The user's uid on success, or FALSE on failure to authenticate. |
|
2259 */ |
|
2260 function user_authenticate($name, $password) { |
|
2261 $uid = FALSE; |
|
2262 if (!empty($name) && strlen(trim($password)) > 0) { |
|
2263 $account = user_load_by_name($name); |
|
2264 if ($account) { |
|
2265 // Allow alternate password hashing schemes. |
|
2266 require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc'); |
|
2267 if (user_check_password($password, $account)) { |
|
2268 // Successful authentication. |
|
2269 $uid = $account->uid; |
|
2270 |
|
2271 // Update user to new password scheme if needed. |
|
2272 if (user_needs_new_hash($account)) { |
|
2273 user_save($account, array('pass' => $password)); |
|
2274 } |
|
2275 } |
|
2276 } |
|
2277 } |
|
2278 return $uid; |
|
2279 } |
|
2280 |
|
2281 /** |
|
2282 * Finalize the login process. Must be called when logging in a user. |
|
2283 * |
|
2284 * The function records a watchdog message about the new session, saves the |
|
2285 * login timestamp, calls hook_user_login(), and generates a new session. |
|
2286 * |
|
2287 * @param array $edit |
|
2288 * The array of form values submitted by the user. |
|
2289 * |
|
2290 * @see hook_user_login() |
|
2291 */ |
|
2292 function user_login_finalize(&$edit = array()) { |
|
2293 global $user; |
|
2294 watchdog('user', 'Session opened for %name.', array('%name' => $user->name)); |
|
2295 // Update the user table timestamp noting user has logged in. |
|
2296 // This is also used to invalidate one-time login links. |
|
2297 $user->login = REQUEST_TIME; |
|
2298 db_update('users') |
|
2299 ->fields(array('login' => $user->login)) |
|
2300 ->condition('uid', $user->uid) |
|
2301 ->execute(); |
|
2302 |
|
2303 // Regenerate the session ID to prevent against session fixation attacks. |
|
2304 // This is called before hook_user in case one of those functions fails |
|
2305 // or incorrectly does a redirect which would leave the old session in place. |
|
2306 drupal_session_regenerate(); |
|
2307 |
|
2308 user_module_invoke('login', $edit, $user); |
|
2309 } |
|
2310 |
|
2311 /** |
|
2312 * Submit handler for the login form. Load $user object and perform standard login |
|
2313 * tasks. The user is then redirected to the My Account page. Setting the |
|
2314 * destination in the query string overrides the redirect. |
|
2315 */ |
|
2316 function user_login_submit($form, &$form_state) { |
|
2317 global $user; |
|
2318 $user = user_load($form_state['uid']); |
|
2319 $form_state['redirect'] = 'user/' . $user->uid; |
|
2320 |
|
2321 user_login_finalize($form_state); |
|
2322 } |
|
2323 |
|
2324 /** |
|
2325 * Helper function for authentication modules. Either logs in or registers |
|
2326 * the current user, based on username. Either way, the global $user object is |
|
2327 * populated and login tasks are performed. |
|
2328 */ |
|
2329 function user_external_login_register($name, $module) { |
|
2330 $account = user_external_load($name); |
|
2331 if (!$account) { |
|
2332 // Register this new user. |
|
2333 $userinfo = array( |
|
2334 'name' => $name, |
|
2335 'pass' => user_password(), |
|
2336 'init' => $name, |
|
2337 'status' => 1, |
|
2338 'access' => REQUEST_TIME |
|
2339 ); |
|
2340 $account = user_save(drupal_anonymous_user(), $userinfo); |
|
2341 // Terminate if an error occurred during user_save(). |
|
2342 if (!$account) { |
|
2343 drupal_set_message(t("Error saving user account."), 'error'); |
|
2344 return; |
|
2345 } |
|
2346 user_set_authmaps($account, array("authname_$module" => $name)); |
|
2347 } |
|
2348 |
|
2349 // Log user in. |
|
2350 $form_state['uid'] = $account->uid; |
|
2351 user_login_submit(array(), $form_state); |
|
2352 } |
|
2353 |
|
2354 /** |
|
2355 * Generates a unique URL for a user to login and reset their password. |
|
2356 * |
|
2357 * @param object $account |
|
2358 * An object containing the user account, which must contain at least the |
|
2359 * following properties: |
|
2360 * - uid: The user ID number. |
|
2361 * - login: The UNIX timestamp of the user's last login. |
|
2362 * |
|
2363 * @return |
|
2364 * A unique URL that provides a one-time log in for the user, from which |
|
2365 * they can change their password. |
|
2366 */ |
|
2367 function user_pass_reset_url($account) { |
|
2368 $timestamp = REQUEST_TIME; |
|
2369 return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE)); |
|
2370 } |
|
2371 |
|
2372 /** |
|
2373 * Generates a URL to confirm an account cancellation request. |
|
2374 * |
|
2375 * @param object $account |
|
2376 * The user account object, which must contain at least the following |
|
2377 * properties: |
|
2378 * - uid: The user ID number. |
|
2379 * - pass: The hashed user password string. |
|
2380 * - login: The UNIX timestamp of the user's last login. |
|
2381 * |
|
2382 * @return |
|
2383 * A unique URL that may be used to confirm the cancellation of the user |
|
2384 * account. |
|
2385 * |
|
2386 * @see user_mail_tokens() |
|
2387 * @see user_cancel_confirm() |
|
2388 */ |
|
2389 function user_cancel_url($account) { |
|
2390 $timestamp = REQUEST_TIME; |
|
2391 return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE)); |
|
2392 } |
|
2393 |
|
2394 /** |
|
2395 * Creates a unique hash value for use in time-dependent per-user URLs. |
|
2396 * |
|
2397 * This hash is normally used to build a unique and secure URL that is sent to |
|
2398 * the user by email for purposes such as resetting the user's password. In |
|
2399 * order to validate the URL, the same hash can be generated again, from the |
|
2400 * same information, and compared to the hash value from the URL. The URL |
|
2401 * normally contains both the time stamp and the numeric user ID. The login |
|
2402 * timestamp and hashed password are retrieved from the database as necessary. |
|
2403 * For a usage example, see user_cancel_url() and user_cancel_confirm(). |
|
2404 * |
|
2405 * @param string $password |
|
2406 * The hashed user account password value. |
|
2407 * @param int $timestamp |
|
2408 * A UNIX timestamp, typically REQUEST_TIME. |
|
2409 * @param int $login |
|
2410 * The UNIX timestamp of the user's last login. |
|
2411 * @param int $uid |
|
2412 * The user ID of the user account. |
|
2413 * |
|
2414 * @return |
|
2415 * A string that is safe for use in URLs and SQL statements. |
|
2416 */ |
|
2417 function user_pass_rehash($password, $timestamp, $login, $uid) { |
|
2418 // Backwards compatibility: Try to determine a $uid if one was not passed. |
|
2419 // (Since $uid is a required parameter to this function, a PHP warning will |
|
2420 // be generated if it's not provided, which is an indication that the calling |
|
2421 // code should be updated. But the code below will try to generate a correct |
|
2422 // hash in the meantime.) |
|
2423 if (!isset($uid)) { |
|
2424 $uids = db_query_range('SELECT uid FROM {users} WHERE pass = :password AND login = :login AND uid > 0', 0, 2, array(':password' => $password, ':login' => $login))->fetchCol(); |
|
2425 // If exactly one user account matches the provided password and login |
|
2426 // timestamp, proceed with that $uid. |
|
2427 if (count($uids) == 1) { |
|
2428 $uid = reset($uids); |
|
2429 } |
|
2430 // Otherwise there is no safe hash to return, so return a random string |
|
2431 // that will never be treated as a valid token. |
|
2432 else { |
|
2433 return drupal_random_key(); |
|
2434 } |
|
2435 } |
|
2436 |
|
2437 return drupal_hmac_base64($timestamp . $login . $uid, drupal_get_hash_salt() . $password); |
|
2438 } |
|
2439 |
|
2440 /** |
|
2441 * Cancel a user account. |
|
2442 * |
|
2443 * Since the user cancellation process needs to be run in a batch, either |
|
2444 * Form API will invoke it, or batch_process() needs to be invoked after calling |
|
2445 * this function and should define the path to redirect to. |
|
2446 * |
|
2447 * @param $edit |
|
2448 * An array of submitted form values. |
|
2449 * @param $uid |
|
2450 * The user ID of the user account to cancel. |
|
2451 * @param $method |
|
2452 * The account cancellation method to use. |
|
2453 * |
|
2454 * @see _user_cancel() |
|
2455 */ |
|
2456 function user_cancel($edit, $uid, $method) { |
|
2457 global $user; |
|
2458 |
|
2459 $account = user_load($uid); |
|
2460 |
|
2461 if (!$account) { |
|
2462 drupal_set_message(t('The user account %id does not exist.', array('%id' => $uid)), 'error'); |
|
2463 watchdog('user', 'Attempted to cancel non-existing user account: %id.', array('%id' => $uid), WATCHDOG_ERROR); |
|
2464 return; |
|
2465 } |
|
2466 |
|
2467 // Initialize batch (to set title). |
|
2468 $batch = array( |
|
2469 'title' => t('Cancelling account'), |
|
2470 'operations' => array(), |
|
2471 ); |
|
2472 batch_set($batch); |
|
2473 |
|
2474 // Modules use hook_user_delete() to respond to deletion. |
|
2475 if ($method != 'user_cancel_delete') { |
|
2476 // Allow modules to add further sets to this batch. |
|
2477 module_invoke_all('user_cancel', $edit, $account, $method); |
|
2478 } |
|
2479 |
|
2480 // Finish the batch and actually cancel the account. |
|
2481 $batch = array( |
|
2482 'title' => t('Cancelling user account'), |
|
2483 'operations' => array( |
|
2484 array('_user_cancel', array($edit, $account, $method)), |
|
2485 ), |
|
2486 ); |
|
2487 |
|
2488 // After cancelling account, ensure that user is logged out. |
|
2489 if ($account->uid == $user->uid) { |
|
2490 // Batch API stores data in the session, so use the finished operation to |
|
2491 // manipulate the current user's session id. |
|
2492 $batch['finished'] = '_user_cancel_session_regenerate'; |
|
2493 } |
|
2494 |
|
2495 batch_set($batch); |
|
2496 |
|
2497 // Batch processing is either handled via Form API or has to be invoked |
|
2498 // manually. |
|
2499 } |
|
2500 |
|
2501 /** |
|
2502 * Implements callback_batch_operation(). |
|
2503 * |
|
2504 * Last step for cancelling a user account. |
|
2505 * |
|
2506 * Since batch and session API require a valid user account, the actual |
|
2507 * cancellation of a user account needs to happen last. |
|
2508 * |
|
2509 * @see user_cancel() |
|
2510 */ |
|
2511 function _user_cancel($edit, $account, $method) { |
|
2512 global $user; |
|
2513 |
|
2514 switch ($method) { |
|
2515 case 'user_cancel_block': |
|
2516 case 'user_cancel_block_unpublish': |
|
2517 default: |
|
2518 // Send account blocked notification if option was checked. |
|
2519 if (!empty($edit['user_cancel_notify'])) { |
|
2520 _user_mail_notify('status_blocked', $account); |
|
2521 } |
|
2522 user_save($account, array('status' => 0)); |
|
2523 drupal_set_message(t('%name has been disabled.', array('%name' => $account->name))); |
|
2524 watchdog('user', 'Blocked user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE); |
|
2525 break; |
|
2526 |
|
2527 case 'user_cancel_reassign': |
|
2528 case 'user_cancel_delete': |
|
2529 // Send account canceled notification if option was checked. |
|
2530 if (!empty($edit['user_cancel_notify'])) { |
|
2531 _user_mail_notify('status_canceled', $account); |
|
2532 } |
|
2533 user_delete($account->uid); |
|
2534 drupal_set_message(t('%name has been deleted.', array('%name' => $account->name))); |
|
2535 watchdog('user', 'Deleted user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE); |
|
2536 break; |
|
2537 } |
|
2538 |
|
2539 // After cancelling account, ensure that user is logged out. We can't destroy |
|
2540 // their session though, as we might have information in it, and we can't |
|
2541 // regenerate it because batch API uses the session ID, we will regenerate it |
|
2542 // in _user_cancel_session_regenerate(). |
|
2543 if ($account->uid == $user->uid) { |
|
2544 $user = drupal_anonymous_user(); |
|
2545 } |
|
2546 |
|
2547 // Clear the cache for anonymous users. |
|
2548 cache_clear_all(); |
|
2549 } |
|
2550 |
|
2551 /** |
|
2552 * Implements callback_batch_finished(). |
|
2553 * |
|
2554 * Finished batch processing callback for cancelling a user account. |
|
2555 * |
|
2556 * @see user_cancel() |
|
2557 */ |
|
2558 function _user_cancel_session_regenerate() { |
|
2559 // Regenerate the users session instead of calling session_destroy() as we |
|
2560 // want to preserve any messages that might have been set. |
|
2561 drupal_session_regenerate(); |
|
2562 } |
|
2563 |
|
2564 /** |
|
2565 * Delete a user. |
|
2566 * |
|
2567 * @param $uid |
|
2568 * A user ID. |
|
2569 */ |
|
2570 function user_delete($uid) { |
|
2571 user_delete_multiple(array($uid)); |
|
2572 } |
|
2573 |
|
2574 /** |
|
2575 * Delete multiple user accounts. |
|
2576 * |
|
2577 * @param $uids |
|
2578 * An array of user IDs. |
|
2579 */ |
|
2580 function user_delete_multiple(array $uids) { |
|
2581 if (!empty($uids)) { |
|
2582 $accounts = user_load_multiple($uids, array()); |
|
2583 |
|
2584 $transaction = db_transaction(); |
|
2585 try { |
|
2586 foreach ($accounts as $uid => $account) { |
|
2587 module_invoke_all('user_delete', $account); |
|
2588 module_invoke_all('entity_delete', $account, 'user'); |
|
2589 field_attach_delete('user', $account); |
|
2590 drupal_session_destroy_uid($account->uid); |
|
2591 } |
|
2592 |
|
2593 db_delete('users') |
|
2594 ->condition('uid', $uids, 'IN') |
|
2595 ->execute(); |
|
2596 db_delete('users_roles') |
|
2597 ->condition('uid', $uids, 'IN') |
|
2598 ->execute(); |
|
2599 db_delete('authmap') |
|
2600 ->condition('uid', $uids, 'IN') |
|
2601 ->execute(); |
|
2602 } |
|
2603 catch (Exception $e) { |
|
2604 $transaction->rollback(); |
|
2605 watchdog_exception('user', $e); |
|
2606 throw $e; |
|
2607 } |
|
2608 entity_get_controller('user')->resetCache(); |
|
2609 } |
|
2610 } |
|
2611 |
|
2612 /** |
|
2613 * Page callback wrapper for user_view(). |
|
2614 */ |
|
2615 function user_view_page($account) { |
|
2616 // An administrator may try to view a non-existent account, |
|
2617 // so we give them a 404 (versus a 403 for non-admins). |
|
2618 return is_object($account) ? user_view($account) : MENU_NOT_FOUND; |
|
2619 } |
|
2620 |
|
2621 /** |
|
2622 * Generate an array for rendering the given user. |
|
2623 * |
|
2624 * When viewing a user profile, the $page array contains: |
|
2625 * |
|
2626 * - $page['content']['Profile Category']: |
|
2627 * Profile categories keyed by their human-readable names. |
|
2628 * - $page['content']['Profile Category']['profile_machine_name']: |
|
2629 * Profile fields keyed by their machine-readable names. |
|
2630 * - $page['content']['user_picture']: |
|
2631 * User's rendered picture. |
|
2632 * - $page['content']['summary']: |
|
2633 * Contains the default "History" profile data for a user. |
|
2634 * - $page['content']['#account']: |
|
2635 * The user account of the profile being viewed. |
|
2636 * |
|
2637 * To theme user profiles, copy modules/user/user-profile.tpl.php |
|
2638 * to your theme directory, and edit it as instructed in that file's comments. |
|
2639 * |
|
2640 * @param $account |
|
2641 * A user object. |
|
2642 * @param $view_mode |
|
2643 * View mode, e.g. 'full'. |
|
2644 * @param $langcode |
|
2645 * (optional) A language code to use for rendering. Defaults to the global |
|
2646 * content language of the current request. |
|
2647 * |
|
2648 * @return |
|
2649 * An array as expected by drupal_render(). |
|
2650 */ |
|
2651 function user_view($account, $view_mode = 'full', $langcode = NULL) { |
|
2652 if (!isset($langcode)) { |
|
2653 $langcode = $GLOBALS['language_content']->language; |
|
2654 } |
|
2655 |
|
2656 // Retrieve all profile fields and attach to $account->content. |
|
2657 user_build_content($account, $view_mode, $langcode); |
|
2658 |
|
2659 $build = $account->content; |
|
2660 // We don't need duplicate rendering info in account->content. |
|
2661 unset($account->content); |
|
2662 |
|
2663 $build += array( |
|
2664 '#theme' => 'user_profile', |
|
2665 '#account' => $account, |
|
2666 '#view_mode' => $view_mode, |
|
2667 '#language' => $langcode, |
|
2668 ); |
|
2669 |
|
2670 // Allow modules to modify the structured user. |
|
2671 $type = 'user'; |
|
2672 drupal_alter(array('user_view', 'entity_view'), $build, $type); |
|
2673 |
|
2674 return $build; |
|
2675 } |
|
2676 |
|
2677 /** |
|
2678 * Builds a structured array representing the profile content. |
|
2679 * |
|
2680 * @param $account |
|
2681 * A user object. |
|
2682 * @param $view_mode |
|
2683 * View mode, e.g. 'full'. |
|
2684 * @param $langcode |
|
2685 * (optional) A language code to use for rendering. Defaults to the global |
|
2686 * content language of the current request. |
|
2687 */ |
|
2688 function user_build_content($account, $view_mode = 'full', $langcode = NULL) { |
|
2689 if (!isset($langcode)) { |
|
2690 $langcode = $GLOBALS['language_content']->language; |
|
2691 } |
|
2692 |
|
2693 // Remove previously built content, if exists. |
|
2694 $account->content = array(); |
|
2695 |
|
2696 // Allow modules to change the view mode. |
|
2697 $view_mode = key(entity_view_mode_prepare('user', array($account->uid => $account), $view_mode, $langcode)); |
|
2698 |
|
2699 // Build fields content. |
|
2700 field_attach_prepare_view('user', array($account->uid => $account), $view_mode, $langcode); |
|
2701 entity_prepare_view('user', array($account->uid => $account), $langcode); |
|
2702 $account->content += field_attach_view('user', $account, $view_mode, $langcode); |
|
2703 |
|
2704 // Populate $account->content with a render() array. |
|
2705 module_invoke_all('user_view', $account, $view_mode, $langcode); |
|
2706 module_invoke_all('entity_view', $account, 'user', $view_mode, $langcode); |
|
2707 |
|
2708 // Make sure the current view mode is stored if no module has already |
|
2709 // populated the related key. |
|
2710 $account->content += array('#view_mode' => $view_mode); |
|
2711 } |
|
2712 |
|
2713 /** |
|
2714 * Implements hook_mail(). |
|
2715 */ |
|
2716 function user_mail($key, &$message, $params) { |
|
2717 $language = $message['language']; |
|
2718 $variables = array('user' => $params['account']); |
|
2719 $message['subject'] .= _user_mail_text($key . '_subject', $language, $variables); |
|
2720 $message['body'][] = _user_mail_text($key . '_body', $language, $variables); |
|
2721 } |
|
2722 |
|
2723 /** |
|
2724 * Returns a mail string for a variable name. |
|
2725 * |
|
2726 * Used by user_mail() and the settings forms to retrieve strings. |
|
2727 */ |
|
2728 function _user_mail_text($key, $language = NULL, $variables = array(), $replace = TRUE) { |
|
2729 $langcode = isset($language) ? $language->language : NULL; |
|
2730 |
|
2731 if ($admin_setting = variable_get('user_mail_' . $key, FALSE)) { |
|
2732 // An admin setting overrides the default string. |
|
2733 $text = $admin_setting; |
|
2734 } |
|
2735 else { |
|
2736 // No override, return default string. |
|
2737 switch ($key) { |
|
2738 case 'register_no_approval_required_subject': |
|
2739 $text = t('Account details for [user:name] at [site:name]', array(), array('langcode' => $langcode)); |
|
2740 break; |
|
2741 case 'register_no_approval_required_body': |
|
2742 $text = t("[user:name], |
|
2743 |
|
2744 Thank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser: |
|
2745 |
|
2746 [user:one-time-login-url] |
|
2747 |
|
2748 This link can only be used once to log in and will lead you to a page where you can set your password. |
|
2749 |
|
2750 After setting your password, you will be able to log in at [site:login-url] in the future using: |
|
2751 |
|
2752 username: [user:name] |
|
2753 password: Your password |
|
2754 |
|
2755 -- [site:name] team", array(), array('langcode' => $langcode)); |
|
2756 break; |
|
2757 |
|
2758 case 'register_admin_created_subject': |
|
2759 $text = t('An administrator created an account for you at [site:name]', array(), array('langcode' => $langcode)); |
|
2760 break; |
|
2761 case 'register_admin_created_body': |
|
2762 $text = t("[user:name], |
|
2763 |
|
2764 A site administrator at [site:name] has created an account for you. You may now log in by clicking this link or copying and pasting it to your browser: |
|
2765 |
|
2766 [user:one-time-login-url] |
|
2767 |
|
2768 This link can only be used once to log in and will lead you to a page where you can set your password. |
|
2769 |
|
2770 After setting your password, you will be able to log in at [site:login-url] in the future using: |
|
2771 |
|
2772 username: [user:name] |
|
2773 password: Your password |
|
2774 |
|
2775 -- [site:name] team", array(), array('langcode' => $langcode)); |
|
2776 break; |
|
2777 |
|
2778 case 'register_pending_approval_subject': |
|
2779 case 'register_pending_approval_admin_subject': |
|
2780 $text = t('Account details for [user:name] at [site:name] (pending admin approval)', array(), array('langcode' => $langcode)); |
|
2781 break; |
|
2782 case 'register_pending_approval_body': |
|
2783 $text = t("[user:name], |
|
2784 |
|
2785 Thank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another e-mail containing information about how to log in, set your password, and other details. |
|
2786 |
|
2787 |
|
2788 -- [site:name] team", array(), array('langcode' => $langcode)); |
|
2789 break; |
|
2790 case 'register_pending_approval_admin_body': |
|
2791 $text = t("[user:name] has applied for an account. |
|
2792 |
|
2793 [user:edit-url]", array(), array('langcode' => $langcode)); |
|
2794 break; |
|
2795 |
|
2796 case 'password_reset_subject': |
|
2797 $text = t('Replacement login information for [user:name] at [site:name]', array(), array('langcode' => $langcode)); |
|
2798 break; |
|
2799 case 'password_reset_body': |
|
2800 $text = t("[user:name], |
|
2801 |
|
2802 A request to reset the password for your account has been made at [site:name]. |
|
2803 |
|
2804 You may now log in by clicking this link or copying and pasting it to your browser: |
|
2805 |
|
2806 [user:one-time-login-url] |
|
2807 |
|
2808 This link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used. |
|
2809 |
|
2810 -- [site:name] team", array(), array('langcode' => $langcode)); |
|
2811 break; |
|
2812 |
|
2813 case 'status_activated_subject': |
|
2814 $text = t('Account details for [user:name] at [site:name] (approved)', array(), array('langcode' => $langcode)); |
|
2815 break; |
|
2816 case 'status_activated_body': |
|
2817 $text = t("[user:name], |
|
2818 |
|
2819 Your account at [site:name] has been activated. |
|
2820 |
|
2821 You may now log in by clicking this link or copying and pasting it into your browser: |
|
2822 |
|
2823 [user:one-time-login-url] |
|
2824 |
|
2825 This link can only be used once to log in and will lead you to a page where you can set your password. |
|
2826 |
|
2827 After setting your password, you will be able to log in at [site:login-url] in the future using: |
|
2828 |
|
2829 username: [user:name] |
|
2830 password: Your password |
|
2831 |
|
2832 -- [site:name] team", array(), array('langcode' => $langcode)); |
|
2833 break; |
|
2834 |
|
2835 case 'status_blocked_subject': |
|
2836 $text = t('Account details for [user:name] at [site:name] (blocked)', array(), array('langcode' => $langcode)); |
|
2837 break; |
|
2838 case 'status_blocked_body': |
|
2839 $text = t("[user:name], |
|
2840 |
|
2841 Your account on [site:name] has been blocked. |
|
2842 |
|
2843 -- [site:name] team", array(), array('langcode' => $langcode)); |
|
2844 break; |
|
2845 |
|
2846 case 'cancel_confirm_subject': |
|
2847 $text = t('Account cancellation request for [user:name] at [site:name]', array(), array('langcode' => $langcode)); |
|
2848 break; |
|
2849 case 'cancel_confirm_body': |
|
2850 $text = t("[user:name], |
|
2851 |
|
2852 A request to cancel your account has been made at [site:name]. |
|
2853 |
|
2854 You may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser: |
|
2855 |
|
2856 [user:cancel-url] |
|
2857 |
|
2858 NOTE: The cancellation of your account is not reversible. |
|
2859 |
|
2860 This link expires in one day and nothing will happen if it is not used. |
|
2861 |
|
2862 -- [site:name] team", array(), array('langcode' => $langcode)); |
|
2863 break; |
|
2864 |
|
2865 case 'status_canceled_subject': |
|
2866 $text = t('Account details for [user:name] at [site:name] (canceled)', array(), array('langcode' => $langcode)); |
|
2867 break; |
|
2868 case 'status_canceled_body': |
|
2869 $text = t("[user:name], |
|
2870 |
|
2871 Your account on [site:name] has been canceled. |
|
2872 |
|
2873 -- [site:name] team", array(), array('langcode' => $langcode)); |
|
2874 break; |
|
2875 } |
|
2876 } |
|
2877 |
|
2878 if ($replace) { |
|
2879 // We do not sanitize the token replacement, since the output of this |
|
2880 // replacement is intended for an e-mail message, not a web browser. |
|
2881 return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); |
|
2882 } |
|
2883 |
|
2884 return $text; |
|
2885 } |
|
2886 |
|
2887 /** |
|
2888 * Token callback to add unsafe tokens for user mails. |
|
2889 * |
|
2890 * This function is used by the token_replace() call at the end of |
|
2891 * _user_mail_text() to set up some additional tokens that can be |
|
2892 * used in email messages generated by user_mail(). |
|
2893 * |
|
2894 * @param $replacements |
|
2895 * An associative array variable containing mappings from token names to |
|
2896 * values (for use with strtr()). |
|
2897 * @param $data |
|
2898 * An associative array of token replacement values. If the 'user' element |
|
2899 * exists, it must contain a user account object with the following |
|
2900 * properties: |
|
2901 * - login: The UNIX timestamp of the user's last login. |
|
2902 * - pass: The hashed account login password. |
|
2903 * @param $options |
|
2904 * Unused parameter required by the token_replace() function. |
|
2905 */ |
|
2906 function user_mail_tokens(&$replacements, $data, $options) { |
|
2907 if (isset($data['user'])) { |
|
2908 $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user']); |
|
2909 $replacements['[user:cancel-url]'] = user_cancel_url($data['user']); |
|
2910 } |
|
2911 } |
|
2912 |
|
2913 /*** Administrative features ***********************************************/ |
|
2914 |
|
2915 /** |
|
2916 * Retrieve an array of roles matching specified conditions. |
|
2917 * |
|
2918 * @param $membersonly |
|
2919 * Set this to TRUE to exclude the 'anonymous' role. |
|
2920 * @param $permission |
|
2921 * A string containing a permission. If set, only roles containing that |
|
2922 * permission are returned. |
|
2923 * |
|
2924 * @return |
|
2925 * An associative array with the role id as the key and the role name as |
|
2926 * value. |
|
2927 */ |
|
2928 function user_roles($membersonly = FALSE, $permission = NULL) { |
|
2929 $query = db_select('role', 'r'); |
|
2930 $query->addTag('translatable'); |
|
2931 $query->fields('r', array('rid', 'name')); |
|
2932 $query->orderBy('weight'); |
|
2933 $query->orderBy('name'); |
|
2934 if (!empty($permission)) { |
|
2935 $query->innerJoin('role_permission', 'p', 'r.rid = p.rid'); |
|
2936 $query->condition('p.permission', $permission); |
|
2937 } |
|
2938 $result = $query->execute(); |
|
2939 |
|
2940 $roles = array(); |
|
2941 foreach ($result as $role) { |
|
2942 switch ($role->rid) { |
|
2943 // We only translate the built in role names |
|
2944 case DRUPAL_ANONYMOUS_RID: |
|
2945 if (!$membersonly) { |
|
2946 $roles[$role->rid] = t($role->name); |
|
2947 } |
|
2948 break; |
|
2949 case DRUPAL_AUTHENTICATED_RID: |
|
2950 $roles[$role->rid] = t($role->name); |
|
2951 break; |
|
2952 default: |
|
2953 $roles[$role->rid] = $role->name; |
|
2954 } |
|
2955 } |
|
2956 |
|
2957 return $roles; |
|
2958 } |
|
2959 |
|
2960 /** |
|
2961 * Fetches a user role by role ID. |
|
2962 * |
|
2963 * @param $rid |
|
2964 * An integer representing the role ID. |
|
2965 * |
|
2966 * @return |
|
2967 * A fully-loaded role object if a role with the given ID exists, or FALSE |
|
2968 * otherwise. |
|
2969 * |
|
2970 * @see user_role_load_by_name() |
|
2971 */ |
|
2972 function user_role_load($rid) { |
|
2973 return db_select('role', 'r') |
|
2974 ->fields('r') |
|
2975 ->condition('rid', $rid) |
|
2976 ->execute() |
|
2977 ->fetchObject(); |
|
2978 } |
|
2979 |
|
2980 /** |
|
2981 * Fetches a user role by role name. |
|
2982 * |
|
2983 * @param $role_name |
|
2984 * A string representing the role name. |
|
2985 * |
|
2986 * @return |
|
2987 * A fully-loaded role object if a role with the given name exists, or FALSE |
|
2988 * otherwise. |
|
2989 * |
|
2990 * @see user_role_load() |
|
2991 */ |
|
2992 function user_role_load_by_name($role_name) { |
|
2993 return db_select('role', 'r') |
|
2994 ->fields('r') |
|
2995 ->condition('name', $role_name) |
|
2996 ->execute() |
|
2997 ->fetchObject(); |
|
2998 } |
|
2999 |
|
3000 /** |
|
3001 * Save a user role to the database. |
|
3002 * |
|
3003 * @param $role |
|
3004 * A role object to modify or add. If $role->rid is not specified, a new |
|
3005 * role will be created. |
|
3006 * @return |
|
3007 * Status constant indicating if role was created or updated. |
|
3008 * Failure to write the user role record will return FALSE. Otherwise. |
|
3009 * SAVED_NEW or SAVED_UPDATED is returned depending on the operation |
|
3010 * performed. |
|
3011 */ |
|
3012 function user_role_save($role) { |
|
3013 if ($role->name) { |
|
3014 // Prevent leading and trailing spaces in role names. |
|
3015 $role->name = trim($role->name); |
|
3016 } |
|
3017 if (!isset($role->weight)) { |
|
3018 // Set a role weight to make this new role last. |
|
3019 $query = db_select('role'); |
|
3020 $query->addExpression('MAX(weight)'); |
|
3021 $role->weight = $query->execute()->fetchField() + 1; |
|
3022 } |
|
3023 |
|
3024 // Let modules modify the user role before it is saved to the database. |
|
3025 module_invoke_all('user_role_presave', $role); |
|
3026 |
|
3027 if (!empty($role->rid) && $role->name) { |
|
3028 $status = drupal_write_record('role', $role, 'rid'); |
|
3029 module_invoke_all('user_role_update', $role); |
|
3030 } |
|
3031 else { |
|
3032 $status = drupal_write_record('role', $role); |
|
3033 module_invoke_all('user_role_insert', $role); |
|
3034 } |
|
3035 |
|
3036 // Clear the user access cache. |
|
3037 drupal_static_reset('user_access'); |
|
3038 drupal_static_reset('user_role_permissions'); |
|
3039 |
|
3040 return $status; |
|
3041 } |
|
3042 |
|
3043 /** |
|
3044 * Delete a user role from database. |
|
3045 * |
|
3046 * @param $role |
|
3047 * A string with the role name, or an integer with the role ID. |
|
3048 */ |
|
3049 function user_role_delete($role) { |
|
3050 if (is_int($role)) { |
|
3051 $role = user_role_load($role); |
|
3052 } |
|
3053 else { |
|
3054 $role = user_role_load_by_name($role); |
|
3055 } |
|
3056 |
|
3057 // If this is the administrator role, delete the user_admin_role variable. |
|
3058 if ($role->rid == variable_get('user_admin_role')) { |
|
3059 variable_del('user_admin_role'); |
|
3060 } |
|
3061 |
|
3062 db_delete('role') |
|
3063 ->condition('rid', $role->rid) |
|
3064 ->execute(); |
|
3065 db_delete('role_permission') |
|
3066 ->condition('rid', $role->rid) |
|
3067 ->execute(); |
|
3068 // Update the users who have this role set: |
|
3069 db_delete('users_roles') |
|
3070 ->condition('rid', $role->rid) |
|
3071 ->execute(); |
|
3072 |
|
3073 module_invoke_all('user_role_delete', $role); |
|
3074 |
|
3075 // Clear the user access cache. |
|
3076 drupal_static_reset('user_access'); |
|
3077 drupal_static_reset('user_role_permissions'); |
|
3078 } |
|
3079 |
|
3080 /** |
|
3081 * Menu access callback for user role editing. |
|
3082 */ |
|
3083 function user_role_edit_access($role) { |
|
3084 // Prevent the system-defined roles from being altered or removed. |
|
3085 if ($role->rid == DRUPAL_ANONYMOUS_RID || $role->rid == DRUPAL_AUTHENTICATED_RID) { |
|
3086 return FALSE; |
|
3087 } |
|
3088 |
|
3089 return user_access('administer permissions'); |
|
3090 } |
|
3091 |
|
3092 /** |
|
3093 * Determine the modules that permissions belong to. |
|
3094 * |
|
3095 * @return |
|
3096 * An associative array in the format $permission => $module. |
|
3097 */ |
|
3098 function user_permission_get_modules() { |
|
3099 $permissions = array(); |
|
3100 foreach (module_implements('permission') as $module) { |
|
3101 $perms = module_invoke($module, 'permission'); |
|
3102 foreach ($perms as $key => $value) { |
|
3103 $permissions[$key] = $module; |
|
3104 } |
|
3105 } |
|
3106 return $permissions; |
|
3107 } |
|
3108 |
|
3109 /** |
|
3110 * Change permissions for a user role. |
|
3111 * |
|
3112 * This function may be used to grant and revoke multiple permissions at once. |
|
3113 * For example, when a form exposes checkboxes to configure permissions for a |
|
3114 * role, the form submit handler may directly pass the submitted values for the |
|
3115 * checkboxes form element to this function. |
|
3116 * |
|
3117 * @param $rid |
|
3118 * The ID of a user role to alter. |
|
3119 * @param $permissions |
|
3120 * An associative array, where the key holds the permission name and the value |
|
3121 * determines whether to grant or revoke that permission. Any value that |
|
3122 * evaluates to TRUE will cause the permission to be granted. Any value that |
|
3123 * evaluates to FALSE will cause the permission to be revoked. |
|
3124 * @code |
|
3125 * array( |
|
3126 * 'administer nodes' => 0, // Revoke 'administer nodes' |
|
3127 * 'administer blocks' => FALSE, // Revoke 'administer blocks' |
|
3128 * 'access user profiles' => 1, // Grant 'access user profiles' |
|
3129 * 'access content' => TRUE, // Grant 'access content' |
|
3130 * 'access comments' => 'access comments', // Grant 'access comments' |
|
3131 * ) |
|
3132 * @endcode |
|
3133 * Existing permissions are not changed, unless specified in $permissions. |
|
3134 * |
|
3135 * @see user_role_grant_permissions() |
|
3136 * @see user_role_revoke_permissions() |
|
3137 */ |
|
3138 function user_role_change_permissions($rid, array $permissions = array()) { |
|
3139 // Grant new permissions for the role. |
|
3140 $grant = array_filter($permissions); |
|
3141 if (!empty($grant)) { |
|
3142 user_role_grant_permissions($rid, array_keys($grant)); |
|
3143 } |
|
3144 // Revoke permissions for the role. |
|
3145 $revoke = array_diff_assoc($permissions, $grant); |
|
3146 if (!empty($revoke)) { |
|
3147 user_role_revoke_permissions($rid, array_keys($revoke)); |
|
3148 } |
|
3149 } |
|
3150 |
|
3151 /** |
|
3152 * Grant permissions to a user role. |
|
3153 * |
|
3154 * @param $rid |
|
3155 * The ID of a user role to alter. |
|
3156 * @param $permissions |
|
3157 * A list of permission names to grant. |
|
3158 * |
|
3159 * @see user_role_change_permissions() |
|
3160 * @see user_role_revoke_permissions() |
|
3161 */ |
|
3162 function user_role_grant_permissions($rid, array $permissions = array()) { |
|
3163 $modules = user_permission_get_modules(); |
|
3164 // Grant new permissions for the role. |
|
3165 foreach ($permissions as $name) { |
|
3166 db_merge('role_permission') |
|
3167 ->key(array( |
|
3168 'rid' => $rid, |
|
3169 'permission' => $name, |
|
3170 )) |
|
3171 ->fields(array( |
|
3172 'module' => $modules[$name], |
|
3173 )) |
|
3174 ->execute(); |
|
3175 } |
|
3176 |
|
3177 // Clear the user access cache. |
|
3178 drupal_static_reset('user_access'); |
|
3179 drupal_static_reset('user_role_permissions'); |
|
3180 } |
|
3181 |
|
3182 /** |
|
3183 * Revoke permissions from a user role. |
|
3184 * |
|
3185 * @param $rid |
|
3186 * The ID of a user role to alter. |
|
3187 * @param $permissions |
|
3188 * A list of permission names to revoke. |
|
3189 * |
|
3190 * @see user_role_change_permissions() |
|
3191 * @see user_role_grant_permissions() |
|
3192 */ |
|
3193 function user_role_revoke_permissions($rid, array $permissions = array()) { |
|
3194 // Revoke permissions for the role. |
|
3195 db_delete('role_permission') |
|
3196 ->condition('rid', $rid) |
|
3197 ->condition('permission', $permissions, 'IN') |
|
3198 ->execute(); |
|
3199 |
|
3200 // Clear the user access cache. |
|
3201 drupal_static_reset('user_access'); |
|
3202 drupal_static_reset('user_role_permissions'); |
|
3203 } |
|
3204 |
|
3205 /** |
|
3206 * Implements hook_user_operations(). |
|
3207 */ |
|
3208 function user_user_operations($form = array(), $form_state = array()) { |
|
3209 $operations = array( |
|
3210 'unblock' => array( |
|
3211 'label' => t('Unblock the selected users'), |
|
3212 'callback' => 'user_user_operations_unblock', |
|
3213 ), |
|
3214 'block' => array( |
|
3215 'label' => t('Block the selected users'), |
|
3216 'callback' => 'user_user_operations_block', |
|
3217 ), |
|
3218 'cancel' => array( |
|
3219 'label' => t('Cancel the selected user accounts'), |
|
3220 ), |
|
3221 ); |
|
3222 |
|
3223 if (user_access('administer permissions')) { |
|
3224 $roles = user_roles(TRUE); |
|
3225 unset($roles[DRUPAL_AUTHENTICATED_RID]); // Can't edit authenticated role. |
|
3226 |
|
3227 $add_roles = array(); |
|
3228 foreach ($roles as $key => $value) { |
|
3229 $add_roles['add_role-' . $key] = $value; |
|
3230 } |
|
3231 |
|
3232 $remove_roles = array(); |
|
3233 foreach ($roles as $key => $value) { |
|
3234 $remove_roles['remove_role-' . $key] = $value; |
|
3235 } |
|
3236 |
|
3237 if (count($roles)) { |
|
3238 $role_operations = array( |
|
3239 t('Add a role to the selected users') => array( |
|
3240 'label' => $add_roles, |
|
3241 ), |
|
3242 t('Remove a role from the selected users') => array( |
|
3243 'label' => $remove_roles, |
|
3244 ), |
|
3245 ); |
|
3246 |
|
3247 $operations += $role_operations; |
|
3248 } |
|
3249 } |
|
3250 |
|
3251 // If the form has been posted, we need to insert the proper data for |
|
3252 // role editing if necessary. |
|
3253 if (!empty($form_state['submitted'])) { |
|
3254 $operation_rid = explode('-', $form_state['values']['operation']); |
|
3255 $operation = $operation_rid[0]; |
|
3256 if ($operation == 'add_role' || $operation == 'remove_role') { |
|
3257 $rid = $operation_rid[1]; |
|
3258 if (user_access('administer permissions')) { |
|
3259 $operations[$form_state['values']['operation']] = array( |
|
3260 'callback' => 'user_multiple_role_edit', |
|
3261 'callback arguments' => array($operation, $rid), |
|
3262 ); |
|
3263 } |
|
3264 else { |
|
3265 watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING); |
|
3266 return; |
|
3267 } |
|
3268 } |
|
3269 } |
|
3270 |
|
3271 return $operations; |
|
3272 } |
|
3273 |
|
3274 /** |
|
3275 * Callback function for admin mass unblocking users. |
|
3276 */ |
|
3277 function user_user_operations_unblock($accounts) { |
|
3278 $accounts = user_load_multiple($accounts); |
|
3279 foreach ($accounts as $account) { |
|
3280 // Skip unblocking user if they are already unblocked. |
|
3281 if ($account !== FALSE && $account->status == 0) { |
|
3282 user_save($account, array('status' => 1)); |
|
3283 } |
|
3284 } |
|
3285 } |
|
3286 |
|
3287 /** |
|
3288 * Callback function for admin mass blocking users. |
|
3289 */ |
|
3290 function user_user_operations_block($accounts) { |
|
3291 $accounts = user_load_multiple($accounts); |
|
3292 foreach ($accounts as $account) { |
|
3293 // Skip blocking user if they are already blocked. |
|
3294 if ($account !== FALSE && $account->status == 1) { |
|
3295 // For efficiency manually save the original account before applying any |
|
3296 // changes. |
|
3297 $account->original = clone $account; |
|
3298 user_save($account, array('status' => 0)); |
|
3299 } |
|
3300 } |
|
3301 } |
|
3302 |
|
3303 /** |
|
3304 * Callback function for admin mass adding/deleting a user role. |
|
3305 */ |
|
3306 function user_multiple_role_edit($accounts, $operation, $rid) { |
|
3307 // The role name is not necessary as user_save() will reload the user |
|
3308 // object, but some modules' hook_user() may look at this first. |
|
3309 $role_name = db_query('SELECT name FROM {role} WHERE rid = :rid', array(':rid' => $rid))->fetchField(); |
|
3310 |
|
3311 switch ($operation) { |
|
3312 case 'add_role': |
|
3313 $accounts = user_load_multiple($accounts); |
|
3314 foreach ($accounts as $account) { |
|
3315 // Skip adding the role to the user if they already have it. |
|
3316 if ($account !== FALSE && !isset($account->roles[$rid])) { |
|
3317 $roles = $account->roles + array($rid => $role_name); |
|
3318 // For efficiency manually save the original account before applying |
|
3319 // any changes. |
|
3320 $account->original = clone $account; |
|
3321 user_save($account, array('roles' => $roles)); |
|
3322 } |
|
3323 } |
|
3324 break; |
|
3325 case 'remove_role': |
|
3326 $accounts = user_load_multiple($accounts); |
|
3327 foreach ($accounts as $account) { |
|
3328 // Skip removing the role from the user if they already don't have it. |
|
3329 if ($account !== FALSE && isset($account->roles[$rid])) { |
|
3330 $roles = array_diff($account->roles, array($rid => $role_name)); |
|
3331 // For efficiency manually save the original account before applying |
|
3332 // any changes. |
|
3333 $account->original = clone $account; |
|
3334 user_save($account, array('roles' => $roles)); |
|
3335 } |
|
3336 } |
|
3337 break; |
|
3338 } |
|
3339 } |
|
3340 |
|
3341 function user_multiple_cancel_confirm($form, &$form_state) { |
|
3342 $edit = $form_state['input']; |
|
3343 |
|
3344 $form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE); |
|
3345 $accounts = user_load_multiple(array_keys(array_filter($edit['accounts']))); |
|
3346 foreach ($accounts as $uid => $account) { |
|
3347 // Prevent user 1 from being canceled. |
|
3348 if ($uid <= 1) { |
|
3349 continue; |
|
3350 } |
|
3351 $form['accounts'][$uid] = array( |
|
3352 '#type' => 'hidden', |
|
3353 '#value' => $uid, |
|
3354 '#prefix' => '<li>', |
|
3355 '#suffix' => check_plain($account->name) . "</li>\n", |
|
3356 ); |
|
3357 } |
|
3358 |
|
3359 // Output a notice that user 1 cannot be canceled. |
|
3360 if (isset($accounts[1])) { |
|
3361 $redirect = (count($accounts) == 1); |
|
3362 $message = t('The user account %name cannot be cancelled.', array('%name' => $accounts[1]->name)); |
|
3363 drupal_set_message($message, $redirect ? 'error' : 'warning'); |
|
3364 // If only user 1 was selected, redirect to the overview. |
|
3365 if ($redirect) { |
|
3366 drupal_goto('admin/people'); |
|
3367 } |
|
3368 } |
|
3369 |
|
3370 $form['operation'] = array('#type' => 'hidden', '#value' => 'cancel'); |
|
3371 |
|
3372 module_load_include('inc', 'user', 'user.pages'); |
|
3373 $form['user_cancel_method'] = array( |
|
3374 '#type' => 'item', |
|
3375 '#title' => t('When cancelling these accounts'), |
|
3376 ); |
|
3377 $form['user_cancel_method'] += user_cancel_methods(); |
|
3378 // Remove method descriptions. |
|
3379 foreach (element_children($form['user_cancel_method']) as $element) { |
|
3380 unset($form['user_cancel_method'][$element]['#description']); |
|
3381 } |
|
3382 |
|
3383 // Allow to send the account cancellation confirmation mail. |
|
3384 $form['user_cancel_confirm'] = array( |
|
3385 '#type' => 'checkbox', |
|
3386 '#title' => t('Require e-mail confirmation to cancel account.'), |
|
3387 '#default_value' => FALSE, |
|
3388 '#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'), |
|
3389 ); |
|
3390 // Also allow to send account canceled notification mail, if enabled. |
|
3391 $form['user_cancel_notify'] = array( |
|
3392 '#type' => 'checkbox', |
|
3393 '#title' => t('Notify user when account is canceled.'), |
|
3394 '#default_value' => FALSE, |
|
3395 '#access' => variable_get('user_mail_status_canceled_notify', FALSE), |
|
3396 '#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'), |
|
3397 ); |
|
3398 |
|
3399 return confirm_form($form, |
|
3400 t('Are you sure you want to cancel these user accounts?'), |
|
3401 'admin/people', t('This action cannot be undone.'), |
|
3402 t('Cancel accounts'), t('Cancel')); |
|
3403 } |
|
3404 |
|
3405 /** |
|
3406 * Submit handler for mass-account cancellation form. |
|
3407 * |
|
3408 * @see user_multiple_cancel_confirm() |
|
3409 * @see user_cancel_confirm_form_submit() |
|
3410 */ |
|
3411 function user_multiple_cancel_confirm_submit($form, &$form_state) { |
|
3412 global $user; |
|
3413 |
|
3414 if ($form_state['values']['confirm']) { |
|
3415 foreach ($form_state['values']['accounts'] as $uid => $value) { |
|
3416 // Prevent programmatic form submissions from cancelling user 1. |
|
3417 if ($uid <= 1) { |
|
3418 continue; |
|
3419 } |
|
3420 // Prevent user administrators from deleting themselves without confirmation. |
|
3421 if ($uid == $user->uid) { |
|
3422 $admin_form_state = $form_state; |
|
3423 unset($admin_form_state['values']['user_cancel_confirm']); |
|
3424 $admin_form_state['values']['_account'] = $user; |
|
3425 user_cancel_confirm_form_submit(array(), $admin_form_state); |
|
3426 } |
|
3427 else { |
|
3428 user_cancel($form_state['values'], $uid, $form_state['values']['user_cancel_method']); |
|
3429 } |
|
3430 } |
|
3431 } |
|
3432 $form_state['redirect'] = 'admin/people'; |
|
3433 } |
|
3434 |
|
3435 /** |
|
3436 * Retrieve a list of all user setting/information categories and sort them by weight. |
|
3437 */ |
|
3438 function _user_categories() { |
|
3439 $categories = module_invoke_all('user_categories'); |
|
3440 usort($categories, '_user_sort'); |
|
3441 |
|
3442 return $categories; |
|
3443 } |
|
3444 |
|
3445 function _user_sort($a, $b) { |
|
3446 $a = (array) $a + array('weight' => 0, 'title' => ''); |
|
3447 $b = (array) $b + array('weight' => 0, 'title' => ''); |
|
3448 return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1)); |
|
3449 } |
|
3450 |
|
3451 /** |
|
3452 * List user administration filters that can be applied. |
|
3453 */ |
|
3454 function user_filters() { |
|
3455 // Regular filters |
|
3456 $filters = array(); |
|
3457 $roles = user_roles(TRUE); |
|
3458 unset($roles[DRUPAL_AUTHENTICATED_RID]); // Don't list authorized role. |
|
3459 if (count($roles)) { |
|
3460 $filters['role'] = array( |
|
3461 'title' => t('role'), |
|
3462 'field' => 'ur.rid', |
|
3463 'options' => array( |
|
3464 '[any]' => t('any'), |
|
3465 ) + $roles, |
|
3466 ); |
|
3467 } |
|
3468 |
|
3469 $options = array(); |
|
3470 foreach (module_implements('permission') as $module) { |
|
3471 $function = $module . '_permission'; |
|
3472 if ($permissions = $function()) { |
|
3473 asort($permissions); |
|
3474 foreach ($permissions as $permission => $description) { |
|
3475 $options[t('@module module', array('@module' => $module))][$permission] = t($permission); |
|
3476 } |
|
3477 } |
|
3478 } |
|
3479 ksort($options); |
|
3480 $filters['permission'] = array( |
|
3481 'title' => t('permission'), |
|
3482 'options' => array( |
|
3483 '[any]' => t('any'), |
|
3484 ) + $options, |
|
3485 ); |
|
3486 |
|
3487 $filters['status'] = array( |
|
3488 'title' => t('status'), |
|
3489 'field' => 'u.status', |
|
3490 'options' => array( |
|
3491 '[any]' => t('any'), |
|
3492 1 => t('active'), |
|
3493 0 => t('blocked'), |
|
3494 ), |
|
3495 ); |
|
3496 return $filters; |
|
3497 } |
|
3498 |
|
3499 /** |
|
3500 * Extends a query object for user administration filters based on session. |
|
3501 * |
|
3502 * @param $query |
|
3503 * Query object that should be filtered. |
|
3504 */ |
|
3505 function user_build_filter_query(SelectQuery $query) { |
|
3506 $filters = user_filters(); |
|
3507 // Extend Query with filter conditions. |
|
3508 foreach (isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array() as $filter) { |
|
3509 list($key, $value) = $filter; |
|
3510 // This checks to see if this permission filter is an enabled permission for |
|
3511 // the authenticated role. If so, then all users would be listed, and we can |
|
3512 // skip adding it to the filter query. |
|
3513 if ($key == 'permission') { |
|
3514 $account = new stdClass(); |
|
3515 $account->uid = 'user_filter'; |
|
3516 $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1); |
|
3517 if (user_access($value, $account)) { |
|
3518 continue; |
|
3519 } |
|
3520 $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid'); |
|
3521 $permission_alias = $query->join('role_permission', 'p', $users_roles_alias . '.rid = %alias.rid'); |
|
3522 $query->condition($permission_alias . '.permission', $value); |
|
3523 } |
|
3524 elseif ($key == 'role') { |
|
3525 $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid'); |
|
3526 $query->condition($users_roles_alias . '.rid' , $value); |
|
3527 } |
|
3528 else { |
|
3529 $query->condition($filters[$key]['field'], $value); |
|
3530 } |
|
3531 } |
|
3532 } |
|
3533 |
|
3534 /** |
|
3535 * Implements hook_comment_view(). |
|
3536 */ |
|
3537 function user_comment_view($comment) { |
|
3538 if (variable_get('user_signatures', 0) && !empty($comment->signature)) { |
|
3539 // @todo This alters and replaces the original object value, so a |
|
3540 // hypothetical process of loading, viewing, and saving will hijack the |
|
3541 // stored data. Consider renaming to $comment->signature_safe or similar |
|
3542 // here and elsewhere in Drupal 8. |
|
3543 $comment->signature = check_markup($comment->signature, $comment->signature_format, '', TRUE); |
|
3544 } |
|
3545 else { |
|
3546 $comment->signature = ''; |
|
3547 } |
|
3548 } |
|
3549 |
|
3550 /** |
|
3551 * Returns HTML for a user signature. |
|
3552 * |
|
3553 * @param $variables |
|
3554 * An associative array containing: |
|
3555 * - signature: The user's signature. |
|
3556 * |
|
3557 * @ingroup themeable |
|
3558 */ |
|
3559 function theme_user_signature($variables) { |
|
3560 $signature = $variables['signature']; |
|
3561 $output = ''; |
|
3562 |
|
3563 if ($signature) { |
|
3564 $output .= '<div class="clear">'; |
|
3565 $output .= '<div>—</div>'; |
|
3566 $output .= $signature; |
|
3567 $output .= '</div>'; |
|
3568 } |
|
3569 |
|
3570 return $output; |
|
3571 } |
|
3572 |
|
3573 /** |
|
3574 * Get the language object preferred by the user. This user preference can |
|
3575 * be set on the user account editing page, and is only available if there |
|
3576 * are more than one languages enabled on the site. If the user did not |
|
3577 * choose a preferred language, or is the anonymous user, the $default |
|
3578 * value, or if it is not set, the site default language will be returned. |
|
3579 * |
|
3580 * @param $account |
|
3581 * User account to look up language for. |
|
3582 * @param $default |
|
3583 * Optional default language object to return if the account |
|
3584 * has no valid language. |
|
3585 */ |
|
3586 function user_preferred_language($account, $default = NULL) { |
|
3587 $language_list = language_list(); |
|
3588 if (!empty($account->language) && isset($language_list[$account->language])) { |
|
3589 return $language_list[$account->language]; |
|
3590 } |
|
3591 else { |
|
3592 return $default ? $default : language_default(); |
|
3593 } |
|
3594 } |
|
3595 |
|
3596 /** |
|
3597 * Conditionally create and send a notification email when a certain |
|
3598 * operation happens on the given user account. |
|
3599 * |
|
3600 * @see user_mail_tokens() |
|
3601 * @see drupal_mail() |
|
3602 * |
|
3603 * @param $op |
|
3604 * The operation being performed on the account. Possible values: |
|
3605 * - 'register_admin_created': Welcome message for user created by the admin. |
|
3606 * - 'register_no_approval_required': Welcome message when user |
|
3607 * self-registers. |
|
3608 * - 'register_pending_approval': Welcome message, user pending admin |
|
3609 * approval. |
|
3610 * - 'password_reset': Password recovery request. |
|
3611 * - 'status_activated': Account activated. |
|
3612 * - 'status_blocked': Account blocked. |
|
3613 * - 'cancel_confirm': Account cancellation request. |
|
3614 * - 'status_canceled': Account canceled. |
|
3615 * |
|
3616 * @param $account |
|
3617 * The user object of the account being notified. Must contain at |
|
3618 * least the fields 'uid', 'name', and 'mail'. |
|
3619 * @param $language |
|
3620 * Optional language to use for the notification, overriding account language. |
|
3621 * |
|
3622 * @return |
|
3623 * The return value from drupal_mail_system()->mail(), if ends up being |
|
3624 * called. |
|
3625 */ |
|
3626 function _user_mail_notify($op, $account, $language = NULL) { |
|
3627 // By default, we always notify except for canceled and blocked. |
|
3628 $default_notify = ($op != 'status_canceled' && $op != 'status_blocked'); |
|
3629 $notify = variable_get('user_mail_' . $op . '_notify', $default_notify); |
|
3630 if ($notify) { |
|
3631 $params['account'] = $account; |
|
3632 $language = $language ? $language : user_preferred_language($account); |
|
3633 $mail = drupal_mail('user', $op, $account->mail, $language, $params); |
|
3634 if ($op == 'register_pending_approval') { |
|
3635 // If a user registered requiring admin approval, notify the admin, too. |
|
3636 // We use the site default language for this. |
|
3637 drupal_mail('user', 'register_pending_approval_admin', variable_get('site_mail', ini_get('sendmail_from')), language_default(), $params); |
|
3638 } |
|
3639 } |
|
3640 return empty($mail) ? NULL : $mail['result']; |
|
3641 } |
|
3642 |
|
3643 /** |
|
3644 * Form element process handler for client-side password validation. |
|
3645 * |
|
3646 * This #process handler is automatically invoked for 'password_confirm' form |
|
3647 * elements to add the JavaScript and string translations for dynamic password |
|
3648 * validation. |
|
3649 * |
|
3650 * @see system_element_info() |
|
3651 */ |
|
3652 function user_form_process_password_confirm($element) { |
|
3653 global $user; |
|
3654 |
|
3655 $js_settings = array( |
|
3656 'password' => array( |
|
3657 'strengthTitle' => t('Password strength:'), |
|
3658 'hasWeaknesses' => t('To make your password stronger:'), |
|
3659 'tooShort' => t('Make it at least 6 characters'), |
|
3660 'addLowerCase' => t('Add lowercase letters'), |
|
3661 'addUpperCase' => t('Add uppercase letters'), |
|
3662 'addNumbers' => t('Add numbers'), |
|
3663 'addPunctuation' => t('Add punctuation'), |
|
3664 'sameAsUsername' => t('Make it different from your username'), |
|
3665 'confirmSuccess' => t('yes'), |
|
3666 'confirmFailure' => t('no'), |
|
3667 'weak' => t('Weak'), |
|
3668 'fair' => t('Fair'), |
|
3669 'good' => t('Good'), |
|
3670 'strong' => t('Strong'), |
|
3671 'confirmTitle' => t('Passwords match:'), |
|
3672 'username' => (isset($user->name) ? $user->name : ''), |
|
3673 ), |
|
3674 ); |
|
3675 |
|
3676 $element['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.js'; |
|
3677 $element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting'); |
|
3678 |
|
3679 return $element; |
|
3680 } |
|
3681 |
|
3682 /** |
|
3683 * Implements hook_node_load(). |
|
3684 */ |
|
3685 function user_node_load($nodes, $types) { |
|
3686 // Build an array of all uids for node authors, keyed by nid. |
|
3687 $uids = array(); |
|
3688 foreach ($nodes as $nid => $node) { |
|
3689 $uids[$nid] = $node->uid; |
|
3690 } |
|
3691 |
|
3692 // Fetch name, picture, and data for these users. |
|
3693 $user_fields = db_query("SELECT uid, name, picture, data FROM {users} WHERE uid IN (:uids)", array(':uids' => $uids))->fetchAllAssoc('uid'); |
|
3694 |
|
3695 // Add these values back into the node objects. |
|
3696 foreach ($uids as $nid => $uid) { |
|
3697 $nodes[$nid]->name = $user_fields[$uid]->name; |
|
3698 $nodes[$nid]->picture = $user_fields[$uid]->picture; |
|
3699 $nodes[$nid]->data = $user_fields[$uid]->data; |
|
3700 } |
|
3701 } |
|
3702 |
|
3703 /** |
|
3704 * Implements hook_image_style_delete(). |
|
3705 */ |
|
3706 function user_image_style_delete($style) { |
|
3707 // If a style is deleted, update the variables. |
|
3708 // Administrators choose a replacement style when deleting. |
|
3709 user_image_style_save($style); |
|
3710 } |
|
3711 |
|
3712 /** |
|
3713 * Implements hook_image_style_save(). |
|
3714 */ |
|
3715 function user_image_style_save($style) { |
|
3716 // If a style is renamed, update the variables that use it. |
|
3717 if (isset($style['old_name']) && $style['old_name'] == variable_get('user_picture_style', '')) { |
|
3718 variable_set('user_picture_style', $style['name']); |
|
3719 } |
|
3720 } |
|
3721 |
|
3722 /** |
|
3723 * Implements hook_action_info(). |
|
3724 */ |
|
3725 function user_action_info() { |
|
3726 return array( |
|
3727 'user_block_user_action' => array( |
|
3728 'label' => t('Block current user'), |
|
3729 'type' => 'user', |
|
3730 'configurable' => FALSE, |
|
3731 'triggers' => array('any'), |
|
3732 ), |
|
3733 ); |
|
3734 } |
|
3735 |
|
3736 /** |
|
3737 * Blocks a specific user or the current user, if one is not specified. |
|
3738 * |
|
3739 * @param $entity |
|
3740 * (optional) An entity object; if it is provided and it has a uid property, |
|
3741 * the user with that ID is blocked. |
|
3742 * @param $context |
|
3743 * (optional) An associative array; if no user ID is found in $entity, the |
|
3744 * 'uid' element of this array determines the user to block. |
|
3745 * |
|
3746 * @ingroup actions |
|
3747 */ |
|
3748 function user_block_user_action(&$entity, $context = array()) { |
|
3749 // First priority: If there is a $entity->uid, block that user. |
|
3750 // This is most likely a user object or the author if a node or comment. |
|
3751 if (isset($entity->uid)) { |
|
3752 $uid = $entity->uid; |
|
3753 } |
|
3754 elseif (isset($context['uid'])) { |
|
3755 $uid = $context['uid']; |
|
3756 } |
|
3757 // If neither of those are valid, then block the current user. |
|
3758 else { |
|
3759 $uid = $GLOBALS['user']->uid; |
|
3760 } |
|
3761 $account = user_load($uid); |
|
3762 $account = user_save($account, array('status' => 0)); |
|
3763 watchdog('action', 'Blocked user %name.', array('%name' => $account->name)); |
|
3764 } |
|
3765 |
|
3766 /** |
|
3767 * Implements hook_form_FORM_ID_alter(). |
|
3768 * |
|
3769 * Add a checkbox for the 'user_register_form' instance settings on the 'Edit |
|
3770 * field instance' form. |
|
3771 */ |
|
3772 function user_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) { |
|
3773 $instance = $form['#instance']; |
|
3774 |
|
3775 if ($instance['entity_type'] == 'user' && !$form['#field']['locked']) { |
|
3776 $form['instance']['settings']['user_register_form'] = array( |
|
3777 '#type' => 'checkbox', |
|
3778 '#title' => t('Display on user registration form.'), |
|
3779 '#description' => t("This is compulsory for 'required' fields."), |
|
3780 // Field instances created in D7 beta releases before the setting was |
|
3781 // introduced might be set as 'required' and 'not shown on user_register |
|
3782 // form'. We make sure the checkbox comes as 'checked' for those. |
|
3783 '#default_value' => $instance['settings']['user_register_form'] || $instance['required'], |
|
3784 // Display just below the 'required' checkbox. |
|
3785 '#weight' => $form['instance']['required']['#weight'] + .1, |
|
3786 // Disabled when the 'required' checkbox is checked. |
|
3787 '#states' => array( |
|
3788 'enabled' => array('input[name="instance[required]"]' => array('checked' => FALSE)), |
|
3789 ), |
|
3790 // Checked when the 'required' checkbox is checked. This is done through |
|
3791 // a custom behavior, since the #states system would also synchronize on |
|
3792 // uncheck. |
|
3793 '#attached' => array( |
|
3794 'js' => array(drupal_get_path('module', 'user') . '/user.js'), |
|
3795 ), |
|
3796 ); |
|
3797 |
|
3798 array_unshift($form['#submit'], 'user_form_field_ui_field_edit_form_submit'); |
|
3799 } |
|
3800 } |
|
3801 |
|
3802 /** |
|
3803 * Additional submit handler for the 'Edit field instance' form. |
|
3804 * |
|
3805 * Make sure the 'user_register_form' setting is set for required fields. |
|
3806 */ |
|
3807 function user_form_field_ui_field_edit_form_submit($form, &$form_state) { |
|
3808 $instance = $form_state['values']['instance']; |
|
3809 |
|
3810 if (!empty($instance['required'])) { |
|
3811 form_set_value($form['instance']['settings']['user_register_form'], 1, $form_state); |
|
3812 } |
|
3813 } |
|
3814 |
|
3815 /** |
|
3816 * Form builder; the user registration form. |
|
3817 * |
|
3818 * @ingroup forms |
|
3819 * @see user_account_form() |
|
3820 * @see user_account_form_validate() |
|
3821 * @see user_register_submit() |
|
3822 */ |
|
3823 function user_register_form($form, &$form_state) { |
|
3824 global $user; |
|
3825 |
|
3826 $admin = user_access('administer users'); |
|
3827 |
|
3828 // Pass access information to the submit handler. Running an access check |
|
3829 // inside the submit function interferes with form processing and breaks |
|
3830 // hook_form_alter(). |
|
3831 $form['administer_users'] = array( |
|
3832 '#type' => 'value', |
|
3833 '#value' => $admin, |
|
3834 ); |
|
3835 |
|
3836 // If we aren't admin but already logged on, go to the user page instead. |
|
3837 if (!$admin && $user->uid) { |
|
3838 drupal_goto('user/' . $user->uid); |
|
3839 } |
|
3840 |
|
3841 $form['#user'] = drupal_anonymous_user(); |
|
3842 $form['#user_category'] = 'register'; |
|
3843 |
|
3844 $form['#attached']['library'][] = array('system', 'jquery.cookie'); |
|
3845 $form['#attributes']['class'][] = 'user-info-from-cookie'; |
|
3846 |
|
3847 // Start with the default user account fields. |
|
3848 user_account_form($form, $form_state); |
|
3849 |
|
3850 // Attach field widgets, and hide the ones where the 'user_register_form' |
|
3851 // setting is not on. |
|
3852 $langcode = entity_language('user', $form['#user']); |
|
3853 field_attach_form('user', $form['#user'], $form, $form_state, $langcode); |
|
3854 foreach (field_info_instances('user', 'user') as $field_name => $instance) { |
|
3855 if (empty($instance['settings']['user_register_form'])) { |
|
3856 $form[$field_name]['#access'] = FALSE; |
|
3857 } |
|
3858 } |
|
3859 |
|
3860 if ($admin) { |
|
3861 // Redirect back to page which initiated the create request; |
|
3862 // usually admin/people/create. |
|
3863 $form_state['redirect'] = $_GET['q']; |
|
3864 } |
|
3865 |
|
3866 $form['actions'] = array('#type' => 'actions'); |
|
3867 $form['actions']['submit'] = array( |
|
3868 '#type' => 'submit', |
|
3869 '#value' => t('Create new account'), |
|
3870 ); |
|
3871 |
|
3872 $form['#validate'][] = 'user_register_validate'; |
|
3873 // Add the final user registration form submit handler. |
|
3874 $form['#submit'][] = 'user_register_submit'; |
|
3875 |
|
3876 return $form; |
|
3877 } |
|
3878 |
|
3879 /** |
|
3880 * Validation function for the user registration form. |
|
3881 */ |
|
3882 function user_register_validate($form, &$form_state) { |
|
3883 entity_form_field_validate('user', $form, $form_state); |
|
3884 } |
|
3885 |
|
3886 /** |
|
3887 * Submit handler for the user registration form. |
|
3888 * |
|
3889 * This function is shared by the installation form and the normal registration form, |
|
3890 * which is why it can't be in the user.pages.inc file. |
|
3891 * |
|
3892 * @see user_register_form() |
|
3893 */ |
|
3894 function user_register_submit($form, &$form_state) { |
|
3895 $admin = $form_state['values']['administer_users']; |
|
3896 |
|
3897 if (!variable_get('user_email_verification', TRUE) || $admin) { |
|
3898 $pass = $form_state['values']['pass']; |
|
3899 } |
|
3900 else { |
|
3901 $pass = user_password(); |
|
3902 } |
|
3903 $notify = !empty($form_state['values']['notify']); |
|
3904 |
|
3905 // Remove unneeded values. |
|
3906 form_state_values_clean($form_state); |
|
3907 |
|
3908 $form_state['values']['pass'] = $pass; |
|
3909 $form_state['values']['init'] = $form_state['values']['mail']; |
|
3910 |
|
3911 $account = $form['#user']; |
|
3912 |
|
3913 entity_form_submit_build_entity('user', $account, $form, $form_state); |
|
3914 |
|
3915 // Populate $edit with the properties of $account, which have been edited on |
|
3916 // this form by taking over all values, which appear in the form values too. |
|
3917 $edit = array_intersect_key((array) $account, $form_state['values']); |
|
3918 $account = user_save($account, $edit); |
|
3919 |
|
3920 // Terminate if an error occurred during user_save(). |
|
3921 if (!$account) { |
|
3922 drupal_set_message(t("Error saving user account."), 'error'); |
|
3923 $form_state['redirect'] = ''; |
|
3924 return; |
|
3925 } |
|
3926 $form_state['user'] = $account; |
|
3927 $form_state['values']['uid'] = $account->uid; |
|
3928 |
|
3929 watchdog('user', 'New user: %name (%email).', array('%name' => $form_state['values']['name'], '%email' => $form_state['values']['mail']), WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit')); |
|
3930 |
|
3931 // Add plain text password into user account to generate mail tokens. |
|
3932 $account->password = $pass; |
|
3933 |
|
3934 // New administrative account without notification. |
|
3935 $uri = entity_uri('user', $account); |
|
3936 if ($admin && !$notify) { |
|
3937 drupal_set_message(t('Created a new user account for <a href="@url">%name</a>. No e-mail has been sent.', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name))); |
|
3938 } |
|
3939 // No e-mail verification required; log in user immediately. |
|
3940 elseif (!$admin && !variable_get('user_email_verification', TRUE) && $account->status) { |
|
3941 _user_mail_notify('register_no_approval_required', $account); |
|
3942 $form_state['uid'] = $account->uid; |
|
3943 user_login_submit(array(), $form_state); |
|
3944 drupal_set_message(t('Registration successful. You are now logged in.')); |
|
3945 $form_state['redirect'] = ''; |
|
3946 } |
|
3947 // No administrator approval required. |
|
3948 elseif ($account->status || $notify) { |
|
3949 $op = $notify ? 'register_admin_created' : 'register_no_approval_required'; |
|
3950 _user_mail_notify($op, $account); |
|
3951 if ($notify) { |
|
3952 drupal_set_message(t('A welcome message with further instructions has been e-mailed to the new user <a href="@url">%name</a>.', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name))); |
|
3953 } |
|
3954 else { |
|
3955 drupal_set_message(t('A welcome message with further instructions has been sent to your e-mail address.')); |
|
3956 $form_state['redirect'] = ''; |
|
3957 } |
|
3958 } |
|
3959 // Administrator approval required. |
|
3960 else { |
|
3961 _user_mail_notify('register_pending_approval', $account); |
|
3962 drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, a welcome message with further instructions has been sent to your e-mail address.')); |
|
3963 $form_state['redirect'] = ''; |
|
3964 } |
|
3965 } |
|
3966 |
|
3967 /** |
|
3968 * Implements hook_modules_installed(). |
|
3969 */ |
|
3970 function user_modules_installed($modules) { |
|
3971 // Assign all available permissions to the administrator role. |
|
3972 $rid = variable_get('user_admin_role', 0); |
|
3973 if ($rid) { |
|
3974 $permissions = array(); |
|
3975 foreach ($modules as $module) { |
|
3976 if ($module_permissions = module_invoke($module, 'permission')) { |
|
3977 $permissions = array_merge($permissions, array_keys($module_permissions)); |
|
3978 } |
|
3979 } |
|
3980 if (!empty($permissions)) { |
|
3981 user_role_grant_permissions($rid, $permissions); |
|
3982 } |
|
3983 } |
|
3984 } |
|
3985 |
|
3986 /** |
|
3987 * Implements hook_modules_uninstalled(). |
|
3988 */ |
|
3989 function user_modules_uninstalled($modules) { |
|
3990 db_delete('role_permission') |
|
3991 ->condition('module', $modules, 'IN') |
|
3992 ->execute(); |
|
3993 } |
|
3994 |
|
3995 /** |
|
3996 * Helper function to rewrite the destination to avoid redirecting to login page after login. |
|
3997 * |
|
3998 * Third-party authentication modules may use this function to determine the |
|
3999 * proper destination after a user has been properly logged in. |
|
4000 */ |
|
4001 function user_login_destination() { |
|
4002 $destination = drupal_get_destination(); |
|
4003 if ($destination['destination'] == 'user/login') { |
|
4004 $destination['destination'] = 'user'; |
|
4005 } |
|
4006 return $destination; |
|
4007 } |
|
4008 |
|
4009 /** |
|
4010 * Saves visitor information as a cookie so it can be reused. |
|
4011 * |
|
4012 * @param $values |
|
4013 * An array of key/value pairs to be saved into a cookie. |
|
4014 */ |
|
4015 function user_cookie_save(array $values) { |
|
4016 foreach ($values as $field => $value) { |
|
4017 // Set cookie for 365 days. |
|
4018 setrawcookie('Drupal.visitor.' . $field, rawurlencode($value), REQUEST_TIME + 31536000, '/'); |
|
4019 } |
|
4020 } |
|
4021 |
|
4022 /** |
|
4023 * Delete a visitor information cookie. |
|
4024 * |
|
4025 * @param $cookie_name |
|
4026 * A cookie name such as 'homepage'. |
|
4027 */ |
|
4028 function user_cookie_delete($cookie_name) { |
|
4029 setrawcookie('Drupal.visitor.' . $cookie_name, '', REQUEST_TIME - 3600, '/'); |
|
4030 } |
|
4031 |
|
4032 /** |
|
4033 * Implements hook_rdf_mapping(). |
|
4034 */ |
|
4035 function user_rdf_mapping() { |
|
4036 return array( |
|
4037 array( |
|
4038 'type' => 'user', |
|
4039 'bundle' => RDF_DEFAULT_BUNDLE, |
|
4040 'mapping' => array( |
|
4041 'rdftype' => array('sioc:UserAccount'), |
|
4042 'name' => array( |
|
4043 'predicates' => array('foaf:name'), |
|
4044 ), |
|
4045 'homepage' => array( |
|
4046 'predicates' => array('foaf:page'), |
|
4047 'type' => 'rel', |
|
4048 ), |
|
4049 ), |
|
4050 ), |
|
4051 ); |
|
4052 } |
|
4053 |
|
4054 /** |
|
4055 * Implements hook_file_download_access(). |
|
4056 */ |
|
4057 function user_file_download_access($field, $entity_type, $entity) { |
|
4058 if ($entity_type == 'user') { |
|
4059 return user_view_access($entity); |
|
4060 } |
|
4061 } |
|
4062 |
|
4063 /** |
|
4064 * Implements hook_system_info_alter(). |
|
4065 * |
|
4066 * Drupal 7 ships with two methods to add additional fields to users: Profile |
|
4067 * module, a legacy module dating back from 2002, and Field API integration |
|
4068 * with users. While Field API support for users currently provides less end |
|
4069 * user features, the inefficient data storage mechanism of Profile module, as |
|
4070 * well as its lack of consistency with the rest of the entity / field based |
|
4071 * systems in Drupal 7, make this a sub-optimal solution to those who were not |
|
4072 * using it in previous releases of Drupal. |
|
4073 * |
|
4074 * To prevent new Drupal 7 sites from installing Profile module, and |
|
4075 * unwittingly ending up with two completely different and incompatible methods |
|
4076 * of extending users, only make the Profile module available if the profile_* |
|
4077 * tables are present. |
|
4078 * |
|
4079 * @todo: Remove in D8, pending upgrade path. |
|
4080 */ |
|
4081 function user_system_info_alter(&$info, $file, $type) { |
|
4082 if ($type == 'module' && $file->name == 'profile' && db_table_exists('profile_field')) { |
|
4083 $info['hidden'] = FALSE; |
|
4084 } |
|
4085 } |