r43665 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r43664‎ | r43665 | r43666 >
Date:06:17, 18 November 2008
Author:tstarling
Status:deferred
Tags:
Comment:
Work to date. The basic features are:
* Flexible backend for better cooperation with scripted installs (e.g. Debian packages)
* Wizard-style frontend with validation at each step. Avoids asking the user lots of questions that they don't need to answer.
* Implementation as an ordinary MediaWiki entry point, including the ability to parse wikitext. Internationalised, wikitext-formatted interface text.
* Modular DBMS support, to simplify addition and maintenance of non-MySQL DBMS modules.
Modified paths:
  • /branches/new-installer/phase3/config/new-index.php (added) (history)
  • /branches/new-installer/phase3/includes/AutoLoader.php (modified) (history)
  • /branches/new-installer/phase3/includes/installer (added) (history)
  • /branches/new-installer/phase3/includes/installer/Installer.php (added) (history)
  • /branches/new-installer/phase3/includes/installer/InstallerDBType.php (added) (history)
  • /branches/new-installer/phase3/includes/installer/MysqlInstaller.php (added) (history)
  • /branches/new-installer/phase3/includes/installer/PostgresInstaller.php (added) (history)
  • /branches/new-installer/phase3/includes/installer/SqliteInstaller.php (added) (history)
  • /branches/new-installer/phase3/includes/installer/WebInstaller.php (added) (history)
  • /branches/new-installer/phase3/includes/installer/WebInstallerOutput.php (added) (history)
  • /branches/new-installer/phase3/languages/messages/MessagesEn.php (modified) (history)

Diff [purge]

