system.install 67.7 KB
Newer Older
Dries's avatar
   
Dries committed
1
<?php
2

3
use Drupal\Core\Database\Database;
4

5
6
7
8
9
/**
 * @file
 * Install, update and uninstall functions for the system module.
 */

10
11
/**
 * Test and report Drupal installation requirements.
12
13
14
15
16
 *
 * @param $phase
 *   The current system installation phase.
 * @return
 *   An array of system requirements.
17
18
 */
function system_requirements($phase) {
19
  global $base_url;
20
21
  $requirements = array();
  // Ensure translations don't break at install time
22
  $t = get_t();
23
24
25
26
27
28

  // Report Drupal version
  if ($phase == 'runtime') {
    $requirements['drupal'] = array(
      'title' => $t('Drupal'),
      'value' => VERSION,
Steven Wittens's avatar
Steven Wittens committed
29
30
      'severity' => REQUIREMENT_INFO,
      'weight' => -10,
31
    );
32
33
34
35

    // Display the currently active install profile, if the site
    // is not running the default install profile.
    $profile = drupal_get_profile();
36
    if ($profile != 'standard') {
37
      $info = system_get_info('module', $profile);
38
39
40
41
42
43
44
45
46
47
      $requirements['install_profile'] = array(
        'title' => $t('Install profile'),
        'value' => $t('%profile_name (%profile-%version)', array(
          '%profile_name' => $info['name'],
          '%profile' => $profile,
          '%version' => $info['version']
        )),
        'severity' => REQUIREMENT_INFO,
        'weight' => -9
      );
48
    }
49
50
  }

51
  // Web server information.
Steven Wittens's avatar
Steven Wittens committed
52
  $software = $_SERVER['SERVER_SOFTWARE'];
53
54
  $requirements['webserver'] = array(
    'title' => $t('Web server'),
Steven Wittens's avatar
Steven Wittens committed
55
    'value' => $software,
56
57
  );

58
59
60
61
62
63
64
65
66
67
68
69
  // Test PHP version and show link to phpinfo() if it's available
  $phpversion = phpversion();
  if (function_exists('phpinfo')) {
    $requirements['php'] = array(
      'title' => $t('PHP'),
      'value' => ($phase == 'runtime') ? $phpversion .' ('. l($t('more information'), 'admin/reports/status/php') .')' : $phpversion,
    );
  }
  else {
    $requirements['php'] = array(
      'title' => $t('PHP'),
      'value' => $phpversion,
70
      'description' => $t('The phpinfo() function has been disabled for security reasons. To see your server\'s phpinfo() information, change your PHP settings or contact your server administrator. For more information, <a href="@phpinfo">Enabling and disabling phpinfo()</a> handbook page.', array('@phpinfo' => 'http://drupal.org/node/243993')),
71
72
73
74
75
      'severity' => REQUIREMENT_INFO,
    );
  }

  if (version_compare($phpversion, DRUPAL_MINIMUM_PHP) < 0) {
76
77
    $requirements['php']['description'] = $t('Your PHP installation is too old. Drupal requires at least PHP %version.', array('%version' => DRUPAL_MINIMUM_PHP));
    $requirements['php']['severity'] = REQUIREMENT_ERROR;
78
79
    // If PHP is old, it's not safe to continue with the requirements check.
    return $requirements;
80
  }
81

82
83
84
85
86
  // Test PHP register_globals setting.
  $requirements['php_register_globals'] = array(
    'title' => $t('PHP register globals'),
  );
  $register_globals = trim(ini_get('register_globals'));
87
  // Unfortunately, ini_get() may return many different values, and we can't
88
89
90
91
92
93
94
95
96
97
98
99
  // be certain which values mean 'on', so we instead check for 'not off'
  // since we never want to tell the user that their site is secure
  // (register_globals off), when it is in fact on. We can only guarantee
  // register_globals is off if the value returned is 'off', '', or 0.
  if (!empty($register_globals) && strtolower($register_globals) != 'off') {
    $requirements['php_register_globals']['description'] = $t('<em>register_globals</em> is enabled. Drupal requires this configuration directive to be disabled. Your site may not be secure when <em>register_globals</em> is enabled. The PHP manual has instructions for <a href="http://php.net/configuration.changes">how to change configuration settings</a>.');
    $requirements['php_register_globals']['severity'] = REQUIREMENT_ERROR;
    $requirements['php_register_globals']['value'] = $t("Enabled ('@value')", array('@value' => $register_globals));
  }
  else {
    $requirements['php_register_globals']['value'] = $t('Disabled');
  }
100

101
102
103
  // Test for PHP extensions.
  $requirements['php_extensions'] = array(
    'title' => $t('PHP extensions'),
104
  );
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

  $missing_extensions = array();
  $required_extensions = array(
    'date',
    'dom',
    'filter',
    'gd',
    'hash',
    'json',
    'pcre',
    'pdo',
    'session',
    'SimpleXML',
    'SPL',
    'xml',
  );
  foreach ($required_extensions as $extension) {
    if (!extension_loaded($extension)) {
      $missing_extensions[] = $extension;
    }
  }

  if (!empty($missing_extensions)) {
    $description = $t('Drupal requires you to enable the PHP extensions in the following list (see the <a href="@system_requirements">system requirements page</a> for more information):', array(
      '@system_requirements' => 'http://drupal.org/requirements',
    ));

132
    $description .= theme('item_list', array('items' => $missing_extensions));
133
134
135
136

    $requirements['php_extensions']['value'] = $t('Disabled');
    $requirements['php_extensions']['severity'] = REQUIREMENT_ERROR;
    $requirements['php_extensions']['description'] = $description;
137
138
  }
  else {
139
    $requirements['php_extensions']['value'] = $t('Enabled');
140
  }
141

142
143
144
145
146
  if ($phase == 'install' || $phase == 'update') {
    // Test for PDO (database).
    $requirements['database_extensions'] = array(
      'title' => $t('Database support'),
    );
147

148
    // Make sure PDO is available.
149
    $database_ok = extension_loaded('pdo');
150
151
152
153
154
155
156
    if (!$database_ok) {
      $pdo_message = $t('Your web server does not appear to support PDO (PHP Data Objects). Ask your hosting provider if they support the native PDO extension. See the <a href="@link">system requirements</a> page for more information.', array(
        '@link' => 'http://drupal.org/requirements/pdo',
      ));
    }
    else {
      // Make sure at least one supported database driver exists.
157
      $drivers = drupal_detect_database_types();
158
159
160
161
162
163
164
165
166
167
168
169
170
171
      if (empty($drivers)) {
        $database_ok = FALSE;
        $pdo_message = $t('Your web server does not appear to support any common PDO database extensions. Check with your hosting provider to see if they support PDO (PHP Data Objects) and offer any databases that <a href="@drupal-databases">Drupal supports</a>.', array(
          '@drupal-databases' => 'http://drupal.org/node/270#database',
        ));
      }
      // Make sure the native PDO extension is available, not the older PEAR
      // version. (See install_verify_pdo() for details.)
      if (!defined('PDO::ATTR_DEFAULT_FETCH_MODE')) {
        $database_ok = FALSE;
        $pdo_message = $t('Your web server seems to have the wrong version of PDO installed. Drupal 7 requires the PDO extension from PHP core. This system has the older PECL version. See the <a href="@link">system requirements</a> page for more information.', array(
          '@link' => 'http://drupal.org/requirements/pdo#pecl',
        ));
      }
172
    }
173

174
175
176
    if (!$database_ok) {
      $requirements['database_extensions']['value'] = $t('Disabled');
      $requirements['database_extensions']['severity'] = REQUIREMENT_ERROR;
177
      $requirements['database_extensions']['description'] = $pdo_message;
178
179
180
181
    }
    else {
      $requirements['database_extensions']['value'] = $t('Enabled');
    }
182
  }
183
184
  else {
    // Database information.
185
    $class = Database::getConnection()->getDriverClass('Install\\Tasks');
186
187
188
189
190
191
192
193
194
195
    $tasks = new $class();
    $requirements['database_system'] = array(
      'title' => $t('Database system'),
      'value' => $tasks->name(),
    );
    $requirements['database_system_version'] = array(
      'title' => $t('Database system version'),
      'value' => Database::getConnection()->version(),
    );
  }
196

197
  // Test PHP memory_limit
198
  $memory_limit = ini_get('memory_limit');
199
200
  $requirements['php_memory_limit'] = array(
    'title' => $t('PHP memory limit'),
201
    'value' => $memory_limit == -1 ? t('-1 (Unlimited)') : $memory_limit,
202
  );
203

204
  if (!drupal_check_memory_limit(DRUPAL_MINIMUM_PHP_MEMORY_LIMIT, $memory_limit)) {
205
206
207
    $description = '';
    if ($phase == 'install') {
      $description = $t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the installation process.', array('%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
208
209
210
    }
    elseif ($phase == 'update') {
      $description = $t('Consider increasing your PHP memory limit to %memory_minimum_limit to help prevent errors in the update process.', array('%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
211
    }
212
213
    elseif ($phase == 'runtime') {
      $description = $t('Depending on your configuration, Drupal can run with a %memory_limit PHP memory limit. However, a %memory_minimum_limit PHP memory limit or above is recommended, especially if your site uses additional custom or contributed modules.', array('%memory_limit' => $memory_limit, '%memory_minimum_limit' => DRUPAL_MINIMUM_PHP_MEMORY_LIMIT));
214
    }
215

216
217
    if (!empty($description)) {
      if ($php_ini_path = get_cfg_var('cfg_file_path')) {
218
        $description .= ' ' . $t('Increase the memory limit by editing the memory_limit parameter in the file %configuration-file and then restart your web server (or contact your system administrator or hosting provider for assistance).', array('%configuration-file' => $php_ini_path));
219
220
      }
      else {
221
        $description .= ' ' . $t('Contact your system administrator or hosting provider for assistance with increasing your PHP memory limit.');
222
      }
223

224
      $requirements['php_memory_limit']['description'] = $description . ' ' . $t('See the <a href="@url">Drupal requirements</a> for more information.', array('@url' => 'http://drupal.org/requirements'));
225
      $requirements['php_memory_limit']['severity'] = REQUIREMENT_WARNING;
226
    }
227
  }
228

229
  // Test configuration files and directory for writability.
230
  if ($phase == 'runtime') {
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
    $conf_errors = array();
    $conf_path = conf_path();
    if (!drupal_verify_install_file($conf_path, FILE_NOT_WRITABLE, 'dir')) {
      $conf_errors[] = $t("The directory %file is not protected from modifications and poses a security risk. You must change the directory's permissions to be non-writable.", array('%file' => $conf_path));
    }
    foreach (array('settings.php', 'settings.local.php') as $conf_file) {
      $full_path = $conf_path . '/' . $conf_file;
      if (file_exists($full_path) && !drupal_verify_install_file($full_path, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE)) {
        $conf_errors[] = $t("The file %file is not protected from modifications and poses a security risk. You must change the file's permissions to be non-writable.", array('%file' => $full_path));
      }
    }
    if (!empty($conf_errors)) {
      if (count($conf_errors) == 1) {
        $description = $conf_errors[0];
      }
      else {
        $description = theme('item_list', array('items' => $conf_errors));
      }
249
250
251
      $requirements['settings.php'] = array(
        'value' => $t('Not protected'),
        'severity' => REQUIREMENT_ERROR,
252
        'description' => $description,
253
254
255
256
257
258
259
      );
    }
    else {
      $requirements['settings.php'] = array(
        'value' => $t('Protected'),
      );
    }
260
    $requirements['settings.php']['title'] = $t('Configuration files');
261
262
  }

263
  // Report cron status.
264
  if ($phase == 'runtime') {
265
    $config = config('system.cron');
266
    // Cron warning threshold defaults to two days.
267
    $threshold_warning = $config->get('cron_threshold_warning');
268
    // Cron error threshold defaults to two weeks.
269
    $threshold_error = $config->get('cron_threshold_error');
270
    // Cron configuration help text.
271
    $help = $t('For more information, see the online handbook entry for <a href="@cron-handbook">configuring cron jobs</a>.', array('@cron-handbook' => 'http://drupal.org/cron'));
272

273
    // Determine when cron last ran.
274
    $cron_last = variable_get('cron_last');
275
276
277
    if (!is_numeric($cron_last)) {
      $cron_last = variable_get('install_time', 0);
    }
278

279
    // Determine severity based on time since cron last ran.
280
    $severity = REQUIREMENT_INFO;
281
    if (REQUEST_TIME - $cron_last > $threshold_error) {
282
      $severity = REQUIREMENT_ERROR;
283
    }
284
    elseif (REQUEST_TIME - $cron_last > $threshold_warning) {
285
286
287
288
      $severity = REQUIREMENT_WARNING;
    }

    // Set summary and description based on values determined above.
289
290
    $summary = $t('Last run !time ago', array('!time' => format_interval(REQUEST_TIME - $cron_last)));
    $description = '';
291
    if ($severity != REQUIREMENT_INFO) {
292
      $description = $t('Cron has not run recently.') . ' ' . $help;
293
    }
294

295
    $description .= ' ' . $t('You can <a href="@cron">run cron manually</a>.', array('@cron' => url('admin/reports/status/run-cron')));
296
    $description .= '<br />' . $t('To run cron from outside the site, go to <a href="!cron">!cron</a>', array('!cron' => url('cron/' . $config->get('cron_key'))));
297

298
299
300
301
    $requirements['cron'] = array(
      'title' => $t('Cron maintenance tasks'),
      'severity' => $severity,
      'value' => $summary,
302
      'description' => $description
303
    );
304
305
  }

306
  // Test files directories.
307
308
309
310
311
  // If we are installing Drupal, the settings.php file might not exist yet in
  // the intended conf_path() directory, so don't require it. The conf_path()
  // cache must also be reset in this case.
  $require_settings = ($phase != 'install');
  $reset_cache = !$require_settings;
312
  $directories = array(
313
    variable_get('file_public_path', conf_path($require_settings, $reset_cache) . '/files'),
314
315
316
    // By default no private files directory is configured. For private files
    // to be secure the admin needs to provide a path outside the webroot.
    variable_get('file_private_path', FALSE),
317
  );
318
319
320
321
322
323
324
325
326
327
328

  // Do not check for the temporary files directory at install time
  // unless it has been set in settings.php. In this case the user has
  // no alternative but to fix the directory if it is not writable.
  if ($phase == 'install') {
    $directories[] = variable_get('file_temporary_path', FALSE);
  }
  else {
    $directories[] = variable_get('file_temporary_path', file_directory_temp());
  }

329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  // Check the config directory if it is defined in settings.php. If it isn't
  // defined, the installer will create a valid config directory later, but
  // during runtime we must always display an error.
  if (!empty($GLOBALS['config_directory_name'])) {
    $directories[] = config_get_config_directory();
  }
  elseif ($phase != 'install') {
    $requirements['config directory'] = array(
      'title' => $t('Configuration directory'),
      'value' => $t('Not present'),
      'description' => $t('Your %file file must define the $config_directory_name variable as the name of a directory in which configuration files can be written.', array('%file' => conf_path() . '/settings.php')),
      'severity' => REQUIREMENT_ERROR,
    );
  }

344
345
346
  $requirements['file system'] = array(
    'title' => $t('File system'),
  );
347

348
349
350
  $error = '';
  // For installer, create the directories if possible.
  foreach ($directories as $directory) {
351
352
353
    if (!$directory) {
      continue;
    }
354
    if ($phase == 'install') {
355
      file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
356
    }
357
358
359
360
361
362
363
364
365
366
367
368
369
    $is_writable = is_writable($directory);
    $is_directory = is_dir($directory);
    if (!$is_writable || !$is_directory) {
      $description = '';
      $requirements['file system']['value'] = $t('Not writable');
      if (!$is_directory) {
        $error .= $t('The directory %directory does not exist.', array('%directory' => $directory)) . ' ';
      }
      else {
        $error .= $t('The directory %directory is not writable.', array('%directory' => $directory)) . ' ';
      }
      // The files directory requirement check is done only during install and runtime.
      if ($phase == 'runtime') {
370
        $description = $error . $t('You may need to set the correct directory at the <a href="@admin-file-system">file system settings page</a> or change the current directory\'s permissions so that it is writable.', array('@admin-file-system' => url('admin/config/media/file-system')));
371
372
373
374
      }
      elseif ($phase == 'install') {
        // For the installer UI, we need different wording. 'value' will
        // be treated as version, so provide none there.
375
        $description = $error . $t('An automated attempt to create this directory failed, possibly due to a permissions problem. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see INSTALL.txt or the <a href="@handbook_url">online handbook</a>.', array('@handbook_url' => 'http://drupal.org/server-permissions'));
376
377
378
379
380
381
        $requirements['file system']['value'] = '';
      }
      if (!empty($description)) {
        $requirements['file system']['description'] = $description;
        $requirements['file system']['severity'] = REQUIREMENT_ERROR;
      }
382
383
    }
    else {
384
      if (file_default_scheme() == 'public') {
385
386
387
388
389
        $requirements['file system']['value'] = $t('Writable (<em>public</em> download method)');
      }
      else {
        $requirements['file system']['value'] = $t('Writable (<em>private</em> download method)');
      }
390
391
392
    }
  }

393
394
395
  // See if updates are available in update.php.
  if ($phase == 'runtime') {
    $requirements['update'] = array(
396
      'title' => $t('Database updates'),
397
398
399
400
401
402
403
404
405
406
407
      'value' => $t('Up to date'),
    );

    // Check installed modules.
    foreach (module_list() as $module) {
      $updates = drupal_get_schema_versions($module);
      if ($updates !== FALSE) {
        $default = drupal_get_installed_schema_version($module);
        if (max($updates) > $default) {
          $requirements['update']['severity'] = REQUIREMENT_ERROR;
          $requirements['update']['value'] = $t('Out of date');
408
          $requirements['update']['description'] = $t('Some modules have database schema updates to install. You should run the <a href="@update">database update script</a> immediately.', array('@update' => base_path() . 'core/update.php'));
409
410
411
412
413
414
          break;
        }
      }
    }
  }

415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  // Verify the update.php access setting
  if ($phase == 'runtime') {
    if (!empty($GLOBALS['update_free_access'])) {
      $requirements['update access'] = array(
        'value' => $t('Not protected'),
        'severity' => REQUIREMENT_ERROR,
        'description' => $t('The update.php script is accessible to everyone without authentication check, which is a security risk. You must change the $update_free_access value in your settings.php back to FALSE.'),
      );
    }
    else {
      $requirements['update access'] = array(
        'value' => $t('Protected'),
      );
    }
    $requirements['update access']['title'] = $t('Access to update.php');
  }

432
433
  // Display an error if a newly introduced dependency in a module is not resolved.
  if ($phase == 'update') {
434
    $profile = drupal_get_profile();
435
436
    $files = system_rebuild_module_data();
    foreach ($files as $module => $file) {
437
      // Ignore disabled modules and install profiles.
438
      if (!$file->status || $module == $profile) {
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
        continue;
      }
      // Check the module's PHP version.
      $name = $file->info['name'];
      $php = $file->info['php'];
      if (version_compare($php, PHP_VERSION, '>')) {
        $requirements['php']['description'] .= $t('@name requires at least PHP @version.', array('@name' => $name, '@version' => $php));
        $requirements['php']['severity'] = REQUIREMENT_ERROR;
      }
      // Check the module's required modules.
      foreach ($file->requires as $requirement) {
        $required_module = $requirement['name'];
        // Check if the module exists.
        if (!isset($files[$required_module])) {
          $requirements["$module-$required_module"] = array(
            'title' => $t('Unresolved dependency'),
            'description' => $t('@name requires this module.', array('@name' => $name)),
            'value' => t('@required_name (Missing)', array('@required_name' => $required_module)),
            'severity' => REQUIREMENT_ERROR,
          );
          continue;
        }
        // Check for an incompatible version.
        $required_file = $files[$required_module];
        $required_name = $required_file->info['name'];
        $version = str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', $required_file->info['version']);
        $compatibility = drupal_check_incompatibility($requirement, $version);
        if ($compatibility) {
          $compatibility = rtrim(substr($compatibility, 2), ')');
          $requirements["$module-$required_module"] = array(
            'title' => $t('Unresolved dependency'),
            'description' => $t('@name requires this module and version. Currently using @required_name version @version', array('@name' => $name, '@required_name' => $required_name, '@version' => $version)),
            'value' => t('@required_name (Version @compatibility required)', array('@required_name' => $required_name, '@compatibility' => $compatibility)),
            'severity' => REQUIREMENT_ERROR,
          );
          continue;
        }
      }
    }
  }

480
  // Test Unicode library
481
  include_once DRUPAL_ROOT . '/core/includes/unicode.inc';
482
483
  $requirements = array_merge($requirements, unicode_requirements());

484
  if ($phase == 'runtime') {
485
    // Check for update status module.
486
487
488
    if (!module_exists('update')) {
      $requirements['update status'] = array(
        'value' => $t('Not enabled'),
489
        'severity' => REQUIREMENT_WARNING,
490
        'description' => $t('Update notifications are not enabled. It is <strong>highly recommended</strong> that you enable the Update Manager module from the <a href="@module">module administration page</a> in order to stay up-to-date on new releases. For more information, <a href="@update">Update status handbook page</a>.', array('@update' => 'http://drupal.org/documentation/modules/update', '@module' => url('admin/modules'))),
491
492
493
494
495
496
497
498
499
500
      );
    }
    else {
      $requirements['update status'] = array(
        'value' => $t('Enabled'),
      );
    }
    $requirements['update status']['title'] = $t('Update notifications');
  }

501
502
503
  return $requirements;
}

504
/**
505
 * Implements hook_install().
506
 */
507
function system_install() {
508
  // Create tables.
509
510
511
512
  drupal_install_schema('system');
  $versions = drupal_get_schema_versions('system');
  $version = $versions ? max($versions) : SCHEMA_INSTALLED;
  drupal_set_installed_schema_version('system', $version);
513

514
  // Clear out module list and hook implementation statics before calling
515
  // system_rebuild_theme_data().
516
  module_list(TRUE);
517
  module_implements_reset();
518

519
  // Load system theme data appropriately.
520
  system_rebuild_theme_data();
521

522
  // Enable the default theme.
523
  variable_set('theme_default', 'stark');
524
525
526
  db_update('system')
    ->fields(array('status' => 1))
    ->condition('type', 'theme')
527
    ->condition('name', 'stark')
528
529
    ->execute();

530
  // Populate the cron key variable.
531
  $cron_key = drupal_hash_base64(drupal_random_bytes(55));
532
533
534
  config('system.cron')
    ->set('cron_key', $cron_key)
    ->save();
535
536
}

537
/**
538
 * Implements hook_schema().
539
540
541
542
543
544
 */
function system_schema() {
  // NOTE: {variable} needs to be created before all other tables, as
  // some database drivers, e.g. Oracle and DB2, will require variable_get()
  // and variable_set() for overcoming some database specific limitations.
  $schema['variable'] = array(
545
    'description' => 'Named variable/value pairs created by Drupal core or any other module or theme. All variables are cached in memory at the start of every Drupal request so developers should not be careless about what is stored here.',
546
    'fields' => array(
547
      'name' => array(
548
        'description' => 'The name of the variable.',
549
550
551
        'type' => 'varchar',
        'length' => 128,
        'not null' => TRUE,
552
553
        'default' => '',
      ),
554
      'value' => array(
555
        'description' => 'The value of the variable.',
556
        'type' => 'blob',
557
        'not null' => TRUE,
558
        'size' => 'big',
559
        'translatable' => TRUE,
560
      ),
561
    ),
562
    'primary key' => array('name'),
563
  );
564
565

  $schema['actions'] = array(
566
    'description' => 'Stores action information.',
567
    'fields' => array(
568
      'aid' => array(
569
        'description' => 'Primary Key: Unique actions ID.',
570
571
572
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
573
574
        'default' => '0',
      ),
575
      'type' => array(
576
        'description' => 'The object that that action acts on (node, user, comment, system or custom types.)',
577
578
579
        'type' => 'varchar',
        'length' => 32,
        'not null' => TRUE,
580
581
        'default' => '',
      ),
582
      'callback' => array(
583
        'description' => 'The callback function that executes when the action runs.',
584
585
586
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
587
588
        'default' => '',
      ),
589
      'parameters' => array(
590
        'description' => 'Parameters to be passed to the callback function.',
591
        'type' => 'blob',
592
        'not null' => TRUE,
593
594
        'size' => 'big',
      ),
595
596
      'label' => array(
        'description' => 'Label of the action.',
597
598
599
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
600
        'default' => '0',
601
      ),
602
    ),
603
    'primary key' => array('aid'),
604
  );
605
606

  $schema['batch'] = array(
607
    'description' => 'Stores details about batches (processes that run in multiple HTTP requests).',
608
    'fields' => array(
609
      'bid' => array(
610
        'description' => 'Primary Key: Unique batch ID.',
611
612
613
        // This is not a serial column, to allow both progressive and
        // non-progressive batches. See batch_process().
        'type' => 'int',
614
        'unsigned' => TRUE,
615
616
        'not null' => TRUE,
      ),
617
      'token' => array(
618
        'description' => "A string token generated against the current user's session id and the batch id, used to ensure that only the user who submitted the batch can effectively access it.",
619
620
        'type' => 'varchar',
        'length' => 64,
621
622
        'not null' => TRUE,
      ),
623
      'timestamp' => array(
624
        'description' => 'A Unix timestamp indicating when this batch was submitted for processing. Stale batches are purged at cron time.',
625
        'type' => 'int',
626
627
        'not null' => TRUE,
      ),
628
      'batch' => array(
629
        'description' => 'A serialized array containing the processing data for the batch.',
630
        'type' => 'blob',
631
        'not null' => FALSE,
632
        'size' => 'big',
633
      ),
634
    ),
635
    'primary key' => array('bid'),
636
637
638
639
    'indexes' => array(
      'token' => array('token'),
    ),
  );
640

641
  $schema['blocked_ips'] = array(
642
    'description' => 'Stores blocked IP addresses.',
643
644
    'fields' => array(
       'iid' => array(
645
        'description' => 'Primary Key: unique ID for IP addresses.',
646
647
648
649
650
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'ip' => array(
651
        'description' => 'IP address',
652
        'type' => 'varchar',
653
        'length' => 40,
654
655
656
657
658
659
660
661
662
663
        'not null' => TRUE,
        'default' => '',
      ),
    ),
    'indexes' => array(
      'blocked_ip' => array('ip'),
    ),
    'primary key' => array('iid'),
  );

664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  $schema['cache_tags'] = array(
    'description' => 'Cache table for tracking cache tags related to the cache bin.',
    'fields' => array(
      'tag' => array(
        'description' => 'Namespace-prefixed tag string.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'invalidations' => array(
        'description' => 'Number incremented when the tag is invalidated.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
    ),
    'primary key' => array('tag'),
  );

684
  $schema['cache'] = array(
685
    'description' => 'Generic cache table for caching things not separated out into their own tables. Contributed modules may also use this to store cached items.',
686
    'fields' => array(
687
      'cid' => array(
688
        'description' => 'Primary Key: Unique cache ID.',
689
690
691
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
692
693
        'default' => '',
      ),
694
      'data' => array(
695
        'description' => 'A collection of data to cache.',
696
697
        'type' => 'blob',
        'not null' => FALSE,
698
699
        'size' => 'big',
      ),
700
      'expire' => array(
701
        'description' => 'A Unix timestamp indicating when the cache entry should expire, or 0 for never.',
702
703
        'type' => 'int',
        'not null' => TRUE,
704
705
        'default' => 0,
      ),
706
      'created' => array(
707
        'description' => 'A Unix timestamp indicating when the cache entry was created.',
708
709
        'type' => 'int',
        'not null' => TRUE,
710
711
        'default' => 0,
      ),
712
      'serialized' => array(
713
        'description' => 'A flag to indicate whether content is serialized (1) or not (0).',
714
715
716
        'type' => 'int',
        'size' => 'small',
        'not null' => TRUE,
717
        'default' => 0,
718
      ),
719
720
721
722
723
724
725
726
727
728
729
730
      'tags' => array(
        'description' => 'Space-separated list of cache tags for this entry.',
        'type' => 'text',
        'size' => 'big',
        'not null' => FALSE,
      ),
      'checksum' => array(
        'description' => 'The tag invalidation sum when this entry was saved.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
731
732
733
734
    ),
    'indexes' => array(
      'expire' => array('expire'),
    ),
735
    'primary key' => array('cid'),
736
  );
737
738
  $schema['cache_bootstrap'] = $schema['cache'];
  $schema['cache_bootstrap']['description'] = 'Cache table for data required to bootstrap Drupal, may be routed to a shared memory cache.';
739
  $schema['cache_form'] = $schema['cache'];
740
  $schema['cache_form']['description'] = 'Cache table for the form system to store recently built forms and their storage data, to be used in subsequent page requests.';
741
  $schema['cache_page'] = $schema['cache'];
742
  $schema['cache_page']['description'] = 'Cache table used to store compressed pages for anonymous users, if page caching is enabled.';
743
  $schema['cache_menu'] = $schema['cache'];
744
  $schema['cache_menu']['description'] = 'Cache table for the menu system to store router information as well as generated link trees for various menu/page/user combinations.';
745
746
  $schema['cache_path'] = $schema['cache'];
  $schema['cache_path']['description'] = 'Cache table for path alias lookup.';
747

748
749
750
751
  $schema['config'] = array(
    'description' => 'Default active store for the configuration system.',
    'fields' => array(
      'name' => array(
752
        'description' => 'The identifier for the configuration entry, such as module.example (the name of the file, minus the file extension).',
753
754
755
756
757
758
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'data' => array(
759
        'description' => 'The raw data for this configuration entry.',
760
761
762
763
764
765
766
767
768
769
        'type' => 'blob',
        'not null' => TRUE,
        'size' => 'big',
        'translatable' => TRUE,
      ),
    ),
    'primary key' => array('name'),
  );


770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  $schema['date_format_type'] = array(
    'description' => 'Stores configured date format types.',
    'fields' => array(
      'type' => array(
        'description' => 'The date format type, e.g. medium.',
        'type' => 'varchar',
        'length' => 64,
        'not null' => TRUE,
      ),
      'title' => array(
        'description' => 'The human readable name of the format type.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
      ),
      'locked' => array(
        'description' => 'Whether or not this is a system provided format.',
        'type' => 'int',
        'size' => 'tiny',
        'default' => 0,
        'not null' => TRUE,
      ),
    ),
    'primary key' => array('type'),
794
795
796
    'indexes' => array(
      'title' => array('title'),
    ),
797
798
  );

799
  // This table's name is plural as some versions of MySQL can't create a
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
  // table named 'date_format'.
  $schema['date_formats'] = array(
    'description' => 'Stores configured date formats.',
    'fields' => array(
      'dfid' => array(
        'description' => 'The date format identifier.',
        'type' => 'serial',
        'not null' => TRUE,
        'unsigned' => TRUE,
      ),
      'format' => array(
        'description' => 'The date format string.',
        'type' => 'varchar',
        'length' => 100,
        'not null' => TRUE,
      ),
      'type' => array(
        'description' => 'The date format type, e.g. medium.',
        'type' => 'varchar',
        'length' => 64,
        'not null' => TRUE,
      ),
      'locked' => array(
        'description' => 'Whether or not this format can be modified.',
        'type' => 'int',
        'size' => 'tiny',
        'default' => 0,
        'not null' => TRUE,
      ),
    ),
    'primary key' => array('dfid'),
    'unique keys' => array('formats' => array('format', 'type')),
  );

  $schema['date_format_locale'] = array(
    'description' => 'Stores configured date formats for each locale.',
    'fields' => array(
      'format' => array(
        'description' => 'The date format string.',
        'type' => 'varchar',
        'length' => 100,
        'not null' => TRUE,
      ),
      'type' => array(
        'description' => 'The date format type, e.g. medium.',
        'type' => 'varchar',
        'length' => 64,
        'not null' => TRUE,
      ),
      'language' => array(
850
        'description' => 'A {language}.langcode for this format to be used with.',
851
852
853
854
855
856
857
858
        'type' => 'varchar',
        'length' => 12,
        'not null' => TRUE,
      ),
    ),
    'primary key' => array('type', 'language'),
  );

859
  $schema['file_managed'] = array(
860
    'description' => 'Stores information for uploaded files.',
861
    'fields' => array(
862
      'fid' => array(
863
        'description' => 'File ID.',
864
865
        'type' => 'serial',
        'unsigned' => TRUE,
866
867
        'not null' => TRUE,
      ),
868
      'uid' => array(
869
        'description' => 'The {users}.uid of the user who is associated with the file.',
870
871
872
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
873
874
        'default' => 0,
      ),
875
      'filename' => array(
876
        'description' => 'Name of the file with no path components. This may differ from the basename of the URI if the file is renamed to avoid overwriting an existing file.',
877
878
879
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
880
        'default' => '',
881
        'binary' => TRUE,
882
      ),
883
      'uri' => array(
884
        'description' => 'The URI to access the file (either local or remote).',
885
886
887
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
888
        'default' => '',
889
        'binary' => TRUE,
890
      ),
891
892
893
894
895
896
897
      'langcode' => array(
        'description' => 'The {language}.langcode of this file.',
        'type' => 'varchar',
        'length' => 12,
        'not null' => TRUE,
        'default' => '',
      ),
898
      'filemime' => array(
899
        'description' => "The file's MIME type.",
900
901
902
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
903
904
        'default' => '',
      ),
905
      'filesize' => array(
906
        'description' => 'The size of the file in bytes.',
907
908
909
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
910
911
        'default' => 0,
      ),
912
      'status' => array(
913
        'description' => 'A field indicating the status of the file. Two status are defined in core: temporary (0) and permanent (1). Temporary files older than DRUPAL_MAXIMUM_TEMP_FILE_AGE will be removed during a cron run.',
914
915
        'type' => 'int',
        'not null' => TRUE,
916
        'default' => 0,
917
        'size' => 'tiny',
918
      ),
919
      'timestamp' => array(
920
        'description' => 'UNIX timestamp for when the file was added.',
921
922
923
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
924
        'default' => 0,
925
      ),
926
    ),
927
    'indexes' => array(
928
929
      'uid' => array('uid'),
      'status' => array('status'),
930
      'timestamp' => array('timestamp'),
931
    ),
932
933
934
    'unique keys' => array(
      'uri' => array('uri'),
    ),
935
    'primary key' => array('fid'),
936
    'foreign keys' => array(
937
938
939
940
      'file_owner' => array(
        'table' => 'users',
        'columns' => array('uid' => 'uid'),
      ),
941
    ),
942
  );
943

944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
  $schema['file_usage'] = array(
    'description' => 'Track where a file is used.',
    'fields' => array(
      'fid' => array(
        'description' => 'File ID.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'module' => array(
        'description' => 'The name of the module that is using the file.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      'type' => array(
        'description' => 'The name of the object type in which the file is used.',
        'type' => 'varchar',
        'length' => 64,
        'not null' => TRUE,
        'default' => '',
      ),
      'id' => array(
        'description' => 'The primary key of the object using the file.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'count' => array(
        'description' => 'The number of times this file is used by this object.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
    ),
    'primary key' => array('fid', 'type', 'id', 'module'),
    'indexes' => array(
      'type_id' => array('type', 'id'),
      'fid_count' => array('fid', 'count'),
      'fid_module' => array('fid', 'module'),
    ),
  );

990
  $schema['flood'] = array(
991
    'description' => 'Flood controls the threshold of events, such as the number of contact attempts.',
992
    'fields' => array(
993
      'fid' => array(
994
        'description' => 'Unique flood event ID.',
995
        'type' => 'serial',
996
997
        'not null' => TRUE,
      ),
998
      'event' => array(
999
        'description' => 'Name of event (e.g. contact).',
1000
1001
1002
        'type' => 'varchar',
        'length' => 64,
        'not null' => TRUE,
1003
1004
        'default' => '',
      ),
1005
1006
      'identifier' => array(
        'description' => 'Identifier of the visitor, such as an IP address or hostname.',
1007
1008
1009
        'type' => 'varchar',
        'length' => 128,
        'not null' => TRUE,
1010
1011
        'default' => '',
      ),
1012
      'timestamp' => array(
1013
        'description' => 'Timestamp of the event.',
1014
1015
        'type' => 'int',
        'not null' => TRUE,
1016
        'default' => 0,
1017
      ),
1018
1019
1020
1021
1022
1023
      'expiration' => array(
        'description' => 'Expiration timestamp. Expired events are purged on cron run.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
1024
    ),
1025
    'primary key' => array('fid'),
1026
    'indexes' => array(
1027
      'allow' => array('event', 'identifier', 'timestamp'),
1028
      'purge' => array('expiration'),
1029
    ),
1030
  );