Projet

Général

Profil

Paste
Télécharger (32,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / masquerade / masquerade.module @ 3461d8cb

1
<?php
2

    
3
/**
4
 * @file
5
 * The masquerade module allows administrators to masquerade as other user.
6
 */
7

    
8
/**
9
 * Implements hook_help().
10
 */
11
function masquerade_help($path, $arg) {
12
  switch ($path) {
13
    case 'admin/help#masquerade':
14
      return t('<p>The masquerade module adds a link on a user\'s profile page that allows permitted users to masquerade as that user. Upon masquerading, a link to "switch back" to the original user will appear in the menu. While masquerading, the option to masquerade as another user will not appear. All masquerading transactions are logged, and $user->masquerading will be set; this could be displayed via theme.</p><p>In the masquerade settings a list of roles are presented; any checked role is considered an "administrator" and requires the second level "masquerade as admin" permission to masquerade as. User #1 is automatically considered an administrator, regardless of roles.</p>');
15
    case 'admin/settings/masquerade':
16
      return t('Only the users with <strong>masquerade as admin</strong> permission, will be able to masquerade as the users who belong to the roles selected below. User #1 is automatically considered an administrator, regardless of roles.');
17
  }
18
}
19

    
20
/**
21
 * Implements hook_permission().
22
 *
23
 * @return array
24
 */
25
function masquerade_permission() {
26
  return array(
27
    'masquerade as user' => array(
28
      'title' => t('Masquerade as user'),
29
      'description' => t('Masquerade as another user.'),
30
    ),
31
    'masquerade as admin' => array(
32
      'title' => t('Masquerade as admin'),
33
      'description' => t('Masquerade as the site admin (UID 1).'),
34
    ),
35
    'administer masquerade' => array(
36
      'title' => t('Administer Masquerade'),
37
      'description' => t('Perform administration tasks and configure the Masquerade module.'),
38
    ),
39
  );
40
}
41

    
42
/**
43
 * Implements hook_init().
44
 */
45
function masquerade_init() {
46
  global $user;
47

    
48
  // Try to load masqing uid from masquerade table.
49
  $uid = db_query("SELECT uid_from FROM {masquerade} WHERE sid = :sid AND uid_as = :uid_as", array(
50
    ':sid' => session_id(),
51
    ':uid_as' => $user->uid,
52
  ))->fetchField();
53

    
54
  // We are using identical operator (===) instead of equal (==) because if
55
  // $uid === 0 we want to store the session variable. If there's no record in
56
  // masquerade table we clear the session variable.
57
  if ($uid === FALSE) {
58
    if (isset($_SESSION)) {
59
      unset($_SESSION['masquerading']);
60
    }
61
  }
62
  else {
63
    $_SESSION['masquerading'] = $uid;
64
  }
65
}
66

    
67
/**
68
 * Implements hook_cron().
69
 *
70
 * Cleanup masquerade records where people didn't use the switch back link
71
 * that would have cleanly removed the user switch record.
72
 */
73
function masquerade_cron() {
74
  // see http://drupal.org/node/268487 before modifying this query
75
  $subquery = db_select('sessions', 's');
76
  $subquery->addField('s', 'sid');
77

    
78
  $query = db_delete('masquerade');
79
  $query->condition('sid', $subquery, 'NOT IN');
80
  $query->execute();
81
}
82

    
83
/**
84
 * Implements hook_menu().
85
 */
86
function masquerade_menu() {
87
  $items = array();
88

    
89
  $default_test_user = _masquerade_user_load(variable_get('masquerade_test_user', ''));
90
  if ($default_test_user && ($default_test_user->uid || $default_test_user->name == variable_get('anonymous', t('Anonymous')))) {
91
    $items['masquerade/switch/' . $default_test_user->uid] = array(
92
      'title' => 'Masquerade as @testuser',
93
      'title arguments' => array('@testuser' => $default_test_user->name),
94
      'page callback' => 'masquerade_switch_user_page',
95
      'page arguments' => array(2),
96
      'access callback' => 'masquerade_menu_access',
97
      'access arguments' => array('switch'),
98
      'type' => MENU_NORMAL_ITEM,
99
    );
100
  }
101

    
102
  $items['masquerade/switch/%'] = array(
103
    'title' => 'Masquerading',
104
    'page callback' => 'masquerade_switch_user_page',
105
    'page arguments' => array(2),
106
    'access callback' => 'masquerade_menu_access',
107
    'access arguments' => array('switch', 2),
108
    'type' => MENU_NORMAL_ITEM,
109
  );
110
  $items['masquerade/unswitch'] = array(
111
    'title' => 'Switch back',
112
    'page callback' => 'masquerade_switch_back_page',
113
    'access callback' => 'masquerade_menu_access',
114
    'access arguments' => array('unswitch'),
115
    'type' => MENU_NORMAL_ITEM,
116
  );
117
  $items['masquerade/autocomplete'] = array(
118
    'title' => '',
119
    'page callback' => 'masquerade_autocomplete',
120
    'access callback' => 'masquerade_menu_access',
121
    'access arguments' => array('autocomplete'),
122
    'type' => MENU_CALLBACK,
123
  );
124
  $items['masquerade/autocomplete-users'] = array(
125
    'title' => '',
126
    'page callback' => 'masquerade_autocomplete_multiple',
127
    'access callback' => 'masquerade_menu_access',
128
    'access arguments' => array('autocomplete'),
129
    'type' => MENU_CALLBACK,
130
  );
131
  $items['masquerade/autocomplete-user'] = array(
132
    'title' => 'Masquerade autocomplete',
133
    'page callback' => 'masquerade_autocomplete_multiple',
134
    'page arguments' => array(2, FALSE),
135
    'access arguments' => array('access user profiles'),
136
    'type' => MENU_CALLBACK,
137
  );
138
  $items['admin/config/people/masquerade'] = array(
139
    'title' => 'Masquerade',
140
    'description' => 'Masquerade module allows administrators to masquerade as other users.',
141
    'page callback' => 'drupal_get_form',
142
    'page arguments' => array('masquerade_admin_settings'),
143
    'access callback' => 'user_access',
144
    'access arguments' => array('administer masquerade'),
145
    'type' => MENU_NORMAL_ITEM,
146
  );
147

    
148
  return $items;
149
}
150

    
151
/**
152
 * Implements hook_menu_alter().
153
 *
154
 * We need to add a token to the Masquerade paths to protect against CSRF
155
 * attacks. Since menu items in Drupal do not support dynamic elements these
156
 * tokens need to be added during rendering via masquerade_translated_menu_link_alter().
157
 * Set the 'alter'-option to TRUE to make sure
158
 * the links get passed through masquerade_translated_menu_link_alter.
159
 */
160
function masquerade_menu_alter(&$items) {
161
  $default_test_user = _masquerade_user_load(variable_get('masquerade_test_user', ''));
162
  if (isset($default_test_user->uid)) {
163
    $items['masquerade/switch/' . $default_test_user->uid]['options']['alter'] = TRUE;
164
  }
165
  $items['masquerade/switch/%']['options']['alter'] = TRUE;
166
  $items['masquerade/unswitch']['options']['alter'] = TRUE;
167
}
168

    
169
/**
170
 * Implements hook_translated_menu_link_alter().
171
 *
172
 * Dynamically add the CSRF protection token to the Masquerade menu items.
173
 */
174
function masquerade_translated_menu_link_alter(&$item, $map) {
175
  if (isset($item['page_callback'])) {
176
    if ($item['page_callback'] == 'masquerade_switch_user_page' && isset($map[2])) {
177
      $item['localized_options']['query']['token'] = drupal_get_token('masquerade/switch/' . $map[2]);
178
    }
179
    elseif ($item['page_callback'] == 'masquerade_switch_back_page') {
180
      $item['localized_options']['query']['token'] = drupal_get_token('masquerade/unswitch');
181
    }
182
  }
183
}
184

    
185
/**
186
 * Implements hook_user_operations().
187
 */
188
function masquerade_user_operations() {
189
  return array(
190
    'masquerade' => array(
191
      'label' => t('Masquerade as user'),
192
      'callback' => 'masquerade_user_operations_masquerade',
193
    ),
194
  );
195
}
196

    
197
/**
198
 * Callback for user operation.
199
 */
200
function masquerade_user_operations_masquerade(array $accounts) {
201
  // Only process the first account since switching to multiple makes no sense.
202
  if (($uid = current($accounts)) && masquerade_menu_access('switch', $uid)) {
203
    masquerade_switch_user($uid);
204
  }
205
}
206

    
207
/**
208
 * Determine if the current user has permission to switch users.
209
 *
210
 * @param string $type
211
 *   Either 'switch', 'unswitch', 'user', or 'autocomplete'.
212
 *
213
 * @param object $uid
214
 *   An optional parameter indicating a specific uid to switch to.
215
 *   Otherwise, return if the user can switch to any user account.
216
 *
217
 * @return
218
 *   TRUE, if the user can perform the requested action, FALSE otherwise.
219
 */
220

    
221
function masquerade_menu_access($type, $uid = NULL) {
222
  switch ($type) {
223
    case 'unswitch':
224
      return isset($_SESSION['masquerading']) || arg(2) == 'menu-customize' || arg(2) == 'menu';
225
    case 'autocomplete':
226
      return isset($_SESSION['masquerading']) || (user_access('masquerade as user') || user_access('masquerade as admin'));
227
      break;
228
    case 'user':
229
      global $user;
230
      return db_query("SELECT 1 FROM {masquerade_users} WHERE uid_from = :uid_from", array(':uid_from' => $user->uid))->fetchField();
231
      break;
232
    case 'switch':
233
      $switch_to_account = FALSE;
234
      global $user;
235
      if ($uid) {
236
        if (!is_numeric($uid)) {
237
          return FALSE;
238
        }
239
        if ($account = user_load($uid)) {
240
          $switch_to_account = db_query("SELECT 1 FROM {masquerade_users} WHERE uid_from = :uid_from AND uid_to = :uid_to", array(
241
            ':uid_from' => $user->uid,
242
            ':uid_to' => $account->uid
243
          ))->fetchField();
244
        }
245
      }
246
      return !isset($_SESSION['masquerading']) && (user_access('masquerade as user') || user_access('masquerade as admin') || $switch_to_account);
247
      break;
248
  }
249
}
250

    
251
/**
252
 * Admin settings form.
253
 */
254
function masquerade_admin_settings() {
255
  // create a list of roles; all selected roles are considered administrative.
256
  $roles = user_roles();
257
  $form['masquerade_admin_roles'] = array(
258
    '#type' => 'checkboxes',
259
    '#title' => t('Roles that are considered "administrators" for masquerading'),
260
    '#options' => $roles,
261
    '#default_value' => variable_get('masquerade_admin_roles', array()),
262
  );
263

    
264
  $test_name = _masquerade_user_load(variable_get('masquerade_test_user', ''));
265

    
266
  $form['masquerade_test_user'] = array(
267
    '#type' => 'textfield',
268
    '#title' => t('Menu <em>Quick Switch</em> user'),
269
    '#autocomplete_path' => 'masquerade/autocomplete',
270
    '#default_value' => isset($test_name->name) ? check_plain($test_name->name) : '',
271
    '#description' => t('Enter the username of an account you wish to switch easily between via a menu item.'),
272
    '#maxlength' => NULL,
273
  );
274

    
275
  $quick_switch = user_load_multiple(variable_get('masquerade_quick_switches', array()));
276
  $quick_switch_users = array();
277
  foreach ($quick_switch as $uid => $account) {
278
    if ($uid == 0) {
279
      $account->name = variable_get('anonymous', t('Anonymous'));
280
    }
281
    $quick_switch_users[] = $account->name;
282
  }
283
  $form['masquerade_quick_switches'] = array(
284
    '#type' => 'textfield',
285
    '#title' => t('Masquerade Block <em>Quick Switch</em> users'),
286
    '#autocomplete_path' => 'masquerade/autocomplete-users',
287
    '#default_value' => drupal_implode_tags($quick_switch_users),
288
    '#description' => t('Enter the usernames, separated by commas, of accounts to show as quick switch links in the Masquerade block.'),
289
    '#maxlength' => NULL,
290
  );
291

    
292
  $form = system_settings_form($form);
293
  $form['#validate'][] = 'masquerade_admin_settings_validate';
294
  $form['#submit'][] = 'masquerade_admin_settings_submit';
295

    
296
  return $form;
297
}
298

    
299
function masquerade_admin_settings_validate($form, &$form_state) {
300
  if (!empty($form_state['values']['masquerade_test_user'])) {
301
    $test_user = _masquerade_user_load($form_state['values']['masquerade_test_user']);
302
    if (!$test_user) {
303
      form_set_error('masquerade_test_user', t('%user does not exist. Please enter a valid username.', array('%user' => $form_state['values']['masquerade_test_user'])));
304
    }
305
  }
306
  // Needs to rebuild menu in masquerade_admin_settings_submit().
307
  $form_state['masquerade_rebuild_menu'] = (variable_get('masquerade_test_user', '') != $form_state['values']['masquerade_test_user']);
308

    
309
  // A comma-separated list of users.
310
  $masquerade_switches = drupal_explode_tags($form_state['values']['masquerade_quick_switches']);
311
  // Change user names to user ID's for system_settings_form_submit() to save.
312
  $masquerade_uids = array();
313
  foreach ($masquerade_switches as $switch_user) {
314
    $test_user = _masquerade_user_load($switch_user);
315
    if (!$test_user) {
316
      form_set_error('masquerade_quick_switches', t('%user does not exist. Please enter a valid username.', array('%user' => $switch_user)));
317
    }
318
    else {
319
      $masquerade_uids[] = $test_user->uid;
320
    }
321
  }
322
  $form_state['values']['masquerade_quick_switches'] = $masquerade_uids;
323
}
324

    
325
function masquerade_admin_settings_submit($form, &$form_state) {
326
  // Rebuild the menu system so the menu "Quick Switch" user is updated.
327
  if ($form_state['masquerade_rebuild_menu']) {
328
    menu_rebuild();
329
  }
330
}
331

    
332
/**
333
 * Wrapper around user_load() to allow the loading of anonymous users.
334
 *
335
 * @param $username
336
 *   The username of the user you wish to load (i.e. $user->name). To load the
337
 *   anonymous user, pass the value of the 'anonymous' variable.
338
 *
339
 * @return
340
 *   A fully-loaded $user object upon successful user load or FALSE if user
341
 *   cannot be loaded.
342
 */
343
function _masquerade_user_load($username) {
344
  $account = FALSE;
345
  if (!empty($username)) {
346
    $anon = variable_get('anonymous', t('Anonymous'));
347
    $account = user_load_by_name(($username == $anon ? '' : $username));
348
    if (isset($account->uid) && empty($account->uid)) {
349
      // Anonymous user should have a name.
350
      $account->name = $anon;
351
    }
352
  }
353
  return $account;
354
}
355

    
356
/**
357
 * Implements hook_user_logout().
358
 */
359
function masquerade_user_logout($account) {
360
  if (!empty($account->masquerading)) {
361
    global $user;
362
    cache_clear_all($user->uid, 'cache_menu', TRUE);
363
    $real_user = user_load($user->masquerading);
364
    watchdog('masquerade', "User %user no longer masquerading as %masq_as.", array('%user' => $real_user->name, '%masq_as' => $user->name), WATCHDOG_INFO);
365

    
366
    $query = db_delete('masquerade');
367
    $query->condition('sid', session_id());
368
    $query->condition('uid_as', $account->uid);
369
    $query->execute();
370
  }
371
}
372

    
373
/**
374
 * Implements hook_field_extra_fields().
375
 */
376
function masquerade_field_extra_fields() {
377
  $return['user']['user']  = array(
378
    'form' => array(
379
      'masquerade' => array(
380
        'label' => t('Masquerade'),
381
        'description' => t('User masquerade settings.'),
382
        'weight' => 50,
383
      ),
384
    ),
385
    'display' => array(
386
      'masquerade' => array(
387
        'label' => t('Masquerade'),
388
        'description' => t('Masquerade as user link.'),
389
        'weight' => 50,
390
      ),
391
    ),
392
  );
393

    
394
  return $return;
395
}
396

    
397
/**
398
 * Implements hook_user_view().
399
 */
400
function masquerade_user_view($account, $view_mode, $langcode) {
401
  // check if user qualifies as admin
402
  $roles = array_keys(array_filter(variable_get('masquerade_admin_roles', array())));
403
  $perm = $account->uid == 1 || array_intersect(array_keys((array)$account->roles), $roles) ?
404
    'masquerade as admin' :
405
    'masquerade as user';
406

    
407
  global $user;
408

    
409
  // Query allowed uids so the "masquerade as <user>" link can be shown or
410
  // hidden.
411
  $allowed_uids = db_query("SELECT uid_to FROM {masquerade_users} WHERE uid_from = :uid_from", array(':uid_from' => $user->uid))
412
    ->fetchCol();
413

    
414
  if (user_access($perm) && empty($account->masquerading) && $user->uid != $account->uid && in_array($account->uid, $allowed_uids)) {
415
    $account->content['masquerade'] = array(
416
      '#markup' => l(t('Masquerade as !user', array('!user' => $account->name)),
417
        'masquerade/switch/' . $account->uid,
418
        array('query' => array(
419
          'token' => drupal_get_token('masquerade/switch/' . $account->uid)),
420
          'destination' => $_GET['q'],
421
          'attributes' => array('class' => array('masquerade-switch')),
422
        )),
423
      '#weight' => 10,
424
    );
425
  }
426
}
427

    
428
/**
429
 * Implements hook_form_FORM_ID_alter().
430
 */
431
function masquerade_form_user_profile_form_alter(&$form, &$form_state, $form_id) {
432
  if ($form['#user_category'] != 'account') {
433
    // Do not show this form for different categories.
434
    return;
435
  }
436
  $form['masquerade'] = array(
437
    '#type' => 'fieldset',
438
    '#title' => t('Masquerade settings'),
439
    '#access' => user_access('administer masquerade'),
440
  );
441
  $edit_user = $form['#user'];
442
  $uids = db_query("SELECT uid_to FROM {masquerade_users} WHERE uid_from = :uid_from", array(':uid_from' => $edit_user->uid))
443
    ->fetchCol();
444
  $users = user_load_multiple($uids);
445
  $masquerade_users = array();
446
  foreach ($users as $uid => $account) {
447
    if ($uid == 0) {
448
      $masquerade_users[] = variable_get('anonymous', t('Anonymous'));
449
    }
450
    else {
451
      $masquerade_users[] = $account->name;
452
    }
453
  }
454
  $form['masquerade']['masquerade_users'] = array(
455
    '#type' => 'textfield',
456
    '#title' => t('Enter the users this user is able to masquerade as'),
457
    '#description' => t('Enter a comma separated list of user names that this user can masquerade as.'),
458
    '#autocomplete_path' => 'masquerade/autocomplete-user',
459
    '#default_value' => drupal_implode_tags($masquerade_users),
460
    '#maxlength' => NULL,
461
  );
462
  $form['#validate'][] = 'masquerade_user_validate';
463
  $form['#submit'][] = 'masquerade_user_submit';
464
}
465

    
466
/**
467
 * Validates user account form.
468
 */
469
function masquerade_user_validate(&$form, $form_state) {
470
  if (isset($form_state['values']['masquerade_users'])) {
471
    $users = drupal_explode_tags($form_state['values']['masquerade_users']);
472
    foreach ($users as $username) {
473
      if (!_masquerade_user_load($username)) {
474
        form_set_error('masquerade_users', t('%user is not a valid user name.', array('%user' => $username)));
475
      }
476
    }
477
  }
478
}
479

    
480
/**
481
 * Submit handler for masquerade users form element.
482
 */
483
function masquerade_user_submit(&$form, $form_state) {
484
  global $_masquerade_old_session_id;
485
  $_masquerade_old_session_id = session_id();
486
}
487

    
488
/**
489
 * Implements hook_user_update().
490
 */
491
function masquerade_user_update(&$edit, $account, $category) {
492
  global $_masquerade_old_session_id;
493
  if ($category == 'account' && isset($edit['masquerade_users'])) {
494
    $query = db_delete('masquerade_users');
495
    $query->condition('uid_from', $account->uid);
496
    $query->execute();
497
    // Save users from settings form.
498
    $users = drupal_explode_tags($edit['masquerade_users']);
499
    $query = db_insert('masquerade_users')->fields(array('uid_from', 'uid_to'));
500
    foreach ($users as $username) {
501
      if ($to_user = _masquerade_user_load($username)) {
502
        $query->values(array(
503
          'uid_from' => $account->uid,
504
          'uid_to' => $to_user->uid,
505
        ));
506
      }
507
    }
508
    $query->execute();
509
    $edit['masquerade_users'] = NULL;
510

    
511
    // Update user session...
512
    // @TODO check other way of session API.
513
    if (!empty($_masquerade_old_session_id)) {
514
      $query = db_update('masquerade');
515
      $query->fields(array(
516
        'sid' => session_id(),
517
      ));
518
      $query->condition('sid', $_masquerade_old_session_id);
519
      $query->execute();
520
    }
521
  }
522
}
523

    
524
/**
525
 * Implements hook_user_delete().
526
 */
527
function masquerade_user_delete($account) {
528
  // Cleanup tables.
529
  $query = db_delete('masquerade_users');
530
  $conditions = db_or();
531
  $conditions->condition('uid_from', $account->uid);
532
  $conditions->condition('uid_to', $account->uid);
533
  $query->condition($conditions);
534
  $query->execute();
535
  // Cleanup variables.
536
  $switches = variable_get('masquerade_quick_switches', array());
537
  $switches_new = array_diff($switches, array($account->uid));
538
  if ($switches != $switches_new) {
539
    variable_set('masquerade_quick_switches', $switches_new);
540
    // @TODO Implement block cache cleaning.
541
    menu_rebuild();
542
  }
543
}
544

    
545
/**
546
 * Implements hook_block_info().
547
 */
548
function masquerade_block_info() {
549
  $blocks = array();
550
  $blocks['masquerade'] = array(
551
    'info' => t('Masquerade'),
552
    'cache' => DRUPAL_NO_CACHE,
553
  );
554
  return $blocks;
555
}
556

    
557
/**
558
 * Implements hook_block_view().
559
 */
560
function masquerade_block_view($delta = '') {
561
  $block = array();
562
  switch ($delta) {
563
    case 'masquerade':
564
      if (isset($_SESSION['masquerading']) || (user_access('masquerade as user') || user_access('masquerade as admin'))) {
565
        $block['subject'] = t('Masquerade');
566
        $block['content'] = drupal_get_form('masquerade_block_1');
567
      }
568
      break;
569
  }
570
  return $block;
571
}
572

    
573
/**
574
 * Masquerade block form.
575
 */
576
function masquerade_block_1() {
577
  global $user;
578
  $quick_switch_links = array();
579
  $markup_value = '';
580
  if (isset($_SESSION['masquerading'])) {
581
    $quick_switch_links[] = l(t('Switch back'), 'masquerade/unswitch', array('query' => array('token' => drupal_get_token('masquerade/unswitch'))));
582
    if ($user->uid > 0) {
583
      $markup_value = t('You are masquerading as <a href="@user-url">%masq_as</a>.', array('@user-url' => url('user/' . $user->uid), '%masq_as' => $user->name));
584
    }
585
    else {
586
      $markup_value = t('You are masquerading as %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous'))));
587
    }
