Projet

Général

Profil

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

root / drupal7 / sites / all / modules / masquerade / masquerade.module @ 87dbc3bf

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 any user' => array(
32
      'title' => t('Masquerade as any user'),
33
      'description' => t('Masquerade as any user.'),
34
      'restrict access' => TRUE,
35
    ),
36
    'masquerade as admin' => array(
37
      'title' => t('Masquerade as admin'),
38
      'description' => t('Masquerade as the site admin (UID 1).'),
39
      'restrict access' => TRUE,
40
    ),
41
    'administer masquerade' => array(
42
      'title' => t('Administer Masquerade'),
43
      'description' => t('Perform administration tasks and configure the Masquerade module.'),
44
      'restrict access' => TRUE,
45
    ),
46
  );
47
}
48

    
49
/**
50
 * Implements hook_init().
51
 */
52
function masquerade_init() {
53
  global $user;
54

    
55
  // Try to load masqing uid from masquerade table.
56
  $uid = db_query("SELECT uid_from FROM {masquerade} WHERE sid = :sid AND uid_as = :uid_as", array(
57
    ':sid' => session_id(),
58
    ':uid_as' => $user->uid,
59
  ))->fetchField();
60

    
61
  // We are using identical operator (===) instead of equal (==) because if
62
  // $uid === 0 we want to store the session variable. If there's no record in
63
  // masquerade table we clear the session variable.
64
  if ($uid === FALSE) {
65
    if (isset($_SESSION)) {
66
      unset($_SESSION['masquerading']);
67
    }
68
  }
69
  else {
70
    $_SESSION['masquerading'] = $uid;
71
  }
72
}
73

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

    
85
  $query = db_delete('masquerade');
86
  $query->condition('sid', $subquery, 'NOT IN');
87
  $query->execute();
88
}
89

    
90
/**
91
 * Implements hook_menu().
92
 */
93
function masquerade_menu() {
94
  $items = array();
95

    
96
  $default_test_user = _masquerade_user_load(variable_get('masquerade_test_user', ''));
97
  if ($default_test_user && ($default_test_user->uid || $default_test_user->name == variable_get('anonymous', t('Anonymous')))) {
98
    $items['masquerade/switch/' . $default_test_user->uid] = array(
99
      'title' => 'Masquerade as @testuser',
100
      'title arguments' => array('@testuser' => $default_test_user->name),
101
      'page callback' => 'masquerade_switch_user_page',
102
      'page arguments' => array(2),
103
      'access callback' => 'masquerade_menu_access',
104
      'access arguments' => array('switch'),
105
      'type' => MENU_NORMAL_ITEM,
106
    );
107
  }
108

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

    
155
  return $items;
156
}
157

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

    
176
/**
177
 * Implements hook_translated_menu_link_alter().
178
 *
179
 * Dynamically add the CSRF protection token to the Masquerade menu items.
180
 */
181
function masquerade_translated_menu_link_alter(&$item, $map) {
182
  if (isset($item['page_callback'])) {
183
    if ($item['page_callback'] == 'masquerade_switch_user_page' && isset($map[2])) {
184
      $item['localized_options']['query']['token'] = drupal_get_token('masquerade/switch/' . $map[2]);
185
    }
186
    elseif ($item['page_callback'] == 'masquerade_switch_back_page') {
187
      $item['localized_options']['query']['token'] = drupal_get_token('masquerade/unswitch');
188
    }
189
  }
190
}
191

    
192
/**
193
 * Implements hook_user_operations().
194
 */
195
function masquerade_user_operations() {
196
  return array(
197
    'masquerade' => array(
198
      'label' => t('Masquerade as user'),
199
      'callback' => 'masquerade_user_operations_masquerade',
200
    ),
201
  );
202
}
203

    
204
/**
205
 * Callback for user operation.
206
 */
207
function masquerade_user_operations_masquerade(array $accounts) {
208
  // Only process the first account since switching to multiple makes no sense.
209
  if (($uid = current($accounts)) && masquerade_menu_access('switch', $uid)) {
210
    masquerade_switch_user($uid);
211
  }
212
}
213

    
214
/**
215
 * Determine if the current user has permission to switch users.
216
 *
217
 * @param string $type
218
 *   Either 'switch', 'unswitch', 'user', or 'autocomplete'.
219
 *
220
 * @param object $uid
221
 *   An optional parameter indicating a specific uid to switch to.
222
 *   Otherwise, return if the user can switch to any user account.
223
 *
224
 * @return
225
 *   TRUE, if the user can perform the requested action, FALSE otherwise.
226
 */
