MediaWiki  REL1_24
WebInstallerPage.php
Go to the documentation of this file.
00001 <?php
00030 abstract class WebInstallerPage {
00031 
00037     public $parent;
00038 
00042     abstract public function execute();
00043 
00047     public function __construct( WebInstaller $parent ) {
00048         $this->parent = $parent;
00049     }
00050 
00058     public function isSlow() {
00059         return false;
00060     }
00061 
00065     public function addHTML( $html ) {
00066         $this->parent->output->addHTML( $html );
00067     }
00068 
00069     public function startForm() {
00070         $this->addHTML(
00071             "<div class=\"config-section\">\n" .
00072             Html::openElement(
00073                 'form',
00074                 array(
00075                     'method' => 'post',
00076                     'action' => $this->parent->getUrl( array( 'page' => $this->getName() ) )
00077                 )
00078             ) . "\n"
00079         );
00080     }
00081 
00086     public function endForm( $continue = 'continue', $back = 'back' ) {
00087         $s = "<div class=\"config-submit\">\n";
00088         $id = $this->getId();
00089 
00090         if ( $id === false ) {
00091             $s .= Html::hidden( 'lastPage', $this->parent->request->getVal( 'lastPage' ) );
00092         }
00093 
00094         if ( $continue ) {
00095             // Fake submit button for enter keypress (bug 26267)
00096             // Messages: config-continue, config-restart, config-regenerate
00097             $s .= Xml::submitButton(
00098                 wfMessage( "config-$continue" )->text(),
00099                 array(
00100                     'name' => "enter-$continue",
00101                     'style' => 'visibility:hidden;overflow:hidden;width:1px;margin:0'
00102                 )
00103             ) . "\n";
00104         }
00105 
00106         if ( $back ) {
00107             // Message: config-back
00108             $s .= Xml::submitButton(
00109                 wfMessage( "config-$back" )->text(),
00110                 array(
00111                     'name' => "submit-$back",
00112                     'tabindex' => $this->parent->nextTabIndex()
00113                 )
00114             ) . "\n";
00115         }
00116 
00117         if ( $continue ) {
00118             // Messages: config-continue, config-restart, config-regenerate
00119             $s .= Xml::submitButton(
00120                 wfMessage( "config-$continue" )->text(),
00121                 array(
00122                     'name' => "submit-$continue",
00123                     'tabindex' => $this->parent->nextTabIndex(),
00124                 )
00125             ) . "\n";
00126         }
00127 
00128         $s .= "</div></form></div>\n";
00129         $this->addHTML( $s );
00130     }
00131 
00135     public function getName() {
00136         return str_replace( 'WebInstaller', '', get_class( $this ) );
00137     }
00138 
00142     protected function getId() {
00143         return array_search( $this->getName(), $this->parent->pageSequence );
00144     }
00145 
00152     public function getVar( $var, $default = null ) {
00153         return $this->parent->getVar( $var, $default );
00154     }
00155 
00160     public function setVar( $name, $value ) {
00161         $this->parent->setVar( $name, $value );
00162     }
00163 
00171     protected function getFieldsetStart( $legend ) {
00172         return "\n<fieldset><legend>" . wfMessage( $legend )->escaped() . "</legend>\n";
00173     }
00174 
00180     protected function getFieldsetEnd() {
00181         return "</fieldset>\n";
00182     }
00183 
00187     protected function startLiveBox() {
00188         $this->addHTML(
00189             '<div id="config-spinner" style="display:none;">' .
00190             '<img src="images/ajax-loader.gif" /></div>' .
00191             '<script>jQuery( "#config-spinner" ).show();</script>' .
00192             '<div id="config-live-log">' .
00193             '<textarea name="LiveLog" rows="10" cols="30" readonly="readonly">'
00194         );
00195         $this->parent->output->flush();
00196     }
00197 
00201     protected function endLiveBox() {
00202         $this->addHTML( '</textarea></div>
00203 <script>jQuery( "#config-spinner" ).hide()</script>' );
00204         $this->parent->output->flush();
00205     }
00206 
00207 }
00208 
00209 class WebInstallerLanguage extends WebInstallerPage {
00210 
00214     public function execute() {
00215         global $wgLang;
00216         $r = $this->parent->request;
00217         $userLang = $r->getVal( 'uselang' );
00218         $contLang = $r->getVal( 'ContLang' );
00219 
00220         $languages = Language::fetchLanguageNames();
00221         $lifetime = intval( ini_get( 'session.gc_maxlifetime' ) );
00222         if ( !$lifetime ) {
00223             $lifetime = 1440; // PHP default
00224         }
00225 
00226         if ( $r->wasPosted() ) {
00227             # Do session test
00228             if ( $this->parent->getSession( 'test' ) === null ) {
00229                 $requestTime = $r->getVal( 'LanguageRequestTime' );
00230                 if ( !$requestTime ) {
00231                     // The most likely explanation is that the user was knocked back
00232                     // from another page on POST due to session expiry
00233                     $msg = 'config-session-expired';
00234                 } elseif ( time() - $requestTime > $lifetime ) {
00235                     $msg = 'config-session-expired';
00236                 } else {
00237                     $msg = 'config-no-session';
00238                 }
00239                 $this->parent->showError( $msg, $wgLang->formatTimePeriod( $lifetime ) );
00240             } else {
00241                 if ( isset( $languages[$userLang] ) ) {
00242                     $this->setVar( '_UserLang', $userLang );
00243                 }
00244                 if ( isset( $languages[$contLang] ) ) {
00245                     $this->setVar( 'wgLanguageCode', $contLang );
00246                 }
00247 
00248                 return 'continue';
00249             }
00250         } elseif ( $this->parent->showSessionWarning ) {
00251             # The user was knocked back from another page to the start
00252             # This probably indicates a session expiry
00253             $this->parent->showError( 'config-session-expired',
00254                 $wgLang->formatTimePeriod( $lifetime ) );
00255         }
00256 
00257         $this->parent->setSession( 'test', true );
00258 
00259         if ( !isset( $languages[$userLang] ) ) {
00260             $userLang = $this->getVar( '_UserLang', 'en' );
00261         }
00262         if ( !isset( $languages[$contLang] ) ) {
00263             $contLang = $this->getVar( 'wgLanguageCode', 'en' );
00264         }
00265         $this->startForm();
00266         $s = Html::hidden( 'LanguageRequestTime', time() ) .
00267             $this->getLanguageSelector( 'uselang', 'config-your-language', $userLang,
00268                 $this->parent->getHelpBox( 'config-your-language-help' ) ) .
00269             $this->getLanguageSelector( 'ContLang', 'config-wiki-language', $contLang,
00270                 $this->parent->getHelpBox( 'config-wiki-language-help' ) );
00271         $this->addHTML( $s );
00272         $this->endForm( 'continue', false );
00273 
00274         return null;
00275     }
00276 
00287     public function getLanguageSelector( $name, $label, $selectedCode, $helpHtml = '' ) {
00288         global $wgDummyLanguageCodes;
00289 
00290         $s = $helpHtml;
00291 
00292         $s .= Html::openElement( 'select', array( 'id' => $name, 'name' => $name,
00293                 'tabindex' => $this->parent->nextTabIndex() ) ) . "\n";
00294 
00295         $languages = Language::fetchLanguageNames();
00296         ksort( $languages );
00297         foreach ( $languages as $code => $lang ) {
00298             if ( isset( $wgDummyLanguageCodes[$code] ) ) {
00299                 continue;
00300             }
00301             $s .= "\n" . Xml::option( "$code - $lang", $code, $code == $selectedCode );
00302         }
00303         $s .= "\n</select>\n";
00304 
00305         return $this->parent->label( $label, $name, $s );
00306     }
00307 
00308 }
00309 
00310 class WebInstallerExistingWiki extends WebInstallerPage {
00311 
00315     public function execute() {
00316         // If there is no LocalSettings.php, continue to the installer welcome page
00317         $vars = Installer::getExistingLocalSettings();
00318         if ( !$vars ) {
00319             return 'skip';
00320         }
00321 
00322         // Check if the upgrade key supplied to the user has appeared in LocalSettings.php
00323         if ( $vars['wgUpgradeKey'] !== false
00324             && $this->getVar( '_UpgradeKeySupplied' )
00325             && $this->getVar( 'wgUpgradeKey' ) === $vars['wgUpgradeKey']
00326         ) {
00327             // It's there, so the user is authorized
00328             $status = $this->handleExistingUpgrade( $vars );
00329             if ( $status->isOK() ) {
00330                 return 'skip';
00331             } else {
00332                 $this->startForm();
00333                 $this->parent->showStatusBox( $status );
00334                 $this->endForm( 'continue' );
00335 
00336                 return 'output';
00337             }
00338         }
00339 
00340         // If there is no $wgUpgradeKey, tell the user to add one to LocalSettings.php
00341         if ( $vars['wgUpgradeKey'] === false ) {
00342             if ( $this->getVar( 'wgUpgradeKey', false ) === false ) {
00343                 $secretKey = $this->getVar( 'wgSecretKey' ); // preserve $wgSecretKey
00344                 $this->parent->generateKeys();
00345                 $this->setVar( 'wgSecretKey', $secretKey );
00346                 $this->setVar( '_UpgradeKeySupplied', true );
00347             }
00348             $this->startForm();
00349             $this->addHTML( $this->parent->getInfoBox(
00350                 wfMessage( 'config-upgrade-key-missing', "<pre dir=\"ltr\">\$wgUpgradeKey = '" .
00351                     $this->getVar( 'wgUpgradeKey' ) . "';</pre>" )->plain()
00352             ) );
00353             $this->endForm( 'continue' );
00354 
00355             return 'output';
00356         }
00357 
00358         // If there is an upgrade key, but it wasn't supplied, prompt the user to enter it
00359 
00360         $r = $this->parent->request;
00361         if ( $r->wasPosted() ) {
00362             $key = $r->getText( 'config_wgUpgradeKey' );
00363             if ( !$key || $key !== $vars['wgUpgradeKey'] ) {
00364                 $this->parent->showError( 'config-localsettings-badkey' );
00365                 $this->showKeyForm();
00366 
00367                 return 'output';
00368             }
00369             // Key was OK
00370             $status = $this->handleExistingUpgrade( $vars );
00371             if ( $status->isOK() ) {
00372                 return 'continue';
00373             } else {
00374                 $this->parent->showStatusBox( $status );
00375                 $this->showKeyForm();
00376 
00377                 return 'output';
00378             }
00379         } else {
00380             $this->showKeyForm();
00381 
00382             return 'output';
00383         }
00384     }
00385 
00389     protected function showKeyForm() {
00390         $this->startForm();
00391         $this->addHTML(
00392             $this->parent->getInfoBox( wfMessage( 'config-localsettings-upgrade' )->plain() ) .
00393             '<br />' .
00394             $this->parent->getTextBox( array(
00395                 'var' => 'wgUpgradeKey',
00396                 'label' => 'config-localsettings-key',
00397                 'attribs' => array( 'autocomplete' => 'off' ),
00398             ) )
00399         );
00400         $this->endForm( 'continue' );
00401     }
00402 
00409     protected function importVariables( $names, $vars ) {
00410         $status = Status::newGood();
00411         foreach ( $names as $name ) {
00412             if ( !isset( $vars[$name] ) ) {
00413                 $status->fatal( 'config-localsettings-incomplete', $name );
00414             }
00415             $this->setVar( $name, $vars[$name] );
00416         }
00417 
00418         return $status;
00419     }
00420 
00428     protected function handleExistingUpgrade( $vars ) {
00429         // Check $wgDBtype
00430         if ( !isset( $vars['wgDBtype'] ) ||
00431             !in_array( $vars['wgDBtype'], Installer::getDBTypes() )
00432         ) {
00433             return Status::newFatal( 'config-localsettings-connection-error', '' );
00434         }
00435 
00436         // Set the relevant variables from LocalSettings.php
00437         $requiredVars = array( 'wgDBtype' );
00438         $status = $this->importVariables( $requiredVars, $vars );
00439         $installer = $this->parent->getDBInstaller();
00440         $status->merge( $this->importVariables( $installer->getGlobalNames(), $vars ) );
00441         if ( !$status->isOK() ) {
00442             return $status;
00443         }
00444 
00445         if ( isset( $vars['wgDBadminuser'] ) ) {
00446             $this->setVar( '_InstallUser', $vars['wgDBadminuser'] );
00447         } else {
00448             $this->setVar( '_InstallUser', $vars['wgDBuser'] );
00449         }
00450         if ( isset( $vars['wgDBadminpassword'] ) ) {
00451             $this->setVar( '_InstallPassword', $vars['wgDBadminpassword'] );
00452         } else {
00453             $this->setVar( '_InstallPassword', $vars['wgDBpassword'] );
00454         }
00455 
00456         // Test the database connection
00457         $status = $installer->getConnection();
00458         if ( !$status->isOK() ) {
00459             // Adjust the error message to explain things correctly
00460             $status->replaceMessage( 'config-connection-error',
00461                 'config-localsettings-connection-error' );
00462 
00463             return $status;
00464         }
00465 
00466         // All good
00467         $this->setVar( '_ExistingDBSettings', true );
00468 
00469         return $status;
00470     }
00471 
00472 }
00473 
00474 class WebInstallerWelcome extends WebInstallerPage {
00475 
00479     public function execute() {
00480         if ( $this->parent->request->wasPosted() ) {
00481             if ( $this->getVar( '_Environment' ) ) {
00482                 return 'continue';
00483             }
00484         }
00485         $this->parent->output->addWikiText( wfMessage( 'config-welcome' )->plain() );
00486         $status = $this->parent->doEnvironmentChecks();
00487         if ( $status->isGood() ) {
00488             $this->parent->output->addHTML( '<span class="success-message">' .
00489                 wfMessage( 'config-env-good' )->escaped() . '</span>' );
00490             $this->parent->output->addWikiText( wfMessage( 'config-copyright',
00491                 SpecialVersion::getCopyrightAndAuthorList() )->plain() );
00492             $this->startForm();
00493             $this->endForm();
00494         } else {
00495             $this->parent->showStatusMessage( $status );
00496         }
00497 
00498         return '';
00499     }
00500 
00501 }
00502 
00503 class WebInstallerDBConnect extends WebInstallerPage {
00504 
00508     public function execute() {
00509         if ( $this->getVar( '_ExistingDBSettings' ) ) {
00510             return 'skip';
00511         }
00512 
00513         $r = $this->parent->request;
00514         if ( $r->wasPosted() ) {
00515             $status = $this->submit();
00516 
00517             if ( $status->isGood() ) {
00518                 $this->setVar( '_UpgradeDone', false );
00519 
00520                 return 'continue';
00521             } else {
00522                 $this->parent->showStatusBox( $status );
00523             }
00524         }
00525 
00526         $this->startForm();
00527 
00528         $types = "<ul class=\"config-settings-block\">\n";
00529         $settings = '';
00530         $defaultType = $this->getVar( 'wgDBtype' );
00531 
00532         // Messages: config-dbsupport-mysql, config-dbsupport-postgres, config-dbsupport-oracle,
00533         // config-dbsupport-sqlite, config-dbsupport-mssql
00534         $dbSupport = '';
00535         foreach ( Installer::getDBTypes() as $type ) {
00536             $dbSupport .= wfMessage( "config-dbsupport-$type" )->plain() . "\n";
00537         }
00538         $this->addHTML( $this->parent->getInfoBox(
00539             wfMessage( 'config-support-info', trim( $dbSupport ) )->text() ) );
00540 
00541         // It's possible that the library for the default DB type is not compiled in.
00542         // In that case, instead select the first supported DB type in the list.
00543         $compiledDBs = $this->parent->getCompiledDBs();
00544         if ( !in_array( $defaultType, $compiledDBs ) ) {
00545             $defaultType = $compiledDBs[0];
00546         }
00547 
00548         foreach ( $compiledDBs as $type ) {
00549             $installer = $this->parent->getDBInstaller( $type );
00550             $types .=
00551                 '<li>' .
00552                 Xml::radioLabel(
00553                     $installer->getReadableName(),
00554                     'DBType',
00555                     $type,
00556                     "DBType_$type",
00557                     $type == $defaultType,
00558                     array( 'class' => 'dbRadio', 'rel' => "DB_wrapper_$type" )
00559                 ) .
00560                 "</li>\n";
00561 
00562             // Messages: config-header-mysql, config-header-postgres, config-header-oracle,
00563             // config-header-sqlite
00564             $settings .= Html::openElement(
00565                     'div',
00566                     array(
00567                         'id' => 'DB_wrapper_' . $type,
00568                         'class' => 'dbWrapper'
00569                     )
00570                 ) .
00571                 Html::element( 'h3', array(), wfMessage( 'config-header-' . $type )->text() ) .
00572                 $installer->getConnectForm() .
00573                 "</div>\n";
00574         }
00575 
00576         $types .= "</ul><br style=\"clear: left\"/>\n";
00577 
00578         $this->addHTML( $this->parent->label( 'config-db-type', false, $types ) . $settings );
00579         $this->endForm();
00580 
00581         return null;
00582     }
00583 
00587     public function submit() {
00588         $r = $this->parent->request;
00589         $type = $r->getVal( 'DBType' );
00590         if ( !$type ) {
00591             return Status::newFatal( 'config-invalid-db-type' );
00592         }
00593         $this->setVar( 'wgDBtype', $type );
00594         $installer = $this->parent->getDBInstaller( $type );
00595         if ( !$installer ) {
00596             return Status::newFatal( 'config-invalid-db-type' );
00597         }
00598 
00599         return $installer->submitConnectForm();
00600     }
00601 
00602 }
00603 
00604 class WebInstallerUpgrade extends WebInstallerPage {
00605 
00609     public function isSlow() {
00610         return true;
00611     }
00612 
00616     public function execute() {
00617         if ( $this->getVar( '_UpgradeDone' ) ) {
00618             // Allow regeneration of LocalSettings.php, unless we are working
00619             // from a pre-existing LocalSettings.php file and we want to avoid
00620             // leaking its contents
00621             if ( $this->parent->request->wasPosted() && !$this->getVar( '_ExistingDBSettings' ) ) {
00622                 // Done message acknowledged
00623                 return 'continue';
00624             } else {
00625                 // Back button click
00626                 // Show the done message again
00627                 // Make them click back again if they want to do the upgrade again
00628                 $this->showDoneMessage();
00629 
00630                 return 'output';
00631             }
00632         }
00633 
00634         // wgDBtype is generally valid here because otherwise the previous page
00635         // (connect) wouldn't have declared its happiness
00636         $type = $this->getVar( 'wgDBtype' );
00637         $installer = $this->parent->getDBInstaller( $type );
00638 
00639         if ( !$installer->needsUpgrade() ) {
00640             return 'skip';
00641         }
00642 
00643         if ( $this->parent->request->wasPosted() ) {
00644             $installer->preUpgrade();
00645 
00646             $this->startLiveBox();
00647             $result = $installer->doUpgrade();
00648             $this->endLiveBox();
00649 
00650             if ( $result ) {
00651                 // If they're going to possibly regenerate LocalSettings, we
00652                 // need to create the upgrade/secret keys. Bug 26481
00653                 if ( !$this->getVar( '_ExistingDBSettings' ) ) {
00654                     $this->parent->generateKeys();
00655                 }
00656                 $this->setVar( '_UpgradeDone', true );
00657                 $this->showDoneMessage();
00658 
00659                 return 'output';
00660             }
00661         }
00662 
00663         $this->startForm();
00664         $this->addHTML( $this->parent->getInfoBox(
00665             wfMessage( 'config-can-upgrade', $GLOBALS['wgVersion'] )->plain() ) );
00666         $this->endForm();
00667 
00668         return null;
00669     }
00670 
00671     public function showDoneMessage() {
00672         $this->startForm();
00673         $regenerate = !$this->getVar( '_ExistingDBSettings' );
00674         if ( $regenerate ) {
00675             $msg = 'config-upgrade-done';
00676         } else {
00677             $msg = 'config-upgrade-done-no-regenerate';
00678         }
00679         $this->parent->disableLinkPopups();
00680         $this->addHTML(
00681             $this->parent->getInfoBox(
00682                 wfMessage( $msg,
00683                     $this->getVar( 'wgServer' ) .
00684                     $this->getVar( 'wgScriptPath' ) . '/index' .
00685                     $this->getVar( 'wgScriptExtension' )
00686                 )->plain(), 'tick-32.png'
00687             )
00688         );
00689         $this->parent->restoreLinkPopups();
00690         $this->endForm( $regenerate ? 'regenerate' : false, false );
00691     }
00692 
00693 }
00694 
00695 class WebInstallerDBSettings extends WebInstallerPage {
00696 
00700     public function execute() {
00701         $installer = $this->parent->getDBInstaller( $this->getVar( 'wgDBtype' ) );
00702 
00703         $r = $this->parent->request;
00704         if ( $r->wasPosted() ) {
00705             $status = $installer->submitSettingsForm();
00706             if ( $status === false ) {
00707                 return 'skip';
00708             } elseif ( $status->isGood() ) {
00709                 return 'continue';
00710             } else {
00711                 $this->parent->showStatusBox( $status );
00712             }
00713         }
00714 
00715         $form = $installer->getSettingsForm();
00716         if ( $form === false ) {
00717             return 'skip';
00718         }
00719 
00720         $this->startForm();
00721         $this->addHTML( $form );
00722         $this->endForm();
00723 
00724         return null;
00725     }
00726 
00727 }
00728 
00729 class WebInstallerName extends WebInstallerPage {
00730 
00734     public function execute() {
00735         $r = $this->parent->request;
00736         if ( $r->wasPosted() ) {
00737             if ( $this->submit() ) {
00738                 return 'continue';
00739             }
00740         }
00741 
00742         $this->startForm();
00743 
00744         // Encourage people to not name their site 'MediaWiki' by blanking the
00745         // field. I think that was the intent with the original $GLOBALS['wgSitename']
00746         // but these two always were the same so had the effect of making the
00747         // installer forget $wgSitename when navigating back to this page.
00748         if ( $this->getVar( 'wgSitename' ) == 'MediaWiki' ) {
00749             $this->setVar( 'wgSitename', '' );
00750         }
00751 
00752         // Set wgMetaNamespace to something valid before we show the form.
00753         // $wgMetaNamespace defaults to $wgSiteName which is 'MediaWiki'
00754         $metaNS = $this->getVar( 'wgMetaNamespace' );
00755         $this->setVar(
00756             'wgMetaNamespace',
00757             wfMessage( 'config-ns-other-default' )->inContentLanguage()->text()
00758         );
00759 
00760         $this->addHTML(
00761             $this->parent->getTextBox( array(
00762                 'var' => 'wgSitename',
00763                 'label' => 'config-site-name',
00764                 'help' => $this->parent->getHelpBox( 'config-site-name-help' )
00765             ) ) .
00766             // getRadioSet() builds a set of labeled radio buttons.
00767             // For grep: The following messages are used as the item labels:
00768             // config-ns-site-name, config-ns-generic, config-ns-other
00769             $this->parent->getRadioSet( array(
00770                 'var' => '_NamespaceType',
00771                 'label' => 'config-project-namespace',
00772                 'itemLabelPrefix' => 'config-ns-',
00773                 'values' => array( 'site-name', 'generic', 'other' ),
00774                 'commonAttribs' => array( 'class' => 'enableForOther',
00775                     'rel' => 'config_wgMetaNamespace' ),
00776                 'help' => $this->parent->getHelpBox( 'config-project-namespace-help' )
00777             ) ) .
00778             $this->parent->getTextBox( array(
00779                 'var' => 'wgMetaNamespace',
00780                 'label' => '', // @todo Needs a label?
00781                 'attribs' => array( 'readonly' => 'readonly', 'class' => 'enabledByOther' )
00782             ) ) .
00783             $this->getFieldSetStart( 'config-admin-box' ) .
00784             $this->parent->getTextBox( array(
00785                 'var' => '_AdminName',
00786                 'label' => 'config-admin-name',
00787                 'help' => $this->parent->getHelpBox( 'config-admin-help' )
00788             ) ) .
00789             $this->parent->getPasswordBox( array(
00790                 'var' => '_AdminPassword',
00791                 'label' => 'config-admin-password',
00792             ) ) .
00793             $this->parent->getPasswordBox( array(
00794                 'var' => '_AdminPasswordConfirm',
00795                 'label' => 'config-admin-password-confirm'
00796             ) ) .
00797             $this->parent->getTextBox( array(
00798                 'var' => '_AdminEmail',
00799                 'label' => 'config-admin-email',
00800                 'help' => $this->parent->getHelpBox( 'config-admin-email-help' )
00801             ) ) .
00802             $this->parent->getCheckBox( array(
00803                 'var' => '_Subscribe',
00804                 'label' => 'config-subscribe',
00805                 'help' => $this->parent->getHelpBox( 'config-subscribe-help' )
00806             ) ) .
00807             $this->getFieldSetEnd() .
00808             $this->parent->getInfoBox( wfMessage( 'config-almost-done' )->text() ) .
00809             // getRadioSet() builds a set of labeled radio buttons.
00810             // For grep: The following messages are used as the item labels:
00811             // config-optional-continue, config-optional-skip
00812             $this->parent->getRadioSet( array(
00813                 'var' => '_SkipOptional',
00814                 'itemLabelPrefix' => 'config-optional-',
00815                 'values' => array( 'continue', 'skip' )
00816             ) )
00817         );
00818 
00819         // Restore the default value
00820         $this->setVar( 'wgMetaNamespace', $metaNS );
00821 
00822         $this->endForm();
00823 
00824         return 'output';
00825     }
00826 
00830     public function submit() {
00831         $retVal = true;
00832         $this->parent->setVarsFromRequest( array( 'wgSitename', '_NamespaceType',
00833             '_AdminName', '_AdminPassword', '_AdminPasswordConfirm', '_AdminEmail',
00834             '_Subscribe', '_SkipOptional', 'wgMetaNamespace' ) );
00835 
00836         // Validate site name
00837         if ( strval( $this->getVar( 'wgSitename' ) ) === '' ) {
00838             $this->parent->showError( 'config-site-name-blank' );
00839             $retVal = false;
00840         }
00841 
00842         // Fetch namespace
00843         $nsType = $this->getVar( '_NamespaceType' );
00844         if ( $nsType == 'site-name' ) {
00845             $name = $this->getVar( 'wgSitename' );
00846             // Sanitize for namespace
00847             // This algorithm should match the JS one in WebInstallerOutput.php
00848             $name = preg_replace( '/[\[\]\{\}|#<>%+? ]/', '_', $name );
00849             $name = str_replace( '&', '&amp;', $name );
00850             $name = preg_replace( '/__+/', '_', $name );
00851             $name = ucfirst( trim( $name, '_' ) );
00852         } elseif ( $nsType == 'generic' ) {
00853             $name = wfMessage( 'config-ns-generic' )->text();
00854         } else { // other
00855             $name = $this->getVar( 'wgMetaNamespace' );
00856         }
00857 
00858         // Validate namespace
00859         if ( strpos( $name, ':' ) !== false ) {
00860             $good = false;
00861         } else {
00862             // Title-style validation
00863             $title = Title::newFromText( $name );
00864             if ( !$title ) {
00865                 $good = $nsType == 'site-name';
00866             } else {
00867                 $name = $title->getDBkey();
00868                 $good = true;
00869             }
00870         }
00871         if ( !$good ) {
00872             $this->parent->showError( 'config-ns-invalid', $name );
00873             $retVal = false;
00874         }
00875 
00876         // Make sure it won't conflict with any existing namespaces
00877         global $wgContLang;
00878         $nsIndex = $wgContLang->getNsIndex( $name );
00879         if ( $nsIndex !== false && $nsIndex !== NS_PROJECT ) {
00880             $this->parent->showError( 'config-ns-conflict', $name );
00881             $retVal = false;
00882         }
00883 
00884         $this->setVar( 'wgMetaNamespace', $name );
00885 
00886         // Validate username for creation
00887         $name = $this->getVar( '_AdminName' );
00888         if ( strval( $name ) === '' ) {
00889             $this->parent->showError( 'config-admin-name-blank' );
00890             $cname = $name;
00891             $retVal = false;
00892         } else {
00893             $cname = User::getCanonicalName( $name, 'creatable' );
00894             if ( $cname === false ) {
00895                 $this->parent->showError( 'config-admin-name-invalid', $name );
00896                 $retVal = false;
00897             } else {
00898                 $this->setVar( '_AdminName', $cname );
00899             }
00900         }
00901 
00902         // Validate password
00903         $msg = false;
00904         $pwd = $this->getVar( '_AdminPassword' );
00905         $user = User::newFromName( $cname );
00906         if ( $user ) {
00907             $valid = $user->getPasswordValidity( $pwd );
00908         } else {
00909             $valid = 'config-admin-name-invalid';
00910         }
00911         if ( strval( $pwd ) === '' ) {
00912             # $user->getPasswordValidity just checks for $wgMinimalPasswordLength.
00913             # This message is more specific and helpful.
00914             $msg = 'config-admin-password-blank';
00915         } elseif ( $pwd !== $this->getVar( '_AdminPasswordConfirm' ) ) {
00916             $msg = 'config-admin-password-mismatch';
00917         } elseif ( $valid !== true ) {
00918             $msg = $valid;
00919         }
00920         if ( $msg !== false ) {
00921             call_user_func_array( array( $this->parent, 'showError' ), (array)$msg );
00922             $this->setVar( '_AdminPassword', '' );
00923             $this->setVar( '_AdminPasswordConfirm', '' );
00924             $retVal = false;
00925         }
00926 
00927         // Validate e-mail if provided
00928         $email = $this->getVar( '_AdminEmail' );
00929         if ( $email && !Sanitizer::validateEmail( $email ) ) {
00930             $this->parent->showError( 'config-admin-error-bademail' );
00931             $retVal = false;
00932         }
00933         // If they asked to subscribe to mediawiki-announce but didn't give
00934         // an e-mail, show an error. Bug 29332
00935         if ( !$email && $this->getVar( '_Subscribe' ) ) {
00936             $this->parent->showError( 'config-subscribe-noemail' );
00937             $retVal = false;
00938         }
00939 
00940         return $retVal;
00941     }
00942 
00943 }
00944 
00945 class WebInstallerOptions extends WebInstallerPage {
00946 
00950     public function execute() {
00951         if ( $this->getVar( '_SkipOptional' ) == 'skip' ) {
00952             $this->submitSkins();
00953             return 'skip';
00954         }
00955         if ( $this->parent->request->wasPosted() ) {
00956             if ( $this->submit() ) {
00957                 return 'continue';
00958             }
00959         }
00960 
00961         $emailwrapperStyle = $this->getVar( 'wgEnableEmail' ) ? '' : 'display: none';
00962         $this->startForm();
00963         $this->addHTML(
00964             # User Rights
00965             // getRadioSet() builds a set of labeled radio buttons.
00966             // For grep: The following messages are used as the item labels:
00967             // config-profile-wiki, config-profile-no-anon, config-profile-fishbowl, config-profile-private
00968             $this->parent->getRadioSet( array(
00969                 'var' => '_RightsProfile',
00970                 'label' => 'config-profile',
00971                 'itemLabelPrefix' => 'config-profile-',
00972                 'values' => array_keys( $this->parent->rightsProfiles ),
00973             ) ) .
00974             $this->parent->getInfoBox( wfMessage( 'config-profile-help' )->plain() ) .
00975 
00976             # Licensing
00977             // getRadioSet() builds a set of labeled radio buttons.
00978             // For grep: The following messages are used as the item labels:
00979             // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa,
00980             // config-license-cc-0, config-license-pd, config-license-gfdl,
00981             // config-license-none, config-license-cc-choose
00982             $this->parent->getRadioSet( array(
00983                 'var' => '_LicenseCode',
00984                 'label' => 'config-license',
00985                 'itemLabelPrefix' => 'config-license-',
00986                 'values' => array_keys( $this->parent->licenses ),
00987                 'commonAttribs' => array( 'class' => 'licenseRadio' ),
00988             ) ) .
00989             $this->getCCChooser() .
00990             $this->parent->getHelpBox( 'config-license-help' ) .
00991 
00992             # E-mail
00993             $this->getFieldSetStart( 'config-email-settings' ) .
00994             $this->parent->getCheckBox( array(
00995                 'var' => 'wgEnableEmail',
00996                 'label' => 'config-enable-email',
00997                 'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'emailwrapper' ),
00998             ) ) .
00999             $this->parent->getHelpBox( 'config-enable-email-help' ) .
01000             "<div id=\"emailwrapper\" style=\"$emailwrapperStyle\">" .
01001             $this->parent->getTextBox( array(
01002                 'var' => 'wgPasswordSender',
01003                 'label' => 'config-email-sender'
01004             ) ) .
01005             $this->parent->getHelpBox( 'config-email-sender-help' ) .
01006             $this->parent->getCheckBox( array(
01007                 'var' => 'wgEnableUserEmail',
01008                 'label' => 'config-email-user',
01009             ) ) .
01010             $this->parent->getHelpBox( 'config-email-user-help' ) .
01011             $this->parent->getCheckBox( array(
01012                 'var' => 'wgEnotifUserTalk',
01013                 'label' => 'config-email-usertalk',
01014             ) ) .
01015             $this->parent->getHelpBox( 'config-email-usertalk-help' ) .
01016             $this->parent->getCheckBox( array(
01017                 'var' => 'wgEnotifWatchlist',
01018                 'label' => 'config-email-watchlist',
01019             ) ) .
01020             $this->parent->getHelpBox( 'config-email-watchlist-help' ) .
01021             $this->parent->getCheckBox( array(
01022                 'var' => 'wgEmailAuthentication',
01023                 'label' => 'config-email-auth',
01024             ) ) .
01025             $this->parent->getHelpBox( 'config-email-auth-help' ) .
01026             "</div>" .
01027             $this->getFieldSetEnd()
01028         );
01029 
01030         $skins = $this->parent->findExtensions( 'skins' );
01031         $skinHtml = $this->getFieldSetStart( 'config-skins' );
01032 
01033         if ( $skins ) {
01034             $skinNames = array_map( 'strtolower', $skins );
01035 
01036             $radioButtons = $this->parent->getRadioElements( array(
01037                 'var' => 'wgDefaultSkin',
01038                 'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ),
01039                 'values' => $skinNames,
01040                 'value' => $this->getVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) ),
01041             ) );
01042 
01043             foreach ( $skins as $skin ) {
01044                 $skinHtml .=
01045                     '<div class="config-skins-item">' .
01046                     $this->parent->getCheckBox( array(
01047                         'var' => "skin-$skin",
01048                         'rawtext' => $skin,
01049                         'value' => $this->getVar( "skin-$skin", true ), // all found skins enabled by default
01050                     ) ) .
01051                     '<div class="config-skins-use-as-default">' . $radioButtons[strtolower( $skin )] . '</div>' .
01052                     '</div>';
01053             }
01054         } else {
01055             $skinHtml .= $this->parent->getWarningBox( wfMessage( 'config-skins-missing' )->plain() );
01056         }
01057 
01058         $skinHtml .= $this->parent->getHelpBox( 'config-skins-help' ) .
01059             $this->getFieldSetEnd();
01060         $this->addHTML( $skinHtml );
01061 
01062         $extensions = $this->parent->findExtensions();
01063 
01064         if ( $extensions ) {
01065             $extHtml = $this->getFieldSetStart( 'config-extensions' );
01066 
01067             foreach ( $extensions as $ext ) {
01068                 $extHtml .= $this->parent->getCheckBox( array(
01069                     'var' => "ext-$ext",
01070                     'rawtext' => $ext,
01071                 ) );
01072             }
01073 
01074             $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) .
01075                 $this->getFieldSetEnd();
01076             $this->addHTML( $extHtml );
01077         }
01078 
01079         // Having / in paths in Windows looks funny :)
01080         $this->setVar( 'wgDeletedDirectory',
01081             str_replace(
01082                 '/', DIRECTORY_SEPARATOR,
01083                 $this->getVar( 'wgDeletedDirectory' )
01084             )
01085         );
01086 
01087         $uploadwrapperStyle = $this->getVar( 'wgEnableUploads' ) ? '' : 'display: none';
01088         $this->addHTML(
01089             # Uploading
01090             $this->getFieldSetStart( 'config-upload-settings' ) .
01091             $this->parent->getCheckBox( array(
01092                 'var' => 'wgEnableUploads',
01093                 'label' => 'config-upload-enable',
01094                 'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'uploadwrapper' ),
01095                 'help' => $this->parent->getHelpBox( 'config-upload-help' )
01096             ) ) .
01097             '<div id="uploadwrapper" style="' . $uploadwrapperStyle . '">' .
01098             $this->parent->getTextBox( array(
01099                 'var' => 'wgDeletedDirectory',
01100                 'label' => 'config-upload-deleted',
01101                 'attribs' => array( 'dir' => 'ltr' ),
01102                 'help' => $this->parent->getHelpBox( 'config-upload-deleted-help' )
01103             ) ) .
01104             '</div>' .
01105             $this->parent->getTextBox( array(
01106                 'var' => 'wgLogo',
01107                 'label' => 'config-logo',
01108                 'attribs' => array( 'dir' => 'ltr' ),
01109                 'help' => $this->parent->getHelpBox( 'config-logo-help' )
01110             ) )
01111         );
01112         $this->addHTML(
01113             $this->parent->getCheckBox( array(
01114                 'var' => 'wgUseInstantCommons',
01115                 'label' => 'config-instantcommons',
01116                 'help' => $this->parent->getHelpBox( 'config-instantcommons-help' )
01117             ) ) .
01118             $this->getFieldSetEnd()
01119         );
01120 
01121         $caches = array( 'none' );
01122         if ( count( $this->getVar( '_Caches' ) ) ) {
01123             $caches[] = 'accel';
01124         }
01125         $caches[] = 'memcached';
01126 
01127         // We'll hide/show this on demand when the value changes, see config.js.
01128         $cacheval = $this->getVar( 'wgMainCacheType' );
01129         if ( !$cacheval ) {
01130             // We need to set a default here; but don't hardcode it
01131             // or we lose it every time we reload the page for validation
01132             // or going back!
01133             $cacheval = 'none';
01134         }
01135         $hidden = ( $cacheval == 'memcached' ) ? '' : 'display: none';
01136         $this->addHTML(
01137             # Advanced settings
01138             $this->getFieldSetStart( 'config-advanced-settings' ) .
01139             # Object cache settings
01140             // getRadioSet() builds a set of labeled radio buttons.
01141             // For grep: The following messages are used as the item labels:
01142             // config-cache-none, config-cache-accel, config-cache-memcached
01143             $this->parent->getRadioSet( array(
01144                 'var' => 'wgMainCacheType',
01145                 'label' => 'config-cache-options',
01146                 'itemLabelPrefix' => 'config-cache-',
01147                 'values' => $caches,
01148                 'value' => $cacheval,
01149             ) ) .
01150             $this->parent->getHelpBox( 'config-cache-help' ) .
01151             "<div id=\"config-memcachewrapper\" style=\"$hidden\">" .
01152             $this->parent->getTextArea( array(
01153                 'var' => '_MemCachedServers',
01154                 'label' => 'config-memcached-servers',
01155                 'help' => $this->parent->getHelpBox( 'config-memcached-help' )
01156             ) ) .
01157             '</div>' .
01158             $this->getFieldSetEnd()
01159         );
01160         $this->endForm();
01161 
01162         return null;
01163     }
01164 
01168     public function getCCPartnerUrl() {
01169         $server = $this->getVar( 'wgServer' );
01170         $exitUrl = $server . $this->parent->getUrl( array(
01171             'page' => 'Options',
01172             'SubmitCC' => 'indeed',
01173             'config__LicenseCode' => 'cc',
01174             'config_wgRightsUrl' => '[license_url]',
01175             'config_wgRightsText' => '[license_name]',
01176             'config_wgRightsIcon' => '[license_button]',
01177         ) );
01178         $styleUrl = $server . dirname( dirname( $this->parent->getUrl() ) ) .
01179             '/mw-config/config-cc.css';
01180         $iframeUrl = 'http://creativecommons.org/license/?' .
01181             wfArrayToCgi( array(
01182                 'partner' => 'MediaWiki',
01183                 'exit_url' => $exitUrl,
01184                 'lang' => $this->getVar( '_UserLang' ),
01185                 'stylesheet' => $styleUrl,
01186             ) );
01187 
01188         return $iframeUrl;
01189     }
01190 
01194     public function getCCChooser() {
01195         $iframeAttribs = array(
01196             'class' => 'config-cc-iframe',
01197             'name' => 'config-cc-iframe',
01198             'id' => 'config-cc-iframe',
01199             'frameborder' => 0,
01200             'width' => '100%',
01201             'height' => '100%',
01202         );
01203         if ( $this->getVar( '_CCDone' ) ) {
01204             $iframeAttribs['src'] = $this->parent->getUrl( array( 'ShowCC' => 'yes' ) );
01205         } else {
01206             $iframeAttribs['src'] = $this->getCCPartnerUrl();
01207         }
01208         $wrapperStyle = ( $this->getVar( '_LicenseCode' ) == 'cc-choose' ) ? '' : 'display: none';
01209 
01210         return "<div class=\"config-cc-wrapper\" id=\"config-cc-wrapper\" style=\"$wrapperStyle\">\n" .
01211             Html::element( 'iframe', $iframeAttribs, '', false /* not short */ ) .
01212             "</div>\n";
01213     }
01214 
01218     public function getCCDoneBox() {
01219         $js = "parent.document.getElementById('config-cc-wrapper').style.height = '$1';";
01220         // If you change this height, also change it in config.css
01221         $expandJs = str_replace( '$1', '54em', $js );
01222         $reduceJs = str_replace( '$1', '70px', $js );
01223 
01224         return '<p>' .
01225             Html::element( 'img', array( 'src' => $this->getVar( 'wgRightsIcon' ) ) ) .
01226             '&#160;&#160;' .
01227             htmlspecialchars( $this->getVar( 'wgRightsText' ) ) .
01228             "</p>\n" .
01229             "<p style=\"text-align: center;\">" .
01230             Html::element( 'a',
01231                 array(
01232                     'href' => $this->getCCPartnerUrl(),
01233                     'onclick' => $expandJs,
01234                 ),
01235                 wfMessage( 'config-cc-again' )->text()
01236             ) .
01237             "</p>\n" .
01238             "<script>\n" .
01239             # Reduce the wrapper div height
01240             htmlspecialchars( $reduceJs ) .
01241             "\n" .
01242             "</script>\n";
01243     }
01244 
01245     public function submitCC() {
01246         $newValues = $this->parent->setVarsFromRequest(
01247             array( 'wgRightsUrl', 'wgRightsText', 'wgRightsIcon' ) );
01248         if ( count( $newValues ) != 3 ) {
01249             $this->parent->showError( 'config-cc-error' );
01250 
01251             return;
01252         }
01253         $this->setVar( '_CCDone', true );
01254         $this->addHTML( $this->getCCDoneBox() );
01255     }
01256 
01263     public function submitSkins() {
01264         $skins = $this->parent->findExtensions( 'skins' );
01265         $this->parent->setVar( '_Skins', $skins );
01266 
01267         if ( $skins ) {
01268             $skinNames = array_map( 'strtolower', $skins );
01269             $this->parent->setVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) );
01270         }
01271 
01272         return true;
01273     }
01274 
01278     public function submit() {
01279         $this->parent->setVarsFromRequest( array( '_RightsProfile', '_LicenseCode',
01280             'wgEnableEmail', 'wgPasswordSender', 'wgEnableUploads', 'wgLogo',
01281             'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist',
01282             'wgEmailAuthentication', 'wgMainCacheType', '_MemCachedServers',
01283             'wgUseInstantCommons', 'wgDefaultSkin' ) );
01284 
01285         $retVal = true;
01286 
01287         if ( !array_key_exists( $this->getVar( '_RightsProfile' ), $this->parent->rightsProfiles )
01288         ) {
01289             reset( $this->parent->rightsProfiles );
01290             $this->setVar( '_RightsProfile', key( $this->parent->rightsProfiles ) );
01291         }
01292 
01293         $code = $this->getVar( '_LicenseCode' );
01294         if ( $code == 'cc-choose' ) {
01295             if ( !$this->getVar( '_CCDone' ) ) {
01296                 $this->parent->showError( 'config-cc-not-chosen' );
01297                 $retVal = false;
01298             }
01299         } elseif ( array_key_exists( $code, $this->parent->licenses ) ) {
01300             // Messages:
01301             // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa,
01302             // config-license-cc-0, config-license-pd, config-license-gfdl, config-license-none,
01303             // config-license-cc-choose
01304             $entry = $this->parent->licenses[$code];
01305             if ( isset( $entry['text'] ) ) {
01306                 $this->setVar( 'wgRightsText', $entry['text'] );
01307             } else {
01308                 $this->setVar( 'wgRightsText', wfMessage( 'config-license-' . $code )->text() );
01309             }
01310             $this->setVar( 'wgRightsUrl', $entry['url'] );
01311             $this->setVar( 'wgRightsIcon', $entry['icon'] );
01312         } else {
01313             $this->setVar( 'wgRightsText', '' );
01314             $this->setVar( 'wgRightsUrl', '' );
01315             $this->setVar( 'wgRightsIcon', '' );
01316         }
01317 
01318         $skinsAvailable = $this->parent->findExtensions( 'skins' );
01319         $skinsToInstall = array();
01320         foreach ( $skinsAvailable as $skin ) {
01321             $this->parent->setVarsFromRequest( array( "skin-$skin" ) );
01322             if ( $this->getVar( "skin-$skin" ) ) {
01323                 $skinsToInstall[] = $skin;
01324             }
01325         }
01326         $this->parent->setVar( '_Skins', $skinsToInstall );
01327 
01328         if ( !$skinsToInstall && $skinsAvailable ) {
01329             $this->parent->showError( 'config-skins-must-enable-some' );
01330             $retVal = false;
01331         }
01332         $defaultSkin = $this->getVar( 'wgDefaultSkin' );
01333         $skinsToInstallLowercase = array_map( 'strtolower', $skinsToInstall );
01334         if ( $skinsToInstall && array_search( $defaultSkin, $skinsToInstallLowercase ) === false ) {
01335             $this->parent->showError( 'config-skins-must-enable-default' );
01336             $retVal = false;
01337         }
01338 
01339         $extsAvailable = $this->parent->findExtensions();
01340         $extsToInstall = array();
01341         foreach ( $extsAvailable as $ext ) {
01342             $this->parent->setVarsFromRequest( array( "ext-$ext" ) );
01343             if ( $this->getVar( "ext-$ext" ) ) {
01344                 $extsToInstall[] = $ext;
01345             }
01346         }
01347         $this->parent->setVar( '_Extensions', $extsToInstall );
01348 
01349         if ( $this->getVar( 'wgMainCacheType' ) == 'memcached' ) {
01350             $memcServers = explode( "\n", $this->getVar( '_MemCachedServers' ) );
01351             if ( !$memcServers ) {
01352                 $this->parent->showError( 'config-memcache-needservers' );
01353                 $retVal = false;
01354             }
01355 
01356             foreach ( $memcServers as $server ) {
01357                 $memcParts = explode( ":", $server, 2 );
01358                 if ( !isset( $memcParts[0] )
01359                     || ( !IP::isValid( $memcParts[0] )
01360                         && ( gethostbyname( $memcParts[0] ) == $memcParts[0] ) )
01361                 ) {
01362                     $this->parent->showError( 'config-memcache-badip', $memcParts[0] );
01363                     $retVal = false;
01364                 } elseif ( !isset( $memcParts[1] ) ) {
01365                     $this->parent->showError( 'config-memcache-noport', $memcParts[0] );
01366                     $retVal = false;
01367                 } elseif ( $memcParts[1] < 1 || $memcParts[1] > 65535 ) {
01368                     $this->parent->showError( 'config-memcache-badport', 1, 65535 );
01369                     $retVal = false;
01370                 }
01371             }
01372         }
01373 
01374         return $retVal;
01375     }
01376 
01377 }
01378 
01379 class WebInstallerInstall extends WebInstallerPage {
01380 
01384     public function isSlow() {
01385         return true;
01386     }
01387 
01391     public function execute() {
01392         if ( $this->getVar( '_UpgradeDone' ) ) {
01393             return 'skip';
01394         } elseif ( $this->getVar( '_InstallDone' ) ) {
01395             return 'continue';
01396         } elseif ( $this->parent->request->wasPosted() ) {
01397             $this->startForm();
01398             $this->addHTML( "<ul>" );
01399             $results = $this->parent->performInstallation(
01400                 array( $this, 'startStage' ),
01401                 array( $this, 'endStage' )
01402             );
01403             $this->addHTML( "</ul>" );
01404             // PerformInstallation bails on a fatal, so make sure the last item
01405             // completed before giving 'next.' Likewise, only provide back on failure
01406             $lastStep = end( $results );
01407             $continue = $lastStep->isOK() ? 'continue' : false;
01408             $back = $lastStep->isOK() ? false : 'back';
01409             $this->endForm( $continue, $back );
01410         } else {
01411             $this->startForm();
01412             $this->addHTML( $this->parent->getInfoBox( wfMessage( 'config-install-begin' )->plain() ) );
01413             $this->endForm();
01414         }
01415 
01416         return true;
01417     }
01418 
01422     public function startStage( $step ) {
01423         // Messages: config-install-database, config-install-tables, config-install-interwiki,
01424         // config-install-stats, config-install-keys, config-install-sysop, config-install-mainpage
01425         $this->addHTML( "<li>" . wfMessage( "config-install-$step" )->escaped() .
01426             wfMessage( 'ellipsis' )->escaped() );
01427 
01428         if ( $step == 'extension-tables' ) {
01429             $this->startLiveBox();
01430         }
01431     }
01432 
01437     public function endStage( $step, $status ) {
01438         if ( $step == 'extension-tables' ) {
01439             $this->endLiveBox();
01440         }
01441         $msg = $status->isOk() ? 'config-install-step-done' : 'config-install-step-failed';
01442         $html = wfMessage( 'word-separator' )->escaped() . wfMessage( $msg )->escaped();
01443         if ( !$status->isOk() ) {
01444             $html = "<span class=\"error\">$html</span>";
01445         }
01446         $this->addHTML( $html . "</li>\n" );
01447         if ( !$status->isGood() ) {
01448             $this->parent->showStatusBox( $status );
01449         }
01450     }
01451 
01452 }
01453 
01454 class WebInstallerComplete extends WebInstallerPage {
01455 
01456     public function execute() {
01457         // Pop up a dialog box, to make it difficult for the user to forget
01458         // to download the file
01459         $lsUrl = $this->getVar( 'wgServer' ) . $this->parent->getURL( array( 'localsettings' => 1 ) );
01460         if ( isset( $_SERVER['HTTP_USER_AGENT'] ) &&
01461             strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE' ) !== false
01462         ) {
01463             // JS appears to be the only method that works consistently with IE7+
01464             $this->addHtml( "\n<script>jQuery( function () { document.location = " .
01465                 Xml::encodeJsVar( $lsUrl ) . "; } );</script>\n" );
01466         } else {
01467             $this->parent->request->response()->header( "Refresh: 0;url=$lsUrl" );
01468         }
01469 
01470         $this->startForm();
01471         $this->parent->disableLinkPopups();
01472         $this->addHTML(
01473             $this->parent->getInfoBox(
01474                 wfMessage( 'config-install-done',
01475                     $lsUrl,
01476                     $this->getVar( 'wgServer' ) .
01477                     $this->getVar( 'wgScriptPath' ) . '/index' .
01478                     $this->getVar( 'wgScriptExtension' ),
01479                     '<downloadlink/>'
01480                 )->plain(), 'tick-32.png'
01481             )
01482         );
01483         $this->addHTML( $this->parent->getInfoBox(
01484             wfMessage( 'config-extension-link' )->text() ) );
01485 
01486         $this->parent->restoreLinkPopups();
01487         $this->endForm( false, false );
01488     }
01489 
01490 }
01491 
01492 class WebInstallerRestart extends WebInstallerPage {
01493 
01497     public function execute() {
01498         $r = $this->parent->request;
01499         if ( $r->wasPosted() ) {
01500             $really = $r->getVal( 'submit-restart' );
01501             if ( $really ) {
01502                 $this->parent->reset();
01503             }
01504 
01505             return 'continue';
01506         }
01507 
01508         $this->startForm();
01509         $s = $this->parent->getWarningBox( wfMessage( 'config-help-restart' )->plain() );
01510         $this->addHTML( $s );
01511         $this->endForm( 'restart' );
01512 
01513         return null;
01514     }
01515 
01516 }
01517 
01518 abstract class WebInstallerDocument extends WebInstallerPage {
01519 
01523     abstract protected function getFileName();
01524 
01525     public function execute() {
01526         $text = $this->getFileContents();
01527         $text = InstallDocFormatter::format( $text );
01528         $this->parent->output->addWikiText( $text );
01529         $this->startForm();
01530         $this->endForm( false );
01531     }
01532 
01536     public function getFileContents() {
01537         $file = __DIR__ . '/../../' . $this->getFileName();
01538         if ( !file_exists( $file ) ) {
01539             return wfMessage( 'config-nofile', $file )->plain();
01540         }
01541 
01542         return file_get_contents( $file );
01543     }
01544 
01545 }
01546 
01547 class WebInstallerReadme extends WebInstallerDocument {
01548 
01552     protected function getFileName() {
01553         return 'README';
01554     }
01555 
01556 }
01557 
01558 class WebInstallerReleaseNotes extends WebInstallerDocument {
01559 
01564     protected function getFileName() {
01565         global $wgVersion;
01566 
01567         if ( !preg_match( '/^(\d+)\.(\d+).*/i', $wgVersion, $result ) ) {
01568             throw new MWException( 'Variable $wgVersion has an invalid value.' );
01569         }
01570 
01571         return 'RELEASE-NOTES-' . $result[1] . '.' . $result[2];
01572     }
01573 
01574 }
01575 
01576 class WebInstallerUpgradeDoc extends WebInstallerDocument {
01577 
01581     protected function getFileName() {
01582         return 'UPGRADE';
01583     }
01584 
01585 }
01586 
01587 class WebInstallerCopying extends WebInstallerDocument {
01588 
01592     protected function getFileName() {
01593         return 'COPYING';
01594     }
01595 
01596 }