install.inc 22.8 KB
Newer Older
1 2 3
<?php
// $Id$

4 5 6
/**
 * Indicates that a module has not been installed yet.
 */
7
define('SCHEMA_UNINSTALLED', -1);
8 9 10 11

/**
 * Indicates that a module has been installed.
 */
12
define('SCHEMA_INSTALLED', 0);
13

14 15 16
/**
 * Requirement severity -- Informational message only.
 */
Steven Wittens's avatar
Steven Wittens committed
17
define('REQUIREMENT_INFO', -1);
18 19 20 21

/**
 * Requirement severity -- Requirement successfully met.
 */
22
define('REQUIREMENT_OK', 0);
23 24 25 26

/**
 * Requirement severity -- Warning condition; proceed but flag warning.
 */
27
define('REQUIREMENT_WARNING', 1);
28 29 30 31

/**
 * Requirement severity -- Error condition; abort installation.
 */
32
define('REQUIREMENT_ERROR', 2);
33

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
/**
 * File permission check -- File exists.
 */
define('FILE_EXIST', 1);

/**
 * File permission check -- File is readable.
 */
define('FILE_READABLE', 2);

/**
 * File permission check -- File is writable.
 */
define('FILE_WRITABLE', 4);

/**
 * File permission check -- File is executable.
 */
define('FILE_EXECUTABLE', 8);

/**
 * File permission check -- File does not exist.
 */
define('FILE_NOT_EXIST', 16);

/**
 * File permission check -- File is not readable.
 */
define('FILE_NOT_READABLE', 32);

/**
 * File permission check -- File is not writable.
 */
define('FILE_NOT_WRITABLE', 64);

/**
 * File permission check -- File is not executable.
 */
72
define('FILE_NOT_EXECUTABLE', 128);
73

74 75 76 77
/**
 * Initialize the update system by loading all installed module's .install files.
 */
function drupal_load_updates() {
78 79 80 81
  foreach (drupal_get_installed_schema_version(NULL, FALSE, TRUE) as $module => $schema_version) {
    if ($schema_version > -1) {
      module_load_install($module);
    }
82 83 84 85
  }
}

/**
86
 * Returns an array of available schema versions for a module.
87 88 89 90 91 92 93 94
 *
 * @param $module
 *   A module name.
 * @return
 *   If the module has updates, an array of available updates. Otherwise,
 *   FALSE.
 */
function drupal_get_schema_versions($module) {
95
  $updates = array();
96 97
  $functions = get_defined_functions();
  foreach ($functions['user'] as $function) {
98 99
    if (strpos($function, $module . '_update_') === 0) {
      $version = substr($function, strlen($module . '_update_'));
100 101 102
      if (is_numeric($version)) {
        $updates[] = $version;
      }
103
    }
104
  }
105 106
  if (count($updates) == 0) {
    return FALSE;
107
  }
108
  return $updates;
109 110 111 112 113 114 115
}

/**
 * Returns the currently installed schema version for a module.
 *
 * @param $module
 *   A module name.
116 117 118
 * @param $reset
 *   Set to TRUE after modifying the system table.
 * @param $array
119
 *   Set to TRUE if you want to get information about all modules in the
120
 *   system.
121 122 123
 * @return
 *   The currently installed schema version.
 */
124
function drupal_get_installed_schema_version($module, $reset = FALSE, $array = FALSE) {
125
  static $versions = array();
126 127

  if ($reset) {
128
    $versions = array();
129 130 131 132
  }

  if (!$versions) {
    $versions = array();
133
    $result = db_query("SELECT name, schema_version FROM {system} WHERE type = '%s'", 'module');
134 135 136 137 138
    while ($row = db_fetch_object($result)) {
      $versions[$row->name] = $row->schema_version;
    }
  }

139
  return $array ? $versions : $versions[$module];
140 141 142 143 144 145 146 147 148 149 150 151 152
}

/**
 * Update the installed version information for a module.
 *
 * @param $module
 *   A module name.
 * @param $version
 *   The new schema version.
 */
function drupal_set_installed_schema_version($module, $version) {
  db_query("UPDATE {system} SET schema_version = %d WHERE name = '%s'", $version, $module);
}
153 154 155 156 157 158 159 160 161 162 163 164 165

/**
 * Loads the profile definition, extracting the profile's defined name.
 *
 * @return
 *   The name defined in the profile's _profile_details() hook.
 */