588
  }
589
  else {
590
    $quick_switches = variable_get('masquerade_quick_switches', array());
591

    
592
    // Add in user-specific switches, and prevent duplicates.
593
    $user_switches = db_query("SELECT uid_to FROM {masquerade_users} WHERE uid_from = :uid_from", array(':uid_from' => $user->uid))->fetchCol();
594
    $masquerade_switches = array_unique(array_merge($quick_switches, $user_switches));
595

    
596
    foreach ($masquerade_switches as $switch_user) {
597
      if (!isset($_SESSION['user']->uid) || $switch_user != $_SESSION['user']->uid) {
598
        $account = user_load($switch_user);
599
        if (isset($account->uid)) {
600
          $switch_link = 'masquerade/switch/' . $account->uid;
601
          if ($account->uid) {
602
            $quick_switch_links[] = l($account->name, $switch_link, array('query' => array('token' => drupal_get_token($switch_link))));
603
          }
604
          if ($switch_user == 0) {
605
            $account->name = variable_get('anonymous', t('Anonymous'));
606
            $quick_switch_links[] = l($account->name, $switch_link, array('query' => array('token' => drupal_get_token($switch_link))));
607
          }
608
        }
609
      }
610
    }
611

    
612
    if (masquerade_menu_access('autocomplete')) {
613
      $markup_value .= t('Enter the username to masquerade as.');
614
      $form['masquerade_user_field'] = array(
615
        '#prefix' => '<div class="container-inline">',
616
        '#type' => 'textfield',
617
        '#size' => '18',
618
        '#default_value' => '',
619
        '#autocomplete_path' => 'masquerade/autocomplete',
620
        '#required' => TRUE,
621
      );
622
      $form['submit'] = array(
623
        '#type' => 'submit',
624
        '#value' => t('Go'),
625
        '#suffix' => '</div>',
626
      );
627
    }
628

    
629
  }