Index: branches/new-installer/phase3/includes/installer/WebInstaller.php
@@ -0,0 +1,818 @@
 2+<?php
 3+
 4+class WebInstaller extends Installer {
 5+ /** WebRequest object */
 6+ var $request;
 7+
 8+ /** Cached session array */
 9+ var $session;
 10+
 11+ /** Captured PHP error text. Temporary.
 12+ */
 13+ var $phpErrors;
 14+
 15+ /**
 16+ * The main sequence of page names. These will be displayed in turn.
 17+ * To add one:
 18+ * * Add it here
 19+ * * Add a config-page-<name> message
 20+ * * Add a WebInstaller_<name> class
 21+ */
 22+ var $pageSequence = array(
 23+ 'Language',
 24+ 'Environment',
 25+ 'DBConnect',
 26+ 'Upgrade',
 27+ 'DBSettings',
 28+ 'Identity',
 29+ 'License',
 30+ 'Email',
 31+ 'Install',
 32+ 'Complete',
 33+ );
 34+
 35+ /**
 36+ * Out of sequence pages, selectable by the user at any time
 37+ */
 38+ var $otherPages = array(
 39+ 'Restart',
 40+ );
 41+
 42+ /**
 43+ * Array of pages which have declared that they have been submitted, have validated
 44+ * their input, and need no further processing
 45+ */
 46+ var $happyPages;
 47+
 48+ /**
 49+ * List of "skipped" pages. These are pages that will automatically continue
 50+ * to the next page on any GET request. To avoid breaking the "back" button,
 51+ * they need to be skipped during a back operation.
 52+ */
 53+ var $skippedPages;
 54+
 55+ /**
 56+ * Flag indicating that session data may have been lost
 57+ */
 58+ var $showSessionWarning = false;
 59+
 60+ /** Constructor */
 61+ function __construct( $request ) {
 62+ parent::__construct();
 63+ $this->output = new WebInstallerOutput( $this );
 64+ $this->request = $request;
 65+ $this->internalDefaults['_UserLang'] = 'en';
 66+ }
 67+
 68+ /**
 69+ * Main entry point.
 70+ * @param array $session Initial session array
 71+ * @return array New session array
 72+ */
 73+ function execute( $session ) {
 74+ $this->session = $session;
 75+ if ( isset( $session['settings'] ) ) {
 76+ $this->settings = $session['settings'] + $this->settings;
 77+ }
 78+ if ( isset( $session['happyPages'] ) ) {
 79+ $this->happyPages = $session['happyPages'];
 80+ } else {
 81+ $this->happyPages = array();
 82+ }
 83+ if ( isset( $session['skippedPages'] ) ) {
 84+ $this->skippedPages = $session['skippedPages'];
 85+ } else {
 86+ $this->skippedPages = array();
 87+ }
 88+ $lowestUnhappy = $this->getLowestUnhappy();
 89+
 90+
 91+ # Get the page name
 92+ $pageName = $this->request->getVal( 'page' );
 93+
 94+ if ( in_array( $pageName, $this->otherPages ) ) {
 95+ # Out of sequence
 96+ $pageId = false;
 97+ $page = $this->getPageByName( $pageName );
 98+ } else {
 99+ # Main sequence
 100+ if ( !$pageName || !in_array( $pageName, $this->pageSequence ) ) {
 101+ $pageId = $lowestUnhappy;
 102+ } else {
 103+ $pageId = array_search( $pageName, $this->pageSequence );
 104+ }
 105+
 106+ # If necessary, move back to the lowest-numbered unhappy page
 107+ if ( $pageId > $lowestUnhappy ) {
 108+ $pageId = $lowestUnhappy;
 109+ if ( $lowestUnhappy == 0 ) {
 110+ # Knocked back to start, possible loss of session data
 111+ $this->showSessionWarning = true;
 112+ }
 113+ }
 114+ $pageName = $this->pageSequence[$pageId];
 115+ $page = $this->getPageByName( $pageName );
 116+ }
 117+
 118+ # If a back button was submitted, go back without submitting the form data
 119+ if ( $this->request->wasPosted() && $this->request->getBool( 'submit-back' ) ) {
 120+ if ( $this->request->getVal( 'lastPage' ) ) {
 121+ $nextPage = $this->request->getVal( 'lastPage' );
 122+ } elseif ( $pageId !== false ) {
 123+ # Main sequence page
 124+ # Skip the skipped pages
 125+ $nextPageId = $pageId;
 126+ do {
 127+ $nextPageId--;
 128+ $nextPage = $this->pageSequence[$nextPageId];
 129+ } while( isset( $this->skippedPages[$nextPage] ) );
 130+ } else {
 131+ $nextPage = $this->pageSequence[$lowestUnhappy];
 132+ }
 133+ $this->output->redirect( $this->getUrl( array( 'page' => $nextPage ) ) );
 134+ return $this->finish();
 135+ }
 136+
 137+ # Execute the page
 138+ $this->startPageWrapper( $pageName );
 139+ $result = $page->execute();
 140+ $this->endPageWrapper();
 141+
 142+ if ( $result == 'skip' ) {
 143+ # Page skipped without explicit submission
 144+ # Skip it when we click "back" so that we don't just go forward again
 145+ $this->skippedPages[$pageName] = true;
 146+ $result = 'continue';
 147+ } else {
 148+ unset( $this->skippedPages[$pageName] );
 149+ }
 150+
 151+ # If it was posted, the page can request a continue to the next page
 152+ if ( $result === 'continue' ) {
 153+ if ( $pageId !== false ) {
 154+ $this->happyPages[$pageId] = true;
 155+ }
 156+ $lowestUnhappy = $this->getLowestUnhappy();
 157+
 158+ if ( $this->request->getVal( 'lastPage' ) ) {
 159+ $nextPage = $this->request->getVal( 'lastPage' );
 160+ } elseif ( $pageId !== false ) {
 161+ $nextPage = $this->pageSequence[$pageId + 1];
 162+ } else {
 163+ $nextPage = $this->pageSequence[$lowestUnhappy];
 164+ }
 165+ if ( array_search( $nextPage, $this->pageSequence ) > $lowestUnhappy ) {
 166+ $nextPage = $this->pageSequence[$lowestUnhappy];
 167+ }
 168+ $this->output->redirect( $this->getUrl( array( 'page' => $nextPage ) ) );
 169+ }
 170+ return $this->finish();
 171+ }
 172+
 173+ function getLowestUnhappy() {
 174+ if ( count( $this->happyPages ) == 0 ) {
 175+ return 0;
 176+ } else {
 177+ return max( array_keys( $this->happyPages ) ) + 1;
 178+ }
 179+ }
 180+
 181+ /**
 182+ * Start the PHP session. This may be called before execute() to start the PHP session.
 183+ */
 184+ function startSession() {
 185+ if( wfIniGetBool( 'session.auto_start' ) || session_id() ) {
 186+ // Done already
 187+ return true;
 188+ }
 189+
 190+ $this->phpErrors = array();
 191+ set_error_handler( array( $this, 'errorHandler' ) );
 192+ session_start();
 193+ restore_error_handler();
 194+ if ( $this->phpErrors ) {
 195+ $this->showError( 'config-session-error', $this->phpErrors[0] );
 196+ return false;
 197+ }
 198+ return true;
 199+ }
 200+
 201+ /**
 202+ * Show an error message in a box. Parameters are like wfMsg().
 203+ */
 204+ function showError( $msg /*...*/ ) {
 205+ $args = func_get_args();
 206+ array_shift( $args );
 207+ $args = array_map( 'htmlspecialchars', $args );
 208+ $msg = wfMsgReal( $msg, $args );
 209+ $this->output->addHTML( "<div class=\"config-error-top\">\n$msg\n</div>\n" );
 210+ }
 211+
 212+ /**
 213+ * Temporary error handler for session start debugging
 214+ */
 215+ function errorHandler( $errno, $errstr ) {
 216+ $this->phpErrors[] = $errstr;
 217+ }
 218+
 219+ /**
 220+ * Clean up from execute()
 221+ * @private.
 222+ */
 223+ function finish() {
 224+ $this->output->output();
 225+ $this->session['happyPages'] = $this->happyPages;
 226+ $this->session['skippedPages'] = $this->skippedPages;
 227+ $this->session['settings'] = $this->settings;
 228+ return $this->session;
 229+ }
 230+
 231+ /**
 232+ * Get a URL for submission back to the same script
 233+ */
 234+ function getUrl( $query = array() ) {
 235+ $url = $this->request->getRequestURL();
 236+ # Remove existing query
 237+ $url = preg_replace( '/\?.*$/', '', $url );
 238+ if ( $query ) {
 239+ $url .= '?' . wfArrayToCGI( $query );
 240+ }
 241+ return $url;
 242+ }
 243+
 244+ /**
 245+ * Get a WebInstallerPage from the main sequence, by ID
 246+ */
 247+ function getPageById( $id ) {
 248+ $pageName = $this->pageSequence[$id];
 249+ $pageClass = 'WebInstaller_' . $pageName;
 250+ return new $pageClass( $this );
 251+ }
 252+
 253+ /**
 254+ * Get a WebInstallerPage by name
 255+ */
 256+ function getPageByName( $pageName ) {
 257+ $pageClass = 'WebInstaller_' . $pageName;
 258+ return new $pageClass( $this );
 259+ }
 260+
 261+ /**
 262+ * Get a session variable
 263+ */
 264+ function getSession( $name, $default = null ) {
 265+ if ( !isset( $this->session[$name] ) ) {
 266+ return $default;
 267+ } else {
 268+ return $this->session[$name];
 269+ }
 270+ }
 271+
 272+ /**
 273+ * Set a session variable
 274+ */
 275+ function setSession( $name, $value ) {
 276+ $this->session[$name] = $value;
 277+ }
 278+
 279+ /**
 280+ * Called by execute() before page output starts, to show a page list
 281+ */
 282+ function startPageWrapper( $currentPageName ) {
 283+ $s = "<div class=\"config-page-wrapper\">\n" .
 284+ "<div class=\"config-page-list\"><ul>\n";
 285+ $lastHappy = -1;
 286+ foreach ( $this->pageSequence as $id => $pageName ) {
 287+ $happy = !empty( $this->happyPages[$id] );
 288+ $s .= $this->getPageListItem( $pageName,
 289+ $happy || $lastHappy == $id - 1, $currentPageName );
 290+ if ( $happy ) {
 291+ $lastHappy = $id;
 292+ }
 293+ }
 294+ $s .= "</ul><br/><ul>\n";
 295+ foreach ( $this->otherPages as $pageName ) {
 296+ $s .= $this->getPageListItem( $pageName, true, $currentPageName );
 297+ }
 298+ $s .= "</ul></div>\n". // end list pane
 299+ "<div class=\"config-page\">\n" .
 300+ Xml::element( 'h2', array(),
 301+ wfMsg( 'config-page-' . strtolower( $currentPageName ) ) );
 302+
 303+ $this->output->addHTMLNoFlush( $s );
 304+ }
 305+
 306+ /**
 307+ * Get a list item for the page list
 308+ */
 309+ function getPageListItem( $pageName, $enabled, $currentPageName ) {
 310+ $s = "<li class=\"config-page-list-item\">";
 311+ $name = wfMsg( 'config-page-' . strtolower( $pageName ) );
 312+ if ( $enabled ) {
 313+ $query = array( 'page' => $pageName );
 314+ if ( !in_array( $pageName, $this->pageSequence ) ) {
 315+ $query['lastPage'] = $currentPageName;
 316+ $link = Xml::element( 'a',
 317+ array(
 318+ 'href' => $this->getUrl( $query )
 319+ ),
 320+ $name
 321+ );
 322+ } else {
 323+ $link = htmlspecialchars( $name );
 324+ }
 325+ if ( $pageName == $currentPageName ) {
 326+ $s .= "<span class=\"config-page-current\">$link</span>";
 327+ } else {
 328+ $s .= $link;
 329+ }
 330+ } else {
 331+ $s .= Xml::element( 'span',
 332+ array(
 333+ 'class' => 'config-page-disabled'
 334+ ),
 335+ $name
 336+ );
 337+ }
 338+ $s .= "</li>\n";
 339+ return $s;
 340+ }
 341+
 342+ /**
 343+ * Output some stuff after a page is finished
 344+ */
 345+ function endPageWrapper() {
 346+ $this->output->addHTMLNoFlush(
 347+ "</div>\n" .
 348+ "<br clear=\"left\"/>\n" .
 349+ "</div>" );
 350+ }
 351+
 352+ /**
 353+ * Get HTML for a warning box with an icon
 354+ */
 355+ function getWarningBox( $msg ) {
 356+ return $this->getInfoBox( $msg, 'warning-32.png' );
 357+ }
 358+
 359+ /**
 360+ * Get HTML for an info box with an icon
 361+ */
 362+ function getInfoBox( $msg, $icon = 'info-32.png' ) {
 363+ if ( is_array( $msg ) ) {
 364+ $args = $msg;
 365+ $msg = array_shift( $args );
 366+ $text = wfMsgReal( $msg, $args, false, false, false );
 367+ } else {
 368+ $text = wfMsgNoTrans( $msg );
 369+ }
 370+ $s = "<div class=\"config-info\">\n" .
 371+ "<div class=\"config-info-left\">\n" .
 372+ Xml::element( 'img',
 373+ array(
 374+ 'src' => '../skins/common/images/' . $icon
 375+ )
 376+ ) . "\n" .
 377+ "</div>\n" .
 378+ "<div class=\"config-info-right\">\n" .
 379+ $this->parse( $text ) .
 380+ "</div></div>\n";
 381+ return $s;
 382+ }
 383+
 384+ /**
 385+ * Get small text indented help for a preceding form field.
 386+ * Parameters like wfMsg().
 387+ */
 388+ function getHelpBox( $msg /*, ... */ ) {
 389+ $args = func_get_args();
 390+ array_shift( $args );
 391+ $args = array_map( 'htmlspecialchars', $args );
 392+ return "<div class=\"config-desc\">\n" .
 393+ $this->parse( wfMsgReal( $msg, $args, false, false, false ) ) .
 394+ "</div>\n";
 395+ }
 396+
 397+ /**
 398+ * Output a help box
 399+ */
 400+ function showHelpBox( $msg /*, ... */ ) {
 401+ $args = func_get_args();
 402+ $html = call_user_func_array( array( $this, 'getHelpBox' ), $args );
 403+ $this->output->addHTML( $html );
 404+ }
 405+
 406+ /**
 407+ * Show a short informational message
 408+ * Output looks like a list.
 409+ */
 410+ function showMessage( $msg /*, ... */ ) {
 411+ $args = func_get_args();
 412+ array_shift( $args );
 413+ $html = '<div class="config-message">' .
 414+ $this->parse( wfMsgReal( $msg, $args, false, false, false ) ) .
 415+ "</div>\n";
 416+ $this->output->addHTML( $html );
 417+ }
 418+
 419+ /**
 420+ * Get a label element using a message name
 421+ */
 422+ function getLabel( $msg, $for ) {
 423+ return Xml::element( 'label',
 424+ array( 'for' => $for, 'class' => 'config-label' ),
 425+ wfMsg( $msg ) ) . "\n";
 426+ }
 427+
 428+ /**
 429+ * Get a text box
 430+ */
 431+ function getTextBox( $name, $value = '', $type = 'text' ) {
 432+ return Xml::element( 'input',
 433+ array(
 434+ 'type' => $type,
 435+ 'name' => $name,
 436+ 'id' => $name,
 437+ 'value' => $value,
 438+ 'class' => 'config-input-text',
 439+ )
 440+ );
 441+ }
 442+
 443+ /**
 444+ * Get a checkbox
 445+ */
 446+ function getCheckBox( $name, $value, $attribs ) {
 447+ return Xml::element( 'input',
 448+ $attribs + array(
 449+ 'type' => 'checkbox',
 450+ 'name' => $name,
 451+ 'id' => $name,
 452+ 'checked' => $value ? '1' : '',
 453+ 'class' => 'config-input-text',
 454+ )
 455+ );
 456+ }
 457+
 458+ /**
 459+ * Output an error box using a Status object
 460+ */
 461+ function showStatusErrorBox( $status ) {
 462+ $text = $status->getWikiText();
 463+ $this->parent->output->addWikiText(
 464+ "<div class=\"config-error-top\">\n" .
 465+ $text .
 466+ "</div>"
 467+ );
 468+ }
 469+
 470+ function showStatusError( $status ) {
 471+ $text = $status->getWikiText();
 472+ $this->parent->output->addWikiText(
 473+ "<div class=\"config-message\">\n" .
 474+ $text .
 475+ "</div>"
 476+ );
 477+ }
 478+}
 479+
 480+class WebInstallerPage {
 481+ function __construct( $parent ) {
 482+ $this->parent = $parent;
 483+ }
 484+
 485+ function startForm() {
 486+ $this->parent->output->addHTML(
 487+ "<div class=\"config-section\">\n" .
 488+ Xml::openElement(
 489+ 'form',
 490+ array(
 491+ 'method' => 'post',
 492+ 'action' => $this->parent->getUrl( array( 'page' => $this->getName() ) )
 493+ )
 494+ ) . "\n"
 495+ );
 496+ }
 497+
 498+ function endForm( $continue = 'continue' ) {
 499+ $s = "<div class=\"config-submit\">\n";
 500+ $id = $this->getId();
 501+ if ( $id === false ) {
 502+ $s .= Xml::hidden( 'lastPage', $this->parent->request->getVal( 'lastPage' ) );
 503+ }
 504+ if ( $continue ) {
 505+ // Fake submit button for enter keypress
 506+ $s .= Xml::submitButton( wfMsg( "config-$continue" ),
 507+ array( 'name' => "enter-$continue", 'style' => 'display:none' ) );
 508+ }
 509+ if ( $id !== 0 ) {
 510+ $s .= Xml::submitButton( wfMsg( 'config-back' ), array( 'name' => 'submit-back' ) );
 511+ }
 512+ if ( $continue ) {
 513+ $s .= Xml::submitButton( wfMsg( "config-$continue" ),
 514+ array( 'name' => "submit-$continue" ) );
 515+ }
 516+ $s .= "</div></form></div>\n";
 517+ $this->parent->output->addHTML( $s );
 518+ }
 519+
 520+ function getName() {
 521+ return str_replace( 'WebInstaller_', '', get_class( $this ) );
 522+ }
 523+
 524+ function getId() {
 525+ return array_search( $this->getName(), $this->parent->pageSequence );
 526+ }
 527+
 528+ function execute() {
 529+ if ( $this->parent->request->wasPosted() ) {
 530+ return 'continue';
 531+ } else {
 532+ $this->startForm();
 533+ $this->parent->output->addHTML( 'Mockup' );
 534+ $this->endForm();
 535+ }
 536+ }
 537+}
 538+
 539+class WebInstaller_Language extends WebInstallerPage {
 540+ function execute() {
 541+ global $wgLang;
 542+ $r = $this->parent->request;
 543+ $userLang = $r->getVal( 'UserLang' );
 544+ $contLang = $r->getVal( 'ContLang' );
 545+
 546+ if ( $r->wasPosted() ) {
 547+ # Do session test
 548+ if ( $this->parent->getSession( 'test' ) === null ) {
 549+ $requestTime = $r->getVal( 'LanguageRequestTime' );
 550+ $lifetime = intval( ini_get( 'session.gc_maxlifetime' ) );
 551+ if ( !$lifetime ) {
 552+ $lifetime = 1440;
 553+ }
 554+ if ( !$requestTime ) {
 555+ // The most likely explanation is that the user was knocked back
 556+ // from another page on POST due to session expiry
 557+ $msg = 'config-session-expired';
 558+ } elseif ( time() - $requestTime > $lifetime ) {
 559+ $msg = 'config-session-expired';
 560+ } else {
 561+ $msg = 'config-no-session';
 562+ }
 563+ $this->parent->showError( $msg, $wgLang->formatTimePeriod( $lifetime ) );
 564+ } else {
 565+ $languages = Language::getLanguageNames();
 566+ if ( isset( $languages[$userLang] ) ) {
 567+ $this->parent->setVar( '_UserLang', $userLang );
 568+ }
 569+ if ( isset( $languages[$contLang] ) ) {
 570+ $this->parent->setVar( 'wgLanguageCode', $contLang );
 571+ }
 572+ return 'continue';
 573+ }
 574+ } elseif ( $this->parent->showSessionWarning ) {
 575+ # The user was knocked back from another page to the start
 576+ # This probably indicates a session expiry
 577+ $this->parent->showError( 'config-session-expired' );
 578+ }
 579+
 580+ $this->parent->setSession( 'test', true );
 581+
 582+ if ( !isset( $languages[$userLang] ) ) {
 583+ $userLang = $this->parent->getVar( '_UserLang', 'en' );
 584+ }
 585+ if ( !isset( $languages[$contLang] ) ) {
 586+ $contLang = $this->parent->getVar( 'wgLanguageCode', 'en' );
 587+ }
 588+ $this->startForm();
 589+ $s =
 590+ Xml::hidden( 'LanguageRequestTime', time() ) .
 591+ $this->getLanguageSelector( 'UserLang', 'config-your-language', $userLang ) .
 592+ $this->parent->getHelpBox( 'config-your-language-help' ) .
 593+ $this->getLanguageSelector( 'ContLang', 'config-wiki-language', $contLang ) .
 594+ $this->parent->getHelpBox( 'config-wiki-language-help' );
 595+
 596+
 597+ $this->parent->output->addHTML( $s );
 598+ $this->endForm();
 599+ }
 600+
 601+ /**
 602+ * Get a <select> for selecting languages
 603+ */
 604+ function getLanguageSelector( $name, $label, $selectedCode ) {
 605+ $s = "<div class=\"config-input\">\n" .
 606+ $this->parent->getLabel( $label, $name ) .
 607+ Xml::openElement( 'select', array( 'id' => $name, 'name' => $name ) ) . "\n";
 608+
 609+ $languages = Language::getLanguageNames();
 610+ ksort( $languages );
 611+ foreach ( $languages as $code => $name ) {
 612+ $s .= "\n" . Xml::option( "$code - $name", $code, $code == $selectedCode );
 613+ }
 614+ $s .= "\n</select>\n</div>\n";
 615+ return $s;
 616+ }
 617+
 618+}
 619+
 620+class WebInstaller_Environment extends WebInstallerPage {
 621+ function execute() {
 622+ if ( $this->parent->request->wasPosted() ) {
 623+ if ( $this->parent->getVar( '_Environment' ) ) {
 624+ return 'continue';
 625+ }
 626+ }
 627+ $status = $this->parent->doEnvironmentChecks();
 628+ if ( $status ) {
 629+ $this->startForm();
 630+ $this->endForm();
 631+ }
 632+ }
 633+}
 634+
 635+class WebInstaller_DBConnect extends WebInstallerPage {
 636+ function execute() {
 637+ $r = $this->parent->request;
 638+ if ( $this->parent->request->wasPosted() ) {
 639+ $status = $this->submit();
 640+ if ( $status->isGood() ) {
 641+ $this->parent->setVar( '_UpgradeDone', false );
 642+ return 'continue';
 643+ } else {
 644+ $error = $status->getWikiText();
 645+ $this->parent->output->addWikiText(
 646+ "<div class=\"config-error-top\">\n" .
 647+ $error .
 648+ "</div>"
 649+ );
 650+ }
 651+ }
 652+
 653+
 654+ $this->startForm();
 655+
 656+ $types = "<label class=\"config-label\">" .
 657+ wfMsg( 'config-db-type' ) .
 658+ "</label>" .
 659+ "<ul class=\"config-settings-block\">\n";
 660+ $settings = '';
 661+ $defaultType = $this->parent->getVar( 'wgDBtype' );
 662+ foreach ( $this->parent->getDBTypes() as $type ) {
 663+ $installer = $this->parent->getDBInstaller( $type );
 664+ $encType = Xml::encodeJsVar( $type );
 665+ $types .=
 666+ '<li>' .
 667+ Xml::radioLabel(
 668+ $installer->getReadableName(),
 669+ 'DBType',
 670+ $type,
 671+ 'DBType_' . $type,
 672+ $type == $defaultType,
 673+ array( 'onclick' => "showDBArea($encType);" )
 674+ ) .
 675+ "</li>\n";
 676+
 677+ $settings .=
 678+ Xml::openElement( 'div', array( 'id' => 'DB_wrapper_' . $type ) ) .
 679+ Xml::element( 'h3', array(), wfMsg( 'config-header-' . $type ) ) .
 680+ $installer->getConnectForm() .
 681+ "</div>\n";
 682+ }
 683+ $types .= "</ul><br clear=\"left\"/>\n";
 684+ $encType = Xml::encodeJsVar( $defaultType );
 685+
 686+ $this->parent->output->addHTML(
 687+ $types .
 688+ $settings .
 689+ "<script>resetDBArea();</script>\n"
 690+ );
 691+
 692+ $this->endForm();
 693+ }
 694+
 695+ function submit() {
 696+ $r = $this->parent->request;
 697+ $type = $r->getVal( 'DBType' );
 698+ $this->parent->setVar( 'wgDBtype', $type );
 699+ $installer = $this->parent->getDBInstaller( $type );
 700+ if ( !$installer ) {
 701+ return Status::newFatal( 'config-invalid-db-type' );
 702+ }
 703+ return $installer->submitConnectForm();
 704+ }
 705+}
 706+
 707+class WebInstaller_Upgrade extends WebInstallerPage {
 708+ function execute() {
 709+ if ( $this->parent->getVar( '_UpgradeDone' ) ) {
 710+ if ( $this->parent->request->wasPosted() ) {
 711+ // Done message acknowledged
 712+ return 'continue';
 713+ } else {
 714+ // Back button click
 715+ // Show the done message again
 716+ // Make them click back again if they want to do the upgrade again
 717+ $this->showDoneMessage();
 718+ return 'output';
 719+ }
 720+ }
 721+
 722+ // wgDBtype is generally valid here because otherwise the previous page
 723+ // (connect) wouldn't have declared its happiness
 724+ $type = $this->parent->getVar( 'wgDBtype' );
 725+ $installer = $this->parent->getDBInstaller( $type );
 726+
 727+ // There's no guarantee the connection will still succeed though
 728+ $conn = $installer->getConnection();
 729+ if ( $conn instanceof Status ) {
 730+ $this->startForm();
 731+ $this->showStatusErrorBox( $conn );
 732+ $this->endForm();
 733+ return 'output';
 734+ }
 735+
 736+ $ok = $conn->selectDB( $this->parent->getVar( 'wgDBname' ) );
 737+ if ( !$ok ) {
 738+ // No DB exists yet
 739+ return 'skip';
 740+ }
 741+ if ( !$conn->tableExists( 'cur' ) && !$conn->tableExists( 'revision' ) ) {
 742+ // Nothing to upgrade
 743+ return 'skip';
 744+ }
 745+
 746+ if ( $this->parent->request->wasPosted() ) {
 747+ if ( true || $installer->doUpgrade() ) {
 748+ $this->parent->setVar( '_UpgradeDone', true );
 749+ $this->showDoneMessage();
 750+ return 'output';
 751+ }
 752+ }
 753+
 754+ $this->startForm();
 755+ $this->parent->output->addHTML( $this->parent->getInfoBox(
 756+ array( 'config-can-upgrade', $GLOBALS['wgVersion'] ) ) );
 757+ $this->endForm();
 758+ }
 759+
 760+ function showDoneMessage() {
 761+ $this->startForm();
 762+ $this->parent->output->addHTML(
 763+ $this->parent->getInfoBox(
 764+ array(
 765+ 'config-upgrade-done',
 766+ $GLOBALS['wgServer'] .
 767+ $this->parent->getVar( 'wgScriptPath' ) . '/index' .
 768+ $this->parent->getVar( 'wgScriptExtension' )
 769+ ), 'tick-32.png'
 770+ )
 771+ );
 772+ $this->endForm( 'regenerate' );
 773+ }
 774+}
 775+
 776+class WebInstaller_DBSettings extends WebInstallerPage {
 777+ function execute() {
 778+ $installer = $this->parent->getDBInstaller( $this->parent->getVar( 'wgDBtype' ) );
 779+ $form = $installer->getSettingsForm();
 780+ if ( $form === false ) {
 781+ return 'skip';
 782+ }
 783+ $this->startForm();
 784+ $this->parent->output->addHTML( $form );
 785+ $this->endForm();
 786+ }
 787+
 788+}
 789+
 790+class WebInstaller_Identity extends WebInstallerPage {
 791+}
 792+class WebInstaller_License extends WebInstallerPage {
 793+}
 794+class WebInstaller_Email extends WebInstallerPage {
 795+}
 796+class WebInstaller_Install extends WebInstallerPage {
 797+}
 798+class WebInstaller_Complete extends WebInstallerPage {
 799+}
 800+class WebInstaller_Restart extends WebInstallerPage {
 801+ function execute() {
 802+ $r = $this->parent->request;
 803+ if ( $r->wasPosted() ) {
 804+ $really = $r->getVal( 'submit-restart' );
 805+ if ( $really ) {
 806+ $this->parent->session = array();
 807+ $this->parent->happyPages = array();
 808+ $this->parent->settings = array();
 809+ }
 810+ return 'continue';
 811+ }
 812+
 813+ $this->startForm();
 814+ $s = $this->parent->getWarningBox( 'config-help-restart' );
 815+ $this->parent->output->addHTML( $s );
 816+ $this->endForm( 'restart' );
 817+ }
 818+}
 819+
