~ubuntu-branches/ubuntu/karmic/drupal5/karmic-security

1 by Luigi Gangitano
Import upstream version 5.1
1
<?php
1.1.6 by Emanuele Gentili
Import upstream version 5.8
2
// $Id: install.php,v 1.34.2.5 2008/07/09 21:48:41 drumm Exp $
1 by Luigi Gangitano
Import upstream version 5.1
3
4
require_once './includes/install.inc';
5
6
/**
7
 * The Drupal installation happens in a series of steps. We begin by verifying
8
 * that the current environment meets our minimum requirements. We then go
9
 * on to verify that settings.php is properly configured. From there we
10
 * connect to the configured database and verify that it meets our minimum
11
 * requirements. Finally we can allow the user to select an installation
12
 * profile and complete the installation process.
13
 *
14
 * @param $phase
15
 *   The installation phase we should proceed to.
16
 */
17
function install_main() {
18
  require_once './includes/bootstrap.inc';
19
  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
1.1.3 by Stephan Hermann
Import upstream version 5.5
20
  // This must go after drupal_bootstrap(), which unsets globals!
21
  global $profile, $install_locale;
1 by Luigi Gangitano
Import upstream version 5.1
22
  require_once './modules/system/system.install';
23
  require_once './includes/file.inc';
24
25
  // Ensure correct page headers are sent (e.g. caching)
26
  drupal_page_header();
27
28
  // Check existing settings.php.
29
  $verify = install_verify_settings();
30
31
  // Drupal may already be installed.
32
  if ($verify) {
33
    // Establish a connection to the database.
34
    require_once './includes/database.inc';
35
    db_set_active();
36
    // Check if Drupal is installed.
37
    if (install_verify_drupal()) {
38
      install_already_done_error();
39
    }
40
  }
41
42
  // Load module basics (needed for hook invokes).
43
  include_once './includes/module.inc';
44
  $module_list['system']['filename'] = 'modules/system/system.module';
45
  $module_list['filter']['filename'] = 'modules/filter/filter.module';
46
  module_list(TRUE, FALSE, FALSE, $module_list);
47
  drupal_load('module', 'system');
48
  drupal_load('module', 'filter');
49
50
  // Decide which profile to use.
51
  if (!empty($_GET['profile'])) {
52
    $profile = preg_replace('/[^a-zA-Z_0-9]/', '', $_GET['profile']);
53
  }
54
  elseif ($profile = install_select_profile()) {
55
    install_goto("install.php?profile=$profile");
56
  }
57
  else {
58
    install_no_profile_error();
59
  }
60
61
  // Locale selection
62
  if (!empty($_GET['locale'])) {
63
    $install_locale = preg_replace('/[^a-zA-Z_0-9]/', '', $_GET['locale']);
64
  }
65
  elseif (($install_locale = install_select_locale($profile)) !== FALSE) {
66
    install_goto("install.php?profile=$profile&locale=$install_locale");
67
  }
68
69
  // Load the profile.
70
  require_once "./profiles/$profile/$profile.profile";
71
72
  // Check the installation requirements for Drupal and this profile.
73
  install_check_requirements($profile);
74
75
  // Change the settings.php information if verification failed earlier.
76
  // Note: will trigger a redirect if database credentials change.
77
  if (!$verify) {
78
    install_change_settings($profile, $install_locale);
79
  }
80
81
  // Verify existence of all required modules.
82
  $modules = drupal_verify_profile($profile, $install_locale);
83
  if (!$modules) {
84
    install_missing_modules_error($profile);
85
  }
86
87
  // Perform actual installation defined in the profile.
88
  drupal_install_profile($profile, $modules);
89
90
  // Warn about settings.php permissions risk
91
  $settings_file = './'. conf_path() .'/settings.php';
92
  if (!drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE)) {
93
    drupal_set_message(st('All necessary changes to %file have been made, so you should now remove write permissions to this file. Failure to remove write permissions to this file is a security risk.', array('%file' => $settings_file)), 'error');
94
  }
95
  else {
96
    drupal_set_message(st('All necessary changes to %file have been made. It has been set to read-only for security.', array('%file' => $settings_file)));
97
  }
98
99
  // Show end page.
100
  install_complete($profile);
101
}
102
103
/**
104
 * Verify if Drupal is installed.
105
 */
106
function install_verify_drupal() {
107
  $result = @db_query("SELECT name FROM {system} WHERE name = 'system'");
108
  return $result && db_result($result) == 'system';
109
}
110
111
/**
112
 * Verify existing settings.php
113
 */