630
  if ($quick_switch_links) {
631
    $markup_value .= '<div id="quick_switch_links">' . t('Quick switches:') . theme('item_list', array('items' => $quick_switch_links)) . '</div>';
632
  }
633
  $form['masquerade_desc'] = array(
634
    '#prefix' => '<div class="form-item"><div class="description">',
635
    '#markup' => $markup_value,
636
    '#suffix' => '</div></div>',
637
  );
638
  return $form;
639
}
640

    
641
/**
642
 * Masquerade block form validation.
643
 */
644
function masquerade_block_1_validate($form, &$form_state) {
645
  global $user;
646
  //unset($form);
647
  $name = $form_state['values']['masquerade_user_field'];
648
  $allowed = FALSE;
649
  $to_uid = db_select('users', 'u')
650
    ->fields('u', array('uid'))
651
    ->condition('u.name', $name, '=')
652
    ->execute()
653
    ->fetchField();
654
  if ($to_uid !== FALSE) {
655
    $allowed = db_select('masquerade_users', 'm')
656
      ->fields('m', array('uid_to'))
657
      ->condition('m.uid_to', $to_uid, '=')
658
      ->condition('m.uid_from', $user->uid, '=')
659
      ->execute()
660
      ->fetchField();
661
  }
662
  if (isset($_SESSION['masquerading'])) {
663
    form_set_error('masquerade_user_field', t('You are already masquerading. Please <a href="@unswitch">switch back</a> to your account to masquerade as another user.', array('@unswitch' => url('masquerade/unswitch', array('query' => array('token' => drupal_get_token('masquerade/unswitch')))))));
664
  }
665
  if ($allowed === FALSE) {
666
    form_set_error('masquerade_user_field', t('You are not allowed to masquerade as the selected user.'));
667
  }
668

    
669
  if ($name != variable_get('anonymous', t('Anonymous')) && module_exists('alt_login')) {
670
    $alt_login = db_query("SELECT u.name FROM {users} u INNER JOIN {alt_login} al ON u.uid = al.uid WHERE al.alt_login = :alt_login", array(
671
      ':alt_login' => $name
672
    ))->fetchObject();
673
    if (isset($alt_login->name)) {
674
      $name = $alt_login->name;
675
    }
676
  }
677
  $masq_user = _masquerade_user_load($name);
678
  if (!$masq_user) {
679
    form_set_error('masquerade_user_field', t('User %masq_as does not exist. Please enter a valid username.', array('%masq_as' => $form_state['values']['masquerade_user_field'])));
680
  }
681
  elseif ($masq_user->uid == $user->uid) {
682
    form_set_error('masquerade_user_field', t('You cannot masquerade as yourself. Please choose a different user to masquerade as.'));
683
  }
684
  elseif (variable_get('maintenance_mode', 0) && !user_access('access site in maintenance mode', $masq_user)) {
685
    form_set_error('masquerade_user_field', t('It is not possible to masquerade in off-line mode as !user does not have the %config-perm permission. Please <a href="@site-maintenance">set the site status</a> to "online" to masquerade as !user.', array('!user' => theme('username', array('account' => $masq_user)), '%config-perm' => 'use the site in maintenance mode', '@site-maintenance' => url('admin/settings/site-maintenance'))));
686
  }
687
  else {
688
    $form_state['values']['masquerade_user_field'] = $name;
689
  }
690
}
691

    
692
/**
693
 * Masquerade block form submission.
694
 */