function drupal_install_profile_name() {
  global $profile;
  static $name = NULL;

  if (!isset($name)) {
    // Load profile details.
166
    $function = $profile . '_profile_details';
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    if (function_exists($function)) {
      $details = $function();
    }
    $name = isset($details['name']) ? $details['name'] : 'Drupal';
  }

  return $name;
}

/**
 * Auto detect the base_url with PHP predefined variables.
 *
 * @param $file
 *   The name of the file calling this function so we can strip it out of
 *   the URI when generating the base_url.
 *
 * @return
 *   The auto-detected $base_url that should be configured in settings.php
 */
function drupal_detect_baseurl($file = 'install.php') {
  global $profile;
  $proto = $_SERVER['HTTPS'] ? 'https://' : 'http://';
  $host = $_SERVER['SERVER_NAME'];
190
  $port = ($_SERVER['SERVER_PORT'] == 80 ? '' : ':' . $_SERVER['SERVER_PORT']);
191
  $uri = preg_replace("/\?.*/", '', $_SERVER['REQUEST_URI']);
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
  $dir = str_replace("/$file", '', $uri);

  return "$proto$host$port$dir";
}

/**
 * Detect all databases supported by Drupal that are compiled into the current
 * PHP installation.
 *
 * @return
 *  An array of database types compiled into PHP.
 */
function drupal_detect_database_types() {
  $databases = array();

  foreach (array('mysql', 'mysqli', 'pgsql') as $type) {
208 209 210
    if (file_exists('./includes/install.' . $type . '.inc')) {
      include_once './includes/install.' . $type . '.inc';
      $function = $type . '_is_available';
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
      if ($function()) {
        $databases[$type] = $type;
      }
    }
  }

  return $databases;
}

/**
 * Read settings.php into a buffer line by line, changing values specified in
 * $settings array, then over-writing the old settings.php file.
 *
 * @param $settings
 *   An array of settings that need to be updated.
 */
function drupal_rewrite_settings($settings = array(), $prefix = '') {
228
  $default_settings = './sites/default/default.settings.php';
229
  $settings_file = './' . conf_path(FALSE, TRUE) . '/' . $prefix . 'settings.php';
230 231 232 233 234 235 236 237 238 239

  // Build list of setting names and insert the values into the global namespace.
  $keys = array();
  foreach ($settings as $setting => $data) {
    $GLOBALS[$setting] = $data['value'];
    $keys[] = $setting;
  }

  $buffer = NULL;
  $first = TRUE;
240
  if ($fp = fopen($default_settings, 'r')) {
241 242 243 244 245 246 247 248 249 250 251 252
    // Step line by line through settings.php.
    while (!feof($fp)) {
      $line = fgets($fp);
      if ($first && substr($line, 0, 5) != '<?php') {
        $buffer = "<?php\n\n";
      }
      $first = FALSE;
      // Check for constants.
      if (substr($line, 0, 7) == 'define(') {
        preg_match('/define\(\s*[\'"]([A-Z_-]+)[\'"]\s*,(.*?)\);/', $line, $variable);
        if (in_array($variable[1], $keys)) {
          $setting = $settings[$variable[1]];
253
          $buffer .= str_replace($variable[2], " '" . $setting['value'] . "'", $line);
254 255 256 257 258 259 260 261 262 263 264 265 266 267
          unset($settings[$variable[1]]);
          unset($settings[$variable[2]]);
        }
        else {
          $buffer .= $line;
        }
      }
      // Check for variables.
      elseif (substr($line, 0, 1) == '$') {
        preg_match('/\$([^ ]*) /', $line, $variable);
        if (in_array($variable[1], $keys)) {
          // Write new value to settings.php in the following format:
          //    $'setting' = 'value'; // 'comment'
          $setting = $settings[$variable[1]];
268
          $buffer .= '$' . $variable[1] . " = '" . $setting['value'] . "';" . (!empty($setting['comment']) ? ' // ' . $setting['comment'] . "\n" : "\n");
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
          unset($settings[$variable[1]]);
        }
        else {
          $buffer .= $line;
        }
      }
      else {
        $buffer .= $line;
      }
    }
    fclose($fp);

    // Add required settings that were missing from settings.php.
    foreach ($settings as $setting => $data) {
      if ($data['required']) {
284
        $buffer .= "\$$setting = '" . $data['value'] . "';\n";
285 286 287 288 289
      }
    }

    $fp = fopen($settings_file, 'w');
    if ($fp && fwrite($fp, $buffer) === FALSE) {
290
      drupal_set_message(st('Failed to modify %settings, please verify the file permissions.', array('%settings' => $settings_file)), 'error');
291 292 293
    }
  }
  else {
294
    drupal_set_message(st('Failed to open %settings, please verify the file permissions.', array('%settings' => $default_settings)), 'error');
295 296 297 298 299 300 301 302 303 304 305 306
  }
}