114
function install_verify_settings() {
115
  global $db_prefix, $db_type, $db_url;
116
117
  // Verify existing settings (if any).
118
  if ($_SERVER['REQUEST_METHOD'] == 'GET' && $db_url != 'mysql://username:password@localhost/databasename') {
119
    // We need this because we want to run form_get_errors.
120
    include_once './includes/form.inc';
121
122
    $url = parse_url(is_array($db_url) ? $db_url['default'] : $db_url);
123
    $db_user = urldecode($url['user']);
124
    $db_pass = urldecode($url['pass']);
125
    $db_host = urldecode($url['host']);
126
    $db_port = isset($url['port']) ? urldecode($url['port']) : '';
127
    $db_path = ltrim(urldecode($url['path']), '/');
128
    $settings_file = './'. conf_path() .'/settings.php';
129
130
    _install_settings_form_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_port, $db_path, $settings_file);
131
    if (!form_get_errors()) {
132
      return TRUE;
133
    }
134
  }
135
  return FALSE;
136
}
137
138
/**
139
 * Configure and rewrite settings.php.
140
 */
141
function install_change_settings($profile = 'default', $install_locale = '') {
142
  global $db_url, $db_type, $db_prefix;
143
144
  $url = parse_url(is_array($db_url) ? $db_url['default'] : $db_url);
145
  $db_user = urldecode($url['user']);
146
  $db_pass = urldecode($url['pass']);
147
  $db_host = urldecode($url['host']);
148
  $db_port = isset($url['port']) ? urldecode($url['port']) : '';
149
  $db_path = ltrim(urldecode($url['path']), '/');
150
  $settings_file = './'. conf_path() .'/settings.php';
151
152
  // We always need this because we want to run form_get_errors.
153
  include_once './includes/form.inc';
154
  drupal_maintenance_theme();
155
156
  // Don't fill in placeholders
157
  if ($db_url == 'mysql://username:password@localhost/databasename') {
158
    $db_user = $db_pass = $db_path = '';
159
  }
1.1.2 by Stephan Hermann
Import upstream version 5.3
160
  elseif (!empty($db_url)) {
161
    // Do not install over a configured settings.php.
162
    install_already_done_error();
163
  }
1.1.6 by Emanuele Gentili
Import upstream version 5.8
164
165
  // The existing database settings are not working, so we need write access
166
  // to settings.php to change them.
167
  if (!drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_WRITABLE)) {
168
    drupal_set_message(st('The @drupal installer requires write permissions to %file during the installation process.', array('@drupal' => drupal_install_profile_name(), '%file' => $settings_file)), 'error');
169
170
    drupal_set_title(st('Drupal database setup'));
171
    print theme('install_page', '');
172
    exit;
173
  }
174
1 by Luigi Gangitano
Import upstream version 5.1
175
  $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);
176
  drupal_set_title(st('Database configuration'));
177
  print theme('install_page', $output);
178
  exit;
179
}
180
181
182
/**
183
 * Form API array definition for install_settings.
184
 */
185
function install_settings_form($profile, $install_locale, $settings_file, $db_url, $db_type, $db_prefix, $db_user, $db_pass, $db_host, $db_port, $db_path) {
186
  $db_types = drupal_detect_database_types();
187
  if (count($db_types) == 0) {
188
    $form['no_db_types'] = array(
189
      '#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')),
190
    );
191
  }
192
  else {
193
    $form['basic_options'] = array(
194
      '#type' => 'fieldset',
195
      '#title' => st('Basic options'),
196
      '#description' => '<p>'. st('To set up your @drupal database, enter the following information.', array('@drupal' => drupal_install_profile_name())) .'</p>',
197
    );
198
199
    if (count($db_types) > 1) {
200
      // Database type
201
      $db_types = drupal_detect_database_types();
202
      $form['basic_options']['db_type'] = array(
203
        '#type' => 'radios',
204
        '#title' => st('Database type'),
205
        '#required' => TRUE,
206
        '#options' => $db_types,
207
        '#default_value' => ($db_type ? $db_type : current($db_types)),
208
        '#description' => st('The type of database your @drupal data will be stored in.', array('@drupal' => drupal_install_profile_name())),
209
      );
210
      $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()));
211
    }
212
    else {
213
      if (count($db_types) == 1) {
214
        $db_types = array_values($db_types);
215
        $form['basic_options']['db_type'] = array(
216
          '#type' => 'hidden',
217
          '#value' => $db_types[0],
218
        );
219
        $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()));