695
function masquerade_block_1_submit($form, &$form_state) {
696
  //unset($form);
697
  $masq_user = _masquerade_user_load($form_state['values']['masquerade_user_field']);
698
  if (!masquerade_switch_user($masq_user->uid)) {
699
    drupal_access_denied();
700
  }
701
  else {
702
    drupal_goto($_SERVER['HTTP_REFERER']);
703
  }
704
}
705

    
706
/**
707
 * Returns JS array for Masquerade autocomplete fields.
708
 */
709
function masquerade_autocomplete($string) {
710
  $matches = array();
711
  // Anonymous user goes first to be visible for user.
712
  $anonymous = variable_get('anonymous', t('Anonymous'));
713
  if (stripos($anonymous, $string) === 0) {
714
    $matches[$anonymous] = $anonymous;
715
  }
716
  // Other suggestions.
717
  $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER(:string)", 0, 10, array(
718
    ':string' => $string . '%',
719
  ));
720
  foreach ($result as $user) {
721
    $matches[$user->name] = check_plain($user->name);
722
  }
723
  if (module_exists('devel')) {
724
    $GLOBALS['devel_shutdown'] = FALSE;
725
  }
726
  drupal_json_output($matches);
727
}
728

    
729
/**
730
 * Returns JS array for Masquerade autocomplete fields.
731
 *
732
 * Supports multiple entries separated by a comma.
733
 *
734
 * @param $string
735
 *   The string of autocmplete value submitted by the user.
736
 * @param $add_anonymous
737
 *   Flag to include Anonymous user into result.
738
 */