227

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

    
258
/**
259
 * Admin settings form.
260
 */
261
function masquerade_admin_settings() {
262
  // create a list of roles; all selected roles are considered administrative.
263
  $roles = user_roles();
264
  $form['masquerade_admin_roles'] = array(
265
    '#type' => 'checkboxes',
266
    '#title' => t('Roles that are considered "administrators" for masquerading'),
267
    '#options' => $roles,
268
    '#default_value' => variable_get('masquerade_admin_roles', array()),
269
  );
270

    
271
  $test_name = _masquerade_user_load(variable_get('masquerade_test_user', ''));
272

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

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

    
299
  $form = system_settings_form($form);
300
  $form['#validate'][] = 'masquerade_admin_settings_validate';
301
  $form['#submit'][] = 'masquerade_admin_settings_submit';
302

    
303
  return $form;
304
}
305

    
306
function masquerade_admin_settings_validate($form, &$form_state) {
307
  if (!empty($form_state['values']['masquerade_test_user'])) {
308
    $test_user = _masquerade_user_load($form_state['values']['masquerade_test_user']);
309
    if (!$test_user) {
310
      form_set_error('masquerade_test_user', t('%user does not exist. Please enter a valid username.', array('%user' => $form_state['values']['masquerade_test_user'])));
311
    }
312
  }
313
  // Needs to rebuild menu in masquerade_admin_settings_submit().
314
  $form_state['masquerade_rebuild_menu'] = (variable_get('masquerade_test_user', '') != $form_state['values']['masquerade_test_user']);
315

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

    
332
function masquerade_admin_settings_submit($form, &$form_state) {
333
  // Rebuild the menu system so the menu "Quick Switch" user is updated.
334
  if ($form_state['masquerade_rebuild_menu']) {
335
    menu_rebuild();
336
  }
337
}
338

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

    
363
/**
364
 * Implements hook_user_logout().
365
 */
366
function masquerade_user_logout($account) {
367
  if (!empty($account->masquerading)) {
368
    global $user;
369
    cache_clear_all($user->uid, 'cache_menu', TRUE);
370
    $real_user = user_load($user->masquerading);
371
    watchdog('masquerade', "User %user no longer masquerading as %masq_as.", array('%user' => $real_user->name, '%masq_as' => $user->name), WATCHDOG_INFO);
372

    
373
    $query = db_delete('masquerade');
374
    $query->condition('sid', session_id());
375
    $query->condition('uid_as', $account->uid);
376
    $query->execute();
377
  }
378
}
379

    
380
/**
381
 * Implements hook_field_extra_fields().
382
 */
383
function masquerade_field_extra_fields() {
384
  $return['user']['user']  = array(
385
    'form' => array(
386
      'masquerade' => array(
387
        'label' => t('Masquerade'),
388
        'description' => t('User masquerade settings.'),
389
        'weight' => 50,
390
      ),
391
    ),
392
    'display' => array(
393
      'masquerade' => array(
394
        'label' => t('Masquerade'),
395
        'description' => t('Masquerade as user link.'),
396
        'weight' => 50,
397
      ),
398
    ),
399
  );
400

    
401
  return $return;
402
}
403

    
404
/**
405
 * Implements hook_user_view().
406
 */
407
function masquerade_user_view($account, $view_mode, $langcode) {
408
  // check if user qualifies as admin
409
  $roles = array_keys(array_filter(variable_get('masquerade_admin_roles', array())));
410
  $perm = $account->uid == 1 || array_intersect(array_keys((array)$account->roles), $roles) ?
411
    'masquerade as admin' :
412
    'masquerade as user';
413

    
414
  global $user;
415

    
416
  // Query allowed uids so the "masquerade as <user>" link can be shown or
417
  // hidden.
418
  $allowed_uids = db_query("SELECT uid_to FROM {masquerade_users} WHERE uid_from = :uid_from", array(':uid_from' => $user->uid))
419
    ->fetchCol();
420
  $can_masquerade_as_user = in_array($account->uid, $allowed_uids) || user_access('masquerade as any user');
421

    
422
  if (user_access($perm) && empty($account->masquerading) && $user->uid != $account->uid && $can_masquerade_as_user) {
423
    $account->content['masquerade'] = array(
424
      '#markup' => l(t('Masquerade as !user', array('!user' => $account->name)),
425
        'masquerade/switch/' . $account->uid,
426
        array('query' => array(
427
          'token' => drupal_get_token('masquerade/switch/' . $account->uid)),
428
          'destination' => $_GET['q'],
429
          'attributes' => array('class' => array('masquerade-switch')),
430
        )),
431
      '#weight' => 10,
432
    );
433
  }
434
}
435

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

    
474
/**
475
 * Validates user account form.
476
 */
477
function masquerade_user_validate(&$form, $form_state) {
478
  if (isset($form_state['values']['masquerade_users'])) {
479
    $users = drupal_explode_tags($form_state['values']['masquerade_users']);
480
    foreach ($users as $username) {
481
      if (!_masquerade_user_load($username)) {
482
        form_set_error('masquerade_users', t('%user is not a valid user name.', array('%user' => $username)));
483
      }
484
    }
485
  }
486
}
487

    
488
/**
489
 * Submit handler for masquerade users form element.
490
 */
491
function masquerade_user_submit(&$form, $form_state) {
492
  global $_masquerade_old_session_id;
493
  $_masquerade_old_session_id = session_id();
494
}
495

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

    
519
    // Update user session...
520
    // @TODO check other way of session API.
521
    if (!empty($_masquerade_old_session_id)) {
522
      $query = db_update('masquerade');
523
      $query->fields(array(
524
        'sid' => session_id(),
525
      ));
526
      $query->condition('sid', $_masquerade_old_session_id);
527
      $query->execute();
528
    }
529
  }