/**
 * Get list of all .install files.
 *
 * @param $module_list
 *   An array of modules to search for their .install files.
 */
function drupal_get_install_files($module_list = array()) {
  $installs = array();
  foreach ($module_list as $module) {
307
    $installs = array_merge($installs, drupal_system_listing($module . '.install$', 'modules'));
308 309 310 311 312
  }
  return $installs;
}

/**
Steven Wittens's avatar
Steven Wittens committed
313
 * Verify a profile for installation.
314 315
 *
 * @param profile
Steven Wittens's avatar
Steven Wittens committed
316
 *   Name of profile to verify.
drumm's avatar
drumm committed
317 318
 * @param locale
 *   Name of locale used (if any).
Steven Wittens's avatar
Steven Wittens committed
319 320
 * @return
 *   The list of modules to install.
321
 */
drumm's avatar
drumm committed
322
function drupal_verify_profile($profile, $locale) {
323
  include_once './includes/file.inc';
324
  include_once './includes/common.inc';
325

326
  $profile_file = "./profiles/$profile/$profile.profile";
327 328

  if (!isset($profile) || !file_exists($profile_file)) {
329
    install_no_profile_error();
330 331 332 333 334
  }

  require_once($profile_file);

  // Get a list of modules required by this profile.
335
  $function = $profile . '_profile_modules';
336
  $module_list = array_merge(drupal_required_modules(), $function(), ($locale != 'en' ? array('locale') : array()));
337

338 339
  // Get a list of modules that exist in Drupal's assorted subdirectories.
  $present_modules = array();
340
  foreach (drupal_system_listing('\.module$', 'modules', 'name', 0) as $present_module) {
341 342 343 344 345 346
    $present_modules[] = $present_module->name;
  }

  // Verify that all of the profile's required modules are present.
  $missing_modules = array_diff($module_list, $present_modules);
  if (count($missing_modules)) {
347
    foreach ($missing_modules as $module) {
Steven Wittens's avatar
Steven Wittens committed
348 349 350
      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');
    }
  }
351 352 353
  else {
    return $module_list;
  }
Steven Wittens's avatar
Steven Wittens committed
354
}
355

Steven Wittens's avatar
Steven Wittens committed
356
/**
357 358
 * Calls the install function and updates the system table for a given list of
 * modules.
Steven Wittens's avatar
Steven Wittens committed
359 360
 *
 * @param module_list
361 362 363
 *   The modules to install.
 */
function drupal_install_modules($module_list = array()) {
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
  $files = module_rebuild_cache();
  $module_list = array_flip(array_values($module_list));
  do {
    $moved = FALSE;
    foreach ($module_list as $module => $weight) {
      $file = $files[$module];
      if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) {
        foreach ($file->info['dependencies'] as $dependency) {
          if (isset($module_list[$dependency]) && $module_list[$module] < $module_list[$dependency] +1) {
            $module_list[$module] = $module_list[$dependency] +1;
            $moved = TRUE;
          }
        }
      }
    }
  } while ($moved);
  asort($module_list);
  $module_list = array_keys($module_list);
382 383 384 385 386 387 388 389 390 391
  array_filter($module_list, '_drupal_install_module');
  module_enable($module_list);
}

/**
 * Callback to install an individual profile module.
 *
 * Used during installation to install modules one at a time and then
 * enable them, or to install a number of modules at one time
 * from admin/build/modules.
Steven Wittens's avatar
Steven Wittens committed
392
 */
393 394 395 396 397 398 399 400 401
function _drupal_install_module($module) {
  if (drupal_get_installed_schema_version($module, TRUE) == SCHEMA_UNINSTALLED) {
    module_load_install($module);
    module_invoke($module, 'install');
    $versions = drupal_get_schema_versions($module);
    drupal_set_installed_schema_version($module, $versions ? max($versions) : SCHEMA_INSTALLED);
    return TRUE;
  }
}
Steven Wittens's avatar
Steven Wittens committed
402