220
      }
221
    }
222
223
    // Database name
224
    $form['basic_options']['db_path'] = array(
225
      '#type' => 'textfield',
226
      '#title' => st('Database name'),
227
      '#default_value' => $db_path,
228
      '#size' => 45,
229
      '#maxlength' => 45,
230
      '#required' => TRUE,
231
      '#description' => $db_path_description
232
    );
233
234
    // Database username
235
    $form['basic_options']['db_user'] = array(
236
      '#type' => 'textfield',
237
      '#title' => st('Database username'),
238
      '#default_value' => $db_user,
239
      '#size' => 45,
240
      '#maxlength' => 45,
241
      '#required' => TRUE,
242
    );
243
244
    // Database username
245
    $form['basic_options']['db_pass'] = array(
246
      '#type' => 'password',
247
      '#title' => st('Database password'),
248
      '#default_value' => $db_pass,
249
      '#size' => 45,
250
      '#maxlength' => 45,
251
    );
252
253
    $form['advanced_options'] = array(
254
      '#type' => 'fieldset',
255
      '#title' => st('Advanced options'),
256
      '#collapsible' => TRUE,
257
      '#collapsed' => TRUE,
258
      '#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.")
259
    );
260
261
    // Database host
262
    $form['advanced_options']['db_host'] = array(
263
      '#type' => 'textfield',
264
      '#title' => st('Database host'),
265
      '#default_value' => $db_host,
266
      '#size' => 45,
267
      '#maxlength' => 45,
268
      '#required' => TRUE,
269
      '#description' => st('If your database is located on a different server, change this.'),
270
    );
271
272
    // Database port
273
    $form['advanced_options']['db_port'] = array(
274
      '#type' => 'textfield',
275
      '#title' => st('Database port'),
276
      '#default_value' => $db_port,
277
      '#size' => 45,
278
      '#maxlength' => 45,
279
      '#description' => st('If your database server is listening to a non-standard port, enter its number.'),
280
    );
281
282
    // Table prefix
283
    $form['advanced_options']['db_prefix'] = array(
284
      '#type' => 'textfield',
285
      '#title' => st('Table prefix'),
286
      '#default_value' => $db_prefix,
287
      '#size' => 45,
288
      '#maxlength' => 45,
289
      '#description' => st('If more than one @drupal web site will be sharing this database, enter a table prefix for your @drupal site here.', array('@drupal' => drupal_install_profile_name())),
290
    );
291
292
    $form['save'] = array(
293
      '#type' => 'submit',
294
      '#value' => st('Save configuration'),
295
    );
296
297
    $form['errors'] = array();
298
    $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file);
299
    $form['_db_url'] = array('#type' => 'value');
300
    $form['#action'] = "install.php?profile=$profile" . ($install_locale ? "&locale=$install_locale" : '');
301
    $form['#redirect'] = NULL;
302
  }
303
  return $form;
304
}
305
/**
306
 * Form API validate for install_settings form.
307
 */
308
function install_settings_form_validate($form_id, $form_values, $form) {
309
  global $db_url;
310
  _install_settings_form_validate($form_values['db_prefix'], $form_values['db_type'], $form_values['db_user'], $form_values['db_pass'], $form_values['db_host'], $form_values['db_port'], $form_values['db_path'], $form_values['settings_file'], $form);
311
}
312
313
/**
314
 * Helper function for install_settings_validate.
315
 */
316
function _install_settings_form_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_port, $db_path, $settings_file, $form = NULL) {
317
  global $db_url;
318
319
  // Check for default username/password
320
  if ($db_user == 'username' && $db_pass == 'password') {
321
    form_set_error('db_user', st('You have configured @drupal to use the default username and password. This is not allowed for security reasons.', array('@drupal' => drupal_install_profile_name())));
322
  }
323
324
  // Verify the table prefix
1.1.1 by Michael Bienia
Import upstream version 5.2
325
  if (!empty($db_prefix) && is_string($db_prefix) && !preg_match('/^[A-Za-z0-9_]+$/', $db_prefix)) {
326
    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 or underscores.', array('%db_prefix' => $db_prefix)), 'error');
1 by Luigi Gangitano
Import upstream version 5.1
327
  }
328
329
  if (!empty($db_port) && !is_numeric($db_port)) {
330
    form_set_error('db_port', st('Database port must be a number.'));
331
  }
332
333
  // Check database type
334
  if (!isset($form)) {
335
    $_db_url = is_array($db_url) ? $db_url['default'] : $db_url;
336
    $db_type = substr($_db_url, 0, strpos($_db_url, '://'));
337
  }
338
  $databases = drupal_detect_database_types();
339
  if (!in_array($db_type, $databases)) {
340
    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)));