530
}
531

    
532
/**
533
 * Implements hook_user_delete().
534
 */
535
function masquerade_user_delete($account) {
536
  // Cleanup tables.
537
  $query = db_delete('masquerade_users');
538
  $conditions = db_or();
539
  $conditions->condition('uid_from', $account->uid);
540
  $conditions->condition('uid_to', $account->uid);
541
  $query->condition($conditions);
542
  $query->execute();
543
  // Cleanup variables.
544
  $switches = variable_get('masquerade_quick_switches', array());
545
  $switches_new = array_diff($switches, array($account->uid));
546
  if ($switches != $switches_new) {
547
    variable_set('masquerade_quick_switches', $switches_new);
548
    // @TODO Implement block cache cleaning.
549
    menu_rebuild();
550
  }
551
}
552

    
553
/**
554
 * Implements hook_block_info().
555
 */
556
function masquerade_block_info() {
557
  $blocks = array();
558
  $blocks['masquerade'] = array(
559
    'info' => t('Masquerade'),
560
    'cache' => DRUPAL_NO_CACHE,
561
  );
562
  return $blocks;
563
}
564

    
565
/**
566
 * Implements hook_block_view().
567
 */
568
function masquerade_block_view($delta = '') {
569
  $block = array();
570
  switch ($delta) {
571
    case 'masquerade':
572
      if (isset($_SESSION['masquerading']) || (user_access('masquerade as user') || user_access('masquerade as admin'))) {
573
        $block['subject'] = t('Masquerade');
574
        $block['content'] = drupal_get_form('masquerade_block_1');
575
      }
576
      break;
577
  }
578
  return $block;
579
}
580

    
581
/**
582
 * Masquerade block form.
583
 */
584
function masquerade_block_1() {
585
  global $user;
586
  $quick_switch_links = array();
587
  $markup_value = '';
588
  if (isset($_SESSION['masquerading'])) {
589
    $quick_switch_links[] = l(t('Switch back'), 'masquerade/unswitch', array('query' => array('token' => drupal_get_token('masquerade/unswitch'))));
590
    if ($user->uid > 0) {
591
      $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));
592
    }
593
    else {
594
      $markup_value = t('You are masquerading as %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous'))));
595
    }
596
  }
597
  else {
598
    $quick_switches = variable_get('masquerade_quick_switches', array());
599

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

    
604
    foreach ($masquerade_switches as $switch_user) {
605
      if (!isset($_SESSION['user']->uid) || $switch_user != $_SESSION['user']->uid) {
606
        $account = user_load($switch_user);
607
        if (isset($account->uid)) {
608
          $switch_link = 'masquerade/switch/' . $account->uid;
609
          if ($account->uid) {
610
            $quick_switch_links[] = l($account->name, $switch_link, array('query' => array('token' => drupal_get_token($switch_link))));
611
          }
612
          if ($switch_user == 0) {
613
            $account->name = variable_get('anonymous', t('Anonymous'));
614
            $quick_switch_links[] = l($account->name, $switch_link, array('query' => array('token' => drupal_get_token($switch_link))));
615
          }
616
        }
617
      }
618
    }
619

    
620
    if (masquerade_menu_access('autocomplete')) {
621
      $markup_value .= t('Enter the username to masquerade as.');
622
      $form['masquerade_user_field'] = array(
623
        '#prefix' => '<div class="container-inline">',
624
        '#type' => 'textfield',
625
        '#size' => '18',
626
        '#default_value' => '',
627
        '#autocomplete_path' => 'masquerade/autocomplete',
628
        '#required' => TRUE,
629
      );
630
      $form['submit'] = array(
631
        '#type' => 'submit',
632
        '#value' => t('Go'),
633
        '#suffix' => '</div>',
634
      );
635
    }
636

    
637
  }