403 404 405 406 407 408 409
/**
 * Callback to install the system module.
 *
 * Separated from the installation of other modules so core system
 * functions can be made available while other modules are installed.
 */
function drupal_install_system() {
Dries's avatar
Dries committed
410
  $system_path = dirname(drupal_get_filename('module', 'system', NULL));
411
  require_once './' . $system_path . '/system.install';
Steven Wittens's avatar
Steven Wittens committed
412 413 414
  module_invoke('system', 'install');
  $system_versions = drupal_get_schema_versions('system');
  $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED;
415
  db_query("INSERT INTO {system} (filename, name, type, owner, status, bootstrap, schema_version) VALUES('%s', '%s', '%s', '%s', %d, %d, %d)", $system_path . '/system.module', 'system', 'module', '', 1, 0, $system_version);
Steven Wittens's avatar
Steven Wittens committed
416
  // Now that we've installed things properly, bootstrap the full Drupal environment
417
  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
Steven Wittens's avatar
Steven Wittens committed
418
  module_rebuild_cache();
419 420
}

421

422 423 424 425 426 427 428
/**
 * Calls the uninstall function and updates the system table for a given module.
 *
 * @param $module
 *   The module to uninstall.
 */
function drupal_uninstall_module($module) {
429 430 431 432 433
  // First, retrieve all the module's menu paths from db.
  drupal_load('module', $module);
  $paths = module_invoke($module, 'menu');

  // Uninstall the module(s).
434 435
  module_load_install($module);
  module_invoke($module, 'uninstall');
Dries's avatar
Dries committed
436

437
  // Now remove the menu links for all paths declared by this module.
438 439 440
  if (!empty($paths)) {
    $paths = array_keys($paths);
    // Clean out the names of load functions.
441
    foreach ($paths as $index => $path) {
442 443 444 445 446 447 448 449 450
      $parts = explode('/', $path, MENU_MAX_PARTS);
      foreach ($parts as $k => $part) {
        if (preg_match('/^%[a-z_]*$/', $part)) {
          $parts[$k] = '%';
        }
      }
      $paths[$index] = implode('/', $parts);
    }
    $placeholders = implode(', ', array_fill(0, count($paths), "'%s'"));
Dries's avatar
Dries committed
451

452
    $result = db_query('SELECT * FROM {menu_links} WHERE router_path IN (' . $placeholders . ') AND external = 0 ORDER BY depth DESC', $paths);
453 454 455 456 457 458 459
    // Remove all such items. Starting from those with the greatest depth will
    // minimize the amount of re-parenting done by menu_link_delete().
    while ($item = db_fetch_array($result)) {
      _menu_delete_item($item, TRUE);
    }
  }

460 461 462
  drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED);
}

463 464 465 466 467 468 469 470 471 472
/**
 * Verify the state of the specified file.
 *
 * @param $file
 *   The file to check for.
 * @param $mask
 *   An optional bitmask created from various FILE_* constants.
 * @param $type
 *   The type of file. Can be file (default), dir, or link.
 * @return
473
 *   TRUE on success or FALSE on failure. A message is set for the latter.
474 475 476 477 478 479 480 481 482
 */