Property changes on: branches/new-installer/phase3/includes/installer/WebInstaller.php
___________________________________________________________________
Name: svn:eol-style
1820 + native
Index: branches/new-installer/phase3/includes/installer/WebInstallerOutput.php
@@ -0,0 +1,323 @@
 2+<?php
 3+
 4+/**
 5+ * Output class modelled on OutputPage.
 6+ *
 7+ * I've opted to use a distinct class rather than derive from OutputPage here in
 8+ * the interests of separation of concerns: if we used a subclass, there would be
 9+ * quite a lot of things you could do in OutputPage that would break the installer,
 10+ * that wouldn't be immediately obvious.
 11+ */
 12+class WebInstallerOutput {
 13+ var $parent;
 14+ var $contents = '';
 15+ var $headerDone = false;
 16+ var $redirectTarget;
 17+ var $debug = true;
 18+
 19+ function __construct( $parent ) {
 20+ $this->parent = $parent;
 21+ }
 22+
 23+ function addHTML( $html ) {
 24+ $this->contents .= $html;
 25+ $this->flush();
 26+ }
 27+
 28+ function addWikiText( $text ) {
 29+ $this->addHTML( $this->parent->parse( $text ) );
 30+ }
 31+
 32+ function addHTMLNoFlush( $html ) {
 33+ $this->contents .= $html;
 34+ }
 35+
 36+ function redirect( $url ) {
 37+ $this->redirectTarget = $url;
 38+ }
 39+
 40+ function output() {
 41+ $this->flush();
 42+ $this->outputFooter();
 43+ }
 44+
 45+ function flush() {
 46+ if ( !$this->headerDone ) {
 47+ $this->outputHeader();
 48+ }
 49+ if ( !$this->redirectTarget && strlen( $this->contents ) ) {
 50+ echo $this->contents;
 51+ flush();
 52+ $this->contents = '';
 53+ }
 54+ }
 55+
 56+ function outputHeader() {
 57+ global $wgVersion;
 58+ $this->headerDone = true;
 59+ $dbTypes = $this->parent->getDBTypes();
 60+
 61+ $this->parent->request->response()->header("Content-Type: text/html; charset=utf-8");
 62+ if ( $this->redirectTarget ) {
 63+ $this->parent->request->response()->header( 'Location: '.$this->redirectTarget );
 64+ return;
 65+ }
 66+
 67+
 68+?>
 69+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 70+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
 71+<head>
 72+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
 73+ <title>MediaWiki <?php echo( htmlspecialchars( $wgVersion ) ); ?> Installation</title>
 74+ <style type="text/css">
 75+
 76+ @import "../skins/monobook/main.css";
 77+
 78+ .env-check {
 79+ font-size: 90%;
 80+ margin: 1em 0 1em 2.5em;
 81+ }
 82+
 83+ .config-section {
 84+ margin-top: 2em;
 85+ }
 86+
 87+ .config-label {
 88+ clear: left;
 89+ font-weight: bold;
 90+ width: 10em;
 91+ float: left;
 92+ text-align: right;
 93+ padding-right: 1em;
 94+ padding-top: .2em;
 95+ }
 96+
 97+ .config-input {
 98+ clear: left;
 99+ zoom: 100%; /* IE hack */
 100+ }
 101+
 102+ .config-page-wrapper {
 103+ padding: 0.5em;
 104+ }
 105+
 106+ .config-page-list {
 107+ float: right;
 108+ width: 12em;
 109+ border: 1px solid #aaa;
 110+ padding: 0.5em;
 111+ margin: 0.5em;
 112+ }
 113+
 114+ .config-page {
 115+ padding: 0.5em 2em 0.5em 2em;
 116+ /* 15em right margin to leave space for 12em page list */
 117+ margin: 0.5em 15em 0.5em 0.5em;
 118+ border: 1px solid #aaa;
 119+ }
 120+
 121+ .config-submit {
 122+ clear: left;
 123+ text-align: center;
 124+ padding: 1em;
 125+ }
 126+
 127+ .config-submit input {
 128+ margin-left: 0.5em;
 129+ margin-right: 0.5em;
 130+ }
 131+
 132+ .config-page-disabled {
 133+ color: #aaa;
 134+ }
 135+
 136+ .config-info-left {
 137+ margin: 0.5em;
 138+ float: left;
 139+ width: 35px;
 140+ }
 141+
 142+ .config-info-right {
 143+ margin: 0.5em;
 144+ float: left;
 145+ width: 30em;
 146+ }
 147+
 148+ .config-page-current {
 149+ font-weight: bold;
 150+ }
 151+
 152+ .config-desc {
 153+ clear: left;
 154+ margin: 0 0 2em 12em;
 155+ padding-top: 1em;
 156+ font-size: 85%;
 157+ }
 158+
 159+ .config-message {
 160+ display: list-item;
 161+ line-height: 1.5em;
 162+ list-style-image: url(../skins/common/images/bullet.gif);
 163+ list-style-type: square;
 164+ }
 165+
 166+ .config-input-text {
 167+ width: 20em;
 168+ margin-right: 1em;
 169+ }
 170+
 171+ .config-input-check {
 172+ margin-left: 10em;
 173+ }
 174+
 175+ .error {
 176+ color: red;
 177+ background-color: #fff;
 178+ font-weight: bold;
 179+ left: 1em;
 180+ font-size: 100%;
 181+ }
 182+
 183+ .config-error-top {
 184+ background-color: #FFF0F0;
 185+ border: 2px solid red;
 186+ font-size: 110%;
 187+ font-weight: bold;
 188+ padding: 1em 1.5em;
 189+ margin: 2em 0 1em;
 190+ }
 191+
 192+ .config-settings-block {
 193+ list-style-type: none;
 194+ list-style-image: none;
 195+ float: left;
 196+ margin: 0;
 197+ padding: 0;
 198+ }
 199+
 200+ .btn-install {
 201+ font-weight: bold;
 202+ font-size: 110%;
 203+ padding: .2em .3em;
 204+ }
 205+
 206+ .license {
 207+ clear: both;
 208+ font-size: 85%;
 209+ padding-top: 3em;
 210+ }
 211+
 212+ .success-message {
 213+ font-weight: bold;
 214+ font-size: 110%;
 215+ color: green;
 216+ }
 217+ .success-box {
 218+ font-size: 130%;
 219+ }
 220+
 221+ </style>
 222+ <script type="text/javascript">
 223+ <!--
 224+<?php
 225+ echo "var dbTypes = " . Xml::encodeJsVar( $dbTypes ) . "\n";
 226+?>
 227+ function hideAllDBs() {
 228+ for ( var i = 0; i < dbTypes.length; i++ ) {
 229+ elt = document.getElementById( 'DB_wrapper_' + dbTypes[i] );
 230+ if ( elt ) elt.style.display = 'none';
 231+ }
 232+ }
 233+ function showDBArea(type) {
 234+ hideAllDBs();
 235+ var div = document.getElementById('DB_wrapper_' + type);
 236+ if (div) div.style.display = 'block';
 237+ }
 238+ function resetDBArea() {
 239+ for ( var i = 0; i < dbTypes.length; i++ ) {
 240+ input = document.getElementById('DBType_' + dbTypes[i]);
 241+ if ( input && input.checked ) {
 242+ showDBArea( dbTypes[i] );
 243+ return;
 244+ }
 245+ }
 246+ }
 247+ function disableControlArray( sourceID, targetIDs ) {
 248+ var source = document.getElementById( sourceID );
 249+ var disabled = source.checked ? '1' : '';
 250+ if ( !source ) {
 251+ return;
 252+ }
 253+ for ( var i = 0; i < targetIDs.length; i++ ) {
 254+ var elt = document.getElementById( targetIDs[i] );
 255+ if ( elt ) elt.disabled = disabled;
 256+ }
 257+ }
 258+ // -->
 259+ </script>
 260+</head>
 261+
 262+<body>
 263+<div id="globalWrapper">
 264+<div id="column-content">
 265+<div id="content">
 266+<div id="bodyContent">
 267+
 268+<h1>MediaWiki <?php print htmlspecialchars( $wgVersion ); ?> Installation</h1>
 269+<?php
 270+ }
 271+
 272+ function outputFooter() {
 273+?>
 274+ <div class="license">
 275+ <hr/>
 276+ <p>This program is free software; you can redistribute it and/or modify
 277+ it under the terms of the GNU General Public License as published by
 278+ the Free Software Foundation; either version 2 of the License, or
 279+ (at your option) any later version.</p>
 280+
 281+ <p>This program is distributed in the hope that it will be useful,
 282+ but WITHOUT ANY WARRANTY; without even the implied warranty of
 283+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 284+ GNU General Public License for more details.</p>
 285+
 286+ <p>You should have received <a href="../COPYING">a copy of the GNU General Public License</a>
 287+ along with this program; if not, write to the Free Software
 288+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 289+ or <a href="http://www.gnu.org/copyleft/gpl.html">read it online</a></p>
 290+ </div>
 291+
 292+</div></div></div>
 293+
 294+
 295+<div id="column-one">
 296+ <div class="portlet" id="p-logo">
 297+ <a style="background-image: url(../skins/common/images/mediawiki.png);"
 298+ href="http://www.mediawiki.org/"
 299+ title="Main Page"></a>
 300+ </div>
 301+ <script type="text/javascript"> if (window.isMSIE55) fixalpha(); </script>
 302+ <div class='portlet'><div class='pBody'>
 303+ <ul>
 304+ <li><strong><a href="http://www.mediawiki.org/">MediaWiki home</a></strong></li>
 305+ <li><a href="../README">Readme</a></li>
 306+ <li><a href="../RELEASE-NOTES">Release notes</a></li>
 307+ <li><a href="../docs/">Documentation</a></li>
 308+ <li><a href="http://www.mediawiki.org/wiki/Help:Contents">User's Guide</a></li>
 309+ <li><a href="http://www.mediawiki.org/wiki/Manual:Contents">Administrator's Guide</a></li>
 310+ <li><a href="http://www.mediawiki.org/wiki/Manual:FAQ">FAQ</a></li>
 311+ </ul>
 312+ <p style="font-size:90%;margin-top:1em">MediaWiki is Copyright © 2001-2008 by Magnus Manske, Brion Vibber,
 313+ Lee Daniel Crocker, Tim Starling, Erik Möller, Gabriel Wicke, Ævar Arnfjörð Bjarmason, Niklas Laxström,
 314+ Domas Mituzas, Rob Church, Yuri Astrakhan, Aryeh Gregor, Aaron Schulz and others.</p>
 315+ </div></div>
 316+</div>
 317+
 318+</div>
 319+
 320+</body>
 321+</html>
 322+<?php
 323+ }
 324+}
