2001-11-15 22:53:06 +00:00
< ? php
2003-09-25 07:27:22 +00:00
// $Id$
2004-08-21 06:42:38 +00:00
2008-09-20 20:22:25 +00:00
/**
* Root directory of Drupal installation .
*/
2009-02-08 20:27:51 +00:00
define ( 'DRUPAL_ROOT' , getcwd ());
2008-09-20 20:22:25 +00:00
2004-08-21 06:42:38 +00:00
/**
* @ file
* Administrative page for handling updates from one Drupal version to another .
*
2006-03-11 13:45:41 +00:00
* Point your browser to " http://www.example.com/update.php " and follow the
2004-08-21 06:42:38 +00:00
* instructions .
*
2009-10-09 07:48:07 +00:00
* If you are not logged in using either the site maintenance account or an
* account with the " Administer software updates " permission , you will need to
* modify the access check statement inside your settings . php file . After
* finishing the upgrade , be sure to open settings . php again , and change it
* back to its original state !
2004-08-21 06:42:38 +00:00
*/
2001-12-16 14:42:51 +00:00
2008-01-07 19:43:29 +00:00
/**
* Global flag to identify update . php run , and so avoid various unwanted
* operations , such as hook_init () and hook_exit () invokes , css / js preprocessing
* and translation , and solve some theming issues . This flag is checked on several
* places in Drupal code ( not just update . php ) .
*/
2007-11-30 12:19:10 +00:00
define ( 'MAINTENANCE_MODE' , 'update' );
2005-12-06 09:25:22 +00:00
function update_selection_page () {
2006-08-18 18:58:47 +00:00
drupal_set_title ( 'Drupal database update' );
2009-05-12 08:37:45 +00:00
$output = drupal_render ( drupal_get_form ( 'update_script_selection_form' ));
2006-08-18 18:58:47 +00:00
2007-03-02 09:40:27 +00:00
update_task_list ( 'select' );
2006-08-18 18:58:47 +00:00
return $output ;
}
2009-11-04 05:39:14 +00:00
function update_script_selection_form ( $form , & $form_state ) {
2008-10-24 18:47:02 +00:00
$count = 0 ;
2005-10-07 06:11:12 +00:00
$form [ 'start' ] = array (
2005-12-06 09:25:22 +00:00
'#tree' => TRUE ,
'#type' => 'fieldset' ,
'#collapsed' => TRUE ,
2008-08-31 12:45:41 +00:00
'#collapsible' => TRUE ,
2005-12-06 09:25:22 +00:00
);
2006-07-31 16:23:52 +00:00
// Ensure system.module's updates appear first
$form [ 'start' ][ 'system' ] = array ();
2009-08-21 06:40:05 +00:00
$updates = update_get_update_list ();
foreach ( $updates as $module => $update ) {
if ( ! isset ( $update [ 'start' ])) {
$form [ 'start' ][ $module ] = array (
'#title' => $module ,
'#item' => $update [ 'warning' ],
'#prefix' => '<div class="warning">' ,
'#suffix' => '</div>' ,
);
continue ;
}
if ( ! empty ( $update [ 'pending' ])) {
$form [ 'start' ][ $module ] = array (
'#type' => 'hidden' ,
'#value' => $update [ 'start' ],
);
$form [ 'start' ][ $module . '_updates' ] = array (
2009-10-09 01:00:08 +00:00
'#markup' => theme ( 'item_list' , array ( 'items' => $update [ 'pending' ], 'title' => $module . ' module' )),
2009-08-21 06:40:05 +00:00
);
}
if ( isset ( $update [ 'pending' ])) {
$count = $count + count ( $update [ 'pending' ]);
2005-12-06 09:25:22 +00:00
}
}
2008-10-24 18:47:02 +00:00
if ( empty ( $count )) {
2008-08-31 12:45:41 +00:00
drupal_set_message ( t ( 'No pending updates.' ));
unset ( $form );
$form [ 'links' ] = array (
2009-10-09 01:00:08 +00:00
'#markup' => theme ( 'item_list' , array ( 'items' => update_helpful_links ())),
2008-08-31 12:45:41 +00:00
);
}
else {
$form [ 'help' ] = array (
'#markup' => '<p>The version of Drupal you are updating from has been automatically detected.</p>' ,
'#weight' => - 5 ,
);
2009-09-28 22:16:32 +00:00
$form [ 'start' ][ '#title' ] = format_plural ( $count , '1 pending update' , '@count pending updates' );
2008-08-31 12:45:41 +00:00
$form [ 'has_js' ] = array (
'#type' => 'hidden' ,
'#default_value' => FALSE ,
);
$form [ 'submit' ] = array (
'#type' => 'submit' ,
2009-03-01 08:07:36 +00:00
'#value' => 'Apply pending updates' ,
2008-08-31 12:45:41 +00:00
);
}
2006-08-18 18:58:47 +00:00
return $form ;
2005-12-06 09:25:22 +00:00
}
2008-08-31 12:45:41 +00:00
function update_helpful_links () {
2005-08-17 01:44:14 +00:00
// NOTE: we can't use l() here because the URL would point to 'update.php?q=admin'.
2009-01-17 18:55:29 +00:00
$links [] = '<a href="' . base_path () . '">Front page</a>' ;
2008-04-14 17:48:46 +00:00
$links [] = '<a href="' . base_path () . '?q=admin">Administration pages</a>' ;
2008-08-31 12:45:41 +00:00
return $links ;
}
function update_results_page () {
drupal_set_title ( 'Drupal database update' );
$links = update_helpful_links ();
2006-03-01 22:19:24 +00:00
2007-03-02 09:40:27 +00:00
update_task_list ();
2006-03-28 09:29:23 +00:00
// Report end result
2007-10-02 08:41:13 +00:00
if ( module_exists ( 'dblog' )) {
2008-04-14 17:48:46 +00:00
$log_message = ' All errors have been <a href="' . base_path () . '?q=admin/reports/dblog">logged</a>.' ;
2007-10-02 08:41:13 +00:00
}
else {
$log_message = ' All errors have been logged.' ;
}
2007-05-04 09:41:37 +00:00
if ( $_SESSION [ 'update_success' ]) {
2008-04-14 17:48:46 +00:00
$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>' ;
2006-03-01 22:19:24 +00:00
}
else {
2007-05-04 09:41:37 +00:00
list ( $module , $version ) = array_pop ( reset ( $_SESSION [ 'updates_remaining' ]));
2008-04-14 17:48:46 +00:00
$output = '<p class="error">The update process was aborted prematurely while running <strong>update #' . $version . ' in ' . $module . '.module</strong>.' . $log_message ;
2007-10-02 08:41:13 +00:00
if ( module_exists ( 'dblog' )) {
$output .= ' You may need to check the <code>watchdog</code> database table manually.' ;
}
$output .= '</p>' ;
2006-03-01 22:19:24 +00:00
}
2007-08-28 11:42:56 +00:00
if ( ! empty ( $GLOBALS [ 'update_free_access' ])) {
$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> " ;
2001-11-15 22:53:06 +00:00
}
2007-05-06 05:47:52 +00:00
2009-10-09 01:00:08 +00:00
$output .= theme ( 'item_list' , array ( 'items' => $links ));
2005-12-06 09:25:22 +00:00
// Output a list of queries executed
2007-03-28 07:02:47 +00:00
if ( ! empty ( $_SESSION [ 'update_results' ])) {
2005-12-06 09:25:22 +00:00
$output .= '<div id="update-results">' ;
2009-09-07 15:43:55 +00:00
$output .= '<h2>The following updates returned messages</h2>' ;
2005-12-06 09:25:22 +00:00
foreach ( $_SESSION [ 'update_results' ] as $module => $updates ) {
2008-04-14 17:48:46 +00:00
$output .= '<h3>' . $module . ' module</h3>' ;
2005-12-06 09:25:22 +00:00
foreach ( $updates as $number => $queries ) {
2008-01-17 20:05:23 +00:00
if ( $number != '#abort' ) {
2009-09-07 15:43:55 +00:00
$messages = array ();
2008-01-17 20:05:23 +00:00
foreach ( $queries as $query ) {
2009-09-07 15:43:55 +00:00
// If there is no message for this update, don't show anything.
if ( empty ( $query [ 'query' ])) {
continue ;
}
2008-01-17 20:05:23 +00:00
if ( $query [ 'success' ]) {
2009-09-07 15:43:55 +00:00
$messages [] = '<li class="success">' . $query [ 'query' ] . '</li>' ;
2008-01-17 20:05:23 +00:00
}
else {
2009-09-07 15:43:55 +00:00
$messages [] = '<li class="failure"><strong>Failed:</strong> ' . $query [ 'query' ] . '</li>' ;
2008-01-17 20:05:23 +00:00
}
2005-12-06 09:25:22 +00:00
}
2009-09-07 15:43:55 +00:00
if ( $messages ) {
$output .= '<h4>Update #' . $number . " </h4> \n " ;
$output .= '<ul>' . implode ( " \n " , $messages ) . " </ul> \n " ;
2005-12-06 09:25:22 +00:00
}
}
$output .= '</ul>' ;
}
}
$output .= '</div>' ;
}
2007-05-04 09:41:37 +00:00
unset ( $_SESSION [ 'update_results' ]);
unset ( $_SESSION [ 'update_success' ]);
2005-12-06 09:25:22 +00:00
2005-08-17 01:44:14 +00:00
return $output ;
2001-11-15 22:53:06 +00:00
}
2005-08-17 01:44:14 +00:00
function update_info_page () {
2008-01-07 19:43:29 +00:00
// Change query-strings on css/js files to enforce reload for all users.
_drupal_flush_css_js ();
2008-01-30 22:13:25 +00:00
// Flush the cache of all data for the update status module.
if ( db_table_exists ( 'cache_update' )) {
2008-02-03 18:41:16 +00:00
cache_clear_all ( '*' , 'cache_update' , TRUE );
2008-01-30 22:13:25 +00:00
}
2008-01-07 19:43:29 +00:00
2007-03-02 09:40:27 +00:00
update_task_list ( 'info' );
2005-07-29 20:31:05 +00:00
drupal_set_title ( 'Drupal database update' );
2009-01-21 14:47:12 +00:00
$token = drupal_get_token ( 'update' );
2007-07-15 05:57:40 +00:00
$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>' ;
$output .= " <ol> \n " ;
$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 " ;
$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 " ;
2009-08-11 17:26:33 +00:00
$output .= '<li>Put your site into <a href="' . base_path () . '?q=admin/config/development/maintenance">maintenance mode</a>.</li>' . " \n " ;
2007-07-15 05:57:40 +00:00
$output .= " <li>Install your new files in the appropriate location, as described in the handbook.</li> \n " ;
$output .= " </ol> \n " ;
$output .= " <p>When you have performed the steps above, you may proceed.</p> \n " ;
2009-11-19 03:11:53 +00:00
$output .= '<form method="post" action="update.php?op=selection&token=' . $token . '"><p><input type="submit" value="Continue" class="form-submit" /></p></form>' ;
2007-07-15 05:57:40 +00:00
$output .= " \n " ;
2005-08-17 01:44:14 +00:00
return $output ;
}
function update_access_denied_page () {
2009-10-09 07:48:07 +00:00
drupal_add_http_header ( '403 Forbidden' );
watchdog ( 'access denied' , 'update.php' , NULL , WATCHDOG_WARNING );
2005-08-17 01:44:14 +00:00
drupal_set_title ( 'Access denied' );
2009-10-09 07:48:07 +00:00
return ' < p > Access denied . You are not authorized to access this page . Please log in using either an account with the < em > administer software updates </ em > permission or the site maintenance account ( the account you created during installation ) . If you cannot log in , you will have to edit < code > settings . php </ code > to bypass this access check . To do this :</ p >
2005-08-17 01:44:14 +00:00
< ol >
2007-08-28 11:42:56 +00:00
< 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 >
< 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 >
< 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 >
2009-10-09 07:48:07 +00:00
< li > To avoid having this problem in the future , remember to log in to your website using either an account with the < em > administer software updates </ em > permission or the site maintenance account ( the account you created during installation ) before you backup your database at the beginning of the update process .</ li >
2005-08-17 01:44:14 +00:00
</ ol > ' ;
2001-11-15 22:53:06 +00:00
}
2002-05-11 17:23:45 +00:00
2009-10-09 07:48:07 +00:00
/**
* Determines if the current user is allowed to run update . php .
*
* @ return
* TRUE if the current user should be granted access , or FALSE otherwise .
*/
function update_access_allowed () {
global $update_free_access , $user ;
// Allow the global variable in settings.php to override the access check.
if ( ! empty ( $update_free_access )) {
return TRUE ;
}
// Calls to user_access() might fail during the Drupal 6 to 7 update process,
// so we fall back on requiring that the user be logged in as user #1.
try {
require_once drupal_get_path ( 'module' , 'user' ) . '/user.module' ;
return user_access ( 'administer software updates' );
}
catch ( Exception $e ) {
return ( $user -> uid == 1 );
}
}
2007-03-02 09:40:27 +00:00
/**
* Add the update task list to the current page .
*/
function update_task_list ( $active = NULL ) {
// Default list of tasks.
$tasks = array (
2009-05-09 18:35:01 +00:00
'requirements' => 'Verify requirements' ,
2007-03-02 09:40:27 +00:00
'info' => 'Overview' ,
2008-08-31 12:45:41 +00:00
'select' => 'Review updates' ,
2007-03-02 09:40:27 +00:00
'run' => 'Run updates' ,
'finished' => 'Review log' ,
);
2009-10-09 01:00:08 +00:00
drupal_add_region_content ( 'sidebar_first' , theme ( 'task_list' , array ( 'items' => $tasks , 'active' => $active )));
2007-03-02 09:40:27 +00:00
}
2008-01-16 10:37:43 +00:00
/**
2009-05-09 18:35:01 +00:00
* Returns ( and optionally stores ) extra requirements that only apply during
* particular parts of the update . php process .
2008-01-16 10:37:43 +00:00
*/
2009-05-09 18:35:01 +00:00
function update_extra_requirements ( $requirements = NULL ) {
static $extra_requirements = array ();
if ( isset ( $requirements )) {
$extra_requirements += $requirements ;
2008-01-16 10:37:43 +00:00
}
2009-05-09 18:35:01 +00:00
return $extra_requirements ;
2009-03-01 09:32:17 +00:00
}
/**
2009-05-09 18:35:01 +00:00
* Check update requirements and report any errors .
2009-03-01 09:32:17 +00:00
*/
2009-05-09 18:35:01 +00:00
function update_check_requirements () {
// Check the system module and update.php requirements only.
$requirements = module_invoke ( 'system' , 'requirements' , 'update' );
$requirements += update_extra_requirements ();
$severity = drupal_requirements_severity ( $requirements );
// If there are issues, report them.
if ( $severity == REQUIREMENT_ERROR ) {
update_task_list ( 'requirements' );
drupal_set_title ( 'Requirements problem' );
2009-10-09 01:00:08 +00:00
$status_report = theme ( 'status_report' , array ( 'requirements' => $requirements ));
2009-05-09 18:35:01 +00:00
$status_report .= 'Please check the error messages and <a href="' . request_uri () . '">try again</a>.' ;
2009-10-09 01:00:08 +00:00
print theme ( 'update_page' , array ( 'content' => $status_report ));
2009-05-09 18:35:01 +00:00
exit ();
2009-03-01 09:32:17 +00:00
}
2008-01-16 10:37:43 +00:00
}
2006-03-11 13:45:41 +00:00
// Some unavoidable errors happen because the database is not yet up-to-date.
2006-04-11 11:33:15 +00:00
// Our custom error handler is not yet installed, so we just suppress them.
2006-03-01 22:19:24 +00:00
ini_set ( 'display_errors' , FALSE );
2009-05-09 18:35:01 +00:00
// We prepare a minimal bootstrap for the update requirements check to avoid
// reaching the PHP memory limit.
2008-09-20 20:22:25 +00:00
require_once DRUPAL_ROOT . '/includes/bootstrap.inc' ;
2009-07-29 05:59:59 +00:00
require_once DRUPAL_ROOT . '/includes/update.inc' ;
2009-08-25 21:53:48 +00:00
require_once DRUPAL_ROOT . '/includes/common.inc' ;
require_once DRUPAL_ROOT . '/includes/entity.inc' ;
2009-05-09 18:35:01 +00:00
update_prepare_d7_bootstrap ();
2008-01-16 10:37:43 +00:00
2009-05-09 18:35:01 +00:00
// Determine if the current user has access to run update.php.
drupal_bootstrap ( DRUPAL_BOOTSTRAP_SESSION );
2008-01-16 10:37:43 +00:00
2009-05-09 18:35:01 +00:00
// Only allow the requirements check to proceed if the current user has access
// to run updates (since it may expose sensitive information about the site's
// configuration).
$op = isset ( $_REQUEST [ 'op' ]) ? $_REQUEST [ 'op' ] : '' ;
2009-10-09 07:48:07 +00:00
if ( empty ( $op ) && update_access_allowed ()) {
2008-09-20 20:22:25 +00:00
require_once DRUPAL_ROOT . '/includes/install.inc' ;
require_once DRUPAL_ROOT . '/includes/file.inc' ;
require_once DRUPAL_ROOT . '/modules/system/system.install' ;
2008-01-16 10:37:43 +00:00
// Load module basics.
2008-09-20 20:22:25 +00:00
include_once DRUPAL_ROOT . '/includes/module.inc' ;
2008-01-16 10:37:43 +00:00
$module_list [ 'system' ][ 'filename' ] = 'modules/system/system.module' ;
2009-08-24 00:14:23 +00:00
module_list ( TRUE , FALSE , FALSE , $module_list );
2008-01-16 10:37:43 +00:00
drupal_load ( 'module' , 'system' );
- Patch #557542 by CorniI, catch, fago, Crell, sun | pwolanin, chx, webchick, mattyoung, alexanderpas, justinrandell, dropcube, moshe weitzman, Damien Tournoud, Rob Loach, Dries: cache module_implements() for better performance and scalability.
2009-09-27 11:08:45 +00:00
// Reset the module_implements() cache so that any new hook implementations
// in updated code are picked up.
module_implements ( '' , FALSE , TRUE );
2008-01-16 10:37:43 +00:00
// Set up $language, since the installer components require it.
2009-07-14 10:22:17 +00:00
drupal_language_initialize ();
2008-01-16 10:37:43 +00:00
// Set up theme system for the maintenance page.
drupal_maintenance_theme ();
// Check the update requirements for Drupal.
2009-05-09 18:35:01 +00:00
update_check_requirements ();
2009-03-01 09:32:17 +00:00
2009-05-09 18:35:01 +00:00
// Redirect to the update information page if all requirements were met.
2008-01-16 10:37:43 +00:00
install_goto ( 'update.php?op=info' );
}
2006-03-28 09:29:23 +00:00
2009-10-24 01:22:28 +00:00
// update_fix_d7_requirements() needs to run before bootstrapping beyond path.
// So bootstrap to DRUPAL_BOOTSTRAP_LANGUAGE then include unicode.inc.
drupal_bootstrap ( DRUPAL_BOOTSTRAP_LANGUAGE );
include_once DRUPAL_ROOT . '/includes/unicode.inc' ;
update_fix_d7_requirements ();
// Now proceed with a full bootstrap.
2005-12-06 09:25:22 +00:00
drupal_bootstrap ( DRUPAL_BOOTSTRAP_FULL );
2005-07-29 20:31:05 +00:00
drupal_maintenance_theme ();
2005-08-31 17:56:07 +00:00
2006-03-28 09:29:23 +00:00
// Turn error reporting back on. From now on, only fatal errors (which are
// not passed through the error handler) will cause a message to be printed.
ini_set ( 'display_errors' , TRUE );
2009-05-09 18:35:01 +00:00
// Only proceed with updates if the user is allowed to run them.
2009-10-09 07:48:07 +00:00
if ( update_access_allowed ()) {
2006-03-28 09:29:23 +00:00
2008-09-20 20:22:25 +00:00
include_once DRUPAL_ROOT . '/includes/install.inc' ;
include_once DRUPAL_ROOT . '/includes/batch.inc' ;
2006-07-31 19:24:16 +00:00
drupal_load_updates ();
2003-01-07 05:56:47 +00:00
2007-06-08 05:50:58 +00:00
update_fix_compatibility ();
2005-08-17 01:44:14 +00:00
2005-12-06 09:25:22 +00:00
$op = isset ( $_REQUEST [ 'op' ]) ? $_REQUEST [ 'op' ] : '' ;
switch ( $op ) {
2007-05-04 09:41:37 +00:00
// update.php ops
2005-12-06 09:25:22 +00:00
2007-05-04 09:41:37 +00:00
case 'selection' :
2009-01-21 14:47:12 +00:00
if ( isset ( $_GET [ 'token' ]) && $_GET [ 'token' ] == drupal_get_token ( 'update' )) {
$output = update_selection_page ();
break ;
}
2005-12-06 09:25:22 +00:00
2009-03-01 09:17:53 +00:00
case 'Apply pending updates' :
2009-01-21 14:47:12 +00:00
if ( isset ( $_GET [ 'token' ]) && $_GET [ 'token' ] == drupal_get_token ( 'update' )) {
2009-08-03 19:37:38 +00:00
update_batch ( $_POST [ 'start' ], $base_url . '/update.php?op=results' , $base_url . '/update.php' );
2009-01-21 14:47:12 +00:00
break ;
}
case 'info' :
$output = update_info_page ();
2005-12-06 09:25:22 +00:00
break ;
2007-05-04 09:41:37 +00:00
case 'results' :
$output = update_results_page ();
2005-12-06 09:25:22 +00:00
break ;
2007-05-04 09:41:37 +00:00
// Regular batch ops : defer to batch processing API
2005-12-06 09:25:22 +00:00
default :
2007-05-04 09:41:37 +00:00
update_task_list ( 'run' );
$output = _batch_page ();
2005-12-06 09:25:22 +00:00
break ;
2002-05-15 22:36:30 +00:00
}
}
else {
2005-12-06 09:25:22 +00:00
$output = update_access_denied_page ();
2005-08-17 01:44:14 +00:00
}
2007-05-04 09:41:37 +00:00
if ( isset ( $output ) && $output ) {
2009-10-24 01:31:05 +00:00
// Explictly start a session so that the update.php token will be accepted.
drupal_session_start ();
2007-12-20 11:57:20 +00:00
// We defer the display of messages until all updates are done.
$progress_page = ( $batch = batch_get ()) && isset ( $batch [ 'running' ]);
2009-10-09 01:00:08 +00:00
print theme ( 'update_page' , array ( 'content' => $output , 'show_messages' => ! $progress_page ));
2006-03-14 21:19:41 +00:00
}