739
function masquerade_autocomplete_multiple($string, $add_anonymous = TRUE) {
740
  $matches = array();
741
  // The user enters a comma-separated list of users. We only autocomplete the last user.
742
  $users_typed = drupal_explode_tags($string);
743
  // Fetch last string.
744
  $last_string = drupal_strtolower(array_pop($users_typed));
745
  if ($last_string) {
746
    $prefix = count($users_typed) ? implode(', ', $users_typed) . ', ' : '';
747
    if ($add_anonymous) {
748
      // Anonymous user goes first to be visible for user.
749
      $anonymous = variable_get('anonymous', t('Anonymous'));
750
      if (stripos($anonymous, $last_string) === 0) {
751
        $matches[$prefix . $anonymous] = $anonymous;
752
      }
753
    }
754
    // Other suggestions.
755
    $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE :string", 0, 10, array(
756
      ':string' => $last_string . '%',
757
    ));
758
    foreach ($result as $user) {
759
      $matches[$prefix . $user->name] = check_plain($user->name);
760
    }
761

    
762
    // Remove existing tags.
763
    $matches = array_diff($matches, $users_typed);
764

    
765
    // @todo Check compatibility for D7.
766
    if (module_exists('alt_login')) {
767
      $result = db_query_range("SELECT u.alt_login AS alt_login FROM {alt_login} u WHERE LOWER(u.alt_login) LIKE LOWER(:string)", 0, 10, array(
768
        ':string' => $last_string . '%',
769
      ));
770
      foreach ($result as $user) {
771
        $matches[$user->alt_login] = check_plain($user->alt_login);
772
      }
773
    }
