web/drupal/update.php
branchdrupal
changeset 74 0ff3ba646492
equal deleted inserted replaced
73:fcf75e232c5b 74:0ff3ba646492
       
     1 <?php
       
     2 // $Id: update.php,v 1.252.2.3 2009/03/30 11:15:11 goba Exp $
       
     3 
       
     4 /**
       
     5  * @file
       
     6  * Administrative page for handling updates from one Drupal version to another.
       
     7  *
       
     8  * Point your browser to "http://www.example.com/update.php" and follow the
       
     9  * instructions.
       
    10  *
       
    11  * If you are not logged in as administrator, you will need to modify the access
       
    12  * check statement inside your settings.php file. After finishing the upgrade,
       
    13  * be sure to open settings.php again, and change it back to its original state!
       
    14  */
       
    15 
       
    16 /**
       
    17  * Global flag to identify update.php run, and so avoid various unwanted
       
    18  * operations, such as hook_init() and hook_exit() invokes, css/js preprocessing
       
    19  * and translation, and solve some theming issues. This flag is checked on several
       
    20  * places in Drupal code (not just update.php).
       
    21  */
       
    22 define('MAINTENANCE_MODE', 'update');
       
    23 
       
    24 /**
       
    25  * Add a column to a database using syntax appropriate for PostgreSQL.
       
    26  * Save result of SQL commands in $ret array.
       
    27  *
       
    28  * Note: when you add a column with NOT NULL and you are not sure if there are
       
    29  * already rows in the table, you MUST also add DEFAULT. Otherwise PostgreSQL
       
    30  * won't work when the table is not empty, and db_add_column() will fail.
       
    31  * To have an empty string as the default, you must use: 'default' => "''"
       
    32  * in the $attributes array. If NOT NULL and DEFAULT are set the PostgreSQL
       
    33  * version will set values of the added column in old rows to the
       
    34  * DEFAULT value.
       
    35  *
       
    36  * @param $ret
       
    37  *   Array to which results will be added.
       
    38  * @param $table
       
    39  *   Name of the table, without {}
       
    40  * @param $column
       
    41  *   Name of the column
       
    42  * @param $type
       
    43  *   Type of column
       
    44  * @param $attributes
       
    45  *   Additional optional attributes. Recognized attributes:
       
    46  *     not null => TRUE|FALSE
       
    47  *     default  => NULL|FALSE|value (the value must be enclosed in '' marks)
       
    48  * @return
       
    49  *   nothing, but modifies $ret parameter.
       
    50  */
       
    51 function db_add_column(&$ret, $table, $column, $type, $attributes = array()) {
       
    52   if (array_key_exists('not null', $attributes) and $attributes['not null']) {
       
    53     $not_null = 'NOT NULL';
       
    54   }
       
    55   if (array_key_exists('default', $attributes)) {
       
    56     if (is_null($attributes['default'])) {
       
    57       $default_val = 'NULL';
       
    58       $default = 'default NULL';
       
    59     }
       
    60     elseif ($attributes['default'] === FALSE) {
       
    61       $default = '';
       
    62     }
       
    63     else {
       
    64       $default_val = "$attributes[default]";
       
    65       $default = "default $attributes[default]";
       
    66     }
       
    67   }
       
    68 
       
    69   $ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column $type");
       
    70   if (!empty($default)) {
       
    71     $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET $default");
       
    72   }
       
    73   if (!empty($not_null)) {
       
    74     if (!empty($default)) {
       
    75       $ret[] = update_sql("UPDATE {". $table ."} SET $column = $default_val");
       
    76     }
       
    77     $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET NOT NULL");
       
    78   }
       
    79 }
       
    80 
       
    81 /**
       
    82  * Change a column definition using syntax appropriate for PostgreSQL.
       
    83  * Save result of SQL commands in $ret array.
       
    84  *
       
    85  * Remember that changing a column definition involves adding a new column
       
    86  * and dropping an old one. This means that any indices, primary keys and
       
    87  * sequences from serial-type columns are dropped and might need to be
       
    88  * recreated.
       
    89  *
       
    90  * @param $ret
       
    91  *   Array to which results will be added.
       
    92  * @param $table
       
    93  *   Name of the table, without {}
       
    94  * @param $column
       
    95  *   Name of the column to change
       
    96  * @param $column_new
       
    97  *   New name for the column (set to the same as $column if you don't want to change the name)
       
    98  * @param $type
       
    99  *   Type of column
       
   100  * @param $attributes
       
   101  *   Additional optional attributes. Recognized attributes:
       
   102  *     not null => TRUE|FALSE
       
   103  *     default  => NULL|FALSE|value (with or without '', it won't be added)
       
   104  * @return
       
   105  *   nothing, but modifies $ret parameter.
       
   106  */
       
   107 function db_change_column(&$ret, $table, $column, $column_new, $type, $attributes = array()) {
       
   108   if (array_key_exists('not null', $attributes) and $attributes['not null']) {
       
   109     $not_null = 'NOT NULL';
       
   110   }
       
   111   if (array_key_exists('default', $attributes)) {
       
   112     if (is_null($attributes['default'])) {
       
   113       $default_val = 'NULL';
       
   114       $default = 'default NULL';
       
   115     }
       
   116     elseif ($attributes['default'] === FALSE) {
       
   117       $default = '';
       
   118     }
       
   119     else {
       
   120       $default_val = "$attributes[default]";
       
   121       $default = "default $attributes[default]";
       
   122     }
       
   123   }
       
   124 
       
   125   $ret[] = update_sql("ALTER TABLE {". $table ."} RENAME $column TO ". $column ."_old");
       
   126   $ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column_new $type");
       
   127   $ret[] = update_sql("UPDATE {". $table ."} SET $column_new = ". $column ."_old");
       
   128   if ($default) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column_new SET $default"); }
       
   129   if ($not_null) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column_new SET NOT NULL"); }
       
   130   $ret[] = update_sql("ALTER TABLE {". $table ."} DROP ". $column ."_old");
       
   131 }
       
   132 
       
   133 /**
       
   134  * Perform one update and store the results which will later be displayed on
       
   135  * the finished page.
       
   136  *
       
   137  * An update function can force the current and all later updates for this
       
   138  * module to abort by returning a $ret array with an element like:
       
   139  * $ret['#abort'] = array('success' => FALSE, 'query' => 'What went wrong');
       
   140  * The schema version will not be updated in this case, and all the
       
   141  * aborted updates will continue to appear on update.php as updates that
       
   142  * have not yet been run.
       
   143  *
       
   144  * @param $module
       
   145  *   The module whose update will be run.
       
   146  * @param $number
       
   147  *   The update number to run.
       
   148  * @param $context
       
   149  *   The batch context array
       
   150  */
       
   151 function update_do_one($module, $number, &$context) {
       
   152   // If updates for this module have been aborted
       
   153   // in a previous step, go no further.
       
   154   if (!empty($context['results'][$module]['#abort'])) {
       
   155     return;
       
   156   }
       
   157 
       
   158   $function = $module .'_update_'. $number;
       
   159   if (function_exists($function)) {
       
   160     $ret = $function($context['sandbox']);
       
   161   }
       
   162 
       
   163   if (isset($ret['#finished'])) {
       
   164     $context['finished'] = $ret['#finished'];
       
   165     unset($ret['#finished']);
       
   166   }
       
   167 
       
   168   if (!isset($context['results'][$module])) {
       
   169     $context['results'][$module] = array();
       
   170   }
       
   171   if (!isset($context['results'][$module][$number])) {
       
   172     $context['results'][$module][$number] = array();
       
   173   }
       
   174   $context['results'][$module][$number] = array_merge($context['results'][$module][$number], $ret);
       
   175 
       
   176   if (!empty($ret['#abort'])) {
       
   177     $context['results'][$module]['#abort'] = TRUE;
       
   178   }
       
   179   // Record the schema update if it was completed successfully.
       
   180   if ($context['finished'] == 1 && empty($context['results'][$module]['#abort'])) {
       
   181     drupal_set_installed_schema_version($module, $number);
       
   182   }
       
   183 
       
   184   $context['message'] = 'Updating '. check_plain($module) .' module';
       
   185 }
       
   186 
       
   187 function update_selection_page() {
       
   188   $output = '<p>The version of Drupal you are updating from has been automatically detected. You can select a different version, but you should not need to.</p>';
       
   189   $output .= '<p>Click Update to start the update process.</p>';
       
   190 
       
   191   drupal_set_title('Drupal database update');
       
   192   $output .= drupal_get_form('update_script_selection_form');
       
   193 
       
   194   update_task_list('select');
       
   195 
       
   196   return $output;
       
   197 }
       
   198 
       
   199 function update_script_selection_form() {
       
   200   $form = array();
       
   201   $form['start'] = array(
       
   202     '#tree' => TRUE,
       
   203     '#type' => 'fieldset',
       
   204     '#title' => 'Select versions',
       
   205     '#collapsible' => TRUE,
       
   206     '#collapsed' => TRUE,
       
   207   );
       
   208 
       
   209   // Ensure system.module's updates appear first
       
   210   $form['start']['system'] = array();
       
   211 
       
   212   $modules = drupal_get_installed_schema_version(NULL, FALSE, TRUE);
       
   213   foreach ($modules as $module => $schema_version) {
       
   214     $updates = drupal_get_schema_versions($module);
       
   215     // Skip incompatible module updates completely, otherwise test schema versions.
       
   216     if (!update_check_incompatibility($module) && $updates !== FALSE && $schema_version >= 0) {
       
   217       // module_invoke returns NULL for nonexisting hooks, so if no updates
       
   218       // are removed, it will == 0.
       
   219       $last_removed = module_invoke($module, 'update_last_removed');
       
   220       if ($schema_version < $last_removed) {
       
   221         $form['start'][$module] = array(
       
   222           '#value'  => '<em>'. $module .'</em> module can not be updated. Its schema version is '. $schema_version .'. Updates up to and including '. $last_removed .' have been removed in this release. In order to update <em>'. $module .'</em> module, you will first <a href="http://drupal.org/upgrade">need to upgrade</a> to the last version in which these updates were available.',
       
   223           '#prefix' => '<div class="warning">',
       
   224           '#suffix' => '</div>',
       
   225         );
       
   226         $form['start']['#collapsed'] = FALSE;
       
   227         continue;
       
   228       }
       
   229       $updates = drupal_map_assoc($updates);
       
   230       $updates[] = 'No updates available';
       
   231       $default = $schema_version;
       
   232       foreach (array_keys($updates) as $update) {
       
   233         if ($update > $schema_version) {
       
   234           $default = $update;
       
   235           break;
       
   236         }
       
   237       }
       
   238       $form['start'][$module] = array(
       
   239         '#type' => 'select',
       
   240         '#title' => $module .' module',
       
   241         '#default_value' => $default,
       
   242         '#options' => $updates,
       
   243       );
       
   244     }
       
   245   }
       
   246 
       
   247   $form['has_js'] = array(
       
   248     '#type' => 'hidden',
       
   249     '#default_value' => FALSE,
       
   250   );
       
   251   $form['submit'] = array(
       
   252     '#type' => 'submit',
       
   253     '#value' => 'Update',
       
   254   );
       
   255   return $form;
       
   256 }
       
   257 
       
   258 function update_batch() {
       
   259   global $base_url;
       
   260 
       
   261   $operations = array();
       
   262   // Set the installed version so updates start at the correct place.
       
   263   foreach ($_POST['start'] as $module => $version) {
       
   264     drupal_set_installed_schema_version($module, $version - 1);
       
   265     $updates = drupal_get_schema_versions($module);
       
   266     $max_version = max($updates);
       
   267     if ($version <= $max_version) {
       
   268       foreach ($updates as $update) {
       
   269         if ($update >= $version) {
       
   270           $operations[] = array('update_do_one', array($module, $update));
       
   271         }
       
   272       }
       
   273     }
       
   274   }
       
   275   $batch = array(
       
   276     'operations' => $operations,
       
   277     'title' => 'Updating',
       
   278     'init_message' => 'Starting updates',
       
   279     'error_message' => 'An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference.',
       
   280     'finished' => 'update_finished',
       
   281   );
       
   282   batch_set($batch);
       
   283   batch_process($base_url .'/update.php?op=results', $base_url .'/update.php');
       
   284 }
       
   285 
       
   286 function update_finished($success, $results, $operations) {
       
   287   // clear the caches in case the data has been updated.
       
   288   drupal_flush_all_caches();
       
   289 
       
   290   $_SESSION['update_results'] = $results;
       
   291   $_SESSION['update_success'] = $success;
       
   292   $_SESSION['updates_remaining'] = $operations;
       
   293 }
       
   294 
       
   295 function update_results_page() {
       
   296   drupal_set_title('Drupal database update');
       
   297   // NOTE: we can't use l() here because the URL would point to 'update.php?q=admin'.
       
   298   $links[] = '<a href="'. base_path() .'">Main page</a>';
       
   299   $links[] = '<a href="'. base_path() .'?q=admin">Administration pages</a>';
       
   300 
       
   301   update_task_list();
       
   302   // Report end result
       
   303   if (module_exists('dblog')) {
       
   304     $log_message = ' All errors have been <a href="'. base_path() .'?q=admin/reports/dblog">logged</a>.';
       
   305   }
       
   306   else {
       
   307     $log_message = ' All errors have been logged.';
       
   308   }
       
   309 
       
   310   if ($_SESSION['update_success']) {
       
   311     $output = '<p>Updates were attempted. If you see no failures below, you may proceed happily to the <a href="'. base_path() .'?q=admin">administration pages</a>. Otherwise, you may need to update your database manually.'. $log_message .'</p>';
       
   312   }
       
   313   else {
       
   314     list($module, $version) = array_pop(reset($_SESSION['updates_remaining']));
       
   315     $output = '<p class="error">The update process was aborted prematurely while running <strong>update #'. $version .' in '. $module .'.module</strong>.'. $log_message;
       
   316     if (module_exists('dblog')) {
       
   317       $output .= ' You may need to check the <code>watchdog</code> database table manually.';
       
   318     }
       
   319     $output .= '</p>';
       
   320   }
       
   321 
       
   322   if (!empty($GLOBALS['update_free_access'])) {
       
   323     $output .= "<p><strong>Reminder: don't forget to set the <code>\$update_free_access</code> value in your <code>settings.php</code> file back to <code>FALSE</code>.</strong></p>";
       
   324   }
       
   325 
       
   326   $output .= theme('item_list', $links);
       
   327 
       
   328   // Output a list of queries executed
       
   329   if (!empty($_SESSION['update_results'])) {
       
   330     $output .= '<div id="update-results">';
       
   331     $output .= '<h2>The following queries were executed</h2>';
       
   332     foreach ($_SESSION['update_results'] as $module => $updates) {
       
   333       $output .= '<h3>'. $module .' module</h3>';
       
   334       foreach ($updates as $number => $queries) {
       
   335         if ($number != '#abort') {
       
   336           $output .= '<h4>Update #'. $number .'</h4>';
       
   337           $output .= '<ul>';
       
   338           foreach ($queries as $query) {
       
   339             if ($query['success']) {
       
   340               $output .= '<li class="success">'. $query['query'] .'</li>';
       
   341             }
       
   342             else {
       
   343               $output .= '<li class="failure"><strong>Failed:</strong> '. $query['query'] .'</li>';
       
   344             }
       
   345           }
       
   346           if (!count($queries)) {
       
   347             $output .= '<li class="none">No queries</li>';
       
   348           }
       
   349         }
       
   350         $output .= '</ul>';
       
   351       }
       
   352     }
       
   353     $output .= '</div>';
       
   354   }
       
   355   unset($_SESSION['update_results']);
       
   356   unset($_SESSION['update_success']);
       
   357 
       
   358   return $output;
       
   359 }
       
   360 
       
   361 function update_info_page() {
       
   362   // Change query-strings on css/js files to enforce reload for all users.
       
   363   _drupal_flush_css_js();
       
   364   // Flush the cache of all data for the update status module.
       
   365   if (db_table_exists('cache_update')) {
       
   366     cache_clear_all('*', 'cache_update', TRUE);
       
   367   }
       
   368 
       
   369   update_task_list('info');
       
   370   drupal_set_title('Drupal database update');
       
   371   $token = drupal_get_token('update');
       
   372   $output = '<p>Use this utility to update your database whenever a new release of Drupal or a module is installed.</p><p>For more detailed information, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>';
       
   373   $output .= "<ol>\n";
       
   374   $output .= "<li><strong>Back up your database</strong>. This process will change your database values and in case of emergency you may need to revert to a backup.</li>\n";
       
   375   $output .= "<li><strong>Back up your code</strong>. Hint: when backing up module code, do not leave that backup in the 'modules' or 'sites/*/modules' directories as this may confuse Drupal's auto-discovery mechanism.</li>\n";
       
   376   $output .= '<li>Put your site into <a href="'. base_path() .'?q=admin/settings/site-maintenance">maintenance mode</a>.</li>'."\n";
       
   377   $output .= "<li>Install your new files in the appropriate location, as described in the handbook.</li>\n";
       
   378   $output .= "</ol>\n";
       
   379   $output .= "<p>When you have performed the steps above, you may proceed.</p>\n";
       
   380   $output .= '<form method="post" action="update.php?op=selection&amp;token='. $token .'"><p><input type="submit" value="Continue" /></p></form>';
       
   381   $output .= "\n";
       
   382   return $output;
       
   383 }
       
   384 
       
   385 function update_access_denied_page() {
       
   386   drupal_set_title('Access denied');
       
   387   return '<p>Access denied. You are not authorized to access this page. Please log in as the admin user (the first user you created). If you cannot log in, you will have to edit <code>settings.php</code> to bypass this access check. To do this:</p>
       
   388 <ol>
       
   389  <li>With a text editor find the settings.php file on your system. From the main Drupal directory that you installed all the files into, go to <code>sites/your_site_name</code> if such directory exists, or else to <code>sites/default</code> which applies otherwise.</li>
       
   390  <li>There is a line inside your settings.php file that says <code>$update_free_access = FALSE;</code>. Change it to <code>$update_free_access = TRUE;</code>.</li>
       
   391  <li>As soon as the update.php script is done, you must change the settings.php file back to its original form with <code>$update_free_access = FALSE;</code>.</li>
       
   392  <li>To avoid having this problem in future, remember to log in to your website as the admin user (the user you first created) before you backup your database at the beginning of the update process.</li>
       
   393 </ol>';
       
   394 }
       
   395 
       
   396 /**
       
   397  * Create the batch table.
       
   398  *
       
   399  * This is part of the Drupal 5.x to 6.x migration.
       
   400  */
       
   401 function update_create_batch_table() {
       
   402 
       
   403   // If batch table exists, update is not necessary
       
   404   if (db_table_exists('batch')) {
       
   405     return;
       
   406   }
       
   407 
       
   408   $schema['batch'] = array(
       
   409     'fields' => array(
       
   410       'bid'       => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
       
   411       'token'     => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE),
       
   412       'timestamp' => array('type' => 'int', 'not null' => TRUE),
       
   413       'batch'     => array('type' => 'text', 'not null' => FALSE, 'size' => 'big')
       
   414     ),
       
   415     'primary key' => array('bid'),
       
   416     'indexes' => array('token' => array('token')),
       
   417   );
       
   418 
       
   419   $ret = array();
       
   420   db_create_table($ret, 'batch', $schema['batch']);
       
   421   return $ret;
       
   422 }
       
   423 
       
   424 /**
       
   425  * Disable anything in the {system} table that is not compatible with the
       
   426  * current version of Drupal core.
       
   427  */
       
   428 function update_fix_compatibility() {
       
   429   $ret = array();
       
   430   $incompatible = array();
       
   431   $query = db_query("SELECT name, type, status FROM {system} WHERE status = 1 AND type IN ('module','theme')");
       
   432   while ($result = db_fetch_object($query)) {
       
   433     if (update_check_incompatibility($result->name, $result->type)) {
       
   434       $incompatible[] = $result->name;
       
   435     }
       
   436   }
       
   437   if (!empty($incompatible)) {
       
   438     $ret[] = update_sql("UPDATE {system} SET status = 0 WHERE name IN ('". implode("','", $incompatible) ."')");
       
   439   }
       
   440   return $ret;
       
   441 }
       
   442 
       
   443 /**
       
   444  * Helper function to test compatibility of a module or theme.
       
   445  */
       
   446 function update_check_incompatibility($name, $type = 'module') {
       
   447   static $themes, $modules;
       
   448 
       
   449   // Store values of expensive functions for future use.
       
   450   if (empty($themes) || empty($modules)) {
       
   451     $themes = _system_theme_data();
       
   452     $modules = module_rebuild_cache();
       
   453   }
       
   454 
       
   455   if ($type == 'module' && isset($modules[$name])) {
       
   456     $file = $modules[$name];
       
   457   }
       
   458   else if ($type == 'theme' && isset($themes[$name])) {
       
   459     $file = $themes[$name];
       
   460   }
       
   461   if (!isset($file)
       
   462       || !isset($file->info['core'])
       
   463       || $file->info['core'] != DRUPAL_CORE_COMPATIBILITY
       
   464       || version_compare(phpversion(), $file->info['php']) < 0) {
       
   465     return TRUE;
       
   466   }
       
   467   return FALSE;
       
   468 }
       
   469 
       
   470 /**
       
   471  * Perform Drupal 5.x to 6.x updates that are required for update.php
       
   472  * to function properly.
       
   473  *
       
   474  * This function runs when update.php is run the first time for 6.x,
       
   475  * even before updates are selected or performed.  It is important
       
   476  * that if updates are not ultimately performed that no changes are
       
   477  * made which make it impossible to continue using the prior version.
       
   478  * Just adding columns is safe.  However, renaming the
       
   479  * system.description column to owner is not.  Therefore, we add the
       
   480  * system.owner column and leave it to system_update_6008() to copy
       
   481  * the data from description and remove description. The same for
       
   482  * renaming locales_target.locale to locales_target.language, which
       
   483  * will be finished by locale_update_6002().
       
   484  */
       
   485 function update_fix_d6_requirements() {
       
   486   $ret = array();
       
   487 
       
   488   if (drupal_get_installed_schema_version('system') < 6000 && !variable_get('update_d6_requirements', FALSE)) {
       
   489     $spec = array('type' => 'int', 'size' => 'small', 'default' => 0, 'not null' => TRUE);
       
   490     db_add_field($ret, 'cache', 'serialized', $spec);
       
   491     db_add_field($ret, 'cache_filter', 'serialized', $spec);
       
   492     db_add_field($ret, 'cache_page', 'serialized', $spec);
       
   493     db_add_field($ret, 'cache_menu', 'serialized', $spec);
       
   494 
       
   495     db_add_field($ret, 'system', 'info', array('type' => 'text'));
       
   496     db_add_field($ret, 'system', 'owner', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
       
   497     if (db_table_exists('locales_target')) {
       
   498       db_add_field($ret, 'locales_target', 'language', array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => ''));
       
   499     }
       
   500     if (db_table_exists('locales_source')) {
       
   501       db_add_field($ret, 'locales_source', 'textgroup', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'default'));
       
   502       db_add_field($ret, 'locales_source', 'version', array('type' => 'varchar', 'length' => 20, 'not null' => TRUE, 'default' => 'none'));
       
   503     }
       
   504     variable_set('update_d6_requirements', TRUE);
       
   505 
       
   506     // Create the cache_block table. See system_update_6027() for more details.
       
   507     $schema['cache_block'] = array(
       
   508       'fields' => array(
       
   509         'cid'        => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       
   510         'data'       => array('type' => 'blob', 'not null' => FALSE, 'size' => 'big'),
       
   511         'expire'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       
   512         'created'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       
   513         'headers'    => array('type' => 'text', 'not null' => FALSE),
       
   514         'serialized' => array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0)
       
   515       ),
       
   516       'indexes' => array('expire' => array('expire')),
       
   517       'primary key' => array('cid'),
       
   518     );
       
   519     db_create_table($ret, 'cache_block', $schema['cache_block']);
       
   520   }
       
   521 
       
   522   return $ret;
       
   523 }
       
   524 
       
   525 /**
       
   526  * Add the update task list to the current page.
       
   527  */
       
   528 function update_task_list($active = NULL) {
       
   529   // Default list of tasks.
       
   530   $tasks = array(
       
   531     'info' => 'Overview',
       
   532     'select' => 'Select updates',
       
   533     'run' => 'Run updates',
       
   534     'finished' => 'Review log',
       
   535   );
       
   536 
       
   537   drupal_set_content('left', theme('task_list', $tasks, $active));
       
   538 }
       
   539 
       
   540 /**
       
   541  * Check update requirements and report any errors.
       
   542  */
       
   543 function update_check_requirements() {
       
   544   // Check the system module requirements only.
       
   545   $requirements = module_invoke('system', 'requirements', 'update');
       
   546   $severity = drupal_requirements_severity($requirements);
       
   547 
       
   548   // If there are issues, report them.
       
   549   if ($severity != REQUIREMENT_OK) {
       
   550     foreach ($requirements as $requirement) {
       
   551       if (isset($requirement['severity']) && $requirement['severity'] != REQUIREMENT_OK) {
       
   552         $message = isset($requirement['description']) ? $requirement['description'] : '';
       
   553         if (isset($requirement['value']) && $requirement['value']) {
       
   554           $message .= ' (Currently using '. $requirement['title'] .' '. $requirement['value'] .')';
       
   555         }
       
   556         drupal_set_message($message, 'warning');
       
   557       }
       
   558     }
       
   559   }
       
   560 }
       
   561 
       
   562 // Some unavoidable errors happen because the database is not yet up-to-date.
       
   563 // Our custom error handler is not yet installed, so we just suppress them.
       
   564 ini_set('display_errors', FALSE);
       
   565 
       
   566 require_once './includes/bootstrap.inc';
       
   567 
       
   568 // We only load DRUPAL_BOOTSTRAP_CONFIGURATION for the update requirements
       
   569 // check to avoid reaching the PHP memory limit.
       
   570 $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
       
   571 if (empty($op)) {
       
   572   // Minimum load of components.
       
   573   drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
       
   574 
       
   575   require_once './includes/install.inc';
       
   576   require_once './includes/file.inc';
       
   577   require_once './modules/system/system.install';
       
   578 
       
   579   // Load module basics.
       
   580   include_once './includes/module.inc';
       
   581   $module_list['system']['filename'] = 'modules/system/system.module';
       
   582   $module_list['filter']['filename'] = 'modules/filter/filter.module';
       
   583   module_list(TRUE, FALSE, FALSE, $module_list);
       
   584   drupal_load('module', 'system');
       
   585   drupal_load('module', 'filter');
       
   586 
       
   587   // Set up $language, since the installer components require it.
       
   588   drupal_init_language();
       
   589 
       
   590   // Set up theme system for the maintenance page.
       
   591   drupal_maintenance_theme();
       
   592 
       
   593   // Check the update requirements for Drupal.
       
   594   update_check_requirements();
       
   595 
       
   596   // Display the warning messages (if any) in a dedicated maintenance page,
       
   597   // or redirect to the update information page if no message.
       
   598   $messages = drupal_set_message();
       
   599   if (!empty($messages['warning'])) {
       
   600     drupal_maintenance_theme();
       
   601     print theme('update_page', '<form method="post" action="update.php?op=info"><input type="submit" value="Continue" /></form>', FALSE);
       
   602     exit;
       
   603   }
       
   604   install_goto('update.php?op=info');
       
   605 }
       
   606 
       
   607 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
       
   608 drupal_maintenance_theme();
       
   609 
       
   610 // This must happen *after* drupal_bootstrap(), since it calls
       
   611 // variable_(get|set), which only works after a full bootstrap.
       
   612 update_create_batch_table();
       
   613 
       
   614 // Turn error reporting back on. From now on, only fatal errors (which are
       
   615 // not passed through the error handler) will cause a message to be printed.
       
   616 ini_set('display_errors', TRUE);
       
   617 
       
   618 // Access check:
       
   619 if (!empty($update_free_access) || $user->uid == 1) {
       
   620 
       
   621   include_once './includes/install.inc';
       
   622   include_once './includes/batch.inc';
       
   623   drupal_load_updates();
       
   624 
       
   625   update_fix_d6_requirements();
       
   626   update_fix_compatibility();
       
   627 
       
   628   $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : '';
       
   629   switch ($op) {
       
   630     case 'selection':
       
   631       if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) {
       
   632         $output = update_selection_page();
       
   633         break;
       
   634       }
       
   635 
       
   636     case 'Update':
       
   637       if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) {
       
   638         update_batch();
       
   639         break;
       
   640       }
       
   641 
       
   642     // update.php ops
       
   643     case 'info':
       
   644       $output = update_info_page();
       
   645       break;
       
   646 
       
   647     case 'results':
       
   648       $output = update_results_page();
       
   649       break;
       
   650 
       
   651     // Regular batch ops : defer to batch processing API
       
   652     default:
       
   653       update_task_list('run');
       
   654       $output = _batch_page();
       
   655       break;
       
   656   }
       
   657 }
       
   658 else {
       
   659   $output = update_access_denied_page();
       
   660 }
       
   661 if (isset($output) && $output) {
       
   662   // We defer the display of messages until all updates are done.
       
   663   $progress_page = ($batch = batch_get()) && isset($batch['running']);
       
   664   print theme('update_page', $output, !$progress_page);
       
   665 }