638
  if ($quick_switch_links) {
639
    $markup_value .= '<div id="quick_switch_links">' . t('Quick switches:') . theme('item_list', array('items' => $quick_switch_links)) . '</div>';
640
  }
641
  $form['masquerade_desc'] = array(
642
    '#prefix' => '<div class="form-item"><div class="description">',
643
    '#markup' => $markup_value,
644
    '#suffix' => '</div></div>',
645
  );
646
  return $form;
647
}
648

    
649
/**
650
 * Masquerade block form validation.
651
 */
652
function masquerade_block_1_validate($form, &$form_state) {
653
  global $user;
654
  //unset($form);
655
  $name = $form_state['values']['masquerade_user_field'];
656
  $allowed = FALSE;
657
  $to_uid = db_select('users', 'u')
658
    ->fields('u', array('uid'))
659
    ->condition('u.name', $name, '=')
660
    ->execute()
661
    ->fetchField();
662
  if ($to_uid !== FALSE) {
663
    $allowed = user_access('masquerade as any user') ||
664
               db_select('masquerade_users', 'm')
665
                  ->fields('m', array('uid_to'))
666
                  ->condition('m.uid_to', $to_uid, '=')
667
                  ->condition('m.uid_from', $user->uid, '=')
668
                  ->execute()
669
                  ->fetchField();
670
  }
671
  if (isset($_SESSION['masquerading'])) {
672
    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')))))));
673
  }
674
  if ($allowed === FALSE) {
675
    form_set_error('masquerade_user_field', t('You are not allowed to masquerade as the selected user.'));
676
  }
677

    
678
  if ($name != variable_get('anonymous', t('Anonymous')) && module_exists('alt_login')) {
679
    $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(
680
      ':alt_login' => $name
681
    ))->fetchObject();
682
    if (isset($alt_login->name)) {
683
      $name = $alt_login->name;
684
    }
685
  }
686
  $masq_user = _masquerade_user_load($name);
687
  if (!$masq_user) {
688
    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'])));
689
  }
690
  elseif ($masq_user->uid == $user->uid) {
691
    form_set_error('masquerade_user_field', t('You cannot masquerade as yourself. Please choose a different user to masquerade as.'));
692
  }
693
  elseif (variable_get('maintenance_mode', 0) && !user_access('access site in maintenance mode', $masq_user)) {
694
    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'))));
695
  }
696
  else {
697
    $form_state['values']['masquerade_user_field'] = $name;
698
  }
699
}
700

    
701
/**
702
 * Masquerade block form submission.
703
 */
704
function masquerade_block_1_submit($form, &$form_state) {
705
  //unset($form);
706
  $masq_user = _masquerade_user_load($form_state['values']['masquerade_user_field']);
707
  if (!masquerade_switch_user($masq_user->uid)) {
708
    drupal_access_denied();
709
  }
710
  else {
711
    drupal_goto($_SERVER['HTTP_REFERER']);
712
  }
713
}
714

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

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

    
771
    // Remove existing tags.
772
    $matches = array_diff($matches, $users_typed);
773

    
774
    // @todo Check compatibility for D7.
775
    if (module_exists('alt_login')) {
776
      $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(
777
        ':string' => $last_string . '%',
778
      ));
779
      foreach ($result as $user) {
780
        $matches[$user->alt_login] = check_plain($user->alt_login);
781
      }
782
    }
783
  }
784
  if (module_exists('devel')) {
785
    $GLOBALS['devel_shutdown'] = FALSE;
786
  }
787
  drupal_json_output($matches);
788
}
789

    
790
/**
791
 * Page callback to switch users.
792
 */
793
function masquerade_switch_user_page($uid) {
794
  if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'masquerade/switch/' . $uid) && masquerade_switch_user($uid)) {
795
    drupal_goto($_SERVER['HTTP_REFERER']);
796
  }
