Split Installer into Installer and CoreInstaller + made misc style and doc improvements
authorJeroen De Dauw <jeroendedauw@users.mediawiki.org>
Thu, 22 Jul 2010 17:58:26 +0000 (17:58 +0000)
committerJeroen De Dauw <jeroendedauw@users.mediawiki.org>
Thu, 22 Jul 2010 17:58:26 +0000 (17:58 +0000)
includes/AutoLoader.php
includes/installer/CliInstaller.php
includes/installer/CoreInstaller.php [new file with mode: 0644]
includes/installer/DatabaseInstaller.php
includes/installer/Installer.php
includes/installer/WebInstaller.php
includes/installer/WebInstallerPage.php

index e893189..77e174c 100644 (file)
@@ -415,6 +415,7 @@ $wgAutoloadLocalClasses = array(
        # includes/installer
        'CliInstaller' => 'includes/installer/CliInstaller.php',
        'Installer' => 'includes/installer/Installer.php',
+       'CoreInstaller' => 'includes/installer/CoreInstaller.php',
        'DatabaseInstaller' => 'includes/installer/DatabaseInstaller.php',
        'DatabaseUpdater' => 'includes/installer/DatabaseUpdater.php',
        'LBFactory_InstallerFake' => 'includes/installer/Installer.php',
index 5319b0f..bbb43fb 100644 (file)
@@ -1,6 +1,11 @@
 <?php
 
-class CliInstaller extends Installer {
+/**
+ * Class for the core installer command line interface.
+ * 
+ * @since 1.17
+ */
+class CliInstaller extends CoreInstaller {
 
        /* The maintenance class in effect */
        private $maint;
diff --git a/includes/installer/CoreInstaller.php b/includes/installer/CoreInstaller.php
new file mode 100644 (file)
index 0000000..ee514bb
--- /dev/null
@@ -0,0 +1,447 @@
+<?php
+
+/**
+ * Base core installer class.
+ * Handles everything that is independent of user interface.
+ * 
+ * @since 1.17
+ */
+abstract class CoreInstaller extends Installer {
+
+       /**
+        * MediaWiki configuration globals that will eventually be passed through
+        * to LocalSettings.php. The names only are given here, the defaults
+        * typically come from DefaultSettings.php.
+        * 
+        * @var array
+        */
+       protected $defaultVarNames = array(
+               'wgSitename',
+               'wgPasswordSender',
+               'wgLanguageCode',
+               'wgRightsIcon',
+               'wgRightsText',
+               'wgRightsUrl',
+               'wgMainCacheType',
+               'wgEnableEmail',
+               'wgEnableUserEmail',
+               'wgEnotifUserTalk',
+               'wgEnotifWatchlist',
+               'wgEmailAuthentication',
+               'wgDBtype',
+               'wgDiff3',
+               'wgImageMagickConvertCommand',
+               'IP',
+               'wgScriptPath',
+               'wgScriptExtension',
+               'wgMetaNamespace',
+               'wgDeletedDirectory',
+               'wgEnableUploads',
+               'wgLogo',
+               'wgShellLocale',
+               'wgSecretKey',
+               'wgUseInstantCommons',
+       );
+
+       /**
+        * Variables that are stored alongside globals, and are used for any
+        * configuration of the installation process aside from the MediaWiki
+        * configuration. Map of names to defaults.
+        * 
+        * @var array
+        */
+       protected $internalDefaults = array(
+               '_UserLang' => 'en',
+               '_Environment' => false,
+               '_CompiledDBs' => array(),
+               '_SafeMode' => false,
+               '_RaiseMemory' => false,
+               '_UpgradeDone' => false,
+               '_InstallDone' => false,
+               '_Caches' => array(),
+               '_InstallUser' => 'root',
+               '_InstallPassword' => '',
+               '_SameAccount' => true,
+               '_CreateDBAccount' => false,
+               '_NamespaceType' => 'site-name',
+               '_AdminName' => '', // will be set later, when the user selects language
+               '_AdminPassword' => '',
+               '_AdminPassword2' => '',
+               '_AdminEmail' => '',
+               '_Subscribe' => false,
+               '_SkipOptional' => 'continue',
+               '_RightsProfile' => 'wiki',
+               '_LicenseCode' => 'none',
+               '_CCDone' => false,
+               '_Extensions' => array(),
+               '_MemCachedServers' => '',
+               '_ExternalHTTP' => false,
+       );
+
+       /**
+        * Steps for installation.
+        * 
+        * @var array
+        */
+       protected $installSteps = array(
+               'database',
+               'tables',
+               'interwiki',
+               'secretkey',
+               'sysop',
+       );
+
+       /**
+        * Known object cache types and the functions used to test for their existence.
+        * 
+        * @var array
+        */
+       protected $objectCaches = array(
+               'xcache' => 'xcache_get',
+               'apc' => 'apc_fetch',
+               'eaccel' => 'eaccelerator_get',
+               'wincache' => 'wincache_ucache_get'
+       );
+
+       /**
+        * User rights profiles.
+        * 
+        * @var array
+        */
+       public $rightsProfiles = array(
+               'wiki' => array(),
+               'no-anon' => array(
+                       '*' => array( 'edit' => false )
+               ),
+               'fishbowl' => array(
+                       '*' => array(
+                               'createaccount' => false,
+                               'edit' => false,
+                       ),
+               ),
+               'private' => array(
+                       '*' => array(
+                               'createaccount' => false,
+                               'edit' => false,
+                               'read' => false,
+                       ),
+               ),
+       );
+
+       /**
+        * License types.
+        * 
+        * @var array
+        */
+       public $licenses = array(
+               'none' => array(
+                       'url' => '',
+                       'icon' => '',
+                       'text' => ''
+               ),
+               'cc-by-sa' => array(
+                       'url' => 'http://creativecommons.org/licenses/by-sa/3.0/',
+                       'icon' => '{$wgStylePath}/common/images/cc-by-sa.png',
+               ),
+               'cc-by-nc-sa' => array(
+                       'url' => 'http://creativecommons.org/licenses/by-nc-sa/3.0/',
+                       'icon' => '{$wgStylePath}/common/images/cc-by-nc-sa.png',
+               ),
+               'pd' => array(
+                       'url' => 'http://creativecommons.org/licenses/publicdomain/',
+                       'icon' => '{$wgStylePath}/common/images/public-domain.png',
+               ),
+               'gfdl-old' => array(
+                       'url' => 'http://www.gnu.org/licenses/old-licenses/fdl-1.2.html',
+                       'icon' => '{$wgStylePath}/common/images/gnu-fdl.png',
+               ),
+               'gfdl-current' => array(
+                       'url' => 'http://www.gnu.org/copyleft/fdl.html',
+                       'icon' => '{$wgStylePath}/common/images/gnu-fdl.png',
+               ),
+               'cc-choose' => array(
+                       // details will be filled in by the selector
+                       'url' => '',
+                       'icon' => '',
+                       'text' => '',
+               ),
+       );
+
+       /**
+        * Constructor, always call this from child classes.
+        */
+       public function __construct() {
+               parent::__construct();
+               
+               global $wgExtensionMessagesFiles, $wgUser, $wgHooks;
+
+               // Load the installer's i18n file.
+               $wgExtensionMessagesFiles['MediawikiInstaller'] =
+                       './includes/installer/Installer.i18n.php';
+
+               // Having a user with id = 0 safeguards us from DB access via User::loadOptions().
+               $wgUser = User::newFromId( 0 );
+
+               // Set our custom <doclink> hook.
+               $wgHooks['ParserFirstCallInit'][] = array( $this, 'registerDocLink' );
+
+               $this->settings = $this->internalDefaults;
+               
+               foreach ( $this->defaultVarNames as $var ) {
+                       $this->settings[$var] = $GLOBALS[$var];
+               }
+               
+               foreach ( $this->dbTypes as $type ) {
+                       $installer = $this->getDBInstaller( $type );
+                       
+                       if ( !$installer->isCompiled() ) {
+                               continue;
+                       }
+                       
+                       $defaults = $installer->getGlobalDefaults();
+                       
+                       foreach ( $installer->getGlobalNames() as $var ) {
+                               if ( isset( $defaults[$var] ) ) {
+                                       $this->settings[$var] = $defaults[$var];
+                               } else {
+                                       $this->settings[$var] = $GLOBALS[$var];
+                               }
+                       }
+               }
+
+               $this->parserTitle = Title::newFromText( 'Installer' );
+               $this->parserOptions = new ParserOptions;
+               $this->parserOptions->setEditSection( false );
+       }
+
+       /**
+        * Register tag hook below.
+        * 
+        * @param $parser Parser
+        */
+       public function registerDocLink( Parser &$parser ) {
+               $parser->setHook( 'doclink', array( $this, 'docLink' ) );
+               return true;
+       }
+
+       /**
+        * Extension tag hook for a documentation link.
+        */
+       public function docLink( $linkText, $attribs, $parser ) {
+               $url = $this->getDocUrl( $attribs['href'] );
+               return '<a href="' . htmlspecialchars( $url ) . '">' .
+                       htmlspecialchars( $linkText ) .
+                       '</a>';
+       }
+
+       /**
+        * Overridden by WebInstaller to provide lastPage parameters.
+        */
+       protected function getDocUrl( $page ) {
+               return "{$_SERVER['PHP_SELF']}?page=" . urlencode( $attribs['href'] );
+       }
+
+       /**
+        * Finds extensions that follow the format /extensions/Name/Name.php,
+        * and returns an array containing the value for 'Name' for each found extension.
+        * 
+        * @return array
+        */
+       public function findExtensions() {
+               if( $this->getVar( 'IP' ) === null ) {
+                       return false;
+               }
+               
+               $exts = array();
+               $dir = $this->getVar( 'IP' ) . '/extensions';
+               $dh = opendir( $dir );
+               
+               while ( ( $file = readdir( $dh ) ) !== false ) {
+                       if( file_exists( "$dir/$file/$file.php" ) ) {
+                               $exts[] = $file;
+                       }
+               }
+               
+               $this->setVar( '_Extensions', $exts );
+               
+               return $exts;
+       }
+       
+       /**
+        * Installs the auto-detected extensions.
+        * 
+        * TODO: this only requires them?
+        * 
+        * @return Status
+        */
+       public function installExtensions() {
+               global $wgHooks, $wgAutoloadClasses;
+               
+               $exts = $this->getVar( '_Extensions' );
+               $path = $this->getVar( 'IP' ) . '/extensions';
+               
+               foreach( $exts as $e ) {
+                       require( "$path/$e/$e.php" );
+               }
+               
+               return Status::newGood();
+       }       
+
+       public function getInstallSteps() {
+               if( $this->getVar( '_UpgradeDone' ) ) {
+                       $this->installSteps = array( 'localsettings' );
+               }
+               
+               if( count( $this->getVar( '_Extensions' ) ) ) {
+                       array_unshift( $this->installSteps, 'extensions' );
+               }
+               
+               return $this->installSteps;
+       }
+
+       /**
+        * Actually perform the installation.
+        * 
+        * @param Array $startCB A callback array for the beginning of each step
+        * @param Array $endCB A callback array for the end of each step
+        * 
+        * @return Array of Status objects
+        */
+       public function performInstallation( $startCB, $endCB ) {
+               $installResults = array();
+               $installer = $this->getDBInstaller();
+               
+               foreach( $this->getInstallSteps() as $stepObj ) {
+                       $step = is_array( $stepObj ) ? $stepObj['name'] : $stepObj;
+                       call_user_func_array( $startCB, array( $step ) );
+                       $status = null;
+
+                       # Call our working function
+                       if ( is_array( $stepObj ) ) {
+                               # A custom callaback
+                               $callback = $stepObj['callback'];
+                               $status = call_user_func_array( $callback, array( $installer ) );
+                       } else {
+                               # Boring implicitly named callback
+                               $func = 'install' . ucfirst( $step );
+                               $status = $this->{$func}( $installer );
+                       }
+                       
+                       call_user_func_array( $endCB, array( $step, $status ) );
+                       $installResults[$step] = $status;
+
+                       // If we've hit some sort of fatal, we need to bail. 
+                       // Callback already had a chance to do output above.
+                       if( !$status->isOk() ) {
+                               break;
+                       }
+                               
+               }
+               
+               if( $status->isOk() ) {
+                       $this->setVar( '_InstallDone', true );
+               }
+               
+               return $installResults;
+       }
+
+       /**
+        * TODO: document
+        * 
+        * @return Status
+        */     
+       public function installSecretKey() {
+               if ( wfIsWindows() ) {
+                       $file = null;
+               } else {
+                       wfSuppressWarnings();
+                       $file = fopen( "/dev/urandom", "r" );
+                       wfRestoreWarnings();
+               }
+
+               $status = Status::newGood();
+
+               if ( $file ) {
+                       $secretKey = bin2hex( fread( $file, 32 ) );
+                       fclose( $file );
+               } else {
+                       $secretKey = '';
+                       
+                       for ( $i=0; $i<8; $i++ ) {
+                               $secretKey .= dechex( mt_rand( 0, 0x7fffffff ) );
+                       }
+                       
+                       $status->warning( 'config-insecure-secretkey' );
+               }
+               
+               $this->setVar( 'wgSecretKey', $secretKey );
+
+               return $status;
+       }
+
+       /**
+        * TODO: document
+        * 
+        * @return Status
+        */
+       public function installSysop() {
+               $name = $this->getVar( '_AdminName' );
+               $user = User::newFromName( $name );
+               
+               if ( !$user ) {
+                       // We should've validated this earlier anyway!
+                       return Status::newFatal( 'config-admin-error-user', $name );
+               }
+               
+               if ( $user->idForName() == 0 ) {
+                       $user->addToDatabase();
+                       
+                       try {
+                               $user->setPassword( $this->getVar( '_AdminPassword' ) );
+                       } catch( PasswordError $pwe ) {
+                               return Status::newFatal( 'config-admin-error-password', $name, $pwe->getMessage() );
+                       }
+                       
+                       $user->addGroup( 'sysop' );
+                       $user->addGroup( 'bureaucrat' );
+                       $user->saveSettings();
+               }
+               
+               return Status::newGood();
+       }
+
+       /**
+        * Override the necessary bits of the config to run an installation.
+        */
+       public static function overrideConfig() {
+               define( 'MW_NO_SESSION', 1 );
+
+               // Don't access the database
+               $GLOBALS['wgUseDatabaseMessages'] = false;
+               // Debug-friendly
+               $GLOBALS['wgShowExceptionDetails'] = true;
+               // Don't break forms
+               $GLOBALS['wgExternalLinkTarget'] = '_blank';
+
+               // Extended debugging. Maybe disable before release?
+               $GLOBALS['wgShowSQLErrors'] = true;
+               $GLOBALS['wgShowDBErrorBacktrace'] = true;
+       }
+
+       /**
+        * Add an installation step following the given step.
+        * 
+        * @param $findStep String the step to find.  Use NULL to put the step at the beginning.
+        * @param $callback array
+        */
+       public function addInstallStepFollowing( $findStep, $callback ) {
+               $where = 0;
+               
+               if( $findStep !== null ) {
+                       $where = array_search( $findStep, $this->installSteps );
+               }
+
+               array_splice( $this->installSteps, $where, 0, $callback );
+       }
+
+}
\ No newline at end of file
index fa16dc1..acf0e68 100644 (file)
@@ -101,7 +101,7 @@ abstract class DatabaseInstaller {
        /**
         * Create database tables from scratch.
         * 
-        * @return \type Status
+        * @return Status
         */
        public abstract function createTables();
 
index bfca426..a8a641b 100644 (file)
 
 /**
  * Base installer class.
- * Handles everything that is independent of user interface.
+ * 
+ * This class provides the base for installation and update functionality
+ * for both MediaWiki core and extensions.
+ * 
+ * @since 1.17
  */
 abstract class Installer {
        
-       public $settings;
-       
-       /**
-        * 
-        * @var unknown_type
-        */
-       public $output;
-
        /**
-        * MediaWiki configuration globals that will eventually be passed through
-        * to LocalSettings.php. The names only are given here, the defaults
-        * typically come from DefaultSettings.php.
+        * TODO: make protected?
         * 
         * @var array
         */
-       protected $defaultVarNames = array(
-               'wgSitename',
-               'wgPasswordSender',
-               'wgLanguageCode',
-               'wgRightsIcon',
-               'wgRightsText',
-               'wgRightsUrl',
-               'wgMainCacheType',
-               'wgEnableEmail',
-               'wgEnableUserEmail',
-               'wgEnotifUserTalk',
-               'wgEnotifWatchlist',
-               'wgEmailAuthentication',
-               'wgDBtype',
-               'wgDiff3',
-               'wgImageMagickConvertCommand',
-               'IP',
-               'wgScriptPath',
-               'wgScriptExtension',
-               'wgMetaNamespace',
-               'wgDeletedDirectory',
-               'wgEnableUploads',
-               'wgLogo',
-               'wgShellLocale',
-               'wgSecretKey',
-               'wgUseInstantCommons',
-       );
-
+       public $settings;       
+       
        /**
-        * Variables that are stored alongside globals, and are used for any
-        * configuration of the installation process aside from the MediaWiki
-        * configuration. Map of names to defaults.
+        * Cached DB installer instances, access using getDBInstaller().
         * 
         * @var array
         */
-       protected $internalDefaults = array(
-               '_UserLang' => 'en',
-               '_Environment' => false,
-               '_CompiledDBs' => array(),
-               '_SafeMode' => false,
-               '_RaiseMemory' => false,
-               '_UpgradeDone' => false,
-               '_InstallDone' => false,
-               '_Caches' => array(),
-               '_InstallUser' => 'root',
-               '_InstallPassword' => '',
-               '_SameAccount' => true,
-               '_CreateDBAccount' => false,
-               '_NamespaceType' => 'site-name',
-               '_AdminName' => '', // will be set later, when the user selects language
-               '_AdminPassword' => '',
-               '_AdminPassword2' => '',
-               '_AdminEmail' => '',
-               '_Subscribe' => false,
-               '_SkipOptional' => 'continue',
-               '_RightsProfile' => 'wiki',
-               '_LicenseCode' => 'none',
-               '_CCDone' => false,
-               '_Extensions' => array(),
-               '_MemCachedServers' => '',
-               '_ExternalHTTP' => false,
-       );
-
-       /**
-        * Known database types. These correspond to the class names <type>Installer,
-        * and are also MediaWiki database types valid for $wgDBtype.
-        *
-        * To add a new type, create a <type>Installer class and a Database<type>
-        * class, and add a config-type-<type> message to MessagesEn.php.
-        * 
-        * @var array
-        */
-       private $dbTypes = array(
-               'mysql',
-               'postgres',
-               'sqlite',
-               'oracle'
-       );
+       protected $dbInstallers = array();
 
        /**
         * Minimum memory size in MB.
         * 
         * @var integer
         */
-       private $minMemorySize = 50;
-
+       protected $minMemorySize = 50;          
+       
        /**
         * Cached Title, used by parse().
+        * 
+        * @var Title
         */
-       private $parserTitle;
+       protected $parserTitle;
        
        /**
         * Cached ParserOptions, used by parse().
+        * 
+        * @var ParserOptions
         */     
-       private $parserOptions; 
+       protected $parserOptions;               
        
        /**
-        * Cached DB installer instances, access using getDBInstaller().
+        * Known database types. These correspond to the class names <type>Installer,
+        * and are also MediaWiki database types valid for $wgDBtype.
+        *
+        * To add a new type, create a <type>Installer class and a Database<type>
+        * class, and add a config-type-<type> message to MessagesEn.php.
         * 
         * @var array
         */
-       private $dbInstallers = array();
-
+       protected $dbTypes = array(
+               'mysql',
+               'postgres',
+               'sqlite',
+               'oracle'
+       );
+       
        /**
         * A list of environment check methods called by doEnvironmentChecks().
         * These may output warnings using showMessage(), and/or abort the
@@ -151,177 +88,39 @@ abstract class Installer {
                'envCheckExtension',
                'envCheckShellLocale',
                'envCheckUploadsDirectory',
-       );
-
-       /**
-        * Steps for installation.
-        * 
-        * @var array
-        */
-       protected $installSteps = array(
-               'database',
-               'tables',
-               'interwiki',
-               'secretkey',
-               'sysop',
-       );
-
-       /**
-        * Known object cache types and the functions used to test for their existence.
-        * 
-        * @var array
-        */
-       protected $objectCaches = array(
-               'xcache' => 'xcache_get',
-               'apc' => 'apc_fetch',
-               'eaccel' => 'eaccelerator_get',
-               'wincache' => 'wincache_ucache_get'
-       );
-
+       );      
+       
        /**
-        * User rights profiles.
-        * 
-        * @var array
+        * UI interface for displaying a short message
+        * The parameters are like parameters to wfMsg().
+        * The messages will be in wikitext format, which will be converted to an
+        * output format such as HTML or text before being sent to the user.
         */
-       public $rightsProfiles = array(
-               'wiki' => array(),
-               'no-anon' => array(
-                       '*' => array( 'edit' => false )
-               ),
-               'fishbowl' => array(
-                       '*' => array(
-                               'createaccount' => false,
-                               'edit' => false,
-                       ),
-               ),
-               'private' => array(
-                       '*' => array(
-                               'createaccount' => false,
-                               'edit' => false,
-                               'read' => false,
-                       ),
-               ),
-       );
+       public abstract function showMessage( $msg /*, ... */ );
 
        /**
-        * License types.
+        * TODO: doucment
         * 
-        * @var array
+        * @param $status
         */
-       public $licenses = array(
-               'none' => array(
-                       'url' => '',
-                       'icon' => '',
-                       'text' => ''
-               ),
-               'cc-by-sa' => array(
-                       'url' => 'http://creativecommons.org/licenses/by-sa/3.0/',
-                       'icon' => '{$wgStylePath}/common/images/cc-by-sa.png',
-               ),
-               'cc-by-nc-sa' => array(
-                       'url' => 'http://creativecommons.org/licenses/by-nc-sa/3.0/',
-                       'icon' => '{$wgStylePath}/common/images/cc-by-nc-sa.png',
-               ),
-               'pd' => array(
-                       'url' => 'http://creativecommons.org/licenses/publicdomain/',
-                       'icon' => '{$wgStylePath}/common/images/public-domain.png',
-               ),
-               'gfdl-old' => array(
-                       'url' => 'http://www.gnu.org/licenses/old-licenses/fdl-1.2.html',
-                       'icon' => '{$wgStylePath}/common/images/gnu-fdl.png',
-               ),
-               'gfdl-current' => array(
-                       'url' => 'http://www.gnu.org/copyleft/fdl.html',
-                       'icon' => '{$wgStylePath}/common/images/gnu-fdl.png',
-               ),
-               'cc-choose' => array(
-                       // details will be filled in by the selector
-                       'url' => '',
-                       'icon' => '',
-                       'text' => '',
-               ),
-       );
-
-
+       public abstract function showStatusMessage( $status );  
+       
        /**
-        * Constructor, always call this from child classes
+        * Constructor, always call this from child classes.
         */
-       public function __construct() {
+       public function __construct() { 
                // Disable the i18n cache and LoadBalancer
                Language::getLocalisationCache()->disableBackend();
                LBFactory::disableBackend();
-
-               // Load the installer's i18n file
-               global $wgExtensionMessagesFiles;
-               $wgExtensionMessagesFiles['MediawikiInstaller'] =
-                       './includes/installer/Installer.i18n.php';
-
-               global $wgUser;
-               $wgUser = User::newFromId( 0 );
-               // Having a user with id = 0 safeguards us from DB access via User::loadOptions()
-
-               // Set our custom <doclink> hook
-               global $wgHooks;
-               $wgHooks['ParserFirstCallInit'][] = array( $this, 'registerDocLink' );
-
-               $this->settings = $this->internalDefaults;
-               foreach ( $this->defaultVarNames as $var ) {
-                       $this->settings[$var] = $GLOBALS[$var];
-               }
-               foreach ( $this->dbTypes as $type ) {
-                       $installer = $this->getDBInstaller( $type );
-                       if ( !$installer->isCompiled() ) {
-                               continue;
-                       }
-                       $defaults = $installer->getGlobalDefaults();
-                       foreach ( $installer->getGlobalNames() as $var ) {
-                               if ( isset( $defaults[$var] ) ) {
-                                       $this->settings[$var] = $defaults[$var];
-                               } else {
-                                       $this->settings[$var] = $GLOBALS[$var];
-                               }
-                       }
-               }
-
-               $this->parserTitle = Title::newFromText( 'Installer' );
-               $this->parserOptions = new ParserOptions;
-               $this->parserOptions->setEditSection( false );
        }
-
-       /**
-        * UI interface for displaying a short message
-        * The parameters are like parameters to wfMsg().
-        * The messages will be in wikitext format, which will be converted to an
-        * output format such as HTML or text before being sent to the user.
-        */
-       public abstract function showMessage( $msg /*, ... */ );
-
-       public abstract function showStatusMessage( $status );
-
+       
        /**
         * Get a list of known DB types.
         */
        public function getDBTypes() {
                return $this->dbTypes;
-       }
-
-       /**
-        * Get an instance of DatabaseInstaller for the specified DB type
-        * @param $type Mixed: DB installer for which is needed, false to use default.
-        */
-       public function getDBInstaller( $type = false ) {
-               if ( !$type ) {
-                       $type = $this->getVar( 'wgDBtype' );
-               }
-               $type = strtolower($type);
-
-               if ( !isset( $this->dbInstallers[$type] ) ) {
-                       $class = ucfirst( $type ). 'Installer';
-                       $this->dbInstallers[$type] = new $class( $this );
-               }
-               return $this->dbInstallers[$type];
-       }
-
+       }       
+       
        /**
         * Do initial checks of the PHP environment. Set variables according to
         * the observed environment.
@@ -332,30 +131,51 @@ abstract class Installer {
         *
         * Under the web subclass, it can already be assumed that PHP 5+ is in use
         * and that sessions are working.
+        * 
+        * @return boolean
         */
        public function doEnvironmentChecks() {
                $this->showMessage( 'config-env-php', phpversion() );
 
                $good = true;
+               
                foreach ( $this->envChecks as $check ) {
                        $status = $this->$check();
                        if ( $status === false ) {
                                $good = false;
                        }
                }
+               
                $this->setVar( '_Environment', $good );
+               
                if ( $good ) {
                        $this->showMessage( 'config-env-good' );
                } else {
                        $this->showMessage( 'config-env-bad' );
                }
+               
                return $good;
        }
 
+       /**
+        * Set a MW configuration variable, or internal installer configuration variable.
+        * 
+        * @param $name String
+        * @param $value Mixed
+        */
+       public function setVar( $name, $value ) {
+               $this->settings[$name] = $value;
+       }
+
        /**
         * Get an MW configuration variable, or internal installer configuration variable.
         * The defaults come from $GLOBALS (ultimately DefaultSettings.php).
         * Installer variables are typically prefixed by an underscore.
+        * 
+        * @param $name String
+        * @param $default Mixed
+        * 
+        * @return mixed
         */
        public function getVar( $name, $default = null ) {
                if ( !isset( $this->settings[$name] ) ) {
@@ -363,30 +183,65 @@ abstract class Installer {
                } else {
                        return $this->settings[$name];
                }
-       }
-
+       }       
+       
        /**
-        * Set a MW configuration variable, or internal installer configuration variable.
+        * Get an instance of DatabaseInstaller for the specified DB type.
+        * 
+        * @param $type Mixed: DB installer for which is needed, false to use default.
+        * 
+        * @return DatabaseInstaller
         */
-       public function setVar( $name, $value ) {
-               $this->settings[$name] = $value;
-       }
+       public function getDBInstaller( $type = false ) {
+               if ( !$type ) {
+                       $type = $this->getVar( 'wgDBtype' );
+               }
+               
+               $type = strtolower( $type );
 
+               if ( !isset( $this->dbInstallers[$type] ) ) {
+                       $class = ucfirst( $type ). 'Installer';
+                       $this->dbInstallers[$type] = new $class( $this );
+               }
+               
+               return $this->dbInstallers[$type];
+       }       
+       
        /**
-        * Exports all wg* variables stored by the installer into global scope
+        * Determine if LocalSettings exists. If it does, return an appropriate
+        * status for whether we should can upgrade or not.
+        * 
+        * @return Status
         */
-       public function exportVars() {
-               foreach ( $this->settings as $name => $value ) {
-                       if ( substr( $name, 0, 2 ) == 'wg' ) {
-                               $GLOBALS[$name] = $value;
+       public function getLocalSettingsStatus() {
+               global $IP;
+
+               $status = Status::newGood();
+
+               wfSuppressWarnings();
+               $ls = file_exists( "$IP/LocalSettings.php" );
+               wfRestoreWarnings();
+
+               if( $ls ) {
+                       if( $this->getDBInstaller()->needsUpgrade() ) {
+                               $status->warning( 'config-localsettings-upgrade' );
+                       }
+                       else {
+                               $status->fatal( 'config-localsettings-noupgrade' );
                        }
                }
-       }
-
+               
+               return $status;
+       }       
+       
        /**
         * Get a fake password for sending back to the user in HTML.
         * This is a security mechanism to avoid compromise of the password in the
         * event of session ID compromise.
+        * 
+        * @param $realPassword String
+        * 
+        * @return string
         */
        public function getFakePassword( $realPassword ) {
                return str_repeat( '*', strlen( $realPassword ) );
@@ -395,44 +250,175 @@ abstract class Installer {
        /**
         * Set a variable which stores a password, except if the new value is a
         * fake password in which case leave it as it is.
+        * 
+        * @param $name String
+        * @param $value Mixed
         */
        public function setPassword( $name, $value ) {
                if ( !preg_match( '/^\*+$/', $value ) ) {
                        $this->setVar( $name, $value );
                }
+       }       
+
+       /**
+        * On POSIX systems return the primary group of the webserver we're running under.
+        * On other systems just returns null.
+        *
+        * This is used to advice the user that he should chgrp his config/data/images directory as the
+        * webserver user before he can install.
+        *
+        * Public because SqliteInstaller needs it, and doesn't subclass Installer.
+        *
+        * @return mixed
+        */
+       public static function maybeGetWebserverPrimaryGroup() {
+               if ( !function_exists( 'posix_getegid' ) || !function_exists( 'posix_getpwuid' ) ) {
+                       # I don't know this, this isn't UNIX.
+                       return null;
+               }
+
+               # posix_getegid() *not* getmygid() because we want the group of the webserver,
+               # not whoever owns the current script.
+               $gid = posix_getegid();
+               $getpwuid = posix_getpwuid( $gid );
+               $group = $getpwuid['name'];
+
+               return $group;
+       }       
+       
+       /**
+        * Convert wikitext $text to HTML.
+        *
+        * This is potentially error prone since many parser features require a complete
+        * installed MW database. The solution is to just not use those features when you
+        * write your messages. This appears to work well enough. Basic formatting and
+        * external links work just fine.
+        *
+        * But in case a translator decides to throw in a #ifexist or internal link or
+        * whatever, this function is guarded to catch attempted DB access and to present
+        * some fallback text.
+        *
+        * @param $text String
+        * @param $lineStart Boolean
+        * @return String
+        */
+       public function parse( $text, $lineStart = false ) {
+               global $wgParser;
+               
+               try {
+                       $out = $wgParser->parse( $text, $this->parserTitle, $this->parserOptions, $lineStart );
+                       $html = $out->getText();
+               } catch ( DBAccessError $e ) {
+                       $html = '<!--DB access attempted during parse-->  ' . htmlspecialchars( $text );
+                       
+                       if ( !empty( $this->debug ) ) {
+                               $html .= "<!--\n" . $e->getTraceAsString() . "\n-->";
+                       }
+               }
+               
+               return $html;
+       }       
+       
+       /**
+        * TODO: document
+        * 
+        * @param DatabaseInstaller $installer
+        * 
+        * @return Status
+        */
+       public function installDatabase( DatabaseInstaller &$installer ) {
+               if( !$installer ) {
+                       $type = $this->getVar( 'wgDBtype' );
+                       $status = Status::newFatal( "config-no-db", $type );
+               } else {
+                       $status = $installer->setupDatabase();
+               }
+               
+               return $status;
        }
 
-       /** Check if we're installing the latest version */
+       /**
+        * TODO: document
+        * 
+        * @param DatabaseInstaller $installer
+        * 
+        * @return Status
+        */
+       public function installTables( DatabaseInstaller &$installer ) {
+               $status = $installer->createTables();
+               
+               if( $status->isOK() ) {
+                       LBFactory::enableBackend();
+               }
+               
+               return $status;
+       }
+
+       /**
+        * TODO: document
+        * 
+        * @param DatabaseInstaller $installer
+        * 
+        * @return Status
+        */     
+       public function installInterwiki( DatabaseInstaller &$installer ) {
+               return $installer->populateInterwikiTable();
+       }       
+       
+       /**
+        * Exports all wg* variables stored by the installer into global scope.
+        */
+       public function exportVars() {
+               foreach ( $this->settings as $name => $value ) {
+                       if ( substr( $name, 0, 2 ) == 'wg' ) {
+                               $GLOBALS[$name] = $value;
+                       }
+               }
+       }       
+       
+       /**
+        * Check if we're installing the latest version.
+        */
        public function envLatestVersion() {
                global $wgVersion;
+               
                $latestInfoUrl = 'http://www.mediawiki.org/w/api.php?action=mwreleases&format=json';
                $latestInfo = Http::get( $latestInfoUrl );
+               
                if( !$latestInfo ) {
                        $this->showMessage( 'config-env-latest-can-not-check', $latestInfoUrl );
                        return;
                }
+               
                $this->setVar( '_ExternalHTTP', true );
                $latestInfo = FormatJson::decode($latestInfo);
+               
                if ($latestInfo === false || !isset( $latestInfo->mwreleases ) ) {
                        # For when the request is successful but there's e.g. some silly man in
                        # the middle firewall blocking us, e.g. one of those annoying airport ones
                        $this->showMessage( 'config-env-latest-data-invalid', $latestInfoUrl );
                        return;
                }
+               
                foreach( $latestInfo->mwreleases as $rel ) {
-                       if( isset( $rel->current ) )
+                       if( isset( $rel->current ) ) {
                                $currentVersion = $rel->version;
+                       }
                }
+               
                if( version_compare( $wgVersion, $currentVersion, '<' ) ) {
                        $this->showMessage( 'config-env-latest-old' );
                        $this->showHelpBox( 'config-env-latest-help', $wgVersion, $currentVersion );
                } elseif( version_compare( $wgVersion, $currentVersion, '>' ) ) {
                        $this->showMessage( 'config-env-latest-new' );
                }
+               
                $this->showMessage( 'config-env-latest-ok' );
        }
 
-       /** Environment check for DB types */
+       /**
+        * Environment check for DB types.
+        */
        public function envCheckDB() {
                global $wgLang;
                
@@ -629,53 +615,9 @@ abstract class Installer {
                } else {
                        $this->setVar( 'wgDiff3', false );
                        $this->showMessage( 'config-diff3-bad' );
-               }
-       }
-
-       /**
-        * Search a path for any of the given executable names. Returns the
-        * executable name if found. Also checks the version string returned
-        * by each executable.
-        *
-        * @param $path String: path to search
-        * @param $names Array of executable names
-        * @param $versionInfo Boolean false or array with two members:
-        *               0 => Command to run for version check, with $1 for the path
-        *               1 => String to compare the output with
-        *
-        * If $versionInfo is not false, only executables with a version
-        * matching $versionInfo[1] will be returned.
-        */
-       public function locateExecutable( $path, $names, $versionInfo = false ) {
-               if ( !is_array( $names ) ) {
-                       $names = array( $names );
-               }
-
-               foreach ( $names as $name ) {
-                       $command = "$path/$name";
-                       
-                       wfSuppressWarnings();
-                       $file_exists = file_exists( $command );
-                       wfRestoreWarnings();
-                       
-                       if ( $file_exists ) {
-                               if ( !$versionInfo ) {
-                                       return $command;
-                               }
-                                       
-                               $file = str_replace( '$1', $command, $versionInfo[0] );
-                               
-                               # Should maybe be wfShellExec( $file), but runs into a ulimit, see
-                               # http://www.mediawiki.org/w/index.php?title=New-installer_issues&diff=prev&oldid=335456
-                               if ( strstr( `$file`, $versionInfo[1]) !== false ) {
-                                       return $command;
-                               }
-                       }
-               }
-               
-               return false;
-       }
-
+               }
+       }       
+       
        /**
         * Environment check for ImageMagick and GD.
         */
@@ -768,6 +710,9 @@ abstract class Installer {
                $this->showMessage( 'config-file-extension', $ext );
        }
 
+       /**
+        * TODO: document
+        */
        public function envCheckShellLocale() {
                # Give up now if we're in safe mode or open_basedir.
                # It's theoretically possible but tricky to work with.
@@ -848,6 +793,9 @@ abstract class Installer {
                return true;
        }
 
+       /**
+        * TODO: document
+        */
        public function envCheckUploadsDirectory() {
                global $IP, $wgServer;
                
@@ -860,10 +808,58 @@ abstract class Installer {
                } else {
                        $this->showMessage( 'config-uploads-not-safe', $dir );
                }
-       }
+       }       
+       
+       /**
+        * Search a path for any of the given executable names. Returns the
+        * executable name if found. Also checks the version string returned
+        * by each executable.
+        * 
+        * Used only by environment checks.
+        *
+        * @param $path String: path to search
+        * @param $names Array of executable names
+        * @param $versionInfo Boolean false or array with two members:
+        *               0 => Command to run for version check, with $1 for the path
+        *               1 => String to compare the output with
+        *
+        * If $versionInfo is not false, only executables with a version
+        * matching $versionInfo[1] will be returned.
+        */
+       protected function locateExecutable( $path, $names, $versionInfo = false ) {
+               if ( !is_array( $names ) ) {
+                       $names = array( $names );
+               }
 
+               foreach ( $names as $name ) {
+                       $command = "$path/$name";
+                       
+                       wfSuppressWarnings();
+                       $file_exists = file_exists( $command );
+                       wfRestoreWarnings();
+                       
+                       if ( $file_exists ) {
+                               if ( !$versionInfo ) {
+                                       return $command;
+                               }
+                                       
+                               $file = str_replace( '$1', $command, $versionInfo[0] );
+                               
+                               # Should maybe be wfShellExec( $file), but runs into a ulimit, see
+                               # http://www.mediawiki.org/w/index.php?title=New-installer_issues&diff=prev&oldid=335456
+                               if ( strstr( `$file`, $versionInfo[1]) !== false ) {
+                                       return $command;
+                               }
+                       }
+               }
+               
+               return false;
+       }       
+       
        /**
         * Checks if scripts located in the given directory can be executed via the given URL.
+        * 
+        * Used only by environment checks.
         */
        public function dirIsExecutable( $dir, $url ) {
                $scriptTypes = array(
@@ -898,321 +894,6 @@ abstract class Installer {
                wfRestoreWarnings();
                
                return false;
-       }
-
-       /**
-        * Convert wikitext $text to HTML.
-        *
-        * This is potentially error prone since many parser features require a complete
-        * installed MW database. The solution is to just not use those features when you
-        * write your messages. This appears to work well enough. Basic formatting and
-        * external links work just fine.
-        *
-        * But in case a translator decides to throw in a #ifexist or internal link or
-        * whatever, this function is guarded to catch attempted DB access and to present
-        * some fallback text.
-        *
-        * @param $text String
-        * @param $lineStart Boolean
-        * @return String
-        */
-       public function parse( $text, $lineStart = false ) {
-               global $wgParser;
-               
-               try {
-                       $out = $wgParser->parse( $text, $this->parserTitle, $this->parserOptions, $lineStart );
-                       $html = $out->getText();
-               } catch ( DBAccessError $e ) {
-                       $html = '<!--DB access attempted during parse-->  ' . htmlspecialchars( $text );
-                       
-                       if ( !empty( $this->debug ) ) {
-                               $html .= "<!--\n" . $e->getTraceAsString() . "\n-->";
-                       }
-               }
-               
-               return $html;
-       }
-
-       /**
-        * Register tag hook below.
-        */
-       public function registerDocLink( &$parser ) {
-               $parser->setHook( 'doclink', array( $this, 'docLink' ) );
-               return true;
-       }
-
-       /**
-        * Extension tag hook for a documentation link.
-        */
-       public function docLink( $linkText, $attribs, $parser ) {
-               $url = $this->getDocUrl( $attribs['href'] );
-               return '<a href="' . htmlspecialchars( $url ) . '">' .
-                       htmlspecialchars( $linkText ) .
-                       '</a>';
-       }
-
-       /**
-        * Overridden by WebInstaller to provide lastPage parameters.
-        */
-       protected function getDocUrl( $page ) {
-               return "{$_SERVER['PHP_SELF']}?page=" . urlencode( $attribs['href'] );
-       }
-
-       public function findExtensions() {
-               if( $this->getVar( 'IP' ) === null ) {
-                       return false;
-               }
-               
-               $exts = array();
-               $dir = $this->getVar( 'IP' ) . '/extensions';
-               $dh = opendir( $dir );
-               
-               while ( ( $file = readdir( $dh ) ) !== false ) {
-                       if( file_exists( "$dir/$file/$file.php" ) ) {
-                               $exts[$file] = null;
-                       }
-               }
-               
-               $this->setVar( '_Extensions', $exts );
-               
-               return $exts;
-       }
-
-       public function getInstallSteps() {
-               if( $this->getVar( '_UpgradeDone' ) ) {
-                       $this->installSteps = array( 'localsettings' );
-               }
-               
-               if( count( $this->getVar( '_Extensions' ) ) ) {
-                       array_unshift( $this->installSteps, 'extensions' );
-               }
-               
-               return $this->installSteps;
-       }
-
-       /**
-        * Actually perform the installation.
-        * 
-        * @param Array $startCB A callback array for the beginning of each step
-        * @param Array $endCB A callback array for the end of each step
-        * 
-        * @return Array of Status objects
-        */
-       public function performInstallation( $startCB, $endCB ) {
-               $installResults = array();
-               $installer = $this->getDBInstaller();
-               
-               foreach( $this->getInstallSteps() as $stepObj ) {
-                       $step = is_array( $stepObj ) ? $stepObj['name'] : $stepObj;
-                       call_user_func_array( $startCB, array( $step ) );
-                       $status = null;
-
-                       # Call our working function
-                       if ( is_array( $stepObj ) ) {
-                               # A custom callaback
-                               $callback = $stepObj['callback'];
-                               $status = call_user_func_array( $callback, array( $installer ) );
-                       } else {
-                               # Boring implicitly named callback
-                               $func = 'install' . ucfirst( $step );
-                               $status = $this->{$func}( $installer );
-                       }
-                       
-                       call_user_func_array( $endCB, array( $step, $status ) );
-                       $installResults[$step] = $status;
-
-                       // If we've hit some sort of fatal, we need to bail. 
-                       // Callback already had a chance to do output above.
-                       if( !$status->isOk() ) {
-                               break;
-                       }
-                               
-               }
-               
-               if( $status->isOk() ) {
-                       $this->setVar( '_InstallDone', true );
-               }
-               
-               return $installResults;
-       }
-
-       public function installExtensions() {
-               global $wgHooks, $wgAutoloadClasses;
-               
-               $exts = $this->getVar( '_Extensions' );
-               $path = $this->getVar( 'IP' ) . '/extensions';
-               
-               foreach( $exts as $e ) {
-                       require( "$path/$e/$e.php" );
-               }
-               
-               return Status::newGood();
-       }
-
-       public function installDatabase( &$installer ) {
-               if( !$installer ) {
-                       $type = $this->getVar( 'wgDBtype' );
-                       $status = Status::newFatal( "config-no-db", $type );
-               } else {
-                       $status = $installer->setupDatabase();
-               }
-               
-               return $status;
-       }
-
-       public function installTables( &$installer ) {
-               $status = $installer->createTables();
-               
-               if( $status->isOK() ) {
-                       LBFactory::enableBackend();
-               }
-               
-               return $status;
-       }
-
-       public function installInterwiki( &$installer ) {
-               return $installer->populateInterwikiTable();
-       }
-
-       public function installSecretKey() {
-               if ( wfIsWindows() ) {
-                       $file = null;
-               } else {
-                       wfSuppressWarnings();
-                       $file = fopen( "/dev/urandom", "r" );
-                       wfRestoreWarnings();
-               }
-
-               $status = Status::newGood();
-
-               if ( $file ) {
-                       $secretKey = bin2hex( fread( $file, 32 ) );
-                       fclose( $file );
-               } else {
-                       $secretKey = '';
-                       
-                       for ( $i=0; $i<8; $i++ ) {
-                               $secretKey .= dechex(mt_rand(0, 0x7fffffff));
-                       }
-                       
-                       $status->warning( 'config-insecure-secretkey' );
-               }
-               
-               $this->setVar( 'wgSecretKey', $secretKey );
-
-               return $status;
-       }
-
-       public function installSysop() {
-               $name = $this->getVar( '_AdminName' );
-               $user = User::newFromName( $name );
-               
-               if ( !$user ) {
-                       // we should've validated this earlier anyway!
-                       return Status::newFatal( 'config-admin-error-user', $name );
-               }
-               
-               if ( $user->idForName() == 0 ) {
-                       $user->addToDatabase();
-                       
-                       try {
-                               $user->setPassword( $this->getVar( '_AdminPassword' ) );
-                       } catch( PasswordError $pwe ) {
-                               return Status::newFatal( 'config-admin-error-password', $name, $pwe->getMessage() );
-                       }
-                       
-                       $user->addGroup( 'sysop' );
-                       $user->addGroup( 'bureaucrat' );
-                       $user->saveSettings();
-               }
-               
-               return Status::newGood();
-       }
-
-       /**
-        * Determine if LocalSettings exists. If it does, return an appropriate
-        * status for whether we should can upgrade or not.
-        * @return Status
-        */
-       public function getLocalSettingsStatus() {
-               global $IP;
-
-               $status = Status::newGood();
-
-               wfSuppressWarnings();
-               $ls = file_exists( "$IP/LocalSettings.php" );
-               wfRestoreWarnings();
-
-               if( $ls ) {
-                       if( $this->getDBInstaller()->needsUpgrade() ) {
-                               $status->warning( 'config-localsettings-upgrade' );
-                       }
-                       else {
-                               $status->fatal( 'config-localsettings-noupgrade' );
-                       }
-               }
-               
-               return $status;
-       }
-
-       /**
-        * On POSIX systems return the primary group of the webserver we're running under.
-        * On other systems just returns null.
-        *
-        * This is used to advice the user that he should chgrp his config/data/images directory as the
-        * webserver user before he can install.
-        *
-        * Public because SqliteInstaller needs it, and doesn't subclass Installer.
-        *
-        * @return String
-        */
-       public static function maybeGetWebserverPrimaryGroup() {
-               if ( !function_exists( 'posix_getegid' ) || !function_exists( 'posix_getpwuid' ) ) {
-                       # I don't know this, this isn't UNIX.
-                       return null;
-               }
-
-               # posix_getegid() *not* getmygid() because we want the group of the webserver,
-               # not whoever owns the current script.
-               $gid = posix_getegid();
-               $getpwuid = posix_getpwuid( $gid );
-               $group = $getpwuid['name'];
-
-               return $group;
-       }
-
-       /**
-        * Override the necessary bits of the config to run an installation.
-        */
-       public static function overrideConfig() {
-               define( 'MW_NO_SESSION', 1 );
-
-               // Don't access the database
-               $GLOBALS['wgUseDatabaseMessages'] = false;
-               // Debug-friendly
-               $GLOBALS['wgShowExceptionDetails'] = true;
-               // Don't break forms
-               $GLOBALS['wgExternalLinkTarget'] = '_blank';
-
-               // Extended debugging. Maybe disable before release?
-               $GLOBALS['wgShowSQLErrors'] = true;
-               $GLOBALS['wgShowDBErrorBacktrace'] = true;
-       }
-
-       /**
-        * Add an installation step following the given step.
-        * 
-        * @param $findStep String the step to find.  Use NULL to put the step at the beginning.
-        * @param $callback array
-        */
-       public function addInstallStepFollowing( $findStep, $callback ) {
-               $where = 0;
-               
-               if( $findStep !== null ) {
-                       $where = array_search( $findStep, $this->installSteps );
-               }
-
-               array_splice( $this->installSteps, $where, 0, $callback );
-       }
-
+       }               
+       
 }
\ No newline at end of file
index a336b2b..b18536c 100644 (file)
@@ -1,6 +1,16 @@
 <?php
 
-class WebInstaller extends Installer {
+/**
+ * Class for the core installer web interface.
+ * 
+ * @since 1.17
+ */
+class WebInstaller extends CoreInstaller {
+       
+       /**
+        * @var WebInstallerOutput
+        */
+       public $output; 
        
        /**
         * WebRequest object.
@@ -16,7 +26,8 @@ class WebInstaller extends Installer {
         */
        public $session;
 
-       /** Captured PHP error text. Temporary.
+       /** 
+        * Captured PHP error text. Temporary.
         */
        public $phpErrors;
 
@@ -472,8 +483,11 @@ class WebInstaller extends Installer {
                
                foreach ( $this->pageSequence as $id => $pageName ) {
                        $happy = !empty( $this->happyPages[$id] );
-                       $s .= $this->getPageListItem( $pageName,
-                               $happy || $lastHappy == $id - 1, $currentPageName );
+                       $s .= $this->getPageListItem( 
+                               $pageName,
+                               $happy || $lastHappy == $id - 1,
+                               $currentPageName
+                       );
                                
                        if ( $happy ) {
                                $lastHappy = $id;
@@ -930,9 +944,11 @@ class WebInstaller extends Installer {
         */
        public function getDocUrl( $page ) {
                $url = "{$_SERVER['PHP_SELF']}?page=" . urlencode( $page );
+               
                if ( in_array( $this->currentPageName, $this->pageSequence ) ) {
                        $url .= '&lastPage=' . urlencode( $this->currentPageName );
                }
+               
                return $url;
        }
        
index 640e6f4..b6b0266 100644 (file)
@@ -595,14 +595,17 @@ class WebInstaller_Options extends WebInstallerPage {
                );
 
                $extensions = $this->parent->findExtensions();
+               
                if( $extensions ) {
                        $extHtml = $this->parent->getFieldsetStart( 'config-extensions' );
-                       foreach( array_keys($extensions) as $ext ) {
+                       
+                       foreach( $extensions as $ext ) {
                                $extHtml .= $this->parent->getCheckBox( array(
                                        'var' => "ext-$ext",
                                        'rawtext' => $ext,
                                ) );
                        }
+                       
                        $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) .
                                $this->parent->getFieldsetEnd();
                        $this->addHTML( $extHtml );