* Made the web upgrade process more friendly. Instead of saying "access denied, go...
authorTim Starling <tstarling@users.mediawiki.org>
Thu, 9 Dec 2010 08:24:54 +0000 (08:24 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Thu, 9 Dec 2010 08:24:54 +0000 (08:24 +0000)
* When an upgrade key is entered, or a supplied upgrade key is edited into LocalSettings.php by the upgrader, fetch database settings from LocalSettings.php and AdminSettings.php for use during the upgrade. This allows the DBConnect page to be skipped, making web upgrade almost as easy to use as CLI upgrade.
* Made LocalSettingsGenerator add $wgUpgradeKey in non-commented form, for easier subsequent upgrades.
* Converted the $wgUpgradeKey check to a normal in-sequence page, called ExistingWiki. This allows the removal of related special cases from WebInstaller. The code for WebInstaller_ExistingWiki is loosely based on WebInstaller_Locked.
* Added Status::replaceMessage(), to support informative DB connection error messages from the ExistingWiki page.
* In WebInstaller::getInfoBox(), call parse() with $lineStart=true, so that line-start syntax like bullet points can work.
* Reduced the length of the generated $wgUpgradeKey from 64 to 16. This is ample for what it does, and makes it fit on the screen and not overlap with the right sidebar when when displayed by WebInstaller_ExistingWiki.
* Added $wgUpgradeKey to DefaultSettings.php.

includes/DefaultSettings.php
includes/Status.php
includes/installer/CoreInstaller.php
includes/installer/Installer.i18n.php
includes/installer/Installer.php
includes/installer/LocalSettingsGenerator.php
includes/installer/WebInstaller.php
includes/installer/WebInstallerPage.php

index ccd5261..a2ee8e5 100644 (file)
@@ -5233,6 +5233,10 @@ $wgEnableSelenium = false;
 $wgSeleniumTestConfigs = array();
 $wgSeleniumConfigFile = null;
 
+/**
+ * Set this to a random string to allow web-based upgrades
+ */
+$wgUpgradeKey = false;
 
 
 /**
index ffb396c..f049980 100644 (file)
@@ -300,6 +300,23 @@ class Status {
                return false;
        }
 
+       /**
+        * If the specified source message exists, replace it with the specified 
+        * destination message, but keep the same parameters as in the original error.
+        *
+        * Return true if the replacement was done, false otherwise.
+        */
+       function replaceMessage( $source, $dest ) {
+               $replaced = false;
+               foreach ( $this->errors as $index => $error ) {
+                       if ( $error['message'] === $source ) {
+                               $this->errors[$index]['message'] = $dest;
+                               $replaced = true;
+                       }
+               }
+               return $replaced;
+       }
+
        /**
         * Backward compatibility function for WikiError -> Status migration
         *
index 32ab950..e86ccc5 100644 (file)
@@ -84,8 +84,8 @@ abstract class CoreInstaller extends Installer {
                '_CCDone' => false,
                '_Extensions' => array(),
                '_MemCachedServers' => '',
-               '_LocalSettingsLocked' => true,
-               '_UpgradeKey' => '',
+               '_UpgradeKeySupplied' => false,
+               '_ExistingDBSettings' => false,
        );
 
        /**
@@ -381,7 +381,7 @@ abstract class CoreInstaller extends Installer {
         *
         * @return Status
         */
-       protected function generateSecret( $secretName ) {
+       protected function generateSecret( $secretName, $length = 64 ) {
                if ( wfIsWindows() ) {
                        $file = null;
                } else {
@@ -393,12 +393,12 @@ abstract class CoreInstaller extends Installer {
                $status = Status::newGood();
 
                if ( $file ) {
-                       $secretKey = bin2hex( fread( $file, 32 ) );
+                       $secretKey = bin2hex( fread( $file, $length / 2 ) );
                        fclose( $file );
                } else {
                        $secretKey = '';
 
-                       for ( $i=0; $i<8; $i++ ) {
+                       for ( $i = 0; $i < $length / 8; $i++ ) {
                                $secretKey .= dechex( mt_rand( 0, 0x7fffffff ) );
                        }
 
@@ -411,13 +411,15 @@ abstract class CoreInstaller extends Installer {
        }
 
        /**
-        * Generate a default $wgUpradeKey, Will warn if we had to use
+        * Generate a default $wgUpgradeKey. Will warn if we had to use
         * mt_rand() instead of /dev/urandom
         *
         * @return Status
         */
-       protected function generateUpgradeKey() {
-               return $this->generateSecret( 'wgUpgradeKey' );
+       public function generateUpgradeKey() {
+               if ( strval( $this->getVar( 'wgUpgradeKey' ) ) === '' ) {
+                       return $this->generateSecret( 'wgUpgradeKey', 16 );
+               }
        }
 
        /**
index eeaa84c..c492c1b 100644 (file)
@@ -15,14 +15,22 @@ $messages['en'] = array(
        'config-desc'                     => 'The installer for MediaWiki',
        'config-title'                    => 'MediaWiki $1 installation',
        'config-information'              => 'Information',
-       'config-localsettings-upgrade'    => "'''Warning''': A <code>LocalSettings.php</code> file has been detected.
-Your software is able to upgrade.
-Please fill in the value of <code>\$wgUpgradeKey</code> in the box.",
+       'config-localsettings-upgrade'    => "A <code>LocalSettings.php</code> file has been detected.
+To upgrade this installation, please enter the value of <code>\$wgUpgradeKey</code> in the box below. 
+You will find it in LocalSettings.php.",
        'config-localsettings-key'        => 'Upgrade key:',
-       'config-localsettings-badkey'     => 'The key you provided is incorrect',
-       'config-localsettings-noupgrade'  => "'''Error''': A <code>LocalSettings.php</code> file has been detected.
-Your software is not able to upgrade at this time.
-The installer has been disabled for security reasons.",
+       'config-localsettings-badkey'     => 'The key you provided is incorrect.',
+       'config-upgrade-key-missing'      => 'An existing installation of MediaWiki has been detected.
+To upgrade this installation, please put the following line at the bottom of your LocalSettings.php:
+
+$1
+',
+       'config-localsettings-incomplete' => 'The existing LocalSettings.php appears to be incomplete.
+The $1 variable is not set.
+Please change LocalSettings.php so that this variable is set, and click "Continue".',
+       'config-localsettings-connection-error' => 'An error was encountered when connecting to the database using the settings specified in LocalSettings.php or AdminSettings.php. Please fix these settings and try again.
+
+$1',
        'config-session-error'            => 'Error starting session: $1',
        'config-session-expired'          => 'Your session data seems to have expired.
 Sessions are configured for a lifetime of $1.
@@ -51,7 +59,7 @@ Check your php.ini and make sure <code>session.save_path</code> is set to an app
        'config-page-releasenotes'        => 'Release notes',
        'config-page-copying'             => 'Copying',
        'config-page-upgradedoc'          => 'Upgrading',
-       'config-page-locked'              => 'Permission denied',
+       'config-page-existingwiki'        => 'Existing wiki',
        'config-help-restart'             => 'Do you want to clear all saved data that you have entered and restart the installation process?',
        'config-restart'                  => 'Yes, restart it',
        'config-welcome'                  => "=== Environmental checks ===
index 4282806..5f91cee 100644 (file)
@@ -213,33 +213,30 @@ abstract class Installer {
        }
 
        /**
-        * Determine if LocalSettings exists. If it does, return an appropriate
-        * status for whether upgrading is enabled or not.
+        * Determine if LocalSettings.php exists. If it does, return its variables, 
+        * merged with those from AdminSettings.php, as an array.
         *
-        * @return Status
+        * @return Array
         */
-       public function getLocalSettingsStatus() {
+       public function getExistingLocalSettings() {
                global $IP;
 
-               $status = Status::newGood();
-
                wfSuppressWarnings();
-               $ls = file_exists( "$IP/LocalSettings.php" );
+               $_lsExists = file_exists( "$IP/LocalSettings.php" );
                wfRestoreWarnings();
 
-               if( $ls ) {
+               if( $_lsExists ) {
                        require( "$IP/includes/DefaultSettings.php" );
-                       require_once( "$IP/LocalSettings.php" );
-                       $vars = get_defined_vars();
-                       if( isset( $vars['wgUpgradeKey'] ) && $vars['wgUpgradeKey'] ) {
-                               $status->warning( 'config-localsettings-upgrade' );
-                               $this->setVar( '_UpgradeKey', $vars['wgUpgradeKey' ] );
-                       } else {
-                               $status->fatal( 'config-localsettings-noupgrade' );
+                       require( "$IP/LocalSettings.php" );
+                       if ( file_exists( "$IP/AdminSettings.php" ) ) {
+                               require( "$IP/AdminSettings.php" );
                        }
+                       $vars = get_defined_vars();
+                       unset( $vars['_lsExists'] );
+                       return $vars;
+               } else {
+                       return false;
                }
-
-               return $status;
        }
 
        /**
index 4342a17..5cc0e3c 100644 (file)
@@ -282,7 +282,7 @@ if ( !defined( 'MEDIAWIKI' ) ) {
 
 # Site upgrade key. Must be set to a string (default provided) to turn on the
 # web installer while LocalSettings.php is in place
-#\$wgUpgradeKey = \"{$this->values['wgUpgradeKey']}\";
+\$wgUpgradeKey = \"{$this->values['wgUpgradeKey']}\";
 
 ## Default skin: you can change the default skin. Use the internal symbolic
 ## names, ie 'standard', 'nostalgia', 'cologneblue', 'monobook', 'vector':
index fc250dc..e4d1154 100644 (file)
@@ -47,6 +47,7 @@ class WebInstaller extends CoreInstaller {
         */
        public $pageSequence = array(
                'Language',
+               'ExistingWiki',
                'Welcome',
                'DBConnect',
                'Upgrade',
@@ -175,15 +176,7 @@ class WebInstaller extends CoreInstaller {
                # Get the page name.
                $pageName = $this->request->getVal( 'page' );
 
-               # Check LocalSettings status
-               $localSettings = $this->getLocalSettingsStatus();
-
-               if( !$localSettings->isGood() && $this->getVar( '_LocalSettingsLocked' ) ) {
-                       $pageName = 'Locked';
-                       $pageId = false;
-                       $page = $this->getPageByName( $pageName );
-                       $page->setLocalSettingsStatus( $localSettings );
-               } elseif ( in_array( $pageName, $this->otherPages ) ) {
+               if ( in_array( $pageName, $this->otherPages ) ) {
                        # Out of sequence
                        $pageId = false;
                        $page = $this->getPageByName( $pageName );
@@ -620,7 +613,7 @@ class WebInstaller extends CoreInstaller {
                                ) . "\n" .
                                "</div>\n" .
                                "<div class=\"config-info-right\">\n" .
-                                       $this->parse( $text ) . "\n" .
+                                       $this->parse( $text, true ) . "\n" .
                                "</div>\n" .
                                "<div style=\"clear: left;\"></div>\n" .
                        "</div>\n";
index 26dea3d..ff7c681 100644 (file)
@@ -116,56 +116,6 @@ abstract class WebInstallerPage {
        }
 }
 
-class WebInstaller_Locked extends WebInstallerPage {
-       // The status of Installer::getLocalSettingsStatus()
-       private $status;
-
-       public function setLocalSettingsStatus( Status $s ) {
-               $this->status = $s;
-       }
-
-       protected function getId() {
-               return 0;
-       }
-
-       public function execute() {
-               $r = $this->parent->request;
-               if( !$r->wasPosted() || !$this->status->isOK() ) {
-                       $this->display();
-                       return 'output';
-               } else {
-                       $key = $r->getText( 'config_wpUpgradeKey' );
-                       if( !$key || $key !== $this->getVar( '_UpgradeKey' ) ) {
-                               $this->parent->showError( 'config-localsettings-badkey' );
-                               $this->display();
-                               return 'output';
-                       } else {
-                               $this->setVar( '_LocalSettingsLocked', false );
-                               return 'continue';
-                       }
-               }
-       }
-
-       /**
-        * Display stuff to the end user
-        */
-       private function display() {
-               $this->startForm();
-               $this->parent->showStatusBox( $this->status );
-               $continue = false;
-               if( $this->status->isOK() && !$this->status->isGood() ) {
-                       $this->addHTML( "<br />" .
-                               $this->parent->getTextBox( array(
-                                       'var' => 'wpUpgradeKey',
-                                       'label' => 'config-localsettings-key',
-                               ) )
-                       );
-                       $continue = 'continue';
-               }
-               $this->endForm( $continue );
-       }
-}
-
 class WebInstaller_Language extends WebInstallerPage {
        
        public function execute() {
@@ -245,6 +195,146 @@ class WebInstaller_Language extends WebInstallerPage {
        
 }
 
+class WebInstaller_ExistingWiki extends WebInstallerPage {
+       public function execute() {
+               // If there is no LocalSettings.php, continue to the installer welcome page
+               $vars = $this->parent->getExistingLocalSettings();
+               if ( !$vars ) {
+                       return 'skip';
+               }
+
+               // Check if the upgrade key supplied to the user has appeared in LocalSettings.php
+               if ( $vars['wgUpgradeKey'] !== false
+                       && $this->getVar( '_UpgradeKeySupplied' )
+                       && $this->getVar( 'wgUpgradeKey' ) === $vars['wgUpgradeKey'] ) 
+               {
+                       // It's there, so the user is authorized
+                       $status = $this->handleExistingUpgrade( $vars );
+                       if ( $status->isOK() ) {
+                               return 'skip';
+                       } else {
+                               $this->startForm();
+                               $this->parent->showStatusBox( $status );
+                               $this->endForm( 'continue' );
+                               return 'output';
+                       }
+                       return $this->handleExistingUpgrade( $vars );
+               }
+
+               // If there is no $wgUpgradeKey, tell the user to add one to LocalSettings.php
+               if ( $vars['wgUpgradeKey'] === false ) {
+                       if ( $this->getVar( 'wgUpgradeKey', false ) === false ) {
+                               $this->parent->generateUpgradeKey();
+                               $this->setVar( '_UpgradeKeySupplied', true );
+                       }
+                       $this->startForm();
+                       $this->addHTML( $this->parent->getInfoBox( 
+                               wfMsgNoTrans( 'config-upgrade-key-missing', 
+                                       "<pre>\$wgUpgradeKey = '" . $this->getVar( 'wgUpgradeKey' ) . "';</pre>" )
+                       ) );
+                       $this->endForm( 'continue' );
+                       return 'output';
+               }
+
+               // If there is an upgrade key, but it wasn't supplied, prompt the user to enter it
+                       
+               $r = $this->parent->request;
+               if ( $r->wasPosted() ) {
+                       $key = $r->getText( 'config_wgUpgradeKey' );
+                       if( !$key || $key !== $vars['wgUpgradeKey'] ) {
+                               $this->parent->showError( 'config-localsettings-badkey' );
+                               $this->showKeyForm();
+                               return 'output';
+                       }
+                       // Key was OK
+                       $status = $this->handleExistingUpgrade( $vars );
+                       if ( $status->isOK() ) {
+                               return 'continue';
+                       } else {
+                               $this->parent->showStatusBox( $status );
+                               $this->showKeyForm();
+                               return 'output';
+                       }
+               } else {
+                       $this->showKeyForm();
+                       return 'output';
+               }
+       }
+
+       /**
+        * Show the "enter key" form
+        */
+       protected function showKeyForm() {
+               $this->startForm();
+               $this->addHTML( 
+                       $this->parent->getInfoBox( wfMsgNoTrans( 'config-localsettings-upgrade' ) ).
+                       '<br />' .
+                       $this->parent->getTextBox( array(
+                               'var' => 'wgUpgradeKey',
+                               'label' => 'config-localsettings-key',
+                               'attribs' => array( 'autocomplete' => 'off' ),
+                       ) )
+               );
+               $this->endForm( 'continue' );
+       }
+
+       protected function importVariables( $names, $vars ) {
+               $status = Status::newGood();
+               foreach ( $names as $name ) {
+                       if ( !isset( $vars[$name] ) ) {
+                               $status->fatal( 'config-localsettings-incomplete', $name );
+                       }
+                       $this->setVar( $name, $vars[$name] );
+               }
+               return $status;
+       }
+
+       /**
+        * Initiate an upgrade of the existing database
+        * @param $vars Variables from LocalSettings.php and AdminSettings.php
+        * @return Status
+        */
+       protected function handleExistingUpgrade( $vars ) {
+               // Check $wgDBtype
+               if ( !isset( $vars['wgDBtype'] ) || !in_array( $vars['wgDBtype'], Installer::getDBTypes() ) ) {
+                       return Status::newFatal( 'config-localsettings-connection-error', '' );
+               }
+
+               // Set the relevant variables from LocalSettings.php
+               $requiredVars = array( 'wgDBtype', 'wgDBuser', 'wgDBpassword' );
+               $status = $this->importVariables( $requiredVars , $vars );
+               $installer = $this->parent->getDBInstaller();
+               $status->merge( $this->importVariables( $installer->getGlobalNames(), $vars ) );
+               if ( !$status->isOK() ) {
+                       return $status;
+               }
+
+               if ( isset( $vars['wgDBadminuser'] ) ) {
+                       $this->setVar( '_InstallUser', $vars['wgDBadminuser'] );
+               } else {
+                       $this->setVar( '_InstallUser', $vars['wgDBuser'] );
+               }
+               if ( isset( $vars['wgDBadminpassword'] ) ) {
+                       $this->setVar( '_InstallPassword', $vars['wgDBadminpassword'] );
+               } else {
+                       $this->setVar( '_InstallPassword', $vars['wgDBpassword'] );
+               }
+
+               // Test the database connection
+               $status = $installer->getConnection();
+               if ( !$status->isOK() ) {
+                       // Adjust the error message to explain things correctly
+                       $status->replaceMessage( 'config-connection-error', 
+                               'config-localsettings-connection-error' );
+                       return $status;
+               }
+
+               // All good
+               $this->setVar( '_ExistingDBSettings', true );
+               return $status;
+       }
+}
+
 class WebInstaller_Welcome extends WebInstallerPage {
        
        public function execute() {
@@ -268,6 +358,10 @@ class WebInstaller_Welcome extends WebInstallerPage {
 class WebInstaller_DBConnect extends WebInstallerPage {
        
        public function execute() {
+               if ( $this->getVar( '_ExistingDBSettings' ) ) {
+                       return 'skip';
+               }
+
                $r = $this->parent->request;
                if ( $r->wasPosted() ) {
                        $status = $this->submit();