[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/ -> install.php (source)

   1  <?php
   2  // $Id: install.php,v 1.113.2.13 2010/12/06 06:50:56 goba Exp $
   3  
   4  require_once  './includes/install.inc';
   5  
   6  define('MAINTENANCE_MODE', 'install');
   7  
   8  /**
   9   * The Drupal installation happens in a series of steps. We begin by verifying
  10   * that the current environment meets our minimum requirements. We then go
  11   * on to verify that settings.php is properly configured. From there we
  12   * connect to the configured database and verify that it meets our minimum
  13   * requirements. Finally we can allow the user to select an installation
  14   * profile and complete the installation process.
  15   *
  16   * @param $phase
  17   *   The installation phase we should proceed to.
  18   */
  19  function install_main() {
  20    require_once  './includes/bootstrap.inc';
  21    drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
  22  
  23    // This must go after drupal_bootstrap(), which unsets globals!
  24    global $profile, $install_locale, $conf;
  25  
  26    require_once  './modules/system/system.install';
  27    require_once  './includes/file.inc';
  28  
  29    // Ensure correct page headers are sent (e.g. caching)
  30    drupal_page_header();
  31  
  32    // Set up $language, so t() caller functions will still work.
  33    drupal_init_language();
  34  
  35    // Load module basics (needed for hook invokes).
  36    include_once  './includes/module.inc';
  37    $module_list['system']['filename'] = 'modules/system/system.module';
  38    $module_list['filter']['filename'] = 'modules/filter/filter.module';
  39    module_list(TRUE, FALSE, FALSE, $module_list);
  40    drupal_load('module', 'system');
  41    drupal_load('module', 'filter');
  42  
  43    // Install profile chosen, set the global immediately.
  44    // This needs to be done before the theme cache gets 
  45    // initialized in drupal_maintenance_theme().
  46    if (!empty($_GET['profile'])) {
  47      $profile = preg_replace('/[^a-zA-Z_0-9]/', '', $_GET['profile']);
  48    }
  49  
  50    // Set up theme system for the maintenance page.
  51    drupal_maintenance_theme();
  52  
  53    // Check existing settings.php.
  54    $verify = install_verify_settings();
  55  
  56    if ($verify) {
  57      // Since we have a database connection, we use the normal cache system.
  58      // This is important, as the installer calls into the Drupal system for
  59      // the clean URL checks, so we should maintain the cache properly.
  60      require_once  './includes/cache.inc';
  61      $conf['cache_inc'] = './includes/cache.inc';
  62  
  63      // Establish a connection to the database.
  64      require_once  './includes/database.inc';
  65      db_set_active();
  66  
  67      // Check if Drupal is installed.
  68      $task = install_verify_drupal();
  69      if ($task == 'done') {
  70        install_already_done_error();
  71      }
  72    }
  73    else {
  74      // Since no persistent storage is available yet, and functions that check
  75      // for cached data will fail, we temporarily replace the normal cache
  76      // system with a stubbed-out version that short-circuits the actual
  77      // caching process and avoids any errors.
  78      require_once  './includes/cache-install.inc';
  79      $conf['cache_inc'] = './includes/cache-install.inc';
  80  
  81      $task = NULL;
  82    }
  83  
  84    // No profile was passed in GET, ask the user.
  85    if (empty($_GET['profile'])) {
  86      if ($profile = install_select_profile()) {
  87        install_goto("install.php?profile=$profile");
  88      }
  89      else {
  90        install_no_profile_error();
  91      }
  92    }
  93  
  94    // Load the profile.
  95    require_once "./profiles/$profile/$profile.profile";
  96  
  97    // Locale selection
  98    if (!empty($_GET['locale'])) {
  99      $install_locale = preg_replace('/[^a-zA-Z_0-9\-]/', '', $_GET['locale']);
 100    }
 101    elseif (($install_locale = install_select_locale($profile)) !== FALSE) {
 102      install_goto("install.php?profile=$profile&locale=$install_locale");
 103    }
 104  
 105    // Tasks come after the database is set up
 106    if (!$task) {
 107      global $db_url;
 108  
 109      if (!$verify && !empty($db_url)) {
 110        // Do not install over a configured settings.php.
 111        install_already_done_error();
 112      }
 113  
 114      // Check the installation requirements for Drupal and this profile.
 115      install_check_requirements($profile, $verify);
 116  
 117      // Verify existence of all required modules.
 118      $modules = drupal_verify_profile($profile, $install_locale);
 119  
 120      // If any error messages are set now, it means a requirement problem.
 121      $messages = drupal_set_message();
 122      if (!empty($messages['error'])) {
 123        install_task_list('requirements');
 124        drupal_set_title(st('Requirements problem'));
 125        print theme('install_page', '');
 126        exit;
 127      }
 128  
 129      // Change the settings.php information if verification failed earlier.
 130      // Note: will trigger a redirect if database credentials change.
 131      if (!$verify) {
 132        install_change_settings($profile, $install_locale);
 133      }
 134  
 135      // Install system.module.
 136      drupal_install_system();
 137      // Save the list of other modules to install for the 'profile-install'
 138      // task. variable_set() can be used now that system.module is installed
 139      // and drupal is bootstrapped.
 140      variable_set('install_profile_modules', array_diff($modules, array('system')));
 141    }
 142  
 143    // The database is set up, turn to further tasks.
 144    install_tasks($profile, $task);
 145  }
 146  
 147  /**
 148   * Verify if Drupal is installed.
 149   */
 150  function install_verify_drupal() {
 151    // Read the variable manually using the @ so we don't trigger an error if it fails.
 152    $result = @db_query("SELECT value FROM {variable} WHERE name = '%s'", 'install_task');
 153    if ($result) {
 154      return unserialize(db_result($result));
 155    }
 156  }
 157  
 158  /**
 159   * Verify existing settings.php
 160   */
 161  function install_verify_settings() {
 162    global $db_prefix, $db_type, $db_url;
 163  
 164    // Verify existing settings (if any).
 165    if (!empty($db_url)) {
 166      // We need this because we want to run form_get_errors.
 167      include_once  './includes/form.inc';
 168  
 169      $url = parse_url(is_array($db_url) ? $db_url['default'] : $db_url);
 170      $db_user = urldecode($url['user']);
 171      $db_pass = isset($url['pass']) ? urldecode($url['pass']) : NULL;
 172      $db_host = urldecode($url['host']);
 173      $db_port = isset($url['port']) ? urldecode($url['port']) : '';
 174      $db_path = ltrim(urldecode($url['path']), '/');
 175      $settings_file = './'. conf_path(FALSE, TRUE) .'/settings.php';
 176  
 177      $form_state = array();
 178      _install_settings_form_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_port, $db_path, $settings_file, $form_state);
 179      if (!form_get_errors()) {
 180        return TRUE;
 181      }
 182    }
 183    return FALSE;
 184  }
 185  
 186  /**
 187   * Configure and rewrite settings.php.
 188   */
 189  function install_change_settings($profile = 'default', $install_locale = '') {
 190    global $db_url, $db_type, $db_prefix;
 191  
 192    $url = parse_url(is_array($db_url) ? $db_url['default'] : $db_url);
 193    $db_user = isset($url['user']) ? urldecode($url['user']) : '';
 194    $db_pass = isset($url['pass']) ? urldecode($url['pass']) : '';
 195    $db_host = isset($url['host']) ? urldecode($url['host']) : '';
 196    $db_port = isset($url['port']) ? urldecode($url['port']) : '';
 197    $db_path = ltrim(urldecode($url['path']), '/');
 198    $conf_path = './'. conf_path(FALSE, TRUE);
 199    $settings_file = $conf_path .'/settings.php';
 200  
 201    // We always need this because we want to run form_get_errors.
 202    include_once  './includes/form.inc';
 203    install_task_list('database');
 204  
 205    $output = drupal_get_form('install_settings_form', $profile, $install_locale, $settings_file, $db_url, $db_type, $db_prefix, $db_user, $db_pass, $db_host, $db_port, $db_path);
 206    drupal_set_title(st('Database configuration'));
 207    print theme('install_page', $output);
 208    exit;
 209  }
 210  
 211  
 212  /**
 213   * Form API array definition for install_settings.
 214   */
 215  function install_settings_form(&$form_state, $profile, $install_locale, $settings_file, $db_url, $db_type, $db_prefix, $db_user, $db_pass, $db_host, $db_port, $db_path) {
 216    if (empty($db_host)) {
 217      $db_host = 'localhost';
 218    }
 219    $db_types = drupal_detect_database_types();
 220  
 221    // If both 'mysql' and 'mysqli' are available, we disable 'mysql':
 222    if (isset($db_types['mysqli'])) {
 223      unset($db_types['mysql']);
 224    }
 225  
 226    if (count($db_types) == 0) {
 227      $form['no_db_types'] = array(
 228        '#value' => st('Your web server does not appear to support any common database types. Check with your hosting provider to see if they offer any databases that <a href="@drupal-databases">Drupal supports</a>.', array('@drupal-databases' => 'http://drupal.org/node/270#database')),
 229      );
 230    }
 231    else {
 232      $form['basic_options'] = array(
 233        '#type' => 'fieldset',
 234        '#title' => st('Basic options'),
 235        '#description' => '<p>'. st('To set up your @drupal database, enter the following information.', array('@drupal' => drupal_install_profile_name())) .'</p>',
 236      );
 237  
 238      if (count($db_types) > 1) {
 239        $form['basic_options']['db_type'] = array(
 240          '#type' => 'radios',
 241          '#title' => st('Database type'),
 242          '#required' => TRUE,
 243          '#options' => $db_types,
 244          '#default_value' => ($db_type ? $db_type : current($db_types)),
 245          '#description' => st('The type of database your @drupal data will be stored in.', array('@drupal' => drupal_install_profile_name())),
 246        );
 247        $db_path_description = st('The name of the database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('@drupal' => drupal_install_profile_name()));
 248      }
 249      else {
 250        if (count($db_types) == 1) {
 251          $db_types = array_values($db_types);
 252          $form['basic_options']['db_type'] = array(
 253            '#type' => 'hidden',
 254            '#value' => $db_types[0],
 255          );
 256          $db_path_description = st('The name of the %db_type database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('%db_type' => $db_types[0], '@drupal' => drupal_install_profile_name()));
 257        }
 258      }
 259  
 260      // Database name
 261      $form['basic_options']['db_path'] = array(
 262        '#type' => 'textfield',
 263        '#title' => st('Database name'),
 264        '#default_value' => $db_path,
 265        '#size' => 45,
 266        '#required' => TRUE,
 267        '#description' => $db_path_description
 268      );
 269  
 270      // Database username
 271      $form['basic_options']['db_user'] = array(
 272        '#type' => 'textfield',
 273        '#title' => st('Database username'),
 274        '#default_value' => $db_user,
 275        '#size' => 45,
 276        '#required' => TRUE,
 277      );
 278  
 279      // Database username
 280      $form['basic_options']['db_pass'] = array(
 281        '#type' => 'password',
 282        '#title' => st('Database password'),
 283        '#default_value' => $db_pass,
 284        '#size' => 45,
 285      );
 286  
 287      $form['advanced_options'] = array(
 288        '#type' => 'fieldset',
 289        '#title' => st('Advanced options'),
 290        '#collapsible' => TRUE,
 291        '#collapsed' => TRUE,
 292        '#description' => st("These options are only necessary for some sites. If you're not sure what you should enter here, leave the default settings or check with your hosting provider.")
 293      );
 294  
 295      // Database host
 296      $form['advanced_options']['db_host'] = array(
 297        '#type' => 'textfield',
 298        '#title' => st('Database host'),
 299        '#default_value' => $db_host,
 300        '#size' => 45,
 301        // Hostnames can be 255 characters long.
 302        '#maxlength' => 255,
 303        '#required' => TRUE,
 304        '#description' => st('If your database is located on a different server, change this.'),
 305      );
 306  
 307      // Database port
 308      $form['advanced_options']['db_port'] = array(
 309        '#type' => 'textfield',
 310        '#title' => st('Database port'),
 311        '#default_value' => $db_port,
 312        '#size' => 45,
 313        // The maximum port number is 65536, 5 digits.
 314        '#maxlength' => 5,
 315        '#description' => st('If your database server is listening to a non-standard port, enter its number.'),
 316      );
 317  
 318      // Table prefix
 319      $prefix = ($profile == 'default') ? 'drupal_' : $profile .'_';
 320      $form['advanced_options']['db_prefix'] = array(
 321        '#type' => 'textfield',
 322        '#title' => st('Table prefix'),
 323        '#default_value' => $db_prefix,
 324        '#size' => 45,
 325        '#description' => st('If more than one application will be sharing this database, enter a table prefix such as %prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_name(), '%prefix' => $prefix)),
 326      );
 327  
 328      $form['save'] = array(
 329        '#type' => 'submit',
 330        '#value' => st('Save and continue'),
 331      );
 332  
 333      $form['errors'] = array();
 334      $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file);
 335      $form['_db_url'] = array('#type' => 'value');
 336      $form['#action'] = "install.php?profile=$profile". ($install_locale ? "&locale=$install_locale" : '');
 337      $form['#redirect'] = FALSE;
 338    }
 339    return $form;
 340  }
 341  
 342  /**
 343   * Form API validate for install_settings form.
 344   */
 345  function install_settings_form_validate($form, &$form_state) {
 346    global $db_url;
 347    _install_settings_form_validate($form_state['values']['db_prefix'], $form_state['values']['db_type'], $form_state['values']['db_user'], $form_state['values']['db_pass'], $form_state['values']['db_host'], $form_state['values']['db_port'], $form_state['values']['db_path'], $form_state['values']['settings_file'], $form_state, $form);
 348  }
 349  
 350  /**
 351   * Helper function for install_settings_validate.
 352   */
 353  function _install_settings_form_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_port, $db_path, $settings_file, &$form_state, $form = NULL) {
 354    global $db_url;
 355  
 356    // Verify the table prefix
 357    if (!empty($db_prefix) && is_string($db_prefix) && !preg_match('/^[A-Za-z0-9_.]+$/', $db_prefix)) {
 358      form_set_error('db_prefix', st('The database table prefix you have entered, %db_prefix, is invalid. The table prefix can only contain alphanumeric characters, periods, or underscores.', array('%db_prefix' => $db_prefix)), 'error');
 359    }
 360  
 361    if (!empty($db_port) && !is_numeric($db_port)) {
 362      form_set_error('db_port', st('Database port must be a number.'));
 363    }
 364  
 365    // Check database type
 366    if (!isset($form)) {
 367      $_db_url = is_array($db_url) ? $db_url['default'] : $db_url;
 368      $db_type = substr($_db_url, 0, strpos($_db_url, '://'));
 369    }
 370    $databases = drupal_detect_database_types();
 371    if (!in_array($db_type, $databases)) {
 372      form_set_error('db_type', st("In your %settings_file file you have configured @drupal to use a %db_type server, however your PHP installation currently does not support this database type.", array('%settings_file' => $settings_file, '@drupal' => drupal_install_profile_name(), '%db_type' => $db_type)));
 373    }
 374    else {
 375      // Verify
 376      $db_url = $db_type .'://'. urlencode($db_user) . ($db_pass ? ':'. urlencode($db_pass) : '') .'@'. ($db_host ? urlencode($db_host) : 'localhost') . ($db_port ? ":$db_port" : '') .'/'. urlencode($db_path);
 377      if (isset($form)) {
 378        form_set_value($form['_db_url'], $db_url, $form_state);
 379      }
 380      $success = array();
 381  
 382      $function = 'drupal_test_'. $db_type;
 383      if (!$function($db_url, $success)) {
 384        if (isset($success['CONNECT'])) {
 385          form_set_error('db_type', st('In order for Drupal to work, and to continue with the installation process, you must resolve all permission issues reported above. We were able to verify that we have permission for the following commands: %commands. For more help with configuring your database server, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what any of this means you should probably contact your hosting provider.', array('%commands' => implode($success, ', '))));
 386        }
 387        else {
 388          form_set_error('db_type', '');
 389        }
 390      }
 391    }
 392  }
 393  
 394  /**
 395   * Form API submit for install_settings form.
 396   */
 397  function install_settings_form_submit($form, &$form_state) {
 398    global $profile, $install_locale;
 399  
 400    // Update global settings array and save
 401    $settings['db_url'] = array(
 402      'value'    => $form_state['values']['_db_url'],
 403      'required' => TRUE,
 404    );
 405    $settings['db_prefix'] = array(
 406      'value'    => $form_state['values']['db_prefix'],
 407      'required' => TRUE,
 408    );
 409    drupal_rewrite_settings($settings);
 410  
 411    // Continue to install profile step
 412    install_goto("install.php?profile=$profile". ($install_locale ? "&locale=$install_locale" : ''));
 413  }
 414  
 415  /**
 416   * Find all .profile files.
 417   */
 418  function install_find_profiles() {
 419    return file_scan_directory('./profiles', '\.profile$', array('.', '..', 'CVS'), 0, TRUE, 'name', 0);
 420  }
 421  
 422  /**
 423   * Allow admin to select which profile to install.
 424   *
 425   * @return
 426   *   The selected profile.
 427   */
 428  function install_select_profile() {
 429    include_once  './includes/form.inc';
 430  
 431    $profiles = install_find_profiles();
 432    // Don't need to choose profile if only one available.
 433    if (sizeof($profiles) == 1) {
 434      $profile = array_pop($profiles);
 435      require_once $profile->filename;
 436      return $profile->name;
 437    }
 438    elseif (sizeof($profiles) > 1) {
 439      foreach ($profiles as $profile) {
 440        if (!empty($_POST['profile']) && ($_POST['profile'] == $profile->name)) {
 441          return $profile->name;
 442        }
 443      }
 444  
 445      install_task_list('profile-select');
 446  
 447      drupal_set_title(st('Select an installation profile'));
 448      print theme('install_page', drupal_get_form('install_select_profile_form', $profiles));
 449      exit;
 450    }
 451  }
 452  
 453  /**
 454   * Form API array definition for the profile selection form.
 455   *
 456   * @param $form_state
 457   *   Array of metadata about state of form processing.
 458   * @param $profile_files
 459   *   Array of .profile files, as returned from file_scan_directory().
 460   */
 461  function install_select_profile_form(&$form_state, $profile_files) {
 462    $profiles = array();
 463    $names = array();
 464  
 465    foreach ($profile_files as $profile) {
 466      include_once($profile->filename);
 467  
 468      // Load profile details and store them for later retrieval.
 469      $function = $profile->name .'_profile_details';
 470      if (function_exists($function)) {
 471        $details = $function();
 472      }
 473      $profiles[$profile->name] = $details;
 474  
 475      // Determine the name of the profile; default to file name if defined name
 476      // is unspecified.
 477      $name = isset($details['name']) ? $details['name'] : $profile->name;
 478      $names[$profile->name] = $name;
 479    }
 480  
 481    // Display radio buttons alphabetically by human-readable name. 
 482    natcasesort($names);
 483    foreach ($names as $profile => $name) {
 484      $form['profile'][$name] = array(
 485        '#type' => 'radio',
 486        '#value' => 'default',
 487        '#return_value' => $profile,
 488        '#title' => $name,
 489        '#description' => isset($profiles[$profile]['description']) ? $profiles[$profile]['description'] : '',
 490        '#parents' => array('profile'),
 491      );
 492    }
 493    $form['submit'] =  array(
 494      '#type' => 'submit',
 495      '#value' => st('Save and continue'),
 496    );
 497    return $form;
 498  }
 499  
 500  /**
 501   * Find all .po files for the current profile.
 502   */
 503  function install_find_locales($profilename) {
 504    $locales = file_scan_directory('./profiles/'. $profilename .'/translations', '\.po$', array('.', '..', 'CVS'), 0, FALSE);
 505    array_unshift($locales, (object) array('name' => 'en'));
 506    return $locales;
 507  }
 508  
 509  /**
 510   * Allow admin to select which locale to use for the current profile.
 511   *
 512   * @return
 513   *   The selected language.
 514   */
 515  function install_select_locale($profilename) {
 516    include_once  './includes/file.inc';
 517    include_once  './includes/form.inc';
 518  
 519    // Find all available locales.
 520    $locales = install_find_locales($profilename);
 521  
 522    // If only the built-in (English) language is available,
 523    // and we are using the default profile, inform the user
 524    // that the installer can be localized. Otherwise we assume
 525    // the user know what he is doing.
 526    if (count($locales) == 1) {
 527      if ($profilename == 'default') {
 528        install_task_list('locale-select');
 529        drupal_set_title(st('Choose language'));
 530        if (!empty($_GET['localize'])) {
 531          $output = '<p>'. st('With the addition of an appropriate translation package, this installer is capable of proceeding in another language of your choice. To install and use Drupal in a language other than English:') .'</p>';
 532          $output .= '<ul><li>'. st('Determine if <a href="@translations" target="_blank">a translation of this Drupal version</a> is available in your language of choice. A translation is provided via a translation package; each translation package enables the display of a specific version of Drupal in a specific language. Not all languages are available for every version of Drupal.', array('@translations' => 'http://localize.drupal.org')) .'</li>';
 533          $output .= '<li>'. st('If an alternative translation package of your choice is available, download and extract its contents to your Drupal root directory.') .'</li>';
 534          $output .= '<li>'. st('Return to choose language using the second link below and select your desired language from the displayed list. Reloading the page allows the list to automatically adjust to the presence of new translation packages.') .'</li>';
 535          $output .= '</ul><p>'. st('Alternatively, to install and use Drupal in English, or to defer the selection of an alternative language until after installation, select the first link below.') .'</p>';
 536          $output .= '<p>'. st('How should the installation continue?') .'</p>';
 537          $output .= '<ul><li><a href="install.php?profile='. $profilename .'&amp;locale=en">'. st('Continue installation in English') .'</a></li><li><a href="install.php?profile='. $profilename .'">'. st('Return to choose a language') .'</a></li></ul>';
 538        }
 539        else {
 540          $output = '<ul><li><a href="install.php?profile='. $profilename .'&amp;locale=en">'. st('Install Drupal in English') .'</a></li><li><a href="install.php?profile='. $profilename .'&amp;localize=true">'. st('Learn how to install Drupal in other languages') .'</a></li></ul>';
 541        }
 542        print theme('install_page', $output);
 543        exit;
 544      }
 545      // One language, but not the default profile, assume
 546      // the user knows what he is doing.
 547      return FALSE;
 548    }
 549    else {
 550      // Allow profile to pre-select the language, skipping the selection.
 551      $function = $profilename .'_profile_details';
 552      if (function_exists($function)) {
 553        $details = $function();
 554        if (isset($details['language'])) {
 555          foreach ($locales as $locale) {
 556            if ($details['language'] == $locale->name) {
 557              return $locale->name;
 558            }
 559          }
 560        }
 561      }
 562  
 563      if (!empty($_POST['locale'])) {
 564        foreach ($locales as $locale) {
 565          if ($_POST['locale'] == $locale->name) {
 566            return $locale->name;
 567          }
 568        }
 569      }
 570  
 571      install_task_list('locale-select');
 572  
 573      drupal_set_title(st('Choose language'));
 574      print theme('install_page', drupal_get_form('install_select_locale_form', $locales));
 575      exit;
 576    }
 577  }
 578  
 579  /**
 580   * Form API array definition for language selection.
 581   */
 582  function install_select_locale_form(&$form_state, $locales) {
 583    include_once  './includes/locale.inc';
 584    $languages = _locale_get_predefined_list();
 585    foreach ($locales as $locale) {
 586      // Try to use verbose locale name
 587      $name = $locale->name;
 588      if (isset($languages[$name])) {
 589        $name = $languages[$name][0] . (isset($languages[$name][1]) ? ' '. st('(@language)', array('@language' => $languages[$name][1])) : '');
 590      }
 591      $form['locale'][$locale->name] = array(
 592        '#type' => 'radio',
 593        '#return_value' => $locale->name,
 594        '#default_value' => ($locale->name == 'en' ? TRUE : FALSE),
 595        '#title' => $name . ($locale->name == 'en' ? ' '. st('(built-in)') : ''),
 596        '#parents' => array('locale')
 597      );
 598    }
 599    $form['submit'] =  array(
 600      '#type' => 'submit',
 601      '#value' => st('Select language'),
 602    );
 603    return $form;
 604  }
 605  
 606  /**
 607   * Show an error page when there are no profiles available.
 608   */
 609  function install_no_profile_error() {
 610    install_task_list('profile-select');
 611    drupal_set_title(st('No profiles available'));
 612    print theme('install_page', '<p>'. st('We were unable to find any installer profiles. Installer profiles tell us what modules to enable and what schema to install in the database. A profile is necessary to continue with the installation process.') .'</p>');
 613    exit;
 614  }
 615  
 616  
 617  /**
 618   * Show an error page when Drupal has already been installed.
 619   */
 620  function install_already_done_error() {
 621    global $base_url;
 622  
 623    drupal_set_title(st('Drupal already installed'));
 624    print theme('install_page', st('<ul><li>To start over, you must empty your existing database.</li><li>To install to a different database, edit the appropriate <em>settings.php</em> file in the <em>sites</em> folder.</li><li>To upgrade an existing installation, proceed to the <a href="@base-url/update.php">update script</a>.</li><li>View your <a href="@base-url">existing site</a>.</li></ul>', array('@base-url' => $base_url)));
 625    exit;
 626  }
 627  
 628  /**
 629   * Tasks performed after the database is initialized.
 630   */
 631  function install_tasks($profile, $task) {
 632    global $base_url, $install_locale;
 633  
 634    // Bootstrap newly installed Drupal, while preserving existing messages.
 635    $messages = isset($_SESSION['messages']) ? $_SESSION['messages'] : '';
 636    drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 637    $_SESSION['messages'] = $messages;
 638  
 639    // URL used to direct page requests.
 640    $url = $base_url .'/install.php?locale='. $install_locale .'&profile='. $profile;
 641  
 642    // Build a page for final tasks.
 643    if (empty($task)) {
 644      variable_set('install_task', 'profile-install');
 645      $task = 'profile-install';
 646    }
 647  
 648    // We are using a list of if constructs here to allow for
 649    // passing from one task to the other in the same request.
 650  
 651    // Install profile modules.
 652    if ($task == 'profile-install') {
 653      $modules = variable_get('install_profile_modules', array());
 654      $files = module_rebuild_cache();
 655      variable_del('install_profile_modules');
 656      $operations = array();
 657      foreach ($modules as $module) {
 658        $operations[] = array('_install_module_batch', array($module, $files[$module]->info['name']));
 659      }
 660      $batch = array(
 661        'operations' => $operations,
 662        'finished' => '_install_profile_batch_finished',
 663        'title' => st('Installing @drupal', array('@drupal' => drupal_install_profile_name())),
 664        'error_message' => st('The installation has encountered an error.'),
 665      );
 666      // Start a batch, switch to 'profile-install-batch' task. We need to
 667      // set the variable here, because batch_process() redirects.
 668      variable_set('install_task', 'profile-install-batch');
 669      batch_set($batch);
 670      batch_process($url, $url);
 671    }
 672    // We are running a batch install of the profile's modules.
 673    // This might run in multiple HTTP requests, constantly redirecting
 674    // to the same address, until the batch finished callback is invoked
 675    // and the task advances to 'locale-initial-import'.
 676    if ($task == 'profile-install-batch') {
 677      include_once  'includes/batch.inc';
 678      $output = _batch_page();
 679    }
 680  
 681    // Import interface translations for the enabled modules.
 682    if ($task == 'locale-initial-import') {
 683      if (!empty($install_locale) && ($install_locale != 'en')) {
 684        include_once  'includes/locale.inc';
 685        // Enable installation language as default site language.
 686        locale_add_language($install_locale, NULL, NULL, NULL, NULL, NULL, 1, TRUE);
 687        // Collect files to import for this language.
 688        $batch = locale_batch_by_language($install_locale, '_install_locale_initial_batch_finished');
 689        if (!empty($batch)) {
 690          // Remember components we cover in this batch set.
 691          variable_set('install_locale_batch_components', $batch['#components']);
 692          // Start a batch, switch to 'locale-batch' task. We need to
 693          // set the variable here, because batch_process() redirects.
 694          variable_set('install_task', 'locale-initial-batch');
 695          batch_set($batch);
 696          batch_process($url, $url);
 697        }
 698      }
 699      // Found nothing to import or not foreign language, go to next task.
 700      $task = 'configure';
 701    }
 702    if ($task == 'locale-initial-batch') {
 703      include_once  'includes/batch.inc';
 704      include_once  'includes/locale.inc';
 705      $output = _batch_page();
 706    }
 707  
 708    if ($task == 'configure') {
 709      if (variable_get('site_name', FALSE) || variable_get('site_mail', FALSE)) {
 710        // Site already configured: This should never happen, means re-running
 711        // the installer, possibly by an attacker after the 'install_task' variable
 712        // got accidentally blown somewhere. Stop it now.
 713        install_already_done_error();
 714      }
 715      $form = drupal_get_form('install_configure_form', $url);
 716  
 717      if (!variable_get('site_name', FALSE) && !variable_get('site_mail', FALSE)) {
 718        // Not submitted yet: Prepare to display the form.
 719        $output = $form;
 720        drupal_set_title(st('Configure site'));
 721  
 722        // Warn about settings.php permissions risk
 723        $settings_dir = './'. conf_path();
 724        $settings_file = $settings_dir .'/settings.php';
 725        if (!drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file($settings_dir, FILE_NOT_WRITABLE, 'dir')) {
 726          drupal_set_message(st('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, please consult the <a href="@handbook_url">on-line handbook</a>.', array('%dir' => $settings_dir, '%file' => $settings_file, '@handbook_url' => 'http://drupal.org/getting-started')), 'error');
 727        }
 728        else {
 729          drupal_set_message(st('All necessary changes to %dir and %file have been made. They have been set to read-only for security.', array('%dir' => $settings_dir, '%file' => $settings_file)));
 730        }
 731  
 732        // Add JavaScript validation.
 733        _user_password_dynamic_validation();
 734        drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
 735        // We add these strings as settings because JavaScript translation does not
 736        // work on install time.
 737        drupal_add_js(array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail')), 'cleanURL' => array('success' => st('Your server has been successfully tested to support this feature.'), 'failure' => st('Your system configuration does not currently support this feature. The <a href="http://drupal.org/node/15365">handbook page on Clean URLs</a> has additional troubleshooting information.'), 'testing' => st('Testing clean URLs...'))), 'setting');
 738        drupal_add_js('
 739  // Global Killswitch
 740  if (Drupal.jsEnabled) {
 741    $(document).ready(function() {
 742      Drupal.cleanURLsInstallCheck();
 743      Drupal.setDefaultTimezone();
 744    });
 745  }', 'inline');
 746        // Build menu to allow clean URL check.
 747        menu_rebuild();
 748      }
 749  
 750      else {
 751        $task = 'profile';
 752      }
 753    }
 754  
 755    // If found an unknown task or the 'profile' task, which is
 756    // reserved for profiles, hand over the control to the profile,
 757    // so it can run any number of custom tasks it defines.
 758    if (!in_array($task, install_reserved_tasks())) {
 759      $function = $profile .'_profile_tasks';
 760      if (function_exists($function)) {
 761        // The profile needs to run more code, maybe even more tasks.
 762        // $task is sent through as a reference and may be changed!
 763        $output = $function($task, $url);
 764      }
 765  
 766      // If the profile doesn't move on to a new task we assume
 767      // that it is done.
 768      if ($task == 'profile') {
 769        $task = 'profile-finished';
 770      }
 771    }
 772  
 773    // Profile custom tasks are done, so let the installer regain
 774    // control and proceed with importing the remaining translations.
 775    if ($task == 'profile-finished') {
 776      if (!empty($install_locale) && ($install_locale != 'en')) {
 777        include_once  'includes/locale.inc';
 778        // Collect files to import for this language. Skip components
 779        // already covered in the initial batch set.
 780        $batch = locale_batch_by_language($install_locale, '_install_locale_remaining_batch_finished', variable_get('install_locale_batch_components', array()));
 781        // Remove temporary variable.
 782        variable_del('install_locale_batch_components');
 783        if (!empty($batch)) {
 784          // Start a batch, switch to 'locale-remaining-batch' task. We need to
 785          // set the variable here, because batch_process() redirects.
 786          variable_set('install_task', 'locale-remaining-batch');
 787          batch_set($batch);
 788          batch_process($url, $url);
 789        }
 790      }
 791      // Found nothing to import or not foreign language, go to next task.
 792      $task = 'finished';
 793    }
 794    if ($task == 'locale-remaining-batch') {
 795      include_once  'includes/batch.inc';
 796      include_once  'includes/locale.inc';
 797      $output = _batch_page();
 798    }
 799  
 800    // Display a 'finished' page to user.
 801    if ($task == 'finished') {
 802      drupal_set_title(st('@drupal installation complete', array('@drupal' => drupal_install_profile_name())));
 803      $messages = drupal_set_message();
 804      $output = '<p>'. st('Congratulations, @drupal has been successfully installed.', array('@drupal' => drupal_install_profile_name())) .'</p>';
 805      $output .= '<p>'. (isset($messages['error']) ? st('Please review the messages above before continuing on to <a href="@url">your new site</a>.', array('@url' => url(''))) : st('You may now visit <a href="@url">your new site</a>.', array('@url' => url('')))) .'</p>';
 806      $task = 'done';
 807    }
 808  
 809    // The end of the install process. Remember profile used.
 810    if ($task == 'done') {
 811      // Rebuild menu to get content type links registered by the profile,
 812      // and possibly any other menu items created through the tasks.
 813      menu_rebuild();
 814  
 815      // Register actions declared by any modules.
 816      actions_synchronize();
 817  
 818      // Randomize query-strings on css/js files, to hide the fact that
 819      // this is a new install, not upgraded yet.
 820      _drupal_flush_css_js();
 821  
 822      variable_set('install_profile', $profile);
 823    }
 824  
 825    // Set task for user, and remember the task in the database.
 826    install_task_list($task);
 827    variable_set('install_task', $task);
 828  
 829    // Output page, if some output was required. Otherwise it is possible
 830    // that we are printing a JSON page and theme output should not be there.
 831    if (isset($output)) {
 832      print theme('maintenance_page', $output);
 833    }
 834  }
 835  
 836  /**
 837   * Batch callback for batch installation of modules.
 838   */
 839  function _install_module_batch($module, $module_name, &$context) {
 840    _drupal_install_module($module);
 841    // We enable the installed module right away, so that the module will be
 842    // loaded by drupal_bootstrap in subsequent batch requests, and other
 843    // modules possibly depending on it can safely perform their installation
 844    // steps.
 845    module_enable(array($module));
 846    $context['results'][] = $module;
 847    $context['message'] = st('Installed %module module.', array('%module' => $module_name));
 848  }
 849  
 850  /**
 851   * Finished callback for the modules install batch.
 852   *
 853   * Advance installer task to language import.
 854   */
 855  function _install_profile_batch_finished($success, $results) {
 856    variable_set('install_task', 'locale-initial-import');
 857  }
 858  
 859  /**
 860   * Finished callback for the first locale import batch.
 861   *
 862   * Advance installer task to the configure screen.
 863   */
 864  function _install_locale_initial_batch_finished($success, $results) {
 865    variable_set('install_task', 'configure');
 866  }
 867  
 868  /**
 869   * Finished callback for the second locale import batch.
 870   *
 871   * Advance installer task to the finished screen.
 872   */
 873  function _install_locale_remaining_batch_finished($success, $results) {
 874    variable_set('install_task', 'finished');
 875  }
 876  
 877  /**
 878   * The list of reserved tasks to run in the installer.
 879   */
 880  function install_reserved_tasks() {
 881    return array('configure', 'profile-install', 'profile-install-batch', 'locale-initial-import', 'locale-initial-batch', 'profile-finished', 'locale-remaining-batch', 'finished', 'done');
 882  }
 883  
 884  /**
 885   * Check installation requirements and report any errors.
 886   */
 887  function install_check_requirements($profile, $verify) {
 888  
 889    // If Drupal is not set up already, we need to create a settings file.
 890    if (!$verify) {
 891      $writable = FALSE;
 892      $conf_path = './'. conf_path(FALSE, TRUE);
 893      $settings_file = $conf_path .'/settings.php';
 894      $file = $conf_path;
 895      $exists = FALSE;
 896      // Verify that the directory exists.
 897      if (drupal_verify_install_file($conf_path, FILE_EXIST, 'dir')) {
 898        // Check to make sure a settings.php already exists.
 899        $file = $settings_file;
 900        if (drupal_verify_install_file($settings_file, FILE_EXIST)) {
 901          $exists = TRUE;
 902          // If it does, make sure it is writable.
 903          $writable = drupal_verify_install_file($settings_file, FILE_READABLE|FILE_WRITABLE);
 904        }
 905      }
 906      if (!$exists) {
 907        drupal_set_message(st('The @drupal installer requires that you create a settings file as part of the installation process.
 908  <ol>
 909  <li>Copy the %default_file file to %file.</li>
 910  <li>Change file permissions so that it is writable by the web server. If you are unsure how to grant file permissions, please consult the <a href="@handbook_url">on-line handbook</a>.</li>
 911  </ol>
 912  More details about installing Drupal are available in INSTALL.txt.', array('@drupal' => drupal_install_profile_name(), '%file' => $file, '%default_file' => $conf_path .'/default.settings.php', '@handbook_url' => 'http://drupal.org/server-permissions')), 'error');
 913      }
 914      elseif (!$writable) {
 915        drupal_set_message(st('The @drupal installer requires write permissions to %file during the installation process. If you are unsure how to grant file permissions, please consult the <a href="@handbook_url">on-line handbook</a>.', array('@drupal' => drupal_install_profile_name(), '%file' => $file, '@handbook_url' => 'http://drupal.org/server-permissions')), 'error');
 916      }
 917    }
 918  
 919    // Check the other requirements.
 920    $requirements = drupal_check_profile($profile);
 921    $severity = drupal_requirements_severity($requirements);
 922  
 923    // If there are issues, report them.
 924    if ($severity == REQUIREMENT_ERROR) {
 925  
 926      foreach ($requirements as $requirement) {
 927        if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
 928          $message = $requirement['description'];
 929          if (isset($requirement['value']) && $requirement['value']) {
 930            $message .= ' ('. st('Currently using !item !version', array('!item' => $requirement['title'], '!version' => $requirement['value'])) .')';
 931          }
 932          drupal_set_message($message, 'error');
 933        }
 934      }
 935    }
 936    if ($severity == REQUIREMENT_WARNING) {
 937  
 938      foreach ($requirements as $requirement) {
 939        if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_WARNING) {
 940          $message = $requirement['description'];
 941          if (isset($requirement['value']) && $requirement['value']) {
 942            $message .= ' ('. st('Currently using !item !version', array('!item' => $requirement['title'], '!version' => $requirement['value'])) .')';
 943          }
 944          drupal_set_message($message, 'warning');
 945        }
 946      }
 947    } 
 948  }
 949  
 950  /**
 951   * Add the installation task list to the current page.
 952   */
 953  function install_task_list($active = NULL) {
 954    // Default list of tasks.
 955    $tasks = array(
 956      'profile-select'        => st('Choose profile'),
 957      'locale-select'         => st('Choose language'),
 958      'requirements'          => st('Verify requirements'),
 959      'database'              => st('Set up database'),
 960      'profile-install-batch' => st('Install profile'),
 961      'locale-initial-batch'  => st('Set up translations'),
 962      'configure'             => st('Configure site'),
 963    );
 964  
 965    $profiles = install_find_profiles();
 966    $profile = isset($_GET['profile']) && isset($profiles[$_GET['profile']]) ? $_GET['profile'] : '.';
 967    $locales = install_find_locales($profile);
 968  
 969    // If we have only one profile, remove 'Choose profile'
 970    // and rename 'Install profile'.
 971    if (count($profiles) == 1) {
 972      unset($tasks['profile-select']);
 973      $tasks['profile-install-batch'] = st('Install site');
 974    }
 975  
 976    // Add tasks defined by the profile.
 977    if ($profile) {
 978      $function = $profile .'_profile_task_list';
 979      if (function_exists($function)) {
 980        $result = $function();
 981        if (is_array($result)) {
 982          $tasks += $result;
 983        }
 984      }
 985    }
 986  
 987    if (count($locales) < 2 || empty($_GET['locale']) || $_GET['locale'] == 'en') {
 988      // If not required, remove translation import from the task list.
 989      unset($tasks['locale-initial-batch']);
 990    }
 991    else {
 992      // If required, add remaining translations import task.
 993      $tasks += array('locale-remaining-batch' => st('Finish translations'));
 994    }
 995  
 996    // Add finished step as the last task.
 997    $tasks += array(
 998      'finished'     => st('Finished')
 999    );
1000  
1001    // Let the theming function know that 'finished' and 'done'
1002    // include everything, so every step is completed.
1003    if (in_array($active, array('finished', 'done'))) {
1004      $active = NULL;
1005    }
1006    drupal_set_content('left', theme_task_list($tasks, $active));
1007  }
1008  
1009  /**
1010   * Form API array definition for site configuration.
1011   */
1012  function install_configure_form(&$form_state, $url) {
1013  
1014    $form['intro'] = array(
1015      '#value' => st('To configure your website, please provide the following information.'),
1016      '#weight' => -10,
1017    );
1018    $form['site_information'] = array(
1019      '#type' => 'fieldset',
1020      '#title' => st('Site information'),
1021      '#collapsible' => FALSE,
1022    );
1023    $form['site_information']['site_name'] = array(
1024      '#type' => 'textfield',
1025      '#title' => st('Site name'),
1026      '#required' => TRUE,
1027      '#weight' => -20,
1028    );
1029    $form['site_information']['site_mail'] = array(
1030      '#type' => 'textfield',
1031      '#title' => st('Site e-mail address'),
1032      '#default_value' => ini_get('sendmail_from'),
1033      '#description' => st("The <em>From</em> address in automated e-mails sent during registration and new password requests, and other notifications. (Use an address ending in your site's domain to help prevent this e-mail being flagged as spam.)"),
1034      '#required' => TRUE,
1035      '#weight' => -15,
1036    );
1037    $form['admin_account'] = array(
1038      '#type' => 'fieldset',
1039      '#title' => st('Administrator account'),
1040      '#collapsible' => FALSE,
1041    );
1042    $form['admin_account']['account']['#tree'] = TRUE;
1043    $form['admin_account']['markup'] = array(
1044      '#value' => '<p class="description">'. st('The administrator account has complete access to the site; it will automatically be granted all permissions and can perform any administrative activity. This will be the only account that can perform certain activities, so keep its credentials safe.') .'</p>',
1045      '#weight' => -10,
1046    );
1047  
1048    $form['admin_account']['account']['name'] = array('#type' => 'textfield',
1049      '#title' => st('Username'),
1050      '#maxlength' => USERNAME_MAX_LENGTH,
1051      '#description' => st('Spaces are allowed; punctuation is not allowed except for periods, hyphens, and underscores.'),
1052      '#required' => TRUE,
1053      '#weight' => -10,
1054    );
1055  
1056    $form['admin_account']['account']['mail'] = array('#type' => 'textfield',
1057      '#title' => st('E-mail address'),
1058      '#maxlength' => EMAIL_MAX_LENGTH,
1059      '#description' => st('All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
1060      '#required' => TRUE,
1061      '#weight' => -5,
1062    );
1063    $form['admin_account']['account']['pass'] = array(
1064      '#type' => 'password_confirm',
1065      '#required' => TRUE,
1066      '#size' => 25,
1067      '#weight' => 0,
1068    );
1069  
1070    $form['server_settings'] = array(
1071      '#type' => 'fieldset',
1072      '#title' => st('Server settings'),
1073      '#collapsible' => FALSE,
1074    );
1075    $form['server_settings']['date_default_timezone'] = array(
1076      '#type' => 'select',
1077      '#title' => st('Default time zone'),
1078      '#default_value' => 0,
1079      '#options' => _system_zonelist(),
1080      '#description' => st('By default, dates in this site will be displayed in the chosen time zone.'),
1081      '#weight' => 5,
1082    );
1083  
1084    $form['server_settings']['clean_url'] = array(
1085      '#type' => 'radios',
1086      '#title' => st('Clean URLs'),
1087      '#default_value' => 0,
1088      '#options' => array(0 => st('Disabled'), 1 => st('Enabled')),
1089      '#description' => st('This option makes Drupal emit "clean" URLs (i.e. without <code>?q=</code> in the URL).'),
1090      '#disabled' => TRUE,
1091      '#prefix' => '<div id="clean-url" class="install">',
1092      '#suffix' => '</div>',
1093      '#weight' => 10,
1094    );
1095  
1096    $form['server_settings']['update_status_module'] = array(
1097      '#type' => 'checkboxes',
1098      '#title' => st('Update notifications'),
1099      '#options' => array(1 => st('Check for updates automatically')),
1100      '#default_value' => array(1),
1101      '#description' => st('With this option enabled, Drupal will notify you when new releases are available. This will significantly enhance your site\'s security and is <strong>highly recommended</strong>. This requires your site to periodically send anonymous information on its installed components to <a href="@drupal">drupal.org</a>. For more information please see the <a href="@update">update notification information</a>.', array('@drupal' => 'http://drupal.org', '@update' => 'http://drupal.org/handbook/modules/update')),
1102      '#weight' => 15,
1103    );
1104  
1105    $form['submit'] = array(
1106      '#type' => 'submit',
1107      '#value' => st('Save and continue'),
1108      '#weight' => 15,
1109    );
1110    $form['#action'] = $url;
1111    $form['#redirect'] = FALSE;
1112  
1113    // Allow the profile to alter this form. $form_state isn't available
1114    // here, but to conform to the hook_form_alter() signature, we pass
1115    // an empty array.
1116    $hook_form_alter = $_GET['profile'] .'_form_alter';
1117    if (function_exists($hook_form_alter)) {
1118      $hook_form_alter($form, array(), 'install_configure');
1119    }
1120    return $form;
1121  }
1122  
1123  /**
1124   * Form API validate for the site configuration form.
1125   */
1126  function install_configure_form_validate($form, &$form_state) {
1127    if ($error = user_validate_name($form_state['values']['account']['name'])) {
1128      form_error($form['admin_account']['account']['name'], $error);
1129    }
1130    if ($error = user_validate_mail($form_state['values']['account']['mail'])) {
1131      form_error($form['admin_account']['account']['mail'], $error);
1132    }
1133    if ($error = user_validate_mail($form_state['values']['site_mail'])) {
1134      form_error($form['site_information']['site_mail'], $error);
1135    }
1136  }
1137  
1138  /**
1139   * Form API submit for the site configuration form.
1140   */
1141  function install_configure_form_submit($form, &$form_state) {
1142    global $user;
1143  
1144    variable_set('site_name', $form_state['values']['site_name']);
1145    variable_set('site_mail', $form_state['values']['site_mail']);
1146    variable_set('date_default_timezone', $form_state['values']['date_default_timezone']);
1147  
1148    // Enable update.module if this option was selected.
1149    if ($form_state['values']['update_status_module'][1]) {
1150      drupal_install_modules(array('update'));
1151    }
1152  
1153    // Turn this off temporarily so that we can pass a password through.
1154    variable_set('user_email_verification', FALSE);
1155    $form_state['old_values'] = $form_state['values'];
1156    $form_state['values'] = $form_state['values']['account'];
1157  
1158    // We precreated user 1 with placeholder values. Let's save the real values.
1159    $account = user_load(1);
1160    $merge_data = array('init' => $form_state['values']['mail'], 'roles' => array(), 'status' => 1);
1161    user_save($account, array_merge($form_state['values'], $merge_data));
1162    // Log in the first user.
1163    user_authenticate($form_state['values']);
1164    $form_state['values'] = $form_state['old_values'];
1165    unset($form_state['old_values']);
1166    variable_set('user_email_verification', TRUE);
1167  
1168    if (isset($form_state['values']['clean_url'])) {
1169      variable_set('clean_url', $form_state['values']['clean_url']);
1170    }
1171    // The user is now logged in, but has no session ID yet, which
1172    // would be required later in the request, so remember it.
1173    $user->sid = session_id();
1174  
1175    // Record when this install ran.
1176    variable_set('install_time', time());
1177  }
1178  
1179  // Start the installer.
1180  install_main();


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7