774
  }
775
  if (module_exists('devel')) {
776
    $GLOBALS['devel_shutdown'] = FALSE;
777
  }
778
  drupal_json_output($matches);
779
}
780

    
781
/**
782
 * Page callback to switch users.
783
 */
784
function masquerade_switch_user_page($uid) {
785
  if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'masquerade/switch/' . $uid) && masquerade_switch_user($uid)) {
786
    drupal_goto($_SERVER['HTTP_REFERER']);
787
  }
788
  else {
789
    drupal_access_denied();
790
  }
791
}
792

    
793
/**
794
 * Allows a user with the right permissions to become the selected user.
795
 *
796
 * @param $uid
797
 *   The user ID to switch to.
798
 *
799
 * @return
800
 *   TRUE if the user was sucessfully switched, or FALSE if there was an error.
801
 */
802
function masquerade_switch_user($uid) {
803
  global $user;
804
  if (!is_numeric($uid)) {
805
    drupal_set_message(t('A user id was not correctly passed to the switching function.'));
806
    watchdog('masquerade', 'The user id provided to switch users was not numeric.', NULL, WATCHDOG_ERROR);
807
    return drupal_goto($_SERVER['HTTP_REFERER']);
808
  }
809

    
810
  $new_user = user_load($uid);
811

    
812
  $roles = array_keys(array_filter(variable_get('masquerade_admin_roles', array())));
813
  $perm = $uid == 1 || array_intersect(array_keys($new_user->roles), $roles) ?
814
    'masquerade as admin' :
815
    'masquerade as user';
816

    
817
  // Check to see if we need admin permission.
818
  $results = db_query_range('SELECT 1 FROM {masquerade_users} WHERE uid_from = :uid_from AND uid_to = :uid_to', 0, 1, array(
819
    ':uid_from' => $user->uid,
820
    ':uid_to' => $new_user->uid,
821
  ));
822
  if (!user_access($perm) && !isset($_SESSION['masquerading']) && !$results->fetchField()) {
823
    watchdog('masquerade', 'This user requires administrative permissions to switch to the user %user.', array('%user' => $new_user->name), WATCHDOG_ERROR);
824
    return FALSE;
825
  }
826

    
827
  if ($user->uid == $uid || isset($user->masquerading)) {
828
    watchdog('masquerade', 'This user is already %user.', array('%user' => $new_user->name), WATCHDOG_ERROR);
829
    return FALSE;
830
  }
831

    
832
  if (variable_get('maintenance_mode', 0) && !user_access('access site in maintenance mode', $new_user)) {
833
    drupal_set_message(t('It is not possible to masquerade in off-line mode as %user does not have the %config-perm permission. Please <a href="@site-maintenance">set the site status</a> to "online" to masquerade as %user.', array('%user' => $new_user->name, '%config-perm' => 'use the site in maintenance mode', '@site-maintenance' => url('admin/settings/site-maintenance'))));
834
    return FALSE;
835
  }
836

    
837
  // Call logout hooks when switching from original user.
838
  module_invoke_all('user_logout', $user);
839
  drupal_session_regenerate();
840

    
841
  $query = db_insert('masquerade');
842
  $query->fields(array(
843
    'uid_from' => $user->uid,
844
    'uid_as' => $new_user->uid,
845
    'sid' => session_id(),
846
  ));
847
  $query->execute();
848
  // switch user
849

    
850
  watchdog('masquerade', 'User %user now masquerading as %masq_as.', array('%user' => $user->name, '%masq_as' => $new_user->name ? $new_user->name : variable_get('anonymous', t('Anonymous'))), WATCHDOG_INFO);
851
  drupal_set_message(t('You are now masquerading as !masq_as.', array('!masq_as' => theme('username', array('account' => $new_user)))));
852
  $user->masquerading = $new_user->uid;
853
  $user = $new_user;
854

    
855
  // Call all login hooks when switching to masquerading user.
856
  $edit = array(); // Passed by reference.
857
  user_module_invoke('login', $edit, $user);
858

    
859
  return TRUE;
860
}
861

    
862
/**
863
 * Allows a user who is currently masquerading to become a new user.
864
 */