341
  }
342
  else {
343
    // Verify
344
    $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);
345
    if (isset($form)) {
346
      form_set_value($form['_db_url'], $db_url);
347
    }
348
    $success = array();
349
350
    $function = 'drupal_test_'. $db_type;
351
    if (!$function($db_url, $success)) {
352
      if (isset($success['CONNECT'])) {
353
        form_set_error('db_type', st('In order for Drupal to work and to proceed 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, ', '))));
354
      }
355
      else {
356
        form_set_error('db_type', '');
357
      }
358
    }
359
  }
360
}
361
362
/**
363
 * Form API submit for install_settings form.
364
 */
365
function install_settings_form_submit($form_id, $form_values) {
366
  global $profile, $install_locale;
367
368
  // Update global settings array and save
369
  $settings['db_url'] = array(
370
    'value'    => $form_values['_db_url'],
371
    'required' => TRUE,
372
  );
373
  $settings['db_prefix'] = array(
374
    'value'    => $form_values['db_prefix'],
375
    'required' => TRUE,
376
  );
377
  drupal_rewrite_settings($settings);
378
379
  // Continue to install profile step
380
  install_goto("install.php?profile=$profile" . ($install_locale ? "&locale=$install_locale" : ''));
381
}
382
383
/**
384
 * Find all .profile files and allow admin to select which to install.
385
 *
386
 * @return
387
 *   The selected profile.
388
 */
389
function install_select_profile() {
390
  include_once './includes/form.inc';
391
392
  $profiles = file_scan_directory('./profiles', '\.profile$', array('.', '..', 'CVS'), 0, TRUE, 'name', 0);
393
  // Don't need to choose profile if only one available.
394
  if (sizeof($profiles) == 1) {
395
    $profile = array_pop($profiles);
396
    require_once $profile->filename;
397
    return $profile->name;
398
  }
399
  elseif (sizeof($profiles) > 1) {
400
    foreach ($profiles as $profile) {
401
      if ($_POST['profile'] == $profile->name) {
402
        return $profile->name;
403
      }
404
    }
405
406
    drupal_maintenance_theme();
407
408
    drupal_set_title(st('Select an installation profile'));
409
    print theme('install_page', drupal_get_form('install_select_profile_form', $profiles));
410
    exit;
411
  }
412
}
413
414
function install_select_profile_form($profiles) {
415
  foreach ($profiles as $profile) {
416
    include_once($profile->filename);
417
    // Load profile details.
418
    $function = $profile->name .'_profile_details';
419
    if (function_exists($function)) {
420
      $details = $function();
421
    }
422
    // If set, used defined name. Otherwise use file name.
423
    $name = isset($details['name']) ? $details['name'] : $profile->name;
424
    $form['profile'][$name] = array(
425
      '#type' => 'radio',
426
      '#value' => 'default',
427
      '#return_value' => $profile->name,
428
      '#title' => $name,
429
      '#description' => isset($details['description']) ? $details['description'] : '',
430
      '#parents' => array('profile'),
431
    );
432
  }
433
  $form['submit'] =  array(
434
    '#type' => 'submit',
435
    '#value' => st('Save configuration'),
436
  );
437
  return $form;
438
}
439
440
/**
441
 * Find all .po files for the current profile and allow admin to select which to use.
442
 *
443
 * @return
444
 *   The selected language.
445
 */