Property changes on: branches/new-installer/phase3/includes/installer/WebInstallerOutput.php
___________________________________________________________________
Name: svn:eol-style
1325 + native
Index: branches/new-installer/phase3/includes/installer/Installer.php
@@ -0,0 +1,557 @@
 2+<?php
 3+
 4+/**
 5+ * Base installer class
 6+ * Handles everything that is independent of user interface
 7+ */
 8+abstract class Installer {
 9+ var $settings, $output;
 10+
 11+ /**
 12+ * MediaWiki configuration globals that will eventually be passed through
 13+ * to LocalSettings.php. The names only are given here, the defaults
 14+ * typically come from DefaultSettings.php.
 15+ * @protected
 16+ */
 17+ var $defaultVarNames = array(
 18+ 'wgSitename',
 19+ 'wgPasswordSender',
 20+ 'wgLanguageCode',
 21+ 'wgRightsIcon',
 22+ 'wgRightsText',
 23+ 'wgRightsUrl',
 24+ 'wgMainCacheType',
 25+ 'wgEnableEmail',
 26+ 'wgEnableUserEmail',
 27+ 'wgEnotifUserTalk',
 28+ 'wgEnotifWatchlist',
 29+ 'wgDBtype',
 30+ 'wgDiff3',
 31+ 'wgImageMagickConvertCommand',
 32+ 'IP',
 33+ 'wgScriptPath',
 34+ 'wgScriptExtension',
 35+ );
 36+
 37+ /**
 38+ * Variables that are stored alongside globals, and are used for any
 39+ * configuration of the installation process aside from the MediaWiki
 40+ * configuration. Map of names to defaults.
 41+ * @protected
 42+ */
 43+ var $internalDefaults = array(
 44+ '_Environment' => false,
 45+ '_CompiledDBs' => array(),
 46+ '_SafeMode' => false,
 47+ '_RaiseMemory' => false,
 48+ '_UpgradeDone' => false,
 49+ '_Caches' => array(),
 50+ );
 51+
 52+ /**
 53+ * Known database types. These correspond to the class names <type>_Installer,
 54+ * and are also MediaWiki database types valid for $wgDBtype.
 55+ *
 56+ * To add a new type, create a <type>_Installer class and a Database<type>
 57+ * class, and add a config-type-<type> message to MessagesEn.php.
 58+ * @private
 59+ */
 60+ var $dbTypes = array(
 61+ 'mysql',
 62+ 'postgres',
 63+ 'sqlite'
 64+ );
 65+
 66+ /**
 67+ * Cached DB installer instances, access using getDBInstaller()
 68+ * @private
 69+ */
 70+ var $dbInstallers = array();
 71+
 72+ /**
 73+ * A list of environment check methods called by doEnvironmentChecks().
 74+ * These may output warnings using showMessage(), and/or abort the
 75+ * installation process by returning false.
 76+ * @protected
 77+ */
 78+ var $envChecks = array(
 79+ 'envCheckDB',
 80+ 'envCheckRegisterGlobals',
 81+ 'envCheckMagicQuotes',
 82+ 'envCheckMagicSybase',
 83+ 'envCheckMbstring',
 84+ 'envCheckZE1',
 85+ 'envCheckSafeMode',
 86+ 'envCheckXML',
 87+ 'envCheckPCRE',
 88+ 'envCheckMemory',
 89+ 'envCheckCache',
 90+ 'envCheckDiff3',
 91+ 'envCheckGraphics',
 92+ 'envCheckPath',
 93+ 'envCheckExtension',
 94+ );
 95+
 96+ /**
 97+ * Known object cache types and the functions used to test for their existence
 98+ * @protected
 99+ */
 100+ var $objectCaches = array(
 101+ 'turck' => 'mmcache_get',
 102+ 'xcache' => 'xcache_get',
 103+ 'apc' => 'apc_fetch',
 104+ 'eaccel' => 'eaccelerator_get'
 105+ );
 106+
 107+ /**
 108+ * Cached Title and ParserOptions used by parse()
 109+ * @private
 110+ */
 111+ var $parserTitle, $parserOptions;
 112+
 113+ /**
 114+ * Constructor, always call this from child classes
 115+ */
 116+ function __construct() {
 117+ $this->settings = $this->internalDefaults;
 118+ foreach ( $this->defaultVarNames as $var ) {
 119+ $this->settings[$var] = $GLOBALS[$var];
 120+ }
 121+ foreach ( $this->dbTypes as $type ) {
 122+ $installer = $this->getDBInstaller( $type );
 123+ if ( !$installer->isCompiled() ) {
 124+ continue;
 125+ }
 126+ $defaults = $installer->getGlobalDefaults();
 127+ foreach ( $installer->getGlobalNames() as $var ) {
 128+ if ( isset( $defaults[$var] ) ) {
 129+ $this->settings[$var] = $defaults[$var];
 130+ } else {
 131+ $this->settings[$var] = $GLOBALS[$var];
 132+ }
 133+ }
 134+ }
 135+
 136+ $this->parserTitle = Title::newFromText( 'Installer' );
 137+ $this->parserOptions = new ParserOptions;
 138+ $this->parserOptions->setEditSection( false );
 139+ }
 140+
 141+ /**
 142+ * UI interface for displaying a short message
 143+ * The parameters are like parameters to wfMsg().
 144+ * The messages will be in wikitext format, which will be converted to an
 145+ * output format such as HTML or text before being sent to the user.
 146+ */
 147+ abstract function showMessage( $msg /*, ... */ );
 148+
 149+ /**
 150+ * Get a list of known DB types
 151+ */
 152+ function getDBTypes() {
 153+ return $this->dbTypes;
 154+ }
 155+
 156+ /**
 157+ * Get an instance of InstallerDBType for the specified DB type
 158+ */
 159+ function getDBInstaller( $type ) {
 160+ if ( !isset( $this->dbInstallers[$type] ) ) {
 161+ $class = ucfirst( $type ). 'Installer';
 162+ $this->dbInstallers[$type] = new $class( $this );
 163+ }
 164+ return $this->dbInstallers[$type];
 165+ }
 166+
 167+ /**
 168+ * Do initial checks of the PHP environment. Set variables according to
 169+ * the observed environment.
 170+ *
 171+ * It's possible that this may be called under the CLI SAPI, not the SAPI
 172+ * that the wiki will primarily run under. In that case, the subclass should
 173+ * initialise variables such as wgScriptPath, before calling this function.
 174+ *
 175+ * Under the web subclass, it can already be assumed that PHP 5+ is in use
 176+ * and that sessions are working.
 177+ */
 178+ function doEnvironmentChecks() {
 179+ $this->showMessage( 'config-env-php', phpversion() );
 180+
 181+ $good = true;
 182+ foreach ( $this->envChecks as $check ) {
 183+ $status = $this->$check();
 184+ if ( $status === false ) {
 185+ $good = false;
 186+ }
 187+ }
 188+ $this->setVar( '_Environment', $good );
 189+ if ( $good ) {
 190+ $this->showMessage( 'config-env-good' );
 191+ } else {
 192+ $this->showMessage( 'config-env-bad' );
 193+ }
 194+ return $good;
 195+ }
 196+
 197+ /**
 198+ * Get an MW configuration variable, or internal installer configuration variable.
 199+ * The defaults come from $GLOBALS (ultimately DefaultSettings.php).
 200+ * Installer variables are typically prefixed by an underscore.
 201+ */
 202+ function getVar( $name, $default = null ) {
 203+ if ( !isset( $this->settings[$name] ) ) {
 204+ return $default;
 205+ } else {
 206+ return $this->settings[$name];
 207+ }
 208+ }
 209+
 210+ /**
 211+ * Set a MW configuration variable, or internal installer configuration variable.
 212+ */
 213+ function setVar( $name, $value ) {
 214+ $this->settings[$name] = $value;
 215+ }
 216+
 217+ /**
 218+ * Get a fake password for sending back to the user in HTML.
 219+ * This is a security mechanism to avoid compromise of the password in the
 220+ * event of session ID compromise.
 221+ */
 222+ function getFakePassword( $realPassword ) {
 223+ return str_repeat( '*', strlen( $realPassword ) );
 224+ }
 225+
 226+ /**
 227+ * Set a variable which stores a password, except if the new value is a
 228+ * fake password in which case leave it as it is.
 229+ */
 230+ function setPassword( $name, $value ) {
 231+ if ( !preg_match( '/^\*+$/', $value ) ) {
 232+ $this->setVar( $name, $value );
 233+ }
 234+ }
 235+
 236+ /**
 237+ * Returns true if dl() can be used
 238+ */
 239+ function haveDl() {
 240+ return function_exists( 'dl' )
 241+ && is_callable( 'dl' )
 242+ && wfIniGetBool( 'enable_dl' )
 243+ && !wfIniGetBool( 'safe_mode' );
 244+ }
 245+
 246+ /** Environment check for DB types */
 247+ function envCheckDB() {
 248+ $compiledDBs = array();
 249+ $haveDl = $this->haveDl();
 250+ $goodNames = array();
 251+ $allNames = array();
 252+ foreach ( $this->dbTypes as $name ) {
 253+ $db = $this->getDBInstaller( $name );
 254+ $readableName = wfMsg( 'config-type-' . $name );
 255+ if ( $db->isCompiled() ) {
 256+ $compiledDBs[$name] = true;
 257+ $goodNames[] = $readableName;
 258+ }
 259+ $allNames[] = $readableName;
 260+ }
 261+ $this->setVar( '_CompiledDBs', $compiledDBs );
 262+
 263+ global $wgLang;
 264+ if ( !$compiledDBs ) {
 265+ $this->showMessage( 'config-no-db' );
 266+ $this->showHelpBox( 'config-no-db-help', $wgLang->commaList( $allNames ) );
 267+ return false;
 268+ }
 269+ $this->showMessage( 'config-have-db', $wgLang->commaList( $goodNames ) );
 270+ }
 271+
 272+ /** Environment check for register_globals */
 273+ function envCheckRegisterGlobals() {
 274+ if( wfIniGetBool( "magic_quotes_runtime" ) ) {
 275+ $this->showMessage( 'config-register-globals' );
 276+ }
 277+ }
 278+
 279+ /** Environment check for magic_quotes_runtime */
 280+ function envCheckMagicQuotes() {
 281+ if( wfIniGetBool( "magic_quotes_runtime" ) ) {
 282+ $this->showMessage( 'config-magic-quotes-runtime' );
 283+ return false;
 284+ }
 285+ }
 286+
 287+ /** Environment check for magic_quotes_sybase */
 288+ function envCheckMagicSybase() {
 289+ if ( wfIniGetBool( 'magic_quotes_sybase' ) ) {
 290+ $this->showMessage( 'config-magic-quotes-sybase' );
 291+ return false;
 292+ }
 293+ }
 294+
 295+ /* Environment check for mbstring.func_overload */
 296+ function envCheckMbstring() {
 297+ if ( wfIniGetBool( 'mbstring.func_overload' ) ) {
 298+ $this->showMessage( 'config-mbstring' );
 299+ return false;
 300+ }
 301+ }
 302+
 303+ /** Environment check for zend.ze1_compatibility_mode */
 304+ function envCheckZE1() {
 305+ if ( wfIniGetBool( 'zend.ze1_compatibility_mode' ) ) {
 306+ $this->showMessage( 'config-ze1' );
 307+ return false;
 308+ }
 309+ }
 310+
 311+ /** Environment check for safe_mode */
 312+ function envCheckSafeMode() {
 313+ if ( wfIniGetBool( 'safe_mode' ) ) {
 314+ $this->setVar( '_SafeMode', true );
 315+ $this->showMessage( 'config-safe-mode' );
 316+ }
 317+ }
 318+
 319+ /** Environment check for the XML module */
 320+ function envCheckXML() {
 321+ if ( !function_exists( "utf8_encode" ) ) {
 322+ $this->showMessage( 'config-xml-bad' );
 323+ return false;
 324+ }
 325+ $this->showMessage( 'config-xml-good' );
 326+ }
 327+
 328+ /** Environment check for the PCRE module */
 329+ function envCheckPCRE() {
 330+ if ( !function_exists( 'preg_match' ) ) {
 331+ $this->showMessage( 'config-pcre' );
 332+ return false;
 333+ }
 334+ }
 335+
 336+ /** Environment check for available memory */
 337+ function envCheckMemory() {
 338+ $limit = ini_get( 'memory_limit' );
 339+ if ( !$limit || $limit == -1 ) {
 340+ $this->showMessage( 'config-memory-none' );
 341+ return true;
 342+ }
 343+ $n = intval( $limit );
 344+ if( preg_match( '/^([0-9]+)[Mm]$/', trim( $limit ), $m ) ) {
 345+ $n = intval( $m[1] * (1024*1024) );
 346+ }
 347+ if( $n < 20*1024*1024 ) {
 348+ if( false === ini_set( "memory_limit", "20M" ) ) {
 349+ $this->showMessage( 'config-memory-bad', $limit );
 350+ } else {
 351+ $this->showMessage( 'config-memory-raised', $limit );
 352+ $this->setVar( '_RaiseMemory', true );
 353+ }
 354+ } else {
 355+ $this->showMessage( 'config-memory-ok', $limit );
 356+ }
 357+ }
 358+
 359+ /** Environment check for compiled object cache types */
 360+ function envCheckCache() {
 361+ $caches = array();
 362+ foreach ( $this->objectCaches as $name => $function ) {
 363+ if ( function_exists( $function ) ) {
 364+ $caches[$name] = true;
 365+ $this->showMessage( 'config-' . $name );
 366+ }
 367+ }
 368+ if ( !$caches ) {
 369+ $this->showMessage( 'config-no-cache' );
 370+ }
 371+ if ( function_exists( 'dba_open' ) ) {
 372+ $caches['dba'] = true;
 373+ }
 374+ $this->setVar( '_Caches', $caches );
 375+ }
 376+
 377+ /** Search for GNU diff3 */
 378+ function envCheckDiff3() {
 379+ $paths = array_merge(
 380+ array(
 381+ "/usr/bin",
 382+ "/usr/local/bin",
 383+ "/opt/csw/bin",
 384+ "/usr/gnu/bin",
 385+ "/usr/sfw/bin" ),
 386+ explode( PATH_SEPARATOR, getenv( "PATH" ) ) );
 387+ $names = array( "gdiff3", "diff3", "diff3.exe" );
 388+
 389+ $versionInfo = array( '$1 --version 2>&1', 'diff3 (GNU diffutils)' );
 390+ $haveDiff3 = false;
 391+ foreach ( $paths as $path ) {
 392+ $exe = $this->locateExecutable( $path, $names, $versionInfo );
 393+ if ($exe !== false) {
 394+ $this->setVar( 'wgDiff3', $exe );
 395+ $haveDiff3 = true;
 396+ break;
 397+ }
 398+ }
 399+ if ( $haveDiff3 ) {
 400+ $this->showMessage( 'config-diff3-good', $exe );
 401+ } else {
 402+ $this->setVar( 'wgDiff3', false );
 403+ $this->showMessage( 'config-diff3-bad' );
 404+ }
 405+ }
 406+
 407+ /**
 408+ * Search a path for any of the given executable names. Returns the
 409+ * executable name if found. Also checks the version string returned
 410+ * by each executable
 411+ *
 412+ * @param string $path Path to search
 413+ * @param array $names Array of executable names
 414+ * @param string $versionInfo Array with two members:
 415+ * 0 => Command to run for version check, with $1 for the path
 416+ * 1 => String to compare the output with
 417+ *
 418+ * If $versionInfo is not false, only executables with a version
 419+ * matching $versionInfo[1] will be returned.
 420+ */
 421+ function locateExecutable( $path, $names, $versionInfo = false ) {
 422+ if (!is_array($names))
 423+ $names = array($names);
 424+
 425+ foreach ($names as $name) {
 426+ $command = "$path/$name";
 427+ if ( @file_exists( $command ) ) {
 428+ if ( !$versionInfo )
 429+ return $command;
 430+
 431+ $file = str_replace( '$1', $command, $versionInfo[0] );
 432+ if ( strstr( wfShellExec( $file ), $versionInfo[1]) !== false )
 433+ return $command;
 434+ }
 435+ }
 436+ return false;
 437+ }
 438+
 439+ /** Environment check for ImageMagick and GD */
 440+ function envCheckGraphics() {
 441+ $imcheck = array( "/usr/bin", "/opt/csw/bin", "/usr/local/bin", "/sw/bin", "/opt/local/bin" );
 442+ foreach( $imcheck as $dir ) {
 443+ $im = "$dir/convert";
 444+ if( @file_exists( $im ) ) {
 445+ $this->showMessage( 'config-imagemagick', $im );
 446+ $this->setVar( 'wgImageMagickConvertCommand', $im );
 447+ return true;
 448+ }
 449+ }
 450+ if ( function_exists( 'imagejpeg' ) ) {
 451+ $this->showMessage( 'config-gd' );
 452+ return true;
 453+ }
 454+ $this->showMessage( 'no-scaling' );
 455+ }
 456+
 457+ /** Environment check for setting $IP and $wgScriptPath */
 458+ function envCheckPath() {
 459+ $IP = dirname( dirname( dirname( __FILE__ ) ) );
 460+ $this->setVar( 'IP', $IP );
 461+ $this->showMessage( 'config-dir', $IP );
 462+
 463+ // PHP_SELF isn't available sometimes, such as when PHP is CGI but
 464+ // cgi.fix_pathinfo is disabled. In that case, fall back to SCRIPT_NAME
 465+ // to get the path to the current script... hopefully it's reliable. SIGH
 466+ if ( !empty( $_SERVER['PHP_SELF'] ) ) {
 467+ $path = $_SERVER['PHP_SELF'];
 468+ } elseif ( !empty( $_SERVER['SCRIPT_NAME'] ) ) {
 469+ $path = $_SERVER['SCRIPT_NAME'];
 470+ } elseif ( $this->getVar( 'wgScriptPath' ) ) {
 471+ // Some kind soul has set it for us already (e.g. debconf)
 472+ return true;
 473+ } else {
 474+ $this->showMessage( 'config-no-uri' );
 475+ return false;
 476+ }
 477+ $uri = preg_replace( '{^(.*)/config.*$}', '$1', $path );
 478+ $this->setVar( 'wgScriptPath', $uri );
 479+ $this->showMessage( 'config-uri', $uri );
 480+ }
 481+
 482+ abstract function showStatusError( $status );
 483+
 484+ /** Environment check for setting the preferred PHP file extension */
 485+ function envCheckExtension() {
 486+ // FIXME: detect this properly
 487+ if ( defined( 'MW_INSTALL_PHP5_EXT' ) ) {
 488+ $ext = 'php5';
 489+ } else {
 490+ $ext = 'php';
 491+ }
 492+ $this->setVar( 'wgScriptExtension', ".$ext" );
 493+ $this->showMessage( 'config-extension', $ext );
 494+ }
 495+
 496+ /**
 497+ * Convert wikitext $text to HTML.
 498+ *
 499+ * This is potentially error prone since many parser features require a complete
 500+ * installed MW database. The solution is to just not use those features when you
 501+ * write your messages. This appears to work well enough. Basic formatting and
 502+ * external links work just fine.
 503+ *
 504+ * But in case a translator decides to throw in a #ifexist or internal link or
 505+ * whatever, this function is guarded to catch attempted DB access and to present
 506+ * some fallback text.
 507+ *
 508+ * @param string $text
 509+ * @return string
 510+ */
 511+ function parse( $text ) {
 512+ global $wgParser;
 513+ try {
 514+ $out = $wgParser->parse( $text, $this->parserTitle, $this->parserOptions, false );
 515+ $html = $out->getText();
 516+ } catch ( InstallerDBAccessError $e ) {
 517+ $html = '<!--DB access attempted during parse--> ' . htmlspecialchars( $text );
 518+ if ( $this->debug ) {
 519+ $html .= "<!--\n" . $e->getTraceAsString() . "\n-->";
 520+ }
 521+ }
 522+ return $html;
 523+ }
 524+}
 525+
 526+/**
 527+ * Exception class for attempted DB access
 528+ */
 529+class InstallerDBAccessError extends MWException {
 530+ function __construct() {
 531+ parent::__construct( "The installer attempted to access the DB via wfGetDB(). This is not allowed." );
 532+ }
 533+}
 534+
 535+/**
 536+ * LBFactory class that throws an error on any attempt to use it.
 537+ * This will typically be done via wfGetDB().
 538+ * Installer entry points should ensure that they set up $wgLBFactoryConf to
 539+ * array( 'class' => 'LBFactory_InstallerFake' )
 540+ */
 541+class LBFactory_InstallerFake extends LBFactory {
 542+ function __construct( $conf ) {}
 543+
 544+ function newMainLB( $wiki = false) {
 545+ throw new InstallerDBAccessError;
 546+ }
 547+ function getMainLB( $wiki = false ) {
 548+ throw new InstallerDBAccessError;
 549+ }
 550+ function newExternalLB( $cluster, $wiki = false ) {
 551+ throw new InstallerDBAccessError;
 552+ }
 553+ function &getExternalLB( $cluster, $wiki = false ) {
 554+ throw new InstallerDBAccessError;
 555+ }
 556+ function forEachLB( $callback, $params = array() ) {}
 557+}
 558+