function drupal_verify_install_file($file, $mask = NULL, $type = 'file') {
  $return = TRUE;
  // Check for files that shouldn't be there.
  if (isset($mask) && ($mask & FILE_NOT_EXIST) && file_exists($file)) {
    return FALSE;
  }
  // Verify that the file is the type of file it is supposed to be.
  if (isset($type) && file_exists($file)) {
483
    $check = 'is_' . $type;
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
    if (!function_exists($check) || !$check($file)) {
      $return = FALSE;
    }
  }

  // Verify file permissions.
  if (isset($mask)) {
    $masks = array(FILE_EXIST, FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE);
    foreach ($masks as $current_mask) {
      if ($mask & $current_mask) {
        switch ($current_mask) {
          case FILE_EXIST:
            if (!file_exists($file)) {
              if ($type == 'dir') {
                drupal_install_mkdir($file, $mask);
              }
              if (!file_exists($file)) {
                $return = FALSE;
              }
            }
            break;
          case FILE_READABLE:
            if (!is_readable($file) && !drupal_install_fix_file($file, $mask)) {
              $return = FALSE;
            }
            break;
          case FILE_WRITABLE:
            if (!is_writable($file) && !drupal_install_fix_file($file, $mask)) {
              $return = FALSE;
            }
            break;
          case FILE_EXECUTABLE:
            if (!is_executable($file) && !drupal_install_fix_file($file, $mask)) {
              $return = FALSE;
            }
            break;
          case FILE_NOT_READABLE:
            if (is_readable($file) && !drupal_install_fix_file($file, $mask)) {
              $return = FALSE;
            }
            break;
          case FILE_NOT_WRITABLE:
            if (is_writable($file) && !drupal_install_fix_file($file, $mask)) {
              $return = FALSE;
            }
            break;
          case FILE_NOT_EXECUTABLE:
            if (is_executable($file) && !drupal_install_fix_file($file, $mask)) {
              $return = FALSE;
            }
            break;
        }
      }
    }
  }
  return $return;
}

/**
 * Create a directory with specified permissions.
 *
 * @param file
 *  The name of the directory to create;
 * @param mask
 *  The permissions of the directory to create.
 * @param $message
 *  (optional) Whether to output messages. Defaults to TRUE.
 *
 * @return
 *  TRUE/FALSE whether or not the directory was successfully created.
 */
function drupal_install_mkdir($file, $mask, $message = TRUE) {
  $mod = 0;
  $masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE);
  foreach ($masks as $m) {
    if ($mask & $m) {
      switch ($m) {
        case FILE_READABLE:
          $mod += 444;
          break;
        case FILE_WRITABLE:
          $mod += 222;
          break;
        case FILE_EXECUTABLE:
          $mod += 111;
          break;
      }
    }
  }

  if (@mkdir($file, intval("0$mod", 8))) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

/**
 * Attempt to fix file permissions.
 *
585 586 587 588 589 590 591 592 593
 * The general approach here is that, because we do not know the security
 * setup of the webserver, we apply our permission changes to all three
 * digits of the file permission (i.e. user, group and all).
 *
 * To ensure that the values behave as expected (and numbers don't carry
 * from one digit to the next) we do the calculation on the octal value
 * using bitwise operations. This lets us remove, for example, 0222 from
 * 0700 and get the correct value of 0500.
 *
594 595 596 597 598 599 600 601 602 603 604
 * @param $file
 *  The name of the file with permissions to fix.
 * @param $mask
 *  The desired permissions for the file.
 * @param $message
 *  (optional) Whether to output messages. Defaults to TRUE.
 *
 * @return
 *  TRUE/FALSE whether or not we were able to fix the file's permissions.
 */
function drupal_install_fix_file($file, $mask, $message = TRUE) {
605
  $mod = fileperms($file) & 0777;
606
  $masks = array(FILE_READABLE, FILE_WRITABLE, FILE_EXECUTABLE, FILE_NOT_READABLE, FILE_NOT_WRITABLE, FILE_NOT_EXECUTABLE);
607 608 609 610 611

  // FILE_READABLE, FILE_WRITABLE, and FILE_EXECUTABLE permission strings
  // can theoretically be 0400, 0200, and 0100 respectively, but to be safe
  // we set all three access types in case the administrator intends to
  // change the owner of settings.php after installation.
612 613 614 615 616
  foreach ($masks as $m) {
    if ($mask & $m) {
      switch ($m) {
        case FILE_READABLE:
          if (!is_readable($file)) {
617
            $mod |= 0444;
618 619 620 621
          }
          break;
        case FILE_WRITABLE:
          if (!is_writable($file)) {
622
            $mod |= 0222;
623 624 625 626
          }
          break;
        case FILE_EXECUTABLE:
          if (!is_executable($file)) {
627
            $mod |= 0111;
628 629 630 631
          }
          break;
        case FILE_NOT_READABLE:
          if (is_readable($file)) {
632
            $mod &= ~0444;
633 634 635 636
          }
          break;
        case FILE_NOT_WRITABLE:
          if (is_writable($file)) {
637
            $mod &= ~0222;
638 639 640 641
          }
          break;
        case FILE_NOT_EXECUTABLE:
          if (is_executable($file)) {
642
            $mod &= ~0111;
643 644 645 646 647 648
          }
          break;
      }
    }
  }

649 650 651 652
  // chmod() will work if the web server is running as owner of the file.
  // If PHP safe_mode is enabled the currently executing script must also
  // have the same owner.
  if (@chmod($file, $mod)) {
653 654 655 656 657 658 659
    return TRUE;
  }
  else {
    return FALSE;
  }
}