446
function install_select_locale($profilename) {
447
  include_once './includes/file.inc';
448
  include_once './includes/form.inc';
449
450
  // Collect possible locales, add default
451
  $locales = file_scan_directory('./profiles/' . $profilename, '\.po$', array('.', '..', 'CVS'), 0, FALSE);
452
  array_unshift($locales, (object) array('name' => 'en'));
453
454
  // Don't need to choose locale if only one (English) is available.
455
  if (sizeof($locales) == 1) {
456
    return FALSE;
457
  } else {
458
    foreach ($locales as $locale) {
459
      if ($_POST['locale'] == $locale->name) {
460
        return $locale->name;
461
      }
462
    }
463
464
    drupal_maintenance_theme();
465
466
    drupal_set_title(st('Choose your preferred language'));
467
    print theme('install_page', drupal_get_form('install_select_locale_form', $locales));
468
    exit;
469
  }
470
}
471
472
function install_select_locale_form($locales) {
473
  include_once './includes/locale.inc';
474
  $languages = _locale_get_iso639_list();
475
  foreach ($locales as $locale) {
476
    // Try to use verbose locale name
477
    $name = $locale->name;
478
    if (isset($languages[$name])) {
479
      $name = $languages[$name][0] . (isset($languages[$name][1]) ? ' '. st('(@language)', array('@language' => $languages[$name][1])) : '');
480
    }
481
    $form['locale'][$locale->name] = array(
482
      '#type' => 'radio',
483
      '#return_value' => $locale->name,
484
      '#default_value' => ($locale->name == 'en' ? TRUE : FALSE),
485
      '#title' => $name . ($locale->name == 'en' ? ' '. st('(built-in)') : ''),
486
      '#parents' => array('locale')
487
    );
488
  }
489
  $form['submit'] =  array(
490
    '#type' => 'submit',
491
    '#value' => st('Save configuration'),
492
  );
493
  return $form;
494
}
495
496
/**
497
 * Show an error page when there are no profiles available.
498
 */
499
function install_no_profile_error() {
500
  drupal_maintenance_theme();
501
  drupal_set_title(st('No profiles available'));
502
  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>');
503
  exit;
504
}
505
506
507
/**
508
 * Show an error page when Drupal has already been installed.
509
 */
510
function install_already_done_error() {
511
  global $base_url;
512
513
  drupal_maintenance_theme();
514
  drupal_set_title(st('Drupal already installed'));
1.1.2 by Stephan Hermann
Import upstream version 5.3
515
  print theme('install_page', st('<ul><li>To start over, you must empty your existing database and replace the appropriate <em>settings.php</em> with an unmodified copy.</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></ul>', array('@base-url' => $base_url)));
1 by Luigi Gangitano
Import upstream version 5.1
516
  exit;
517
}
518
519
/**
520
 * Show an error page when Drupal is missing required modules.
521
 */
522
function install_missing_modules_error($profile) {
523
  global $base_url;
524
525
  drupal_maintenance_theme();
526
  drupal_set_title(st('Modules missing'));
527
  print theme('install_page', '<p>'. st('One or more required modules are missing. Please check the error messages and <a href="!url">try again</a>.', array('!url' => "install.php?profile=$profile")) .'</p>');
528
  exit;
529
}
530
531
/**
532
 * Page displayed when the installation is complete. Called from install.php.
533
 */
534
function install_complete($profile) {
535
  global $base_url;
1.1.1 by Michael Bienia
Import upstream version 5.2
536
  $output = '';
1 by Luigi Gangitano
Import upstream version 5.1
537
  // Store install profile for later use.
538
  variable_set('install_profile', $profile);
539
540
  // Bootstrap newly installed Drupal, while preserving existing messages.
541
  $messages = $_SESSION['messages'];
542
  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
543
  $_SESSION['messages'] = $messages;
544
545
  // Build final page.
546
  drupal_maintenance_theme();
547
  drupal_set_title(st('@drupal installation complete', array('@drupal' => drupal_install_profile_name())));
548
  $output .= '<p>'. st('Congratulations, @drupal has been successfully installed.', array('@drupal' => drupal_install_profile_name())) .'</p>';
549
550
  // Show profile finalization info.
551
  $function = $profile .'_profile_final';
552
  if (function_exists($function)) {
553
    // More steps required
554
    $profile_message = $function();
555
  }
556
557
  // If the profile returned a welcome message, use that instead of default.
558
  if (isset($profile_message)) {
559
    $output .= $profile_message;
560
  }
561
  else {
562
    // No more steps
563
    $output .= '<p>' . (drupal_set_message() ? 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>';
564
  }
565
  // Output page.
566
  print theme('maintenance_page', $output);
567
}
568
569
/**
570
 * Page to check installation requirements and report any errors.
571
 */
572
function install_check_requirements($profile) {
573
  $requirements = drupal_check_profile($profile);
574
  $severity = drupal_requirements_severity($requirements);
575
576
  // If there are issues, report them.
577
  if ($severity == REQUIREMENT_ERROR) {
578
    drupal_maintenance_theme();
579
580
    foreach ($requirements as $requirement) {
581
      if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
582
        drupal_set_message($requirement['description'] .' ('. st('Currently using !item !version', array('!item' => $requirement['title'], '!version' => $requirement['value'])) .')', 'error');
583
      }
584
    }
585
586
    drupal_set_title(st('Incompatible environment'));
587
    print theme('install_page', '');
588
    exit;
589
  }
590
}
591
592
install_main();