MediaWiki
REL1_21
|
00001 <?php 00030 abstract class WebInstallerPage { 00031 00037 public $parent; 00038 00039 abstract public function execute(); 00040 00046 public function __construct( WebInstaller $parent ) { 00047 $this->parent = $parent; 00048 } 00049 00056 public function isSlow() { 00057 return false; 00058 } 00059 00060 public function addHTML( $html ) { 00061 $this->parent->output->addHTML( $html ); 00062 } 00063 00064 public function startForm() { 00065 $this->addHTML( 00066 "<div class=\"config-section\">\n" . 00067 Html::openElement( 00068 'form', 00069 array( 00070 'method' => 'post', 00071 'action' => $this->parent->getUrl( array( 'page' => $this->getName() ) ) 00072 ) 00073 ) . "\n" 00074 ); 00075 } 00076 00077 public function endForm( $continue = 'continue', $back = 'back' ) { 00078 $s = "<div class=\"config-submit\">\n"; 00079 $id = $this->getId(); 00080 00081 if ( $id === false ) { 00082 $s .= Html::hidden( 'lastPage', $this->parent->request->getVal( 'lastPage' ) ); 00083 } 00084 00085 if ( $continue ) { 00086 // Fake submit button for enter keypress (bug 26267) 00087 $s .= Xml::submitButton( wfMessage( "config-$continue" )->text(), 00088 array( 'name' => "enter-$continue", 'style' => 00089 'visibility:hidden;overflow:hidden;width:1px;margin:0' ) ) . "\n"; 00090 } 00091 00092 if ( $back ) { 00093 $s .= Xml::submitButton( wfMessage( "config-$back" )->text(), 00094 array( 00095 'name' => "submit-$back", 00096 'tabindex' => $this->parent->nextTabIndex() 00097 ) ) . "\n"; 00098 } 00099 00100 if ( $continue ) { 00101 $s .= Xml::submitButton( wfMessage( "config-$continue" )->text(), 00102 array( 00103 'name' => "submit-$continue", 00104 'tabindex' => $this->parent->nextTabIndex(), 00105 ) ) . "\n"; 00106 } 00107 00108 $s .= "</div></form></div>\n"; 00109 $this->addHTML( $s ); 00110 } 00111 00112 public function getName() { 00113 return str_replace( 'WebInstaller_', '', get_class( $this ) ); 00114 } 00115 00116 protected function getId() { 00117 return array_search( $this->getName(), $this->parent->pageSequence ); 00118 } 00119 00120 public function getVar( $var ) { 00121 return $this->parent->getVar( $var ); 00122 } 00123 00124 public function setVar( $name, $value ) { 00125 $this->parent->setVar( $name, $value ); 00126 } 00127 00135 protected function getFieldsetStart( $legend ) { 00136 return "\n<fieldset><legend>" . wfMessage( $legend )->escaped() . "</legend>\n"; 00137 } 00138 00144 protected function getFieldsetEnd() { 00145 return "</fieldset>\n"; 00146 } 00147 00151 protected function startLiveBox() { 00152 $this->addHTML( 00153 '<div id="config-spinner" style="display:none;">' . 00154 '<img src="../skins/common/images/ajax-loader.gif" /></div>' . 00155 '<script>jQuery( "#config-spinner" ).show();</script>' . 00156 '<div id="config-live-log">' . 00157 '<textarea name="LiveLog" rows="10" cols="30" readonly="readonly">' 00158 ); 00159 $this->parent->output->flush(); 00160 } 00161 00165 protected function endLiveBox() { 00166 $this->addHTML( '</textarea></div> 00167 <script>jQuery( "#config-spinner" ).hide()</script>' ); 00168 $this->parent->output->flush(); 00169 } 00170 } 00171 00172 class WebInstaller_Language extends WebInstallerPage { 00173 00174 public function execute() { 00175 global $wgLang; 00176 $r = $this->parent->request; 00177 $userLang = $r->getVal( 'uselang' ); 00178 $contLang = $r->getVal( 'ContLang' ); 00179 00180 $languages = Language::fetchLanguageNames(); 00181 $lifetime = intval( ini_get( 'session.gc_maxlifetime' ) ); 00182 if ( !$lifetime ) { 00183 $lifetime = 1440; // PHP default 00184 } 00185 00186 if ( $r->wasPosted() ) { 00187 # Do session test 00188 if ( $this->parent->getSession( 'test' ) === null ) { 00189 $requestTime = $r->getVal( 'LanguageRequestTime' ); 00190 if ( !$requestTime ) { 00191 // The most likely explanation is that the user was knocked back 00192 // from another page on POST due to session expiry 00193 $msg = 'config-session-expired'; 00194 } elseif ( time() - $requestTime > $lifetime ) { 00195 $msg = 'config-session-expired'; 00196 } else { 00197 $msg = 'config-no-session'; 00198 } 00199 $this->parent->showError( $msg, $wgLang->formatTimePeriod( $lifetime ) ); 00200 } else { 00201 if ( isset( $languages[$userLang] ) ) { 00202 $this->setVar( '_UserLang', $userLang ); 00203 } 00204 if ( isset( $languages[$contLang] ) ) { 00205 $this->setVar( 'wgLanguageCode', $contLang ); 00206 } 00207 return 'continue'; 00208 } 00209 } elseif ( $this->parent->showSessionWarning ) { 00210 # The user was knocked back from another page to the start 00211 # This probably indicates a session expiry 00212 $this->parent->showError( 'config-session-expired', 00213 $wgLang->formatTimePeriod( $lifetime ) ); 00214 } 00215 00216 $this->parent->setSession( 'test', true ); 00217 00218 if ( !isset( $languages[$userLang] ) ) { 00219 $userLang = $this->getVar( '_UserLang', 'en' ); 00220 } 00221 if ( !isset( $languages[$contLang] ) ) { 00222 $contLang = $this->getVar( 'wgLanguageCode', 'en' ); 00223 } 00224 $this->startForm(); 00225 $s = Html::hidden( 'LanguageRequestTime', time() ) . 00226 $this->getLanguageSelector( 'uselang', 'config-your-language', $userLang, 00227 $this->parent->getHelpBox( 'config-your-language-help' ) ) . 00228 $this->getLanguageSelector( 'ContLang', 'config-wiki-language', $contLang, 00229 $this->parent->getHelpBox( 'config-wiki-language-help' ) ); 00230 $this->addHTML( $s ); 00231 $this->endForm( 'continue', false ); 00232 } 00233 00243 public function getLanguageSelector( $name, $label, $selectedCode, $helpHtml = '' ) { 00244 global $wgDummyLanguageCodes; 00245 00246 $s = $helpHtml; 00247 00248 $s .= Html::openElement( 'select', array( 'id' => $name, 'name' => $name, 00249 'tabindex' => $this->parent->nextTabIndex() ) ) . "\n"; 00250 00251 $languages = Language::fetchLanguageNames(); 00252 ksort( $languages ); 00253 foreach ( $languages as $code => $lang ) { 00254 if ( isset( $wgDummyLanguageCodes[$code] ) ) continue; 00255 $s .= "\n" . Xml::option( "$code - $lang", $code, $code == $selectedCode ); 00256 } 00257 $s .= "\n</select>\n"; 00258 return $this->parent->label( $label, $name, $s ); 00259 } 00260 00261 } 00262 00263 class WebInstaller_ExistingWiki extends WebInstallerPage { 00264 public function execute() { 00265 // If there is no LocalSettings.php, continue to the installer welcome page 00266 $vars = Installer::getExistingLocalSettings(); 00267 if ( !$vars ) { 00268 return 'skip'; 00269 } 00270 00271 // Check if the upgrade key supplied to the user has appeared in LocalSettings.php 00272 if ( $vars['wgUpgradeKey'] !== false 00273 && $this->getVar( '_UpgradeKeySupplied' ) 00274 && $this->getVar( 'wgUpgradeKey' ) === $vars['wgUpgradeKey'] ) 00275 { 00276 // It's there, so the user is authorized 00277 $status = $this->handleExistingUpgrade( $vars ); 00278 if ( $status->isOK() ) { 00279 return 'skip'; 00280 } else { 00281 $this->startForm(); 00282 $this->parent->showStatusBox( $status ); 00283 $this->endForm( 'continue' ); 00284 return 'output'; 00285 } 00286 } 00287 00288 // If there is no $wgUpgradeKey, tell the user to add one to LocalSettings.php 00289 if ( $vars['wgUpgradeKey'] === false ) { 00290 if ( $this->getVar( 'wgUpgradeKey', false ) === false ) { 00291 $secretKey = $this->getVar( 'wgSecretKey' ); // preserve $wgSecretKey 00292 $this->parent->generateKeys(); 00293 $this->setVar( 'wgSecretKey', $secretKey ); 00294 $this->setVar( '_UpgradeKeySupplied', true ); 00295 } 00296 $this->startForm(); 00297 $this->addHTML( $this->parent->getInfoBox( 00298 wfMessage( 'config-upgrade-key-missing', "<pre dir=\"ltr\">\$wgUpgradeKey = '" . 00299 $this->getVar( 'wgUpgradeKey' ) . "';</pre>" )->plain() 00300 ) ); 00301 $this->endForm( 'continue' ); 00302 return 'output'; 00303 } 00304 00305 // If there is an upgrade key, but it wasn't supplied, prompt the user to enter it 00306 00307 $r = $this->parent->request; 00308 if ( $r->wasPosted() ) { 00309 $key = $r->getText( 'config_wgUpgradeKey' ); 00310 if( !$key || $key !== $vars['wgUpgradeKey'] ) { 00311 $this->parent->showError( 'config-localsettings-badkey' ); 00312 $this->showKeyForm(); 00313 return 'output'; 00314 } 00315 // Key was OK 00316 $status = $this->handleExistingUpgrade( $vars ); 00317 if ( $status->isOK() ) { 00318 return 'continue'; 00319 } else { 00320 $this->parent->showStatusBox( $status ); 00321 $this->showKeyForm(); 00322 return 'output'; 00323 } 00324 } else { 00325 $this->showKeyForm(); 00326 return 'output'; 00327 } 00328 } 00329 00333 protected function showKeyForm() { 00334 $this->startForm(); 00335 $this->addHTML( 00336 $this->parent->getInfoBox( wfMessage( 'config-localsettings-upgrade' )->plain() ). 00337 '<br />' . 00338 $this->parent->getTextBox( array( 00339 'var' => 'wgUpgradeKey', 00340 'label' => 'config-localsettings-key', 00341 'attribs' => array( 'autocomplete' => 'off' ), 00342 ) ) 00343 ); 00344 $this->endForm( 'continue' ); 00345 } 00346 00347 protected function importVariables( $names, $vars ) { 00348 $status = Status::newGood(); 00349 foreach ( $names as $name ) { 00350 if ( !isset( $vars[$name] ) ) { 00351 $status->fatal( 'config-localsettings-incomplete', $name ); 00352 } 00353 $this->setVar( $name, $vars[$name] ); 00354 } 00355 return $status; 00356 } 00357 00363 protected function handleExistingUpgrade( $vars ) { 00364 // Check $wgDBtype 00365 if ( !isset( $vars['wgDBtype'] ) || 00366 !in_array( $vars['wgDBtype'], Installer::getDBTypes() ) ) { 00367 return Status::newFatal( 'config-localsettings-connection-error', '' ); 00368 } 00369 00370 // Set the relevant variables from LocalSettings.php 00371 $requiredVars = array( 'wgDBtype' ); 00372 $status = $this->importVariables( $requiredVars, $vars ); 00373 $installer = $this->parent->getDBInstaller(); 00374 $status->merge( $this->importVariables( $installer->getGlobalNames(), $vars ) ); 00375 if ( !$status->isOK() ) { 00376 return $status; 00377 } 00378 00379 if ( isset( $vars['wgDBadminuser'] ) ) { 00380 $this->setVar( '_InstallUser', $vars['wgDBadminuser'] ); 00381 } else { 00382 $this->setVar( '_InstallUser', $vars['wgDBuser'] ); 00383 } 00384 if ( isset( $vars['wgDBadminpassword'] ) ) { 00385 $this->setVar( '_InstallPassword', $vars['wgDBadminpassword'] ); 00386 } else { 00387 $this->setVar( '_InstallPassword', $vars['wgDBpassword'] ); 00388 } 00389 00390 // Test the database connection 00391 $status = $installer->getConnection(); 00392 if ( !$status->isOK() ) { 00393 // Adjust the error message to explain things correctly 00394 $status->replaceMessage( 'config-connection-error', 00395 'config-localsettings-connection-error' ); 00396 return $status; 00397 } 00398 00399 // All good 00400 $this->setVar( '_ExistingDBSettings', true ); 00401 return $status; 00402 } 00403 } 00404 00405 class WebInstaller_Welcome extends WebInstallerPage { 00406 00407 public function execute() { 00408 if ( $this->parent->request->wasPosted() ) { 00409 if ( $this->getVar( '_Environment' ) ) { 00410 return 'continue'; 00411 } 00412 } 00413 $this->parent->output->addWikiText( wfMessage( 'config-welcome' )->plain() ); 00414 $status = $this->parent->doEnvironmentChecks(); 00415 if ( $status->isGood() ) { 00416 $this->parent->output->addHTML( '<span class="success-message">' . 00417 wfMessage( 'config-env-good' )->escaped() . '</span>' ); 00418 $this->parent->output->addWikiText( wfMessage( 'config-copyright', 00419 SpecialVersion::getCopyrightAndAuthorList() )->plain() ); 00420 $this->startForm(); 00421 $this->endForm(); 00422 } else { 00423 $this->parent->showStatusMessage( $status ); 00424 } 00425 return ''; 00426 } 00427 00428 } 00429 00430 class WebInstaller_DBConnect extends WebInstallerPage { 00431 00432 public function execute() { 00433 if ( $this->getVar( '_ExistingDBSettings' ) ) { 00434 return 'skip'; 00435 } 00436 00437 $r = $this->parent->request; 00438 if ( $r->wasPosted() ) { 00439 $status = $this->submit(); 00440 00441 if ( $status->isGood() ) { 00442 $this->setVar( '_UpgradeDone', false ); 00443 return 'continue'; 00444 } else { 00445 $this->parent->showStatusBox( $status ); 00446 } 00447 } 00448 00449 $this->startForm(); 00450 00451 $types = "<ul class=\"config-settings-block\">\n"; 00452 $settings = ''; 00453 $defaultType = $this->getVar( 'wgDBtype' ); 00454 00455 $dbSupport = ''; 00456 foreach( $this->parent->getDBTypes() as $type ) { 00457 $link = DatabaseBase::factory( $type )->getSoftwareLink(); 00458 $dbSupport .= wfMessage( "config-support-$type", $link )->plain() . "\n"; 00459 } 00460 $this->addHTML( $this->parent->getInfoBox( 00461 wfMessage( 'config-support-info', trim( $dbSupport ) )->text() ) ); 00462 00463 // It's possible that the library for the default DB type is not compiled in. 00464 // In that case, instead select the first supported DB type in the list. 00465 $compiledDBs = $this->parent->getCompiledDBs(); 00466 if ( !in_array( $defaultType, $compiledDBs ) ) { 00467 $defaultType = $compiledDBs[0]; 00468 } 00469 00470 foreach ( $compiledDBs as $type ) { 00471 $installer = $this->parent->getDBInstaller( $type ); 00472 $types .= 00473 '<li>' . 00474 Xml::radioLabel( 00475 $installer->getReadableName(), 00476 'DBType', 00477 $type, 00478 "DBType_$type", 00479 $type == $defaultType, 00480 array( 'class' => 'dbRadio', 'rel' => "DB_wrapper_$type" ) 00481 ) . 00482 "</li>\n"; 00483 00484 $settings .= 00485 Html::openElement( 'div', array( 'id' => 'DB_wrapper_' . $type, 00486 'class' => 'dbWrapper' ) ) . 00487 Html::element( 'h3', array(), wfMessage( 'config-header-' . $type )->text() ) . 00488 $installer->getConnectForm() . 00489 "</div>\n"; 00490 } 00491 $types .= "</ul><br style=\"clear: left\"/>\n"; 00492 00493 $this->addHTML( 00494 $this->parent->label( 'config-db-type', false, $types ) . 00495 $settings 00496 ); 00497 00498 $this->endForm(); 00499 } 00500 00501 public function submit() { 00502 $r = $this->parent->request; 00503 $type = $r->getVal( 'DBType' ); 00504 if ( !$type ) { 00505 return Status::newFatal( 'config-invalid-db-type' ); 00506 } 00507 $this->setVar( 'wgDBtype', $type ); 00508 $installer = $this->parent->getDBInstaller( $type ); 00509 if ( !$installer ) { 00510 return Status::newFatal( 'config-invalid-db-type' ); 00511 } 00512 return $installer->submitConnectForm(); 00513 } 00514 00515 } 00516 00517 class WebInstaller_Upgrade extends WebInstallerPage { 00518 public function isSlow() { 00519 return true; 00520 } 00521 00522 public function execute() { 00523 if ( $this->getVar( '_UpgradeDone' ) ) { 00524 // Allow regeneration of LocalSettings.php, unless we are working 00525 // from a pre-existing LocalSettings.php file and we want to avoid 00526 // leaking its contents 00527 if ( $this->parent->request->wasPosted() && !$this->getVar( '_ExistingDBSettings' ) ) { 00528 // Done message acknowledged 00529 return 'continue'; 00530 } else { 00531 // Back button click 00532 // Show the done message again 00533 // Make them click back again if they want to do the upgrade again 00534 $this->showDoneMessage(); 00535 return 'output'; 00536 } 00537 } 00538 00539 // wgDBtype is generally valid here because otherwise the previous page 00540 // (connect) wouldn't have declared its happiness 00541 $type = $this->getVar( 'wgDBtype' ); 00542 $installer = $this->parent->getDBInstaller( $type ); 00543 00544 if ( !$installer->needsUpgrade() ) { 00545 return 'skip'; 00546 } 00547 00548 if ( $this->parent->request->wasPosted() ) { 00549 $installer->preUpgrade(); 00550 00551 $this->startLiveBox(); 00552 $result = $installer->doUpgrade(); 00553 $this->endLiveBox(); 00554 00555 if ( $result ) { 00556 // If they're going to possibly regenerate LocalSettings, we 00557 // need to create the upgrade/secret keys. Bug 26481 00558 if( !$this->getVar( '_ExistingDBSettings' ) ) { 00559 $this->parent->generateKeys(); 00560 } 00561 $this->setVar( '_UpgradeDone', true ); 00562 $this->showDoneMessage(); 00563 return 'output'; 00564 } 00565 } 00566 00567 $this->startForm(); 00568 $this->addHTML( $this->parent->getInfoBox( 00569 wfMessage( 'config-can-upgrade', $GLOBALS['wgVersion'] )->plain() ) ); 00570 $this->endForm(); 00571 } 00572 00573 public function showDoneMessage() { 00574 $this->startForm(); 00575 $regenerate = !$this->getVar( '_ExistingDBSettings' ); 00576 if ( $regenerate ) { 00577 $msg = 'config-upgrade-done'; 00578 } else { 00579 $msg = 'config-upgrade-done-no-regenerate'; 00580 } 00581 $this->parent->disableLinkPopups(); 00582 $this->addHTML( 00583 $this->parent->getInfoBox( 00584 wfMessage( $msg, 00585 $this->getVar( 'wgServer' ) . 00586 $this->getVar( 'wgScriptPath' ) . '/index' . 00587 $this->getVar( 'wgScriptExtension' ) 00588 )->plain(), 'tick-32.png' 00589 ) 00590 ); 00591 $this->parent->restoreLinkPopups(); 00592 $this->endForm( $regenerate ? 'regenerate' : false, false ); 00593 } 00594 00595 } 00596 00597 class WebInstaller_DBSettings extends WebInstallerPage { 00598 00599 public function execute() { 00600 $installer = $this->parent->getDBInstaller( $this->getVar( 'wgDBtype' ) ); 00601 00602 $r = $this->parent->request; 00603 if ( $r->wasPosted() ) { 00604 $status = $installer->submitSettingsForm(); 00605 if ( $status === false ) { 00606 return 'skip'; 00607 } elseif ( $status->isGood() ) { 00608 return 'continue'; 00609 } else { 00610 $this->parent->showStatusBox( $status ); 00611 } 00612 } 00613 00614 $form = $installer->getSettingsForm(); 00615 if ( $form === false ) { 00616 return 'skip'; 00617 } 00618 00619 $this->startForm(); 00620 $this->addHTML( $form ); 00621 $this->endForm(); 00622 } 00623 00624 } 00625 00626 class WebInstaller_Name extends WebInstallerPage { 00627 00628 public function execute() { 00629 $r = $this->parent->request; 00630 if ( $r->wasPosted() ) { 00631 if ( $this->submit() ) { 00632 return 'continue'; 00633 } 00634 } 00635 00636 $this->startForm(); 00637 00638 // Encourage people to not name their site 'MediaWiki' by blanking the 00639 // field. I think that was the intent with the original $GLOBALS['wgSitename'] 00640 // but these two always were the same so had the effect of making the 00641 // installer forget $wgSitename when navigating back to this page. 00642 if ( $this->getVar( 'wgSitename' ) == 'MediaWiki' ) { 00643 $this->setVar( 'wgSitename', '' ); 00644 } 00645 00646 // Set wgMetaNamespace to something valid before we show the form. 00647 // $wgMetaNamespace defaults to $wgSiteName which is 'MediaWiki' 00648 $metaNS = $this->getVar( 'wgMetaNamespace' ); 00649 $this->setVar( 00650 'wgMetaNamespace', 00651 wfMessage( 'config-ns-other-default' )->inContentLanguage()->text() 00652 ); 00653 00654 $this->addHTML( 00655 $this->parent->getTextBox( array( 00656 'var' => 'wgSitename', 00657 'label' => 'config-site-name', 00658 'help' => $this->parent->getHelpBox( 'config-site-name-help' ) 00659 ) ) . 00660 $this->parent->getRadioSet( array( 00661 'var' => '_NamespaceType', 00662 'label' => 'config-project-namespace', 00663 'itemLabelPrefix' => 'config-ns-', 00664 'values' => array( 'site-name', 'generic', 'other' ), 00665 'commonAttribs' => array( 'class' => 'enableForOther', 00666 'rel' => 'config_wgMetaNamespace' ), 00667 'help' => $this->parent->getHelpBox( 'config-project-namespace-help' ) 00668 ) ) . 00669 $this->parent->getTextBox( array( 00670 'var' => 'wgMetaNamespace', 00671 'label' => '', //TODO: Needs a label? 00672 'attribs' => array( 'readonly' => 'readonly', 'class' => 'enabledByOther' ), 00673 00674 ) ) . 00675 $this->getFieldSetStart( 'config-admin-box' ) . 00676 $this->parent->getTextBox( array( 00677 'var' => '_AdminName', 00678 'label' => 'config-admin-name', 00679 'help' => $this->parent->getHelpBox( 'config-admin-help' ) 00680 ) ) . 00681 $this->parent->getPasswordBox( array( 00682 'var' => '_AdminPassword', 00683 'label' => 'config-admin-password', 00684 ) ) . 00685 $this->parent->getPasswordBox( array( 00686 'var' => '_AdminPassword2', 00687 'label' => 'config-admin-password-confirm' 00688 ) ) . 00689 $this->parent->getTextBox( array( 00690 'var' => '_AdminEmail', 00691 'label' => 'config-admin-email', 00692 'help' => $this->parent->getHelpBox( 'config-admin-email-help' ) 00693 ) ) . 00694 $this->parent->getCheckBox( array( 00695 'var' => '_Subscribe', 00696 'label' => 'config-subscribe', 00697 'help' => $this->parent->getHelpBox( 'config-subscribe-help' ) 00698 ) ) . 00699 $this->getFieldSetEnd() . 00700 $this->parent->getInfoBox( wfMessage( 'config-almost-done' )->text() ) . 00701 $this->parent->getRadioSet( array( 00702 'var' => '_SkipOptional', 00703 'itemLabelPrefix' => 'config-optional-', 00704 'values' => array( 'continue', 'skip' ) 00705 ) ) 00706 ); 00707 00708 // Restore the default value 00709 $this->setVar( 'wgMetaNamespace', $metaNS ); 00710 00711 $this->endForm(); 00712 return 'output'; 00713 } 00714 00715 public function submit() { 00716 $retVal = true; 00717 $this->parent->setVarsFromRequest( array( 'wgSitename', '_NamespaceType', 00718 '_AdminName', '_AdminPassword', '_AdminPassword2', '_AdminEmail', 00719 '_Subscribe', '_SkipOptional', 'wgMetaNamespace' ) ); 00720 00721 // Validate site name 00722 if ( strval( $this->getVar( 'wgSitename' ) ) === '' ) { 00723 $this->parent->showError( 'config-site-name-blank' ); 00724 $retVal = false; 00725 } 00726 00727 // Fetch namespace 00728 $nsType = $this->getVar( '_NamespaceType' ); 00729 if ( $nsType == 'site-name' ) { 00730 $name = $this->getVar( 'wgSitename' ); 00731 // Sanitize for namespace 00732 // This algorithm should match the JS one in WebInstallerOutput.php 00733 $name = preg_replace( '/[\[\]\{\}|#<>%+? ]/', '_', $name ); 00734 $name = str_replace( '&', '&', $name ); 00735 $name = preg_replace( '/__+/', '_', $name ); 00736 $name = ucfirst( trim( $name, '_' ) ); 00737 } elseif ( $nsType == 'generic' ) { 00738 $name = wfMessage( 'config-ns-generic' )->text(); 00739 } else { // other 00740 $name = $this->getVar( 'wgMetaNamespace' ); 00741 } 00742 00743 // Validate namespace 00744 if ( strpos( $name, ':' ) !== false ) { 00745 $good = false; 00746 } else { 00747 // Title-style validation 00748 $title = Title::newFromText( $name ); 00749 if ( !$title ) { 00750 $good = $nsType == 'site-name'; 00751 } else { 00752 $name = $title->getDBkey(); 00753 $good = true; 00754 } 00755 } 00756 if ( !$good ) { 00757 $this->parent->showError( 'config-ns-invalid', $name ); 00758 $retVal = false; 00759 } 00760 00761 // Make sure it won't conflict with any existing namespaces 00762 global $wgContLang; 00763 $nsIndex = $wgContLang->getNsIndex( $name ); 00764 if( $nsIndex !== false && $nsIndex !== NS_PROJECT ) { 00765 $this->parent->showError( 'config-ns-conflict', $name ); 00766 $retVal = false; 00767 } 00768 00769 $this->setVar( 'wgMetaNamespace', $name ); 00770 00771 // Validate username for creation 00772 $name = $this->getVar( '_AdminName' ); 00773 if ( strval( $name ) === '' ) { 00774 $this->parent->showError( 'config-admin-name-blank' ); 00775 $cname = $name; 00776 $retVal = false; 00777 } else { 00778 $cname = User::getCanonicalName( $name, 'creatable' ); 00779 if ( $cname === false ) { 00780 $this->parent->showError( 'config-admin-name-invalid', $name ); 00781 $retVal = false; 00782 } else { 00783 $this->setVar( '_AdminName', $cname ); 00784 } 00785 } 00786 00787 // Validate password 00788 $msg = false; 00789 $pwd = $this->getVar( '_AdminPassword' ); 00790 $user = User::newFromName( $cname ); 00791 $valid = $user && $user->getPasswordValidity( $pwd ); 00792 if ( strval( $pwd ) === '' ) { 00793 # $user->getPasswordValidity just checks for $wgMinimalPasswordLength. 00794 # This message is more specific and helpful. 00795 $msg = 'config-admin-password-blank'; 00796 } elseif ( $pwd !== $this->getVar( '_AdminPassword2' ) ) { 00797 $msg = 'config-admin-password-mismatch'; 00798 } elseif ( $valid !== true ) { 00799 # As of writing this will only catch the username being e.g. 'FOO' and 00800 # the password 'foo' 00801 $msg = $valid; 00802 } 00803 if ( $msg !== false ) { 00804 call_user_func_array( array( $this->parent, 'showError' ), (array)$msg ); 00805 $this->setVar( '_AdminPassword', '' ); 00806 $this->setVar( '_AdminPassword2', '' ); 00807 $retVal = false; 00808 } 00809 00810 // Validate e-mail if provided 00811 $email = $this->getVar( '_AdminEmail' ); 00812 if( $email && !Sanitizer::validateEmail( $email ) ) { 00813 $this->parent->showError( 'config-admin-error-bademail' ); 00814 $retVal = false; 00815 } 00816 // If they asked to subscribe to mediawiki-announce but didn't give 00817 // an e-mail, show an error. Bug 29332 00818 if( !$email && $this->getVar( '_Subscribe' ) ) { 00819 $this->parent->showError( 'config-subscribe-noemail' ); 00820 $retVal = false; 00821 } 00822 00823 return $retVal; 00824 } 00825 00826 } 00827 00828 class WebInstaller_Options extends WebInstallerPage { 00829 00830 public function execute() { 00831 if ( $this->getVar( '_SkipOptional' ) == 'skip' ) { 00832 return 'skip'; 00833 } 00834 if ( $this->parent->request->wasPosted() ) { 00835 if ( $this->submit() ) { 00836 return 'continue'; 00837 } 00838 } 00839 00840 $emailwrapperStyle = $this->getVar( 'wgEnableEmail' ) ? '' : 'display: none'; 00841 $this->startForm(); 00842 $this->addHTML( 00843 # User Rights 00844 $this->parent->getRadioSet( array( 00845 'var' => '_RightsProfile', 00846 'label' => 'config-profile', 00847 'itemLabelPrefix' => 'config-profile-', 00848 'values' => array_keys( $this->parent->rightsProfiles ), 00849 ) ) . 00850 $this->parent->getInfoBox( wfMessage( 'config-profile-help' )->plain() ) . 00851 00852 # Licensing 00853 $this->parent->getRadioSet( array( 00854 'var' => '_LicenseCode', 00855 'label' => 'config-license', 00856 'itemLabelPrefix' => 'config-license-', 00857 'values' => array_keys( $this->parent->licenses ), 00858 'commonAttribs' => array( 'class' => 'licenseRadio' ), 00859 ) ) . 00860 $this->getCCChooser() . 00861 $this->parent->getHelpBox( 'config-license-help' ) . 00862 00863 # E-mail 00864 $this->getFieldSetStart( 'config-email-settings' ) . 00865 $this->parent->getCheckBox( array( 00866 'var' => 'wgEnableEmail', 00867 'label' => 'config-enable-email', 00868 'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'emailwrapper' ), 00869 ) ) . 00870 $this->parent->getHelpBox( 'config-enable-email-help' ) . 00871 "<div id=\"emailwrapper\" style=\"$emailwrapperStyle\">" . 00872 $this->parent->getTextBox( array( 00873 'var' => 'wgPasswordSender', 00874 'label' => 'config-email-sender' 00875 ) ) . 00876 $this->parent->getHelpBox( 'config-email-sender-help' ) . 00877 $this->parent->getCheckBox( array( 00878 'var' => 'wgEnableUserEmail', 00879 'label' => 'config-email-user', 00880 ) ) . 00881 $this->parent->getHelpBox( 'config-email-user-help' ) . 00882 $this->parent->getCheckBox( array( 00883 'var' => 'wgEnotifUserTalk', 00884 'label' => 'config-email-usertalk', 00885 ) ) . 00886 $this->parent->getHelpBox( 'config-email-usertalk-help' ) . 00887 $this->parent->getCheckBox( array( 00888 'var' => 'wgEnotifWatchlist', 00889 'label' => 'config-email-watchlist', 00890 ) ) . 00891 $this->parent->getHelpBox( 'config-email-watchlist-help' ) . 00892 $this->parent->getCheckBox( array( 00893 'var' => 'wgEmailAuthentication', 00894 'label' => 'config-email-auth', 00895 ) ) . 00896 $this->parent->getHelpBox( 'config-email-auth-help' ) . 00897 "</div>" . 00898 $this->getFieldSetEnd() 00899 ); 00900 00901 $extensions = $this->parent->findExtensions(); 00902 00903 if( $extensions ) { 00904 $extHtml = $this->getFieldSetStart( 'config-extensions' ); 00905 00906 foreach( $extensions as $ext ) { 00907 $extHtml .= $this->parent->getCheckBox( array( 00908 'var' => "ext-$ext", 00909 'rawtext' => $ext, 00910 ) ); 00911 } 00912 00913 $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) . 00914 $this->getFieldSetEnd(); 00915 $this->addHTML( $extHtml ); 00916 } 00917 00918 // Having / in paths in Windows looks funny :) 00919 $this->setVar( 'wgDeletedDirectory', 00920 str_replace( 00921 '/', DIRECTORY_SEPARATOR, 00922 $this->getVar( 'wgDeletedDirectory' ) 00923 ) 00924 ); 00925 // If we're using the default, let the user set it relative to $wgScriptPath 00926 $curLogo = $this->getVar( 'wgLogo' ); 00927 $logoString = ( $curLogo == "/wiki/skins/common/images/wiki.png" ) ? 00928 '$wgStylePath/common/images/wiki.png' : $curLogo; 00929 00930 $uploadwrapperStyle = $this->getVar( 'wgEnableUploads' ) ? '' : 'display: none'; 00931 $this->addHTML( 00932 # Uploading 00933 $this->getFieldSetStart( 'config-upload-settings' ) . 00934 $this->parent->getCheckBox( array( 00935 'var' => 'wgEnableUploads', 00936 'label' => 'config-upload-enable', 00937 'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'uploadwrapper' ), 00938 'help' => $this->parent->getHelpBox( 'config-upload-help' ) 00939 ) ) . 00940 '<div id="uploadwrapper" style="' . $uploadwrapperStyle . '">' . 00941 $this->parent->getTextBox( array( 00942 'var' => 'wgDeletedDirectory', 00943 'label' => 'config-upload-deleted', 00944 'attribs' => array( 'dir' => 'ltr' ), 00945 'help' => $this->parent->getHelpBox( 'config-upload-deleted-help' ) 00946 ) ) . 00947 '</div>' . 00948 $this->parent->getTextBox( array( 00949 'var' => 'wgLogo', 00950 'value' => $logoString, 00951 'label' => 'config-logo', 00952 'attribs' => array( 'dir' => 'ltr' ), 00953 'help' => $this->parent->getHelpBox( 'config-logo-help' ) 00954 ) ) 00955 ); 00956 $this->addHTML( 00957 $this->parent->getCheckBox( array( 00958 'var' => 'wgUseInstantCommons', 00959 'label' => 'config-instantcommons', 00960 'help' => $this->parent->getHelpBox( 'config-instantcommons-help' ) 00961 ) ) . 00962 $this->getFieldSetEnd() 00963 ); 00964 00965 $caches = array( 'none' ); 00966 if( count( $this->getVar( '_Caches' ) ) ) { 00967 $caches[] = 'accel'; 00968 } 00969 $caches[] = 'memcached'; 00970 00971 // We'll hide/show this on demand when the value changes, see config.js. 00972 $cacheval = $this->getVar( 'wgMainCacheType' ); 00973 if ( !$cacheval ) { 00974 // We need to set a default here; but don't hardcode it 00975 // or we lose it every time we reload the page for validation 00976 // or going back! 00977 $cacheval = 'none'; 00978 } 00979 $hidden = ($cacheval == 'memcached') ? '' : 'display: none'; 00980 $this->addHTML( 00981 # Advanced settings 00982 $this->getFieldSetStart( 'config-advanced-settings' ) . 00983 # Object cache settings 00984 $this->parent->getRadioSet( array( 00985 'var' => 'wgMainCacheType', 00986 'label' => 'config-cache-options', 00987 'itemLabelPrefix' => 'config-cache-', 00988 'values' => $caches, 00989 'value' => $cacheval, 00990 ) ) . 00991 $this->parent->getHelpBox( 'config-cache-help' ) . 00992 "<div id=\"config-memcachewrapper\" style=\"$hidden\">" . 00993 $this->parent->getTextArea( array( 00994 'var' => '_MemCachedServers', 00995 'label' => 'config-memcached-servers', 00996 'help' => $this->parent->getHelpBox( 'config-memcached-help' ) 00997 ) ) . 00998 '</div>' . 00999 $this->getFieldSetEnd() 01000 ); 01001 $this->endForm(); 01002 } 01003 01007 public function getCCPartnerUrl() { 01008 $server = $this->getVar( 'wgServer' ); 01009 $exitUrl = $server . $this->parent->getUrl( array( 01010 'page' => 'Options', 01011 'SubmitCC' => 'indeed', 01012 'config__LicenseCode' => 'cc', 01013 'config_wgRightsUrl' => '[license_url]', 01014 'config_wgRightsText' => '[license_name]', 01015 'config_wgRightsIcon' => '[license_button]', 01016 ) ); 01017 $styleUrl = $server . dirname( dirname( $this->parent->getUrl() ) ) . 01018 '/skins/common/config-cc.css'; 01019 $iframeUrl = 'http://creativecommons.org/license/?' . 01020 wfArrayToCgi( array( 01021 'partner' => 'MediaWiki', 01022 'exit_url' => $exitUrl, 01023 'lang' => $this->getVar( '_UserLang' ), 01024 'stylesheet' => $styleUrl, 01025 ) ); 01026 return $iframeUrl; 01027 } 01028 01029 public function getCCChooser() { 01030 $iframeAttribs = array( 01031 'class' => 'config-cc-iframe', 01032 'name' => 'config-cc-iframe', 01033 'id' => 'config-cc-iframe', 01034 'frameborder' => 0, 01035 'width' => '100%', 01036 'height' => '100%', 01037 ); 01038 if ( $this->getVar( '_CCDone' ) ) { 01039 $iframeAttribs['src'] = $this->parent->getUrl( array( 'ShowCC' => 'yes' ) ); 01040 } else { 01041 $iframeAttribs['src'] = $this->getCCPartnerUrl(); 01042 } 01043 $wrapperStyle = ($this->getVar( '_LicenseCode' ) == 'cc-choose') ? '' : 'display: none'; 01044 01045 return 01046 "<div class=\"config-cc-wrapper\" id=\"config-cc-wrapper\" style=\"$wrapperStyle\">\n" . 01047 Html::element( 'iframe', $iframeAttribs, '', false /* not short */ ) . 01048 "</div>\n"; 01049 } 01050 01051 public function getCCDoneBox() { 01052 $js = "parent.document.getElementById('config-cc-wrapper').style.height = '$1';"; 01053 // If you change this height, also change it in config.css 01054 $expandJs = str_replace( '$1', '54em', $js ); 01055 $reduceJs = str_replace( '$1', '70px', $js ); 01056 return 01057 '<p>'. 01058 Html::element( 'img', array( 'src' => $this->getVar( 'wgRightsIcon' ) ) ) . 01059 '  ' . 01060 htmlspecialchars( $this->getVar( 'wgRightsText' ) ) . 01061 "</p>\n" . 01062 "<p style=\"text-align: center\">" . 01063 Html::element( 'a', 01064 array( 01065 'href' => $this->getCCPartnerUrl(), 01066 'onclick' => $expandJs, 01067 ), 01068 wfMessage( 'config-cc-again' )->text() 01069 ) . 01070 "</p>\n" . 01071 "<script type=\"text/javascript\">\n" . 01072 # Reduce the wrapper div height 01073 htmlspecialchars( $reduceJs ) . 01074 "\n" . 01075 "</script>\n"; 01076 } 01077 01078 public function submitCC() { 01079 $newValues = $this->parent->setVarsFromRequest( 01080 array( 'wgRightsUrl', 'wgRightsText', 'wgRightsIcon' ) ); 01081 if ( count( $newValues ) != 3 ) { 01082 $this->parent->showError( 'config-cc-error' ); 01083 return; 01084 } 01085 $this->setVar( '_CCDone', true ); 01086 $this->addHTML( $this->getCCDoneBox() ); 01087 } 01088 01089 public function submit() { 01090 $this->parent->setVarsFromRequest( array( '_RightsProfile', '_LicenseCode', 01091 'wgEnableEmail', 'wgPasswordSender', 'wgEnableUploads', 'wgLogo', 01092 'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist', 01093 'wgEmailAuthentication', 'wgMainCacheType', '_MemCachedServers', 01094 'wgUseInstantCommons' ) ); 01095 01096 if ( !in_array( $this->getVar( '_RightsProfile' ), 01097 array_keys( $this->parent->rightsProfiles ) ) ) 01098 { 01099 reset( $this->parent->rightsProfiles ); 01100 $this->setVar( '_RightsProfile', key( $this->parent->rightsProfiles ) ); 01101 } 01102 01103 $code = $this->getVar( '_LicenseCode' ); 01104 if ( $code == 'cc-choose' ) { 01105 if ( !$this->getVar( '_CCDone' ) ) { 01106 $this->parent->showError( 'config-cc-not-chosen' ); 01107 return false; 01108 } 01109 } elseif ( in_array( $code, array_keys( $this->parent->licenses ) ) ) { 01110 $entry = $this->parent->licenses[$code]; 01111 if ( isset( $entry['text'] ) ) { 01112 $this->setVar( 'wgRightsText', $entry['text'] ); 01113 } else { 01114 $this->setVar( 'wgRightsText', wfMessage( 'config-license-' . $code )->text() ); 01115 } 01116 $this->setVar( 'wgRightsUrl', $entry['url'] ); 01117 $this->setVar( 'wgRightsIcon', $entry['icon'] ); 01118 } else { 01119 $this->setVar( 'wgRightsText', '' ); 01120 $this->setVar( 'wgRightsUrl', '' ); 01121 $this->setVar( 'wgRightsIcon', '' ); 01122 } 01123 01124 $extsAvailable = $this->parent->findExtensions(); 01125 $extsToInstall = array(); 01126 foreach( $extsAvailable as $ext ) { 01127 if( $this->parent->request->getCheck( 'config_ext-' . $ext ) ) { 01128 $extsToInstall[] = $ext; 01129 } 01130 } 01131 $this->parent->setVar( '_Extensions', $extsToInstall ); 01132 01133 if( $this->getVar( 'wgMainCacheType' ) == 'memcached' ) { 01134 $memcServers = explode( "\n", $this->getVar( '_MemCachedServers' ) ); 01135 if( !$memcServers ) { 01136 $this->parent->showError( 'config-memcache-needservers' ); 01137 return false; 01138 } 01139 01140 foreach( $memcServers as $server ) { 01141 $memcParts = explode( ":", $server, 2 ); 01142 if ( !isset( $memcParts[0] ) 01143 || ( !IP::isValid( $memcParts[0] ) 01144 && ( gethostbyname( $memcParts[0] ) == $memcParts[0] ) ) ) { 01145 $this->parent->showError( 'config-memcache-badip', $memcParts[0] ); 01146 return false; 01147 } elseif( !isset( $memcParts[1] ) ) { 01148 $this->parent->showError( 'config-memcache-noport', $memcParts[0] ); 01149 return false; 01150 } elseif( $memcParts[1] < 1 || $memcParts[1] > 65535 ) { 01151 $this->parent->showError( 'config-memcache-badport', 1, 65535 ); 01152 return false; 01153 } 01154 } 01155 } 01156 return true; 01157 } 01158 01159 } 01160 01161 class WebInstaller_Install extends WebInstallerPage { 01162 public function isSlow() { 01163 return true; 01164 } 01165 01166 public function execute() { 01167 if( $this->getVar( '_UpgradeDone' ) ) { 01168 return 'skip'; 01169 } elseif( $this->getVar( '_InstallDone' ) ) { 01170 return 'continue'; 01171 } elseif( $this->parent->request->wasPosted() ) { 01172 $this->startForm(); 01173 $this->addHTML( "<ul>" ); 01174 $results = $this->parent->performInstallation( 01175 array( $this, 'startStage' ), 01176 array( $this, 'endStage' ) 01177 ); 01178 $this->addHTML( "</ul>" ); 01179 // PerformInstallation bails on a fatal, so make sure the last item 01180 // completed before giving 'next.' Likewise, only provide back on failure 01181 $lastStep = end( $results ); 01182 $continue = $lastStep->isOK() ? 'continue' : false; 01183 $back = $lastStep->isOK() ? false : 'back'; 01184 $this->endForm( $continue, $back ); 01185 } else { 01186 $this->startForm(); 01187 $this->addHTML( $this->parent->getInfoBox( wfMessage( 'config-install-begin' )->plain() ) ); 01188 $this->endForm(); 01189 } 01190 return true; 01191 } 01192 01193 public function startStage( $step ) { 01194 $this->addHTML( "<li>" . wfMessage( "config-install-$step" )->escaped() . wfMessage( 'ellipsis' )->escaped() ); 01195 if ( $step == 'extension-tables' ) { 01196 $this->startLiveBox(); 01197 } 01198 } 01199 01204 public function endStage( $step, $status ) { 01205 if ( $step == 'extension-tables' ) { 01206 $this->endLiveBox(); 01207 } 01208 $msg = $status->isOk() ? 'config-install-step-done' : 'config-install-step-failed'; 01209 $html = wfMessage( 'word-separator' )->escaped() . wfMessage( $msg )->escaped(); 01210 if ( !$status->isOk() ) { 01211 $html = "<span class=\"error\">$html</span>"; 01212 } 01213 $this->addHTML( $html . "</li>\n" ); 01214 if( !$status->isGood() ) { 01215 $this->parent->showStatusBox( $status ); 01216 } 01217 } 01218 01219 } 01220 01221 class WebInstaller_Complete extends WebInstallerPage { 01222 01223 public function execute() { 01224 // Pop up a dialog box, to make it difficult for the user to forget 01225 // to download the file 01226 $lsUrl = $this->getVar( 'wgServer' ) . $this->parent->getURL( array( 'localsettings' => 1 ) ); 01227 if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && 01228 strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE' ) !== false ) { 01229 // JS appears the only method that works consistently with IE7+ 01230 $this->addHtml( "\n<script type=\"" . $GLOBALS['wgJsMimeType'] . 01231 '">jQuery( document ).ready( function() { document.location=' . 01232 Xml::encodeJsVar( $lsUrl) . "; } );</script>\n" ); 01233 } else { 01234 $this->parent->request->response()->header( "Refresh: 0;url=$lsUrl" ); 01235 } 01236 01237 $this->startForm(); 01238 $this->parent->disableLinkPopups(); 01239 $this->addHTML( 01240 $this->parent->getInfoBox( 01241 wfMessage( 'config-install-done', 01242 $lsUrl, 01243 $this->getVar( 'wgServer' ) . 01244 $this->getVar( 'wgScriptPath' ) . '/index' . 01245 $this->getVar( 'wgScriptExtension' ), 01246 '<downloadlink/>' 01247 )->plain(), 'tick-32.png' 01248 ) 01249 ); 01250 $this->parent->restoreLinkPopups(); 01251 $this->endForm( false, false ); 01252 } 01253 } 01254 01255 class WebInstaller_Restart extends WebInstallerPage { 01256 01257 public function execute() { 01258 $r = $this->parent->request; 01259 if ( $r->wasPosted() ) { 01260 $really = $r->getVal( 'submit-restart' ); 01261 if ( $really ) { 01262 $this->parent->reset(); 01263 } 01264 return 'continue'; 01265 } 01266 01267 $this->startForm(); 01268 $s = $this->parent->getWarningBox( wfMessage( 'config-help-restart' )->plain() ); 01269 $this->addHTML( $s ); 01270 $this->endForm( 'restart' ); 01271 } 01272 01273 } 01274 01275 abstract class WebInstaller_Document extends WebInstallerPage { 01276 01277 abstract protected function getFileName(); 01278 01279 public function execute() { 01280 $text = $this->getFileContents(); 01281 $text = InstallDocFormatter::format( $text ); 01282 $this->parent->output->addWikiText( $text ); 01283 $this->startForm(); 01284 $this->endForm( false ); 01285 } 01286 01287 public function getFileContents() { 01288 $file = __DIR__ . '/../../' . $this->getFileName(); 01289 if( ! file_exists( $file ) ) { 01290 return wfMessage( 'config-nofile', $file )->plain(); 01291 } 01292 return file_get_contents( $file ); 01293 } 01294 01295 } 01296 01297 class WebInstaller_Readme extends WebInstaller_Document { 01298 protected function getFileName() { return 'README'; } 01299 } 01300 01301 class WebInstaller_ReleaseNotes extends WebInstaller_Document { 01302 protected function getFileName() { 01303 global $wgVersion; 01304 01305 if( !preg_match( '/^(\d+)\.(\d+).*/i', $wgVersion, $result ) ) { 01306 throw new MWException( 'Variable $wgVersion has an invalid value.' ); 01307 } 01308 01309 return 'RELEASE-NOTES-' . $result[1] . '.' . $result[2]; 01310 } 01311 } 01312 01313 class WebInstaller_UpgradeDoc extends WebInstaller_Document { 01314 protected function getFileName() { return 'UPGRADE'; } 01315 } 01316 01317 class WebInstaller_Copying extends WebInstaller_Document { 01318 protected function getFileName() { return 'COPYING'; } 01319 }