Property changes on: branches/new-installer/phase3/includes/installer/Installer.php
___________________________________________________________________
Name: svn:eol-style
1559 + native
Index: branches/new-installer/phase3/includes/installer/SqliteInstaller.php
@@ -0,0 +1,71 @@
 2+<?php
 3+
 4+class SqliteInstaller extends InstallerDBType {
 5+ var $globalNames = array(
 6+ 'wgDBname',
 7+ 'wgSQLiteDataDir'
 8+ );
 9+
 10+ function getName() {
 11+ return 'sqlite';
 12+ }
 13+
 14+ function isCompiled() {
 15+ return $this->checkExtension( 'pdo_sqlite' );
 16+ }
 17+
 18+ function getGlobalNames() {
 19+ return $this->globalNames;
 20+ }
 21+
 22+ function getGlobalDefaults() {
 23+ if ( isset( $_SERVER['DOCUMENT_ROOT'] ) ) {
 24+ return array( 'wgSQLiteDataDir' => dirname( $_SERVER['DOCUMENT_ROOT'] ) . '/data' );
 25+ } else {
 26+ return array();
 27+ }
 28+ }
 29+
 30+ function getConnectForm() {
 31+ return
 32+ $this->getLabelledTextBox( 'wgSQLiteDataDir', 'config-sqlite-dir' ) .
 33+ $this->parent->getHelpBox( 'config-sqlite-dir-help' ) .
 34+ $this->getLabelledTextBox( 'wgDBname', 'config-db-name' ) .
 35+ $this->parent->getHelpBox( 'config-sqlite-name-help' );
 36+ }
 37+
 38+ function submitConnectForm() {
 39+ global $wgSQLiteDataDirMode, $wgSQLiteDataDir;
 40+ $newValues = $this->setVarsFromRequest();
 41+ $dir = $newValues['wgSQLiteDataDir'];
 42+ if ( !is_dir( $dir ) ) {
 43+ if ( !is_writable( dirname( $dir ) ) ) {
 44+ return Status::newFatal( 'config-sqlite-parent-unwritable', $dir, dirname( $dir ) );
 45+ }
 46+ wfSuppressWarnings();
 47+ $ok = wfMkdirParents( $dir, $wgSQLiteDataDirMode );
 48+ wfRestoreWarnings();
 49+ if ( !$ok ) {
 50+ return Status::newFatal( 'config-sqlite-mkdir-error', $dir );
 51+ }
 52+ # Put a .htaccess file in in case the user didn't take our advice
 53+ file_put_contents( "$dir/.htaccess", "Deny from all\n" );
 54+ }
 55+ if ( !is_writable( $dir ) ) {
 56+ return Status::newFatal( 'config-sqlite-unwritable', $dir );
 57+ }
 58+ return Status::newGood();
 59+ /* -- during install:
 60+ $status = Status::newGood();
 61+ try {
 62+ # FIXME: need more sensible constructor parameters, e.g. single associative array
 63+ # Setting globals kind of sucks
 64+ $wgSQLiteDataDir = $dir;
 65+ $this->conn = new DatabaseSqlite( false, false, false, $newValues['wgDBname'] );
 66+ } catch ( DBConnectionError $e ) {
 67+ $status->fatal( 'config-sqlite-connection-error', $e->getMessage() );
 68+ }
 69+ return $status;
 70+ */
 71+ }
 72+}