797
  else {
798
    drupal_access_denied();
799
  }
800
}
801

    
802
/**
803
 * Allows a user with the right permissions to become the selected user.
804
 *
805
 * @param $uid
806
 *   The user ID to switch to.
807
 *
808
 * @return
809
 *   TRUE if the user was sucessfully switched, or FALSE if there was an error.
810
 */
811
function masquerade_switch_user($uid) {
812
  global $user;
813
  if (!is_numeric($uid)) {
814
    drupal_set_message(t('A user id was not correctly passed to the switching function.'));
815
    watchdog('masquerade', 'The user id provided to switch users was not numeric.', NULL, WATCHDOG_ERROR);
816
    return drupal_goto($_SERVER['HTTP_REFERER']);
817
  }
818

    
819
  $new_user = user_load($uid);
820

    
821
  $roles = array_keys(array_filter(variable_get('masquerade_admin_roles', array())));
822
  $perm = $uid == 1 || array_intersect(array_keys($new_user->roles), $roles) ?
823
    'masquerade as admin' :
824
    'masquerade as user';
825

    
826
  // Check to see if we need admin permission.
827
  $results = db_query_range('SELECT 1 FROM {masquerade_users} WHERE uid_from = :uid_from AND uid_to = :uid_to', 0, 1, array(
828
    ':uid_from' => $user->uid,
829
    ':uid_to' => $new_user->uid,
830
  ));
831
  if (!user_access($perm) && !isset($_SESSION['masquerading']) && !$results->fetchField()) {
832
    watchdog('masquerade', 'This user requires administrative permissions to switch to the user %user.', array('%user' => $new_user->name), WATCHDOG_ERROR);
833
    return FALSE;
834
  }
835

    
836
  if ($user->uid == $uid || isset($user->masquerading)) {
837
    watchdog('masquerade', 'This user is already %user.', array('%user' => $new_user->name), WATCHDOG_ERROR);
838
    return FALSE;
839
  }
840

    
841
  if (variable_get('maintenance_mode', 0) && !user_access('access site in maintenance mode', $new_user)) {
842
    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'))));
843
    return FALSE;
844
  }
845

    
846
  // Call logout hooks when switching from original user.
847
  module_invoke_all('user_logout', $user);
848
  drupal_session_regenerate();
849

    
850
  $query = db_insert('masquerade');
851
  $query->fields(array(
852
    'uid_from' => $user->uid,
853
    'uid_as' => $new_user->uid,
854
    'sid' => session_id(),
855
  ));
856
  $query->execute();
857
  // switch user
858

    
859
  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);
860
  drupal_set_message(t('You are now masquerading as !masq_as.', array('!masq_as' => theme('username', array('account' => $new_user)))));
861
  $user->masquerading = $new_user->uid;
862
  $user = $new_user;
863

    
864
  // Call all login hooks when switching to masquerading user.
865
  $edit = array(); // Passed by reference.
866
  user_module_invoke('login', $edit, $user);
867

    
868
  return TRUE;
869
}
870

    
871
/**
872
 * Allows a user who is currently masquerading to become a new user.
873
 */
874
function masquerade_switch_back_page() {
875
  if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'masquerade/unswitch')) {
876
    global $user;
877
    $olduser = $user;
878
    masquerade_switch_back();
879
    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)))));
880
    drupal_goto($_SERVER['HTTP_REFERER']);
881
  }
882
  else {
883
    drupal_access_denied();
884
  }
885
}
886

    
887
/**
888
 * Function for a masquerading user to switch back to the previous user.
889
 */
890
function masquerade_switch_back() {
891
  // switch user
892
  global $user;
893
  cache_clear_all($user->uid, 'cache_menu', TRUE);
894
  $uid = db_query("SELECT m.uid_from FROM {masquerade} m WHERE m.sid = :sid AND m.uid_as = :uid_as ", array(
895
    ':sid' => session_id(),
896
    ':uid_as' => $user->uid,
897
  ))->fetchField();
898
  // erase record
899
  db_delete('masquerade')
900
    ->condition('sid', session_id())
901
    ->condition('uid_as', $user->uid)
902
    ->execute();
903

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

    
906
  // Call logout hooks when switching from masquerading user.
907
  module_invoke_all('user_logout', $user);
908
  drupal_session_regenerate();
909

    
910
  $user = user_load($uid);
911

    
912
  // Call all login hooks when switching back to original user.
913
  $edit = array(); // Passed by reference.
914
  user_module_invoke('login', $edit, $user);
915

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