[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Base code for web installer pages. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup Deployment 22 */ 23 24 /** 25 * Abstract class to define pages for the web installer. 26 * 27 * @ingroup Deployment 28 * @since 1.17 29 */ 30 abstract class WebInstallerPage { 31 32 /** 33 * The WebInstaller object this WebInstallerPage belongs to. 34 * 35 * @var WebInstaller 36 */ 37 public $parent; 38 39 /** 40 * @return string 41 */ 42 abstract public function execute(); 43 44 /** 45 * @param WebInstaller $parent 46 */ 47 public function __construct( WebInstaller $parent ) { 48 $this->parent = $parent; 49 } 50 51 /** 52 * Is this a slow-running page in the installer? If so, WebInstaller will 53 * set_time_limit(0) before calling execute(). Right now this only applies 54 * to Install and Upgrade pages 55 * 56 * @return bool Always false in this default implementation. 57 */ 58 public function isSlow() { 59 return false; 60 } 61 62 /** 63 * @param string $html 64 */ 65 public function addHTML( $html ) { 66 $this->parent->output->addHTML( $html ); 67 } 68 69 public function startForm() { 70 $this->addHTML( 71 "<div class=\"config-section\">\n" . 72 Html::openElement( 73 'form', 74 array( 75 'method' => 'post', 76 'action' => $this->parent->getUrl( array( 'page' => $this->getName() ) ) 77 ) 78 ) . "\n" 79 ); 80 } 81 82 /** 83 * @param string|bool $continue 84 * @param string|bool $back 85 */ 86 public function endForm( $continue = 'continue', $back = 'back' ) { 87 $s = "<div class=\"config-submit\">\n"; 88 $id = $this->getId(); 89 90 if ( $id === false ) { 91 $s .= Html::hidden( 'lastPage', $this->parent->request->getVal( 'lastPage' ) ); 92 } 93 94 if ( $continue ) { 95 // Fake submit button for enter keypress (bug 26267) 96 // Messages: config-continue, config-restart, config-regenerate 97 $s .= Xml::submitButton( 98 wfMessage( "config-$continue" )->text(), 99 array( 100 'name' => "enter-$continue", 101 'style' => 'visibility:hidden;overflow:hidden;width:1px;margin:0' 102 ) 103 ) . "\n"; 104 } 105 106 if ( $back ) { 107 // Message: config-back 108 $s .= Xml::submitButton( 109 wfMessage( "config-$back" )->text(), 110 array( 111 'name' => "submit-$back", 112 'tabindex' => $this->parent->nextTabIndex() 113 ) 114 ) . "\n"; 115 } 116 117 if ( $continue ) { 118 // Messages: config-continue, config-restart, config-regenerate 119 $s .= Xml::submitButton( 120 wfMessage( "config-$continue" )->text(), 121 array( 122 'name' => "submit-$continue", 123 'tabindex' => $this->parent->nextTabIndex(), 124 ) 125 ) . "\n"; 126 } 127 128 $s .= "</div></form></div>\n"; 129 $this->addHTML( $s ); 130 } 131 132 /** 133 * @return string 134 */ 135 public function getName() { 136 return str_replace( 'WebInstaller', '', get_class( $this ) ); 137 } 138 139 /** 140 * @return string 141 */ 142 protected function getId() { 143 return array_search( $this->getName(), $this->parent->pageSequence ); 144 } 145 146 /** 147 * @param string $var 148 * @param mixed $default 149 * 150 * @return mixed 151 */ 152 public function getVar( $var, $default = null ) { 153 return $this->parent->getVar( $var, $default ); 154 } 155 156 /** 157 * @param string $name 158 * @param mixed $value 159 */ 160 public function setVar( $name, $value ) { 161 $this->parent->setVar( $name, $value ); 162 } 163 164 /** 165 * Get the starting tags of a fieldset. 166 * 167 * @param string $legend Message name 168 * 169 * @return string 170 */ 171 protected function getFieldsetStart( $legend ) { 172 return "\n<fieldset><legend>" . wfMessage( $legend )->escaped() . "</legend>\n"; 173 } 174 175 /** 176 * Get the end tag of a fieldset. 177 * 178 * @return string 179 */ 180 protected function getFieldsetEnd() { 181 return "</fieldset>\n"; 182 } 183 184 /** 185 * Opens a textarea used to display the progress of a long operation 186 */ 187 protected function startLiveBox() { 188 $this->addHTML( 189 '<div id="config-spinner" style="display:none;">' . 190 '<img src="images/ajax-loader.gif" /></div>' . 191 '<script>jQuery( "#config-spinner" ).show();</script>' . 192 '<div id="config-live-log">' . 193 '<textarea name="LiveLog" rows="10" cols="30" readonly="readonly">' 194 ); 195 $this->parent->output->flush(); 196 } 197 198 /** 199 * Opposite to WebInstallerPage::startLiveBox 200 */ 201 protected function endLiveBox() { 202 $this->addHTML( '</textarea></div> 203 <script>jQuery( "#config-spinner" ).hide()</script>' ); 204 $this->parent->output->flush(); 205 } 206 207 } 208 209 class WebInstallerLanguage extends WebInstallerPage { 210 211 /** 212 * @return string|null 213 */ 214 public function execute() { 215 global $wgLang; 216 $r = $this->parent->request; 217 $userLang = $r->getVal( 'uselang' ); 218 $contLang = $r->getVal( 'ContLang' ); 219 220 $languages = Language::fetchLanguageNames(); 221 $lifetime = intval( ini_get( 'session.gc_maxlifetime' ) ); 222 if ( !$lifetime ) { 223 $lifetime = 1440; // PHP default 224 } 225 226 if ( $r->wasPosted() ) { 227 # Do session test 228 if ( $this->parent->getSession( 'test' ) === null ) { 229 $requestTime = $r->getVal( 'LanguageRequestTime' ); 230 if ( !$requestTime ) { 231 // The most likely explanation is that the user was knocked back 232 // from another page on POST due to session expiry 233 $msg = 'config-session-expired'; 234 } elseif ( time() - $requestTime > $lifetime ) { 235 $msg = 'config-session-expired'; 236 } else { 237 $msg = 'config-no-session'; 238 } 239 $this->parent->showError( $msg, $wgLang->formatTimePeriod( $lifetime ) ); 240 } else { 241 if ( isset( $languages[$userLang] ) ) { 242 $this->setVar( '_UserLang', $userLang ); 243 } 244 if ( isset( $languages[$contLang] ) ) { 245 $this->setVar( 'wgLanguageCode', $contLang ); 246 } 247 248 return 'continue'; 249 } 250 } elseif ( $this->parent->showSessionWarning ) { 251 # The user was knocked back from another page to the start 252 # This probably indicates a session expiry 253 $this->parent->showError( 'config-session-expired', 254 $wgLang->formatTimePeriod( $lifetime ) ); 255 } 256 257 $this->parent->setSession( 'test', true ); 258 259 if ( !isset( $languages[$userLang] ) ) { 260 $userLang = $this->getVar( '_UserLang', 'en' ); 261 } 262 if ( !isset( $languages[$contLang] ) ) { 263 $contLang = $this->getVar( 'wgLanguageCode', 'en' ); 264 } 265 $this->startForm(); 266 $s = Html::hidden( 'LanguageRequestTime', time() ) . 267 $this->getLanguageSelector( 'uselang', 'config-your-language', $userLang, 268 $this->parent->getHelpBox( 'config-your-language-help' ) ) . 269 $this->getLanguageSelector( 'ContLang', 'config-wiki-language', $contLang, 270 $this->parent->getHelpBox( 'config-wiki-language-help' ) ); 271 $this->addHTML( $s ); 272 $this->endForm( 'continue', false ); 273 274 return null; 275 } 276 277 /** 278 * Get a "<select>" for selecting languages. 279 * 280 * @param string $name 281 * @param string $label 282 * @param string $selectedCode 283 * @param string $helpHtml 284 * 285 * @return string 286 */ 287 public function getLanguageSelector( $name, $label, $selectedCode, $helpHtml = '' ) { 288 global $wgDummyLanguageCodes; 289 290 $s = $helpHtml; 291 292 $s .= Html::openElement( 'select', array( 'id' => $name, 'name' => $name, 293 'tabindex' => $this->parent->nextTabIndex() ) ) . "\n"; 294 295 $languages = Language::fetchLanguageNames(); 296 ksort( $languages ); 297 foreach ( $languages as $code => $lang ) { 298 if ( isset( $wgDummyLanguageCodes[$code] ) ) { 299 continue; 300 } 301 $s .= "\n" . Xml::option( "$code - $lang", $code, $code == $selectedCode ); 302 } 303 $s .= "\n</select>\n"; 304 305 return $this->parent->label( $label, $name, $s ); 306 } 307 308 } 309 310 class WebInstallerExistingWiki extends WebInstallerPage { 311 312 /** 313 * @return string 314 */ 315 public function execute() { 316 // If there is no LocalSettings.php, continue to the installer welcome page 317 $vars = Installer::getExistingLocalSettings(); 318 if ( !$vars ) { 319 return 'skip'; 320 } 321 322 // Check if the upgrade key supplied to the user has appeared in LocalSettings.php 323 if ( $vars['wgUpgradeKey'] !== false 324 && $this->getVar( '_UpgradeKeySupplied' ) 325 && $this->getVar( 'wgUpgradeKey' ) === $vars['wgUpgradeKey'] 326 ) { 327 // It's there, so the user is authorized 328 $status = $this->handleExistingUpgrade( $vars ); 329 if ( $status->isOK() ) { 330 return 'skip'; 331 } else { 332 $this->startForm(); 333 $this->parent->showStatusBox( $status ); 334 $this->endForm( 'continue' ); 335 336 return 'output'; 337 } 338 } 339 340 // If there is no $wgUpgradeKey, tell the user to add one to LocalSettings.php 341 if ( $vars['wgUpgradeKey'] === false ) { 342 if ( $this->getVar( 'wgUpgradeKey', false ) === false ) { 343 $secretKey = $this->getVar( 'wgSecretKey' ); // preserve $wgSecretKey 344 $this->parent->generateKeys(); 345 $this->setVar( 'wgSecretKey', $secretKey ); 346 $this->setVar( '_UpgradeKeySupplied', true ); 347 } 348 $this->startForm(); 349 $this->addHTML( $this->parent->getInfoBox( 350 wfMessage( 'config-upgrade-key-missing', "<pre dir=\"ltr\">\$wgUpgradeKey = '" . 351 $this->getVar( 'wgUpgradeKey' ) . "';</pre>" )->plain() 352 ) ); 353 $this->endForm( 'continue' ); 354 355 return 'output'; 356 } 357 358 // If there is an upgrade key, but it wasn't supplied, prompt the user to enter it 359 360 $r = $this->parent->request; 361 if ( $r->wasPosted() ) { 362 $key = $r->getText( 'config_wgUpgradeKey' ); 363 if ( !$key || $key !== $vars['wgUpgradeKey'] ) { 364 $this->parent->showError( 'config-localsettings-badkey' ); 365 $this->showKeyForm(); 366 367 return 'output'; 368 } 369 // Key was OK 370 $status = $this->handleExistingUpgrade( $vars ); 371 if ( $status->isOK() ) { 372 return 'continue'; 373 } else { 374 $this->parent->showStatusBox( $status ); 375 $this->showKeyForm(); 376 377 return 'output'; 378 } 379 } else { 380 $this->showKeyForm(); 381 382 return 'output'; 383 } 384 } 385 386 /** 387 * Show the "enter key" form 388 */ 389 protected function showKeyForm() { 390 $this->startForm(); 391 $this->addHTML( 392 $this->parent->getInfoBox( wfMessage( 'config-localsettings-upgrade' )->plain() ) . 393 '<br />' . 394 $this->parent->getTextBox( array( 395 'var' => 'wgUpgradeKey', 396 'label' => 'config-localsettings-key', 397 'attribs' => array( 'autocomplete' => 'off' ), 398 ) ) 399 ); 400 $this->endForm( 'continue' ); 401 } 402 403 /** 404 * @param string[] $names 405 * @param mixed[] $vars 406 * 407 * @return Status 408 */ 409 protected function importVariables( $names, $vars ) { 410 $status = Status::newGood(); 411 foreach ( $names as $name ) { 412 if ( !isset( $vars[$name] ) ) { 413 $status->fatal( 'config-localsettings-incomplete', $name ); 414 } 415 $this->setVar( $name, $vars[$name] ); 416 } 417 418 return $status; 419 } 420 421 /** 422 * Initiate an upgrade of the existing database 423 * 424 * @param mixed[] $vars Variables from LocalSettings.php 425 * 426 * @return Status 427 */ 428 protected function handleExistingUpgrade( $vars ) { 429 // Check $wgDBtype 430 if ( !isset( $vars['wgDBtype'] ) || 431 !in_array( $vars['wgDBtype'], Installer::getDBTypes() ) 432 ) { 433 return Status::newFatal( 'config-localsettings-connection-error', '' ); 434 } 435 436 // Set the relevant variables from LocalSettings.php 437 $requiredVars = array( 'wgDBtype' ); 438 $status = $this->importVariables( $requiredVars, $vars ); 439 $installer = $this->parent->getDBInstaller(); 440 $status->merge( $this->importVariables( $installer->getGlobalNames(), $vars ) ); 441 if ( !$status->isOK() ) { 442 return $status; 443 } 444 445 if ( isset( $vars['wgDBadminuser'] ) ) { 446 $this->setVar( '_InstallUser', $vars['wgDBadminuser'] ); 447 } else { 448 $this->setVar( '_InstallUser', $vars['wgDBuser'] ); 449 } 450 if ( isset( $vars['wgDBadminpassword'] ) ) { 451 $this->setVar( '_InstallPassword', $vars['wgDBadminpassword'] ); 452 } else { 453 $this->setVar( '_InstallPassword', $vars['wgDBpassword'] ); 454 } 455 456 // Test the database connection 457 $status = $installer->getConnection(); 458 if ( !$status->isOK() ) { 459 // Adjust the error message to explain things correctly 460 $status->replaceMessage( 'config-connection-error', 461 'config-localsettings-connection-error' ); 462 463 return $status; 464 } 465 466 // All good 467 $this->setVar( '_ExistingDBSettings', true ); 468 469 return $status; 470 } 471 472 } 473 474 class WebInstallerWelcome extends WebInstallerPage { 475 476 /** 477 * @return string 478 */ 479 public function execute() { 480 if ( $this->parent->request->wasPosted() ) { 481 if ( $this->getVar( '_Environment' ) ) { 482 return 'continue'; 483 } 484 } 485 $this->parent->output->addWikiText( wfMessage( 'config-welcome' )->plain() ); 486 $status = $this->parent->doEnvironmentChecks(); 487 if ( $status->isGood() ) { 488 $this->parent->output->addHTML( '<span class="success-message">' . 489 wfMessage( 'config-env-good' )->escaped() . '</span>' ); 490 $this->parent->output->addWikiText( wfMessage( 'config-copyright', 491 SpecialVersion::getCopyrightAndAuthorList() )->plain() ); 492 $this->startForm(); 493 $this->endForm(); 494 } else { 495 $this->parent->showStatusMessage( $status ); 496 } 497 498 return ''; 499 } 500 501 } 502 503 class WebInstallerDBConnect extends WebInstallerPage { 504 505 /** 506 * @return string|null When string, "skip" or "continue" 507 */ 508 public function execute() { 509 if ( $this->getVar( '_ExistingDBSettings' ) ) { 510 return 'skip'; 511 } 512 513 $r = $this->parent->request; 514 if ( $r->wasPosted() ) { 515 $status = $this->submit(); 516 517 if ( $status->isGood() ) { 518 $this->setVar( '_UpgradeDone', false ); 519 520 return 'continue'; 521 } else { 522 $this->parent->showStatusBox( $status ); 523 } 524 } 525 526 $this->startForm(); 527 528 $types = "<ul class=\"config-settings-block\">\n"; 529 $settings = ''; 530 $defaultType = $this->getVar( 'wgDBtype' ); 531 532 // Messages: config-dbsupport-mysql, config-dbsupport-postgres, config-dbsupport-oracle, 533 // config-dbsupport-sqlite, config-dbsupport-mssql 534 $dbSupport = ''; 535 foreach ( Installer::getDBTypes() as $type ) { 536 $dbSupport .= wfMessage( "config-dbsupport-$type" )->plain() . "\n"; 537 } 538 $this->addHTML( $this->parent->getInfoBox( 539 wfMessage( 'config-support-info', trim( $dbSupport ) )->text() ) ); 540 541 // It's possible that the library for the default DB type is not compiled in. 542 // In that case, instead select the first supported DB type in the list. 543 $compiledDBs = $this->parent->getCompiledDBs(); 544 if ( !in_array( $defaultType, $compiledDBs ) ) { 545 $defaultType = $compiledDBs[0]; 546 } 547 548 foreach ( $compiledDBs as $type ) { 549 $installer = $this->parent->getDBInstaller( $type ); 550 $types .= 551 '<li>' . 552 Xml::radioLabel( 553 $installer->getReadableName(), 554 'DBType', 555 $type, 556 "DBType_$type", 557 $type == $defaultType, 558 array( 'class' => 'dbRadio', 'rel' => "DB_wrapper_$type" ) 559 ) . 560 "</li>\n"; 561 562 // Messages: config-header-mysql, config-header-postgres, config-header-oracle, 563 // config-header-sqlite 564 $settings .= Html::openElement( 565 'div', 566 array( 567 'id' => 'DB_wrapper_' . $type, 568 'class' => 'dbWrapper' 569 ) 570 ) . 571 Html::element( 'h3', array(), wfMessage( 'config-header-' . $type )->text() ) . 572 $installer->getConnectForm() . 573 "</div>\n"; 574 } 575 576 $types .= "</ul><br style=\"clear: left\"/>\n"; 577 578 $this->addHTML( $this->parent->label( 'config-db-type', false, $types ) . $settings ); 579 $this->endForm(); 580 581 return null; 582 } 583 584 /** 585 * @return Status 586 */ 587 public function submit() { 588 $r = $this->parent->request; 589 $type = $r->getVal( 'DBType' ); 590 if ( !$type ) { 591 return Status::newFatal( 'config-invalid-db-type' ); 592 } 593 $this->setVar( 'wgDBtype', $type ); 594 $installer = $this->parent->getDBInstaller( $type ); 595 if ( !$installer ) { 596 return Status::newFatal( 'config-invalid-db-type' ); 597 } 598 599 return $installer->submitConnectForm(); 600 } 601 602 } 603 604 class WebInstallerUpgrade extends WebInstallerPage { 605 606 /** 607 * @return bool Always true. 608 */ 609 public function isSlow() { 610 return true; 611 } 612 613 /** 614 * @return string|null 615 */ 616 public function execute() { 617 if ( $this->getVar( '_UpgradeDone' ) ) { 618 // Allow regeneration of LocalSettings.php, unless we are working 619 // from a pre-existing LocalSettings.php file and we want to avoid 620 // leaking its contents 621 if ( $this->parent->request->wasPosted() && !$this->getVar( '_ExistingDBSettings' ) ) { 622 // Done message acknowledged 623 return 'continue'; 624 } else { 625 // Back button click 626 // Show the done message again 627 // Make them click back again if they want to do the upgrade again 628 $this->showDoneMessage(); 629 630 return 'output'; 631 } 632 } 633 634 // wgDBtype is generally valid here because otherwise the previous page 635 // (connect) wouldn't have declared its happiness 636 $type = $this->getVar( 'wgDBtype' ); 637 $installer = $this->parent->getDBInstaller( $type ); 638 639 if ( !$installer->needsUpgrade() ) { 640 return 'skip'; 641 } 642 643 if ( $this->parent->request->wasPosted() ) { 644 $installer->preUpgrade(); 645 646 $this->startLiveBox(); 647 $result = $installer->doUpgrade(); 648 $this->endLiveBox(); 649 650 if ( $result ) { 651 // If they're going to possibly regenerate LocalSettings, we 652 // need to create the upgrade/secret keys. Bug 26481 653 if ( !$this->getVar( '_ExistingDBSettings' ) ) { 654 $this->parent->generateKeys(); 655 } 656 $this->setVar( '_UpgradeDone', true ); 657 $this->showDoneMessage(); 658 659 return 'output'; 660 } 661 } 662 663 $this->startForm(); 664 $this->addHTML( $this->parent->getInfoBox( 665 wfMessage( 'config-can-upgrade', $GLOBALS['wgVersion'] )->plain() ) ); 666 $this->endForm(); 667 668 return null; 669 } 670 671 public function showDoneMessage() { 672 $this->startForm(); 673 $regenerate = !$this->getVar( '_ExistingDBSettings' ); 674 if ( $regenerate ) { 675 $msg = 'config-upgrade-done'; 676 } else { 677 $msg = 'config-upgrade-done-no-regenerate'; 678 } 679 $this->parent->disableLinkPopups(); 680 $this->addHTML( 681 $this->parent->getInfoBox( 682 wfMessage( $msg, 683 $this->getVar( 'wgServer' ) . 684 $this->getVar( 'wgScriptPath' ) . '/index' . 685 $this->getVar( 'wgScriptExtension' ) 686 )->plain(), 'tick-32.png' 687 ) 688 ); 689 $this->parent->restoreLinkPopups(); 690 $this->endForm( $regenerate ? 'regenerate' : false, false ); 691 } 692 693 } 694 695 class WebInstallerDBSettings extends WebInstallerPage { 696 697 /** 698 * @return string|null 699 */ 700 public function execute() { 701 $installer = $this->parent->getDBInstaller( $this->getVar( 'wgDBtype' ) ); 702 703 $r = $this->parent->request; 704 if ( $r->wasPosted() ) { 705 $status = $installer->submitSettingsForm(); 706 if ( $status === false ) { 707 return 'skip'; 708 } elseif ( $status->isGood() ) { 709 return 'continue'; 710 } else { 711 $this->parent->showStatusBox( $status ); 712 } 713 } 714 715 $form = $installer->getSettingsForm(); 716 if ( $form === false ) { 717 return 'skip'; 718 } 719 720 $this->startForm(); 721 $this->addHTML( $form ); 722 $this->endForm(); 723 724 return null; 725 } 726 727 } 728 729 class WebInstallerName extends WebInstallerPage { 730 731 /** 732 * @return string 733 */ 734 public function execute() { 735 $r = $this->parent->request; 736 if ( $r->wasPosted() ) { 737 if ( $this->submit() ) { 738 return 'continue'; 739 } 740 } 741 742 $this->startForm(); 743 744 // Encourage people to not name their site 'MediaWiki' by blanking the 745 // field. I think that was the intent with the original $GLOBALS['wgSitename'] 746 // but these two always were the same so had the effect of making the 747 // installer forget $wgSitename when navigating back to this page. 748 if ( $this->getVar( 'wgSitename' ) == 'MediaWiki' ) { 749 $this->setVar( 'wgSitename', '' ); 750 } 751 752 // Set wgMetaNamespace to something valid before we show the form. 753 // $wgMetaNamespace defaults to $wgSiteName which is 'MediaWiki' 754 $metaNS = $this->getVar( 'wgMetaNamespace' ); 755 $this->setVar( 756 'wgMetaNamespace', 757 wfMessage( 'config-ns-other-default' )->inContentLanguage()->text() 758 ); 759 760 $this->addHTML( 761 $this->parent->getTextBox( array( 762 'var' => 'wgSitename', 763 'label' => 'config-site-name', 764 'help' => $this->parent->getHelpBox( 'config-site-name-help' ) 765 ) ) . 766 // getRadioSet() builds a set of labeled radio buttons. 767 // For grep: The following messages are used as the item labels: 768 // config-ns-site-name, config-ns-generic, config-ns-other 769 $this->parent->getRadioSet( array( 770 'var' => '_NamespaceType', 771 'label' => 'config-project-namespace', 772 'itemLabelPrefix' => 'config-ns-', 773 'values' => array( 'site-name', 'generic', 'other' ), 774 'commonAttribs' => array( 'class' => 'enableForOther', 775 'rel' => 'config_wgMetaNamespace' ), 776 'help' => $this->parent->getHelpBox( 'config-project-namespace-help' ) 777 ) ) . 778 $this->parent->getTextBox( array( 779 'var' => 'wgMetaNamespace', 780 'label' => '', // @todo Needs a label? 781 'attribs' => array( 'readonly' => 'readonly', 'class' => 'enabledByOther' ) 782 ) ) . 783 $this->getFieldSetStart( 'config-admin-box' ) . 784 $this->parent->getTextBox( array( 785 'var' => '_AdminName', 786 'label' => 'config-admin-name', 787 'help' => $this->parent->getHelpBox( 'config-admin-help' ) 788 ) ) . 789 $this->parent->getPasswordBox( array( 790 'var' => '_AdminPassword', 791 'label' => 'config-admin-password', 792 ) ) . 793 $this->parent->getPasswordBox( array( 794 'var' => '_AdminPasswordConfirm', 795 'label' => 'config-admin-password-confirm' 796 ) ) . 797 $this->parent->getTextBox( array( 798 'var' => '_AdminEmail', 799 'label' => 'config-admin-email', 800 'help' => $this->parent->getHelpBox( 'config-admin-email-help' ) 801 ) ) . 802 $this->parent->getCheckBox( array( 803 'var' => '_Subscribe', 804 'label' => 'config-subscribe', 805 'help' => $this->parent->getHelpBox( 'config-subscribe-help' ) 806 ) ) . 807 $this->getFieldSetEnd() . 808 $this->parent->getInfoBox( wfMessage( 'config-almost-done' )->text() ) . 809 // getRadioSet() builds a set of labeled radio buttons. 810 // For grep: The following messages are used as the item labels: 811 // config-optional-continue, config-optional-skip 812 $this->parent->getRadioSet( array( 813 'var' => '_SkipOptional', 814 'itemLabelPrefix' => 'config-optional-', 815 'values' => array( 'continue', 'skip' ) 816 ) ) 817 ); 818 819 // Restore the default value 820 $this->setVar( 'wgMetaNamespace', $metaNS ); 821 822 $this->endForm(); 823 824 return 'output'; 825 } 826 827 /** 828 * @return bool 829 */ 830 public function submit() { 831 $retVal = true; 832 $this->parent->setVarsFromRequest( array( 'wgSitename', '_NamespaceType', 833 '_AdminName', '_AdminPassword', '_AdminPasswordConfirm', '_AdminEmail', 834 '_Subscribe', '_SkipOptional', 'wgMetaNamespace' ) ); 835 836 // Validate site name 837 if ( strval( $this->getVar( 'wgSitename' ) ) === '' ) { 838 $this->parent->showError( 'config-site-name-blank' ); 839 $retVal = false; 840 } 841 842 // Fetch namespace 843 $nsType = $this->getVar( '_NamespaceType' ); 844 if ( $nsType == 'site-name' ) { 845 $name = $this->getVar( 'wgSitename' ); 846 // Sanitize for namespace 847 // This algorithm should match the JS one in WebInstallerOutput.php 848 $name = preg_replace( '/[\[\]\{\}|#<>%+? ]/', '_', $name ); 849 $name = str_replace( '&', '&', $name ); 850 $name = preg_replace( '/__+/', '_', $name ); 851 $name = ucfirst( trim( $name, '_' ) ); 852 } elseif ( $nsType == 'generic' ) { 853 $name = wfMessage( 'config-ns-generic' )->text(); 854 } else { // other 855 $name = $this->getVar( 'wgMetaNamespace' ); 856 } 857 858 // Validate namespace 859 if ( strpos( $name, ':' ) !== false ) { 860 $good = false; 861 } else { 862 // Title-style validation 863 $title = Title::newFromText( $name ); 864 if ( !$title ) { 865 $good = $nsType == 'site-name'; 866 } else { 867 $name = $title->getDBkey(); 868 $good = true; 869 } 870 } 871 if ( !$good ) { 872 $this->parent->showError( 'config-ns-invalid', $name ); 873 $retVal = false; 874 } 875 876 // Make sure it won't conflict with any existing namespaces 877 global $wgContLang; 878 $nsIndex = $wgContLang->getNsIndex( $name ); 879 if ( $nsIndex !== false && $nsIndex !== NS_PROJECT ) { 880 $this->parent->showError( 'config-ns-conflict', $name ); 881 $retVal = false; 882 } 883 884 $this->setVar( 'wgMetaNamespace', $name ); 885 886 // Validate username for creation 887 $name = $this->getVar( '_AdminName' ); 888 if ( strval( $name ) === '' ) { 889 $this->parent->showError( 'config-admin-name-blank' ); 890 $cname = $name; 891 $retVal = false; 892 } else { 893 $cname = User::getCanonicalName( $name, 'creatable' ); 894 if ( $cname === false ) { 895 $this->parent->showError( 'config-admin-name-invalid', $name ); 896 $retVal = false; 897 } else { 898 $this->setVar( '_AdminName', $cname ); 899 } 900 } 901 902 // Validate password 903 $msg = false; 904 $pwd = $this->getVar( '_AdminPassword' ); 905 $user = User::newFromName( $cname ); 906 if ( $user ) { 907 $valid = $user->getPasswordValidity( $pwd ); 908 } else { 909 $valid = 'config-admin-name-invalid'; 910 } 911 if ( strval( $pwd ) === '' ) { 912 # $user->getPasswordValidity just checks for $wgMinimalPasswordLength. 913 # This message is more specific and helpful. 914 $msg = 'config-admin-password-blank'; 915 } elseif ( $pwd !== $this->getVar( '_AdminPasswordConfirm' ) ) { 916 $msg = 'config-admin-password-mismatch'; 917 } elseif ( $valid !== true ) { 918 $msg = $valid; 919 } 920 if ( $msg !== false ) { 921 call_user_func_array( array( $this->parent, 'showError' ), (array)$msg ); 922 $this->setVar( '_AdminPassword', '' ); 923 $this->setVar( '_AdminPasswordConfirm', '' ); 924 $retVal = false; 925 } 926 927 // Validate e-mail if provided 928 $email = $this->getVar( '_AdminEmail' ); 929 if ( $email && !Sanitizer::validateEmail( $email ) ) { 930 $this->parent->showError( 'config-admin-error-bademail' ); 931 $retVal = false; 932 } 933 // If they asked to subscribe to mediawiki-announce but didn't give 934 // an e-mail, show an error. Bug 29332 935 if ( !$email && $this->getVar( '_Subscribe' ) ) { 936 $this->parent->showError( 'config-subscribe-noemail' ); 937 $retVal = false; 938 } 939 940 return $retVal; 941 } 942 943 } 944 945 class WebInstallerOptions extends WebInstallerPage { 946 947 /** 948 * @return string|null 949 */ 950 public function execute() { 951 if ( $this->getVar( '_SkipOptional' ) == 'skip' ) { 952 $this->submitSkins(); 953 return 'skip'; 954 } 955 if ( $this->parent->request->wasPosted() ) { 956 if ( $this->submit() ) { 957 return 'continue'; 958 } 959 } 960 961 $emailwrapperStyle = $this->getVar( 'wgEnableEmail' ) ? '' : 'display: none'; 962 $this->startForm(); 963 $this->addHTML( 964 # User Rights 965 // getRadioSet() builds a set of labeled radio buttons. 966 // For grep: The following messages are used as the item labels: 967 // config-profile-wiki, config-profile-no-anon, config-profile-fishbowl, config-profile-private 968 $this->parent->getRadioSet( array( 969 'var' => '_RightsProfile', 970 'label' => 'config-profile', 971 'itemLabelPrefix' => 'config-profile-', 972 'values' => array_keys( $this->parent->rightsProfiles ), 973 ) ) . 974 $this->parent->getInfoBox( wfMessage( 'config-profile-help' )->plain() ) . 975 976 # Licensing 977 // getRadioSet() builds a set of labeled radio buttons. 978 // For grep: The following messages are used as the item labels: 979 // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa, 980 // config-license-cc-0, config-license-pd, config-license-gfdl, 981 // config-license-none, config-license-cc-choose 982 $this->parent->getRadioSet( array( 983 'var' => '_LicenseCode', 984 'label' => 'config-license', 985 'itemLabelPrefix' => 'config-license-', 986 'values' => array_keys( $this->parent->licenses ), 987 'commonAttribs' => array( 'class' => 'licenseRadio' ), 988 ) ) . 989 $this->getCCChooser() . 990 $this->parent->getHelpBox( 'config-license-help' ) . 991 992 # E-mail 993 $this->getFieldSetStart( 'config-email-settings' ) . 994 $this->parent->getCheckBox( array( 995 'var' => 'wgEnableEmail', 996 'label' => 'config-enable-email', 997 'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'emailwrapper' ), 998 ) ) . 999 $this->parent->getHelpBox( 'config-enable-email-help' ) . 1000 "<div id=\"emailwrapper\" style=\"$emailwrapperStyle\">" . 1001 $this->parent->getTextBox( array( 1002 'var' => 'wgPasswordSender', 1003 'label' => 'config-email-sender' 1004 ) ) . 1005 $this->parent->getHelpBox( 'config-email-sender-help' ) . 1006 $this->parent->getCheckBox( array( 1007 'var' => 'wgEnableUserEmail', 1008 'label' => 'config-email-user', 1009 ) ) . 1010 $this->parent->getHelpBox( 'config-email-user-help' ) . 1011 $this->parent->getCheckBox( array( 1012 'var' => 'wgEnotifUserTalk', 1013 'label' => 'config-email-usertalk', 1014 ) ) . 1015 $this->parent->getHelpBox( 'config-email-usertalk-help' ) . 1016 $this->parent->getCheckBox( array( 1017 'var' => 'wgEnotifWatchlist', 1018 'label' => 'config-email-watchlist', 1019 ) ) . 1020 $this->parent->getHelpBox( 'config-email-watchlist-help' ) . 1021 $this->parent->getCheckBox( array( 1022 'var' => 'wgEmailAuthentication', 1023 'label' => 'config-email-auth', 1024 ) ) . 1025 $this->parent->getHelpBox( 'config-email-auth-help' ) . 1026 "</div>" . 1027 $this->getFieldSetEnd() 1028 ); 1029 1030 $skins = $this->parent->findExtensions( 'skins' ); 1031 $skinHtml = $this->getFieldSetStart( 'config-skins' ); 1032 1033 if ( $skins ) { 1034 $skinNames = array_map( 'strtolower', $skins ); 1035 1036 $radioButtons = $this->parent->getRadioElements( array( 1037 'var' => 'wgDefaultSkin', 1038 'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ), 1039 'values' => $skinNames, 1040 'value' => $this->getVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) ), 1041 ) ); 1042 1043 foreach ( $skins as $skin ) { 1044 $skinHtml .= 1045 '<div class="config-skins-item">' . 1046 $this->parent->getCheckBox( array( 1047 'var' => "skin-$skin", 1048 'rawtext' => $skin, 1049 'value' => $this->getVar( "skin-$skin", true ), // all found skins enabled by default 1050 ) ) . 1051 '<div class="config-skins-use-as-default">' . $radioButtons[strtolower( $skin )] . '</div>' . 1052 '</div>'; 1053 } 1054 } else { 1055 $skinHtml .= $this->parent->getWarningBox( wfMessage( 'config-skins-missing' )->plain() ); 1056 } 1057 1058 $skinHtml .= $this->parent->getHelpBox( 'config-skins-help' ) . 1059 $this->getFieldSetEnd(); 1060 $this->addHTML( $skinHtml ); 1061 1062 $extensions = $this->parent->findExtensions(); 1063 1064 if ( $extensions ) { 1065 $extHtml = $this->getFieldSetStart( 'config-extensions' ); 1066 1067 foreach ( $extensions as $ext ) { 1068 $extHtml .= $this->parent->getCheckBox( array( 1069 'var' => "ext-$ext", 1070 'rawtext' => $ext, 1071 ) ); 1072 } 1073 1074 $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) . 1075 $this->getFieldSetEnd(); 1076 $this->addHTML( $extHtml ); 1077 } 1078 1079 // Having / in paths in Windows looks funny :) 1080 $this->setVar( 'wgDeletedDirectory', 1081 str_replace( 1082 '/', DIRECTORY_SEPARATOR, 1083 $this->getVar( 'wgDeletedDirectory' ) 1084 ) 1085 ); 1086 1087 $uploadwrapperStyle = $this->getVar( 'wgEnableUploads' ) ? '' : 'display: none'; 1088 $this->addHTML( 1089 # Uploading 1090 $this->getFieldSetStart( 'config-upload-settings' ) . 1091 $this->parent->getCheckBox( array( 1092 'var' => 'wgEnableUploads', 1093 'label' => 'config-upload-enable', 1094 'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'uploadwrapper' ), 1095 'help' => $this->parent->getHelpBox( 'config-upload-help' ) 1096 ) ) . 1097 '<div id="uploadwrapper" style="' . $uploadwrapperStyle . '">' . 1098 $this->parent->getTextBox( array( 1099 'var' => 'wgDeletedDirectory', 1100 'label' => 'config-upload-deleted', 1101 'attribs' => array( 'dir' => 'ltr' ), 1102 'help' => $this->parent->getHelpBox( 'config-upload-deleted-help' ) 1103 ) ) . 1104 '</div>' . 1105 $this->parent->getTextBox( array( 1106 'var' => 'wgLogo', 1107 'label' => 'config-logo', 1108 'attribs' => array( 'dir' => 'ltr' ), 1109 'help' => $this->parent->getHelpBox( 'config-logo-help' ) 1110 ) ) 1111 ); 1112 $this->addHTML( 1113 $this->parent->getCheckBox( array( 1114 'var' => 'wgUseInstantCommons', 1115 'label' => 'config-instantcommons', 1116 'help' => $this->parent->getHelpBox( 'config-instantcommons-help' ) 1117 ) ) . 1118 $this->getFieldSetEnd() 1119 ); 1120 1121 $caches = array( 'none' ); 1122 if ( count( $this->getVar( '_Caches' ) ) ) { 1123 $caches[] = 'accel'; 1124 } 1125 $caches[] = 'memcached'; 1126 1127 // We'll hide/show this on demand when the value changes, see config.js. 1128 $cacheval = $this->getVar( 'wgMainCacheType' ); 1129 if ( !$cacheval ) { 1130 // We need to set a default here; but don't hardcode it 1131 // or we lose it every time we reload the page for validation 1132 // or going back! 1133 $cacheval = 'none'; 1134 } 1135 $hidden = ( $cacheval == 'memcached' ) ? '' : 'display: none'; 1136 $this->addHTML( 1137 # Advanced settings 1138 $this->getFieldSetStart( 'config-advanced-settings' ) . 1139 # Object cache settings 1140 // getRadioSet() builds a set of labeled radio buttons. 1141 // For grep: The following messages are used as the item labels: 1142 // config-cache-none, config-cache-accel, config-cache-memcached 1143 $this->parent->getRadioSet( array( 1144 'var' => 'wgMainCacheType', 1145 'label' => 'config-cache-options', 1146 'itemLabelPrefix' => 'config-cache-', 1147 'values' => $caches, 1148 'value' => $cacheval, 1149 ) ) . 1150 $this->parent->getHelpBox( 'config-cache-help' ) . 1151 "<div id=\"config-memcachewrapper\" style=\"$hidden\">" . 1152 $this->parent->getTextArea( array( 1153 'var' => '_MemCachedServers', 1154 'label' => 'config-memcached-servers', 1155 'help' => $this->parent->getHelpBox( 'config-memcached-help' ) 1156 ) ) . 1157 '</div>' . 1158 $this->getFieldSetEnd() 1159 ); 1160 $this->endForm(); 1161 1162 return null; 1163 } 1164 1165 /** 1166 * @return string 1167 */ 1168 public function getCCPartnerUrl() { 1169 $server = $this->getVar( 'wgServer' ); 1170 $exitUrl = $server . $this->parent->getUrl( array( 1171 'page' => 'Options', 1172 'SubmitCC' => 'indeed', 1173 'config__LicenseCode' => 'cc', 1174 'config_wgRightsUrl' => '[license_url]', 1175 'config_wgRightsText' => '[license_name]', 1176 'config_wgRightsIcon' => '[license_button]', 1177 ) ); 1178 $styleUrl = $server . dirname( dirname( $this->parent->getUrl() ) ) . 1179 '/mw-config/config-cc.css'; 1180 $iframeUrl = 'http://creativecommons.org/license/?' . 1181 wfArrayToCgi( array( 1182 'partner' => 'MediaWiki', 1183 'exit_url' => $exitUrl, 1184 'lang' => $this->getVar( '_UserLang' ), 1185 'stylesheet' => $styleUrl, 1186 ) ); 1187 1188 return $iframeUrl; 1189 } 1190 1191 /** 1192 * @return string 1193 */ 1194 public function getCCChooser() { 1195 $iframeAttribs = array( 1196 'class' => 'config-cc-iframe', 1197 'name' => 'config-cc-iframe', 1198 'id' => 'config-cc-iframe', 1199 'frameborder' => 0, 1200 'width' => '100%', 1201 'height' => '100%', 1202 ); 1203 if ( $this->getVar( '_CCDone' ) ) { 1204 $iframeAttribs['src'] = $this->parent->getUrl( array( 'ShowCC' => 'yes' ) ); 1205 } else { 1206 $iframeAttribs['src'] = $this->getCCPartnerUrl(); 1207 } 1208 $wrapperStyle = ( $this->getVar( '_LicenseCode' ) == 'cc-choose' ) ? '' : 'display: none'; 1209 1210 return "<div class=\"config-cc-wrapper\" id=\"config-cc-wrapper\" style=\"$wrapperStyle\">\n" . 1211 Html::element( 'iframe', $iframeAttribs, '', false /* not short */ ) . 1212 "</div>\n"; 1213 } 1214 1215 /** 1216 * @return string 1217 */ 1218 public function getCCDoneBox() { 1219 $js = "parent.document.getElementById('config-cc-wrapper').style.height = '$1';"; 1220 // If you change this height, also change it in config.css 1221 $expandJs = str_replace( '$1', '54em', $js ); 1222 $reduceJs = str_replace( '$1', '70px', $js ); 1223 1224 return '<p>' . 1225 Html::element( 'img', array( 'src' => $this->getVar( 'wgRightsIcon' ) ) ) . 1226 '  ' . 1227 htmlspecialchars( $this->getVar( 'wgRightsText' ) ) . 1228 "</p>\n" . 1229 "<p style=\"text-align: center;\">" . 1230 Html::element( 'a', 1231 array( 1232 'href' => $this->getCCPartnerUrl(), 1233 'onclick' => $expandJs, 1234 ), 1235 wfMessage( 'config-cc-again' )->text() 1236 ) . 1237 "</p>\n" . 1238 "<script>\n" . 1239 # Reduce the wrapper div height 1240 htmlspecialchars( $reduceJs ) . 1241 "\n" . 1242 "</script>\n"; 1243 } 1244 1245 public function submitCC() { 1246 $newValues = $this->parent->setVarsFromRequest( 1247 array( 'wgRightsUrl', 'wgRightsText', 'wgRightsIcon' ) ); 1248 if ( count( $newValues ) != 3 ) { 1249 $this->parent->showError( 'config-cc-error' ); 1250 1251 return; 1252 } 1253 $this->setVar( '_CCDone', true ); 1254 $this->addHTML( $this->getCCDoneBox() ); 1255 } 1256 1257 /** 1258 * If the user skips this installer page, we still need to set up the default skins, but ignore 1259 * everything else. 1260 * 1261 * @return bool 1262 */ 1263 public function submitSkins() { 1264 $skins = $this->parent->findExtensions( 'skins' ); 1265 $this->parent->setVar( '_Skins', $skins ); 1266 1267 if ( $skins ) { 1268 $skinNames = array_map( 'strtolower', $skins ); 1269 $this->parent->setVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) ); 1270 } 1271 1272 return true; 1273 } 1274 1275 /** 1276 * @return bool 1277 */ 1278 public function submit() { 1279 $this->parent->setVarsFromRequest( array( '_RightsProfile', '_LicenseCode', 1280 'wgEnableEmail', 'wgPasswordSender', 'wgEnableUploads', 'wgLogo', 1281 'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist', 1282 'wgEmailAuthentication', 'wgMainCacheType', '_MemCachedServers', 1283 'wgUseInstantCommons', 'wgDefaultSkin' ) ); 1284 1285 $retVal = true; 1286 1287 if ( !array_key_exists( $this->getVar( '_RightsProfile' ), $this->parent->rightsProfiles ) 1288 ) { 1289 reset( $this->parent->rightsProfiles ); 1290 $this->setVar( '_RightsProfile', key( $this->parent->rightsProfiles ) ); 1291 } 1292 1293 $code = $this->getVar( '_LicenseCode' ); 1294 if ( $code == 'cc-choose' ) { 1295 if ( !$this->getVar( '_CCDone' ) ) { 1296 $this->parent->showError( 'config-cc-not-chosen' ); 1297 $retVal = false; 1298 } 1299 } elseif ( array_key_exists( $code, $this->parent->licenses ) ) { 1300 // Messages: 1301 // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa, 1302 // config-license-cc-0, config-license-pd, config-license-gfdl, config-license-none, 1303 // config-license-cc-choose 1304 $entry = $this->parent->licenses[$code]; 1305 if ( isset( $entry['text'] ) ) { 1306 $this->setVar( 'wgRightsText', $entry['text'] ); 1307 } else { 1308 $this->setVar( 'wgRightsText', wfMessage( 'config-license-' . $code )->text() ); 1309 } 1310 $this->setVar( 'wgRightsUrl', $entry['url'] ); 1311 $this->setVar( 'wgRightsIcon', $entry['icon'] ); 1312 } else { 1313 $this->setVar( 'wgRightsText', '' ); 1314 $this->setVar( 'wgRightsUrl', '' ); 1315 $this->setVar( 'wgRightsIcon', '' ); 1316 } 1317 1318 $skinsAvailable = $this->parent->findExtensions( 'skins' ); 1319 $skinsToInstall = array(); 1320 foreach ( $skinsAvailable as $skin ) { 1321 $this->parent->setVarsFromRequest( array( "skin-$skin" ) ); 1322 if ( $this->getVar( "skin-$skin" ) ) { 1323 $skinsToInstall[] = $skin; 1324 } 1325 } 1326 $this->parent->setVar( '_Skins', $skinsToInstall ); 1327 1328 if ( !$skinsToInstall && $skinsAvailable ) { 1329 $this->parent->showError( 'config-skins-must-enable-some' ); 1330 $retVal = false; 1331 } 1332 $defaultSkin = $this->getVar( 'wgDefaultSkin' ); 1333 $skinsToInstallLowercase = array_map( 'strtolower', $skinsToInstall ); 1334 if ( $skinsToInstall && array_search( $defaultSkin, $skinsToInstallLowercase ) === false ) { 1335 $this->parent->showError( 'config-skins-must-enable-default' ); 1336 $retVal = false; 1337 } 1338 1339 $extsAvailable = $this->parent->findExtensions(); 1340 $extsToInstall = array(); 1341 foreach ( $extsAvailable as $ext ) { 1342 $this->parent->setVarsFromRequest( array( "ext-$ext" ) ); 1343 if ( $this->getVar( "ext-$ext" ) ) { 1344 $extsToInstall[] = $ext; 1345 } 1346 } 1347 $this->parent->setVar( '_Extensions', $extsToInstall ); 1348 1349 if ( $this->getVar( 'wgMainCacheType' ) == 'memcached' ) { 1350 $memcServers = explode( "\n", $this->getVar( '_MemCachedServers' ) ); 1351 if ( !$memcServers ) { 1352 $this->parent->showError( 'config-memcache-needservers' ); 1353 $retVal = false; 1354 } 1355 1356 foreach ( $memcServers as $server ) { 1357 $memcParts = explode( ":", $server, 2 ); 1358 if ( !isset( $memcParts[0] ) 1359 || ( !IP::isValid( $memcParts[0] ) 1360 && ( gethostbyname( $memcParts[0] ) == $memcParts[0] ) ) 1361 ) { 1362 $this->parent->showError( 'config-memcache-badip', $memcParts[0] ); 1363 $retVal = false; 1364 } elseif ( !isset( $memcParts[1] ) ) { 1365 $this->parent->showError( 'config-memcache-noport', $memcParts[0] ); 1366 $retVal = false; 1367 } elseif ( $memcParts[1] < 1 || $memcParts[1] > 65535 ) { 1368 $this->parent->showError( 'config-memcache-badport', 1, 65535 ); 1369 $retVal = false; 1370 } 1371 } 1372 } 1373 1374 return $retVal; 1375 } 1376 1377 } 1378 1379 class WebInstallerInstall extends WebInstallerPage { 1380 1381 /** 1382 * @return bool Always true. 1383 */ 1384 public function isSlow() { 1385 return true; 1386 } 1387 1388 /** 1389 * @return string|bool 1390 */ 1391 public function execute() { 1392 if ( $this->getVar( '_UpgradeDone' ) ) { 1393 return 'skip'; 1394 } elseif ( $this->getVar( '_InstallDone' ) ) { 1395 return 'continue'; 1396 } elseif ( $this->parent->request->wasPosted() ) { 1397 $this->startForm(); 1398 $this->addHTML( "<ul>" ); 1399 $results = $this->parent->performInstallation( 1400 array( $this, 'startStage' ), 1401 array( $this, 'endStage' ) 1402 ); 1403 $this->addHTML( "</ul>" ); 1404 // PerformInstallation bails on a fatal, so make sure the last item 1405 // completed before giving 'next.' Likewise, only provide back on failure 1406 $lastStep = end( $results ); 1407 $continue = $lastStep->isOK() ? 'continue' : false; 1408 $back = $lastStep->isOK() ? false : 'back'; 1409 $this->endForm( $continue, $back ); 1410 } else { 1411 $this->startForm(); 1412 $this->addHTML( $this->parent->getInfoBox( wfMessage( 'config-install-begin' )->plain() ) ); 1413 $this->endForm(); 1414 } 1415 1416 return true; 1417 } 1418 1419 /** 1420 * @param string $step 1421 */ 1422 public function startStage( $step ) { 1423 // Messages: config-install-database, config-install-tables, config-install-interwiki, 1424 // config-install-stats, config-install-keys, config-install-sysop, config-install-mainpage 1425 $this->addHTML( "<li>" . wfMessage( "config-install-$step" )->escaped() . 1426 wfMessage( 'ellipsis' )->escaped() ); 1427 1428 if ( $step == 'extension-tables' ) { 1429 $this->startLiveBox(); 1430 } 1431 } 1432 1433 /** 1434 * @param string $step 1435 * @param Status $status 1436 */ 1437 public function endStage( $step, $status ) { 1438 if ( $step == 'extension-tables' ) { 1439 $this->endLiveBox(); 1440 } 1441 $msg = $status->isOk() ? 'config-install-step-done' : 'config-install-step-failed'; 1442 $html = wfMessage( 'word-separator' )->escaped() . wfMessage( $msg )->escaped(); 1443 if ( !$status->isOk() ) { 1444 $html = "<span class=\"error\">$html</span>"; 1445 } 1446 $this->addHTML( $html . "</li>\n" ); 1447 if ( !$status->isGood() ) { 1448 $this->parent->showStatusBox( $status ); 1449 } 1450 } 1451 1452 } 1453 1454 class WebInstallerComplete extends WebInstallerPage { 1455 1456 public function execute() { 1457 // Pop up a dialog box, to make it difficult for the user to forget 1458 // to download the file 1459 $lsUrl = $this->getVar( 'wgServer' ) . $this->parent->getURL( array( 'localsettings' => 1 ) ); 1460 if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && 1461 strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE' ) !== false 1462 ) { 1463 // JS appears to be the only method that works consistently with IE7+ 1464 $this->addHtml( "\n<script>jQuery( function () { document.location = " . 1465 Xml::encodeJsVar( $lsUrl ) . "; } );</script>\n" ); 1466 } else { 1467 $this->parent->request->response()->header( "Refresh: 0;url=$lsUrl" ); 1468 } 1469 1470 $this->startForm(); 1471 $this->parent->disableLinkPopups(); 1472 $this->addHTML( 1473 $this->parent->getInfoBox( 1474 wfMessage( 'config-install-done', 1475 $lsUrl, 1476 $this->getVar( 'wgServer' ) . 1477 $this->getVar( 'wgScriptPath' ) . '/index' . 1478 $this->getVar( 'wgScriptExtension' ), 1479 '<downloadlink/>' 1480 )->plain(), 'tick-32.png' 1481 ) 1482 ); 1483 $this->addHTML( $this->parent->getInfoBox( 1484 wfMessage( 'config-extension-link' )->text() ) ); 1485 1486 $this->parent->restoreLinkPopups(); 1487 $this->endForm( false, false ); 1488 } 1489 1490 } 1491 1492 class WebInstallerRestart extends WebInstallerPage { 1493 1494 /** 1495 * @return string|null 1496 */ 1497 public function execute() { 1498 $r = $this->parent->request; 1499 if ( $r->wasPosted() ) { 1500 $really = $r->getVal( 'submit-restart' ); 1501 if ( $really ) { 1502 $this->parent->reset(); 1503 } 1504 1505 return 'continue'; 1506 } 1507 1508 $this->startForm(); 1509 $s = $this->parent->getWarningBox( wfMessage( 'config-help-restart' )->plain() ); 1510 $this->addHTML( $s ); 1511 $this->endForm( 'restart' ); 1512 1513 return null; 1514 } 1515 1516 } 1517 1518 abstract class WebInstallerDocument extends WebInstallerPage { 1519 1520 /** 1521 * @return string 1522 */ 1523 abstract protected function getFileName(); 1524 1525 public function execute() { 1526 $text = $this->getFileContents(); 1527 $text = InstallDocFormatter::format( $text ); 1528 $this->parent->output->addWikiText( $text ); 1529 $this->startForm(); 1530 $this->endForm( false ); 1531 } 1532 1533 /** 1534 * @return string 1535 */ 1536 public function getFileContents() { 1537 $file = __DIR__ . '/../../' . $this->getFileName(); 1538 if ( !file_exists( $file ) ) { 1539 return wfMessage( 'config-nofile', $file )->plain(); 1540 } 1541 1542 return file_get_contents( $file ); 1543 } 1544 1545 } 1546 1547 class WebInstallerReadme extends WebInstallerDocument { 1548 1549 /** 1550 * @return string 1551 */ 1552 protected function getFileName() { 1553 return 'README'; 1554 } 1555 1556 } 1557 1558 class WebInstallerReleaseNotes extends WebInstallerDocument { 1559 1560 /** 1561 * @throws MWException 1562 * @return string 1563 */ 1564 protected function getFileName() { 1565 global $wgVersion; 1566 1567 if ( !preg_match( '/^(\d+)\.(\d+).*/i', $wgVersion, $result ) ) { 1568 throw new MWException( 'Variable $wgVersion has an invalid value.' ); 1569 } 1570 1571 return 'RELEASE-NOTES-' . $result[1] . '.' . $result[2]; 1572 } 1573 1574 } 1575 1576 class WebInstallerUpgradeDoc extends WebInstallerDocument { 1577 1578 /** 1579 * @return string 1580 */ 1581 protected function getFileName() { 1582 return 'UPGRADE'; 1583 } 1584 1585 } 1586 1587 class WebInstallerCopying extends WebInstallerDocument { 1588 1589 /** 1590 * @return string 1591 */ 1592 protected function getFileName() { 1593 return 'COPYING'; 1594 } 1595 1596 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |