Newer
Older
Dries Buytaert
committed
Steven Wittens
committed
/**
* Test and report Drupal installation requirements.
*
* @param $phase
* The current system installation phase.
* @return
* An array of system requirements.
Steven Wittens
committed
*/
function system_requirements($phase) {
$requirements = array();
// Ensure translations don't break at install time
Steven Wittens
committed
// Report Drupal version
if ($phase == 'runtime') {
$requirements['drupal'] = array(
'title' => $t('Drupal'),
'value' => VERSION,
'severity' => REQUIREMENT_INFO,
'weight' => -10,
Steven Wittens
committed
);
}
// Test web server
Steven Wittens
committed
$requirements['webserver'] = array(
'title' => $t('Web server'),
Steven Wittens
committed
);
// Use server info string, if present.
if ($software && preg_match('![0-9]!', $software)) {
list($server, $version) = split('[ /]', $software);
Steven Wittens
committed
switch ($server) {
case 'Apache':
if (version_compare($version, DRUPAL_MINIMUM_APACHE) < 0) {
$requirements['webserver']['description'] = $t('Your Apache server is too old. Drupal requires at least Apache %version.', array('%version' => DRUPAL_MINIMUM_APACHE));
$requirements['webserver']['severity'] = REQUIREMENT_ERROR;
}
break;
default:
$requirements['webserver']['description'] = $t('The web server you\'re using has not been tested with Drupal and might not work properly.');
$requirements['webserver']['severity'] = REQUIREMENT_WARNING;
break;
}
}
else {
$requirements['webserver']['value'] = $software ? $software : $t('Unknown');
$requirements['webserver']['description'] = $t('Unable to determine your web server type and version. Drupal might not work properly.');
Steven Wittens
committed
$requirements['webserver']['severity'] = REQUIREMENT_WARNING;
}
// Test PHP version
$requirements['php'] = array(
'title' => $t('PHP'),
'value' => ($phase == 'runtime') ? l(phpversion(), 'admin/reports/status/php') : phpversion(),
Steven Wittens
committed
);
if (version_compare(phpversion(), DRUPAL_MINIMUM_PHP) < 0) {
$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;
}
// Test DB version
global $db_type;
if (function_exists('db_status_report')) {
$requirements += db_status_report($phase);
}
// Test settings.php file writability
if ($phase == 'runtime') {
Gábor Hojtsy
committed
$conf_dir = drupal_verify_install_file(conf_path(), FILE_NOT_WRITABLE, 'dir');
$conf_file = drupal_verify_install_file(conf_path() .'/settings.php', FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE);
if (!$conf_dir || !$conf_file) {
Steven Wittens
committed
$requirements['settings.php'] = array(
'value' => $t('Not protected'),
'severity' => REQUIREMENT_ERROR,
Gábor Hojtsy
committed
'description' => '',
Steven Wittens
committed
);
Gábor Hojtsy
committed
if (!$conf_dir) {
$requirements['settings.php']['description'] .= $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()));
}
if (!$conf_file) {
$requirements['settings.php']['description'] .= $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' => conf_path() .'/settings.php'));
}
Steven Wittens
committed
}
else {
$requirements['settings.php'] = array(
'value' => $t('Protected'),
);
}
$requirements['settings.php']['title'] = $t('Configuration file');
}
Gábor Hojtsy
committed
// Report cron status.
Steven Wittens
committed
if ($phase == 'runtime') {
Gábor Hojtsy
committed
// Cron warning threshold defaults to two days.
$threshold_warning = variable_get('cron_threshold_warning', 172800);
// Cron error threshold defaults to two weeks.
$threshold_error = variable_get('cron_threshold_error', 1209600);
// Cron configuration help text.
$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'));
Gábor Hojtsy
committed
// Determine when cron last ran. If never, use the install time to
// determine the warning or error status.
Steven Wittens
committed
$cron_last = variable_get('cron_last', NULL);
Gábor Hojtsy
committed
$never_run = FALSE;
if (!is_numeric($cron_last)) {
$never_run = TRUE;
$cron_last = variable_get('install_time', 0);
}
Steven Wittens
committed
Gábor Hojtsy
committed
// Determine severity based on time since cron last ran.
$severity = REQUIREMENT_OK;
if (time() - $cron_last > $threshold_error) {
$severity = REQUIREMENT_ERROR;
Steven Wittens
committed
}
else if ($never_run || (time() - $cron_last > $threshold_warning)) {
Gábor Hojtsy
committed
$severity = REQUIREMENT_WARNING;
}
// If cron hasn't been run, and the user is viewing the main
// administration page, instead of an error, we display a helpful reminder
// to configure cron jobs.
Gábor Hojtsy
committed
if ($never_run && $severity != REQUIREMENT_ERROR && $_GET['q'] == 'admin' && user_access('administer site configuration')) {
drupal_set_message($t('Cron has not run. Please visit the <a href="@status">status report</a> for more information.', array('@status' => url('admin/reports/status'))));
Steven Wittens
committed
}
Gábor Hojtsy
committed
// Set summary and description based on values determined above.
if ($never_run) {
$summary = $t('Never run');
$description = $t('Cron has not run.') .' '. $help;
}
else {
$summary = $t('Last run !time ago', array('!time' => format_interval(time() - $cron_last)));
$description = '';
if ($severity != REQUIREMENT_OK) {
$description = $t('Cron has not run recently.') .' '. $help;
}
}
Steven Wittens
committed
Gábor Hojtsy
committed
$requirements['cron'] = array(
'title' => $t('Cron maintenance tasks'),
'severity' => $severity,
'value' => $summary,
'description' => $description .' '. $t('You can <a href="@cron">run cron manually</a>.', array('@cron' => url('admin/reports/status/run-cron'))),
Gábor Hojtsy
committed
);
Steven Wittens
committed
}
// Test files directory
Gábor Hojtsy
committed
$directory = file_directory_path();
// For installer, create the directory if possible.
if ($phase == 'install' && !is_dir($directory) && @mkdir($directory)) {
@chmod($directory, 0775); // Necessary for non-webserver users.
}
Gábor Hojtsy
committed
$is_writable = is_writable($directory);
$is_directory = is_dir($directory);
if (!$is_writable || !$is_directory) {
if (!$is_directory) {
$error = $t('The directory %directory does not exist.', array('%directory' => $directory));
}
else {
Gábor Hojtsy
committed
$error = $t('The directory %directory is not writable.', array('%directory' => $directory));
}
$requirements['file system'] = array(
'value' => $t('Not writable'),
'severity' => REQUIREMENT_ERROR,
);
if ($phase == 'runtime') {
$requirements['file system']['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/settings/file-system')));
}
else if ($phase == 'install') {
// For the installer UI, we need different wording. 'value' will
// be treated as version, so provide none there.
$requirements['file system']['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, please see INSTALL.txt or the <a href="@handbook_url">on-line handbook</a>.', array('@handbook_url' => 'http://drupal.org/server-permissions'));
Gábor Hojtsy
committed
$requirements['file system']['value'] = '';
}
}
else {
if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) {
$requirements['file system']['value'] = $t('Writable (<em>public</em> download method)');
}
else {
$requirements['file system']['value'] = $t('Writable (<em>private</em> download method)');
Gábor Hojtsy
committed
$requirements['file system']['title'] = $t('File system');
// See if updates are available in update.php.
if ($phase == 'runtime') {
$requirements['update'] = array(
'title' => $t('Database updates'),
'severity' => REQUIREMENT_OK,
'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');
$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() .'update.php'));
break;
}
}
}
}
Gábor Hojtsy
committed
// 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');
}
Steven Wittens
committed
// Test Unicode library
include_once './includes/unicode.inc';
$requirements = array_merge($requirements, unicode_requirements());
Gábor Hojtsy
committed
// Check for update status module.
if ($phase == 'runtime') {
if (!module_exists('update')) {
$requirements['update status'] = array(
'value' => $t('Not enabled'),
'severity' => REQUIREMENT_ERROR,
'description' => $t('Update notifications are not enabled. It is <strong>highly recommended</strong> that you enable the update status module from the <a href="@module">module administration page</a> in order to stay up-to-date on new releases. For more information please read the <a href="@update">Update status handbook page</a>.', array('@update' => 'http://drupal.org/handbook/modules/update', '@module' => url('admin/build/modules'))),
);
}
else {
$requirements['update status'] = array(
'value' => $t('Enabled'),
);
Gábor Hojtsy
committed
if (variable_get('drupal_http_request_fails', FALSE)) {
$requirements['http requests'] = array(
'title' => $t('HTTP request status'),
'value' => $t('Fails'),
'severity' => REQUIREMENT_ERROR,
'description' => $t('Your system or network configuration does not allow Drupal to access web pages, resulting in reduced functionality. This could be due to your webserver configuration or PHP settings, and should be resolved in order to download information about available updates, fetch aggregator feeds, sign in via OpenID, or use other network-dependent services.'),
);
}
Gábor Hojtsy
committed
}
$requirements['update status']['title'] = $t('Update notifications');
}
Steven Wittens
committed
return $requirements;
}
/**
* Implementation of hook_install().
*/
Dries Buytaert
committed
function system_install() {
Gábor Hojtsy
committed
if ($GLOBALS['db_type'] == 'pgsql') {
Dries Buytaert
committed
// Create unsigned types.
Gábor Hojtsy
committed
db_query("CREATE DOMAIN int_unsigned integer CHECK (VALUE >= 0)");
db_query("CREATE DOMAIN smallint_unsigned smallint CHECK (VALUE >= 0)");
db_query("CREATE DOMAIN bigint_unsigned bigint CHECK (VALUE >= 0)");
Dries Buytaert
committed
// Create functions.
Gábor Hojtsy
committed
db_query('CREATE OR REPLACE FUNCTION "greatest"(numeric, numeric) RETURNS numeric AS
\'SELECT CASE WHEN (($1 > $2) OR ($2 IS NULL)) THEN $1 ELSE $2 END;\'
LANGUAGE \'sql\''
);
db_query('CREATE OR REPLACE FUNCTION "greatest"(numeric, numeric, numeric) RETURNS numeric AS
\'SELECT greatest($1, greatest($2, $3));\'
LANGUAGE \'sql\''
);
if (!db_result(db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'rand'"))) {
db_query('CREATE OR REPLACE FUNCTION "rand"() RETURNS float AS
\'SELECT random();\'
Dries Buytaert
committed
LANGUAGE \'sql\''
);
Gábor Hojtsy
committed
}
Dries Buytaert
committed
Gábor Hojtsy
committed
if (!db_result(db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'concat'"))) {
db_query('CREATE OR REPLACE FUNCTION "concat"(text, text) RETURNS text AS
\'SELECT $1 || $2;\'
Dries Buytaert
committed
LANGUAGE \'sql\''
);
Gábor Hojtsy
committed
}
db_query('CREATE OR REPLACE FUNCTION "if"(boolean, text, text) RETURNS text AS
\'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\'
LANGUAGE \'sql\''
);
db_query('CREATE OR REPLACE FUNCTION "if"(boolean, integer, integer) RETURNS integer AS
\'SELECT CASE WHEN $1 THEN $2 ELSE $3 END;\'
LANGUAGE \'sql\''
);
Dries Buytaert
committed
}
Dries Buytaert
committed
Dries Buytaert
committed
// Create tables.
Dries Buytaert
committed
$modules = array('system', 'filter', 'block', 'user', 'node', 'comment', 'taxonomy');
Dries Buytaert
committed
foreach ($modules as $module) {
drupal_install_schema($module);
Dries Buytaert
committed
}
Dries Buytaert
committed
// Load system theme data appropriately.
system_theme_data();
Dries Buytaert
committed
Gábor Hojtsy
committed
// Inserting uid 0 here confuses MySQL -- the next user might be created as
// uid 2 which is not what we want. So we insert the first user here, the
// anonymous user. uid is 1 here for now, but very soon it will be changed
// to 0.
db_query("INSERT INTO {users} (name, mail) VALUES('%s', '%s')", '', '');
// We need some placeholders here as name and mail are uniques and data is
// presumed to be a serialized array. Install will change uid 1 immediately
// anyways. So we insert the superuser here, the uid is 2 here for now, but
// very soon it will be changed to 1.
db_query("INSERT INTO {users} (name, mail, created, data) VALUES('%s', '%s', %d, '%s')", 'placeholder-for-uid-1', 'placeholder-for-uid-1', time(), serialize(array()));
Gábor Hojtsy
committed
// This sets the above two users uid 0 (anonymous). We avoid an explicit 0
// otherwise MySQL might insert the next auto_increment value.
db_query("UPDATE {users} SET uid = uid - uid WHERE name = '%s'", '');
// This sets uid 1 (superuser). We skip uid 2 but that's not a big problem.
db_query("UPDATE {users} SET uid = 1 WHERE name = '%s'", 'placeholder-for-uid-1');
Gábor Hojtsy
committed
Gábor Hojtsy
committed
db_query("INSERT INTO {role} (name) VALUES ('%s')", 'anonymous user');
db_query("INSERT INTO {role} (name) VALUES ('%s')", 'authenticated user');
Dries Buytaert
committed
Gábor Hojtsy
committed
db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 1, 'access content', 0);
db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 2, 'access comments, access content, post comments, post comments without approval', 0);
Dries Buytaert
committed
Gábor Hojtsy
committed
db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'theme_default', 's:7:"garland";');
db_query("UPDATE {system} SET status = %d WHERE type = '%s' AND name = '%s'", 1, 'theme', 'garland');
Dries Buytaert
committed
db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, pages) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s')", 'user', '0', 'garland', 1, 0, 'left', '');
db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, pages) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s')", 'user', '1', 'garland', 1, 0, 'left', '');
db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, pages) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s')", 'system', '0', 'garland', 1, 10, 'footer', '');
Dries Buytaert
committed
Gábor Hojtsy
committed
db_query("INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, '%s', %d, %d, %d)", 0, 0, 'all', 1, 0, 0);
Dries Buytaert
committed
// Add input formats.
Gábor Hojtsy
committed
db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('%s', '%s', %d)", 'Filtered HTML', ',1,2,', 1);
db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('%s', '%s', %d)", 'Full HTML', '', 1);
// Enable filters for each input format.
// Filtered HTML:
// URL filter.
Gábor Hojtsy
committed
db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 2, 0);
// HTML filter.
Gábor Hojtsy
committed
db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 0, 1);
// Line break filter.
Gábor Hojtsy
committed
db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 1, 2);
// HTML corrector filter.
Gábor Hojtsy
committed
db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 1, 'filter', 3, 10);
// Full HTML:
// URL filter.
Gábor Hojtsy
committed
db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 2, 'filter', 2, 0);
// Line break filter.
Gábor Hojtsy
committed
db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 2, 'filter', 1, 1);
// HTML corrector filter.
db_query("INSERT INTO {filters} (format, module, delta, weight) VALUES (%d, '%s', %d, %d)", 2, 'filter', 3, 10);
Gábor Hojtsy
committed
db_query("INSERT INTO {variable} (name, value) VALUES ('%s','%s')", 'filter_html_1', 'i:1;');
Dries Buytaert
committed
Gábor Hojtsy
committed
db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'node_options_forum', 'a:1:{i:0;s:6:"status";}');
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Implementation of hook_schema().
*/
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(
Dries Buytaert
committed
'description' => t('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.'),
Dries Buytaert
committed
'fields' => array(
'name' => array(
'description' => t('The name of the variable.'),
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => ''),
'value' => array(
'description' => t('The value of the variable.'),
'type' => 'text',
'not null' => TRUE,
'size' => 'big'),
),
Dries Buytaert
committed
'primary key' => array('name'),
Dries Buytaert
committed
$schema['actions'] = array(
'description' => t('Stores action information.'),
Dries Buytaert
committed
'fields' => array(
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
'aid' => array(
'description' => t('Primary Key: Unique actions ID.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '0'),
'type' => array(
'description' => t('The object that that action acts on (node, user, comment, system or custom types.)'),
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => ''),
'callback' => array(
'description' => t('The callback function that executes when the action runs.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'parameters' => array(
'description' => t('Parameters to be passed to the callback function.'),
'type' => 'text',
'not null' => TRUE,
'size' => 'big'),
'description' => array(
'description' => t('Description of the action.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '0'),
),
Dries Buytaert
committed
'primary key' => array('aid'),
Dries Buytaert
committed
$schema['actions_aid'] = array(
'description' => t('Stores action IDs for non-default actions.'),
Dries Buytaert
committed
'fields' => array(
'aid' => array(
'description' => t('Primary Key: Unique actions ID.'),
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE),
),
Dries Buytaert
committed
'primary key' => array('aid'),
Dries Buytaert
committed
$schema['batch'] = array(
'description' => t('Stores details about batches (processes that run in multiple HTTP requests).'),
Dries Buytaert
committed
'fields' => array(
'bid' => array(
'description' => t('Primary Key: Unique batch ID.'),
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE),
'token' => array(
'description' => t("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."),
'type' => 'varchar',
'length' => 64,
'not null' => TRUE),
'timestamp' => array(
'description' => t('A Unix timestamp indicating when this batch was submitted for processing. Stale batches are purged at cron time.'),
'type' => 'int',
'not null' => TRUE),
'batch' => array(
'description' => t('A serialized array containing the processing data for the batch.'),
'type' => 'text',
'not null' => FALSE,
'size' => 'big')
),
Dries Buytaert
committed
'primary key' => array('bid'),
'indexes' => array('token' => array('token')),
Dries Buytaert
committed
$schema['cache'] = array(
'description' => t('Generic cache table for caching things not separated out into their own tables. Contributed modules may also use this to store cached items.'),
Dries Buytaert
committed
'fields' => array(
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
'cid' => array(
'description' => t('Primary Key: Unique cache ID.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'data' => array(
'description' => t('A collection of data to cache.'),
'type' => 'blob',
'not null' => FALSE,
'size' => 'big'),
'expire' => array(
'description' => t('A Unix timestamp indicating when the cache entry should expire, or 0 for never.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'created' => array(
'description' => t('A Unix timestamp indicating when the cache entry was created.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'headers' => array(
'description' => t('Any custom HTTP headers to be added to cached data.'),
'type' => 'text',
'not null' => FALSE),
'serialized' => array(
'description' => t('A flag to indicate whether content is serialized (1) or not (0).'),
'type' => 'int',
'size' => 'small',
'not null' => TRUE,
'default' => 0)
),
Dries Buytaert
committed
'indexes' => array('expire' => array('expire')),
'primary key' => array('cid'),
Dries Buytaert
committed
$schema['cache_form'] = $schema['cache'];
$schema['cache_form']['description'] = t('Cache table for the form system to store recently built forms and their storage data, to be used in subsequent page requests.');
Dries Buytaert
committed
$schema['cache_page'] = $schema['cache'];
$schema['cache_page']['description'] = t('Cache table used to store compressed pages for anonymous users, if page caching is enabled.');
Dries Buytaert
committed
$schema['cache_menu'] = $schema['cache'];
$schema['cache_menu']['description'] = t('Cache table for the menu system to store router information as well as generated link trees for various menu/page/user combinations.');
Dries Buytaert
committed
$schema['files'] = array(
'description' => t('Stores information for uploaded files.'),
Dries Buytaert
committed
'fields' => array(
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
'fid' => array(
'description' => t('Primary Key: Unique files ID.'),
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE),
'uid' => array(
'description' => t('The {users}.uid of the user who is associated with the file.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'filename' => array(
'description' => t('Name of the file.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'filepath' => array(
'description' => t('Path of the file relative to Drupal root.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'filemime' => array(
'description' => t('The file MIME type.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'filesize' => array(
'description' => t('The size of the file in bytes.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'status' => array(
'description' => t('A flag indicating whether file is temporary (1) or permanent (0).'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'timestamp' => array(
'description' => t('UNIX timestamp for when the file was added.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
),
Dries Buytaert
committed
'indexes' => array(
'uid' => array('uid'),
'status' => array('status'),
Dries Buytaert
committed
'timestamp' => array('timestamp'),
Dries Buytaert
committed
'primary key' => array('fid'),
Dries Buytaert
committed
$schema['flood'] = array(
'description' => t('Flood controls the threshold of events, such as the number of contact attempts.'),
Dries Buytaert
committed
'fields' => array(
'fid' => array(
'description' => t('Unique flood event ID.'),
'type' => 'serial',
'not null' => TRUE),
'event' => array(
'description' => t('Name of event (e.g. contact).'),
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => ''),
'hostname' => array(
'description' => t('Hostname of the visitor.'),
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => ''),
'timestamp' => array(
'description' => t('Timestamp of the event.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0)
),
Dries Buytaert
committed
'primary key' => array('fid'),
Dries Buytaert
committed
'indexes' => array(
'allow' => array('event', 'hostname', 'timestamp'),
),
Dries Buytaert
committed
$schema['history'] = array(
'description' => t('A record of which {users} have read which {node}s.'),
Dries Buytaert
committed
'fields' => array(
'uid' => array(
'description' => t('The {users}.uid that read the {node} nid.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'nid' => array(
'description' => t('The {node}.nid that was read.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'timestamp' => array(
'description' => t('The Unix timestamp at which the read occurred.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0)
),
Dries Buytaert
committed
'primary key' => array('uid', 'nid'),
Dries Buytaert
committed
'indexes' => array(
'nid' => array('nid'),
),
Dries Buytaert
committed
$schema['menu_router'] = array(
'description' => t('Maps paths to various callbacks (access, page and title)'),
Dries Buytaert
committed
'fields' => array(
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
'path' => array(
'description' => t('Primary Key: the Drupal path this entry describes'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'load_functions' => array(
'description' => t('A serialized array of function names (like node_load) to be called to load an object corresponding to a part of the current path.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'to_arg_functions' => array(
'description' => t('A serialized array of function names (like user_current_to_arg) to be called to replace a part of the router path with another string.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'access_callback' => array(
'description' => t('The callback which determines the access to this router path. Defaults to user_access.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'access_arguments' => array(
'description' => t('A serialized array of arguments for the access callback.'),
'type' => 'text',
'not null' => FALSE),
'page_callback' => array(
'description' => t('The name of the function that renders the page.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'page_arguments' => array(
'description' => t('A serialized array of arguments for the page callback.'),
'type' => 'text',
'not null' => FALSE),
'fit' => array(
'description' => t('A numeric representation of how specific the path is.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'number_parts' => array(
'description' => t('Number of parts in this router path.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small'),
'tab_parent' => array(
'description' => t('Only for local tasks (tabs) - the router path of the parent page (which may also be a local task).'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'tab_root' => array(
Dries Buytaert
committed
'description' => t('Router path of the closest non-tab parent page. For pages that are not local tasks, this will be the same as the path.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'title' => array(
'description' => t('The title for the current page, or the title for the tab if this is a local task.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'title_callback' => array(
'description' => t('A function which will alter the title. Defaults to t()'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'title_arguments' => array(
Dries Buytaert
committed
'description' => t('A serialized array of arguments for the title callback. If empty, the title will be used as the sole argument for the title callback.'),
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'type' => array(
'description' => t('Numeric representation of the type of the menu item, like MENU_LOCAL_TASK.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'block_callback' => array(
'description' => t('Name of a function used to render the block on the system administration page for this item.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'description' => array(
'description' => t('A description of this item.'),
'type' => 'text',
'not null' => TRUE),
'position' => array(
'description' => t('The position of the block (left or right) on the system administration page for this item.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'weight' => array(
'description' => t('Weight of the element. Lighter weights are higher up, heavier weights go down.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'file' => array(
'description' => t('The file to include for this element, usually the page callback function lives in this file.'),
'type' => 'text',
'size' => 'medium')
),
Dries Buytaert
committed
'indexes' => array(
'fit' => array('fit'),
Dries Buytaert
committed
'tab_parent' => array('tab_parent')
Dries Buytaert
committed
'primary key' => array('path'),
Dries Buytaert
committed
$schema['menu_links'] = array(
'description' => t('Contains the individual links within a menu.'),
Dries Buytaert
committed
'fields' => array(
'menu_name' => array(
'description' => t("The menu name. All links with the same menu name (such as 'navigation') are part of the same menu."),
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => ''),
'mlid' => array(
'description' => t('The menu link ID (mlid) is the integer primary key.'),
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE),
'plid' => array(
'description' => t('The parent link ID (plid) is the mlid of the link above in the hierarchy, or zero if the link is at the top level in its menu.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'link_path' => array(
'description' => t('The Drupal path or external path this link points to.'),
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
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
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'router_path' => array(
'description' => t('For links corresponding to a Drupal path (external = 0), this connects the link to a {menu_router}.path for joins.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'link_title' => array(
'description' => t('The text displayed for the link, which may be modified by a title callback stored in {menu_router}.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'options' => array(
'description' => t('A serialized array of options to be passed to the url() or l() function, such as a query string or HTML attributes.'),
'type' => 'text',
'not null' => FALSE),
'module' => array(
'description' => t('The name of the module that generated this link.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => 'system'),
'hidden' => array(
'description' => t('A flag for whether the link should be rendered in menus. (1 = a disabled menu item that may be shown on admin screens, -1 = a menu callback, 0 = a normal, visible link)'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small'),
'external' => array(
'description' => t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small'),
'has_children' => array(
'description' => t('Flag indicating whether any links have this link as a parent (1 = children exist, 0 = no children).'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small'),
'expanded' => array(
'description' => t('Flag for whether this link should be rendered as expanded in menus - expanded links always have their child links displayed, instead of only when the link is in the active trail (1 = expanded, 0 = not expanded)'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small'),
'weight' => array(
'description' => t('Link weight among links in the same menu at the same depth.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'depth' => array(
'description' => t('The depth relative to the top level. A link with plid == 0 will have depth == 1.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small'),
'customized' => array(
'description' => t('A flag to indicate that the user has manually created or edited the link (1 = customized, 0 = not customized).'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small'),
'p1' => array(
Dries Buytaert
committed
'description' => t('The first mlid in the materialized path. If N = depth, then pN must equal the mlid. If depth > 1 then p(N-1) must equal the plid. All pX where X > depth must equal zero. The columns p1 .. p9 are also called the parents.'),
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'p2' => array(
'description' => t('The second mlid in the materialized path. See p1.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'p3' => array(
'description' => t('The third mlid in the materialized path. See p1.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'p4' => array(
'description' => t('The fourth mlid in the materialized path. See p1.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'p5' => array(
'description' => t('The fifth mlid in the materialized path. See p1.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'p6' => array(
'description' => t('The sixth mlid in the materialized path. See p1.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'p7' => array(
'description' => t('The seventh mlid in the materialized path. See p1.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'p8' => array(
'description' => t('The eighth mlid in the materialized path. See p1.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'p9' => array(
'description' => t('The ninth mlid in the materialized path. See p1.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0),
'updated' => array(
'description' => t('Flag that indicates that this link was generated during the update from Drupal 5.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small'),
),
Dries Buytaert
committed
'indexes' => array(
'path_menu' => array(array('link_path', 128), 'menu_name'),
'menu_plid_expand_child' => array(
'menu_name', 'plid', 'expanded', 'has_children'),
'menu_parents' => array(
'menu_name', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9'),
'router_path' => array(array('router_path', 128)),
),
Dries Buytaert
committed
'primary key' => array('mlid'),
Dries Buytaert
committed
$schema['sessions'] = array(
'description' => t("Drupal's session handlers read and write into the sessions table. Each record represents a user session, either anonymous or authenticated."),
Dries Buytaert
committed
'fields' => array(
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
'uid' => array(
'description' => t('The {users}.uid corresponding to a session, or 0 for anonymous user.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE),
'sid' => array(
'description' => t("Primary key: A session ID. The value is generated by PHP's Session API."),
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => ''),
'hostname' => array(
'description' => t('The IP address that last used this session ID (sid).'),
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => ''),
'timestamp' => array(
'description' => t('The Unix timestamp when this session last requested a page. Old records are purged by PHP automatically.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'cache' => array(
'description' => t("The time of this user's last post. This is used when the site has specified a minimum_cache_lifetime. See cache_get()."),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'session' => array(
Dries Buytaert
committed
'description' => t('The serialized contents of $_SESSION, an array of name/value pairs that persists across page requests by this session ID. Drupal loads $_SESSION from here at the start of each request and saves it at the end.'),
'type' => 'text',
'not null' => FALSE,
'size' => 'big')
),
Dries Buytaert
committed
'primary key' => array('sid'),
'indexes' => array(
'timestamp' => array('timestamp'),
'uid' => array('uid')
),
);
Dries Buytaert
committed
$schema['system'] = array(
'description' => t("A list of all modules, themes, and theme engines that are or have been installed in Drupal's file system."),
Dries Buytaert
committed
'fields' => array(
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
990
'filename' => array(
'description' => t('The path of the primary file for this item, relative to the Drupal root; e.g. modules/node/node.module.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'name' => array(
'description' => t('The name of the item; e.g. node.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'type' => array(
'description' => t('The type of the item, either module, theme, or theme_engine.'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'owner' => array(
'description' => t("A theme's 'parent'. Can be either a theme or an engine."),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => ''),
'status' => array(
'description' => t('Boolean indicating whether or not this item is enabled.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0),
'throttle' => array(
'description' => t('Boolean indicating whether this item is disabled when the throttle.module disables throttleable items.'),
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny'),
'bootstrap' => array(
'description' => t("Boolean indicating whether this module is loaded during Drupal's early bootstrapping phase (e.g. even before the page cache is consulted)."),
'type' => 'int',
'not null' => TRUE,
'default' => 0),