Property changes on: branches/new-installer/phase3/includes/installer/SqliteInstaller.php
___________________________________________________________________
Name: svn:eol-style
173 + native
Index: branches/new-installer/phase3/includes/installer/MysqlInstaller.php
@@ -0,0 +1,197 @@
 2+<?php
 3+
 4+class MysqlInstaller extends InstallerDBType {
 5+ var $globalNames = array(
 6+ 'wgDBserver',
 7+ 'wgDBname',
 8+ 'wgDBuser',
 9+ 'wgDBpassword',
 10+ 'wgDBprefix',
 11+ 'wgDBTableOptions',
 12+ 'wgDBmysql5',
 13+ );
 14+
 15+ var $internalDefaults = array(
 16+ '_MysqlInstallUser' => 'root',
 17+ '_MysqlInstallPassword' => '',
 18+ '_MysqlSameAccount' => true,
 19+ );
 20+
 21+ var $minimumVersion = '4.0.14';
 22+
 23+ var $conn;
 24+
 25+ function getName() {
 26+ return 'mysql';
 27+ }
 28+
 29+ function isCompiled() {
 30+ return $this->checkExtension( 'mysql' );
 31+ }
 32+
 33+ function getGlobalNames() {
 34+ return $this->globalNames;
 35+ }
 36+
 37+ function getGlobalDefaults() {
 38+ return array();
 39+ }
 40+
 41+ function getInternalDefaults() {
 42+ return $this->internalDefaults;
 43+ }
 44+
 45+ function getConnectForm() {
 46+ return
 47+ $this->getLabelledTextBox( 'wgDBserver', 'config-db-host' ) .
 48+ $this->parent->getHelpBox( 'config-db-host-help' ) .
 49+ Xml::openElement( 'fieldset' ) .
 50+ Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
 51+ $this->getLabelledTextBox( 'wgDBname', 'config-db-name' ) .
 52+ $this->parent->getHelpBox( 'config-db-name-help' ) .
 53+ $this->getLabelledTextBox( 'wgDBprefix', 'config-db-prefix' ) .
 54+ $this->parent->getHelpBox( 'config-db-prefix-help' ) .
 55+ Xml::closeElement( 'fieldset' ) .
 56+ Xml::openElement( 'fieldset' ) .
 57+ Xml::element( 'legend', array(), wfMsg( 'config-db-install-account' ) ) .
 58+ $this->getLabelledTextBox( '_MysqlInstallUser', 'config-db-username' ) .
 59+ $this->getLabelledPasswordBox( '_MysqlInstallPassword', 'config-db-password' ) .
 60+ $this->parent->getHelpBox( 'config-db-install-help' ) .
 61+ Xml::closeElement( 'fieldset' );
 62+ }
 63+
 64+ function submitConnectForm() {
 65+ // Get variables from the request
 66+ $newValues = $this->setVarsFromRequest();
 67+
 68+ // Validate them
 69+ $status = Status::newGood();
 70+ if ( !strlen( $newValues['wgDBname'] ) ) {
 71+ $status->fatal( 'config-missing-db-name' );
 72+ } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) {
 73+ $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] );
 74+ }
 75+ if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBprefix'] ) ) {
 76+ $status->fatal( 'config-invalid-db-prefix', $newValues['wgDBprefix'] );
 77+ }
 78+ if ( !$status->isOK() ) {
 79+ return $status;
 80+ }
 81+
 82+ // Try to connect
 83+ $status = $this->attemptConnection();
 84+ if ( !$status->isOK() ) {
 85+ return $status;
 86+ }
 87+
 88+ // Check version
 89+ $version = $this->conn->getServerVersion();
 90+ if ( version_compare( $version, $this->minimumVersion ) < 0 ) {
 91+ return Status::newFatal( 'config-mysql-old', $this->minimumVersion, $version );
 92+ }
 93+
 94+ return $status;
 95+ }
 96+
 97+ function attemptConnection() {
 98+ $status = Status::newGood();
 99+ try {
 100+ $this->conn = new Database(
 101+ $this->getVar( 'wgDBserver' ),
 102+ $this->getVar( '_MysqlInstallUser' ),
 103+ $this->getVar( '_MysqlInstallPassword' ),
 104+ false,
 105+ false,
 106+ 0,
 107+ $this->getVar( 'wgDBprefix' )
 108+ );
 109+ } catch ( DBConnectionError $e ) {
 110+ $status->fatal( 'config-connection-error', $e->getMessage() );
 111+ }
 112+ return $status;
 113+ }
 114+
 115+ function getConnection() {
 116+ $status = $this->attemptConnection();
 117+ if ( $status->isOK() ) {
 118+ return $this->conn;
 119+ } else {
 120+ return $status;
 121+ }
 122+ }
 123+
 124+ function doUpgrade() {
 125+ $conn = $this->getConnection();
 126+ if ( $conn instanceof Status ) {
 127+ $this->parent->showStatusError( $conn );
 128+ return;
 129+ }
 130+
 131+ # Determine existing default character set
 132+ if ( $conn->tableExists( "revision" ) ) {
 133+ $revision = $conn->escapeLike( $this->getVar( 'wgDBprefix' ) . 'revision' );
 134+ $res = $conn->query( "SHOW TABLE STATUS LIKE '$revision'" );
 135+ $row = $conn->fetchObject( $res );
 136+ if ( !$row ) {
 137+ $this->parent->showMessage( 'config-show-table-status' );
 138+ $existingSchema = false;
 139+ $existingEngine = false;
 140+ } else {
 141+ if ( preg_match( '/^latin1/', $row->Collation ) ) {
 142+ $existingSchema = 'mysql4';
 143+ } elseif ( preg_match( '/^utf8/', $row->Collation ) ) {
 144+ $existingSchema = 'mysql5';
 145+ } elseif ( preg_match( '/^binary/', $row->Collation ) ) {
 146+ $existingSchema = 'mysql5-binary';
 147+ } else {
 148+ $existingSchema = false;
 149+ $this->parent->showMessage( 'config-unknown-collation' );
 150+ }
 151+ if ( isset( $row->Engine ) ) {
 152+ $existingEngine = $row->Engine;
 153+ } else {
 154+ $existingEngine = $row->Type;
 155+ }
 156+ }
 157+ }
 158+
 159+ // TODO...
 160+ return;
 161+
 162+ # Create user if required
 163+ if ( $conf->Root ) {
 164+ $conn = $dbc->newFromParams( $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, 1 );
 165+ if ( $conn->isOpen() ) {
 166+ print "<li>DB user account ok</li>\n";
 167+ $conn->close();
 168+ } else {
 169+ print "<li>Granting user permissions...";
 170+ if( $mysqlOldClient && $mysqlNewAuth ) {
 171+ print " <b class='error'>If the next step fails, see <a href='http://dev.mysql.com/doc/mysql/en/old-client.html'>http://dev.mysql.com/doc/mysql/en/old-client.html</a> for help.</b>";
 172+ }
 173+ print "</li>\n";
 174+ dbsource( "../maintenance/users.sql", $conn );
 175+ }
 176+ }
 177+ }
 178+
 179+ function getSettingsForm() {
 180+ $installUser = $this->getVar( '_MysqlInstallUser' );
 181+ $installPass = $this->parent->getFakePassword( $this->getVar( '_MysqlInstallPassword' ) );
 182+ $js = 'disableControlArray( "mysql__MysqlSameAccount", ' .
 183+ '["mysql_wgDBuser", "mysql_wgDBpassword"] )';
 184+
 185+ return
 186+ Xml::openElement( 'fieldset' ) .
 187+ Xml::element( 'legend', array(), wfMsg( 'config-db-web-account' ) ) .
 188+ $this->getLabelledCheckBox(
 189+ '_MysqlSameAccount', 'config-db-web-account-same', array( 'onclick' => $js )
 190+ ) .
 191+ "<br/>\n" .
 192+ $this->getLabelledTextBox( 'wgDBuser', 'config-db-username' ) .
 193+ $this->getLabelledPasswordBox( 'wgDBpassword', 'config-db-password' ) .
 194+ $this->parent->getHelpBox( 'config-db-web-help' ) .
 195+ Xml::closeElement( 'fieldset' ) .
 196+ "<script type=\"text/javascript\">$js</script>";
 197+ }
 198+}