660 661 662 663 664 665 666 667 668

/**
 * Send the user to a different installer page. This issues an on-site HTTP
 * redirect. Messages (and errors) are erased.
 *
 * @param $path
 *   An installer path.
 */
function install_goto($path) {
669
  global $base_url;
670
  header('Location: ' . $base_url . '/' . $path);
671
  header('Cache-Control: no-cache'); // Not a permanent redirect.
672 673 674
  exit();
}

675
/**
676 677 678
 * Hardcoded function for doing the equivalent of t() during
 * the install process, when database, theme, and localization
 * system is possibly not yet available.
679 680
 */
function st($string, $args = array()) {
drumm's avatar
drumm committed
681 682 683 684 685
  static $locale_strings = NULL;
  global $profile, $install_locale;

  if (!isset($locale_strings)) {
    $locale_strings = array();
686
    $filename = './profiles/' . $profile . '/translations/' . $install_locale . '.po';
drumm's avatar
drumm committed
687 688 689 690 691 692 693 694
    if (file_exists($filename)) {
      require_once './includes/locale.inc';
      $file = (object) array('filepath' => $filename);
      _locale_import_read_po('mem-store', $file);
      $locale_strings = _locale_import_one_string('mem-report');
    }
  }

695
  require_once './includes/theme.inc';
696
  // Transform arguments before inserting them
697
  foreach ($args as $key => $value) {
698 699 700 701 702 703 704 705
    switch ($key[0]) {
      // Escaped only
      case '@':
        $args[$key] = check_plain($value);
        break;
      // Escaped and placeholder
      case '%':
      default:
706
        $args[$key] = '<em>' . check_plain($value) . '</em>';
707 708 709 710
        break;
      // Pass-through
      case '!':
    }
711
  }
712
  return strtr((!empty($locale_strings[$string]) ? $locale_strings[$string] : $string), $args);
713
}
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732

/**
 * Check a profile's requirements.
 *
 * @param profile
 *   Name of profile to check.
 */
function drupal_check_profile($profile) {
  include_once './includes/file.inc';

  $profile_file = "./profiles/$profile/$profile.profile";

  if (!isset($profile) || !file_exists($profile_file)) {
    install_no_profile_error();
  }

  require_once($profile_file);

  // Get a list of modules required by this profile.
733
  $function = $profile . '_profile_modules';
734
  $module_list = array_unique(array_merge(drupal_required_modules(), $function()));
735 736 737 738 739 740 741 742

  // Get a list of all .install files.
  $installs = drupal_get_install_files($module_list);

  // Collect requirement testing results
  $requirements = array();
  foreach ($installs as $install) {
    require_once $install->filename;
743 744 745
    $function = $install->name. '_requirements';
    if (function_exists($function)) {
      $requirements = array_merge($requirements, $function('install'));
746
    }
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
  }
  return $requirements;
}

/**
 * Extract highest severity from requirements array.
 */
function drupal_requirements_severity(&$requirements) {
  $severity = REQUIREMENT_OK;
  foreach ($requirements as $requirement) {
    if (isset($requirement['severity'])) {
      $severity = max($severity, $requirement['severity']);
    }
  }
  return $severity;
}

/**
 * Check a module's requirements.
 */
function drupal_check_module($module) {
  // Include install file
  $install = drupal_get_install_files(array($module));
  if (isset($install[$module])) {
    require_once $install[$module]->filename;

    // Check requirements
    $requirements = module_invoke($module, 'requirements', 'install');
    if (is_array($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
      // Print any error messages
      foreach ($requirements as $requirement) {
        if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
779 780
          $message = $requirement['description'];
          if (isset($requirement['value']) && $requirement['value']) {
781
            $message .= ' (' . t('Currently using !item !version', array('!item' => $requirement['title'], '!version' => $requirement['value'])) . ')';
782 783
          }
          drupal_set_message($message, 'error');
784 785 786 787 788 789 790
        }
      }
      return FALSE;
    }
  }
  return TRUE;
}