865
function masquerade_switch_back_page() {
866
  if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'masquerade/unswitch')) {
867
    global $user;
868
    $olduser = $user;
869
    masquerade_switch_back();
870
    drupal_set_message(t('You are no longer masquerading as !masq_as and are now logged in as !user.', array('!user' => theme('username', array('account' => $user)), '!masq_as' => theme('username', array('account' => $olduser)))));
871
    drupal_goto($_SERVER['HTTP_REFERER']);
872
  }
873
  else {
874
    drupal_access_denied();
875
  }
876
}
877

    
878
/**
879
 * Function for a masquerading user to switch back to the previous user.
880
 */
881
function masquerade_switch_back() {
882
  // switch user
883
  global $user;
884
  cache_clear_all($user->uid, 'cache_menu', TRUE);
885
  $uid = db_query("SELECT m.uid_from FROM {masquerade} m WHERE m.sid = :sid AND m.uid_as = :uid_as ", array(
886
    ':sid' => session_id(),
887
    ':uid_as' => $user->uid,
888
  ))->fetchField();
889
  // erase record
890
  db_delete('masquerade')
891
    ->condition('sid', session_id())
892
    ->condition('uid_as', $user->uid)
893
    ->execute();
894

    
895
  $oldname = ($user->uid == 0 ? variable_get('anonymous', t('Anonymous')) : $user->name);
896

    
897
  // Call logout hooks when switching from masquerading user.
898
  module_invoke_all('user_logout', $user);
899
  drupal_session_regenerate();
900

    
901
  $user = user_load($uid);
902

    
903
  // Call all login hooks when switching back to original user.
904
  $edit = array(); // Passed by reference.
905
  user_module_invoke('login', $edit, $user);
906

    
907
  watchdog('masquerade', 'User %user no longer masquerading as %masq_as.', array('%user' => $user->name, '%masq_as' => $oldname), WATCHDOG_INFO);
908
}