Property changes on: branches/new-installer/phase3/includes/installer/MysqlInstaller.php
___________________________________________________________________
Name: svn:eol-style
1199 + native
Index: branches/new-installer/phase3/includes/installer/PostgresInstaller.php
@@ -0,0 +1,110 @@
 2+<?php
 3+
 4+class PostgresInstaller extends InstallerDBType {
 5+
 6+ var $globalNames = array(
 7+ 'wgDBserver',
 8+ 'wgDBport',
 9+ 'wgDBname',
 10+ 'wgDBuser',
 11+ 'wgDBpassword',
 12+ 'wgDBmwschema',
 13+ 'wgDBts2schema',
 14+ );
 15+
 16+ var $internalDefaults = array(
 17+ '_PostgresInstallUser' => 'postgres',
 18+ '_PostgresInstallPassword' => '',
 19+ );
 20+
 21+ var $minimumVersion = '8.1';
 22+
 23+ var $conn;
 24+
 25+ function getName() {
 26+ return 'postgres';
 27+ }
 28+
 29+ function isCompiled() {
 30+ return $this->checkExtension( 'pgsql' );
 31+ }
 32+
 33+ function getGlobalNames() {
 34+ return $this->globalNames;
 35+ }
 36+
 37+ function getInternalDefaults() {
 38+ return $this->internalDefaults;
 39+ }
 40+
 41+ function getConnectForm() {
 42+ return
 43+ $this->getLabelledTextBox( 'wgDBserver', 'config-db-host' ) .
 44+ $this->parent->getHelpBox( 'config-db-host-help' ) .
 45+ $this->getLabelledTextBox( 'wgDBport', 'config-db-port' ) .
 46+ Xml::openElement( 'fieldset' ) .
 47+ Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
 48+ $this->getLabelledTextBox( 'wgDBname', 'config-db-name' ) .
 49+ $this->parent->getHelpBox( 'config-db-name-help' ) .
 50+ $this->getLabelledTextBox( 'wgDBmwschema', 'config-db-schema' ) .
 51+ $this->getLabelledTextBox( 'wgDBts2schema', 'config-db-ts2-schema' ) .
 52+ $this->parent->getHelpBox( 'config-db-schema-help' ) .
 53+ Xml::closeElement( 'fieldset' ) .
 54+ Xml::openElement( 'fieldset' ) .
 55+ Xml::element( 'legend', array(), wfMsg( 'config-db-install-account' ) ) .
 56+ $this->getLabelledTextBox( '_PostgresInstallUser', 'config-db-username' ) .
 57+ $this->getLabelledPasswordBox( '_PostgresInstallPassword', 'config-db-password' ) .
 58+ $this->parent->getHelpBox( 'config-db-install-help' ) .
 59+ Xml::closeElement( 'fieldset' );
 60+ }
 61+
 62+ function submitConnectForm() {
 63+ // Get variables from the request
 64+ $newValues = $this->setVarsFromRequest();
 65+
 66+ // Validate them
 67+ $status = Status::newGood();
 68+ if ( !strlen( $newValues['wgDBname'] ) ) {
 69+ $status->fatal( 'config-missing-db-name' );
 70+ } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) {
 71+ $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] );
 72+ }
 73+ if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBmwschema'] ) ) {
 74+ $status->fatal( 'config-invalid-schema', $newValues['wgDBmwschema'] );
 75+ }
 76+ if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBts2schema'] ) ) {
 77+ $status->fatal( 'config-invalid-ts2schema', $newValues['wgDBts2schema'] );
 78+ }
 79+
 80+ // Try to connect
 81+ if ( $status->isOK() ) {
 82+ $status->merge( $this->attemptConnection() );
 83+ }
 84+ if ( !$status->isOK() ) {
 85+ return $status;
 86+ }
 87+
 88+ // Check version
 89+ $version = $this->conn->getServerVersion();
 90+ if ( version_compare( $version, $this->minimumVersion ) < 0 ) {
 91+ return Status::newFatal( 'config-postgres-old', $this->minimumVersion, $version );
 92+ }
 93+ return $status;
 94+ }
 95+
 96+ function attemptConnection() {
 97+ $status = Status::newGood();
 98+
 99+ try {
 100+ $this->conn = new DatabasePostgres(
 101+ $this->getVar( 'wgDBserver' ),
 102+ $this->getVar( '_PostgresInstallUser' ),
 103+ $this->getVar( '_PostgresInstallPassword' ),
 104+ 'postgres' );
 105+ } catch ( DBConnectionError $e ) {
 106+ $status->fatal( 'config-connection-error', $e->getMessage() );
 107+ }
 108+ return $status;
 109+ }
 110+
 111+}
Property changes on: branches/new-installer/phase3/includes/installer/PostgresInstaller.php
___________________________________________________________________
Name: svn:eol-style
1112 + native
Index: branches/new-installer/phase3/includes/installer/InstallerDBType.php
@@ -0,0 +1,163 @@
 2+<?php
 3+
 4+/**
 5+ * Base class for DBMS-specific installation helper classes
 6+ */
 7+abstract class InstallerDBType {
 8+ /** The Installer object */
 9+ var $parent;
 10+
 11+ /**
 12+ * Construct and initialise parent.
 13+ * This is typically only called from Installer::getDBInstaller()
 14+ */
 15+ function __construct( $parent ) {
 16+ $this->parent = $parent;
 17+ }
 18+
 19+ /**
 20+ * Convenience function
 21+ * Check if a named extension is present
 22+ */
 23+ function checkExtension( $name ) {
 24+ wfSuppressWarnings();
 25+ $compiled = extension_loaded( $name )
 26+ || ( $this->parent->haveDl() && dl( $name . '.' . PHP_SHLIB_SUFFIX ) );
 27+ wfRestoreWarnings();
 28+ return $compiled;
 29+ }
 30+
 31+ /**
 32+ * Return the internal name, e.g. 'mysql', or 'sqlite'
 33+ */
 34+ abstract function getName();
 35+
 36+ /**
 37+ * Get the internationalised name for this DBMS
 38+ */
 39+ function getReadableName() {
 40+ return wfMsg( 'config-type-' . $this->getName() );
 41+ }
 42+
 43+ /**
 44+ * @return true if the client library is compiled in
 45+ */
 46+ abstract function isCompiled();
 47+
 48+ /**
 49+ * Get an array of MW configuration globals that will be configured by this class.
 50+ */
 51+ abstract function getGlobalNames();
 52+
 53+ /**
 54+ * Get a name=>value map of MW configuration globals that overrides
 55+ * DefaultSettings.php
 56+ */
 57+ function getGlobalDefaults() {
 58+ return array();
 59+ }
 60+
 61+ /**
 62+ * Get a name=>value map of internal variables used during installation
 63+ */
 64+ function getInternalDefaults() {
 65+ return array();
 66+ }
 67+
 68+ /**
 69+ * Get HTML for a web form that configures this database
 70+ * If this is called, $this->parent can be assumed to be a WebInstaller
 71+ */
 72+ abstract function getConnectForm();
 73+
 74+ /**
 75+ * Set variables based on the request array, assuming it was submitted
 76+ * via the form returned by getConnectForm()
 77+ * If this is called, $this->parent can be assumed to be a WebInstaller
 78+ */
 79+ abstract function submitConnectForm();
 80+
 81+ /**
 82+ * Get a variable, taking local defaults into account
 83+ */
 84+ function getVar( $var, $default = null ) {
 85+ $defaults = $this->getGlobalDefaults();
 86+ $internal = $this->getInternalDefaults();
 87+ if ( isset( $defaults[$var] ) ) {
 88+ $default = $defaults[$var];
 89+ } elseif ( isset( $internal[$var] ) ) {
 90+ $default = $internal[$var];
 91+ }
 92+ return $this->parent->getVar( $var, $default );
 93+ }
 94+
 95+ /**
 96+ * Convenience function for a labelled text box to configure a variable
 97+ */
 98+ function getLabelledTextBox( $var, $label ) {
 99+ $name = $this->getName() . '_' . $var;
 100+ $value = $this->getVar( $var );
 101+ return
 102+ "<div class=\"config-input\">\n" .
 103+ $this->parent->getLabel( $label, $name ) .
 104+ $this->parent->getTextBox( $name, $value ) .
 105+ "</div>\n";
 106+ }
 107+
 108+ /**
 109+ * Convenience function for a labelled password box.
 110+ * Implements password hiding
 111+ */
 112+ function getLabelledPasswordBox( $var, $label ) {
 113+ $name = $this->getName() . '_' . $var;
 114+ $realPassword = $this->getVar( $var );
 115+ if ( strlen( $var ) ) {
 116+ $fakeValue = $this->parent->getFakePassword( $realPassword );
 117+ } else {
 118+ $fakeValue = '';
 119+ }
 120+ return
 121+ "<div class=\"config-input\">\n" .
 122+ $this->parent->getLabel( $label, $name ) .
 123+ $this->parent->getTextBox( $name, $fakeValue, 'password' ) .
 124+ "</div>\n";
 125+ }
 126+
 127+ /**
 128+ * Convenience function for a labelled checkbox
 129+ */
 130+ function getLabelledCheckBox( $var, $label, $attribs = array() ) {
 131+ $name = $this->getName() . '_' . $var;
 132+ $value = $this->getVar( $var );
 133+ return
 134+ "<div class=\"config-input-check\">\n" .
 135+ "<label>\n" .
 136+ $this->parent->getCheckBox( $name, $value, $attribs ) . "\n" .
 137+ wfMsgHtml( $label ) . "\n" .
 138+ "</label>\n" .
 139+ "</div>\n";
 140+ }
 141+
 142+ /**
 143+ * Convenience function to set variables based on form data
 144+ * Has some heuristics that may need to be overridden in child classes.
 145+ */
 146+ function setVarsFromRequest() {
 147+ $newValues = array();
 148+ $varNames = array_merge( $this->getGlobalNames(),
 149+ array_keys( $this->getInternalDefaults() ) );
 150+ foreach ( $varNames as $name ) {
 151+ $value = $this->parent->request->getVal( $this->getName() . '_' . $name );
 152+ $newValues[$name] = $value;
 153+ if ( $value !== null ) {
 154+ if ( stripos( $name, 'password' ) !== false ) {
 155+ $this->parent->setPassword( $name, $value );
 156+ } else {
 157+ $this->parent->setVar( $name, $value );
 158+ }
 159+ }
 160+ }
 161+ return $newValues;
 162+ }
 163+}
 164+
Property changes on: branches/new-installer/phase3/includes/installer/InstallerDBType.php
___________________________________________________________________
Name: svn:eol-style
1165 + native
Index: branches/new-installer/phase3/includes/AutoLoader.php
@@ -382,6 +382,16 @@
383383 'RepoGroup' => 'includes/filerepo/RepoGroup.php',
384384 'UnregisteredLocalFile' => 'includes/filerepo/UnregisteredLocalFile.php',
385385
 386+ # includes/installer
 387+ 'Installer' => 'includes/installer/Installer.php',
 388+ 'InstallerDBType' => 'includes/installer/InstallerDBType.php',
 389+ 'LBFactory_InstallerFake' => 'includes/installer/Installer.php',
 390+ 'WebInstaller' => 'includes/installer/WebInstaller.php',
 391+ 'WebInstallerOutput' => 'includes/installer/WebInstallerOutput.php',
 392+ 'MysqlInstaller' => 'includes/installer/MysqlInstaller.php',
 393+ 'PostgresInstaller' => 'includes/installer/PostgresInstaller.php',
 394+ 'SqliteInstaller' => 'includes/installer/SqliteInstaller.php',
 395+
386396 # includes/media
387397 'BitmapHandler' => 'includes/media/Bitmap.php',
388398 'BitmapHandler_ClientOnly' => 'includes/media/Bitmap_ClientOnly.php',
Index: branches/new-installer/phase3/config/new-index.php
@@ -0,0 +1,35 @@
 2+<?php
 3+
 4+define( 'MW_NO_DB', 1 );
 5+define( 'MW_CONFIG_CALLBACK', 'wfInstallerConfig' );
 6+
 7+function wfInstallerConfig() {
 8+ $GLOBALS['wgUseDatabaseMessages'] = false;
 9+ $GLOBALS['wgLBFactoryConf'] = array( 'class' => 'LBFactory_InstallerFake' );
 10+ $GLOBALS['wgShowExceptionDetails'] = true;
 11+}
 12+
 13+chdir( ".." );
 14+require( './includes/WebStart.php' );
 15+
 16+$installer = new WebInstaller( $wgRequest );
 17+
 18+if ( !$installer->startSession() ) {
 19+ $installer->finish();
 20+ exit;
 21+}
 22+
 23+$session = isset( $_SESSION['installData'] ) ? $_SESSION['installData'] : array();
 24+
 25+if ( isset( $session['settings']['_UserLang'] ) ) {
 26+ $langCode = $session['settings']['_UserLang'];
 27+} elseif ( !is_null( $wgRequest->getVal( 'UserLang' ) ) ) {
 28+ $langCode = $wgRequest->getVal( 'UserLang' );
 29+} else {
 30+ $langCode = 'en';
 31+}
 32+$wgLang = Language::factory( $langCode );
 33+
 34+$session = $installer->execute( $session );
 35+$_SESSION['installData'] = $session;
 36+
