| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: install.inc,v 1.56.2.4 2009/02/16 10:25:02 goba Exp $ 3 4 define('SCHEMA_UNINSTALLED', -1); 5 define('SCHEMA_INSTALLED', 0); 6 7 define('REQUIREMENT_INFO', -1); 8 define('REQUIREMENT_OK', 0); 9 define('REQUIREMENT_WARNING', 1); 10 define('REQUIREMENT_ERROR', 2); 11 12 define('FILE_EXIST', 1); 13 define('FILE_READABLE', 2); 14 define('FILE_WRITABLE', 4); 15 define('FILE_EXECUTABLE', 8); 16 define('FILE_NOT_EXIST', 16); 17 define('FILE_NOT_READABLE', 32); 18 define('FILE_NOT_WRITABLE', 64); 19 define('FILE_NOT_EXECUTABLE', 128); 20 21 /** 22 * Initialize the update system by loading all installed module's .install files. 23 */ 24 function drupal_load_updates() { 25 foreach (drupal_get_installed_schema_version(NULL, FALSE, TRUE) as $module => $schema_version) { 26 if ($schema_version > -1) { 27 module_load_install($module); 28 } 29 } 30 } 31 32 /** 33 * Returns an array of available schema versions for a module. 34 * 35 * @param $module 36 * A module name. 37 * @return 38 * If the module has updates, an array of available updates sorted by version. 39 * Otherwise, FALSE. 40 */ 41 function drupal_get_schema_versions($module) { 42 $updates = array(); 43 $functions = get_defined_functions(); 44 foreach ($functions['user'] as $function) { 45 if (strpos($function, $module .'_update_') === 0) { 46 $version = substr($function, strlen($module .'_update_')); 47 if (is_numeric($version)) { 48 $updates[] = $version; 49 } 50 } 51 } 52 if (count($updates) == 0) { 53 return FALSE; 54 } 55 sort($updates, SORT_NUMERIC); 56 return $updates; 57 } 58 59 /** 60 * Returns the currently installed schema version for a module. 61 * 62 * @param $module 63 * A module name. 64 * @param $reset 65 * Set to TRUE after modifying the system table. 66 * @param $array 67 * Set to TRUE if you want to get information about all modules in the 68 * system. 69 * @return 70 * The currently installed schema version. 71 */ 72 function drupal_get_installed_schema_version($module, $reset = FALSE, $array = FALSE) { 73 static $versions = array(); 74 75 if ($reset) { 76 $versions = array(); 77 } 78 79 if (!$versions) { 80 $versions = array(); 81 $result = db_query("SELECT name, schema_version FROM {system} WHERE type = '%s'", 'module'); 82 while ($row = db_fetch_object($result)) { 83 $versions[$row->name] = $row->schema_version; 84 } 85 } 86 87 return $array ? $versions : $versions[$module]; 88 } 89 90 /** 91 * Update the installed version information for a module. 92 * 93 * @param $module 94 * A module name. 95 * @param $version 96 * The new schema version. 97 */ 98 function drupal_set_installed_schema_version($module, $version) { 99 db_query("UPDATE {system} SET schema_version = %d WHERE name = '%s'", $version, $module); 100 } 101 102 /** 103 * Loads the profile definition, extracting the profile's defined name. 104 * 105 * @return 106 * The name defined in the profile's _profile_details() hook. 107 */ 108 function drupal_install_profile_name() { 109 global $profile; 110 static $name = NULL; 111 112 if (!isset($name)) { 113 // Load profile details. 114 $function = $profile .'_profile_details'; 115 if (function_exists($function)) { 116 $details = $function(); 117 } 118 $name = isset($details['name']) ? $details['name'] : 'Drupal'; 119 } 120 121 return $name; 122 } 123 124 /** 125 * Auto detect the base_url with PHP predefined variables. 126 * 127 * @param $file 128 * The name of the file calling this function so we can strip it out of 129 * the URI when generating the base_url. 130 * 131 * @return 132 * The auto-detected $base_url that should be configured in settings.php 133 */ 134 function drupal_detect_baseurl($file = 'install.php') { 135 global $profile; 136 $proto = $_SERVER['HTTPS'] ? 'https://' : 'http://'; 137 $host = $_SERVER['SERVER_NAME']; 138 $port = ($_SERVER['SERVER_PORT'] == 80 ? '' : ':'. $_SERVER['SERVER_PORT']); 139 $uri = preg_replace("/\?.*/", '', $_SERVER['REQUEST_URI']); 140 $dir = str_replace("/$file", '', $uri); 141 142 return "$proto$host$port$dir"; 143 } 144 145 /** 146 * Detect all databases supported by Drupal that are compiled into the current 147 * PHP installation. 148 * 149 * @return 150 * An array of database types compiled into PHP. 151 */ 152 function drupal_detect_database_types() { 153 $databases = array(); 154 155 foreach (array('mysql', 'mysqli', 'pgsql') as $type) { 156 if (file_exists('./includes/install.'. $type .'.inc')) { 157 include_once './includes/install.'. $type .'.inc'; 158 $function = $type .'_is_available'; 159 if ($function()) { 160 $databases[$type] = $type; 161 } 162 } 163 } 164 165 return $databases; 166 } 167 168 /** 169 * Read settings.php into a buffer line by line, changing values specified in 170 * $settings array, then over-writing the old settings.php file. 171 * 172 * @param $settings 173 * An array of settings that need to be updated. 174 */ 175 function drupal_rewrite_settings($settings = array(), $prefix = '') { 176 $default_settings = './sites/default/default.settings.php'; 177 $settings_file = './'. conf_path(FALSE, TRUE) .'/'. $prefix .'settings.php'; 178 179 // Build list of setting names and insert the values into the global namespace. 180 $keys = array(); 181 foreach ($settings as $setting => $data) { 182 $GLOBALS[$setting] = $data['value']; 183 $keys[] = $setting; 184 } 185 186 $buffer = NULL; 187 $first = TRUE; 188 if ($fp = fopen($default_settings, 'r')) { 189 // Step line by line through settings.php. 190 while (!feof($fp)) { 191 $line = fgets($fp); 192 if ($first && substr($line, 0, 5) != '<?php') { 193 $buffer = "<?php\n\n"; 194 } 195 $first = FALSE; 196 // Check for constants. 197 if (substr($line, 0, 7) == 'define(') { 198 preg_match('/define\(\s*[\'"]([A-Z_-]+)[\'"]\s*,(.*?)\);/', $line, $variable); 199 if (in_array($variable[1], $keys)) { 200 $setting = $settings[$variable[1]]; 201 $buffer .= str_replace($variable[2], " '". $setting['value'] ."'", $line); 202 unset($settings[$variable[1]]); 203 unset($settings[$variable[2]]); 204 } 205 else { 206 $buffer .= $line; 207 } 208 } 209 // Check for variables. 210 elseif (substr($line, 0, 1) == '$') { 211 preg_match('/\$([^ ]*) /', $line, $variable); 212 if (in_array($variable[1], $keys)) { 213 // Write new value to settings.php in the following format: 214 // $'setting' = 'value'; // 'comment' 215 $setting = $settings[$variable[1]]; 216 $buffer .= '$'. $variable[1] ." = '". $setting['value'] ."';". (!empty($setting['comment']) ? ' // '. $setting['comment'] ."\n" : "\n"); 217 unset($settings[$variable[1]]); 218 } 219 else { 220 $buffer .= $line; 221 } 222 } 223 else { 224 $buffer .= $line; 225 } 226 } 227 fclose($fp); 228 229 // Add required settings that were missing from settings.php. 230 foreach ($settings as $setting => $data) { 231 if ($data['required']) { 232 $buffer .= "\$$setting = '". $data['value'] ."';\n"; 233 } 234 } 235 236 $fp = fopen($settings_file, 'w'); 237 if ($fp && fwrite($fp, $buffer) === FALSE) { 238 drupal_set_message(st('Failed to modify %settings, please verify the file permissions.', array('%settings' => $settings_file)), 'error'); 239 } 240 } 241 else { 242 drupal_set_message(st('Failed to open %settings, please verify the file permissions.', array('%settings' => $default_settings)), 'error'); 243 } 244 } 245 246 /** 247 * Get list of all .install files. 248 * 249 * @param $module_list 250 * An array of modules to search for their .install files. 251 */ 252 function drupal_get_install_files($module_list = array()) { 253 $installs = array(); 254 foreach ($module_list as $module) { 255 $installs = array_merge($installs, drupal_system_listing($module .'.install$', 'modules')); 256 } 257 return $installs; 258 } 259 260 /** 261 * Verify a profile for installation. 262 * 263 * @param profile 264 * Name of profile to verify. 265 * @param locale 266 * Name of locale used (if any). 267 * @return 268 * The list of modules to install. 269 */ 270 function drupal_verify_profile($profile, $locale) { 271 include_once './includes/file.inc'; 272 include_once './includes/common.inc'; 273 274 $profile_file = "./profiles/$profile/$profile.profile"; 275 276 if (!isset($profile) || !file_exists($profile_file)) { 277 install_no_profile_error(); 278 } 279 280 require_once($profile_file); 281 282 // Get a list of modules required by this profile. 283 $function = $profile .'_profile_modules'; 284 $module_list = array_merge(drupal_required_modules(), $function(), ($locale != 'en' && !empty($locale) ? array('locale') : array())); 285 286 // Get a list of modules that exist in Drupal's assorted subdirectories. 287 $present_modules = array(); 288 foreach (drupal_system_listing('\.module$', 'modules', 'name', 0) as $present_module) { 289 $present_modules[] = $present_module->name; 290 } 291 292 // Verify that all of the profile's required modules are present. 293 $missing_modules = array_diff($module_list, $present_modules); 294 if (count($missing_modules)) { 295 foreach ($missing_modules as $module) { 296 drupal_set_message(st('The %module module is required but was not found. Please move it into the <em>modules</em> subdirectory.', array('%module' => $module)), 'error'); 297 } 298 } 299 else { 300 return $module_list; 301 } 302 } 303 304 /** 305 * Calls the install function and updates the system table for a given list of 306 * modules. 307 * 308 * @param module_list 309 * The modules to install. 310 */ 311 function drupal_install_modules($module_list = array()) { 312 $files = module_rebuild_cache(); 313 $module_list = array_flip(array_values($module_list)); 314 do { 315 $moved = FALSE; 316 foreach ($module_list as $module => $weight) { 317 $file = $files[$module]; 318 if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) { 319 foreach ($file->info['dependencies'] as $dependency) { 320 if (isset($module_list[$dependency]) && $module_list[$module] < $module_list[$dependency] +1) { 321 $module_list[$module] = $module_list[$dependency] +1; 322 $moved = TRUE; 323 } 324 } 325 } 326 } 327 } while ($moved); 328 asort($module_list); 329 $module_list = array_keys($module_list); 330 array_filter($module_list, '_drupal_install_module'); 331 module_enable($module_list); 332 } 333 334 /** 335 * Callback to install an individual profile module. 336 * 337 * Used during installation to install modules one at a time and then 338 * enable them, or to install a number of modules at one time 339 * from admin/build/modules. 340 */ 341 function _drupal_install_module($module) { 342 if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) { 343 module_load_install($module); 344 module_invoke($module, 'install'); 345 $versions = drupal_get_schema_versions($module); 346 drupal_set_installed_schema_version($module, $versions ? max($versions) : SCHEMA_INSTALLED); 347 return TRUE; 348 } 349 } 350 351 /** 352 * Callback to install the system module. 353 * 354 * Separated from the installation of other modules so core system 355 * functions can be made available while other modules are installed. 356 */ 357 function drupal_install_system() { 358 $system_path = dirname(drupal_get_filename('module', 'system', NULL)); 359 require_once './'. $system_path .'/system.install'; 360 module_invoke('system', 'install'); 361 $system_versions = drupal_get_schema_versions('system'); 362 $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED; 363 db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version) VALUES('%s', '%s', '%s', '%s', %d, %d, %d, %d)", $system_path .'/system.module', 'system', 'module', '', 1, 0, 0, $system_version); 364 // Now that we've installed things properly, bootstrap the full Drupal environment 365 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); 366 module_rebuild_cache(); 367 } 368 369 370 /** 371 * Calls the uninstall function and updates the system table for a given module. 372 * 373 * @param $module 374 * The module to uninstall. 375 */ 376 function drupal_uninstall_module($module) { 377 // First, retrieve all the module's menu paths from db. 378 drupal_load('module', $module); 379 $paths = module_invoke($module, 'menu'); 380 381 // Uninstall the module(s). 382 module_load_install($module); 383 module_invoke($module, 'uninstall'); 384 385 // Now remove the menu links for all paths declared by this module. 386 if (!empty($paths)) { 387 $paths = array_keys($paths); 388 // Clean out the names of load functions. 389 foreach ($paths as $index => $path) { 390 $parts = explode('/', $path, MENU_MAX_PARTS); 391 foreach ($parts as $k => $part) { 392 if (preg_match('/^%[a-z_]*$/', $part)) { 393 $parts[$k] = '%'; 394 } 395 } 396 $paths[$index] = implode('/', $parts); 397 } 398 $placeholders = implode(', ', array_fill(0, count($paths), "'%s'")); 399 400 $result = db_query('SELECT * FROM {menu_links} WHERE router_path IN ('. $placeholders .') AND external = 0 ORDER BY depth DESC', $paths); 401 // Remove all such items. Starting from those with the greatest depth will 402 // minimize the amount of re-parenting done by menu_link_delete(). 403 while ($item = db_fetch_array($result)) { 404 _menu_delete_item($item, TRUE); 405 } 406 } 407 408 drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED); 409 } 410 411 /** 412 * Verify the state of the specified file. 413 * 414 * @param $file 415 * The file to check for. 416 * @param $mask 417 * An optional bitmask created from various FILE_* constants. 418 * @param $type 419 * The type of file. Can be file (default), dir, or link. 420 * @return 421 * TRUE on success or FALSE on failure. A message is set for the latter. 422 */ 423 function drupal_verify_install_file($file, $mask = NULL, $type = 'file') { 424 $return = TRUE; 425 // Check for files that shouldn't be there. 426 if (isset($mask) && ($mask & FILE_NOT_EXIST) && file_exists($file)) { 427 return FALSE; 428 } 429 // Verify that the file is the type of file it is supposed to be. 430 if (isset($type) && file_exists($file)) { 431 $check = 'is_'. $type; 432 if (!function_exists($check) || !$check($file)) { 433 $return = FALSE; 434 } 435 } 436 437 // Verify file permissions. 438 if (isset($mask)) { 439 $masks = array(FILE_EXIST, FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); 440 foreach ($masks as $current_mask) { 441 if ($mask & $current_mask) { 442 switch ($current_mask) { 443 case FILE_EXIST: 444 if (!file_exists($file)) { 445 if ($type == 'dir') { 446 drupal_install_mkdir($file, $mask); 447 } 448 if (!file_exists($file)) { 449 $return = FALSE; 450 } 451 } 452 break; 453 case FILE_READABLE: 454 if (!is_readable($file) && !drupal_install_fix_file($file, $mask)) { 455 $return = FALSE; 456 } 457 break; 458 case FILE_WRITABLE: 459 if (!is_writable($file) && !drupal_install_fix_file($file, $mask)) { 460 $return = FALSE; 461 } 462 break; 463 case FILE_EXECUTABLE: 464 if (!is_executable($file) && !drupal_install_fix_file($file, $mask)) { 465 $return = FALSE; 466 } 467 break; 468 case FILE_NOT_READABLE: 469 if (is_readable($file) && !drupal_install_fix_file($file, $mask)) { 470 $return = FALSE; 471 } 472 break; 473 case FILE_NOT_WRITABLE: 474 if (is_writable($file) && !drupal_install_fix_file($file, $mask)) { 475 $return = FALSE; 476 } 477 break; 478 case FILE_NOT_EXECUTABLE: 479 if (is_executable($file) && !drupal_install_fix_file($file, $mask)) { 480 $return = FALSE; 481 } 482 break; 483 } 484 } 485 } 486 } 487 return $return; 488 } 489 490 /** 491 * Create a directory with specified permissions. 492 * 493 * @param file 494 * The name of the directory to create; 495 * @param mask 496 * The permissions of the directory to create. 497 * @param $message 498 * (optional) Whether to output messages. Defaults to TRUE. 499 * 500 * @return 501 * TRUE/FALSE whether or not the directory was successfully created. 502 */ 503 function drupal_install_mkdir($file, $mask, $message = TRUE) { 504 $mod = 0; 505 $masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); 506 foreach ($masks as $m) { 507 if ($mask & $m) { 508 switch ($m) { 509 case FILE_READABLE: 510 $mod += 444; 511 break; 512 case FILE_WRITABLE: 513 $mod += 222; 514 break; 515 case FILE_EXECUTABLE: 516 $mod += 111; 517 break; 518 } 519 } 520 } 521 522 if (@mkdir($file, intval("0$mod", 8))) { 523 return TRUE; 524 } 525 else { 526 return FALSE; 527 } 528 } 529 530 /** 531 * Attempt to fix file permissions. 532 * 533 * The general approach here is that, because we do not know the security 534 * setup of the webserver, we apply our permission changes to all three 535 * digits of the file permission (i.e. user, group and all). 536 * 537 * To ensure that the values behave as expected (and numbers don't carry 538 * from one digit to the next) we do the calculation on the octal value 539 * using bitwise operations. This lets us remove, for example, 0222 from 540 * 0700 and get the correct value of 0500. 541 * 542 * @param $file 543 * The name of the file with permissions to fix. 544 * @param $mask 545 * The desired permissions for the file. 546 * @param $message 547 * (optional) Whether to output messages. Defaults to TRUE. 548 * 549 * @return 550 * TRUE/FALSE whether or not we were able to fix the file's permissions. 551 */ 552 function drupal_install_fix_file($file, $mask, $message = TRUE) { 553 $mod = fileperms($file) & 0777; 554 $masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE); 555 556 // FILE_READABLE, FILE_WRITABLE, and FILE_EXECUTABLE permission strings 557 // can theoretically be 0400, 0200, and 0100 respectively, but to be safe 558 // we set all three access types in case the administrator intends to 559 // change the owner of settings.php after installation. 560 foreach ($masks as $m) { 561 if ($mask & $m) { 562 switch ($m) { 563 case FILE_READABLE: 564 if (!is_readable($file)) { 565 $mod |= 0444; 566 } 567 break; 568 case FILE_WRITABLE: 569 if (!is_writable($file)) { 570 $mod |= 0222; 571 } 572 break; 573 case FILE_EXECUTABLE: 574 if (!is_executable($file)) { 575 $mod |= 0111; 576 } 577 break; 578 case FILE_NOT_READABLE: 579 if (is_readable($file)) { 580 $mod &= ~0444; 581 } 582 break; 583 case FILE_NOT_WRITABLE: 584 if (is_writable($file)) { 585 $mod &= ~0222; 586 } 587 break; 588 case FILE_NOT_EXECUTABLE: 589 if (is_executable($file)) { 590 $mod &= ~0111; 591 } 592 break; 593 } 594 } 595 } 596 597 // chmod() will work if the web server is running as owner of the file. 598 // If PHP safe_mode is enabled the currently executing script must also 599 // have the same owner. 600 if (@chmod($file, $mod)) { 601 return TRUE; 602 } 603 else { 604 return FALSE; 605 } 606 } 607 608 609 /** 610 * Send the user to a different installer page. This issues an on-site HTTP 611 * redirect. Messages (and errors) are erased. 612 * 613 * @param $path 614 * An installer path. 615 */ 616 function install_goto($path) { 617 global $base_url; 618 header('Location: '. $base_url .'/'. $path); 619 header('Cache-Control: no-cache'); // Not a permanent redirect. 620 exit(); 621 } 622 623 /** 624 * Hardcoded function for doing the equivalent of t() during 625 * the install process, when database, theme, and localization 626 * system is possibly not yet available. 627 */ 628 function st($string, $args = array()) { 629 static $locale_strings = NULL; 630 global $profile, $install_locale; 631 632 if (!isset($locale_strings)) { 633 $locale_strings = array(); 634 $filename = './profiles/'. $profile .'/translations/'. $install_locale .'.po'; 635 if (file_exists($filename)) { 636 require_once './includes/locale.inc'; 637 $file = (object) array('filepath' => $filename); 638 _locale_import_read_po('mem-store', $file); 639 $locale_strings = _locale_import_one_string('mem-report'); 640 } 641 } 642 643 require_once './includes/theme.inc'; 644 // Transform arguments before inserting them 645 foreach ($args as $key => $value) { 646 switch ($key[0]) { 647 // Escaped only 648 case '@': 649 $args[$key] = check_plain($value); 650 break; 651 // Escaped and placeholder 652 case '%': 653 default: 654 $args[$key] = '<em>'. check_plain($value) .'</em>'; 655 break; 656 // Pass-through 657 case '!': 658 } 659 } 660 return strtr((!empty($locale_strings[$string]) ? $locale_strings[$string] : $string), $args); 661 } 662 663 /** 664 * Check a profile's requirements. 665 * 666 * @param profile 667 * Name of profile to check. 668 */ 669 function drupal_check_profile($profile) { 670 include_once './includes/file.inc'; 671 672 $profile_file = "./profiles/$profile/$profile.profile"; 673 674 if (!isset($profile) || !file_exists($profile_file)) { 675 install_no_profile_error(); 676 } 677 678 require_once($profile_file); 679 680 // Get a list of modules required by this profile. 681 $function = $profile .'_profile_modules'; 682 $module_list = array_unique(array_merge(drupal_required_modules(), $function())); 683 684 // Get a list of all .install files. 685 $installs = drupal_get_install_files($module_list); 686 687 // Collect requirement testing results 688 $requirements = array(); 689 foreach ($installs as $install) { 690 require_once $install->filename; 691 if (module_hook($install->name, 'requirements')) { 692 $requirements = array_merge($requirements, module_invoke($install->name, 'requirements', 'install')); 693 } 694 } 695 return $requirements; 696 } 697 698 /** 699 * Extract highest severity from requirements array. 700 */ 701 function drupal_requirements_severity(&$requirements) { 702 $severity = REQUIREMENT_OK; 703 foreach ($requirements as $requirement) { 704 if (isset($requirement['severity'])) { 705 $severity = max($severity, $requirement['severity']); 706 } 707 } 708 return $severity; 709 } 710 711 /** 712 * Check a module's requirements. 713 */ 714 function drupal_check_module($module) { 715 // Include install file 716 $install = drupal_get_install_files(array($module)); 717 if (isset($install[$module])) { 718 require_once $install[$module]->filename; 719 720 // Check requirements 721 $requirements = module_invoke($module, 'requirements', 'install'); 722 if (is_array($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) { 723 // Print any error messages 724 foreach ($requirements as $requirement) { 725 if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) { 726 $message = $requirement['description']; 727 if (isset($requirement['value']) && $requirement['value']) { 728 $message .= ' ('. t('Currently using !item !version', array('!item' => $requirement['title'], '!version' => $requirement['value'])) .')'; 729 } 730 drupal_set_message($message, 'error'); 731 } 732 } 733 return FALSE; 734 } 735 } 736 return TRUE; 737 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |