1<?php 2 3/** 4 * @file 5 * Install, update and uninstall functions for the user module. 6 */ 7 8/** 9 * Implements hook_schema(). 10 */ 11function user_schema() { 12 $schema['authmap'] = array( 13 'description' => 'Stores distributed authentication mapping.', 14 'fields' => array( 15 'aid' => array( 16 'description' => 'Primary Key: Unique authmap ID.', 17 'type' => 'serial', 18 'unsigned' => TRUE, 19 'not null' => TRUE, 20 ), 21 'uid' => array( 22 'type' => 'int', 23 'not null' => TRUE, 24 'default' => 0, 25 'description' => "User's {users}.uid.", 26 ), 27 'authname' => array( 28 'type' => 'varchar', 29 'length' => 128, 30 'not null' => TRUE, 31 'default' => '', 32 'description' => 'Unique authentication name.', 33 ), 34 'module' => array( 35 'type' => 'varchar', 36 'length' => 128, 37 'not null' => TRUE, 38 'default' => '', 39 'description' => 'Module which is controlling the authentication.', 40 ), 41 ), 42 'unique keys' => array( 43 'authname' => array('authname'), 44 ), 45 'primary key' => array('aid'), 46 'foreign keys' => array( 47 'user' => array( 48 'table' => 'users', 49 'columns' => array('uid' => 'uid'), 50 ), 51 ), 52 'indexes' => array( 53 'uid_module' => array('uid', 'module'), 54 ), 55 ); 56 57 $schema['role_permission'] = array( 58 'description' => 'Stores the permissions assigned to user roles.', 59 'fields' => array( 60 'rid' => array( 61 'type' => 'int', 62 'unsigned' => TRUE, 63 'not null' => TRUE, 64 'description' => 'Foreign Key: {role}.rid.', 65 ), 66 'permission' => array( 67 'type' => 'varchar', 68 'length' => 128, 69 'not null' => TRUE, 70 'default' => '', 71 'description' => 'A single permission granted to the role identified by rid.', 72 ), 73 'module' => array( 74 'type' => 'varchar', 75 'length' => 255, 76 'not null' => TRUE, 77 'default' => '', 78 'description' => "The module declaring the permission.", 79 ), 80 ), 81 'primary key' => array('rid', 'permission'), 82 'indexes' => array( 83 'permission' => array('permission'), 84 ), 85 'foreign keys' => array( 86 'role' => array( 87 'table' => 'role', 88 'columns' => array('rid' => 'rid'), 89 ), 90 ), 91 ); 92 93 $schema['role'] = array( 94 'description' => 'Stores user roles.', 95 'fields' => array( 96 'rid' => array( 97 'type' => 'serial', 98 'unsigned' => TRUE, 99 'not null' => TRUE, 100 'description' => 'Primary Key: Unique role ID.', 101 ), 102 'name' => array( 103 'type' => 'varchar', 104 'length' => 64, 105 'not null' => TRUE, 106 'default' => '', 107 'description' => 'Unique role name.', 108 'translatable' => TRUE, 109 ), 110 'weight' => array( 111 'type' => 'int', 112 'not null' => TRUE, 113 'default' => 0, 114 'description' => 'The weight of this role in listings and the user interface.', 115 ), 116 ), 117 'unique keys' => array( 118 'name' => array('name'), 119 ), 120 'primary key' => array('rid'), 121 'indexes' => array( 122 'name_weight' => array('name', 'weight'), 123 ), 124 ); 125 126 // The table name here is plural, despite Drupal table naming standards, 127 // because "user" is a reserved word in many databases. 128 $schema['users'] = array( 129 'description' => 'Stores user data.', 130 'fields' => array( 131 'uid' => array( 132 'type' => 'int', 133 'unsigned' => TRUE, 134 'not null' => TRUE, 135 'description' => 'Primary Key: Unique user ID.', 136 'default' => 0, 137 ), 138 'name' => array( 139 'type' => 'varchar', 140 'length' => 60, 141 'not null' => TRUE, 142 'default' => '', 143 'description' => 'Unique user name.', 144 ), 145 'pass' => array( 146 'type' => 'varchar', 147 'length' => 128, 148 'not null' => TRUE, 149 'default' => '', 150 'description' => "User's password (hashed).", 151 ), 152 'mail' => array( 153 'type' => 'varchar', 154 'length' => 254, 155 'not null' => FALSE, 156 'default' => '', 157 'description' => "User's e-mail address.", 158 ), 159 'theme' => array( 160 'type' => 'varchar', 161 'length' => 255, 162 'not null' => TRUE, 163 'default' => '', 164 'description' => "User's default theme.", 165 ), 166 'signature' => array( 167 'type' => 'varchar', 168 'length' => 255, 169 'not null' => TRUE, 170 'default' => '', 171 'description' => "User's signature.", 172 ), 173 'signature_format' => array( 174 'type' => 'varchar', 175 'length' => 255, 176 'not null' => FALSE, 177 'description' => 'The {filter_format}.format of the signature.', 178 ), 179 'created' => array( 180 'type' => 'int', 181 'not null' => TRUE, 182 'default' => 0, 183 'description' => 'Timestamp for when user was created.', 184 ), 185 'access' => array( 186 'type' => 'int', 187 'not null' => TRUE, 188 'default' => 0, 189 'description' => 'Timestamp for previous time user accessed the site.', 190 ), 191 'login' => array( 192 'type' => 'int', 193 'not null' => TRUE, 194 'default' => 0, 195 'description' => "Timestamp for user's last login.", 196 ), 197 'status' => array( 198 'type' => 'int', 199 'not null' => TRUE, 200 'default' => 0, 201 'size' => 'tiny', 202 'description' => 'Whether the user is active(1) or blocked(0).', 203 ), 204 'timezone' => array( 205 'type' => 'varchar', 206 'length' => 32, 207 'not null' => FALSE, 208 'description' => "User's time zone.", 209 ), 210 'language' => array( 211 'type' => 'varchar', 212 'length' => 12, 213 'not null' => TRUE, 214 'default' => '', 215 'description' => "User's default language.", 216 ), 217 'picture' => array( 218 'type' => 'int', 219 'not null' => TRUE, 220 'default' => 0, 221 'description' => "Foreign key: {file_managed}.fid of user's picture.", 222 ), 223 'init' => array( 224 'type' => 'varchar', 225 'length' => 254, 226 'not null' => FALSE, 227 'default' => '', 228 'description' => 'E-mail address used for initial account creation.', 229 ), 230 'data' => array( 231 'type' => 'blob', 232 'not null' => FALSE, 233 'size' => 'big', 234 'serialize' => TRUE, 235 'description' => 'A serialized array of name value pairs that are related to the user. Any form values posted during user edit are stored and are loaded into the $user object during user_load(). Use of this field is discouraged and it will likely disappear in a future version of Drupal.', 236 ), 237 ), 238 'indexes' => array( 239 'access' => array('access'), 240 'created' => array('created'), 241 'mail' => array('mail'), 242 'picture' => array('picture'), 243 ), 244 'unique keys' => array( 245 'name' => array('name'), 246 ), 247 'primary key' => array('uid'), 248 'foreign keys' => array( 249 'signature_format' => array( 250 'table' => 'filter_format', 251 'columns' => array('signature_format' => 'format'), 252 ), 253 ), 254 ); 255 256 $schema['users_roles'] = array( 257 'description' => 'Maps users to roles.', 258 'fields' => array( 259 'uid' => array( 260 'type' => 'int', 261 'unsigned' => TRUE, 262 'not null' => TRUE, 263 'default' => 0, 264 'description' => 'Primary Key: {users}.uid for user.', 265 ), 266 'rid' => array( 267 'type' => 'int', 268 'unsigned' => TRUE, 269 'not null' => TRUE, 270 'default' => 0, 271 'description' => 'Primary Key: {role}.rid for role.', 272 ), 273 ), 274 'primary key' => array('uid', 'rid'), 275 'indexes' => array( 276 'rid' => array('rid'), 277 ), 278 'foreign keys' => array( 279 'user' => array( 280 'table' => 'users', 281 'columns' => array('uid' => 'uid'), 282 ), 283 'role' => array( 284 'table' => 'role', 285 'columns' => array('rid' => 'rid'), 286 ), 287 ), 288 ); 289 290 return $schema; 291} 292 293/** 294 * Implements hook_install(). 295 */ 296function user_install() { 297 // Insert a row for the anonymous user. 298 db_insert('users') 299 ->fields(array( 300 'uid' => 0, 301 'name' => '', 302 'mail' => '', 303 )) 304 ->execute(); 305 306 // We need some placeholders here as name and mail are uniques and data is 307 // presumed to be a serialized array. This will be changed by the settings 308 // form in the installer. 309 db_insert('users') 310 ->fields(array( 311 'uid' => 1, 312 'name' => 'placeholder-for-uid-1', 313 'mail' => 'placeholder-for-uid-1', 314 'created' => REQUEST_TIME, 315 'status' => 1, 316 'data' => NULL, 317 )) 318 ->execute(); 319 320 // Built-in roles. 321 $rid_anonymous = db_insert('role') 322 ->fields(array('name' => 'anonymous user', 'weight' => 0)) 323 ->execute(); 324 $rid_authenticated = db_insert('role') 325 ->fields(array('name' => 'authenticated user', 'weight' => 1)) 326 ->execute(); 327 328 // Sanity check to ensure the anonymous and authenticated role IDs are the 329 // same as the drupal defined constants. In certain situations, this will 330 // not be true. 331 if ($rid_anonymous != DRUPAL_ANONYMOUS_RID) { 332 db_update('role') 333 ->fields(array('rid' => DRUPAL_ANONYMOUS_RID)) 334 ->condition('rid', $rid_anonymous) 335 ->execute(); 336 } 337 if ($rid_authenticated != DRUPAL_AUTHENTICATED_RID) { 338 db_update('role') 339 ->fields(array('rid' => DRUPAL_AUTHENTICATED_RID)) 340 ->condition('rid', $rid_authenticated) 341 ->execute(); 342 } 343} 344 345/** 346 * Implements hook_update_dependencies(). 347 */ 348function user_update_dependencies() { 349 // user_update_7006() updates data in the {role_permission} table, so it must 350 // run after system_update_7007(), which populates that table. 351 $dependencies['user'][7006] = array( 352 'system' => 7007, 353 ); 354 355 // user_update_7010() needs to query the {filter_format} table to get a list 356 // of existing text formats, so it must run after filter_update_7000(), which 357 // creates that table. 358 $dependencies['user'][7010] = array( 359 'filter' => 7000, 360 ); 361 362 // user_update_7012() uses the file API and inserts records into the 363 // {file_managed} table, so it therefore must run after system_update_7061(), 364 // which inserts files with specific IDs into the table and therefore relies 365 // on the table being empty (otherwise it would accidentally overwrite 366 // existing records). 367 $dependencies['user'][7012] = array( 368 'system' => 7061, 369 ); 370 371 // user_update_7013() uses the file usage API, which relies on the 372 // {file_usage} table, so it must run after system_update_7059(), which 373 // creates that table. 374 $dependencies['user'][7013] = array( 375 'system' => 7059, 376 ); 377 378 return $dependencies; 379} 380 381/** 382 * Utility function: grant a set of permissions to a role during update. 383 * 384 * This function is valid for a database schema version 7000. 385 * 386 * @param $rid 387 * The role ID. 388 * @param $permissions 389 * An array of permissions names. 390 * @param $module 391 * The name of the module defining the permissions. 392 * @ingroup update_api 393 */ 394function _update_7000_user_role_grant_permissions($rid, array $permissions, $module) { 395 // Grant new permissions for the role. 396 foreach ($permissions as $name) { 397 db_merge('role_permission') 398 ->key(array( 399 'rid' => $rid, 400 'permission' => $name, 401 )) 402 ->fields(array( 403 'module' => $module, 404 )) 405 ->execute(); 406 } 407} 408 409/** 410 * @addtogroup updates-6.x-to-7.x 411 * @{ 412 */ 413 414/** 415 * Increase the length of the password field to accommodate better hashes. 416 * 417 * Also re-hashes all current passwords to improve security. This may be a 418 * lengthy process, and is performed batch-wise. 419 */ 420function user_update_7000(&$sandbox) { 421 $sandbox['#finished'] = 0; 422 // Lower than DRUPAL_HASH_COUNT to make the update run at a reasonable speed. 423 $hash_count_log2 = 11; 424 // Multi-part update. 425 if (!isset($sandbox['user_from'])) { 426 db_change_field('users', 'pass', 'pass', array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => '')); 427 $sandbox['user_from'] = 0; 428 $sandbox['user_count'] = db_query("SELECT COUNT(uid) FROM {users}")->fetchField(); 429 } 430 else { 431 require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc'); 432 // Hash again all current hashed passwords. 433 $has_rows = FALSE; 434 // Update this many per page load. 435 $count = 1000; 436 $result = db_query_range("SELECT uid, pass FROM {users} WHERE uid > 0 ORDER BY uid", $sandbox['user_from'], $count); 437 foreach ($result as $account) { 438 $has_rows = TRUE; 439 440 // If the $account->pass value is not a MD5 hash (a 32 character 441 // hexadecimal string) then skip it. 442 if (!preg_match('/^[0-9a-f]{32}$/', $account->pass)) { 443 continue; 444 } 445 446 $new_hash = user_hash_password($account->pass, $hash_count_log2); 447 if ($new_hash) { 448 // Indicate an updated password. 449 $new_hash = 'U' . $new_hash; 450 db_update('users') 451 ->fields(array('pass' => $new_hash)) 452 ->condition('uid', $account->uid) 453 ->execute(); 454 } 455 } 456 $sandbox['#finished'] = $sandbox['user_from']/$sandbox['user_count']; 457 $sandbox['user_from'] += $count; 458 if (!$has_rows) { 459 $sandbox['#finished'] = 1; 460 return t('User passwords rehashed to improve security'); 461 } 462 } 463} 464 465/** 466 * Remove the 'threshold', 'mode' and 'sort' columns from the {users} table. 467 * 468 * These fields were previously used to store per-user comment settings. 469 */ 470 471function user_update_7001() { 472 db_drop_field('users', 'threshold'); 473 db_drop_field('users', 'mode'); 474 db_drop_field('users', 'sort'); 475} 476 477/** 478 * Convert user time zones from time zone offsets to time zone names. 479 */ 480function user_update_7002(&$sandbox) { 481 $sandbox['#finished'] = 0; 482 483 // Multi-part update. 484 if (!isset($sandbox['user_from'])) { 485 db_change_field('users', 'timezone', 'timezone', array('type' => 'varchar', 'length' => 32, 'not null' => FALSE)); 486 $sandbox['user_from'] = 0; 487 $sandbox['user_count'] = db_query("SELECT COUNT(uid) FROM {users}")->fetchField(); 488 $sandbox['user_not_migrated'] = 0; 489 } 490 else { 491 $timezones = system_time_zones(); 492 // Update this many per page load. 493 $count = 10000; 494 $contributed_date_module = db_field_exists('users', 'timezone_name'); 495 $contributed_event_module = db_field_exists('users', 'timezone_id'); 496 497 $results = db_query_range("SELECT uid FROM {users} ORDER BY uid", $sandbox['user_from'], $count); 498 foreach ($results as $account) { 499 $timezone = NULL; 500 // If the contributed Date module has created a users.timezone_name 501 // column, use this data to set each user's time zone. 502 if ($contributed_date_module) { 503 $date_timezone = db_query("SELECT timezone_name FROM {users} WHERE uid = :uid", array(':uid' => $account->uid))->fetchField(); 504 if (isset($timezones[$date_timezone])) { 505 $timezone = $date_timezone; 506 } 507 } 508 // If the contributed Event module has stored user time zone information 509 // use that information to update the user accounts. 510 if (!$timezone && $contributed_event_module) { 511 try { 512 $event_timezone = db_query("SELECT t.name FROM {users} u LEFT JOIN {event_timezones} t ON u.timezone_id = t.timezone WHERE u.uid = :uid", array(':uid' => $account->uid))->fetchField(); 513 $event_timezone = str_replace(' ', '_', $event_timezone); 514 if (isset($timezones[$event_timezone])) { 515 $timezone = $event_timezone; 516 } 517 } 518 catch (PDOException $e) { 519 // Ignore error if event_timezones table does not exist or unexpected 520 // schema found. 521 } 522 } 523 if ($timezone) { 524 db_update('users') 525 ->fields(array('timezone' => $timezone)) 526 ->condition('uid', $account->uid) 527 ->execute(); 528 } 529 else { 530 $sandbox['user_not_migrated']++; 531 db_update('users') 532 ->fields(array('timezone' => NULL)) 533 ->condition('uid', $account->uid) 534 ->execute(); 535 } 536 $sandbox['user_from']++; 537 } 538 539 $sandbox['#finished'] = $sandbox['user_from'] / $sandbox['user_count']; 540 if ($sandbox['user_from'] == $sandbox['user_count']) { 541 if ($sandbox['user_not_migrated'] > 0) { 542 variable_set('empty_timezone_message', 1); 543 drupal_set_message(format_string('Some user time zones have been emptied and need to be set to the correct values. Use the new <a href="@config-url">time zone options</a> to choose whether to remind users at login to set the correct time zone.', array('@config-url' => url('admin/config/regional/settings'))), 'warning'); 544 } 545 return t('Migrated user time zones'); 546 } 547 } 548} 549 550/** 551 * Update user settings for cancelling user accounts. 552 * 553 * Prior to 7.x, users were not able to cancel their accounts. When 554 * administrators deleted an account, all contents were assigned to uid 0, 555 * which is the same as the 'user_cancel_reassign' method now. 556 */ 557function user_update_7003() { 558 // Set the default account cancellation method. 559 variable_set('user_cancel_method', 'user_cancel_reassign'); 560 // Re-assign notification setting. 561 if ($setting = variable_get('user_mail_status_deleted_notify', FALSE)) { 562 variable_set('user_mail_status_canceled_notify', $setting); 563 variable_del('user_mail_status_deleted_notify'); 564 } 565 // Re-assign "Account deleted" mail strings to "Account canceled" mail. 566 if ($setting = variable_get('user_mail_status_deleted_subject', FALSE)) { 567 variable_set('user_mail_status_canceled_subject', $setting); 568 variable_del('user_mail_status_deleted_subject'); 569 } 570 if ($setting = variable_get('user_mail_status_deleted_body', FALSE)) { 571 variable_set('user_mail_status_canceled_body', $setting); 572 variable_del('user_mail_status_deleted_body'); 573 } 574} 575 576/** 577 * Changes the users table to allow longer e-mail addresses. 578 */ 579function user_update_7005(&$sandbox) { 580 $mail_field = array( 581 'type' => 'varchar', 582 'length' => 254, 583 'not null' => FALSE, 584 'default' => '', 585 'description' => "User's e-mail address.", 586 ); 587 $init_field = array( 588 'type' => 'varchar', 589 'length' => 254, 590 'not null' => FALSE, 591 'default' => '', 592 'description' => 'E-mail address used for initial account creation.', 593 ); 594 db_drop_index('users', 'mail'); 595 db_change_field('users', 'mail', 'mail', $mail_field, array('indexes' => array('mail' => array('mail')))); 596 db_change_field('users', 'init', 'init', $init_field); 597} 598 599/** 600 * Add module data to {role_permission}. 601 */ 602function user_update_7006(&$sandbox) { 603 $module_field = array( 604 'type' => 'varchar', 605 'length' => 255, 606 'not null' => TRUE, 607 'default' => '', 608 'description' => "The module declaring the permission.", 609 ); 610 // Check that the field hasn't been updated in an aborted run of this 611 // update. 612 if (!db_field_exists('role_permission', 'module')) { 613 // Add a new field for the fid. 614 db_add_field('role_permission', 'module', $module_field); 615 } 616} 617 618/** 619 * Add a weight column to user roles. 620 */ 621function user_update_7007() { 622 db_add_field('role', 'weight', array('type' => 'int', 'not null' => TRUE, 'default' => 0)); 623 db_add_index('role', 'name_weight', array('name', 'weight')); 624} 625 626/** 627 * If 'user_register' variable was unset in Drupal 6, set it to be the same as 628 * the Drupal 6 default setting. 629 */ 630function user_update_7008() { 631 if (!isset($GLOBALS['conf']['user_register'])) { 632 // Set to the Drupal 6 default, "visitors can create accounts". 633 variable_set('user_register', USER_REGISTER_VISITORS); 634 } 635} 636 637/** 638 * Converts fields that store serialized variables from text to blob. 639 */ 640function user_update_7009() { 641 $spec = array( 642 'type' => 'blob', 643 'not null' => FALSE, 644 'size' => 'big', 645 'serialize' => TRUE, 646 'description' => 'A serialized array of name value pairs that are related to the user. Any form values posted during user edit are stored and are loaded into the $user object during user_load(). Use of this field is discouraged and it will likely disappear in a future version of Drupal.', 647 ); 648 db_change_field('users', 'data', 'data', $spec); 649} 650 651/** 652 * Update the {user}.signature_format column. 653 */ 654function user_update_7010() { 655 // Update the database column to allow NULL values. 656 db_change_field('users', 'signature_format', 'signature_format', array( 657 'type' => 'int', 658 'unsigned' => TRUE, 659 'not null' => FALSE, 660 'description' => 'The {filter_format}.format of the signature.', 661 )); 662 663 // Replace the signature format with NULL if the signature is empty and does 664 // not already have a stored text format. 665 // 666 // In Drupal 6, "0" (the former FILTER_FORMAT_DEFAULT constant) could be used 667 // to indicate this situation, but in Drupal 7, only NULL is supported. This 668 // update therefore preserves the ability of user accounts which were never 669 // given a signature (for example, if the site did not have user signatures 670 // enabled, or if the user never edited their account information) to not 671 // have a particular text format assumed for them the first time the 672 // signature is edited. 673 db_update('users') 674 ->fields(array('signature_format' => NULL)) 675 ->condition('signature', '') 676 ->condition('signature_format', 0) 677 ->execute(); 678 679 // There are a number of situations in which a Drupal 6 site could store 680 // content with a nonexistent text format. This includes text formats that 681 // had later been deleted, or non-empty content stored with a value of "0" 682 // (the former FILTER_FORMAT_DEFAULT constant). Drupal 6 would filter this 683 // content using whatever the site-wide default text format was at the moment 684 // the text was being displayed. 685 // 686 // In Drupal 7, this behavior is no longer supported, and all content must be 687 // stored with an explicit text format (or it will not be displayed when it 688 // is filtered). Therefore, to preserve the behavior of the site after the 689 // upgrade, we must replace all instances described above with the current 690 // value of the (old) site-wide default format at the moment of the upgrade. 691 $existing_formats = db_query("SELECT format FROM {filter_format}")->fetchCol(); 692 $default_format = variable_get('filter_default_format', 1); 693 db_update('users') 694 ->fields(array('signature_format' => $default_format)) 695 ->isNotNull('signature_format') 696 ->condition('signature_format', $existing_formats, 'NOT IN') 697 ->execute(); 698} 699 700/** 701 * Placeholder function. 702 * 703 * As a fix for user_update_7011() not updating email templates to use the new 704 * tokens, user_update_7017() now targets email templates of Drupal 6 sites and 705 * already upgraded sites. 706 */ 707function user_update_7011() { 708} 709 710/** 711 * Add the user's pictures to the {file_managed} table and make them managed 712 * files. 713 */ 714function user_update_7012(&$sandbox) { 715 716 $picture_field = array( 717 'type' => 'int', 718 'not null' => TRUE, 719 'default' => 0, 720 'description' => "Foreign key: {file_managed}.fid of user's picture.", 721 ); 722 723 if (!isset($sandbox['progress'])) { 724 // Check that the field hasn't been updated in an aborted run of this 725 // update. 726 if (!db_field_exists('users', 'picture_fid')) { 727 // Add a new field for the fid. 728 db_add_field('users', 'picture_fid', $picture_field); 729 } 730 731 // Initialize batch update information. 732 $sandbox['progress'] = 0; 733 $sandbox['last_user_processed'] = -1; 734 $sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} WHERE picture <> ''")->fetchField(); 735 } 736 737 // As a batch operation move the photos into the {file_managed} table and 738 // update the {users} records. 739 $limit = 500; 740 $result = db_query_range("SELECT uid, picture FROM {users} WHERE picture <> '' AND uid > :uid ORDER BY uid", 0, $limit, array(':uid' => $sandbox['last_user_processed'])); 741 foreach ($result as $user) { 742 // Don't bother adding files that don't exist. 743 if (file_exists($user->picture)) { 744 745 // Check if the file already exists. 746 $files = file_load_multiple(array(), array('uri' => $user->picture)); 747 if (count($files)) { 748 $file = reset($files); 749 } 750 else { 751 // Create a file object. 752 $file = new stdClass(); 753 $file->uri = $user->picture; 754 $file->filename = drupal_basename($file->uri); 755 $file->filemime = file_get_mimetype($file->uri); 756 $file->uid = $user->uid; 757 $file->status = FILE_STATUS_PERMANENT; 758 $file = file_save($file); 759 } 760 761 db_update('users') 762 ->fields(array('picture_fid' => $file->fid)) 763 ->condition('uid', $user->uid) 764 ->execute(); 765 } 766 767 // Update our progress information for the batch update. 768 $sandbox['progress']++; 769 $sandbox['last_user_processed'] = $user->uid; 770 } 771 772 // Indicate our current progress to the batch update system. If there's no 773 // max value then there's nothing to update and we're finished. 774 $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']); 775 776 // When we're finished, drop the old picture field and rename the new one to 777 // replace it. 778 if (isset($sandbox['#finished']) && $sandbox['#finished'] == 1) { 779 db_drop_field('users', 'picture'); 780 db_change_field('users', 'picture_fid', 'picture', $picture_field); 781 } 782} 783 784/** 785 * Add user module file usage entries. 786 */ 787function user_update_7013(&$sandbox) { 788 if (!isset($sandbox['progress'])) { 789 // Initialize batch update information. 790 $sandbox['progress'] = 0; 791 $sandbox['last_uid_processed'] = -1; 792 $sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} u WHERE u.picture <> 0")->fetchField(); 793 } 794 795 // Add usage entries for the user picture files. 796 $limit = 500; 797 $result = db_query_range('SELECT f.*, u.uid as user_uid FROM {users} u INNER JOIN {file_managed} f ON u.picture = f.fid WHERE u.picture <> 0 AND u.uid > :uid ORDER BY u.uid', 0, $limit, array(':uid' => $sandbox['last_uid_processed']))->fetchAllAssoc('fid', PDO::FETCH_ASSOC); 798 foreach ($result as $row) { 799 $uid = $row['user_uid']; 800 $file = (object) $row; 801 file_usage_add($file, 'user', 'user', $uid); 802 803 // Update our progress information for the batch update. 804 $sandbox['progress']++; 805 $sandbox['last_uid_processed'] = $uid; 806 } 807 808 // Indicate our current progress to the batch update system. 809 $sandbox['#finished'] = empty($sandbox['max']) || ($sandbox['progress'] / $sandbox['max']); 810} 811 812/** 813 * Rename the 'post comments without approval' permission. 814 * 815 * In Drupal 7, this permission has been renamed to 'skip comment approval'. 816 */ 817function user_update_7014() { 818 db_update('role_permission') 819 ->fields(array('permission' => 'skip comment approval')) 820 ->condition('permission', 'post comments without approval') 821 ->execute(); 822 823 return t("Renamed the 'post comments without approval' permission to 'skip comment approval'."); 824} 825 826/** 827 * Change {users}.signature_format into varchar. 828 */ 829function user_update_7015() { 830 db_change_field('users', 'signature_format', 'signature_format', array( 831 'type' => 'varchar', 832 'length' => 255, 833 'not null' => FALSE, 834 'description' => 'The {filter_format}.format of the signature.', 835 )); 836} 837 838/** 839 * @} End of "addtogroup updates-6.x-to-7.x". 840 */ 841 842/** 843 * @addtogroup updates-7.x-extra 844 * @{ 845 */ 846 847/** 848 * Update the database to match the schema. 849 */ 850function user_update_7016() { 851 // Add field default. 852 db_change_field('users', 'uid', 'uid', array( 853 'type' => 'int', 854 'unsigned' => TRUE, 855 'not null' => TRUE, 856 'default' => 0, 857 )); 858} 859 860/** 861 * Update email templates to use new tokens. 862 * 863 * This function upgrades customized email templates from the old !token format 864 * to the new core tokens format. Additionally, in Drupal 7 we no longer e-mail 865 * plain text passwords to users, and there is no token for a plain text 866 * password in the new token system. Therefore, it also modifies any saved 867 * templates using the old '!password' token such that the token is removed, and 868 * displays a warning to users that they may need to go and modify the wording 869 * of their templates. 870 */ 871function user_update_7017() { 872 $message = ''; 873 874 $tokens = array( 875 '!site' => '[site:name]', 876 '!username' => '[user:name]', 877 '!mailto' => '[user:mail]', 878 '!login_uri' => '[site:login-url]', 879 '!uri_brief' => '[site:url-brief]', 880 '!edit_uri' => '[user:edit-url]', 881 '!login_url' => '[user:one-time-login-url]', 882 '!uri' => '[site:url]', 883 '!date' => '[date:medium]', 884 '!password' => '', 885 ); 886 887 $result = db_select('variable', 'v') 888 ->fields('v', array('name')) 889 ->condition('name', db_like('user_mail_') . '%', 'LIKE') 890 ->execute(); 891 892 foreach ($result as $row) { 893 // Use variable_get() to get the unserialized value for free. 894 if ($value = variable_get($row->name, FALSE)) { 895 896 if (empty($message) && (strpos($value, '!password') !== FALSE)) { 897 $message = t('The ability to send users their passwords in plain text has been removed in Drupal 7. Your existing email templates have been modified to remove it. You should <a href="@template-url">review these templates</a> to make sure they read properly.', array('@template-url' => url('admin/config/people/accounts'))); 898 } 899 900 variable_set($row->name, str_replace(array_keys($tokens), $tokens, $value)); 901 } 902 } 903 904 return $message; 905} 906 907/** 908 * Ensure there is an index on {users}.picture. 909 */ 910function user_update_7018() { 911 if (!db_index_exists('users', 'picture')) { 912 db_add_index('users', 'picture', array('picture')); 913 } 914} 915 916/** 917 * Ensure there is a combined index on {authmap}.uid and {authmap}.module. 918 */ 919function user_update_7019() { 920 // Check first in case it was already added manually. 921 if (!db_index_exists('authmap', 'uid_module')) { 922 db_add_index('authmap', 'uid_module', array('uid', 'module')); 923 } 924} 925/** 926 * @} End of "addtogroup updates-7.x-extra". 927 */ 928