Property changes on: branches/new-installer/phase3/config/new-index.php
___________________________________________________________________
Name: svn:eol-style
137 + native
Index: branches/new-installer/phase3/languages/messages/MessagesEn.php
@@ -3682,6 +3682,169 @@
36833683 'unknown_extension_tag' => 'Unknown extension tag "$1"',
36843684 'duplicate-defaultsort' => 'Warning: Default sort key "$2" overrides earlier default sort key "$1".',
36853685
 3686+# Installer
 3687+'config-session-error' => 'Error starting session: $1',
 3688+'config-session-expired' => 'Your session data seems to have expired.
 3689+Sessions are configured for a lifetime of $1, you can increase this by setting session.gc_maxlifetime in php.ini.
 3690+Please restart the installation process.',
 3691+'config-no-session' => 'Your session data was lost!
 3692+Please check your php.ini and make sure session.save_path is set to an appropriate directory.',
 3693+'config-your-language' => 'Your language:',
 3694+'config-your-language-help' => 'Select a language to use during the installation process',
 3695+'config-wiki-language' => 'Wiki language:',
 3696+'config-wiki-language-help' => 'Select the language that the wiki will predominantly be written in',
 3697+'config-back' => '< Back',
 3698+'config-continue' => 'Continue >',
 3699+'config-page-language' => 'Language',
 3700+'config-page-environment' => 'Environment',
 3701+'config-page-dbconnect' => 'Connect to DB',
 3702+'config-page-upgrade' => 'Upgrade existing',
 3703+'config-page-dbsettings' => 'DB settings',
 3704+'config-page-identity' => 'Identity',
 3705+'config-page-license' => 'License',
 3706+'config-page-email' => 'Email',
 3707+'config-page-install' => 'Install',
 3708+'config-page-complete' => 'Complete!',
 3709+'config-page-restart' => 'Restart installation',
 3710+'config-help-restart' => 'Do you want to clear all saved data that you have entered, and restart the installation process?',
 3711+'config-restart' => 'Yes, restart it',
 3712+
 3713+'config-env-good' => '<span class="success-message">Environment checked. You can install MediaWiki.</span>',
 3714+'config-env-bad' => 'Cannot install MediaWiki.',
 3715+'config-env-php' => 'PHP $1 installed',
 3716+'config-no-db' => 'Could not find a suitable database driver!',
 3717+'config-no-db-help' => 'You need to install a database driver for PHP.
 3718+The following database types are supported: $1.
 3719+If you are on shared hosting, ask your hosting provider to install a suitable database driver.
 3720+If you compiled PHP yourself, reconfigure it with a database client enabled, for example using the ./configure --with-mysql.
 3721+If you installed PHP from a Debian or Ubuntu package, then you also need install the php5-mysql module.',
 3722+'config-have-db' => 'Found database drivers for: $1',
 3723+'config-register-globals' => '<strong class="error">Warning:</strong>
 3724+<strong>PHP\'s <tt>[http://php.net/register_globals register_globals]</tt> option is enabled. Disable it if you can.</strong>
 3725+MediaWiki will work, but your server is more exposed to PHP-based security vulnerabilities.',
 3726+'config-magic-quotes-runtime' => '<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] is active!</strong>
 3727+This option corrupts data input unpredictably; you cannot install or use MediaWiki unless this option is disabled.',
 3728+'config-magic-quotes-sybase' => '<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] is active!</strong>
 3729+This option corrupts data input unpredictably; you cannot install or use MediaWiki unless this option is disabled.',
 3730+'config-mbstring' => '<strong>Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] is active!</strong>
 3731+This option causes errors and may corrupt data unpredictably; you cannot install or use MediaWiki unless this option is disabled.',
 3732+'config-ze1' => '<strong>Fatal: [http://www.php.net/manual/en/ini.core.php zend.ze1_compatibility_mode] is active!</strong>
 3733+This option causes horrible bugs with MediaWiki; you cannot install or use MediaWiki unless this option is disabled.',
 3734+'config-safe-mode' => '<b class="error">Warning:</b>
 3735+<strong>PHP\'s [http://www.php.net/features.safe-mode safe mode] is active.</strong>
 3736+You may have problems caused by this, particularly if using image uploads.',
 3737+'config-xml-good' => 'Have XML / Latin1-UTF-8 conversion support.',
 3738+'config-xml-bad' => 'PHP\'s XML module is missing;
 3739+the wiki requires functions in this module and won\'t work in this configuration.
 3740+If you\'re running Mandrake, install the php-xml package.',
 3741+'config-pcre' => 'The PCRE support module appears to be missing.
 3742+MediaWiki requires the Perl-compatible regular expression functions.',
 3743+'config-memory-none' => 'PHP is configured with no <tt>memory_limit</tt>',
 3744+'config-memory-ok' => 'PHP\'s <tt>memory_limit</tt> is $1, ok.',
 3745+'config-memory-raised' => 'PHP\'s <tt>memory_limit</tt> is $1, raised to $2.',
 3746+'config-memory-bad' => '<strong>Warning:</strong> PHP\'s <tt>memory_limit</tt> is $1.
 3747+This is probably too low, the installation may fail!',
 3748+'config-turck' => '[http://turck-mmcache.sourceforge.net/ Turck MMCache] installed</li>',
 3749+'config-xcache' => '[http://trac.lighttpd.net/xcache/ XCache] installed',
 3750+'config-apc' => '[http://www.php.net/apc APC] installed',
 3751+'config-eaccel' => '[http://eaccelerator.sourceforge.net/ eAccelerator] installed',
 3752+'config-no-cache' => '<strong>Warning:</strong>
 3753+Couldn\'t find [http://turck-mmcache.sourceforge.net Turck MMCache],
 3754+[http://eaccelerator.sourceforge.net eAccelerator],
 3755+[http://www.php.net/apc APC] or [http://trac.lighttpd.net/xcache/ XCache];
 3756+cannot use these for object caching.',
 3757+'config-diff3-good' => 'Found GNU diff3: <tt>$1</tt>.',
 3758+'config-diff3-bad' => 'GNU diff3 not found.',
 3759+'config-imagemagick' => 'Found ImageMagick: <tt>$1</tt>; image thumbnailing will be enabled if you enable uploads.',
 3760+'config-gd' => 'Found GD graphics library built-in, image thumbnailing will be enabled if you enable uploads.',
 3761+'config-no-scaling' => 'Couldn\'t find GD library or ImageMagick; image thumbnailing disabled.',
 3762+'config-dir' => 'Installation directory: <tt>$1</tt>',
 3763+'config-uri' => 'Script URI path: <tt>$1</tt>',
 3764+'config-no-uri' => '<strong>Error:</strong> Could not determine the current URI. Installation aborted.',
 3765+'config-extension' => 'Installing MediaWiki with <tt>$1</tt> file extensions',
 3766+
 3767+'config-db-type' => 'DB type:',
 3768+'config-db-host' => 'DB host:',
 3769+'config-db-host-help' => 'If your database server isn\'t on your web server, enter the name or IP address here.
 3770+If you are using a shared web host, your hosting provider should give you the correct host name in their documentation.',
 3771+'config-db-wiki-settings' => 'Identify this wiki',
 3772+'config-db-name' => 'DB name:',
 3773+'config-db-name-help' => 'Choose a name that identifies your wiki. It should not contain spaces or hyphens.
 3774+If you are using a shared host, your hosting provider will either give you a specific database name to use, or let you create databases via a control panel.',
 3775+'config-db-install-account' => 'User account for installation',
 3776+'config-db-username' => 'DB username:',
 3777+'config-db-password' => 'DB password:',
 3778+'config-db-install-help' => 'Select the username and password that will be used to connect to the database during the installation process.',
 3779+'config-db-account-lock' => 'Use the same username and password during normal operation',
 3780+'config-db-wiki-account' => 'User account for normal operation',
 3781+'config-db-wiki-help' => 'Select the username and password that will be used to connect to the database during normal wiki operation.
 3782+If the account does not exist, and the installation account has sufficient privileges, this user account will be created with the minimum privileges required to operate the wiki.',
 3783+'config-db-prefix' => 'DB table prefix:',
 3784+'config-db-prefix-help' => 'If you need to share one database between multiple wikis, or between MediaWiki and another web application, you may choose to add a prefix to all the table names to avoid conflicts.
 3785+Do not use spaces or hyphens.
 3786+
 3787+This may normally be left blank.',
 3788+'config-db-charset' => 'DB character set',
 3789+'config-charset-mysql5-binary' => 'MySQL 4.1/5.0 binary',
 3790+'config-charset-mysql5' => 'MySQL 4.1/5.0 UTF-8',
 3791+'config-charset-mysql4' => 'MySQL 4.0 backwards-compatible UTF-8',
 3792+'config-charset-help' => '<b>WARNING:</b> If you use <b>backwards-compatible UTF-8</b> on MySQL 4.1+, and subsequently back up the database with <tt>mysqldump</tt>, it may destroy all non-ASCII characters, irreversibly corrupting your backups!.
 3793+<br/><br/>
 3794+In <b>binary mode</b>, MediaWiki stores UTF-8 text to the database in binary fields. This is more efficient than MySQL\'s UTF-8 mode, and allows you to use the full range of Unicode characters. In <b>UTF-8 mode</b>, MySQL will know what character set your data is in, and can present and convert it appropriately, but it won\'t let you store characters above the [http://en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Basic Multilingual Plane].
 3795+',
 3796+'config-mysql-old' => 'MySQL $1 or later is required, you have $2.',
 3797+'config-db-port' => 'DB port:',
 3798+'config-db-schema' => 'Schema for MediaWiki',
 3799+'config-db-ts2-schema' => 'Schema for tsearch2',
 3800+'config-db-schema-help' => 'The above schemas are generally correct, only change them if you are sure you need to.',
 3801+'config-sqlite-dir' => 'SQLite data directory:',
 3802+'config-sqlite-dir-help' => 'SQLite stores table data into files in the filesystem.
 3803+This directory must be writable by the webserver.
 3804+It should <strong>not</strong> accessible via the web.',
 3805+'config-type-mysql' => 'MySQL',
 3806+'config-type-postgres' => 'PostgreSQL',
 3807+'config-type-sqlite' => 'SQLite',
 3808+'config-header-mysql' => 'MySQL settings',
 3809+'config-header-postgres' => 'PostgreSQL settings',
 3810+'config-header-sqlite' => 'SQLite settings',
 3811+'config-invalid-db-type' => 'Invalid DB type',
 3812+'config-missing-db-name' => 'You must enter a value for "DB name"',
 3813+'config-invalid-db-name' => 'Invalid DB name "$1". It may only contain numbers, letters and underscores.',
 3814+'config-invalid-db-prefix' => 'Invalid DB prefix "$1". It may only contain numbers, letters and underscores.',
 3815+'config-connection-error' => '$1.
 3816+
 3817+Check the host, username and password below and try again.',
 3818+'config-invalid-schema' => 'Invalid schema for MediaWiki "$1". Please use only letters, numbers and underscores.',
 3819+'config-invalid-ts2schema' => 'Invalid schema for tsearch2 "$1". Please use only letters, numbers and underscores.',
 3820+'config-postgres-old' => 'Postgres $1 or later is required, you have $2.',
 3821+'config-sqlite-name-help' => 'Choose a name that identifies your wiki. Do not use spaces or hyphens. This will be used for the SQLite data file name.',
 3822+'config-sqlite-parent-unwritable' => 'Cannot create the data directory "$1", because the parent directory "$2" is not writable by the webserver. Please create this directory yourself, make it writable, and try again.',
 3823+'config-sqlite-mkdir-error' => 'Error creating the data directory "$1". Please check the location and try again.',
 3824+'config-sqlite-unwritable' => 'Unable to write to the directory specified: $1. Please change its permissions so that the webserver can write to it, and try again.',
 3825+'config-sqlite-connection-error' => '$1.
 3826+
 3827+Check the data directory and DB name below and try again.',
 3828+'config-can-upgrade' => 'There are MediaWiki tables in this database.
 3829+To upgrade them to MediaWiki $1, click <strong>Continue</strong>.',
 3830+'config-upgrade-done' => 'Upgrade complete.
 3831+
 3832+You can now [$1 start using your wiki].
 3833+
 3834+If you want to regenerate your LocalSettings.php file, click the button below.
 3835+This is <strong>not recommended</strong> unless you are having problems with your wiki.
 3836+',
 3837+'config-regenerate' => 'Regenerate LocalSettings.php >',
 3838+'config-show-table-status' => 'SHOW TABLE STATUS query failed!',
 3839+'config-unknown-collation' => '<strong>Warning:</strong> Unrecognised existing collation',
 3840+
 3841+'config-db-web-account' => 'DB account for web access',
 3842+'config-db-web-help' => 'Select the username and password that the web server will use to connect to the database server, during ordinary operation of the wiki.
 3843+
 3844+If the account specified does not exist, the installer will attempt to create it.
 3845+',
 3846+'config-db-web-account-same' => 'Use the same account as for installation',
 3847+
 3848+
36863849 # Special:Version
36873850 'version' => 'Version', # Not used as normal message but as header for the special page itself
36883851 'version-extensions' => 'Installed extensions',

Follow-up revisions

RevisionCommit summaryAuthorDate
r45496Merging changes from trunk from r43665 to r45494.tstarling12:35, 7 January 2009

Status & tagging log