r66008 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r66007‎ | r66008 | r66009 >
Date:12:25, 7 May 2010
Author:demon
Status:ok (Comments)
Tags:
Comment:
Merge new-installer branch to trunk
* This is not complete yet, and should not be used outside of testing. Using it on a production database may ruin everything. This is the reason for the second entry point of new-index.php. You've been warned.
* Known issues are at [[mw:New-installer_issues]]. Please add new items to the list if you find them.
Modified paths:
  • /trunk/phase3 (modified) (history)
  • /trunk/phase3/config/new-index.php (added) (history)
  • /trunk/phase3/includes (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/GlobalFunctions.php (modified) (history)
  • /trunk/phase3/includes/Setup.php (modified) (history)
  • /trunk/phase3/includes/db/LBFactory.php (modified) (history)
  • /trunk/phase3/includes/installer (added) (history)
  • /trunk/phase3/maintenance/install.php (added) (history)
  • /trunk/phase3/skins/common/config-cc.css (added) (history)
  • /trunk/phase3/skins/common/config.css (added) (history)
  • /trunk/phase3/skins/common/config.js (added) (history)
  • /trunk/phase3/skins/common/images/critical-32.png (added) (history)
  • /trunk/phase3/skins/common/images/help-22.png (added) (history)
  • /trunk/phase3/skins/common/images/info-32.png (added) (history)
  • /trunk/phase3/skins/common/images/tick-32.png (added) (history)
  • /trunk/phase3/skins/common/images/warning-32.png (added) (history)

Diff [purge]

Index: trunk/phase3/maintenance/install.php
@@ -0,0 +1,49 @@
 2+<?php
 3+
 4+if ( php_sapi_name() != 'cli' ) {
 5+ echo "This is a command-line script.\n";
 6+ exit( 1 );
 7+}
 8+
 9+define( 'MEDIAWIKI', 1 );
 10+define( 'MW_NO_DB', 1 );
 11+define( 'MW_NO_SESSION', 1 );
 12+define( 'MW_CONFIG_CALLBACK', 'wfInstallerConfig' );
 13+
 14+$IP = dirname( dirname( __FILE__ ) );
 15+
 16+function wfInstallerConfig() {
 17+ // Don't access the database
 18+ $GLOBALS['wgUseDatabaseMessages'] = false;
 19+ // Debug-friendly
 20+ $GLOBALS['wgShowExceptionDetails'] = true;
 21+ // Don't break forms
 22+ $GLOBALS['wgExternalLinkTarget'] = '_blank';
 23+}
 24+
 25+require_once( "$IP/includes/ProfilerStub.php" );
 26+require_once( "$IP/includes/Defines.php" );
 27+require_once( "$IP/includes/GlobalFunctions.php" );
 28+require_once( "$IP/includes/AutoLoader.php" );
 29+require_once( "$IP/includes/Hooks.php" );
 30+require_once( "$IP/includes/DefaultSettings.php" );
 31+require_once( "$IP/includes/Namespace.php" );
 32+
 33+$wgContLang = Language::factory( 'en' ); // will be overridden later
 34+
 35+// Disable the i18n cache and LoadBalancer
 36+Language::getLocalisationCache()->disableBackend();
 37+LBFactory::disableBackend();
 38+
 39+$installer = new CliInstaller( $argv );
 40+
 41+$langCode = 'en';
 42+
 43+$wgLang = Language::factory( $langCode );
 44+
 45+$wgMetaNamespace = $wgCanonicalNamespaceNames[NS_PROJECT];
 46+
 47+$session = $installer->execute( $argv );
 48+
 49+$_SESSION['installData'] = $session;
 50+
Property changes on: trunk/phase3/maintenance/install.php
___________________________________________________________________
Added: svn:eol-style
151 + native
Index: trunk/phase3/skins/common/config.js
@@ -0,0 +1,88 @@
 2+(function( $ ) {
 3+ $( document ).ready( function() {
 4+ // Show/hide code for help text
 5+ $( '.config-show-help a' ).click( function() {
 6+ $(this).parent().siblings( '.config-help-message' ).show( 'slow' );
 7+ $(this).parent().siblings( '.config-hide-help' ).show();
 8+ $(this).parent().hide();
 9+ return false;
 10+ } );
 11+ $( '.config-hide-help a' ).click( function() {
 12+ $(this).parent().siblings( '.config-help-message' ).hide( 'slow' );
 13+ $(this).parent().siblings( '.config-show-help' ).show();
 14+ $(this).parent().hide();
 15+ return false;
 16+ } );
 17+
 18+ // Show/hide code for DB-specific options
 19+ // FIXME: Do we want slow, fast, or even non-animated (instantaneous) showing/hiding here?
 20+ $( '.dbRadio' ).each( function() { $( '#' + $(this).attr( 'rel' ) ).hide(); } );
 21+ $( '#' + $( '.dbRadio:checked' ).attr( 'rel' ) ).show();
 22+ $( '.dbRadio' ).click( function() {
 23+ var $checked = $( '.dbRadio:checked' );
 24+ var $wrapper = $( '#' + $checked.attr( 'rel' ) );
 25+ if ( !$wrapper.is( ':visible' ) ) {
 26+ $( '.dbWrapper' ).hide( 'slow' );
 27+ $wrapper.show( 'slow' );
 28+ }
 29+ } );
 30+
 31+ // Scroll to the bottom of upgrade log
 32+ $( "#config-update-log" ).each( function() { this.scrollTop = this.scrollHeight; } );
 33+
 34+ // Show/hide Creative Commons thingy
 35+ $( '.licenseRadio' ).click( function() {
 36+ var $wrapper = $( '#config-cc-wrapper' );
 37+ if ( $( '#config__LicenseCode_cc-choose' ).is( ':checked' ) ) {
 38+ $wrapper.show( 'slow' );
 39+ } else {
 40+ $wrapper.hide( 'slow' );
 41+ }
 42+ } );
 43+
 44+ // Show/hide random stuff (email, upload)
 45+ $( '.showHideRadio' ).click( function() {
 46+ var $wrapper = $( '#' + $(this).attr( 'rel' ) );
 47+ if ( $(this).is( ':checked' ) ) {
 48+ $wrapper.show( 'slow' );
 49+ } else {
 50+ $wrapper.hide( 'slow' );
 51+ }
 52+ } );
 53+ $( '.hideShowRadio' ).click( function() {
 54+ var $wrapper = $( '#' + $(this).attr( 'rel' ) );
 55+ if ( $(this).is( ':checked' ) ) {
 56+ $wrapper.hide( 'slow' );
 57+ } else {
 58+ $wrapper.show( 'slow' );
 59+ }
 60+ } );
 61+
 62+ // Enable/disable "other" textboxes
 63+ $( '.enableForOther' ).click( function() {
 64+ var $textbox = $( '#' + $(this).attr( 'rel' ) );
 65+ if ( $(this).val() == 'other' ) { // FIXME: Ugh, this is ugly
 66+ $textbox.removeAttr( 'disabled' );
 67+ } else {
 68+ $textbox.attr( 'disabled', 'disabled' );
 69+ }
 70+ } );
 71+
 72+ // Synchronize radio button label for sitename with textbox
 73+ $label = $( 'label[for=config__NamespaceType_site-name]' );
 74+ labelText = $label.text();
 75+ $label.text( labelText.replace( '$1', '' ) );
 76+ $( '#config_wgSitename' ).bind( 'keyup change', syncText ).each( syncText );
 77+ function syncText() {
 78+ var value = $(this).val()
 79+ .replace( /[\[\]\{\}|#<>%+? ]/g, '_' )
 80+ .replace( /&/, '&amp;' )
 81+ .replace( /__+/g, '_' )
 82+ .replace( /^_+/, '' )
 83+ .replace( /_+$/, '' );
 84+ value = value.substr( 0, 1 ).toUpperCase() + value.substr( 1 );
 85+ $label.text( labelText.replace( '$1', value ) );
 86+ }
 87+
 88+ } );
 89+})(jQuery);
Property changes on: trunk/phase3/skins/common/config.js
___________________________________________________________________
Added: svn:eol-style
190 + native
Index: trunk/phase3/skins/common/config.css
@@ -0,0 +1,159 @@
 2+.env-check {
 3+ font-size: 90%;
 4+ margin: 1em 0 1em 2.5em;
 5+}
 6+
 7+.config-section {
 8+ margin-top: 2em;
 9+}
 10+
 11+.config-label {
 12+ clear: left;
 13+ font-weight: bold;
 14+ width: 10em;
 15+ float: left;
 16+ text-align: right;
 17+ padding-right: 1em;
 18+ padding-top: .2em;
 19+}
 20+
 21+.config-input {
 22+ clear: left;
 23+ zoom: 100%; /* IE hack */
 24+}
 25+
 26+.config-page-wrapper {
 27+ padding: 0.5em;
 28+}
 29+
 30+.config-page-list {
 31+ float: right;
 32+ width: 12em;
 33+ border: 1px solid #aaa;
 34+ padding: 0.5em;
 35+ margin: 0.5em;
 36+}
 37+
 38+.config-page {
 39+ padding: 0.5em 2em 0.5em 2em;
 40+ /* 15em right margin to leave space for 12em page list */
 41+ margin: 0.5em 15em 0.5em 0.5em;
 42+ border: 1px solid #aaa;
 43+}
 44+
 45+.config-submit {
 46+ clear: left;
 47+ text-align: center;
 48+ padding: 1em;
 49+}
 50+
 51+.config-submit input {
 52+ margin-left: 0.5em;
 53+ margin-right: 0.5em;
 54+}
 55+
 56+.config-page-disabled {
 57+ color: #aaa;
 58+}
 59+
 60+.config-error-box {
 61+ border: 2px solid #f00;
 62+ margin: 0.4em;
 63+ clear: left;
 64+}
 65+
 66+.config-info-left {
 67+ margin: 7px;
 68+ float: left;
 69+ width: 35px;
 70+}
 71+
 72+.config-info-right {
 73+ margin: 0.5em 0.5em 0.5em 49px;
 74+ width: 30em;
 75+}
 76+
 77+.config-page-current {
 78+ font-weight: bold;
 79+}
 80+
 81+.config-help-wrapper {
 82+ clear: left;
 83+ margin: 0 0 2em 12em;
 84+ padding-top: 1em;
 85+}
 86+.config-show-help, .config-hide-help {
 87+ margin-left: 14em;
 88+}
 89+.config-hide-help { display: none; }
 90+.config-show-help a, .config-hide-help a {
 91+ background-image: url(images/help-22.png);
 92+ background-position: 0 0;
 93+ background-repeat: no-repeat;
 94+ display: inline-block;
 95+ height: 26px;
 96+ padding-left: 26px;
 97+}
 98+
 99+.config-help-message {
 100+ font-size: 85%;
 101+ display: none;
 102+}
 103+
 104+.config-message {
 105+ display: list-item;
 106+ line-height: 1.5em;
 107+ list-style-image: url(../skins/common/images/bullet.gif);
 108+ list-style-type: square;
 109+}
 110+
 111+.config-input-text {
 112+ width: 20em;
 113+ margin-right: 1em;
 114+}
 115+
 116+.config-input-check {
 117+ margin-left: 10em;
 118+}
 119+
 120+.error {
 121+ color: red;
 122+ background-color: #fff;
 123+ font-weight: bold;
 124+ left: 1em;
 125+ font-size: 100%;
 126+}
 127+
 128+.config-settings-block {
 129+ list-style-type: none;
 130+ list-style-image: none;
 131+ float: left;
 132+ margin: 0;
 133+ padding: 0;
 134+}
 135+
 136+.btn-install {
 137+ font-weight: bold;
 138+ font-size: 110%;
 139+ padding: .2em .3em;
 140+}
 141+
 142+.success-message {
 143+ font-weight: bold;
 144+ font-size: 110%;
 145+ color: green;
 146+}
 147+.success-box {
 148+ font-size: 130%;
 149+}
 150+
 151+.config-cc-wrapper {
 152+ clear: left;
 153+ /* If you change this height, also change it in WebInstaller_Options::submitCC() */
 154+ height: 54em;
 155+}
 156+
 157+.config-plainlink a {
 158+ background: none !important;
 159+ padding: 0 !important;
 160+}
Property changes on: trunk/phase3/skins/common/config.css
___________________________________________________________________
Added: svn:eol-style
1161 + native
Index: trunk/phase3/skins/common/images/help-22.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/phase3/skins/common/images/help-22.png
___________________________________________________________________
Added: svn:mime-type
2162 + image/png
Index: trunk/phase3/skins/common/images/tick-32.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/phase3/skins/common/images/tick-32.png
___________________________________________________________________
Added: svn:mime-type
3163 + image/png
Index: trunk/phase3/skins/common/images/critical-32.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/phase3/skins/common/images/critical-32.png
___________________________________________________________________
Added: svn:mime-type
4164 + application/octet-stream
Index: trunk/phase3/skins/common/images/info-32.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/phase3/skins/common/images/info-32.png
___________________________________________________________________
Added: svn:mime-type
5165 + image/png
Index: trunk/phase3/skins/common/images/warning-32.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: trunk/phase3/skins/common/images/warning-32.png
___________________________________________________________________
Added: svn:mime-type
6166 + image/png
Index: trunk/phase3/skins/common/config-cc.css
@@ -0,0 +1,56 @@
 2+/**
 3+ * Copy of CC standard stylesheet, plus tweaks for iframe usage
 4+ */
 5+
 6+body {
 7+ margin:0px;
 8+ background:#eee;
 9+ font-family:verdana;
 10+ color:#333;
 11+}
 12+
 13+#main {
 14+ border:1px solid #D0D0D0;
 15+ background:#fff;
 16+ margin: 0.5em;
 17+}
 18+
 19+/* Looks like you have to specify the width of #menu
 20+or IE5 Mac stretches it all the way across the div, and
 21+Opera streches it half way. */
 22+
 23+#main #menu {
 24+ border-left:1px dotted #ccc;
 25+ /* border-bottom:1px solid #000;*/
 26+ float:right;
 27+ width:230px;
 28+ background:white;
 29+ margin:0px 0px 10px 10px;
 30+}
 31+
 32+td, h3, p,h1,pre {
 33+ margin:0px 20px 20px 20px;
 34+ font-size:11px;
 35+ line-height:140%;
 36+}
 37+
 38+.header {
 39+ padding-left: 10px;
 40+ padding-top:10px;
 41+}
 42+
 43+.nav {
 44+ padding-left:10px;
 45+ padding-bottom:10px;
 46+ font-size:11px;
 47+ margin-bottom:16px;
 48+}
 49+
 50+#menu p {
 51+ font-size:11px;
 52+}
 53+
 54+.dent {
 55+ margin-left:64px;
 56+}
 57+
Property changes on: trunk/phase3/skins/common/config-cc.css
___________________________________________________________________
Added: svn:eol-style
158 + native
Index: trunk/phase3/includes/GlobalFunctions.php
@@ -1815,7 +1815,7 @@
18161816 }
18171817 } else {
18181818 if ( !$suppressCount ) {
1819 - $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE ) );
 1819+ $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE ) );
18201820 }
18211821 ++$suppressCount;
18221822 }
@@ -3326,3 +3326,14 @@
33273327 $langCode = implode ( '-' , $codeBCP );
33283328 return $langCode;
33293329 }
 3330+
 3331+function wfArrayMap( $function, $input ) {
 3332+ $ret = array_map( $function, $input );
 3333+ foreach ( $ret as $key => $value ) {
 3334+ $taint = istainted( $input[$key] );
 3335+ if ( $taint ) {
 3336+ taint( $ret[$key], $taint );
 3337+ }
 3338+ }
 3339+ return $ret;
 3340+}
Index: trunk/phase3/includes/db/LBFactory.php
@@ -12,6 +12,23 @@
1313 static $instance;
1414
1515 /**
 16+ * Disables all access to the load balancer, will cause all database access
 17+ * to throw a DBAccessError
 18+ */
 19+ public static function disableBackend() {
 20+ global $wgLBFactoryConf;
 21+ self::$instance = new LBFactory_Fake( $wgLBFactoryConf );
 22+ }
 23+
 24+ /**
 25+ * Resets the singleton for use if it's been disabled. Does nothing otherwise
 26+ */
 27+ public static function enableBackend() {
 28+ if( self::$instance instanceof LBFactory_Fake )
 29+ self::$instance = null;
 30+ }
 31+
 32+ /**
1633 * Get an LBFactory instance
1734 */
1835 static function &singleton() {
@@ -198,6 +215,39 @@
199216 }
200217
201218 /**
 219+ * LBFactory class that throws an error on any attempt to use it.
 220+ * This will typically be done via wfGetDB().
 221+ * Call LBFactory::disable() to start using this, and LBFactory::enable() to
 222+ * return to normal behavior
 223+ */
 224+class LBFactory_Fake extends LBFactory {
 225+ function __construct( $conf ) {}
 226+
 227+ function newMainLB( $wiki = false) {
 228+ throw new DBAccessError;
 229+ }
 230+ function getMainLB( $wiki = false ) {
 231+ throw new DBAccessError;
 232+ }
 233+ function newExternalLB( $cluster, $wiki = false ) {
 234+ throw new DBAccessError;
 235+ }
 236+ function &getExternalLB( $cluster, $wiki = false ) {
 237+ throw new DBAccessError;
 238+ }
 239+ function forEachLB( $callback, $params = array() ) {}
 240+}
 241+
 242+/**
 243+ * Exception class for attempted DB access
 244+ */
 245+class DBAccessError extends MWException {
 246+ function __construct() {
 247+ parent::__construct( "Mediawiki tried to access the database via wfGetDB(). This is not allowed." );
 248+ }
 249+}
 250+
 251+/**
202252 * Class for ensuring a consistent ordering of events as seen by the user, despite replication.
203253 * Kind of like Hawking's [[Chronology Protection Agency]].
204254 */
Index: trunk/phase3/includes/Setup.php
@@ -297,13 +297,15 @@
298298 if( !wfIniGetBool( 'session.auto_start' ) )
299299 session_name( $wgSessionName ? $wgSessionName : $wgCookiePrefix . '_session' );
300300
301 -if( !$wgCommandLineMode && ( $wgRequest->checkSessionCookie() || isset( $_COOKIE[$wgCookiePrefix.'Token'] ) ) ) {
302 - wfIncrStats( 'request_with_session' );
303 - wfSetupSession();
304 - $wgSessionStarted = true;
305 -} else {
306 - wfIncrStats( 'request_without_session' );
307 - $wgSessionStarted = false;
 301+if( !defined( 'MW_NO_SESSION' ) ) {
 302+ if( !$wgCommandLineMode && ( $wgRequest->checkSessionCookie() || isset( $_COOKIE[$wgCookiePrefix.'Token'] ) ) ) {
 303+ wfIncrStats( 'request_with_session' );
 304+ wfSetupSession();
 305+ $wgSessionStarted = true;
 306+ } else {
 307+ wfIncrStats( 'request_without_session' );
 308+ $wgSessionStarted = false;
 309+ }
308310 }
309311
310312 wfProfileOut( $fname.'-SetupSession' );
Index: trunk/phase3/includes/installer/Installer.i18n.php
@@ -0,0 +1,772 @@
 2+<?php
 3+/*
 4+ * Internationalization file for the install/upgrade process. None of the
 5+ * messages used here are loaded during normal operations, only during
 6+ * install and upgrade. So you should not put normal messages here.
 7+ */
 8+
 9+$messages = array();
 10+
 11+/**
 12+ * English
 13+ */
 14+$messages['en'] = array(
 15+ 'config-title' => 'MediaWiki $1 installation',
 16+ 'config-information' => 'Information',
 17+ 'config-session-error' => 'Error starting session: $1',
 18+ 'config-session-expired' => 'Your session data seems to have expired.
 19+Sessions are configured for a lifetime of $1.
 20+You can increase this by setting <code>session.gc_maxlifetime</code> in php.ini.
 21+Restart the installation process.',
 22+ 'config-no-session' => 'Your session data was lost!
 23+Check your php.ini and make sure <code>session.save_path</code> is set to an appropriate directory.',
 24+ 'config-session-path-bad' => 'Your <code>session.save_path</code> (<code>$1</code>) seems to be invalid or unwritable.',
 25+ 'config-show-help' => 'Help',
 26+ 'config-hide-help' => 'Hide help',
 27+ 'config-your-language' => 'Your language:',
 28+ 'config-your-language-help' => 'Select a language to use during the installation process.',
 29+ 'config-wiki-language' => 'Wiki language:',
 30+ 'config-wiki-language-help' => 'Select the language that the wiki will predominantly be written in.',
 31+ 'config-back' => '← Back',
 32+ 'config-continue' => 'Continue →',
 33+ 'config-page-language' => 'Language',
 34+ 'config-page-welcome' => 'Welcome to MediaWiki!',
 35+ 'config-page-dbconnect' => 'Connect to database',
 36+ 'config-page-upgrade' => 'Upgrade existing',
 37+ 'config-page-dbsettings' => 'Database settings',
 38+ 'config-page-name' => 'Name',
 39+ 'config-page-options' => 'Options',
 40+ 'config-page-install' => 'Install',
 41+ 'config-page-complete' => 'Complete!',
 42+ 'config-page-restart' => 'Restart installation',
 43+ 'config-page-readme' => 'Read me',
 44+ 'config-page-releasenotes' => 'Release notes',
 45+ 'config-page-copying' => 'Copying',
 46+ 'config-page-upgradedoc' => 'Upgrading',
 47+ 'config-help-restart' => 'Do you want to clear all saved data that you have entered and restart the installation process?',
 48+ 'config-restart' => 'Yes, restart it',
 49+ 'config-welcome' => "=== Environmental checks ===
 50+We're doing basic checks to see if this environment is suitable for MediaWiki installation. You
 51+should provide this information if you need help during installation.",
 52+ 'config-copyright' => "=== Copyright and Terms ===
 53+
 54+$1
 55+
 56+This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 57+
 58+This program is distributed in the hope that it will be useful, but '''without any warranty'''; without even the implied warranty of '''merchantability''' or '''fitness for a particular purpose'''.
 59+See the GNU General Public License for more details.
 60+
 61+You should have received <doclink href=Copying>a copy of the GNU General Public License</doclink> along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or [http://www.gnu.org/copyleft/gpl.html read it online].",
 62+ 'config-authors' => 'MediaWiki is Copyright © 2001-2010 by Magnus Manske, Brion Vibber, Lee Daniel Crocker, Tim Starling, Erik Möller, Gabriel Wicke, Ævar Arnfjörð Bjarmason, Niklas Laxström, Domas Mituzas, Rob Church, Yuri Astrakhan, Aryeh Gregor, Aaron Schulz, Andrew Garrett, Raimond Spekking, Alexandre Emsenhuber, Siebrand Mazeland, Chad Horohoe and others.',
 63+ 'config-sidebar' => "* [http://www.mediawiki.org MediaWiki home]
 64+* [http://www.mediawiki.org/wiki/Help:Contents User's Guide]
 65+* [http://www.mediawiki.org/wiki/Manual:Contents Administrator's Guide]
 66+* [http://www.mediawiki.org/wiki/Manual:FAQ FAQ]",
 67+ 'config-env-good' => '<span class="success-message">The environment has been checked.
 68+You can install MediaWiki.</span>', // FIXME: take span out of message.
 69+ 'config-env-bad' => 'The environment has been checked.
 70+You cannot install MediaWiki.',
 71+ 'config-env-php' => 'PHP $1 installed.',
 72+ 'config-env-latest-ok' => 'You are installing the latest version of Mediawiki.',
 73+ 'config-env-latest-new' => "'''Note:''' You are installing a development version of Mediawiki.",
 74+ 'config-env-latest-can-not-check' => "'''Note:''' We were unable to retrieve information about the latest MediaWiki release (from [$1]).",
 75+ 'config-env-latest-data-invalid' => "'''Warning:''' When trying to check if this version was outdated we got invalid data from [$1].",
 76+ 'config-env-latest-old' => "'''Warning:''' You are installing an outdated version of Mediawiki.",
 77+ 'config-env-latest-help' => 'You are installing version $1, but the latest version is $2.
 78+You are advised to use the latest release, which can be downloaded from [http://www.mediawiki.org/wiki/Download mediawiki.org]',
 79+ 'config-no-db' => 'Could not find a suitable database driver!',
 80+ 'config-no-db-help' => 'You need to install a database driver for PHP.
 81+The following database types are supported: $1.
 82+
 83+If you are on shared hosting, ask your hosting provider to install a suitable database driver.
 84+If you compiled PHP yourself, reconfigure it with a database client enabled, for example using <code>./configure --with-mysql</code>.
 85+If you installed PHP from a Debian or Ubuntu package, then you also need install the php5-mysql module.',
 86+ 'config-have-db' => 'Found database drivers: $1.',
 87+ 'config-register-globals' => "'''Warning: PHP's <code>[http://php.net/register_globals register_globals]</code> option is enabled.'''
 88+'''Disable it if you can.'''
 89+MediaWiki will work, but your server is exposed to potential security vulnerabilities.",
 90+ 'config-magic-quotes-runtime' => "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] is active!'''
 91+This option corrupts data input unpredictably.
 92+You cannot install or use MediaWiki unless this option is disabled.",
 93+ 'config-magic-quotes-sybase' => "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] is active!'''
 94+This option corrupts data input unpredictably.
 95+You cannot install or use MediaWiki unless this option is disabled.",
 96+ 'config-mbstring' => "'''Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] is active!'''
 97+This option causes errors and may corrupt data unpredictably.
 98+You cannot install or use MediaWiki unless this option is disabled.",
 99+ 'config-ze1' => "'''Fatal: [http://www.php.net/manual/en/ini.core.php zend.ze1_compatibility_mode] is active!'''
 100+This option causes horrible bugs with MediaWiki.
 101+You cannot install or use MediaWiki unless this option is disabled.",
 102+ 'config-safe-mode' => "'''Warning:''' PHP's [http://www.php.net/features.safe-mode safe mode] is active.
 103+It may cause problems, particularly if using file uploads and <code>math</code> support.",
 104+ 'config-xml-good' => 'Have XML / Latin1-UTF-8 conversion support.',
 105+ 'config-xml-bad' => "PHP's XML module is missing.
 106+MediaWiki requires functions in this module and will not work in this configuration.
 107+If you're running Mandrake, install the php-xml package.",
 108+ 'config-pcre' => 'The PCRE support module appears to be missing.
 109+MediaWiki requires the Perl-compatible regular expression functions to work.',
 110+ 'config-memory-none' => 'PHP is configured with no <code>memory_limit</code>',
 111+ 'config-memory-ok' => "PHP's <code>memory_limit</code> is $1, ok.",
 112+ 'config-memory-raised' => "PHP's <code>memory_limit</code> is $1, raised to $2.",
 113+ 'config-memory-bad' => "'''Warning:''' PHP's <code>memory_limit</code> is $1.
 114+This is probably too low.
 115+The installation may fail!",
 116+ 'config-xcache' => '[http://trac.lighttpd.net/xcache/ XCache] installed',
 117+ 'config-apc' => '[http://www.php.net/apc APC] installed',
 118+ 'config-eaccel' => '[http://eaccelerator.sourceforge.net/ eAccelerator] installed',
 119+ 'config-no-cache' => "'''Warning:''' Could not find [http://eaccelerator.sourceforge.net eAccelerator], [http://www.php.net/apc APC] or [http://trac.lighttpd.net/xcache/ XCache].
 120+Object caching is not enabled.",
 121+ 'config-diff3-good' => 'Found GNU diff3: <code>$1</code>.',
 122+ 'config-diff3-bad' => 'GNU diff3 not found.',
 123+ 'config-imagemagick' => 'Found ImageMagick: <code>$1</code>.
 124+Image thumbnailing will be enabled if you enable uploads.',
 125+ 'config-gd' => 'Found GD graphics library built-in.
 126+Image thumbnailing will be enabled if you enable uploads.',
 127+ 'config-no-scaling' => 'Could not find GD library or ImageMagick.
 128+Image thumbnailing will be disabled.',
 129+ 'config-dir' => 'Installation directory: <code>$1</code>.',
 130+ 'config-uri' => 'Script URI path: <code>$1</code>.',
 131+ 'config-no-uri' => "'''Error:''' Could not determine the current URI.
 132+Installation aborted.",
 133+ 'config-dir-not-writable-group' => "'''Error:''' Cannot write config file.
 134+Installation aborted.
 135+
 136+We've determined the user your webserver is running as. Make the
 137+<code><nowiki>config</nowiki></code> directory writable by it to continue. On a Unix/Linux system:
 138+
 139+<pre>cd $1
 140+chgrp $2 config
 141+chmod g+w config</pre>",
 142+ 'config-dir-not-writable-nogroup' => "'''Error:''' Cannot write config file.
 143+Installation aborted.
 144+
 145+We couldn't determine the user your webserver is running as. Make the
 146+<code><nowiki>config</nowiki></code> directory globally writable by it (and others!) to continue. On
 147+a Unix/Linux system do:
 148+
 149+<pre>cd $1
 150+chmod a+w config</pre>",
 151+ 'config-file-extension' => 'Installing MediaWiki with <code>$1</code> file extensions.',
 152+ 'config-shell-locale' => 'Detected shell locale "$1"',
 153+ 'config-uploads-safe' => 'Default uploads directory is safe from arbitrary scripts execution.',
 154+ 'config-uploads-not-safe' => "'''Warning:''' Your default uploads directory <code>$1</code> is vulnerable to arbitrary scripts execution.
 155+Although MediaWiki checks all uploaded files for security threats, it is highly recommended to [http://www.mediawiki.org/wiki/Manual:Security#Upload_security close this hole] before enabling uploads.",
 156+ 'config-db-type' => 'Database type:',
 157+ 'config-db-host' => 'Database host:',
 158+ 'config-db-host-help' => 'If your database server is on different server, enter the host name or IP address here.
 159+
 160+If you are using shared web hosting, your hosting provider should give you the correct host name in their documentation.',
 161+ 'config-db-wiki-settings' => 'Identify this wiki',
 162+ 'config-db-name' => 'Database name:',
 163+ 'config-db-name-help' => 'Choose a name that identifies your wiki.
 164+It should not contain spaces or hyphens.
 165+
 166+If you are using shared web hosting, your hosting provider will either give you a specific database name to use, or let you create databases via a control panel.',
 167+ 'config-db-install-account' => 'User account for installation',
 168+ 'config-db-username' => 'Database username:',
 169+ 'config-db-password' => 'Database password:',
 170+ 'config-db-install-help' => 'Enter the username and password that will be used to connect to the database during the installation process.',
 171+ 'config-db-account-lock' => 'Use the same username and password during normal operation',
 172+ 'config-db-wiki-account' => 'User account for normal operation',
 173+ 'config-db-wiki-help' => 'Enter the username and password that will be used to connect to the database during normal wiki operation.
 174+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.',
 175+ 'config-db-prefix' => 'Database table prefix:',
 176+ '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.
 177+Do not use spaces or hyphens.
 178+
 179+This field is usually left empty.',
 180+ 'config-db-charset' => 'Database character set',
 181+ 'config-charset-mysql5-binary' => 'MySQL 4.1/5.0 binary',
 182+ 'config-charset-mysql5' => 'MySQL 4.1/5.0 UTF-8',
 183+ 'config-charset-mysql4' => 'MySQL 4.0 backwards-compatible UTF-8',
 184+ 'config-charset-help' => "'''WARNING:''' If you use '''backwards-compatible UTF-8''' on MySQL 4.1+, and subsequently back up the database with <code>mysqldump</code>, it may destroy all non-ASCII characters, irreversibly corrupting your backups!.
 185+
 186+In '''binary mode''', MediaWiki stores UTF-8 text to the database in binary fields.
 187+This is more efficient than MySQL's UTF-8 mode, and allows you to use the full range of Unicode characters.
 188+In '''UTF-8 mode''', MySQL will know what character set your data is in, and can present and convert it appropriately,
 189+but it will not let you store characters above the [http://en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Basic Multilingual Plane].",
 190+ 'config-mysql-old' => 'MySQL $1 or later is required, you have $2.',
 191+ 'config-db-port' => 'Database port:',
 192+ 'config-db-schema' => 'Schema for MediaWiki',
 193+ 'config-db-ts2-schema' => 'Schema for tsearch2',
 194+ 'config-db-schema-help' => 'The above schemas are usually correct.
 195+Only change them if you know you need to.',
 196+ 'config-sqlite-dir' => 'SQLite data directory:',
 197+ 'config-sqlite-dir-help' => "SQLite stores all data in a single file.
 198+
 199+The directory you provide must be writable by the webserver during installation.
 200+
 201+It should '''not''' be accessible via the web, this is why we're not putting it where your PHP files
 202+are.
 203+
 204+We'll write out a <code>.htaccess</code> file along with it, but if that fails someone can gain
 205+access to your raw database. That includes raw user data (E-Mails, hashed passwords) as well as
 206+deleted revisions and other restricted data on the wiki.
 207+
 208+Consider putting the database somewhere altogether, for example <code>/var/lib/mediawiki/yourwiki</code>.",
 209+ 'config-type-mysql' => 'MySQL',
 210+ 'config-type-postgres' => 'PostgreSQL',
 211+ 'config-type-sqlite' => 'SQLite',
 212+ 'config-type-oracle' => 'Oracle',
 213+ 'config-header-mysql' => 'MySQL settings',
 214+ 'config-header-postgres' => 'PostgreSQL settings',
 215+ 'config-header-sqlite' => 'SQLite settings',
 216+ 'config-header-oracle' => 'Oracle settings',
 217+ 'config-invalid-db-type' => 'Invalid database type',
 218+ 'config-missing-db-name' => 'You must enter a value for "Database name"',
 219+ 'config-invalid-db-name' => 'Invalid database name "$1".
 220+It may only contain numbers, letters and underscores.',
 221+ 'config-invalid-db-prefix' => 'Invalid database prefix "$1".
 222+It may only contain numbers, letters and underscores.',
 223+ 'config-connection-error' => '$1.
 224+
 225+Check the host, username and password below and try again.',
 226+ 'config-invalid-schema' => 'Invalid schema for MediaWiki "$1".
 227+Use only letters, numbers and underscores.',
 228+ 'config-invalid-ts2schema' => 'Invalid schema for tsearch2 "$1".
 229+Use only letters, numbers and underscores.',
 230+ 'config-postgres-old' => 'PostgreSQL $1 or later is required, you have $2.',
 231+ 'config-sqlite-name-help' => 'Choose a name that identifies your wiki.
 232+Do not use spaces or hyphens.
 233+This will be used for the SQLite data file name.',
 234+ 'config-sqlite-parent-unwritable-group' => 'Cannot create the data directory <code><nowiki>$1</nowiki></code>, because the parent directory <code><nowiki>$2</nowiki></code> is not writable by the webserver.
 235+
 236+We\'ve determined the user your webserver is running as. Make the <code><nowiki>$3</nowiki></code>
 237+directory writable by it to continue. On a Unix/Linux system do:
 238+
 239+<pre>cd $2
 240+mkdir $3
 241+chgrp $4 $3
 242+chmod g+w $3</pre>',
 243+ 'config-sqlite-parent-unwritable-nogroup' => 'Cannot create the data directory <code><nowiki>$1</nowiki></code>, because the parent directory <code><nowiki>$2</nowiki></code> is not writable by the webserver.
 244+
 245+We couldn\'t determine the user your webserver is running as. Make the <code><nowiki>$3</nowiki></code>
 246+directory globally writable by it (and others!) to continue. On a Unix/Linux system do:
 247+
 248+<pre>cd $2
 249+mkdir $3
 250+chmod a+w $3</pre>',
 251+ 'config-sqlite-mkdir-error' => 'Error creating the data directory "$1".
 252+Check the location and try again.',
 253+ 'config-sqlite-dir-unwritable' => 'Unable to write to the directory "$1".
 254+Change its permissions so that the webserver can write to it, and try again.',
 255+ 'config-sqlite-connection-error' => '$1.
 256+
 257+Check the data directory and database name below and try again.',
 258+ 'config-sqlite-readonly' => 'File <code>$1</code> is not writeable.',
 259+ 'config-sqlite-cant-create-db' => 'Could not create database file <code>$1</code>.',
 260+ 'config-can-upgrade' => "There are MediaWiki tables in this database.
 261+To upgrade them to MediaWiki $1, click '''Continue'''.",
 262+ 'config-upgrade-done' => "Upgrade complete.
 263+
 264+You can now [$1 start using your wiki].
 265+
 266+If you want to regenerate your <code>LocalSettings.php</code> file, click the button below.
 267+This is '''not recommended''' unless you are having problems with your wiki.",
 268+ 'config-regenerate' => 'Regenerate LocalSettings.php →',
 269+ 'config-show-table-status' => 'SHOW TABLE STATUS query failed!',
 270+ 'config-unknown-collation' => "'''Warning:''' Datbase is using unrecognised collation.",
 271+ 'config-db-web-account' => 'Database account for web access',
 272+ '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.',
 273+ 'config-db-web-account-same' => 'Use the same account as for installation',
 274+ 'config-db-web-create' => 'Create the account if it does not already exist',
 275+ 'config-db-web-no-create-privs' => 'The account you specified for installation does not have enough privileges to create an account.
 276+The account you specify here must already exist.',
 277+ 'config-mysql-engine' => 'Storage engine:',
 278+ 'config-mysql-innodb' => 'InnoDB',
 279+ 'config-mysql-myisam' => 'MyISAM',
 280+ 'config-mysql-engine-help' => "'''InnoDB''' is almost always the best option, since it has good concurrency support.
 281+
 282+'''MyISAM''' may be faster in single-user or read-only installations.
 283+MyISAM databases tend to get corrupted more often than InnoDB databases.",
 284+ 'config-mysql-charset' => 'Database character set:',
 285+ 'config-mysql-binary' => 'Binary',
 286+ 'config-mysql-utf8' => 'UTF-8',
 287+ 'config-mysql-charset-help' => "In '''binary mode''', MediaWiki stores UTF-8 text to the database in binary fields.
 288+This is more efficient than MySQL's UTF-8 mode, and allows you to use the full range of Unicode characters.
 289+
 290+In '''UTF-8 mode''', MySQL will know what character set your data is in, and can present and convert it appropriately, but it will not let you store characters above the [http://en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Basic Multilingual Plane].",
 291+ 'config-site-name' => 'Name of wiki:',
 292+ 'config-site-name-help' => "This will appear in the browser's title bar and various other places.",
 293+ 'config-site-name-blank' => 'Enter a site name.',
 294+ 'config-project-namespace' => 'Project namespace:',
 295+ 'config-ns-generic' => 'Project',
 296+ 'config-ns-site-name' => 'Same as the wiki name: $1',
 297+ 'config-ns-other' => 'Other (specify)',
 298+ 'config-ns-other-default' => 'MyWiki',
 299+ 'config-project-namespace-help' => 'Following Wikipedia\'s example, many wikis keep their policy pages separate from their content pages, in a "\'\'\'project namespace\'\'\'".
 300+All page titles in this namespace start with a certain prefix, which you can specify here.
 301+Traditionally, this prefix is derived from the name of the wiki, but it cannot contain punctuation characters such as "#" or ":".',
 302+ 'config-ns-invalid' => 'The specified namespace "<nowiki>$1</nowiki>" is invalid.
 303+Specify a different project namespace',
 304+ 'config-admin-default-username' => 'WikiSysop',
 305+ 'config-admin-box' => 'Administrator account',
 306+ 'config-admin-name' => 'Your name:',
 307+ 'config-admin-password' => 'Password:',
 308+ 'config-admin-password-confirm' => 'Password again:',
 309+ 'config-admin-help' => 'Enter your preferred username here, for example "Joe Bloggs".
 310+This is the name you will use to log in to the wiki.',
 311+ 'config-admin-name-blank' => 'Enter an administrator username.',
 312+ 'config-admin-name-invalid' => 'The specified username "<nowiki>$1</nowiki>" is invalid.
 313+Specify a different username.',
 314+ 'config-admin-password-blank' => 'Enter a password for the administrator account.',
 315+ 'config-admin-password-same' => 'The password must not be the same as the username.',
 316+ 'config-admin-password-mismatch' => 'The two passwords you entered do not match.',
 317+ 'config-admin-email' => 'E-mail address:',
 318+ 'config-admin-email-help' => 'Enter an e-mail address here to allow you to receive e-mail from other users on the wiki, reset your password, and be notified of changes to pages on your watchlist.',
 319+ 'config-admin-error-user' => 'Internal error when creating an admin with the name "<nowiki>$1</nowiki>".',
 320+ 'config-admin-error-password' => 'Internal error when setting a password for the admin "<nowiki>$1</nowiki>": <pre>$2</pre>',
 321+ 'config-subscribe' => 'Subscribe to the [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce release announcements mailing list].',
 322+ 'config-subscribe-help' => 'This is a low-volume mailing list used for release announcements, including important security announcements.
 323+You should subscribe to it and update your MediaWiki installation when new versions come out.',
 324+ 'config-almost-done' => 'You are almost done!
 325+You can now skip the remaining configuration and install the wiki right now.',
 326+ 'config-optional-continue' => 'Ask me more questions.',
 327+ 'config-optional-skip' => "I'm bored already, just install the wiki.",
 328+ 'config-profile' => 'User rights profile:',
 329+ 'config-profile-wiki' => 'Traditional wiki',
 330+ 'config-profile-no-anon' => 'Account creation required',
 331+ 'config-profile-fishbowl' => 'Authorized editors only',
 332+ 'config-profile-private' => 'Private wiki',
 333+ 'config-profile-help' => "Wikis work best when you let as many people edit them as possible.
 334+In MediaWiki, it is easy to review the recent changes, and to revert any damage that is done by naive or malicious users.
 335+
 336+However, many have found MediaWiki to be useful in a wide variety of roles, and sometimes it is not easy to convince everyone of the benefits of the wiki way.
 337+So you have the the choice.
 338+
 339+A '''traditional wiki''' allows anyone to edit, without even logging in.
 340+A wiki with '''account creation required''' provides extra accountability, but may deter casual contributors.
 341+
 342+The '''authorized editors only''' scenario allows approved users to edit, but the public can view the pages, including history.
 343+A '''private wiki''' only allows approved users to view pages, with the same group allowed to edit.
 344+
 345+More complex user rights configurations are available after installation, see the [http://www.mediawiki.org/wiki/Manual:User_rights relevant manual entry].",
 346+ 'config-license' => 'Copyright and license:',
 347+ 'config-license-none' => 'No license footer',
 348+ 'config-license-gfdl-old' => 'GNU Free Documentation License 1.2 or later',
 349+ 'config-license-gfdl-current' => 'GNU Free Documentation License 1.3 or later',
 350+ 'config-license-pd' => 'Public Domain',
 351+ 'config-license-cc-choose' => 'A Creative Commons license',
 352+ 'config-license-help' => "Many public wikis put all contributions under a [http://freedomdefined.org/Definition free license].
 353+This helps to create a sense of community ownership and encourages long-term contribution.
 354+It is not generally necessary for a private or corporate wiki.
 355+
 356+If you want to be able to use text from Wikipedia, and you want Wikipedia to be able to accept text copied from your wiki, you should choose '''GNU Free Documentation License 1.2'''.
 357+However, this license has some features which make reuse and interpretation difficult.
 358+
 359+If Wikipedia-compatibility is not important, '''Creative Commons''' with the '''Share Alike''' option (cc-by-sa) is a good choice.",
 360+ 'config-email-settings' => 'E-mail settings',
 361+ 'config-enable-email' => 'Enable outbound e-mail',
 362+ 'config-enable-email-help' => "If you want e-mail to work, [http://www.php.net/manual/en/mail.configuration.php PHP's mail settings] need to be configured correctly.
 363+If you do not want any e-mail features, you can disable them here.",
 364+ 'config-email-user' => 'Enable user-to-user e-mail',
 365+ 'config-email-user-help' => 'All users to send each other e-mail, if they have enabled it in their preferences',
 366+ 'config-email-usertalk' => 'Enable user talk page notification',
 367+ 'config-email-usertalk-help' => 'Allow users to receive notifications on user talk page changes, if they have enabled it in their preferences',
 368+ 'config-email-watchlist' => 'Enable watchlist notification',
 369+ 'config-email-watchlist-help' => 'Allow users to receive notifications to their watched pages, if they have enabled it in their preferences',
 370+ 'config-email-auth' => 'Enable e-mail authentication',
 371+ 'config-email-auth-help' => "If this option is enabled, users have to confirm their e-mail address using a link sent to them whenever they set or change it.
 372+Only authenticated e-mail addresses can receive e-mails from other users or change notification e-mails.
 373+Setting this option is '''recommended''' for public wikis because of potential abuse of the e-mail features.",
 374+ 'config-email-sender' => 'Return e-mail address:',
 375+ 'config-email-sender-help' => 'Enter the e-mail address to use as the return address on outbound e-mail.
 376+This is where bounces will be sent.
 377+Many mail servers require at least the domain name part to be valid.',
 378+ 'config-upload-settings' => 'Images and file uploads',
 379+ 'config-upload-enable' => 'Enable file uploads',
 380+ 'config-upload-help' => "File uploads potentially expose your server to security risks.
 381+For more information, read the [http://www.mediawiki.org/wiki/Manual:Security security section] in the manual.
 382+
 383+To enable file uploads, change the mode on the <code>images</code> subdirectory under MediaWiki's root directory so that the web server can write to it.
 384+Then enable this option.",
 385+ 'config-upload-deleted' => 'Directory for deleted files:',
 386+ 'config-upload-deleted-help' => 'Choose a directory in which to archive deleted files.
 387+Ideally, this should not be accessible from the web.',
 388+ 'config-logo' => 'Logo URL:',
 389+ 'config-logo-help' => "MediaWiki's default skin includes space for a 135x135 pixel logo in the top left corner.
 390+Upload an image of the appropriate size, and enter the URL here.
 391+
 392+If you do not want a logo, leave this box blank.",
 393+ 'config-cc-error' => 'The Creative Commons license chooser gave no result.
 394+Enter the license name manually.',
 395+ 'config-cc-again' => 'Pick again...',
 396+ 'config-cc-not-chosen' => 'Choose which Creative Commons license you want and click "proceed".',
 397+ 'config-advanced-settings' => 'Advanced configuration',
 398+ 'config-cache-options' => 'Settings for object caching:',
 399+ 'config-cache-help' => 'Object caching is used to improve the speed of MediaWiki by caching frequently used data.
 400+Medium to large sites are highly encouraged to enable this, and small sites will see benefits as well.',
 401+ 'config-cache-none' => 'No caching.
 402+No functionality is removed, but speed may be impacted.',
 403+ 'config-cache-accel' => 'PHP object caching (APC, eAccelerator or XCache)',
 404+ 'config-cache-memcached' => 'Use Memcached (requires additional setup and configuration)',
 405+ 'config-cache-db' => 'Cache data into the database',
 406+ 'config-cache-anything' => 'MediaWiki will attempt to cache data anywhere possible, except in Memcached, unless indicated explicitely',
 407+ 'config-memcached-servers' => 'Memcached servers:',
 408+ 'config-memcached-help' => 'List of IP addresses to use for Memcached.
 409+Should be separated with commas and specify the port to be used (for example: 1.2.3.4:56, 7.8.9.10:11).',
 410+ 'config-extensions' => 'Extensions',
 411+ 'config-extensions-help' => 'The extensions listed above were detected in your <code>./extensions</code> directory.
 412+
 413+They may require additional configuration, but you can enable them now',
 414+ 'config-install-step-done' => 'Done',
 415+ 'config-install-step-failed' => 'Failed',
 416+ 'config-install-extensions' => 'Including extensions',
 417+ 'config-install-database' => 'Setting up database',
 418+ 'config-install-pg-schema-failed' => 'Tables creation failed.
 419+Make sure that the user "$1" can write to the schema "$2".',
 420+ 'config-install-tables' => 'Creating tables',
 421+ 'config-install-interwiki-sql' => 'Could not find file <code>interwiki.sql</code>',
 422+ 'config-install-secretkey' => 'Generating secret key',
 423+ 'config-insecure-secretkey' => "'''Warning:''' Unable to create secure <code>\$wgSecretKey</code>.
 424+Consider changing it manually.",
 425+ 'config-install-sysop' => 'Creating administrator user account',
 426+ 'config-install-localsettings' => 'Creating <code>LocalSettings.php</code>',
 427+ 'config-install-localsettings-unwritable' => 'Warning: Could not write <code>LocalSettings.php</code>.
 428+Create it yourself, using the following text:',
 429+ 'config-install-done' => "'''Congratulations!'''
 430+You have successfully installed MediaWiki.
 431+
 432+We've generated a <code>LocalSettings.php</code> file for you. It contains all your configuration.
 433+
 434+You will need to move it from <code>./config/LocalSettings.php</code> to <code>./LocalSettings.php</code> in order for MediaWiki to work:
 435+
 436+On a Unix/Linux system:
 437+
 438+<pre>
 439+mv ./config/LocalSettings.php ./LocalSettings.php
 440+</pre>
 441+
 442+When that's done, you can [$1 '''enter your wiki''']",
 443+ 'config-install-done-moved' => "'''Congratulations!'''
 444+You have successfully installed MediaWiki.
 445+
 446+[$1 Enter your wiki]",
 447+);
 448+
 449+/** Dutch (Nederlands)
 450+ * @author Siebrand
 451+ */
 452+$messages['nl'] = array(
 453+ 'config-title' => 'Installatie MediaWiki $1',
 454+ 'config-information' => 'Informatie',
 455+ 'config-session-error' => 'Fout bij het begin van de sessie: $1',
 456+ 'config-session-expired' => 'Uw sessiegegevens zijn verlopen.
 457+Sessies zijn ingesteld om een levensduur van $1 te hebben.
 458+U kunt deze wijzigen via de instelling <code>session.gc_maxlifetime</code> in php.ini.
 459+Begin het installatieproces opnieuw.',
 460+ 'config-no-session' => 'Uw sessiegegevens zijn verloren gegaan.
 461+Controleer uw php.ini en zorg dat er een juiste map is ingesteld voor <code>session.save_path</code>.',
 462+ 'config-session-path-bad' => 'Uw <code>session.save_path</code> (<code>$1</code>) lijkt onjuist of er kan niet in geschreven worden.',
 463+ 'config-show-help' => 'Hulp',
 464+ 'config-hide-help' => 'Hulp verbergen',
 465+ 'config-your-language' => 'Uw taal:',
 466+ 'config-your-language-help' => 'Selecteer een taal om tijdens het installatieproces te gebruiken.',
 467+ 'config-wiki-language' => 'Wikitaal:',
 468+ 'config-wiki-language-help' => 'Selecteer de taal waar de wiki voornamelijk in wordt geschreven.',
 469+ 'config-back' => '← Terug',
 470+ 'config-continue' => 'Doorgaan →',
 471+ 'config-page-language' => 'Taal',
 472+ 'config-page-welcome' => 'Welkom bij MediaWiki!',
 473+ 'config-page-dbconnect' => 'Verbinding maken met database',
 474+ 'config-page-upgrade' => 'Bestaande bijwerken',
 475+ 'config-page-dbsettings' => 'Databaseinstellingen',
 476+ 'config-page-name' => 'Naam',
 477+ 'config-page-options' => 'Opties',
 478+ 'config-page-install' => 'Installeren',
 479+ 'config-page-complete' => 'Afgerond!',
 480+ 'config-page-restart' => 'Installatie herstarten',
 481+ 'config-page-readme' => 'Lees mij',
 482+ 'config-page-releasenotes' => 'Release notes',
 483+ 'config-page-copying' => 'Kopiëren',
 484+ 'config-page-upgradedoc' => 'Bijwerken',
 485+ 'config-help-restart' => 'Wilt u alle opgeslagen gegevens die u hebt ingevoerd wissen en het installatieproces opnieuw starten?',
 486+ 'config-restart' => 'Ja, opnieuw starten',
 487+ 'config-authors' => 'MediaWiki is Copyright © 2001-2010 door Magnus Manske, Brion Vibber, Lee Daniel Crocker, Tim Starling, Erik Möller, Gabriel Wicke, Ævar Arnfjörð Bjarmason, Niklas Laxström, Domas Mituzas, Rob Church, Yuri Astrakhan, Aryeh Gregor, Aaron Schulz, Andrew Garrett, Raimond Spekking, Alexandre Emsenhuber, Siebrand Mazeland, Chad Horohoe en anderen.',
 488+ 'config-env-good' => 'De omgeving is gecontroleerd.
 489+U kunt MediaWiki installeren.',
 490+ 'config-env-bad' => 'De omgeving is gecontroleerd.
 491+U kunt MediaWiki niet installeren.',
 492+ 'config-env-php' => 'PHP $1 is geïnstalleerd.',
 493+ 'config-env-latest-ok' => 'U bent bezig de meest recente versie van MediaWiki te installeren.',
 494+ 'config-env-latest-new' => "'''Let op:''' U bent bezig een ontwikkelversie van MediaWiki te installeren.",
 495+ 'config-env-latest-old' => "'''Waarschuwing:''' U bent bezig een verouderde versie van MediaWiki te installeren.",
 496+ 'config-env-latest-help' => 'U bent bezig versie $1 te installeren, maar de meest recente versie is $2.
 497+U wordt aangeraden de meest recente versie te gebruiken die u kunt downloaden van [http://www.mediawiki.org/wiki/Download mediawiki.org].',
 498+ 'config-no-db' => 'Er kon geen geschikte databasedriver geladen worden!',
 499+ 'config-no-db-help' => 'U moet een databasedriver installeren voor PHP.
 500+De volgende databases worden ondersteund: $1.
 501+
 502+Als u op een gedeelde omgeving zit, vraag dan uw hostingprovider een geschikte databasedriver te installeren.
 503+Als u PHP zelf hebt gecompileerd, wijzig dan uw instellingen zodat een databasedriver wordt geactiveerd, bijvoorbeeld via <code>./configure --with-mysql</code>.',
 504+ 'config-have-db' => 'Gevonden databasedrivers: $1.',
 505+ 'config-register-globals' => "'''Waarschuwing: De PHP-optie <code>[http://php.net/register_globals register_globals]</code> is ingeschakeld.'''
 506+'''Schakel deze uit als dat mogelijk is.'''
 507+MediaWiki kan ermee werken, maar uw server is dan meer kwetsbaar voor beveiligingslekken.",
 508+ 'config-magic-quotes-runtime' => "'''Onherstelbare fout: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] is actief!'''
 509+Deze instelling zorgt voor gegevenscorruptie.
 510+U kunt MediaWiki niet installeren tenzij deze instelling is uitgeschakeld.",
 511+ 'config-magic-quotes-sybase' => "'''Onherstelbare fout: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_sybase] is actief!'''
 512+Deze instelling zorgt voor gegevenscorruptie.
 513+U kunt MediaWiki niet installeren tenzij deze instelling is uitgeschakeld.",
 514+ 'config-mbstring' => "'''Onherstelbare fout: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] is actief!'''
 515+Deze instelling zorgt voor gegevenscorruptie.
 516+U kunt MediaWiki niet installeren tenzij deze instelling is uitgeschakeld.",
 517+ 'config-ze1' => "'''Onherstelbare fout: [http://www.php.net/manual/en/ini.core.php zend.ze1_compatibility_mode] is actief!'''
 518+Deze instelling zorgt voor grote problemen in MediaWiki.
 519+U kunt MediaWiki niet installeren tenzij deze instelling is uitgeschakeld.",
 520+ 'config-safe-mode' => "'''Waarschuwing:'''
 521+'''PHP's [http://www.php.net/features.safe-mode veilige modus] actief is.'''
 522+Dit kan problemen veroorzaken, vooral bij het uploaden van bestanden en ondersteuning van <code>math</code>.",
 523+ 'config-xml-bad' => 'De XML-module van PHP ontbreekt.
 524+MediaWiki heeft de functies van deze module nodig en werkt niet zonder deze module.',
 525+ 'config-pcre' => 'De ondersteuningsmodule PCRE lijkt te missen.
 526+MediaWiki vereist dat de met Perl compatibele reguliere expressies werken.',
 527+ 'config-memory-none' => 'PHP is ingesteld zonder <code>memory_limit</code>',
 528+ 'config-memory-ok' => "PHP's <code>memory_limit</code> is $1. In orde.",
 529+ 'config-memory-raised' => "PHP's <code>memory_limit</code> is $1. Verhoogd tot $2.",
 530+ 'config-memory-bad' => "'''Waarschuwing:''' PHP's <code>memory_limit</code> is $1.
 531+Dit is waarschijnlijk te laag.
 532+De installatie kan mislukken!",
 533+ 'config-xcache' => '[http://trac.lighttpd.net/xcache/ XCache] geïnstalleerd',
 534+ 'config-apc' => '[http://www.php.net/apc APC] geïnstalleerd',
 535+ 'config-eaccel' => '[http://eaccelerator.sourceforge.net/ eAccelerator] geïnstalleerd',
 536+ 'config-no-cache' => "'''Waarschuwing:''' [http://eaccelerator.sourceforge.net eAccelerator], [http://www.php.net/apc APC] of [http://trac.lighttpd.net/ xcache / XCache] is niet aangetroffen.
 537+Het cachen van objecten is niet ingeschakeld.",
 538+ 'config-diff3-good' => 'GNU diff3 aangetroffen: <code>$1</code>.',
 539+ 'config-diff3-bad' => 'GNU diff3 niet aangetroffen.',
 540+ 'config-imagemagick' => 'ImageMagick aangetroffen: <code>$1</code>.
 541+Het aanmaken van miniaturen van afbeeldingen wordt ingeschakeld als u uploaden inschakelt.',
 542+ 'config-gd' => 'Ingebouwde GD grafische bibliotheek aangetroffen.
 543+Het aanmaken van miniaturen van afbeeldingen wordt ingeschakeld als u uploaden inschakelt.',
 544+ 'config-no-scaling' => 'De GD-bibliotheek en ImageMagick zijn niet aangetroffen.
 545+Het maken van miniaturen van afbeeldingen wordt uitgeschakeld.',
 546+ 'config-dir' => 'Installatiemap: <code>$1</code>.',
 547+ 'config-uri' => 'Script URI-pad: <code>$1</code>.',
 548+ 'config-no-uri' => "'''Fout:''' de huidige URI kon niet vastgesteld worden.
 549+De installatie is afgebroken.",
 550+ 'config-file-extension' => 'MediaWiki wordt geinstalleerd met <code>$1</code> als bestandsextensie.',
 551+ 'config-shell-locale' => 'Als shelllocale is "$1" herkend',
 552+ 'config-uploads-safe' => 'De uploadmap is beveiligd tegen het arbitrair uitvoeren van scripts.',
 553+ 'config-uploads-not-safe' => "'''Waarschuwing:''' uw uploadmap <code>$1</code> kan gebruikt worden voor het arbitrair uitvoeren van scripts.
 554+Hoewel MediaWiki alle toegevoegde bestanden controleert op bedreigingen, is het zeer aan te bevelen het [http://www.mediawiki.org/wiki/Manual:Security#Upload_security beveiligingslek te verhelpen] alvorens uploads in te schakelen.",
 555+ 'config-db-type' => 'Databasetype:',
 556+ 'config-db-host' => 'Databasehost:',
 557+ 'config-db-host-help' => 'Als uw databaseserver een andere server is, voer dan de hostnaam of het IP-adres hier in.
 558+Als u gebruik maakt van gedeelde webhosting, hoort uw provider u de juiste hostnaam te hebben verstrekt.',
 559+ 'config-db-wiki-settings' => 'Identificeer deze wiki',
 560+ 'config-db-name' => 'Databasenaam:',
 561+ 'config-db-name-help' => 'Kies een naam die uw wiki identificeert.
 562+Er mogen geen spaties of koppeltekens gebruikt worden.
 563+Als u gebruik maakt van gedeelde webhosting, dan hoort uw provider ofwel u een te gebruiken databasenaam gegeven te hebben, of u aangegeven te hebben hoe u databases kunt aanmaken.',
 564+ 'config-db-install-account' => 'Gebruiker voor installatie',
 565+ 'config-db-username' => 'Gebruikersnaam voor database:',
 566+ 'config-db-password' => 'Wachtwoord voor database:',
 567+ 'config-db-install-help' => 'Voer de gebruikersnaam en het wachtwoord in die worden gebruikt voor de databaseverbinding tijdens het installatieproces.',
 568+ 'config-db-account-lock' => 'Dezelfde gebruiker en wachwoord gebruiken na de installatie',
 569+ 'config-db-wiki-account' => 'Gebruiker voor na de installatie',
 570+ 'config-db-wiki-help' => 'Selecteer de gebruikersnaam en het wachtwoord die gebruikt worden om verbinding te maken met de database na de installatie.
 571+Als de gebruiker niet bestaat en de gebruiker die tijdens de installatie gebruikt wordt voldoende rechten heeft, wordt deze gebruiker aangemaakt met de minimaal benodigde rechten voor het laten werken van de wiki.',
 572+ 'config-db-prefix' => 'Databasetabelvoorvoegsel:',
 573+ 'config-db-prefix-help' => "Als u een database moet gebruiken voor meerdere wiki's, of voor MediaWiki en een andere applicatie, dan kunt u ervoor kiezen om een voorvoegsel toe te voegen aan de tabelnamen om conflicten te voorkomen.
 574+Gebruik geen spaties of koppeltekens.
 575+
 576+Dit veld wordt meestal leeg gelaten.",
 577+ 'config-db-charset' => 'Tekenset voor de database',
 578+ 'config-charset-mysql5-binary' => 'MySQL 4.1/5.0 binair',
 579+ 'config-charset-mysql5' => 'MySQL 4.1/5.0 UTF-8',
 580+ 'config-charset-mysql4' => 'MySQL 4.0 UTF-8-compatibel',
 581+ 'config-mysql-old' => 'U moet MySQL $1 of later gebruiken.
 582+U gebruikt $2.',
 583+ 'config-db-port' => 'Databasepoort:',
 584+ 'config-db-schema' => 'Schema voor MediaWiki',
 585+ 'config-db-ts2-schema' => 'Schema voor tsearch2',
 586+ 'config-db-schema-help' => "De bovenstaande schema's kloppen meestal.
 587+Wijzig ze alleen als u weet dat u ze nodig hebt.",
 588+ 'config-sqlite-dir' => 'Gegevensmap voor SQLite:',
 589+ 'config-type-mysql' => 'MySQL',
 590+ 'config-type-postgres' => 'PostgreSQL',
 591+ 'config-type-sqlite' => 'SQLite',
 592+ 'config-type-oracle' => 'Oracle',
 593+ 'config-header-mysql' => 'MySQL-instellingen',
 594+ 'config-header-postgres' => 'PostgreSQL-instellingen',
 595+ 'config-header-sqlite' => 'SQLite-instellingen',
 596+ 'config-header-oracle' => 'Oracle-instellingen',
 597+ 'config-invalid-db-type' => 'Ongeldig databasetype',
 598+ 'config-missing-db-name' => 'U moet een waarde ingeven voor "Databasenaam"',
 599+ 'config-invalid-db-name' => 'Ongeldige database naam "$1".
 600+Deze mag alleen cijfers, letters en liggende streepjes bevatten.',
 601+ 'config-invalid-db-prefix' => 'Ongeldig databasevoorvoegsel "$1".
 602+Dit mag alleen cijfers, letters en liggende streepjes bevatten.',
 603+ 'config-connection-error' => '$1.
 604+
 605+Controleer de host, gebruikersnaam en wachtwoord hieronder in en probeer het opnieuw.',
 606+ 'config-invalid-schema' => 'Ongeldige schema voor MediaWiki "$1".
 607+Gebruik alleen letters, cijfers en liggende streepjes.',
 608+ 'config-invalid-ts2schema' => 'Ongeldig schema voor tsearch "$1".
 609+Gebruik alleen letters, cijfers en liggende streepjes.',
 610+ 'config-postgres-old' => 'PostgreSQL $1 of hoger is vereist.
 611+U gebruikt $2.',
 612+ 'config-sqlite-name-help' => 'Kies een naam die uw wiki identificeert.
 613+Gebruik geen spaties of koppeltekens.
 614+Deze naam wordt gebruikt voor het gegevensbestands van SQLite.',
 615+ 'config-sqlite-mkdir-error' => 'Er is een fout opgetreden bij het aanmaken van de gegevensmap "$1".
 616+Controleer de locatie en probeer het opnieuw.',
 617+ 'config-sqlite-dir-unwritable' => 'Het was niet mogelijk in de map "$1" te schrijven.
 618+Wijzig de rechten zodat de webserver erin kan schrijven en probeer het opnieuw.',
 619+ 'config-sqlite-connection-error' => '$1.
 620+
 621+Controleer de map voor gegevens en de databasenaam hieronder en probeer het opnieuw.',
 622+ 'config-sqlite-readonly' => 'Het bestand <code>$1</code> kan niet geschreven worden.',
 623+ 'config-sqlite-cant-create-db' => 'Het was niet mogelijk het databasebestand <code>$1</code> aan te maken.',
 624+ 'config-can-upgrade' => "Er staan al tabellen voor MediaWiki in deze database.
 625+Klik op '''Doorgaan''' om ze bij te werken naar MediaWiki $1.",
 626+ 'config-upgrade-done' => "Het bijwerken is afgerond.
 627+
 628+Uw kunt [$1 uw wiki gebruiken].
 629+
 630+Als u uw <code>LocalSettings.php</code> opnieuw wilt aanmaken, klik dan op de knop hieronder.
 631+Dit is '''niet aan te raden''' tenzij u problemen hebt met uw wiki.",
 632+ 'config-regenerate' => 'LocalSettings.php opnieuw aanmaken →',
 633+ 'config-show-table-status' => 'Het uitvoeren van SHOW TABLE STATUS is mislukt!',
 634+ 'config-unknown-collation' => "'''Waarschiwing:''' de database gebruikt een collatie die niet wordt herkend.",
 635+ 'config-db-web-account' => 'Databasegebruiker voor webtoegang',
 636+ 'config-db-web-help' => 'Selecteer de gebruikersnaam en het wachtwoord die de webserver gebruikt om verbinding te maken met de databaseserver na de installatie.',
 637+ 'config-db-web-account-same' => 'Dezelfde gebruiker gebruiken als voor de installatie',
 638+ 'config-db-web-create' => 'Maak de gebruiker aan als deze nog niet bestaat',
 639+ 'config-db-web-no-create-privs' => 'De gebruiker die u hebt opgegeven voor de installatie heeft niet voldoende rechten om een gebruiker aan te maken.
 640+De gebruiker die u hier opgeeft moet al bestaan.',
 641+ 'config-mysql-engine' => 'Opslagmethode:',
 642+ 'config-mysql-innodb' => 'InnoDB',
 643+ 'config-mysql-myisam' => 'MyISAM',
 644+ 'config-mysql-engine-help' => "'''InnoDB''' is vrijwel altijd de beste instelling, omdat deze goed omgaat met meerdere verzoeken tegelijkertijd.
 645+
 646+'''MyISAM''' is bij een zeer beperkt aantal gebruikers mogelijk sneller, of als de wiki alleen-lezen is.
 647+MyISAM-databases raken vaker corrupt dan InnoDB-databases.",
 648+ 'config-mysql-charset' => 'Tekenset voor de database:',
 649+ 'config-mysql-binary' => 'Binair',
 650+ 'config-mysql-utf8' => 'UTF-8',
 651+ 'config-site-name' => 'Naam van de wiki:',
 652+ 'config-site-name-help' => 'Deze naam verschijnt in de titelbalk van browsers en op andere plaatsen.',
 653+ 'config-site-name-blank' => 'Geef een naam op voor de site.',
 654+ 'config-project-namespace' => 'Projectnaamruimte:',
 655+ 'config-ns-generic' => 'Project',
 656+ 'config-ns-site-name' => 'Zelfde als de wiki: $1',
 657+ 'config-ns-other' => 'Andere (geen aan welke)',
 658+ 'config-ns-other-default' => 'MijnWiki',
 659+ 'config-project-namespace-help' => "In het kielzog van Wikipedia beheren veel wiki's hun beleidspagina's apart van hun inhoudelijke pagina's in een \"'''projectnaamruimte'''\".
 660+Alle paginanamen in deze naamruimte beginnen met een bepaald voorvoegsel dat u hier kunt aangeven.
 661+Dit voorvoegsel wordt meestal afgeleid van de naam van de wiki, maar het kan geen bijzondere tekens bevatten als \"#\" of \":\".",
 662+ 'config-ns-invalid' => 'De aangegeven naamruimte "<nowiki>$1</nowiki>" is ongeldig.
 663+Geef een andere naamruimte op.',
 664+ 'config-admin-default-username' => 'WikiBeheerder',
 665+ 'config-admin-box' => 'Beheerdersaccount',
 666+ 'config-admin-name' => 'Uw naam:',
 667+ 'config-admin-password' => 'Wachtwoord:',
 668+ 'config-admin-password-confirm' => 'Wachtwoord opnieuw:',
 669+ 'config-admin-help' => 'Voor de gebruikersnaam hier in, bijvoorbeeld "Jan Jansen".
 670+Dit is de naam die wordt gebruikt om aan de melden bij de wiki.',
 671+ 'config-admin-name-blank' => 'Geef een gebruikersnaam op voor de beheerder.',
 672+ 'config-admin-name-invalid' => 'De opgegeven gebruikersnaam "<nowiki>$1</nowiki>" is ongeldig.
 673+Kies een andere gebruikersnaam.',
 674+ 'config-admin-password-blank' => 'Voer een wachtwoord voor de beheerder in.',
 675+ 'config-admin-password-same' => 'Het wachtwoord mag niet hetzelfde zijn als de gebruikersnaam.',
 676+ 'config-admin-password-mismatch' => 'De twee door u ingevoerde wachtwoorden komen niet overeen.',
 677+ 'config-admin-email' => 'E-mailadres:',
 678+ 'config-admin-email-help' => "Voer hier een e-mailadres in om e-mail te kunnen ontvangen van andere gebruikers op de wiki, uw wachtwoord opnieuw in te stellen en op de hoogte te worden gehouden van wijzigingen van pagina's op uw volglijst.",
 679+ 'config-subscribe' => 'Abonneren op de [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce mailinglijst releaseaankondigen].',
 680+ 'config-subscribe-help' => 'Dit is een mailinglijst met een laag volume voor aankondigingen van nieuwe versies, inclusief belangrijke aankondigingen met betrekking tot beveiliging.
 681+Abonneer uzelf erop en werk uw MediaWiki-installatie bij als er nieuwe versies uitkomen.',
 682+ 'config-almost-done' => 'U bent bijna klaar!
 683+Als u wilt kunt u de overige instellingen overslaan en de wiki nu installeren.',
 684+ 'config-optional-continue' => 'Meer vragen',
 685+ 'config-optional-skip' => 'Installeer de wiki',
 686+ 'config-profile' => 'Gebruikersrechtenprofiel:',
 687+ 'config-profile-wiki' => 'Traditionele wiki',
 688+ 'config-profile-no-anon' => 'Gebruiker aanmaken verplicht',
 689+ 'config-profile-private' => 'Privéwiki',
 690+ 'config-license' => 'Auteursrechten en licentie:',
 691+ 'config-license-none' => 'Geen licentie in de voettekst',
 692+ 'config-license-gfdl-old' => 'GNU Free Documentation License 1.2 of hoger',
 693+ 'config-license-gfdl-current' => 'GNU Free Documentation License 1.3 of hoger',
 694+ 'config-license-pd' => 'Publiek domein',
 695+ 'config-license-cc-choose' => 'Een Creative Commons-licentie',
 696+ 'config-email-settings' => 'E-mailinstellingen',
 697+ 'config-enable-email' => 'Uitgaande e-mail inschakelen',
 698+ 'config-enable-email-help' => "Als u wilt dat e-mailen mogelijk is, dan moeten [http://www.php.net/manual/en/mail.configuration.php PHP's e-mailinstellingen] correct zijn.
 699+Als u niet wilt dat e-mailen mogelijk is, dan kunt u de instellingen hier uitschakelen.",
 700+ 'config-email-user' => 'E-mail tussen gebruikers inschakelen',
 701+ 'config-email-user-help' => 'Gebruikers toestaan e-mail aan elkaar te verzenden als dit in de voorkeuren is ingesteld',
 702+ 'config-email-usertalk' => 'Gebruikersoverlegnotificatie inschakelen',
 703+ 'config-email-usertalk-help' => 'Gebruikers toestaan notificaties te ontvangen bij wijzigingen op de eigen overlegpagina als dit in de voorkeuren is ingesteld',
 704+ 'config-email-watchlist' => 'Volglijstnotificatie inschakelen',
 705+ 'config-email-watchlist-help' => "Gebruikers toestaan notificaties te ontvangen bij wijzigingen van pagina's op hun volglijst als dit in de voorkeuren is ingesteld",
 706+ 'config-email-auth' => 'E-mailbevestiging inschakelen',
 707+ 'config-email-auth-help' => "Als deze instelling actief is, moeten gebruikers hun e-mailadres bevestigen via een verwijziging die ze per e-mail wordt toegezonden.
 708+Alleen bevestigde e-mailadressen kunnen e-mail ontvangen van andere gebruikers of wijzigingsnotificaties ontvangen.
 709+Het inschakelen van deze instelling is '''aan te raden''' voor openbare wiki's vanwege de mogelijkheden voor misbruik van e-mailmogelijkheden.",
 710+ 'config-email-sender' => 'E-mailadres voor antwoorden:',
 711+ 'config-email-sender-help' => 'Voer het e-mailadres in dat u wilt gebruiken als antwoordadres voor uitgaande e-mail.
 712+Als een e-mail niet bezorgd kan worden, wordt dat op dit e-mailadres gemeld.
 713+Veel mailservers vereisen dat tenminste het domein bestaat.',
 714+ 'config-upload-settings' => 'Afbeeldingen en bestanden uploaden',
 715+ 'config-upload-enable' => 'Uploaden van bestanden inschakelen',
 716+ 'config-upload-deleted' => 'Map voor verwijderde bestanden:',
 717+ 'config-upload-deleted-help' => 'Kies een map waarin verwijderde bestanden gearchiveerd kunnen worden.
 718+Idealiter is deze map niet via het web te benaderen.',
 719+ 'config-logo' => 'URL voor logo:',
 720+ 'config-logo-help' => 'Het standaarduiterlijk van MediaWiki bevat ruimte voor een logo van 135x135 pixels in de linker bovenhoek.
 721+Upload een afbeelding met de juiste afmetingen en voer de URL hier in.
 722+
 723+Als u geen logo wilt gebruiken, kunt u dit veld leeg laten.',
 724+ 'config-cc-error' => 'De licentiekiezer van Creative Commons heeft geen resultaat opgeleverd.
 725+Voer de licentie handmatig in.',
 726+ 'config-cc-not-chosen' => 'Kies alstublieft de Creative Commons-licentie die u wilt gebruiken en klik op "doorgaan".',
 727+ 'config-advanced-settings' => 'Gevorderde instellingen',
 728+ 'config-cache-options' => 'Instellingen voor het cachen van objecten:',
 729+ 'config-cache-help' => 'Het cachen van objecten wordt gebruikt om de snelheid van MediaWiki te verbeteren door vaak gebruikte gegevens te bewaren.
 730+Middelgrote tot grote websites wordt geadviseerd dit in te schakelen en ook kleine sites merken de voordelen.',
 731+ 'config-cache-none' => 'Niets cachen.
 732+Er gaat geen functionaliteit verloren, maar dit kan invloed hebben op de snelheid.',
 733+ 'config-cache-accel' => 'Cachen van objecten via PHP (APC, eAccelerator or XCache)',
 734+ 'config-cache-memcached' => 'Memcached gebruiken (dit vereist aanvullende instellingen)',
 735+ 'config-cache-db' => 'Gegevens cachen in de database',
 736+ 'config-cache-anything' => 'MediaWiki zal proberen de gegevens te cachen waar mogelijk, behalve in Memcached, tenzij expliciet aangegeven',
 737+ 'config-memcached-servers' => 'Memcachedservers:',
 738+ 'config-memcached-help' => "Lijst met IP-adressen te gebruiken voor Memcached.
 739+Deze moeten worden gescheiden met komma's en geef de poort op die moet worden gebruikt (bijvoorbeeld: 1.2.3.4:56, 7.8.9.10:11).",
 740+ 'config-extensions' => 'Uitbreidingen',
 741+ 'config-extensions-help' => 'De bovenstaande uitbreidingen zijn aangetroffen in de map <code>./extensions</code>.
 742+
 743+Mogelijk moet u aanvullende instellingen maken, maar u kunt deze uitbreidingen nu inschakelen.',
 744+ 'config-install-step-done' => 'Afgerond',
 745+ 'config-install-step-failed' => 'Mislukt',
 746+ 'config-install-extensions' => 'Inclusief uitbreidingen',
 747+ 'config-install-database' => 'Database inrichten',
 748+ 'config-install-pg-schema-failed' => 'Het aanmaken van de tabellen is mislukt.
 749+Zorg dat de gebruiker "$1" in het schema "$2" mag schrijven.',
 750+ 'config-install-tables' => 'Tabellen aanmaken',
 751+ 'config-install-interwiki-sql' => 'Het bestand <code>interwiki.sql</code> is niet aangetroffen',
 752+ 'config-install-secretkey' => 'Geheime sleutel aanmaken',
 753+ 'config-insecure-secretkey' => 'Waarschuwing: het was niet mogelijk een veilige <code>$wgSecretKey</code> aan te maken.
 754+Overweeg deze handmatig te wijzigen.',
 755+ 'config-install-sysop' => 'Gebruiker voor beheerder aanmaken',
 756+ 'config-install-localsettings' => '<code>LocalSettings.php</code> aanmaken',
 757+ 'config-install-localsettings-unwritable' => "'''Waarschuwing:''' het was niet mogelijk <code>LocalSettings.php</code> weg te schrijven.
 758+Maak dit bestand zelf aan met de volgende inhoud:",
 759+ 'config-install-done-moved' => "'''Gefeliciteerd!'''
 760+U hebt MediaWiki geïnstalleerd.
 761+
 762+[$1 Naar uw wiki]",
 763+);
 764+
 765+/**
 766+ * Russian (Русский)
 767+ * @author MaxSem
 768+ */
 769+$messages['ru'] = array(
 770+ 'config-title' => 'Установка MediaWiki $1',
 771+ 'config-page-language' => 'Язык',
 772+ 'config-admin-default-username' => 'ВикиАдминистратор',
 773+);
\ No newline at end of file
Property changes on: trunk/phase3/includes/installer/Installer.i18n.php
___________________________________________________________________
Added: svn:eol-style
1774 + native
Index: trunk/phase3/includes/installer/WebInstaller.php
@@ -0,0 +1,1721 @@
 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+ 'Welcome',
 25+ 'DBConnect',
 26+ 'Upgrade',
 27+ 'DBSettings',
 28+ 'Name',
 29+ 'Options',
 30+ 'Install',
 31+ 'Complete',
 32+ );
 33+
 34+ /**
 35+ * Out of sequence pages, selectable by the user at any time
 36+ */
 37+ var $otherPages = array(
 38+ 'Restart',
 39+ 'Readme',
 40+ 'ReleaseNotes',
 41+ 'Copying',
 42+ 'UpgradeDoc', // Can't use Upgrade due to Upgrade step
 43+ );
 44+
 45+ /**
 46+ * Array of pages which have declared that they have been submitted, have validated
 47+ * their input, and need no further processing
 48+ */
 49+ var $happyPages;
 50+
 51+ /**
 52+ * List of "skipped" pages. These are pages that will automatically continue
 53+ * to the next page on any GET request. To avoid breaking the "back" button,
 54+ * they need to be skipped during a back operation.
 55+ */
 56+ var $skippedPages;
 57+
 58+ /**
 59+ * Flag indicating that session data may have been lost
 60+ */
 61+ var $showSessionWarning = false;
 62+
 63+ var $helpId = 0;
 64+ var $tabIndex = 1;
 65+
 66+ var $currentPageName;
 67+
 68+ /** Constructor */
 69+ function __construct( $request ) {
 70+ parent::__construct();
 71+ $this->output = new WebInstallerOutput( $this );
 72+ $this->request = $request;
 73+ }
 74+
 75+ /**
 76+ * Main entry point.
 77+ * @param array $session Initial session array
 78+ * @return array New session array
 79+ */
 80+ function execute( $session ) {
 81+ $this->session = $session;
 82+ if ( isset( $session['settings'] ) ) {
 83+ $this->settings = $session['settings'] + $this->settings;
 84+ }
 85+ $this->exportVars();
 86+ $this->setupLanguage();
 87+
 88+ if ( isset( $session['happyPages'] ) ) {
 89+ $this->happyPages = $session['happyPages'];
 90+ } else {
 91+ $this->happyPages = array();
 92+ }
 93+ if ( isset( $session['skippedPages'] ) ) {
 94+ $this->skippedPages = $session['skippedPages'];
 95+ } else {
 96+ $this->skippedPages = array();
 97+ }
 98+ $lowestUnhappy = $this->getLowestUnhappy();
 99+
 100+ # Special case for Creative Commons partner chooser box
 101+ if ( $this->request->getVal( 'SubmitCC' ) ) {
 102+ $page = $this->getPageByName( 'Options' );
 103+ $this->output->useShortHeader();
 104+ $page->submitCC();
 105+ return $this->finish();
 106+ }
 107+ if ( $this->request->getVal( 'ShowCC' ) ) {
 108+ $page = $this->getPageByName( 'Options' );
 109+ $this->output->useShortHeader();
 110+ $this->output->addHTML( $page->getCCDoneBox() );
 111+ return $this->finish();
 112+ }
 113+
 114+ # Get the page name
 115+ $pageName = $this->request->getVal( 'page' );
 116+
 117+ if ( in_array( $pageName, $this->otherPages ) ) {
 118+ # Out of sequence
 119+ $pageId = false;
 120+ $page = $this->getPageByName( $pageName );
 121+ } else {
 122+ # Main sequence
 123+ if ( !$pageName || !in_array( $pageName, $this->pageSequence ) ) {
 124+ $pageId = $lowestUnhappy;
 125+ } else {
 126+ $pageId = array_search( $pageName, $this->pageSequence );
 127+ }
 128+
 129+ # If necessary, move back to the lowest-numbered unhappy page
 130+ if ( $pageId > $lowestUnhappy ) {
 131+ $pageId = $lowestUnhappy;
 132+ if ( $lowestUnhappy == 0 ) {
 133+ # Knocked back to start, possible loss of session data
 134+ $this->showSessionWarning = true;
 135+ }
 136+ }
 137+ $pageName = $this->pageSequence[$pageId];
 138+ $page = $this->getPageByName( $pageName );
 139+ }
 140+
 141+ # If a back button was submitted, go back without submitting the form data
 142+ if ( $this->request->wasPosted() && $this->request->getBool( 'submit-back' ) ) {
 143+ if ( $this->request->getVal( 'lastPage' ) ) {
 144+ $nextPage = $this->request->getVal( 'lastPage' );
 145+ } elseif ( $pageId !== false ) {
 146+ # Main sequence page
 147+ # Skip the skipped pages
 148+ $nextPageId = $pageId;
 149+ do {
 150+ $nextPageId--;
 151+ $nextPage = $this->pageSequence[$nextPageId];
 152+ } while( isset( $this->skippedPages[$nextPage] ) );
 153+ } else {
 154+ $nextPage = $this->pageSequence[$lowestUnhappy];
 155+ }
 156+ $this->output->redirect( $this->getUrl( array( 'page' => $nextPage ) ) );
 157+ return $this->finish();
 158+ }
 159+
 160+ # Execute the page
 161+ $this->currentPageName = $page->getName();
 162+ $this->startPageWrapper( $pageName );
 163+ $result = $page->execute();
 164+ $this->endPageWrapper();
 165+
 166+ if ( $result == 'skip' ) {
 167+ # Page skipped without explicit submission
 168+ # Skip it when we click "back" so that we don't just go forward again
 169+ $this->skippedPages[$pageName] = true;
 170+ $result = 'continue';
 171+ } else {
 172+ unset( $this->skippedPages[$pageName] );
 173+ }
 174+
 175+ # If it was posted, the page can request a continue to the next page
 176+ if ( $result === 'continue' && !$this->output->headerDone() ) {
 177+ if ( $pageId !== false ) {
 178+ $this->happyPages[$pageId] = true;
 179+ }
 180+ $lowestUnhappy = $this->getLowestUnhappy();
 181+
 182+ if ( $this->request->getVal( 'lastPage' ) ) {
 183+ $nextPage = $this->request->getVal( 'lastPage' );
 184+ } elseif ( $pageId !== false ) {
 185+ $nextPage = $this->pageSequence[$pageId + 1];
 186+ } else {
 187+ $nextPage = $this->pageSequence[$lowestUnhappy];
 188+ }
 189+ if ( array_search( $nextPage, $this->pageSequence ) > $lowestUnhappy ) {
 190+ $nextPage = $this->pageSequence[$lowestUnhappy];
 191+ }
 192+ $this->output->redirect( $this->getUrl( array( 'page' => $nextPage ) ) );
 193+ }
 194+ return $this->finish();
 195+ }
 196+
 197+ function getLowestUnhappy() {
 198+ if ( count( $this->happyPages ) == 0 ) {
 199+ return 0;
 200+ } else {
 201+ return max( array_keys( $this->happyPages ) ) + 1;
 202+ }
 203+ }
 204+
 205+ /**
 206+ * Start the PHP session. This may be called before execute() to start the PHP session.
 207+ */
 208+ function startSession() {
 209+ $sessPath = $this->getSessionSavePath();
 210+ if( $sessPath != '' ) {
 211+ if( !is_dir( $sessPath ) || !is_writeable( $sessPath ) ) {
 212+ $this->showError( 'config-session-path-bad', $sessPath );
 213+ return false;
 214+ }
 215+ } else {
 216+ // If the path is unset it'll default to some system bit, which *probably* is ok...
 217+ // not sure how to actually get what will be used.
 218+ }
 219+ if( wfIniGetBool( 'session.auto_start' ) || session_id() ) {
 220+ // Done already
 221+ return true;
 222+ }
 223+
 224+ $this->phpErrors = array();
 225+ set_error_handler( array( $this, 'errorHandler' ) );
 226+ session_start();
 227+ restore_error_handler();
 228+ if ( $this->phpErrors ) {
 229+ $this->showError( 'config-session-error', $this->phpErrors[0] );
 230+ return false;
 231+ }
 232+ return true;
 233+ }
 234+
 235+ /**
 236+ * Get the value of session.save_path
 237+ *
 238+ * Per http://www.php.net/manual/en/ref.session.php#ini.session.save-path,
 239+ * this might have some additional preceding parts which need to be
 240+ * ditched
 241+ *
 242+ * @return string
 243+ */
 244+ private function getSessionSavePath() {
 245+ $path = ini_get( 'session.save_path' );
 246+ $path = ltrim( substr( $path, strrpos( $path, ';' ) ), ';');
 247+
 248+ return $path;
 249+ }
 250+
 251+ /**
 252+ * Show an error message in a box. Parameters are like wfMsg().
 253+ */
 254+ function showError( $msg /*...*/ ) {
 255+ $args = func_get_args();
 256+ array_shift( $args );
 257+ $args = array_map( 'htmlspecialchars', $args );
 258+ $msg = wfMsgReal( $msg, $args, false, false, false );
 259+ $this->output->addHTML( $this->getErrorBox( $msg ) );
 260+ }
 261+
 262+ /**
 263+ * Temporary error handler for session start debugging
 264+ */
 265+ function errorHandler( $errno, $errstr ) {
 266+ $this->phpErrors[] = $errstr;
 267+ }
 268+
 269+ /**
 270+ * Clean up from execute()
 271+ * @private.
 272+ */
 273+ function finish() {
 274+ $this->output->output();
 275+ $this->session['happyPages'] = $this->happyPages;
 276+ $this->session['skippedPages'] = $this->skippedPages;
 277+ $this->session['settings'] = $this->settings;
 278+ return $this->session;
 279+ }
 280+
 281+ /**
 282+ * Get a URL for submission back to the same script
 283+ */
 284+ function getUrl( $query = array() ) {
 285+ $url = $this->request->getRequestURL();
 286+ # Remove existing query
 287+ $url = preg_replace( '/\?.*$/', '', $url );
 288+ if ( $query ) {
 289+ $url .= '?' . wfArrayToCGI( $query );
 290+ }
 291+ return $url;
 292+ }
 293+
 294+ /**
 295+ * Get a WebInstallerPage from the main sequence, by ID
 296+ */
 297+ function getPageById( $id ) {
 298+ $pageName = $this->pageSequence[$id];
 299+ $pageClass = 'WebInstaller_' . $pageName;
 300+ return new $pageClass( $this );
 301+ }
 302+
 303+ /**
 304+ * Get a WebInstallerPage by name
 305+ */
 306+ function getPageByName( $pageName ) {
 307+ $pageClass = 'WebInstaller_' . $pageName;
 308+ return new $pageClass( $this );
 309+ }
 310+
 311+ /**
 312+ * Get a session variable
 313+ */
 314+ function getSession( $name, $default = null ) {
 315+ if ( !isset( $this->session[$name] ) ) {
 316+ return $default;
 317+ } else {
 318+ return $this->session[$name];
 319+ }
 320+ }
 321+
 322+ /**
 323+ * Set a session variable
 324+ */
 325+ function setSession( $name, $value ) {
 326+ $this->session[$name] = $value;
 327+ }
 328+
 329+ /**
 330+ * Get the next tabindex attribute value
 331+ */
 332+ function nextTabIndex() {
 333+ return $this->tabIndex++;
 334+ }
 335+
 336+ /**
 337+ * Initializes language-related variables
 338+ */
 339+ function setupLanguage() {
 340+ global $wgLang, $wgContLang, $wgLanguageCode;
 341+ if ( $this->getSession( 'test' ) === null && !$this->request->wasPosted() ) {
 342+ $wgLanguageCode = $this->getAcceptLanguage();
 343+ $wgLang = $wgContLang = Language::factory( $wgLanguageCode );
 344+ $this->setVar( 'wgLanguageCode', $wgLanguageCode );
 345+ $this->setVar( '_UserLang', $wgLanguageCode );
 346+ } else {
 347+ $wgLanguageCode = $this->getVar( 'wgLanguageCode' );
 348+ $wgLang = Language::factory( $this->getVar( '_UserLang' ) );
 349+ $wgContLang = Language::factory( $wgLanguageCode );
 350+ }
 351+ }
 352+
 353+ /**
 354+ * Retrieves MediaWiki language from Accept-Language HTTP header
 355+ */
 356+ function getAcceptLanguage() {
 357+ global $wgLanguageCode;
 358+
 359+ $mwLanguages = Language::getLanguageNames();
 360+ $langs = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
 361+ foreach ( explode( ';', $langs ) as $splitted ) {
 362+ foreach ( explode( ',', $splitted ) as $lang ) {
 363+ $lang = trim( strtolower( $lang ) );
 364+ if ( $lang == '' || $lang[0] == 'q' ) {
 365+ continue;
 366+ }
 367+ if ( isset( $mwLanguages[$lang] ) ) {
 368+ return $lang;
 369+ }
 370+ $lang = preg_replace( '/^(.*?)(?=-[^-]*)$/', '\\1', $lang );
 371+ if ( $lang != '' && isset( $mwLanguages[$lang] ) ) {
 372+ return $lang;
 373+ }
 374+ }
 375+ }
 376+ return $wgLanguageCode;
 377+ }
 378+
 379+ /**
 380+ * Called by execute() before page output starts, to show a page list
 381+ */
 382+ function startPageWrapper( $currentPageName ) {
 383+ $s = "<div class=\"config-page-wrapper\">\n" .
 384+ "<div class=\"config-page-list\"><ul>\n";
 385+ $lastHappy = -1;
 386+ foreach ( $this->pageSequence as $id => $pageName ) {
 387+ $happy = !empty( $this->happyPages[$id] );
 388+ $s .= $this->getPageListItem( $pageName,
 389+ $happy || $lastHappy == $id - 1, $currentPageName );
 390+ if ( $happy ) {
 391+ $lastHappy = $id;
 392+ }
 393+ }
 394+ $s .= "</ul><br/><ul>\n";
 395+ foreach ( $this->otherPages as $pageName ) {
 396+ $s .= $this->getPageListItem( $pageName, true, $currentPageName );
 397+ }
 398+ $s .= "</ul></div>\n". // end list pane
 399+ "<div class=\"config-page\">\n" .
 400+ Xml::element( 'h2', array(),
 401+ wfMsg( 'config-page-' . strtolower( $currentPageName ) ) );
 402+
 403+ $this->output->addHTMLNoFlush( $s );
 404+ }
 405+
 406+ /**
 407+ * Get a list item for the page list
 408+ */
 409+ function getPageListItem( $pageName, $enabled, $currentPageName ) {
 410+ $s = "<li class=\"config-page-list-item\">";
 411+ $name = wfMsg( 'config-page-' . strtolower( $pageName ) );
 412+ if ( $enabled ) {
 413+ $query = array( 'page' => $pageName );
 414+ if ( !in_array( $pageName, $this->pageSequence ) ) {
 415+ if ( in_array( $currentPageName, $this->pageSequence ) ) {
 416+ $query['lastPage'] = $currentPageName;
 417+ }
 418+ $link = Xml::element( 'a',
 419+ array(
 420+ 'href' => $this->getUrl( $query )
 421+ ),
 422+ $name
 423+ );
 424+ } else {
 425+ $link = htmlspecialchars( $name );
 426+ }
 427+ if ( $pageName == $currentPageName ) {
 428+ $s .= "<span class=\"config-page-current\">$link</span>";
 429+ } else {
 430+ $s .= $link;
 431+ }
 432+ } else {
 433+ $s .= Xml::element( 'span',
 434+ array(
 435+ 'class' => 'config-page-disabled'
 436+ ),
 437+ $name
 438+ );
 439+ }
 440+ $s .= "</li>\n";
 441+ return $s;
 442+ }
 443+
 444+ /**
 445+ * Output some stuff after a page is finished
 446+ */
 447+ function endPageWrapper() {
 448+ $this->output->addHTMLNoFlush(
 449+ "</div>\n" .
 450+ "<br style=\"clear:both\"/>\n" .
 451+ "</div>" );
 452+ }
 453+
 454+ /**
 455+ * Get HTML for an error box with an icon
 456+ * @param string $text Wikitext, get this with wfMsgNoTrans()
 457+ */
 458+ function getErrorBox( $text ) {
 459+ return $this->getInfoBox( $text, 'critical-32.png', 'config-error-box' );
 460+ }
 461+
 462+ /**
 463+ * Get HTML for a warning box with an icon
 464+ * @param string $text Wikitext, get this with wfMsgNoTrans()
 465+ */
 466+ function getWarningBox( $text ) {
 467+ return $this->getInfoBox( $text, 'warning-32.png', 'config-warning-box' );
 468+ }
 469+
 470+ /**
 471+ * Get HTML for an info box with an icon
 472+ * @param string $text Wikitext, get this with wfMsgNoTrans()
 473+ * @param string $icon Icon name, file in skins/common/images
 474+ * @param string $class Additional class name to add to the wrapper div
 475+ */
 476+ function getInfoBox( $text, $icon = 'info-32.png', $class = false ) {
 477+ $s =
 478+ "<div class=\"config-info $class\">\n" .
 479+ "<div class=\"config-info-left\">\n" .
 480+ Xml::element( 'img',
 481+ array(
 482+ 'src' => '../skins/common/images/' . $icon,
 483+ 'alt' => wfMsg( 'config-information' ),
 484+ )
 485+ ) . "\n" .
 486+ "</div>\n" .
 487+ "<div class=\"config-info-right\">\n" .
 488+ $this->parse( $text ) . "\n" .
 489+ "</div>\n" .
 490+ "<div style=\"clear: left;\"></div>\n" .
 491+ "</div>\n";
 492+ return $s;
 493+ }
 494+
 495+ /**
 496+ * Get small text indented help for a preceding form field.
 497+ * Parameters like wfMsg().
 498+ */
 499+ function getHelpBox( $msg /*, ... */ ) {
 500+ $args = func_get_args();
 501+ array_shift( $args );
 502+ $args = array_map( 'htmlspecialchars', $args );
 503+ $text = wfMsgReal( $msg, $args, false, false, false );
 504+ $html = $this->parse( $text, true );
 505+ $id = $this->helpId++;
 506+ $alt = wfMsg( 'help' );
 507+
 508+ return
 509+ "<div class=\"config-help-wrapper\">\n" .
 510+ "<div class=\"config-help-message\">\n" .
 511+ $html .
 512+ "</div>\n" .
 513+ "<div class=\"config-show-help\">\n" .
 514+ "<a href=\"#\">" .
 515+ wfMsgHtml( 'config-show-help' ) .
 516+ "</a></div>\n" .
 517+ "<div class=\"config-hide-help\">\n" .
 518+ "<a href=\"#\">" .
 519+ wfMsgHtml( 'config-hide-help' ) .
 520+ "</a></div>\n</div>\n";
 521+ }
 522+
 523+ /**
 524+ * Output a help box
 525+ */
 526+ function showHelpBox( $msg /*, ... */ ) {
 527+ $args = func_get_args();
 528+ $html = call_user_func_array( array( $this, 'getHelpBox' ), $args );
 529+ $this->output->addHTML( $html );
 530+ }
 531+
 532+ /**
 533+ * Show a short informational message
 534+ * Output looks like a list.
 535+ */
 536+ function showMessage( $msg /*, ... */ ) {
 537+ $args = func_get_args();
 538+ array_shift( $args );
 539+ $html = '<div class="config-message">' .
 540+ $this->parse( wfMsgReal( $msg, $args, false, false, false ) ) .
 541+ "</div>\n";
 542+ $this->output->addHTML( $html );
 543+ }
 544+
 545+ /**
 546+ * Label a control by wrapping a config-input div around it and putting a
 547+ * label before it
 548+ */
 549+ function label( $msg, $forId, $contents ) {
 550+ if ( strval( $msg ) == '' ) {
 551+ $labelText = '&nbsp;';
 552+ } else {
 553+ $labelText = wfMsgHtml( $msg );
 554+ }
 555+ $attributes = array( 'class' => 'config-label' );
 556+ if ( $forId ) {
 557+ $attributes['for'] = $forId;
 558+ }
 559+ return
 560+ "<div class=\"config-input\">\n" .
 561+ Xml::tags( 'label',
 562+ $attributes,
 563+ $labelText ) . "\n" .
 564+ $contents .
 565+ "</div>\n";
 566+ }
 567+
 568+ /**
 569+ * Get a labelled text box to configure a variable
 570+ * @param array $params
 571+ * Parameters are:
 572+ * var: The variable to be configured (required)
 573+ * label: The message name for the label (required)
 574+ * attribs: Additional attributes for the input element (optional)
 575+ * controlName: The name for the input element (optional)
 576+ * value: The current value of the variable (optional)
 577+ */
 578+ function getTextBox( $params ) {
 579+ if ( !isset( $params['controlName'] ) ) {
 580+ $params['controlName'] = 'config_' . $params['var'];
 581+ }
 582+ if ( !isset( $params['value'] ) ) {
 583+ $params['value'] = $this->getVar( $params['var'] );
 584+ }
 585+ if ( !isset( $params['attribs'] ) ) {
 586+ $params['attribs'] = array();
 587+ }
 588+ return
 589+ $this->label(
 590+ $params['label'],
 591+ $params['controlName'],
 592+ Xml::input(
 593+ $params['controlName'],
 594+ 30, // intended to be overridden by CSS
 595+ $params['value'],
 596+ $params['attribs'] + array(
 597+ 'id' => $params['controlName'],
 598+ 'class' => 'config-input-text',
 599+ 'tabindex' => $this->nextTabIndex()
 600+ )
 601+ )
 602+ );
 603+ }
 604+
 605+ /**
 606+ * Get a labelled password box to configure a variable
 607+ * Implements password hiding
 608+ * @param array $params
 609+ * Parameters are:
 610+ * var: The variable to be configured (required)
 611+ * label: The message name for the label (required)
 612+ * attribs: Additional attributes for the input element (optional)
 613+ * controlName: The name for the input element (optional)
 614+ * value: The current value of the variable (optional)
 615+ */
 616+ function getPasswordBox( $params ) {
 617+ if ( !isset( $params['value'] ) ) {
 618+ $params['value'] = $this->getVar( $params['var'] );
 619+ }
 620+ if ( !isset( $params['attribs'] ) ) {
 621+ $params['attribs'] = array();
 622+ }
 623+ $params['value'] = $this->getFakePassword( $params['value'] );
 624+ $params['attribs']['type'] = 'password';
 625+ return $this->getTextBox( $params );
 626+ }
 627+
 628+ /**
 629+ * Get a labelled checkbox to configure a boolean variable
 630+ * @param array $params
 631+ * Parameters are:
 632+ * var: The variable to be configured (required)
 633+ * label: The message name for the label (required)
 634+ * attribs: Additional attributes for the input element (optional)
 635+ * controlName: The name for the input element (optional)
 636+ * value: The current value of the variable (optional)
 637+ */
 638+ function getCheckBox( $params ) {
 639+ if ( !isset( $params['controlName'] ) ) {
 640+ $params['controlName'] = 'config_' . $params['var'];
 641+ }
 642+ if ( !isset( $params['value'] ) ) {
 643+ $params['value'] = $this->getVar( $params['var'] );
 644+ }
 645+ if ( !isset( $params['attribs'] ) ) {
 646+ $params['attribs'] = array();
 647+ }
 648+ if( isset( $params['rawtext'] ) ) {
 649+ $labelText = $params['rawtext'];
 650+ } else {
 651+ $labelText = $this->parse( wfMsg( $params['label'] ) );
 652+ }
 653+ return
 654+ "<div class=\"config-input-check\">\n" .
 655+ "<label>\n" .
 656+ Xml::check(
 657+ $params['controlName'],
 658+ $params['value'],
 659+ $params['attribs'] + array(
 660+ 'id' => $params['controlName'],
 661+ 'class' => 'config-input-text',
 662+ 'tabindex' => $this->nextTabIndex(),
 663+ )
 664+ ) .
 665+ $labelText . "\n" .
 666+ "</label>\n" .
 667+ "</div>\n";
 668+ }
 669+
 670+ /**
 671+ * Get a set of labelled radio buttons
 672+ *
 673+ * @param array $params
 674+ * Parameters are:
 675+ * var: The variable to be configured (required)
 676+ * label: The message name for the label (required)
 677+ * itemLabelPrefix: The message name prefix for the item labels (required)
 678+ * values: List of allowed values (required)
 679+ * itemAttribs Array of attribute arrays, outer key is the value name (optional)
 680+ * commonAttribs Attribute array applied to all items
 681+ * controlName: The name for the input element (optional)
 682+ * value: The current value of the variable (optional)
 683+ */
 684+ function getRadioSet( $params ) {
 685+ if ( !isset( $params['controlName'] ) ) {
 686+ $params['controlName'] = 'config_' . $params['var'];
 687+ }
 688+ if ( !isset( $params['value'] ) ) {
 689+ $params['value'] = $this->getVar( $params['var'] );
 690+ }
 691+ if ( !isset( $params['label'] ) ) {
 692+ $label = '';
 693+ } else {
 694+ $label = $this->parse( wfMsgNoTrans( $params['label'] ) );
 695+ }
 696+ $s = "<label class=\"config-label\">\n" .
 697+ $label .
 698+ "</label>\n" .
 699+ "<ul class=\"config-settings-block\">\n";
 700+ foreach ( $params['values'] as $value ) {
 701+ $itemAttribs = array();
 702+ if ( isset( $params['commonAttribs'] ) ) {
 703+ $itemAttribs = $params['commonAttribs'];
 704+ }
 705+ if ( isset( $params['itemAttribs'][$value] ) ) {
 706+ $itemAttribs = $params['itemAttribs'][$value] + $itemAttribs;
 707+ }
 708+ $checked = $value == $params['value'];
 709+ $id = $params['controlName'] . '_' . $value;
 710+ $itemAttribs['id'] = $id;
 711+ $itemAttribs['tabindex'] = $this->nextTabIndex();
 712+ $s .=
 713+ '<li>' .
 714+ Xml::radio( $params['controlName'], $value, $checked, $itemAttribs ) .
 715+ '&nbsp;' .
 716+ Xml::tags( 'label', array( 'for' => $id ), $this->parse(
 717+ wfMsgNoTrans( $params['itemLabelPrefix'] . strtolower( $value ) )
 718+ ) ) .
 719+ "</li>\n";
 720+ }
 721+ $s .= "</ul>\n";
 722+ return $s;
 723+ }
 724+
 725+ /**
 726+ * Output an error box using a Status object
 727+ */
 728+ function showStatusErrorBox( $status ) {
 729+ $text = $status->getWikiText();
 730+ $this->output->addHTML( $this->getErrorBox( $text ) );
 731+ }
 732+
 733+ function showStatusError( $status ) {
 734+ $text = $status->getWikiText();
 735+ $this->output->addWikiText(
 736+ "<div class=\"config-message\">\n" .
 737+ $text .
 738+ "</div>"
 739+ );
 740+ }
 741+
 742+ /**
 743+ * Convenience function to set variables based on form data.
 744+ * Assumes that variables containing "password" in the name are (potentially
 745+ * fake) passwords.
 746+ * @param array $varNames
 747+ * @param string $prefix The prefix added to variables to obtain form names
 748+ */
 749+ function setVarsFromRequest( $varNames, $prefix = 'config_' ) {
 750+ $newValues = array();
 751+ foreach ( $varNames as $name ) {
 752+ $value = trim( $this->request->getVal( $prefix . $name ) );
 753+ $newValues[$name] = $value;
 754+ if ( $value === null ) {
 755+ // Checkbox?
 756+ $this->setVar( $name, false );
 757+ } else {
 758+ if ( stripos( $name, 'password' ) !== false ) {
 759+ $this->setPassword( $name, $value );
 760+ } else {
 761+ $this->setVar( $name, $value );
 762+ }
 763+ }
 764+ }
 765+ return $newValues;
 766+ }
 767+
 768+ /**
 769+ * Get the starting tags of a fieldset
 770+ * @param string $legend Message name
 771+ */
 772+ function getFieldsetStart( $legend ) {
 773+ return "\n<fieldset><legend>" . wfMsgHtml( $legend ) . "</legend>\n";
 774+ }
 775+
 776+ /**
 777+ * Get the end tag of a fieldset
 778+ */
 779+ function getFieldsetEnd() {
 780+ return "</fieldset>\n";
 781+ }
 782+
 783+ /**
 784+ * Helper for Installer::docLink()
 785+ */
 786+ function getDocUrl( $page ) {
 787+ $url = "{$_SERVER['PHP_SELF']}?page=" . urlencode( $page );
 788+ if ( in_array( $this->currentPageName, $this->pageSequence ) ) {
 789+ $url .= '&lastPage=' . urlencode( $this->currentPageName );
 790+ }
 791+ return $url;
 792+ }
 793+}
 794+
 795+class WebInstallerPage {
 796+ function __construct( $parent ) {
 797+ $this->parent = $parent;
 798+ }
 799+
 800+ function addHTML( $html ) {
 801+ $this->parent->output->addHTML( $html );
 802+ }
 803+
 804+ function startForm() {
 805+ $this->addHTML(
 806+ "<div class=\"config-section\">\n" .
 807+ Xml::openElement(
 808+ 'form',
 809+ array(
 810+ 'method' => 'post',
 811+ 'action' => $this->parent->getUrl( array( 'page' => $this->getName() ) )
 812+ )
 813+ ) . "\n"
 814+ );
 815+ }
 816+
 817+ function endForm( $continue = 'continue' ) {
 818+ $this->parent->output->outputWarnings();
 819+ $s = "<div class=\"config-submit\">\n";
 820+ $id = $this->getId();
 821+ if ( $id === false ) {
 822+ $s .= Xml::hidden( 'lastPage', $this->parent->request->getVal( 'lastPage' ) );
 823+ }
 824+ if ( $continue ) {
 825+ // Fake submit button for enter keypress
 826+ $s .= Xml::submitButton( wfMsg( "config-$continue" ),
 827+ array( 'name' => "enter-$continue", 'style' => 'display:none' ) ) . "\n";
 828+ }
 829+ if ( $id !== 0 ) {
 830+ $s .= Xml::submitButton( wfMsg( 'config-back' ),
 831+ array(
 832+ 'name' => 'submit-back',
 833+ 'tabindex' => $this->parent->nextTabIndex()
 834+ ) ) . "\n";
 835+ }
 836+ if ( $continue ) {
 837+ $s .= Xml::submitButton( wfMsg( "config-$continue" ),
 838+ array(
 839+ 'name' => "submit-$continue",
 840+ 'tabindex' => $this->parent->nextTabIndex(),
 841+ ) ) . "\n";
 842+ }
 843+ $s .= "</div></form></div>\n";
 844+ $this->addHTML( $s );
 845+ }
 846+
 847+ function getName() {
 848+ return str_replace( 'WebInstaller_', '', get_class( $this ) );
 849+ }
 850+
 851+ function getId() {
 852+ return array_search( $this->getName(), $this->parent->pageSequence );
 853+ }
 854+
 855+ function execute() {
 856+ if ( $this->parent->request->wasPosted() ) {
 857+ return 'continue';
 858+ } else {
 859+ $this->startForm();
 860+ $this->addHTML( 'Mockup' );
 861+ $this->endForm();
 862+ }
 863+ }
 864+
 865+ function getVar( $var ) {
 866+ return $this->parent->getVar( $var );
 867+ }
 868+
 869+ function setVar( $name, $value ) {
 870+ $this->parent->setVar( $name, $value );
 871+ }
 872+}
 873+
 874+class WebInstaller_Language extends WebInstallerPage {
 875+ function execute() {
 876+ global $wgLang;
 877+ $r = $this->parent->request;
 878+ $userLang = $r->getVal( 'UserLang' );
 879+ $contLang = $r->getVal( 'ContLang' );
 880+
 881+ $lifetime = intval( ini_get( 'session.gc_maxlifetime' ) );
 882+ if ( !$lifetime ) {
 883+ $lifetime = 1440; // PHP default
 884+ }
 885+
 886+ if ( $r->wasPosted() ) {
 887+ # Do session test
 888+ if ( $this->parent->getSession( 'test' ) === null ) {
 889+ $requestTime = $r->getVal( 'LanguageRequestTime' );
 890+ if ( !$requestTime ) {
 891+ // The most likely explanation is that the user was knocked back
 892+ // from another page on POST due to session expiry
 893+ $msg = 'config-session-expired';
 894+ } elseif ( time() - $requestTime > $lifetime ) {
 895+ $msg = 'config-session-expired';
 896+ } else {
 897+ $msg = 'config-no-session';
 898+ }
 899+ $this->parent->showError( $msg, $wgLang->formatTimePeriod( $lifetime ) );
 900+ } else {
 901+ $languages = Language::getLanguageNames();
 902+ if ( isset( $languages[$userLang] ) ) {
 903+ $this->setVar( '_UserLang', $userLang );
 904+ }
 905+ if ( isset( $languages[$contLang] ) ) {
 906+ $this->setVar( 'wgLanguageCode', $contLang );
 907+ if ( $this->getVar( '_AdminName' ) === null ) {
 908+ // Load localised sysop username in *content* language
 909+ $this->setVar( '_AdminName', wfMsgForContent( 'config-admin-default-username' ) );
 910+ }
 911+ }
 912+ return 'continue';
 913+ }
 914+ } elseif ( $this->parent->showSessionWarning ) {
 915+ # The user was knocked back from another page to the start
 916+ # This probably indicates a session expiry
 917+ $this->parent->showError( 'config-session-expired', $wgLang->formatTimePeriod( $lifetime ) );
 918+ }
 919+
 920+ $this->parent->setSession( 'test', true );
 921+
 922+ if ( !isset( $languages[$userLang] ) ) {
 923+ $userLang = $this->getVar( '_UserLang', 'en' );
 924+ }
 925+ if ( !isset( $languages[$contLang] ) ) {
 926+ $contLang = $this->getVar( 'wgLanguageCode', 'en' );
 927+ }
 928+ $this->startForm();
 929+ $s =
 930+ Xml::hidden( 'LanguageRequestTime', time() ) .
 931+ $this->getLanguageSelector( 'UserLang', 'config-your-language', $userLang ) .
 932+ $this->parent->getHelpBox( 'config-your-language-help' ) .
 933+ $this->getLanguageSelector( 'ContLang', 'config-wiki-language', $contLang ) .
 934+ $this->parent->getHelpBox( 'config-wiki-language-help' );
 935+
 936+
 937+ $this->addHTML( $s );
 938+ $this->endForm();
 939+ }
 940+
 941+ /**
 942+ * Get a <select> for selecting languages
 943+ */
 944+ function getLanguageSelector( $name, $label, $selectedCode ) {
 945+ global $wgDummyLanguageCodes;
 946+ $s = Xml::openElement( 'select', array( 'id' => $name, 'name' => $name ) ) . "\n";
 947+
 948+ $languages = Language::getLanguageNames();
 949+ ksort( $languages );
 950+ $dummies = array_flip( $wgDummyLanguageCodes );
 951+ foreach ( $languages as $code => $lang ) {
 952+ if ( isset( $dummies[$code] ) ) continue;
 953+ $s .= "\n" . Xml::option( "$code - $lang", $code, $code == $selectedCode );
 954+ }
 955+ $s .= "\n</select>\n";
 956+ return $this->parent->label( $label, $name, $s );
 957+ }
 958+}
 959+
 960+class WebInstaller_Welcome extends WebInstallerPage {
 961+ function execute() {
 962+ if ( $this->parent->request->wasPosted() ) {
 963+ if ( $this->getVar( '_Environment' ) ) {
 964+ return 'continue';
 965+ }
 966+ }
 967+ $this->parent->output->addWikiText( wfMsgNoTrans( 'config-welcome' ) );
 968+ $status = $this->parent->doEnvironmentChecks();
 969+ if ( $status ) {
 970+ $this->parent->output->addWikiText( wfMsgNoTrans( 'config-copyright', wfMsg( 'config-authors' ) ) );
 971+ $this->startForm();
 972+ $this->endForm();
 973+ }
 974+ }
 975+}
 976+
 977+class WebInstaller_DBConnect extends WebInstallerPage {
 978+ function execute() {
 979+ $r = $this->parent->request;
 980+ if ( $r->wasPosted() ) {
 981+ $status = $this->submit();
 982+ if ( $status->isGood() ) {
 983+ $this->setVar( '_UpgradeDone', false );
 984+ return 'continue';
 985+ } else {
 986+ $this->parent->showStatusErrorBox( $status );
 987+ }
 988+ }
 989+
 990+
 991+ $this->startForm();
 992+
 993+ $types = "<ul class=\"config-settings-block\">\n";
 994+ $settings = '';
 995+ $defaultType = $this->getVar( 'wgDBtype' );
 996+ foreach ( $this->parent->getVar( '_CompiledDBs' ) as $type ) {
 997+ $installer = $this->parent->getDBInstaller( $type );
 998+ $types .=
 999+ '<li>' .
 1000+ Xml::radioLabel(
 1001+ $installer->getReadableName(),
 1002+ 'DBType',
 1003+ $type,
 1004+ "DBType_$type",
 1005+ $type == $defaultType,
 1006+ array( 'class' => 'dbRadio', 'rel' => "DB_wrapper_$type" )
 1007+ ) .
 1008+ "</li>\n";
 1009+
 1010+ $settings .=
 1011+ Xml::openElement( 'div', array( 'id' => 'DB_wrapper_' . $type, 'class' => 'dbWrapper' ) ) .
 1012+ Xml::element( 'h3', array(), wfMsg( 'config-header-' . $type ) ) .
 1013+ $installer->getConnectForm() .
 1014+ "</div>\n";
 1015+ }
 1016+ $types .= "</ul><br clear=\"left\"/>\n";
 1017+
 1018+ $this->addHTML(
 1019+ $this->parent->label( 'config-db-type', false, $types ) .
 1020+ $settings
 1021+ );
 1022+
 1023+ $this->endForm();
 1024+ }
 1025+
 1026+ function submit() {
 1027+ $r = $this->parent->request;
 1028+ $type = $r->getVal( 'DBType' );
 1029+ $this->setVar( 'wgDBtype', $type );
 1030+ $installer = $this->parent->getDBInstaller( $type );
 1031+ if ( !$installer ) {
 1032+ return Status::newFatal( 'config-invalid-db-type' );
 1033+ }
 1034+ return $installer->submitConnectForm();
 1035+ }
 1036+}
 1037+
 1038+class WebInstaller_Upgrade extends WebInstallerPage {
 1039+ function execute() {
 1040+ if ( $this->getVar( '_UpgradeDone' ) ) {
 1041+ if ( $this->parent->request->wasPosted() ) {
 1042+ // Done message acknowledged
 1043+ return 'continue';
 1044+ } else {
 1045+ // Back button click
 1046+ // Show the done message again
 1047+ // Make them click back again if they want to do the upgrade again
 1048+ $this->showDoneMessage();
 1049+ return 'output';
 1050+ }
 1051+ }
 1052+
 1053+ // wgDBtype is generally valid here because otherwise the previous page
 1054+ // (connect) wouldn't have declared its happiness
 1055+ $type = $this->getVar( 'wgDBtype' );
 1056+ $installer = $this->parent->getDBInstaller( $type );
 1057+
 1058+ if ( !$installer->needsUpgrade() ) {
 1059+ return 'skip';
 1060+ }
 1061+
 1062+ if ( $this->parent->request->wasPosted() ) {
 1063+ $this->addHTML(
 1064+ '<div id="config-spinner" style="display:none;"><img src="../skins/common/images/ajax-loader.gif" /></div>' .
 1065+ '<script>jQuery( "#config-spinner" )[0].style.display = "block";</script>' .
 1066+ '<textarea id="config-update-log" name="UpdateLog" rows="10" readonly="readonly">'
 1067+ );
 1068+ $this->parent->output->flush();
 1069+ $result = $installer->doUpgrade();
 1070+ $this->addHTML( '</textarea>
 1071+<script>jQuery( "#config-spinner" )[0].style.display = "none";</script>' );
 1072+ $this->parent->output->flush();
 1073+ if ( $result ) {
 1074+ $this->setVar( '_UpgradeDone', true );
 1075+ $this->showDoneMessage();
 1076+ return 'output';
 1077+ }
 1078+ }
 1079+
 1080+ $this->startForm();
 1081+ $this->addHTML( $this->parent->getInfoBox(
 1082+ wfMsgNoTrans( 'config-can-upgrade', $GLOBALS['wgVersion'] ) ) );
 1083+ $this->endForm();
 1084+ }
 1085+
 1086+ function showDoneMessage() {
 1087+ $this->startForm();
 1088+ $this->addHTML(
 1089+ $this->parent->getInfoBox(
 1090+ wfMsgNoTrans( 'config-upgrade-done',
 1091+ $GLOBALS['wgServer'] .
 1092+ $this->getVar( 'wgScriptPath' ) . '/index' .
 1093+ $this->getVar( 'wgScriptExtension' )
 1094+ ), 'tick-32.png'
 1095+ )
 1096+ );
 1097+ $this->endForm( 'regenerate' );
 1098+ }
 1099+}
 1100+
 1101+class WebInstaller_DBSettings extends WebInstallerPage {
 1102+ function execute() {
 1103+ $installer = $this->parent->getDBInstaller( $this->getVar( 'wgDBtype' ) );
 1104+
 1105+ $r = $this->parent->request;
 1106+ if ( $r->wasPosted() ) {
 1107+ $status = $installer->submitSettingsForm();
 1108+ if ( $status === false ) {
 1109+ return 'skip';
 1110+ } elseif ( $status->isGood() ) {
 1111+ return 'continue';
 1112+ } else {
 1113+ $this->parent->showStatusErrorBox( $status );
 1114+ }
 1115+ }
 1116+
 1117+ $form = $installer->getSettingsForm();
 1118+ if ( $form === false ) {
 1119+ return 'skip';
 1120+ }
 1121+
 1122+ $this->startForm();
 1123+ $this->addHTML( $form );
 1124+ $this->endForm();
 1125+ }
 1126+
 1127+}
 1128+
 1129+class WebInstaller_Name extends WebInstallerPage {
 1130+ function execute() {
 1131+ $r = $this->parent->request;
 1132+ if ( $r->wasPosted() ) {
 1133+ if ( $this->submit() ) {
 1134+ return 'continue';
 1135+ }
 1136+ }
 1137+
 1138+ $this->startForm();
 1139+
 1140+ if ( $this->getVar( 'wgSitename' ) == $GLOBALS['wgSitename'] ) {
 1141+ $this->setVar( 'wgSitename', '' );
 1142+ }
 1143+
 1144+ // Set wgMetaNamespace to something valid before we show the form.
 1145+ // $wgMetaNamespace defaults to $wgSiteName which is 'MediaWiki'
 1146+ $metaNS = $this->getVar( 'wgMetaNamespace' );
 1147+ $this->setVar( 'wgMetaNamespace', wfMsgForContent( 'config-ns-other-default' ) );
 1148+
 1149+ $this->addHTML(
 1150+ $this->parent->getTextBox( array(
 1151+ 'var' => 'wgSitename',
 1152+ 'label' => 'config-site-name',
 1153+ ) ) .
 1154+ $this->parent->getHelpBox( 'config-site-name-help' ) .
 1155+ $this->parent->getRadioSet( array(
 1156+ 'var' => '_NamespaceType',
 1157+ 'label' => 'config-project-namespace',
 1158+ 'itemLabelPrefix' => 'config-ns-',
 1159+ 'values' => array( 'site-name', 'generic', 'other' ),
 1160+ 'commonAttribs' => array( 'class' => 'enableForOther', 'rel' => 'config_wgMetaNamespace' ),
 1161+ ) ) .
 1162+ $this->parent->getTextBox( array(
 1163+ 'var' => 'wgMetaNamespace',
 1164+ 'label' => '',
 1165+ 'attribs' => array( 'disabled' => '' ),
 1166+ ) ) .
 1167+ $this->parent->getHelpBox( 'config-project-namespace-help' ) .
 1168+ $this->parent->getFieldsetStart( 'config-admin-box' ) .
 1169+ $this->parent->getTextBox( array(
 1170+ 'var' => '_AdminName',
 1171+ 'label' => 'config-admin-name'
 1172+ ) ) .
 1173+ $this->parent->getPasswordBox( array(
 1174+ 'var' => '_AdminPassword',
 1175+ 'label' => 'config-admin-password',
 1176+ ) ) .
 1177+ $this->parent->getPasswordBox( array(
 1178+ 'var' => '_AdminPassword2',
 1179+ 'label' => 'config-admin-password-confirm'
 1180+ ) ) .
 1181+ $this->parent->getHelpBox( 'config-admin-help' ) .
 1182+ $this->parent->getTextBox( array(
 1183+ 'var' => '_AdminEmail',
 1184+ 'label' => 'config-admin-email'
 1185+ ) ) .
 1186+ $this->parent->getHelpBox( 'config-admin-email-help' ) .
 1187+ $this->parent->getCheckBox( array(
 1188+ 'var' => '_Subscribe',
 1189+ 'label' => 'config-subscribe'
 1190+ ) ) .
 1191+ $this->parent->getHelpBox( 'config-subscribe-help' ) .
 1192+ $this->parent->getFieldsetEnd() .
 1193+ $this->parent->getInfoBox( wfMsg( 'config-almost-done' ) ) .
 1194+ $this->parent->getRadioSet( array(
 1195+ 'var' => '_SkipOptional',
 1196+ 'itemLabelPrefix' => 'config-optional-',
 1197+ 'values' => array( 'continue', 'skip' )
 1198+ ) )
 1199+ );
 1200+
 1201+ // Restore the default value
 1202+ $this->setVar( 'wgMetaNamespace', $metaNS );
 1203+
 1204+ $this->endForm();
 1205+ return 'output';
 1206+ }
 1207+
 1208+ function submit() {
 1209+ $retVal = true;
 1210+ $this->parent->setVarsFromRequest( array( 'wgSitename', '_NamespaceType',
 1211+ '_AdminName', '_AdminPassword', '_AdminPassword2', '_AdminEmail',
 1212+ '_Subscribe', '_SkipOptional' ) );
 1213+
 1214+ // Validate site name
 1215+ if ( strval( $this->getVar( 'wgSitename' ) ) === '' ) {
 1216+ $this->parent->showError( 'config-site-name-blank' );
 1217+ $retVal = false;
 1218+ }
 1219+
 1220+ // Fetch namespace
 1221+ $nsType = $this->getVar( '_NamespaceType' );
 1222+ if ( $nsType == 'site-name' ) {
 1223+ $name = $this->getVar( 'wgSitename' );
 1224+ // Sanitize for namespace
 1225+ // This algorithm should match the JS one in WebInstallerOutput.php
 1226+ $name = preg_replace( '/[\[\]\{\}|#<>%+? ]/', '_', $name );
 1227+ $name = str_replace( '&', '&amp;', $name );
 1228+ $name = preg_replace( '/__+/', '_', $name );
 1229+ $name = ucfirst( trim( $name, '_' ) );
 1230+ } elseif ( $nsType == 'generic' ) {
 1231+ $name = wfMsg( 'config-ns-generic' );
 1232+ } else { // other
 1233+ $name = $this->getVar( 'wgMetaNamespace' );
 1234+ }
 1235+
 1236+ // Validate namespace
 1237+ if ( strpos( $name, ':' ) !== false ) {
 1238+ $good = false;
 1239+ } else {
 1240+ // Title-style validation
 1241+ $title = Title::newFromText( $name );
 1242+ if ( !$title ) {
 1243+ $good = $nsType == 'site-name' ? true : false;
 1244+ } else {
 1245+ $name = $title->getDBkey();
 1246+ $good = true;
 1247+ }
 1248+ }
 1249+ if ( !$good ) {
 1250+ $this->parent->showError( 'config-ns-invalid', $name );
 1251+ $retVal = false;
 1252+ }
 1253+ $this->setVar( 'wgMetaNamespace', $name );
 1254+
 1255+ // Validate username for creation
 1256+ $name = $this->getVar( '_AdminName' );
 1257+ if ( strval( $name ) === '' ) {
 1258+ $this->parent->showError( 'config-admin-name-blank' );
 1259+ $cname = $name;
 1260+ $retVal = false;
 1261+ } else {
 1262+ $cname = User::getCanonicalName( $name, 'creatable' );
 1263+ if ( $cname === false ) {
 1264+ $this->parent->showError( 'config-admin-name-invalid', $name );
 1265+ $retVal = false;
 1266+ } else {
 1267+ $this->setVar( '_AdminName', $cname );
 1268+ }
 1269+ }
 1270+
 1271+ // Validate password
 1272+ $msg = false;
 1273+ $pwd = $this->getVar( '_AdminPassword' );
 1274+ $user = User::newFromName( $cname );
 1275+ $valid = $user->getPasswordValidity( $pwd );
 1276+ if ( strval( $pwd ) === '' ) {
 1277+ # $user->getPasswordValidity just checks for $wgMinimalPasswordLength.
 1278+ # This message is more specific and helpful.
 1279+ $msg = 'config-admin-password-blank';
 1280+ } elseif ( $pwd !== $this->getVar( '_AdminPassword2' ) ) {
 1281+ $msg = 'config-admin-password-mismatch';
 1282+ } elseif ( $valid !== true ) {
 1283+ # As of writing this will only catch the username being e.g. 'FOO' and
 1284+ # the password 'foo'
 1285+ $msg = $valid;
 1286+ }
 1287+ if ( $msg !== false ) {
 1288+ $this->parent->showError( $msg );
 1289+ $this->setVar( '_AdminPassword', '' );
 1290+ $this->setVar( '_AdminPassword2', '' );
 1291+ $retVal = false;
 1292+ }
 1293+ return $retVal;
 1294+ }
 1295+}
 1296+
 1297+class WebInstaller_Options extends WebInstallerPage {
 1298+ function execute() {
 1299+ if ( $this->getVar( '_SkipOptional' ) == 'skip' ) {
 1300+ return 'skip';
 1301+ }
 1302+ if ( $this->parent->request->wasPosted() ) {
 1303+ if ( $this->submit() ) {
 1304+ return 'continue';
 1305+ }
 1306+ }
 1307+
 1308+ $this->startForm();
 1309+ $this->addHTML(
 1310+ # User Rights
 1311+ $this->parent->getRadioSet( array(
 1312+ 'var' => '_RightsProfile',
 1313+ 'label' => 'config-profile',
 1314+ 'itemLabelPrefix' => 'config-profile-',
 1315+ 'values' => array_keys( $this->parent->rightsProfiles ),
 1316+ ) ) .
 1317+ $this->parent->getHelpBox( 'config-profile-help' ) .
 1318+
 1319+ # Licensing
 1320+ $this->parent->getRadioSet( array(
 1321+ 'var' => '_LicenseCode',
 1322+ 'label' => 'config-license',
 1323+ 'itemLabelPrefix' => 'config-license-',
 1324+ 'values' => array_keys( $this->parent->licenses ),
 1325+ 'commonAttribs' => array( 'class' => 'licenseRadio' ),
 1326+ ) ) .
 1327+ $this->getCCChooser() .
 1328+ $this->parent->getHelpBox( 'config-license-help' ) .
 1329+
 1330+ # E-mail
 1331+ $this->parent->getFieldsetStart( 'config-email-settings' ) .
 1332+ $this->parent->getCheckBox( array(
 1333+ 'var' => 'wgEnableEmail',
 1334+ 'label' => 'config-enable-email',
 1335+ 'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'emailwrapper' ),
 1336+ ) ) .
 1337+ $this->parent->getHelpBox( 'config-enable-email-help' ) .
 1338+ "<div id=\"emailwrapper\">" .
 1339+ $this->parent->getTextBox( array(
 1340+ 'var' => 'wgPasswordSender',
 1341+ 'label' => 'config-email-sender'
 1342+ ) ) .
 1343+ $this->parent->getHelpBox( 'config-email-sender-help' ) .
 1344+ $this->parent->getCheckBox( array(
 1345+ 'var' => 'wgEnableUserEmail',
 1346+ 'label' => 'config-email-user',
 1347+ ) ) .
 1348+ $this->parent->getHelpBox( 'config-email-user-help' ) .
 1349+ $this->parent->getCheckBox( array(
 1350+ 'var' => 'wgEnotifUserTalk',
 1351+ 'label' => 'config-email-usertalk',
 1352+ ) ) .
 1353+ $this->parent->getHelpBox( 'config-email-usertalk-help' ) .
 1354+ $this->parent->getCheckBox( array(
 1355+ 'var' => 'wgEnotifWatchlist',
 1356+ 'label' => 'config-email-watchlist',
 1357+ ) ) .
 1358+ $this->parent->getHelpBox( 'config-email-watchlist-help' ) .
 1359+ $this->parent->getCheckBox( array(
 1360+ 'var' => 'wgEmailAuthentication',
 1361+ 'label' => 'config-email-auth',
 1362+ ) ) .
 1363+ $this->parent->getHelpBox( 'config-email-auth-help' ) .
 1364+ "</div>" .
 1365+ $this->parent->getFieldsetEnd()
 1366+ );
 1367+
 1368+ $extensions = $this->parent->findExtensions();
 1369+ if( $extensions ) {
 1370+ $extHtml = $this->parent->getFieldsetStart( 'config-extensions' );
 1371+ foreach( $extensions as $ext ) {
 1372+ $extHtml .= $this->parent->getCheckBox( array(
 1373+ 'var' => "ext-$ext",
 1374+ 'rawtext' => $ext,
 1375+ ) );
 1376+ }
 1377+ $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) .
 1378+ $this->parent->getFieldsetEnd();
 1379+ $this->addHTML( $extHtml );
 1380+ }
 1381+
 1382+ $this->addHTML(
 1383+ # Uploading
 1384+ $this->parent->getFieldsetStart( 'config-upload-settings' ) .
 1385+ $this->parent->getCheckBox( array(
 1386+ 'var' => 'wgEnableUploads',
 1387+ 'label' => 'config-upload-enable',
 1388+ 'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'uploadwrapper' ),
 1389+ ) ) .
 1390+ $this->parent->getHelpBox( 'config-upload-help' ) .
 1391+ '<div id="uploadwrapper" style="display: none;">' .
 1392+ $this->parent->getTextBox( array(
 1393+ 'var' => 'wgDeletedDirectory',
 1394+ 'label' => 'config-upload-deleted',
 1395+ ) ) .
 1396+ $this->parent->getHelpBox( 'config-upload-deleted-help' ) .
 1397+ $this->parent->getTextBox( array(
 1398+ 'var' => 'wgLogo',
 1399+ 'label' => 'config-logo'
 1400+ ) ) .
 1401+ $this->parent->getHelpBox( 'config-logo-help' ) .
 1402+ '</div>' .
 1403+ $this->parent->getFieldsetEnd()
 1404+ );
 1405+
 1406+ $caches = array( 'none', 'anything', 'db' );
 1407+ $selected = 'db';
 1408+ if( count( $this->getVar( '_Caches' ) ) ) {
 1409+ $caches[] = 'accel';
 1410+ $selected = 'accel';
 1411+ }
 1412+ $caches[] = 'memcached';
 1413+
 1414+ $this->addHTML(
 1415+ # Advanced settings
 1416+ $this->parent->getFieldsetStart( 'config-advanced-settings' ) .
 1417+ # Object cache settings
 1418+ $this->parent->getRadioSet( array(
 1419+ 'var' => 'wgMainCacheType',
 1420+ 'label' => 'config-cache-options',
 1421+ 'itemLabelPrefix' => 'config-cache-',
 1422+ 'values' => $caches,
 1423+ 'value' => $selected,
 1424+ ) ) .
 1425+ $this->parent->getHelpBox( 'config-cache-help' ) .
 1426+ $this->parent->getTextBox( array(
 1427+ 'var' => '_MemCachedServers',
 1428+ 'label' => 'config-memcached-servers',
 1429+ ) ) .
 1430+ $this->parent->getHelpBox( 'config-memcached-help' ) .
 1431+ $this->parent->getFieldsetEnd()
 1432+ );
 1433+ $this->endForm();
 1434+ }
 1435+
 1436+ function getCCPartnerUrl() {
 1437+ global $wgServer;
 1438+ $exitUrl = $wgServer . $this->parent->getUrl( array(
 1439+ 'page' => 'Options',
 1440+ 'SubmitCC' => 'indeed',
 1441+ 'config__LicenseCode' => 'cc',
 1442+ 'config_wgRightsUrl' => '[license_url]',
 1443+ 'config_wgRightsText' => '[license_name]',
 1444+ 'config_wgRightsIcon' => '[license_button]',
 1445+ ) );
 1446+ $styleUrl = $wgServer . dirname( dirname( $this->parent->getUrl() ) ) .
 1447+ '/skins/common/config-cc.css';
 1448+ $iframeUrl = 'http://creativecommons.org/license/?' .
 1449+ wfArrayToCGI( array(
 1450+ 'partner' => 'MediaWiki',
 1451+ 'exit_url' => $exitUrl,
 1452+ 'lang' => $this->getVar( '_UserLang' ),
 1453+ 'stylesheet' => $styleUrl,
 1454+ ) );
 1455+ return $iframeUrl;
 1456+ }
 1457+
 1458+ function getCCChooser() {
 1459+ $iframeAttribs = array(
 1460+ 'class' => 'config-cc-iframe',
 1461+ 'name' => 'config-cc-iframe',
 1462+ 'id' => 'config-cc-iframe',
 1463+ 'frameborder' => 0,
 1464+ 'width' => '100%',
 1465+ 'height' => '100%',
 1466+ );
 1467+ if ( $this->getVar( '_CCDone' ) ) {
 1468+ $iframeAttribs['src'] = $this->parent->getUrl( array( 'ShowCC' => 'yes' ) );
 1469+ } else {
 1470+ $iframeAttribs['src'] = $this->getCCPartnerUrl();
 1471+ }
 1472+
 1473+ return
 1474+ "<div class=\"config-cc-wrapper\" id=\"config-cc-wrapper\" style=\"display: none;\">\n" .
 1475+ Xml::element( 'iframe', $iframeAttribs, '', false /* not short */ ) .
 1476+ "</div>\n";
 1477+ }
 1478+
 1479+ function getCCDoneBox() {
 1480+ $js = "parent.document.getElementById('config-cc-wrapper').style.height = '$1';";
 1481+ // If you change this height, also change it in config.css
 1482+ $expandJs = str_replace( '$1', '54em', $js );
 1483+ $reduceJs = str_replace( '$1', '70px', $js );
 1484+ return
 1485+ '<p>'.
 1486+ Xml::element( 'img', array( 'src' => $this->getVar( 'wgRightsIcon' ) ) ) .
 1487+ '&nbsp;&nbsp;' .
 1488+ htmlspecialchars( $this->getVar( 'wgRightsText' ) ) .
 1489+ "</p>\n" .
 1490+ "<p style=\"text-align: center\">" .
 1491+ Xml::element( 'a',
 1492+ array(
 1493+ 'href' => $this->getCCPartnerUrl(),
 1494+ 'onclick' => $expandJs,
 1495+ ),
 1496+ wfMsg( 'config-cc-again' )
 1497+ ) .
 1498+ "</p>\n" .
 1499+ "<script type=\"text/javascript\">\n" .
 1500+ # Reduce the wrapper div height
 1501+ htmlspecialchars( $reduceJs ) .
 1502+ "\n" .
 1503+ "</script>\n";
 1504+ }
 1505+
 1506+
 1507+ function submitCC() {
 1508+ $newValues = $this->parent->setVarsFromRequest(
 1509+ array( 'wgRightsUrl', 'wgRightsText', 'wgRightsIcon' ) );
 1510+ if ( count( $newValues ) != 3 ) {
 1511+ $this->parent->showError( 'config-cc-error' );
 1512+ return;
 1513+ }
 1514+ $this->setVar( '_CCDone', true );
 1515+ $this->addHTML( $this->getCCDoneBox() );
 1516+ }
 1517+
 1518+ function submit() {
 1519+ $this->parent->setVarsFromRequest( array( '_RightsProfile', '_LicenseCode',
 1520+ 'wgEnableEmail', 'wgPasswordSender', 'wgEnableUpload', 'wgLogo',
 1521+ 'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist',
 1522+ 'wgEmailAuthentication', 'wgMainCacheType', '_MemCachedServers' ) );
 1523+
 1524+ if ( !in_array( $this->getVar( '_RightsProfile' ),
 1525+ array_keys( $this->parent->rightsProfiles ) ) )
 1526+ {
 1527+ reset( $this->parent->rightsProfiles );
 1528+ $this->setVar( '_RightsProfile', key( $this->parent->rightsProfiles ) );
 1529+ }
 1530+
 1531+ $code = $this->getVar( '_LicenseCode' );
 1532+ if ( $code == 'cc-choose' ) {
 1533+ if ( !$this->getVar( '_CCDone' ) ) {
 1534+ $this->parent->showError( 'config-cc-not-chosen' );
 1535+ return false;
 1536+ }
 1537+ } elseif ( in_array( $code, array_keys( $this->parent->licenses ) ) ) {
 1538+ $entry = $this->parent->licenses[$code];
 1539+ if ( isset( $entry['text'] ) ) {
 1540+ $this->setVar( 'wgRightsText', $entry['text'] );
 1541+ } else {
 1542+ $this->setVar( 'wgRightsText', wfMsg( 'config-license-' . $code ) );
 1543+ }
 1544+ $this->setVar( 'wgRightsUrl', $entry['url'] );
 1545+ $this->setVar( 'wgRightsIcon', $entry['icon'] );
 1546+ } else {
 1547+ $this->setVar( 'wgRightsText', '' );
 1548+ $this->setVar( 'wgRightsUrl', '' );
 1549+ $this->setVar( 'wgRightsIcon', '' );
 1550+ }
 1551+
 1552+ $exts = $this->parent->getVar( '_Extensions' );
 1553+ foreach( $exts as $key => $ext ) {
 1554+ if( !$this->parent->request->getCheck( 'config_ext-' . $ext ) ) {
 1555+ unset( $exts[$key] );
 1556+ }
 1557+ }
 1558+ $this->parent->setVar( '_Extensions', $exts );
 1559+ return true;
 1560+ }
 1561+}
 1562+
 1563+class WebInstaller_Install extends WebInstallerPage {
 1564+
 1565+ function execute() {
 1566+ if( $this->parent->request->wasPosted() ) {
 1567+ return 'continue';
 1568+ }
 1569+ $this->startForm();
 1570+ $this->addHTML("<ul>");
 1571+ foreach( $this->parent->getInstallSteps() as $step ) {
 1572+ $this->startStage( "config-install-$step" );
 1573+ $func = 'install' . ucfirst( $step );
 1574+ $status = $this->parent->{$func}();
 1575+ $ok = $status->isGood();
 1576+ if ( !$ok ) {
 1577+ $this->parent->showStatusErrorBox( $status );
 1578+ }
 1579+ $this->endStage( $ok );
 1580+ }
 1581+ $this->addHTML("</ul>");
 1582+ $this->endForm();
 1583+ return true;
 1584+
 1585+ }
 1586+
 1587+ private function startStage( $msg ) {
 1588+ $this->addHTML( "<li>" . wfMsgHtml( $msg ) . wfMsg( 'ellipsis') );
 1589+ }
 1590+
 1591+ private function endStage( $success = true ) {
 1592+ $msg = $success ? 'config-install-step-done' : 'config-install-step-failed';
 1593+ $html = wfMsgHtml( 'word-separator' ) . wfMsgHtml( $msg );
 1594+ if ( !$success ) {
 1595+ $html = "<span class=\"error\">$html</span>";
 1596+ }
 1597+ $this->addHTML( $html . "</li>\n" );
 1598+ }
 1599+}
 1600+
 1601+class WebInstaller_Complete extends WebInstallerPage {
 1602+ public function execute() {
 1603+ global $IP;
 1604+ $this->startForm();
 1605+ $msg = file_exists( "$IP/LocalSettings.php" ) ? 'config-install-done-moved' : 'config-install-done';
 1606+ $this->addHTML(
 1607+ $this->parent->getInfoBox(
 1608+ wfMsgNoTrans( $msg,
 1609+ $GLOBALS['wgServer'] .
 1610+ $this->getVar( 'wgScriptPath' ) . '/index' .
 1611+ $this->getVar( 'wgScriptExtension' )
 1612+ ), 'tick-32.png'
 1613+ )
 1614+ );
 1615+ $this->endForm( false );
 1616+ }
 1617+}
 1618+
 1619+class WebInstaller_Restart extends WebInstallerPage {
 1620+ function execute() {
 1621+ $r = $this->parent->request;
 1622+ if ( $r->wasPosted() ) {
 1623+ $really = $r->getVal( 'submit-restart' );
 1624+ if ( $really ) {
 1625+ $this->parent->session = array();
 1626+ $this->parent->happyPages = array();
 1627+ $this->parent->settings = array();
 1628+ }
 1629+ return 'continue';
 1630+ }
 1631+
 1632+ $this->startForm();
 1633+ $s = $this->parent->getWarningBox( wfMsgNoTrans( 'config-help-restart' ) );
 1634+ $this->addHTML( $s );
 1635+ $this->endForm( 'restart' );
 1636+ }
 1637+}
 1638+
 1639+abstract class WebInstaller_Document extends WebInstallerPage {
 1640+ abstract function getFileName();
 1641+
 1642+ function execute() {
 1643+ $text = $this->getFileContents();
 1644+ $this->parent->output->addWikiText( $text );
 1645+ $this->startForm();
 1646+ $this->endForm( false );
 1647+ }
 1648+
 1649+ function getFileContents() {
 1650+ return file_get_contents( dirname( __FILE__ ) . '/../../' . $this->getFileName() );
 1651+ }
 1652+
 1653+ protected function formatTextFile( $text ) {
 1654+ // replace numbering with [1], [2], etc with MW-style numbering
 1655+ $text = preg_replace( "/\r?\n(\r?\n)?\\[\\d+\\]/m", "\\1#", $text );
 1656+ // join word-wrapped lines into one
 1657+ do {
 1658+ $prev = $text;
 1659+ $text = preg_replace( "/\n([\\*#])([^\r\n]*?)\r?\n([^\r\n#\\*:]+)/", "\n\\1\\2 \\3", $text );
 1660+ } while ( $text != $prev );
 1661+ // turn (bug nnnn) into links
 1662+ $text = preg_replace_callback('/bug (\d+)/', array( $this, 'replaceBugLinks' ), $text );
 1663+ // add links to manual to every global variable mentioned
 1664+ $text = preg_replace_callback('/(\$wg[a-z0-9_]+)/i', array( $this, 'replaceConfigLinks' ), $text );
 1665+ // special case for <pre> - formatted links
 1666+ do {
 1667+ $prev = $text;
 1668+ $text = preg_replace( '/^([^\\s].*?)\r?\n[\\s]+(https?:\/\/)/m', "\\1\n:\\2", $text );
 1669+ } while ( $text != $prev );
 1670+ return $text;
 1671+ }
 1672+
 1673+ private function replaceBugLinks( $matches ) {
 1674+ return '<span class="config-plainlink">[https://bugzilla.wikimedia.org/' .
 1675+ $matches[1] . ' bug ' . $matches[1] . ']</span>';
 1676+ }
 1677+
 1678+ private function replaceConfigLinks( $matches ) {
 1679+ return '<span class="config-plainlink">[http://www.mediawiki.org/wiki/Manual:' .
 1680+ $matches[1] . ' ' . $matches[1] . ']</span>';
 1681+ }
 1682+}
 1683+
 1684+class WebInstaller_Readme extends WebInstaller_Document {
 1685+ function getFileName() { return 'README'; }
 1686+
 1687+ function getFileContents() {
 1688+ return $this->formatTextFile( parent::getFileContents() );
 1689+ }
 1690+}
 1691+
 1692+class WebInstaller_ReleaseNotes extends WebInstaller_Document {
 1693+ function getFileName() { return 'RELEASE-NOTES'; }
 1694+
 1695+ function getFileContents() {
 1696+ return $this->formatTextFile( parent::getFileContents() );
 1697+ }
 1698+}
 1699+
 1700+class WebInstaller_UpgradeDoc extends WebInstaller_Document {
 1701+ function getFileName() { return 'UPGRADE'; }
 1702+
 1703+ function getFileContents() {
 1704+ return $this->formatTextFile( parent::getFileContents() );
 1705+ }
 1706+}
 1707+
 1708+class WebInstaller_Copying extends WebInstaller_Document {
 1709+ function getFileName() { return 'COPYING'; }
 1710+
 1711+ function getFileContents() {
 1712+ $text = parent::getFileContents();
 1713+ $text = str_replace( "\x0C", '', $text );
 1714+ $text = preg_replace_callback( '/\n[ \t]+/m', array( 'WebInstaller_Copying', 'replaceLeadingSpaces' ), $text );
 1715+ $text = '<tt>' . nl2br( $text ) . '</tt>';
 1716+ return $text;
 1717+ }
 1718+
 1719+ private static function replaceLeadingSpaces( $matches ) {
 1720+ return "\n" . str_repeat( '&nbsp;', strlen( $matches[0] ) );
 1721+ }
 1722+}
Property changes on: trunk/phase3/includes/installer/WebInstaller.php
___________________________________________________________________
Added: svn:eol-style
11723 + native
Index: trunk/phase3/includes/installer/WebInstallerOutput.php
@@ -0,0 +1,197 @@
 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 $warnings = '';
 16+ var $headerDone = false;
 17+ var $redirectTarget;
 18+ var $debug = true;
 19+ var $useShortHeader = false;
 20+
 21+ function __construct( $parent ) {
 22+ $this->parent = $parent;
 23+ }
 24+
 25+ function addHTML( $html ) {
 26+ $this->contents .= $html;
 27+ $this->flush();
 28+ }
 29+
 30+ function addWikiText( $text ) {
 31+ $this->addHTML( $this->parent->parse( $text ) );
 32+ }
 33+
 34+ function addHTMLNoFlush( $html ) {
 35+ $this->contents .= $html;
 36+ }
 37+
 38+ function addWarning( $msg ) {
 39+ $this->warnings .= "<p>$msg</p>\n";
 40+ }
 41+
 42+ function addWarningMsg( $msg /*, ... */ ) {
 43+ $params = func_get_args();
 44+ array_shift( $params );
 45+ $this->addWarning( wfMsg( $msg, $params ) );
 46+ }
 47+
 48+ function redirect( $url ) {
 49+ if ( $this->headerDone ) {
 50+ throw new MWException( __METHOD__ . ' called after sending headers' );
 51+ }
 52+ $this->redirectTarget = $url;
 53+ }
 54+
 55+ function output() {
 56+ $this->flush();
 57+ $this->outputFooter();
 58+ }
 59+
 60+ function useShortHeader( $use = true ) {
 61+ $this->useShortHeader = $use;
 62+ }
 63+
 64+ function flush() {
 65+ if ( !$this->headerDone ) {
 66+ $this->outputHeader();
 67+ }
 68+ if ( !$this->redirectTarget && strlen( $this->contents ) ) {
 69+ echo $this->contents;
 70+ flush();
 71+ $this->contents = '';
 72+ }
 73+ }
 74+
 75+ function getDir() {
 76+ global $wgLang;
 77+ if( !is_object( $wgLang ) || !$wgLang->isRtl() )
 78+ return 'ltr';
 79+ else
 80+ return 'rtl';
 81+ }
 82+
 83+ function headerDone() {
 84+ return $this->headerDone;
 85+ }
 86+
 87+ function outputHeader() {
 88+ $this->headerDone = true;
 89+ $dbTypes = $this->parent->getDBTypes();
 90+
 91+ $this->parent->request->response()->header("Content-Type: text/html; charset=utf-8");
 92+ if ( $this->redirectTarget ) {
 93+ $this->parent->request->response()->header( 'Location: '.$this->redirectTarget );
 94+ return;
 95+ }
 96+
 97+ if ( $this->useShortHeader ) {
 98+ $this->outputShortHeader();
 99+ return;
 100+ }
 101+
 102+?>
 103+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 104+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
 105+<head>
 106+ <meta name="robots" content="noindex, nofollow" />
 107+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
 108+ <title><?php $this->outputTitle(); ?></title>
 109+ <link rel="stylesheet" type="text/css" href="../skins/common/shared.css"/>
 110+ <link rel="stylesheet" type="text/css" href="../skins/monobook/main.css"/>
 111+ <link rel="stylesheet" type="text/css" href="../skins/common/config.css"/>
 112+ <script type="text/javascript"><!--
 113+<?php echo "var dbTypes = " . Xml::encodeJsVar( $dbTypes ) . ";\n"; ?>
 114+ // -->
 115+ </script>
 116+ <script type="text/javascript" src="../skins/common/jquery.min.js"></script>
 117+ <script type="text/javascript" src="../skins/common/config.js"></script>
 118+</head>
 119+
 120+<body class="<?php print $this->getDir(); ?>">
 121+<noscript>
 122+<style type="text/css">
 123+.config-help-message { display: block; }
 124+.config-show-help { display: none; }
 125+</style>
 126+</noscript>
 127+<div id="globalWrapper">
 128+<div id="column-content">
 129+<div id="content">
 130+<div id="bodyContent">
 131+
 132+<h1><?php $this->outputTitle(); ?></h1>
 133+<?php
 134+ }
 135+
 136+ function outputFooter() {
 137+ $this->outputWarnings();
 138+
 139+ if ( $this->useShortHeader ) {
 140+?>
 141+</body></html>
 142+<?php
 143+ return;
 144+ }
 145+?>
 146+
 147+</div></div></div>
 148+
 149+
 150+<div id="column-one">
 151+ <div class="portlet" id="p-logo">
 152+ <a style="background-image: url(../skins/common/images/mediawiki.png);"
 153+ href="http://www.mediawiki.org/"
 154+ title="Main Page"></a>
 155+ </div>
 156+ <script type="text/javascript"> if (window.isMSIE55) fixalpha(); </script>
 157+ <div class='portlet'><div class='pBody'>
 158+<?php
 159+ echo $this->parent->parse( wfMsgNoTrans( 'config-sidebar' ), true );
 160+?>
 161+ </div></div>
 162+</div>
 163+
 164+</div>
 165+
 166+</body>
 167+</html>
 168+<?php
 169+ }
 170+
 171+ function outputShortHeader() {
 172+?>
 173+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 174+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
 175+<head>
 176+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
 177+ <meta name="robots" content="noindex, nofollow" />
 178+ <title><?php $this->outputTitle(); ?></title>
 179+ <link rel="stylesheet" type="text/css" href="../skins/monobook/main.css"/>
 180+ <link rel="stylesheet" type="text/css" href="../skins/common/config.css"/>
 181+ <script type="text/javascript" src="../skins/common/jquery.min.js"></script>
 182+ <script type="text/javascript" src="../skins/common/config.js"></script>
 183+</head>
 184+
 185+<body style="background-image: none">
 186+<?php
 187+ }
 188+
 189+ function outputTitle() {
 190+ global $wgVersion;
 191+ echo htmlspecialchars( wfMsg( 'config-title', $wgVersion ) );
 192+ }
 193+
 194+ function outputWarnings() {
 195+ $this->addHTML( $this->warnings );
 196+ $this->warnings = '';
 197+ }
 198+}
Property changes on: trunk/phase3/includes/installer/WebInstallerOutput.php
___________________________________________________________________
Added: svn:eol-style
1199 + native
Index: trunk/phase3/includes/installer/Installer.php
@@ -0,0 +1,932 @@
 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+ 'wgEmailAuthentication',
 30+ 'wgDBtype',
 31+ 'wgDiff3',
 32+ 'wgImageMagickConvertCommand',
 33+ 'IP',
 34+ 'wgScriptPath',
 35+ 'wgScriptExtension',
 36+ 'wgMetaNamespace',
 37+// 'wgDeletedDirectory',
 38+ 'wgEnableUploads',
 39+ 'wgLogo',
 40+ 'wgShellLocale',
 41+ 'wgSecretKey',
 42+ );
 43+
 44+ /**
 45+ * Variables that are stored alongside globals, and are used for any
 46+ * configuration of the installation process aside from the MediaWiki
 47+ * configuration. Map of names to defaults.
 48+ * @protected
 49+ */
 50+ var $internalDefaults = array(
 51+ '_UserLang' => 'en',
 52+ '_Environment' => false,
 53+ '_CompiledDBs' => array(),
 54+ '_SafeMode' => false,
 55+ '_RaiseMemory' => false,
 56+ '_UpgradeDone' => false,
 57+ '_Caches' => array(),
 58+ '_InstallUser' => 'root',
 59+ '_InstallPassword' => '',
 60+ '_SameAccount' => true,
 61+ '_CreateDBAccount' => false,
 62+ '_NamespaceType' => 'site-name',
 63+ '_AdminName' => null, // will be set later, when the user selects language
 64+ '_AdminPassword' => '',
 65+ '_AdminPassword2' => '',
 66+ '_AdminEmail' => '',
 67+ '_Subscribe' => false,
 68+ '_SkipOptional' => 'continue',
 69+ '_RightsProfile' => 'wiki',
 70+ '_LicenseCode' => 'none',
 71+ '_CCDone' => false,
 72+ '_Extensions' => array(),
 73+ '_MemCachedServers' => '',
 74+ );
 75+
 76+ /**
 77+ * Known database types. These correspond to the class names <type>Installer,
 78+ * and are also MediaWiki database types valid for $wgDBtype.
 79+ *
 80+ * To add a new type, create a <type>Installer class and a Database<type>
 81+ * class, and add a config-type-<type> message to MessagesEn.php.
 82+ * @private
 83+ */
 84+ var $dbTypes = array(
 85+ 'mysql',
 86+ 'postgres',
 87+ 'sqlite',
 88+ 'oracle'
 89+ );
 90+
 91+ /**
 92+ * Minimum memory size in MB
 93+ */
 94+ private $minMemorySize = 50;
 95+
 96+ /**
 97+ * Cached DB installer instances, access using getDBInstaller()
 98+ * @private
 99+ */
 100+ var $dbInstallers = array();
 101+
 102+ /**
 103+ * A list of environment check methods called by doEnvironmentChecks().
 104+ * These may output warnings using showMessage(), and/or abort the
 105+ * installation process by returning false.
 106+ * @protected
 107+ */
 108+ var $envChecks = array(
 109+ 'envLatestVersion',
 110+ 'envCheckDB',
 111+ 'envCheckRegisterGlobals',
 112+ 'envCheckMagicQuotes',
 113+ 'envCheckMagicSybase',
 114+ 'envCheckMbstring',
 115+ 'envCheckZE1',
 116+ 'envCheckSafeMode',
 117+ 'envCheckXML',
 118+ 'envCheckPCRE',
 119+ 'envCheckMemory',
 120+ 'envCheckCache',
 121+ 'envCheckDiff3',
 122+ 'envCheckGraphics',
 123+ 'envCheckPath',
 124+ 'envCheckWriteableDir',
 125+ 'envCheckExtension',
 126+ 'envCheckShellLocale',
 127+ 'envCheckUploadsDirectory',
 128+ );
 129+
 130+ var $installSteps = array(
 131+ 'database',
 132+ 'tables',
 133+ 'secretkey',
 134+ 'sysop',
 135+ 'localsettings',
 136+ );
 137+
 138+ /**
 139+ * Known object cache types and the functions used to test for their existence
 140+ * @protected
 141+ */
 142+ var $objectCaches = array(
 143+ 'xcache' => 'xcache_get',
 144+ 'apc' => 'apc_fetch',
 145+ 'eaccel' => 'eaccelerator_get'
 146+ );
 147+
 148+ /**
 149+ * User rights profiles
 150+ */
 151+ var $rightsProfiles = array(
 152+ 'wiki' => array(),
 153+ 'no-anon' => array(
 154+ '*' => array( 'edit' => false )
 155+ ),
 156+ 'fishbowl' => array(
 157+ '*' => array(
 158+ 'createaccount' => false,
 159+ 'edit' => false,
 160+ ),
 161+ ),
 162+ 'private' => array(
 163+ '*' => array(
 164+ 'createaccount' => false,
 165+ 'edit' => false,
 166+ 'read' => false,
 167+ ),
 168+ ),
 169+ );
 170+
 171+ /**
 172+ * License types
 173+ */
 174+ var $licenses = array(
 175+ 'none' => array(
 176+ 'url' => '',
 177+ 'icon' => '',
 178+ 'text' => ''
 179+ ),
 180+ 'pd' => array(
 181+ 'url' => 'http://creativecommons.org/licenses/publicdomain/',
 182+ 'icon' => '{$wgStylePath}/common/images/public-domain.png',
 183+ ),
 184+ 'gfdl-old' => array(
 185+ 'url' => 'http://www.gnu.org/licenses/old-licenses/fdl-1.2.html',
 186+ 'icon' => '{$wgStylePath}/common/images/gnu-fdl.png',
 187+ ),
 188+ 'gfdl-current' => array(
 189+ 'url' => 'http://www.gnu.org/copyleft/fdl.html',
 190+ 'icon' => '{$wgStylePath}/common/images/gnu-fdl.png',
 191+ ),
 192+ 'cc-choose' => array(
 193+ // details will be filled in by the selector
 194+ 'url' => '',
 195+ 'icon' => '',
 196+ 'text' => '',
 197+ ),
 198+ );
 199+ /**
 200+ * Cached Title and ParserOptions used by parse()
 201+ * @private
 202+ */
 203+ var $parserTitle, $parserOptions;
 204+
 205+ /**
 206+ * Constructor, always call this from child classes
 207+ */
 208+ function __construct() {
 209+ $this->settings = $this->internalDefaults;
 210+ foreach ( $this->defaultVarNames as $var ) {
 211+ $this->settings[$var] = $GLOBALS[$var];
 212+ }
 213+ foreach ( $this->dbTypes as $type ) {
 214+ $installer = $this->getDBInstaller( $type );
 215+ if ( !$installer->isCompiled() ) {
 216+ continue;
 217+ }
 218+ $defaults = $installer->getGlobalDefaults();
 219+ foreach ( $installer->getGlobalNames() as $var ) {
 220+ if ( isset( $defaults[$var] ) ) {
 221+ $this->settings[$var] = $defaults[$var];
 222+ } else {
 223+ $this->settings[$var] = $GLOBALS[$var];
 224+ }
 225+ }
 226+ }
 227+
 228+ $this->parserTitle = Title::newFromText( 'Installer' );
 229+ $this->parserOptions = new ParserOptions;
 230+ $this->parserOptions->setEditSection( false );
 231+ }
 232+
 233+ /**
 234+ * UI interface for displaying a short message
 235+ * The parameters are like parameters to wfMsg().
 236+ * The messages will be in wikitext format, which will be converted to an
 237+ * output format such as HTML or text before being sent to the user.
 238+ */
 239+ abstract function showMessage( $msg /*, ... */ );
 240+
 241+ abstract function showStatusError( $status );
 242+
 243+ /**
 244+ * Get a list of known DB types
 245+ */
 246+ function getDBTypes() {
 247+ return $this->dbTypes;
 248+ }
 249+
 250+ /**
 251+ * Get an instance of InstallerDBType for the specified DB type
 252+ * @param $type Mixed: DB installer for which is needed, false to use default
 253+ */
 254+ function getDBInstaller( $type = false ) {
 255+ if ( !$type ) {
 256+ $type = $this->getVar( 'wgDBtype' );
 257+ }
 258+ if ( !isset( $this->dbInstallers[$type] ) ) {
 259+ $class = ucfirst( $type ). 'Installer';
 260+ $this->dbInstallers[$type] = new $class( $this );
 261+ }
 262+ return $this->dbInstallers[$type];
 263+ }
 264+
 265+ /**
 266+ * Do initial checks of the PHP environment. Set variables according to
 267+ * the observed environment.
 268+ *
 269+ * It's possible that this may be called under the CLI SAPI, not the SAPI
 270+ * that the wiki will primarily run under. In that case, the subclass should
 271+ * initialise variables such as wgScriptPath, before calling this function.
 272+ *
 273+ * Under the web subclass, it can already be assumed that PHP 5+ is in use
 274+ * and that sessions are working.
 275+ */
 276+ function doEnvironmentChecks() {
 277+ $this->showMessage( 'config-env-php', phpversion() );
 278+
 279+ $good = true;
 280+ foreach ( $this->envChecks as $check ) {
 281+ $status = $this->$check();
 282+ if ( $status === false ) {
 283+ $good = false;
 284+ }
 285+ }
 286+ $this->setVar( '_Environment', $good );
 287+ if ( $good ) {
 288+ $this->showMessage( 'config-env-good' );
 289+ } else {
 290+ $this->showMessage( 'config-env-bad' );
 291+ }
 292+ return $good;
 293+ }
 294+
 295+ /**
 296+ * Get an MW configuration variable, or internal installer configuration variable.
 297+ * The defaults come from $GLOBALS (ultimately DefaultSettings.php).
 298+ * Installer variables are typically prefixed by an underscore.
 299+ */
 300+ function getVar( $name, $default = null ) {
 301+ if ( !isset( $this->settings[$name] ) ) {
 302+ return $default;
 303+ } else {
 304+ return $this->settings[$name];
 305+ }
 306+ }
 307+
 308+ /**
 309+ * Set a MW configuration variable, or internal installer configuration variable.
 310+ */
 311+ function setVar( $name, $value ) {
 312+ $this->settings[$name] = $value;
 313+ }
 314+
 315+ /**
 316+ * Exports all wg* variables stored by the installer into global scope
 317+ */
 318+ function exportVars() {
 319+ foreach ( $this->settings as $name => $value ) {
 320+ if ( substr( $name, 0, 2 ) == 'wg' ) {
 321+ $GLOBALS[$name] = $value;
 322+ }
 323+ }
 324+ }
 325+
 326+ /**
 327+ * Get a fake password for sending back to the user in HTML.
 328+ * This is a security mechanism to avoid compromise of the password in the
 329+ * event of session ID compromise.
 330+ */
 331+ function getFakePassword( $realPassword ) {
 332+ return str_repeat( '*', strlen( $realPassword ) );
 333+ }
 334+
 335+ /**
 336+ * Set a variable which stores a password, except if the new value is a
 337+ * fake password in which case leave it as it is.
 338+ */
 339+ function setPassword( $name, $value ) {
 340+ if ( !preg_match( '/^\*+$/', $value ) ) {
 341+ $this->setVar( $name, $value );
 342+ }
 343+ }
 344+
 345+ /**
 346+ * Returns true if dl() can be used
 347+ */
 348+ function haveDl() {
 349+ return function_exists( 'dl' )
 350+ && is_callable( 'dl' )
 351+ && wfIniGetBool( 'enable_dl' )
 352+ && !wfIniGetBool( 'safe_mode' );
 353+ }
 354+
 355+ /** Check if we're installing the latest version */
 356+ function envLatestVersion() {
 357+ global $wgVersion;
 358+ $latestInfoUrl = 'http://www.mediawiki.org/w/api.php?action=mwreleases&format=json';
 359+ $latestInfo = Http::get( $latestInfoUrl );
 360+ if( !$latestInfo ) {
 361+ $this->showMessage( 'config-env-latest-can-not-check', $latestInfoUrl );
 362+ return;
 363+ }
 364+ $latestInfo = FormatJson::decode($latestInfo);
 365+ if ($latestInfo === false || !isset( $latestInfo->mwreleases ) ) {
 366+ # For when the request is successful but there's e.g. some silly man in
 367+ # the middle firewall blocking us, e.g. one of those annoying airport ones
 368+ $this->showMessage( 'config-env-latest-data-invalid', $latestInfoUrl );
 369+ return;
 370+ }
 371+ foreach( $latestInfo->mwreleases as $rel ) {
 372+ if( isset( $rel->current ) )
 373+ $currentVersion = $rel->version;
 374+ }
 375+ if( version_compare( $wgVersion, $currentVersion, '<' ) ) {
 376+ $this->showMessage( 'config-env-latest-old' );
 377+ $this->showHelpBox( 'config-env-latest-help', $wgVersion, $currentVersion );
 378+ } elseif( version_compare( $wgVersion, $currentVersion, '>' ) ) {
 379+ $this->showMessage( 'config-env-latest-new' );
 380+ }
 381+ $this->showMessage( 'config-env-latest-ok' );
 382+ }
 383+
 384+ /** Environment check for DB types */
 385+ function envCheckDB() {
 386+ $compiledDBs = array();
 387+ $haveDl = $this->haveDl();
 388+ $goodNames = array();
 389+ $allNames = array();
 390+ foreach ( $this->dbTypes as $name ) {
 391+ $db = $this->getDBInstaller( $name );
 392+ $readableName = wfMsg( 'config-type-' . $name );
 393+ if ( $db->isCompiled() ) {
 394+ $compiledDBs[] = $name;
 395+ $goodNames[] = $readableName;
 396+ }
 397+ $allNames[] = $readableName;
 398+ }
 399+ $this->setVar( '_CompiledDBs', $compiledDBs );
 400+
 401+ global $wgLang;
 402+ if ( !$compiledDBs ) {
 403+ $this->showMessage( 'config-no-db' );
 404+ $this->showHelpBox( 'config-no-db-help', $wgLang->commaList( $allNames ) );
 405+ return false;
 406+ }
 407+ $this->showMessage( 'config-have-db', $wgLang->commaList( $goodNames ) );
 408+ }
 409+
 410+ /** Environment check for register_globals */
 411+ function envCheckRegisterGlobals() {
 412+ if( wfIniGetBool( "magic_quotes_runtime" ) ) {
 413+ $this->showMessage( 'config-register-globals' );
 414+ }
 415+ }
 416+
 417+ /** Environment check for magic_quotes_runtime */
 418+ function envCheckMagicQuotes() {
 419+ if( wfIniGetBool( "magic_quotes_runtime" ) ) {
 420+ $this->showMessage( 'config-magic-quotes-runtime' );
 421+ return false;
 422+ }
 423+ }
 424+
 425+ /** Environment check for magic_quotes_sybase */
 426+ function envCheckMagicSybase() {
 427+ if ( wfIniGetBool( 'magic_quotes_sybase' ) ) {
 428+ $this->showMessage( 'config-magic-quotes-sybase' );
 429+ return false;
 430+ }
 431+ }
 432+
 433+ /* Environment check for mbstring.func_overload */
 434+ function envCheckMbstring() {
 435+ if ( wfIniGetBool( 'mbstring.func_overload' ) ) {
 436+ $this->showMessage( 'config-mbstring' );
 437+ return false;
 438+ }
 439+ }
 440+
 441+ /** Environment check for zend.ze1_compatibility_mode */
 442+ function envCheckZE1() {
 443+ if ( wfIniGetBool( 'zend.ze1_compatibility_mode' ) ) {
 444+ $this->showMessage( 'config-ze1' );
 445+ return false;
 446+ }
 447+ }
 448+
 449+ /** Environment check for safe_mode */
 450+ function envCheckSafeMode() {
 451+ if ( wfIniGetBool( 'safe_mode' ) ) {
 452+ $this->setVar( '_SafeMode', true );
 453+ $this->showMessage( 'config-safe-mode' );
 454+ }
 455+ }
 456+
 457+ /** Environment check for the XML module */
 458+ function envCheckXML() {
 459+ if ( !function_exists( "utf8_encode" ) ) {
 460+ $this->showMessage( 'config-xml-bad' );
 461+ return false;
 462+ }
 463+ $this->showMessage( 'config-xml-good' );
 464+ }
 465+
 466+ /** Environment check for the PCRE module */
 467+ function envCheckPCRE() {
 468+ if ( !function_exists( 'preg_match' ) ) {
 469+ $this->showMessage( 'config-pcre' );
 470+ return false;
 471+ }
 472+ }
 473+
 474+ /** Environment check for available memory */
 475+ function envCheckMemory() {
 476+ $limit = ini_get( 'memory_limit' );
 477+ if ( !$limit || $limit == -1 ) {
 478+ $this->showMessage( 'config-memory-none' );
 479+ return true;
 480+ }
 481+ $n = intval( $limit );
 482+ if( preg_match( '/^([0-9]+)[Mm]$/', trim( $limit ), $m ) ) {
 483+ $n = intval( $m[1] * (1024*1024) );
 484+ }
 485+ if( $n < $this->minMemorySize*1024*1024 ) {
 486+ $newLimit = "{$this->minMemorySize}M";
 487+ if( false === ini_set( "memory_limit", $newLimit ) ) {
 488+ $this->showMessage( 'config-memory-bad', $limit );
 489+ } else {
 490+ $this->showMessage( 'config-memory-raised', $limit, $newLimit );
 491+ $this->setVar( '_RaiseMemory', true );
 492+ }
 493+ } else {
 494+ $this->showMessage( 'config-memory-ok', $limit );
 495+ }
 496+ }
 497+
 498+ /** Environment check for compiled object cache types */
 499+ function envCheckCache() {
 500+ $caches = array();
 501+ foreach ( $this->objectCaches as $name => $function ) {
 502+ if ( function_exists( $function ) ) {
 503+ $caches[$name] = true;
 504+ $this->showMessage( 'config-' . $name );
 505+ }
 506+ }
 507+ if ( !$caches ) {
 508+ $this->showMessage( 'config-no-cache' );
 509+ }
 510+ $this->setVar( '_Caches', $caches );
 511+ }
 512+
 513+ /** Search for GNU diff3 */
 514+ function envCheckDiff3() {
 515+ $paths = array_merge(
 516+ array(
 517+ "/usr/bin",
 518+ "/usr/local/bin",
 519+ "/opt/csw/bin",
 520+ "/usr/gnu/bin",
 521+ "/usr/sfw/bin" ),
 522+ explode( PATH_SEPARATOR, getenv( "PATH" ) ) );
 523+ $names = array( "gdiff3", "diff3", "diff3.exe" );
 524+
 525+ $versionInfo = array( '$1 --version 2>&1', 'diff3 (GNU diffutils)' );
 526+ $haveDiff3 = false;
 527+ foreach ( $paths as $path ) {
 528+ $exe = $this->locateExecutable( $path, $names, $versionInfo );
 529+ if ($exe !== false) {
 530+ $this->setVar( 'wgDiff3', $exe );
 531+ $haveDiff3 = true;
 532+ break;
 533+ }
 534+ }
 535+ if ( $haveDiff3 ) {
 536+ $this->showMessage( 'config-diff3-good', $exe );
 537+ } else {
 538+ $this->setVar( 'wgDiff3', false );
 539+ $this->showMessage( 'config-diff3-bad' );
 540+ }
 541+ }
 542+
 543+ /**
 544+ * Search a path for any of the given executable names. Returns the
 545+ * executable name if found. Also checks the version string returned
 546+ * by each executable
 547+ *
 548+ * @param string $path Path to search
 549+ * @param array $names Array of executable names
 550+ * @param string $versionInfo Array with two members:
 551+ * 0 => Command to run for version check, with $1 for the path
 552+ * 1 => String to compare the output with
 553+ *
 554+ * If $versionInfo is not false, only executables with a version
 555+ * matching $versionInfo[1] will be returned.
 556+ */
 557+ function locateExecutable( $path, $names, $versionInfo = false ) {
 558+ if (!is_array($names))
 559+ $names = array($names);
 560+
 561+ foreach ($names as $name) {
 562+ $command = "$path/$name";
 563+ if ( @file_exists( $command ) ) {
 564+ if ( !$versionInfo )
 565+ return $command;
 566+
 567+ $file = str_replace( '$1', $command, $versionInfo[0] );
 568+ if ( strstr( wfShellExec( $file ), $versionInfo[1]) !== false )
 569+ return $command;
 570+ }
 571+ }
 572+ return false;
 573+ }
 574+
 575+ /** Environment check for ImageMagick and GD */
 576+ function envCheckGraphics() {
 577+ $imcheck = array( "/usr/bin", "/opt/csw/bin", "/usr/local/bin", "/sw/bin", "/opt/local/bin" );
 578+ foreach( $imcheck as $dir ) {
 579+ $im = "$dir/convert";
 580+ if( @file_exists( $im ) ) {
 581+ $this->showMessage( 'config-imagemagick', $im );
 582+ $this->setVar( 'wgImageMagickConvertCommand', $im );
 583+ return true;
 584+ }
 585+ }
 586+ if ( function_exists( 'imagejpeg' ) ) {
 587+ $this->showMessage( 'config-gd' );
 588+ return true;
 589+ }
 590+ $this->showMessage( 'no-scaling' );
 591+ }
 592+
 593+ /** Environment check for setting $IP and $wgScriptPath */
 594+ function envCheckPath() {
 595+ $IP = dirname( dirname( dirname( __FILE__ ) ) );
 596+ $this->setVar( 'IP', $IP );
 597+ $this->showMessage( 'config-dir', $IP );
 598+
 599+ // PHP_SELF isn't available sometimes, such as when PHP is CGI but
 600+ // cgi.fix_pathinfo is disabled. In that case, fall back to SCRIPT_NAME
 601+ // to get the path to the current script... hopefully it's reliable. SIGH
 602+ if ( !empty( $_SERVER['PHP_SELF'] ) ) {
 603+ $path = $_SERVER['PHP_SELF'];
 604+ } elseif ( !empty( $_SERVER['SCRIPT_NAME'] ) ) {
 605+ $path = $_SERVER['SCRIPT_NAME'];
 606+ } elseif ( $this->getVar( 'wgScriptPath' ) ) {
 607+ // Some kind soul has set it for us already (e.g. debconf)
 608+ return true;
 609+ } else {
 610+ $this->showMessage( 'config-no-uri' );
 611+ return false;
 612+ }
 613+ $uri = preg_replace( '{^(.*)/config.*$}', '$1', $path );
 614+ $this->setVar( 'wgScriptPath', $uri );
 615+ $this->showMessage( 'config-uri', $uri );
 616+ }
 617+
 618+ /** Environment check for writable config/ directory */
 619+ function envCheckWriteableDir() {
 620+ $ipDir = $this->getVar( 'IP' );
 621+ $configDir = $ipDir . '/config';
 622+ if( !is_writeable( $configDir ) ) {
 623+ $webserverGroup = self::maybeGetWebserverPrimaryGroup();
 624+ if ( $webserverGroup !== null ) {
 625+ $this->showMessage( 'config-dir-not-writable-group', $ipDir, $webserverGroup );
 626+ } else {
 627+ $this->showMessage( 'config-dir-not-writable-nogroup', $ipDir, $webserverGroup );
 628+ }
 629+ return false;
 630+ }
 631+ }
 632+
 633+ /** Environment check for setting the preferred PHP file extension */
 634+ function envCheckExtension() {
 635+ // FIXME: detect this properly
 636+ if ( defined( 'MW_INSTALL_PHP5_EXT' ) ) {
 637+ $ext = 'php5';
 638+ } else {
 639+ $ext = 'php';
 640+ }
 641+ $this->setVar( 'wgScriptExtension', ".$ext" );
 642+ $this->showMessage( 'config-file-extension', $ext );
 643+ }
 644+
 645+ function envCheckShellLocale() {
 646+ # Give up now if we're in safe mode or open_basedir
 647+ # It's theoretically possible but tricky to work with
 648+ if ( wfIniGetBool( "safe_mode" ) || ini_get( 'open_basedir' ) || !function_exists( 'exec' ) ) {
 649+ return true;
 650+ }
 651+
 652+ $os = php_uname( 's' );
 653+ $supported = array( 'Linux', 'SunOS', 'HP-UX' ); # Tested these
 654+ if ( !in_array( $os, $supported ) ) {
 655+ return true;
 656+ }
 657+
 658+ # Get a list of available locales
 659+ $lines = $ret = false;
 660+ exec( '/usr/bin/locale -a', $lines, $ret );
 661+ if ( $ret ) {
 662+ return true;
 663+ }
 664+
 665+ $lines = wfArrayMap( 'trim', $lines );
 666+ $candidatesByLocale = array();
 667+ $candidatesByLang = array();
 668+ foreach ( $lines as $line ) {
 669+ if ( $line === '' ) {
 670+ continue;
 671+ }
 672+ if ( !preg_match( '/^([a-zA-Z]+)(_[a-zA-Z]+|)\.(utf8|UTF-8)(@[a-zA-Z_]*|)$/i', $line, $m ) ) {
 673+ continue;
 674+ }
 675+ list( $all, $lang, $territory, $charset, $modifier ) = $m;
 676+ $candidatesByLocale[$m[0]] = $m;
 677+ $candidatesByLang[$lang][] = $m;
 678+ }
 679+
 680+ # Try the current value of LANG
 681+ if ( isset( $candidatesByLocale[ getenv( 'LANG' ) ] ) ) {
 682+ $this->setVar( 'wgShellLocale', getenv( 'LANG' ) );
 683+ $this->showMessage( 'config-shell-locale', getenv( 'LANG' ) );
 684+ return true;
 685+ }
 686+
 687+ # Try the most common ones
 688+ $commonLocales = array( 'en_US.UTF-8', 'en_US.utf8', 'de_DE.UTF-8', 'de_DE.utf8' );
 689+ foreach ( $commonLocales as $commonLocale ) {
 690+ if ( isset( $candidatesByLocale[$commonLocale] ) ) {
 691+ $this->setVar( 'wgShellLocale', $commonLocale );
 692+ $this->showMessage( 'config-shell-locale', $commonLocale );
 693+ return true;
 694+ }
 695+ }
 696+
 697+ # Is there an available locale in the Wiki's language?
 698+ $wikiLang = $this->getVar( 'wgLanguageCode' );
 699+ if ( isset( $candidatesByLang[$wikiLang] ) ) {
 700+ $m = reset( $candidatesByLang[$wikiLang] );
 701+ $this->setVar( 'wgShellLocale', $m[0] );
 702+ $this->showMessage( 'config-shell-locale', $m[0] );
 703+ return true;
 704+ }
 705+
 706+ # Are there any at all?
 707+ if ( count( $candidatesByLocale ) ) {
 708+ $m = reset( $candidatesByLocale );
 709+ $this->setVar( 'wgShellLocale', $m[0] );
 710+ $this->showMessage( 'config-shell-locale', $m[0] );
 711+ return true;
 712+ }
 713+
 714+ # Give up
 715+ return true;
 716+ }
 717+
 718+ function envCheckUploadsDirectory() {
 719+ global $IP, $wgServer;
 720+ $dir = $IP . '/images/';
 721+ $url = $wgServer . $this->getVar( 'wgScriptPath' ) . '/images/';
 722+ $safe = !$this->dirIsExecutable( $dir, $url );
 723+ if ( $safe ) {
 724+ $this->showMessage( 'config-uploads-safe' );
 725+ } else {
 726+ $this->showMessage( 'config-uploads-not-safe', $dir );
 727+ }
 728+ }
 729+
 730+ /**
 731+ * Checks if scripts located in the given directory can be executed via the given URL
 732+ */
 733+ function dirIsExecutable( $dir, $url ) {
 734+ $scriptTypes = array(
 735+ 'php' => array(
 736+ "<?php echo 'ex' . 'ec';",
 737+ "#!/var/env php5\n<?php echo 'ex' . 'ec';",
 738+ ),
 739+ );
 740+ // it would be good to check other popular languages here, but it'll be slow
 741+
 742+ wfSuppressWarnings();
 743+ foreach ( $scriptTypes as $ext => $contents ) {
 744+ foreach ( $contents as $source ) {
 745+ $file = 'exectest.' . $ext;
 746+ if ( !file_put_contents( $dir . $file, $source ) ) {
 747+ break;
 748+ }
 749+ $text = Http::get( $url . $file );
 750+ unlink( $dir . $file );
 751+ if ( $text == 'exec' ) {
 752+ wfRestoreWarnings();
 753+ return $ext;
 754+ }
 755+ }
 756+ }
 757+ wfRestoreWarnings();
 758+ return false;
 759+ }
 760+
 761+ /**
 762+ * Convert wikitext $text to HTML.
 763+ *
 764+ * This is potentially error prone since many parser features require a complete
 765+ * installed MW database. The solution is to just not use those features when you
 766+ * write your messages. This appears to work well enough. Basic formatting and
 767+ * external links work just fine.
 768+ *
 769+ * But in case a translator decides to throw in a #ifexist or internal link or
 770+ * whatever, this function is guarded to catch attempted DB access and to present
 771+ * some fallback text.
 772+ *
 773+ * @param string $text
 774+ * @return string
 775+ */
 776+ function parse( $text, $lineStart = false ) {
 777+ global $wgParser;
 778+ try {
 779+ $out = $wgParser->parse( $text, $this->parserTitle, $this->parserOptions, $lineStart );
 780+ $html = $out->getText();
 781+ } catch ( InstallerDBAccessError $e ) {
 782+ $html = '<!--DB access attempted during parse--> ' . htmlspecialchars( $text );
 783+ if ( !empty( $this->debug ) ) {
 784+ $html .= "<!--\n" . $e->getTraceAsString() . "\n-->";
 785+ }
 786+ }
 787+ return $html;
 788+ }
 789+
 790+ /**
 791+ * Extension tag hook for a documentation link
 792+ */
 793+ function docLink( $linkText, $attribs, $parser ) {
 794+ $url = $this->getDocUrl( $attribs['href'] );
 795+ return '<a href="' . htmlspecialchars( $url ) . '">' .
 796+ htmlspecialchars( $linkText ) .
 797+ '</a>';
 798+ }
 799+
 800+ /**
 801+ * Overridden by WebInstaller to provide lastPage parameters
 802+ */
 803+ protected function getDocUrl( $page ) {
 804+ return "{$_SERVER['PHP_SELF']}?page=" . urlencode( $attribs['href'] );
 805+ }
 806+
 807+ public function findExtensions() {
 808+ if( $this->getVar( 'IP' ) === null ) {
 809+ return false;
 810+ }
 811+ $exts = array();
 812+ $dir = $this->getVar( 'IP' ) . '/extensions';
 813+ $dh = opendir( $dir );
 814+ while ( ( $file = readdir( $dh ) ) !== false ) {
 815+ if( file_exists( "$dir/$file/$file.php" ) ) {
 816+ $exts[] = $file;
 817+ }
 818+ }
 819+ $this->setVar( '_Extensions', $exts );
 820+ return $exts;
 821+ }
 822+
 823+ public function getInstallSteps() {
 824+ if( $this->getVar( '_UpgradeDone' ) ) {
 825+ $this->installSteps = array( 'localsettings' );
 826+ }
 827+ if( count( $this->getVar( '_Extensions' ) ) ) {
 828+ $this->installSteps = array_unshift( $this->installSteps, 'extensions' );
 829+ }
 830+ return $this->installSteps;
 831+ }
 832+
 833+ public function installExtensions() {
 834+ global $wgHooks, $wgAutoloadClasses;
 835+ $exts = $this->getVar( '_Extensions' );
 836+ $path = $this->getVar( 'IP' ) . '/extensions';
 837+ foreach( $exts as $e ) {
 838+ require( "$path/$e/$e.php" );
 839+ }
 840+ return Status::newGood();
 841+ }
 842+
 843+ public function installDatabase() {
 844+ $installer = $this->getDBInstaller( $this->getVar( 'wgDBtype' ) );
 845+ $status = $installer->setupDatabase();
 846+ return $status;
 847+ }
 848+
 849+ public function installTables() {
 850+ $installer = $this->getDBInstaller();
 851+ $status = $installer->createTables();
 852+ if( $status->isGood() ) {
 853+ LBFactory::enableBackend();
 854+ }
 855+ return $status;
 856+ }
 857+
 858+ public function installSecretKey() {
 859+ $file = wfIsWindows() ? null : @fopen( "/dev/urandom", "r" );
 860+ if ( $file ) {
 861+ $secretKey = bin2hex( fread( $file, 32 ) );
 862+ fclose( $file );
 863+ } else {
 864+ $secretKey = "";
 865+ for ( $i=0; $i<8; $i++ ) {
 866+ $secretKey .= dechex(mt_rand(0, 0x7fffffff));
 867+ }
 868+ $this->output->addWarningMsg( 'config-insecure-secretkey' );
 869+ }
 870+ $this->setVar( 'wgSecretKey', $secretKey );
 871+ return Status::newGood();
 872+ }
 873+
 874+ public function installSysop() {
 875+ $name = $this->getVar( '_AdminName' );
 876+ $user = User::newFromName( $name );
 877+ if ( !$user ) {
 878+ // we should've validated this earlier anyway!
 879+ return Status::newFatal( 'config-admin-error-user', $name );
 880+ }
 881+ if ( $user->idForName() == 0 ) {
 882+ $user->addToDatabase();
 883+ try {
 884+ $user->setPassword( $this->getVar( '_AdminPassword' ) );
 885+ } catch( PasswordError $pwe ) {
 886+ return Status::newFatal( 'config-admin-error-password', $name, $pwe->getMessage() );
 887+ }
 888+ $user->saveSettings();
 889+ $user->addGroup( 'sysop' );
 890+ $user->addGroup( 'bureaucrat' );
 891+ }
 892+ return Status::newGood();
 893+ }
 894+
 895+ public function installLocalsettings() {
 896+ $localSettings = new LocalSettingsGenerator( $this );
 897+ $ok = $localSettings->writeLocalSettings();
 898+
 899+ # TODO: Make writeLocalSettings() itself not warn, but instead return
 900+ # a Status object to us to pass along.
 901+ if ( $ok ) {
 902+ return Status::newGood();
 903+ } else {
 904+ return Status::newFatal();
 905+ }
 906+ }
 907+
 908+ /*
 909+ * On POSIX systems return the primary group of the webserver we're running under.
 910+ * On other systems just returns null.
 911+ *
 912+ * This is used to advice the user that he should chgrp his config/data/images directory as the
 913+ * webserver user before he can install.
 914+ *
 915+ * Public because SqliteInstaller needs it, and doesn't subclass Installer.
 916+ *
 917+ * @return string
 918+ */
 919+ public static function maybeGetWebserverPrimaryGroup() {
 920+ if ( ! function_exists('posix_getegid') || ! function_exists('posix_getpwuid') ) {
 921+ # I don't know this, this isn't UNIX
 922+ return null;
 923+ }
 924+
 925+ # posix_getegid() *not* getmygid() because we want the group of the webserver,
 926+ # not whoever owns the current script
 927+ $gid = posix_getegid();
 928+ $getpwuid = posix_getpwuid( $gid );
 929+ $group = $getpwuid["name"];
 930+
 931+ return $group;
 932+ }
 933+}
Property changes on: trunk/phase3/includes/installer/Installer.php
___________________________________________________________________
Added: svn:eol-style
1934 + native
Index: trunk/phase3/includes/installer/SqliteInstaller.php
@@ -0,0 +1,186 @@
 2+<?php
 3+
 4+class SqliteInstaller extends InstallerDBType {
 5+ protected $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 getGlobalDefaults() {
 19+ if ( isset( $_SERVER['DOCUMENT_ROOT'] ) ) {
 20+ $path = str_replace(
 21+ array( '/', '\\' ),
 22+ DIRECTORY_SEPARATOR,
 23+ dirname( $_SERVER['DOCUMENT_ROOT'] ) . '/data'
 24+ );
 25+ return array( 'wgSQLiteDataDir' => $path );
 26+ } else {
 27+ return array();
 28+ }
 29+ }
 30+
 31+ function getConnectForm() {
 32+ return $this->getTextBox( 'wgSQLiteDataDir', 'config-sqlite-dir' ) .
 33+ $this->parent->getHelpBox( 'config-sqlite-dir-help' ) .
 34+ $this->getTextBox( 'wgDBname', 'config-db-name' ) .
 35+ $this->parent->getHelpBox( 'config-sqlite-name-help' );
 36+ }
 37+
 38+ function submitConnectForm() {
 39+ global $wgSQLiteDataDir;
 40+ $this->setVarsFromRequest( array( 'wgSQLiteDataDir', 'wgDBname' ) );
 41+
 42+ $dir = realpath( $this->getVar( 'wgSQLiteDataDir' ) );
 43+ if ( !$dir ) {
 44+ // realpath() sometimes fails, especially on Windows
 45+ $dir = $this->getVar( 'wgSQLiteDataDir' );
 46+ }
 47+ $this->setVar( 'wgSQLiteDataDir', $dir );
 48+ return self::dataDirOKmaybeCreate( $dir, true /* create? */ );
 49+ }
 50+
 51+ private static function dataDirOKmaybeCreate( $dir, $create = false ) {
 52+ if ( !is_dir( $dir ) ) {
 53+ if ( !is_writable( dirname( $dir ) ) ) {
 54+ $webserverGroup = Installer::maybeGetWebserverPrimaryGroup();
 55+ if ( $webserverGroup !== null ) {
 56+ return Status::newFatal( 'config-sqlite-parent-unwritable-group', $dir, dirname( $dir ), basename( $dir ), $webserverGroup );
 57+ } else {
 58+ return Status::newFatal( 'config-sqlite-parent-unwritable-nogroup', $dir, dirname( $dir ), basename( $dir ) );
 59+ }
 60+ }
 61+
 62+ # Called early on in the installer, later we just want to sanity check
 63+ # if it's still writable
 64+ if ( $create ) {
 65+ wfSuppressWarnings();
 66+ $ok = wfMkdirParents( $dir, 0700 );
 67+ wfRestoreWarnings();
 68+ if ( !$ok ) {
 69+ return Status::newFatal( 'config-sqlite-mkdir-error', $dir );
 70+ }
 71+ # Put a .htaccess file in in case the user didn't take our advice
 72+ file_put_contents( "$dir/.htaccess", "Deny from all\n" );
 73+ }
 74+ }
 75+ if ( !is_writable( $dir ) ) {
 76+ return Status::newFatal( 'config-sqlite-dir-unwritable', $dir );
 77+ }
 78+
 79+ # We haven't blown up yet, fall through
 80+ return Status::newGood();
 81+ }
 82+
 83+ function getConnection() {
 84+ global $wgSQLiteDataDir;
 85+
 86+ $status = Status::newGood();
 87+ $dir = $this->getVar( 'wgSQLiteDataDir' );
 88+ $dbName = $this->getVar( 'wgDBname' );
 89+
 90+ try {
 91+ # FIXME: need more sensible constructor parameters, e.g. single associative array
 92+ # Setting globals kind of sucks
 93+ $wgSQLiteDataDir = $dir;
 94+ $this->db = new DatabaseSqlite( false, false, false, $dbName );
 95+ $status->value = $this->db;
 96+ } catch ( DBConnectionError $e ) {
 97+ $status->fatal( 'config-sqlite-connection-error', $e->getMessage() );
 98+ }
 99+ return $status;
 100+ }
 101+
 102+ function needsUpgrade() {
 103+ $dir = $this->getVar( 'wgSQLiteDataDir' );
 104+ $dbName = $this->getVar( 'wgDBname' );
 105+ // Don't create the data file yet
 106+ if ( !file_exists( DatabaseSqlite::generateFileName( $dir, $dbName ) ) ) {
 107+ return false;
 108+ }
 109+
 110+ // If the data file exists, look inside it
 111+ return parent::needsUpgrade();
 112+ }
 113+
 114+ function getSettingsForm() {
 115+ return false;
 116+ }
 117+
 118+ function submitSettingsForm() {
 119+ return Status::newGood();
 120+ }
 121+
 122+ function setupDatabase() {
 123+ $dir = $this->getVar( 'wgSQLiteDataDir' );
 124+
 125+ # Sanity check. We checked this before but maybe someone deleted the
 126+ # data dir between then and now
 127+ $dir_status = self::dataDirOKmaybeCreate( $dir, false /* create? */ );
 128+ if ( !$dir_status->isOK() ) {
 129+ return $dir_status;
 130+ }
 131+
 132+ $db = $this->getVar( 'wgDBname' );
 133+ $file = DatabaseSqlite::generateFileName( $dir, $db );
 134+ if ( file_exists( $file ) ) {
 135+ if ( !is_writable( $file ) ) {
 136+ return Status::newFatal( 'config-sqlite-readonly', $file );
 137+ }
 138+ } else {
 139+ if ( file_put_contents( $file, '' ) === false ) {
 140+ return Status::newFatal( 'config-sqlite-cant-create-db', $file );
 141+ }
 142+ }
 143+ // nuke the unused settings for clarity
 144+ $this->setVar( 'wgDBserver', '' );
 145+ $this->setVar( 'wgDBuser', '' );
 146+ $this->setVar( 'wgDBpassword', '' );
 147+ return $this->getConnection();
 148+ }
 149+
 150+ function createTables() {
 151+ global $IP;
 152+ $status = $this->getConnection();
 153+ if ( !$status->isOK() ) {
 154+ return $status;
 155+ }
 156+ // Process common MySQL/SQLite table definitions
 157+ $err = $this->db->sourceFile( "$IP/maintenance/tables.sql" );
 158+ if ( $err !== true ) {
 159+ //@todo or...?
 160+ $this->db->reportQueryError( $err, 0, $sql, __FUNCTION__ );
 161+ }
 162+ //@todo set up searchindex
 163+ // Create default interwikis
 164+ return $this->populateInterwikiTable( $this->db );
 165+ }
 166+
 167+ function doUpgrade() {
 168+ global $wgDatabase;
 169+ LBFactory::enableBackend();
 170+ $wgDatabase = wfGetDB( DB_MASTER );
 171+ ob_start( array( 'SqliteInstaller', 'outputHandler' ) );
 172+ do_all_updates( false, true );
 173+ ob_end_flush();
 174+ return true;
 175+ }
 176+
 177+ static function outputHandler( $string ) {
 178+ return htmlspecialchars( $string );
 179+ }
 180+
 181+ function getLocalSettings() {
 182+ $dir = LocalSettingsGenerator::escapePhpString( $this->getVar( 'wgSQLiteDataDir' ) );
 183+ return
 184+"# SQLite-specific settings
 185+\$wgSQLiteDataDir = \"{$dir}\";";
 186+ }
 187+}
Property changes on: trunk/phase3/includes/installer/SqliteInstaller.php
___________________________________________________________________
Added: svn:eol-style
1188 + native
Index: trunk/phase3/includes/installer/LocalSettingsGenerator.php
@@ -0,0 +1,251 @@
 2+<?php
 3+
 4+class LocalSettingsGenerator {
 5+ private $extensions, $values = array();
 6+ private $configPath, $dbSettings = '';
 7+ private $safeMode = false;
 8+ private $installer;
 9+
 10+ /**
 11+ * Construtor.
 12+ * @param $installer Installer subclass
 13+ */
 14+ public function __construct( Installer $installer ) {
 15+ $this->installer = $installer;
 16+ $this->configPath = $installer->getVar( 'IP' ) . '/config';
 17+ $this->extensions = $installer->getVar( '_Extensions' );
 18+ $db = $installer->getDBInstaller( $installer->getVar( 'wgDBtype' ) );
 19+
 20+ $confItems = array_merge( array( 'wgScriptPath', 'wgScriptExtension',
 21+ 'wgPasswordSender', 'wgImageMagickConvertCommand', 'wgShellLocale',
 22+ 'wgLanguageCode', 'wgEnableEmail', 'wgEnableUserEmail', 'wgDiff3',
 23+ 'wgEnotifUserTalk', 'wgEnotifWatchlist', 'wgEmailAuthentication',
 24+ 'wgDBtype', 'wgSecretKey', 'wgRightsUrl', 'wgSitename', 'wgRightsIcon',
 25+ 'wgRightsText', 'wgRightsCode', 'wgMainCacheType', 'wgEnableUploads',
 26+ 'wgMainCacheType', '_MemCachedServers', 'wgDBserver', 'wgDBuser',
 27+ 'wgDBpassword' ), $db->getGlobalNames() );
 28+ $boolItems = array( 'wgEnableEmail', 'wgEnableUserEmail', 'wgEnotifUserTalk',
 29+ 'wgEnotifWatchlist', 'wgEmailAuthentication', 'wgEnableUploads' );
 30+ foreach( $confItems as $c ) {
 31+ $val = $installer->getVar( $c );
 32+ if( in_array( $c, $boolItems ) ) {
 33+ $val = wfBoolToStr( $val );
 34+ }
 35+ $this->values[$c] = $val;
 36+ }
 37+ $this->dbSettings = $db->getLocalSettings();
 38+ $this->safeMode = $installer->getVar( '_SafeMode' );
 39+ $this->values['wgEmergencyContact'] = $this->values['wgPasswordSender'];
 40+ $this->values = wfArrayMap( array( 'LocalSettingsGenerator', 'escapePhpString' ), $this->values );
 41+ }
 42+
 43+ public static function escapePhpString( $string ) {
 44+ if ( is_array( $string ) || is_object( $string ) ) {
 45+ return false;
 46+ }
 47+ return strtr( $string,
 48+ array(
 49+ "\n" => "\\n",
 50+ "\r" => "\\r",
 51+ "\t" => "\\t",
 52+ "\\" => "\\\\",
 53+ "\$" => "\\\$",
 54+ "\"" => "\\\""
 55+ ));
 56+ }
 57+
 58+ /**
 59+ * Write the file
 60+ * @param $secretKey String A random string to
 61+ * @return boolean On successful file write
 62+ */
 63+ public function writeLocalSettings() {
 64+ $localSettings = $this->getDefaultText();
 65+ if( count( $this->extensions ) ) {
 66+ $localSettings .= "\n# The following extensions were automatically enabled:\n";
 67+ foreach( $this->extensions as $ext ) {
 68+ $localSettings .= "require( 'extensions/$ext/$ext.php' );\n";
 69+ }
 70+ }
 71+ wfSuppressWarnings();
 72+ $ret = file_put_contents( $this->configPath . '/LocalSettings.php', $localSettings );
 73+ wfRestoreWarnings();
 74+ if ( !$ret ) {
 75+ $warn = wfMsg( 'config-install-localsettings-unwritable' ) . '
 76+<textarea name="LocalSettings" id="LocalSettings" cols="80" rows="25" readonly="readonly">'
 77+ . htmlspecialchars( $localSettings ) . '</textarea>';
 78+ $this->installer->output->addWarning( $warn );
 79+ }
 80+ return $ret;
 81+ }
 82+
 83+ private function buildMemcachedServerList() {
 84+ $servers = $this->values['_MemCachedServers'];
 85+ if( !$servers ) {
 86+ return 'array()';
 87+ } else {
 88+ $ret = 'array( ';
 89+ $servers = explode( ',', $servers );
 90+ foreach( $servers as $srv ) {
 91+ $srv = trim( $srv );
 92+ $ret .= "'$srv', ";
 93+ }
 94+ return rtrim( $ret, ', ' ) . ' )';
 95+ }
 96+ }
 97+
 98+ private function getDefaultText() {
 99+ if( !$this->values['wgImageMagickConvertCommand'] ) {
 100+ $this->values['wgImageMagickConvertCommand'] = '/usr/bin/convert';
 101+ $magic = '#';
 102+ } else {
 103+ $magic = '';
 104+ }
 105+ if( !$this->values['wgShellLocale'] ) {
 106+ $this->values['wgShellLocale'] = 'en_US.UTF-8';
 107+ $locale = '#';
 108+ } else {
 109+ $locale = '';
 110+ }
 111+ $rights = $this->values['wgRightsUrl'] ? '' : '#';
 112+ $hashedUploads = $this->safeMode ? '#' : '';
 113+ switch( $this->values['wgMainCacheType'] ) {
 114+ case 'anything':
 115+ case 'db':
 116+ case 'memcached':
 117+ case 'accel':
 118+ $cacheType = 'CACHE_' . strtoupper( $this->values['wgMainCacheType']);
 119+ break;
 120+ case 'none':
 121+ default:
 122+ $cacheType = 'CACHE_NONE';
 123+ }
 124+ $mcservers = $this->buildMemcachedServerList();
 125+ return "<?php
 126+# This file was automatically generated by the MediaWiki {$GLOBALS['wgVersion']}
 127+# installer. If you make manual changes, please keep track in case you
 128+# need to recreate them later.
 129+#
 130+# See includes/DefaultSettings.php for all configurable settings
 131+# and their default values, but don't forget to make changes in _this_
 132+# file, not there.
 133+#
 134+# Further documentation for configuration settings may be found at:
 135+# http://www.mediawiki.org/wiki/Manual:Configuration_settings
 136+
 137+# If you customize your file layout, set \$IP to the directory that contains
 138+# the other MediaWiki files. It will be used as a base to locate files.
 139+if( defined( 'MW_INSTALL_PATH' ) ) {
 140+ \$IP = MW_INSTALL_PATH;
 141+} else {
 142+ \$IP = dirname( __FILE__ );
 143+}
 144+
 145+\$path = array( \$IP, \"\$IP/includes\", \"\$IP/languages\" );
 146+set_include_path( implode( PATH_SEPARATOR, \$path ) . PATH_SEPARATOR . get_include_path() );
 147+
 148+require_once( \"\$IP/includes/DefaultSettings.php\" );
 149+
 150+if ( \$wgCommandLineMode ) {
 151+ if ( isset( \$_SERVER ) && array_key_exists( 'REQUEST_METHOD', \$_SERVER ) ) {
 152+ die( \"This script must be run from the command line\\n\" );
 153+ }
 154+}
 155+## Uncomment this to disable output compression
 156+# \$wgDisableOutputCompression = true;
 157+
 158+\$wgSitename = \"{$this->values['wgSitename']}\";
 159+
 160+## The URL base path to the directory containing the wiki;
 161+## defaults for all runtime URL paths are based off of this.
 162+## For more information on customizing the URLs please see:
 163+## http://www.mediawiki.org/wiki/Manual:Short_URL
 164+\$wgScriptPath = \"{$this->values['wgScriptPath']}\";
 165+\$wgScriptExtension = \"{$this->values['wgScriptExtension']}\";
 166+
 167+## The relative URL path to the skins directory
 168+\$wgStylePath = \"\$wgScriptPath/skins\";
 169+
 170+## The relative URL path to the logo. Make sure you change this from the default,
 171+## or else you'll overwrite your logo when you upgrade!
 172+\$wgLogo = \"\$wgStylePath/common/images/wiki.png\";
 173+
 174+## UPO means: this is also a user preference option
 175+
 176+\$wgEnableEmail = {$this->values['wgEnableEmail']};
 177+\$wgEnableUserEmail = {$this->values['wgEnableUserEmail']}; # UPO
 178+
 179+\$wgEmergencyContact = \"{$this->values['wgEmergencyContact']}\";
 180+\$wgPasswordSender = \"{$this->values['wgPasswordSender']}\";
 181+
 182+\$wgEnotifUserTalk = {$this->values['wgEnotifUserTalk']}; # UPO
 183+\$wgEnotifWatchlist = {$this->values['wgEnotifWatchlist']}; # UPO
 184+\$wgEmailAuthentication = {$this->values['wgEmailAuthentication']};
 185+
 186+## Database settings
 187+\$wgDBtype = \"{$this->values['wgDBtype']}\";
 188+\$wgDBserver = \"{$this->values['wgDBserver']}\";
 189+\$wgDBname = \"{$this->values['wgDBname']}\";
 190+\$wgDBuser = \"{$this->values['wgDBuser']}\";
 191+\$wgDBpassword = \"{$this->values['wgDBpassword']}\";
 192+
 193+{$this->dbSettings}
 194+
 195+## Shared memory settings
 196+\$wgMainCacheType = $cacheType;
 197+\$wgMemCachedServers = $mcservers;
 198+
 199+## To enable image uploads, make sure the 'images' directory
 200+## is writable, then set this to true:
 201+\$wgEnableUploads = {$this->values['wgEnableUploads']};
 202+{$magic}\$wgUseImageMagick = true;
 203+{$magic}\$wgImageMagickConvertCommand = \"{$this->values['wgImageMagickConvertCommand']}\";
 204+
 205+## If you use ImageMagick (or any other shell command) on a
 206+## Linux server, this will need to be set to the name of an
 207+## available UTF-8 locale
 208+{$locale}\$wgShellLocale = \"{$this->values['wgShellLocale']}\";
 209+
 210+## If you want to use image uploads under safe mode,
 211+## create the directories images/archive, images/thumb and
 212+## images/temp, and make them all writable. Then uncomment
 213+## this, if it's not already uncommented:
 214+{$hashedUploads}\$wgHashedUploadDirectory = false;
 215+
 216+## If you have the appropriate support software installed
 217+## you can enable inline LaTeX equations:
 218+\$wgUseTeX = false;
 219+
 220+## Set \$wgCacheDirectory to a writable directory on the web server
 221+## to make your wiki go slightly faster. The directory should not
 222+## be publically accessible from the web.
 223+#\$wgCacheDirectory = \"\$IP/cache\";
 224+
 225+\$wgLocalInterwiki = strtolower( \$wgSitename );
 226+
 227+\$wgLanguageCode = \"{$this->values['wgLanguageCode']}\";
 228+
 229+\$wgSecretKey = \"{$this->values['wgSecretKey']}\";
 230+
 231+## Default skin: you can change the default skin. Use the internal symbolic
 232+## names, ie 'standard', 'nostalgia', 'cologneblue', 'monobook':
 233+\$wgDefaultSkin = 'monobook';
 234+
 235+## For attaching licensing metadata to pages, and displaying an
 236+## appropriate copyright notice / icon. GNU Free Documentation
 237+## License and Creative Commons licenses are supported so far.
 238+{$rights}\$wgEnableCreativeCommonsRdf = true;
 239+\$wgRightsPage = \"\"; # Set to the title of a wiki page that describes your license/copyright
 240+\$wgRightsUrl = \"{$this->values['wgRightsUrl']}\";
 241+\$wgRightsText = \"{$this->values['wgRightsText']}\";
 242+\$wgRightsIcon = \"{$this->values['wgRightsIcon']}\";
 243+# \$wgRightsCode = \"{$this->values['wgRightsCode']}\"; # Not yet used
 244+
 245+\$wgDiff3 = \"{$this->values['wgDiff3']}\";
 246+
 247+# When you make changes to this configuration file, this will make
 248+# sure that cached pages are cleared.
 249+\$wgCacheEpoch = max( \$wgCacheEpoch, gmdate( 'YmdHis', @filemtime( __FILE__ ) ) );
 250+";
 251+ }
 252+}
\ No newline at end of file
Property changes on: trunk/phase3/includes/installer/LocalSettingsGenerator.php
___________________________________________________________________
Added: svn:eol-style
1253 + native
Index: trunk/phase3/includes/installer/MysqlInstaller.php
@@ -0,0 +1,414 @@
 2+<?php
 3+
 4+class MysqlInstaller extends InstallerDBType {
 5+ protected $globalNames = array(
 6+ 'wgDBserver',
 7+ 'wgDBname',
 8+ 'wgDBuser',
 9+ 'wgDBpassword',
 10+ 'wgDBprefix',
 11+ 'wgDBTableOptions',
 12+ 'wgDBmysql5',
 13+ );
 14+
 15+ protected $internalDefaults = array(
 16+ '_MysqlEngine' => 'InnoDB',
 17+ '_MysqlCharset' => 'binary',
 18+ );
 19+
 20+ var $supportedEngines = array( 'InnoDB', 'MyISAM' );
 21+
 22+ var $minimumVersion = '4.0.14';
 23+
 24+ var $webUserPrivs = array(
 25+ 'DELETE',
 26+ 'INSERT',
 27+ 'SELECT',
 28+ 'UPDATE',
 29+ 'CREATE TEMPORARY TABLES',
 30+ );
 31+
 32+ function getName() {
 33+ return 'mysql';
 34+ }
 35+
 36+ function isCompiled() {
 37+ return $this->checkExtension( 'mysql' );
 38+ }
 39+
 40+ function getGlobalDefaults() {
 41+ return array();
 42+ }
 43+
 44+ function getConnectForm() {
 45+ return
 46+ $this->getTextBox( 'wgDBserver', 'config-db-host' ) .
 47+ $this->parent->getHelpBox( 'config-db-host-help' ) .
 48+ Xml::openElement( 'fieldset' ) .
 49+ Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
 50+ $this->getTextBox( 'wgDBname', 'config-db-name' ) .
 51+ $this->parent->getHelpBox( 'config-db-name-help' ) .
 52+ $this->getTextBox( 'wgDBprefix', 'config-db-prefix' ) .
 53+ $this->parent->getHelpBox( 'config-db-prefix-help' ) .
 54+ Xml::closeElement( 'fieldset' ) .
 55+ $this->getInstallUserBox();
 56+ }
 57+
 58+ function submitConnectForm() {
 59+ // Get variables from the request
 60+ $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBname', 'wgDBprefix' ) );
 61+
 62+ // Validate them
 63+ $status = Status::newGood();
 64+ if ( !strlen( $newValues['wgDBname'] ) ) {
 65+ $status->fatal( 'config-missing-db-name' );
 66+ } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) {
 67+ $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] );
 68+ }
 69+ if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBprefix'] ) ) {
 70+ $status->fatal( 'config-invalid-db-prefix', $newValues['wgDBprefix'] );
 71+ }
 72+ if ( !$status->isOK() ) {
 73+ return $status;
 74+ }
 75+
 76+ // Submit user box
 77+ $status = $this->submitInstallUserBox();
 78+ if ( !$status->isOK() ) {
 79+ return $status;
 80+ }
 81+
 82+ // Try to connect
 83+ $status = $this->getConnection();
 84+ if ( !$status->isOK() ) {
 85+ return $status;
 86+ }
 87+ $conn = $status->value;
 88+
 89+ // Check version
 90+ $version = $conn->getServerVersion();
 91+ if ( version_compare( $version, $this->minimumVersion ) < 0 ) {
 92+ return Status::newFatal( 'config-mysql-old', $this->minimumVersion, $version );
 93+ }
 94+
 95+ return $status;
 96+ }
 97+
 98+ function getConnection() {
 99+ $status = Status::newGood();
 100+ try {
 101+ $this->db = new DatabaseMysql(
 102+ $this->getVar( 'wgDBserver' ),
 103+ $this->getVar( '_InstallUser' ),
 104+ $this->getVar( '_InstallPassword' ),
 105+ false,
 106+ false,
 107+ 0,
 108+ $this->getVar( 'wgDBprefix' )
 109+ );
 110+ $status->value = $this->db;
 111+ return $status;
 112+ } catch ( DBConnectionError $e ) {
 113+ $status->fatal( 'config-connection-error', $e->getMessage() );
 114+ }
 115+ return $status;
 116+ }
 117+
 118+ function doUpgrade() {
 119+ $status = $this->getConnection();
 120+ if ( !$status->isOK() ) {
 121+ $this->parent->showStatusError( $status );
 122+ return;
 123+ }
 124+ $conn = $status->value;
 125+
 126+ # Determine existing default character set
 127+ if ( $conn->tableExists( "revision" ) ) {
 128+ $revision = $conn->escapeLike( $this->getVar( 'wgDBprefix' ) . 'revision' );
 129+ $res = $conn->query( "SHOW TABLE STATUS LIKE '$revision'" );
 130+ $row = $conn->fetchObject( $res );
 131+ if ( !$row ) {
 132+ $this->parent->showMessage( 'config-show-table-status' );
 133+ $existingSchema = false;
 134+ $existingEngine = false;
 135+ } else {
 136+ if ( preg_match( '/^latin1/', $row->Collation ) ) {
 137+ $existingSchema = 'mysql4';
 138+ } elseif ( preg_match( '/^utf8/', $row->Collation ) ) {
 139+ $existingSchema = 'mysql5';
 140+ } elseif ( preg_match( '/^binary/', $row->Collation ) ) {
 141+ $existingSchema = 'mysql5-binary';
 142+ } else {
 143+ $existingSchema = false;
 144+ $this->parent->showMessage( 'config-unknown-collation' );
 145+ }
 146+ if ( isset( $row->Engine ) ) {
 147+ $existingEngine = $row->Engine;
 148+ } else {
 149+ $existingEngine = $row->Type;
 150+ }
 151+ }
 152+ }
 153+
 154+ // TODO
 155+ }
 156+
 157+ /**
 158+ * Get a list of storage engines that are available and supported
 159+ */
 160+ function getEngines() {
 161+ $engines = array( 'InnoDB', 'MyISAM' );
 162+ $status = $this->getConnection();
 163+ if ( !$status->isOK() ) {
 164+ return $engines;
 165+ }
 166+ $conn = $status->value;
 167+
 168+ $version = $conn->getServerVersion();
 169+ if ( version_compare( $version, "4.1.2", "<" ) ) {
 170+ // No SHOW ENGINES in this version
 171+ return $engines;
 172+ }
 173+
 174+ $engines = array();
 175+ $res = $conn->query( 'SHOW ENGINES' );
 176+ foreach ( $res as $row ) {
 177+ if ( $row->Support == 'YES' || $row->Support == 'DEFAULT' ) {
 178+ $engines[] = $row->Engine;
 179+ }
 180+ }
 181+ $engines = array_intersect( $this->supportedEngines, $engines );
 182+ return $engines;
 183+ }
 184+
 185+ /**
 186+ * Get a list of character sets that are available and supported
 187+ */
 188+ function getCharsets() {
 189+ $status = $this->getConnection();
 190+ $mysql5 = array( 'binary', 'utf8' );
 191+ $mysql4 = array( 'mysql4' );
 192+ if ( !$status->isOK() ) {
 193+ return $mysql5;
 194+ }
 195+ if ( version_compare( $status->value->getServerVersion(), '4.1.0', '>=' ) ) {
 196+ return $mysql5;
 197+ }
 198+ return $mysql4;
 199+ }
 200+
 201+ /**
 202+ * Return true if the install user can create accounts
 203+ */
 204+ function canCreateAccounts() {
 205+ $status = $this->getConnection();
 206+ if ( !$status->isOK() ) {
 207+ return false;
 208+ }
 209+ $conn = $status->value;
 210+
 211+ // Check version, need INFORMATION_SCHEMA and CREATE USER
 212+ if ( version_compare( $conn->getServerVersion(), '5.0.2', '<' ) ) {
 213+ return false;
 214+ }
 215+
 216+ // Get current account name
 217+ $currentName = $conn->selectField( '', 'CURRENT_USER()', '', __METHOD__ );
 218+ $parts = explode( '@', $currentName );
 219+ if ( count( $parts ) != 2 ) {
 220+ return false;
 221+ }
 222+ $quotedUser = $conn->addQuotes( $parts[0] ) .
 223+ '@' . $conn->addQuotes( $parts[1] );
 224+
 225+ // The user needs to have INSERT on mysql.* to be able to CREATE USER
 226+ // The grantee will be double-quoted in this query, as required
 227+ $res = $conn->select( 'INFORMATION_SCHEMA.USER_PRIVILEGES', '*',
 228+ array( 'GRANTEE' => $quotedUser ), __METHOD__ );
 229+ $insertMysql = false;
 230+ $grantOptions = array_flip( $this->webUserPrivs );
 231+ foreach ( $res as $row ) {
 232+ if ( $row->PRIVILEGE_TYPE == 'INSERT' ) {
 233+ $insertMysql = true;
 234+ }
 235+ if ( $row->IS_GRANTABLE ) {
 236+ unset( $grantOptions[$row->PRIVILEGE_TYPE] );
 237+ }
 238+ }
 239+
 240+ // Check for DB-specific privs for mysql.*
 241+ if ( !$insertMysql ) {
 242+ $row = $conn->selectRow( 'INFORMATION_SCHEMA.SCHEMA_PRIVILEGES', '*',
 243+ array(
 244+ 'GRANTEE' => $quotedUser,
 245+ 'TABLE_SCHEMA' => 'mysql',
 246+ 'PRIVILEGE_TYPE' => 'INSERT',
 247+ ), __METHOD__ );
 248+ if ( $row ) {
 249+ $insertMysql = true;
 250+ }
 251+ }
 252+
 253+ if ( !$insertMysql ) {
 254+ return false;
 255+ }
 256+
 257+ // Check for DB-level grant options
 258+ $res = $conn->select( 'INFORMATION_SCHEMA.SCHEMA_PRIVILEGES', '*',
 259+ array(
 260+ 'GRANTEE' => $quotedUser,
 261+ 'IS_GRANTABLE' => 1,
 262+ ), __METHOD__ );
 263+ foreach ( $res as $row ) {
 264+ $regex = $conn->likeToRegex( $row->TABLE_SCHEMA );
 265+ if ( preg_match( $regex, $this->getVar( 'wgDBname' ) ) ) {
 266+ unset( $grantOptions[$row->PRIVILEGE_TYPE] );
 267+ }
 268+ }
 269+ if ( count( $grantOptions ) ) {
 270+ // Can't grant everything
 271+ return false;
 272+ }
 273+ return true;
 274+ }
 275+
 276+ function getSettingsForm() {
 277+ if ( $this->canCreateAccounts() ) {
 278+ $noCreateMsg = false;
 279+ } else {
 280+ $noCreateMsg = 'config-db-web-no-create-privs';
 281+ }
 282+ $s = $this->getWebUserBox( $noCreateMsg );
 283+
 284+ // Do engine selector
 285+ $engines = $this->getEngines();
 286+ // If the current default engine is not supported, use an engine that is
 287+ if ( !in_array( $this->getVar( '_MysqlEngine' ), $engines ) ) {
 288+ $this->setVar( '_MysqlEngine', reset( $engines ) );
 289+ }
 290+ if ( count( $engines ) >= 2 ) {
 291+ $s .= $this->getRadioSet( array(
 292+ 'var' => '_MysqlEngine',
 293+ 'label' => 'config-mysql-engine',
 294+ 'itemLabelPrefix' => 'config-mysql-',
 295+ 'values' => $engines
 296+ ));
 297+ $s .= $this->parent->getHelpBox( 'config-mysql-engine-help' );
 298+ }
 299+
 300+ // If the current default charset is not supported, use a charset that is
 301+ $charsets = $this->getCharsets();
 302+ if ( !in_array( $this->getVar( '_MysqlCharset' ), $charsets ) ) {
 303+ $this->setVar( '_MysqlCharset', reset( $charsets ) );
 304+ }
 305+
 306+ // Do charset selector
 307+ if ( count( $charsets ) >= 2 ) {
 308+ $s .= $this->getRadioSet( array(
 309+ 'var' => '_MysqlCharset',
 310+ 'label' => 'config-mysql-charset',
 311+ 'itemLabelPrefix' => 'config-mysql-',
 312+ 'values' => $charsets
 313+ ));
 314+ $s .= $this->parent->getHelpBox( 'config-mysql-charset-help' );
 315+ }
 316+
 317+ return $s;
 318+ }
 319+
 320+ function submitSettingsForm() {
 321+ $newValues = $this->setVarsFromRequest( array( '_MysqlEngine', '_MysqlCharset' ) );
 322+ $status = $this->submitWebUserBox();
 323+ if ( !$status->isOK() ) {
 324+ return $status;
 325+ }
 326+
 327+ // Validate the create checkbox
 328+ $canCreate = $this->canCreateAccounts();
 329+ if ( !$canCreate ) {
 330+ $this->setVar( '_CreateDBAccount', false );
 331+ $create = false;
 332+ } else {
 333+ $create = $this->getVar( '_CreateDBAccount' );
 334+ }
 335+
 336+ if ( !$create ) {
 337+ // Test the web account
 338+ try {
 339+ $webConn = new Database(
 340+ $this->getVar( 'wgDBserver' ),
 341+ $this->getVar( 'wgDBuser' ),
 342+ $this->getVar( 'wgDBpassword' ),
 343+ false,
 344+ false,
 345+ 0,
 346+ $this->getVar( 'wgDBprefix' )
 347+ );
 348+ } catch ( DBConnectionError $e ) {
 349+ return Status::newFatal( 'config-connection-error', $e->getMessage() );
 350+ }
 351+ }
 352+
 353+ // Validate engines and charsets
 354+ // This is done pre-submit already so it's just for security
 355+ $engines = $this->getEngines();
 356+ if ( !in_array( $this->getVar( '_MysqlEngine' ), $engines ) ) {
 357+ $this->setVar( '_MysqlEngine', reset( $engines ) );
 358+ }
 359+ $charsets = $this->getCharsets();
 360+ if ( !in_array( $this->getVar( '_MysqlCharset' ), $charsets ) ) {
 361+ $this->setVar( '_MysqlCharset', reset( $charsets ) );
 362+ }
 363+ return Status::newGood();
 364+ }
 365+
 366+ function setupDatabase() {
 367+ $status = $this->getConnection();
 368+ if ( !$status->isOK() ) {
 369+ return $status;
 370+ }
 371+ $conn = $status->value;
 372+ $dbName = $this->getVar( 'wgDBname' );
 373+ if( !$conn->selectDB( $dbName ) ) {
 374+ $conn->query( "CREATE DATABASE `$dbName`" );
 375+ $conn->selectDB( $dbName );
 376+ }
 377+ return $status;
 378+ }
 379+
 380+ function createTables() {
 381+ global $IP;
 382+ $status = $this->getConnection();
 383+ if ( !$status->isOK() ) {
 384+ return $status;
 385+ }
 386+ $this->db->selectDB( $this->getVar( 'wgDBname' ) );
 387+ if ( !$this->db->sourceFile( "$IP/maintenance/tables.sql" )
 388+ || !$this->db->sourceFile( "$IP/maintenance/interwiki.sql" ) )
 389+ {
 390+ //@todo
 391+ }
 392+ return Status::newGood();
 393+ }
 394+
 395+ function getTableOptions() {
 396+ return array( 'engine' => $this->getVar( '_MysqlEngine' ),
 397+ 'default charset' => $this->getVar( '_MysqlCharset' ) );
 398+ }
 399+
 400+ function getLocalSettings() {
 401+ $dbmysql5 = wfBoolToStr( $this->getVar( 'wgDBmysql5', true ) );
 402+ $prefix = $this->getVar( 'wgDBprefix' );
 403+ $opts = $this->getTableOptions();
 404+ $tblOpts = "ENGINE=" . $opts['engine'] . ', DEFAULT CHARSET=' . $opts['default charset'];
 405+ return
 406+"# MySQL specific settings
 407+\$wgDBprefix = \"{$prefix}\";
 408+
 409+# MySQL table options to use during installation or update
 410+\$wgDBTableOptions = \"{$tblOpts}\";
 411+
 412+# Experimental charset support for MySQL 4.1/5.0.
 413+\$wgDBmysql5 = {$dbmysql5};";
 414+ }
 415+}
Property changes on: trunk/phase3/includes/installer/MysqlInstaller.php
___________________________________________________________________
Added: svn:eol-style
1416 + native
Index: trunk/phase3/includes/installer/OracleInstaller.php
@@ -0,0 +1,96 @@
 2+<?php
 3+
 4+class OracleInstaller extends InstallerDBType {
 5+
 6+ protected $globalNames = array(
 7+ 'wgDBport',
 8+ 'wgDBname',
 9+ 'wgDBuser',
 10+ 'wgDBpassword',
 11+ 'wgDBprefix',
 12+ );
 13+
 14+ protected $internalDefaults = array(
 15+ '_InstallUser' => 'sys',
 16+ '_InstallPassword' => '',
 17+ );
 18+
 19+ function getName() {
 20+ return 'oracle';
 21+ }
 22+
 23+ function isCompiled() {
 24+ return $this->checkExtension( 'oci8' );
 25+ }
 26+
 27+ function getConnectForm() {
 28+ return
 29+ Xml::openElement( 'fieldset' ) .
 30+ Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
 31+ $this->getTextBox( 'wgDBname', 'config-db-name' ) .
 32+ $this->parent->getHelpBox( 'config-db-name-help' ) .
 33+ $this->getTextBox( 'wgDBprefix', 'config-db-prefix' ) .
 34+ $this->parent->getHelpBox( 'config-db-prefix-help' ) .
 35+ Xml::closeElement( 'fieldset' ) .
 36+ $this->getInstallUserBox();
 37+ }
 38+
 39+ function submitConnectForm() {
 40+ // Get variables from the request
 41+ $newValues = $this->setVarsFromRequest( array( 'wgDBname', 'wgDBprefix' ) );
 42+
 43+ // Validate them
 44+ $status = Status::newGood();
 45+ if ( !strlen( $newValues['wgDBname'] ) ) {
 46+ $status->fatal( 'config-missing-db-name' );
 47+ } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) {
 48+ $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] );
 49+ }
 50+ if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBprefix'] ) ) {
 51+ $status->fatal( 'config-invalid-schema', $newValues['wgDBprefix'] );
 52+ }
 53+
 54+ // Submit user box
 55+ if ( $status->isOK() ) {
 56+ $status->merge( $this->submitInstallUserBox() );
 57+ }
 58+ if ( !$status->isOK() ) {
 59+ return $status;
 60+ }
 61+
 62+ // Try to connect
 63+ if ( $status->isOK() ) {
 64+ $status->merge( $this->attemptConnection() );
 65+ }
 66+ if ( !$status->isOK() ) {
 67+ return $status;
 68+ }
 69+
 70+ // Check version
 71+/*
 72+ $version = $this->conn->getServerVersion();
 73+ if ( version_compare( $version, $this->minimumVersion ) < 0 ) {
 74+ return Status::newFatal( 'config-postgres-old', $this->minimumVersion, $version );
 75+ }
 76+*/
 77+ return $status;
 78+ }
 79+
 80+
 81+ function getSettingsForm() {}
 82+
 83+ function submitSettingsForm() {}
 84+
 85+ function getConnection() {}
 86+
 87+ function setupDatabase() {}
 88+
 89+ function createTables() {}
 90+
 91+ function getLocalSettings() {
 92+ $prefix = $this->getVar( 'wgDBprefix' );
 93+ return
 94+"# Oracle specific settings
 95+\$wgDBprefix = \"{$prefix}\";";
 96+ }
 97+}
Property changes on: trunk/phase3/includes/installer/OracleInstaller.php
___________________________________________________________________
Added: svn:eol-style
198 + native
Index: trunk/phase3/includes/installer/PostgresInstaller.php
@@ -0,0 +1,135 @@
 2+<?php
 3+
 4+class PostgresInstaller extends InstallerDBType {
 5+
 6+ protected $globalNames = array(
 7+ 'wgDBserver',
 8+ 'wgDBport',
 9+ 'wgDBname',
 10+ 'wgDBuser',
 11+ 'wgDBpassword',
 12+ 'wgDBmwschema',
 13+ 'wgDBts2schema',
 14+ );
 15+
 16+ protected $internalDefaults = array(
 17+ '_InstallUser' => 'postgres',
 18+ '_InstallPassword' => '',
 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 getConnectForm() {
 34+ return
 35+ $this->getTextBox( 'wgDBserver', 'config-db-host' ) .
 36+ $this->parent->getHelpBox( 'config-db-host-help' ) .
 37+ $this->getTextBox( 'wgDBport', 'config-db-port' ) .
 38+ Xml::openElement( 'fieldset' ) .
 39+ Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
 40+ $this->getTextBox( 'wgDBname', 'config-db-name' ) .
 41+ $this->parent->getHelpBox( 'config-db-name-help' ) .
 42+ $this->getTextBox( 'wgDBmwschema', 'config-db-schema' ) .
 43+ $this->getTextBox( 'wgDBts2schema', 'config-db-ts2-schema' ) .
 44+ $this->parent->getHelpBox( 'config-db-schema-help' ) .
 45+ Xml::closeElement( 'fieldset' ) .
 46+ $this->getInstallUserBox();
 47+ }
 48+
 49+ function submitConnectForm() {
 50+ // Get variables from the request
 51+ $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBport',
 52+ 'wgDBname', 'wgDBmwschema', 'wgDBts2schema' ) );
 53+
 54+ // Validate them
 55+ $status = Status::newGood();
 56+ if ( !strlen( $newValues['wgDBname'] ) ) {
 57+ $status->fatal( 'config-missing-db-name' );
 58+ } elseif ( !preg_match( '/^[a-zA-Z0-9_]+$/', $newValues['wgDBname'] ) ) {
 59+ $status->fatal( 'config-invalid-db-name', $newValues['wgDBname'] );
 60+ }
 61+ if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBmwschema'] ) ) {
 62+ $status->fatal( 'config-invalid-schema', $newValues['wgDBmwschema'] );
 63+ }
 64+ if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBts2schema'] ) ) {
 65+ $status->fatal( 'config-invalid-ts2schema', $newValues['wgDBts2schema'] );
 66+ }
 67+
 68+ // Submit user box
 69+ if ( $status->isOK() ) {
 70+ $status->merge( $this->submitInstallUserBox() );
 71+ }
 72+ if ( !$status->isOK() ) {
 73+ return $status;
 74+ }
 75+
 76+ // Try to connect
 77+ if ( $status->isOK() ) {
 78+ $status->merge( $this->attemptConnection() );
 79+ }
 80+ if ( !$status->isOK() ) {
 81+ return $status;
 82+ }
 83+
 84+ // Check version
 85+ $version = $this->conn->getServerVersion();
 86+ if ( version_compare( $version, $this->minimumVersion ) < 0 ) {
 87+ return Status::newFatal( 'config-postgres-old', $this->minimumVersion, $version );
 88+ }
 89+ return $status;
 90+ }
 91+
 92+ function attemptConnection() {
 93+ $status = Status::newGood();
 94+
 95+ try {
 96+ $this->conn = new DatabasePostgres(
 97+ $this->getVar( 'wgDBserver' ),
 98+ $this->getVar( '_InstallUser' ),
 99+ $this->getVar( '_InstallPassword' ),
 100+ 'postgres' );
 101+ $status->value = $this->conn;
 102+ } catch ( DBConnectionError $e ) {
 103+ $status->fatal( 'config-connection-error', $e->getMessage() );
 104+ }
 105+ return $status;
 106+ }
 107+
 108+ function getConnection() {
 109+ return $this->attemptConnection();
 110+ }
 111+
 112+ function getSettingsForm() {
 113+ return false;
 114+ }
 115+
 116+ function submitSettingsForm() {
 117+ return Status::newGood();
 118+ }
 119+
 120+ function setupDatabase() {
 121+ }
 122+
 123+ function createTables() {
 124+ }
 125+
 126+ function getLocalSettings() {
 127+ $port = $this->getVar( 'wgDBport' );
 128+ $schema = $this->getVar( 'wgDBmwschema' );
 129+ $ts2 = $this->getVar( 'wgDBts2schema' );
 130+ return
 131+"# Postgres specific settings
 132+\$wgDBport = \"{$port}\";
 133+\$wgDBmwschema = \"{$schema}\";
 134+\$wgDBts2schema = \"{$ts2}\";";
 135+ }
 136+}
Property changes on: trunk/phase3/includes/installer/PostgresInstaller.php
___________________________________________________________________
Added: svn:eol-style
1137 + native
Index: trunk/phase3/includes/installer/InstallerDBType.php
@@ -0,0 +1,359 @@
 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+ /* Database connection */
 12+ var $db;
 13+
 14+ /** Internal variables for installation */
 15+ protected $internalDefaults = array();
 16+
 17+ /** Array of MW configuration globals this class uses */
 18+ protected $globalNames = array();
 19+
 20+ /**
 21+ * Return the internal name, e.g. 'mysql', or 'sqlite'
 22+ */
 23+ abstract function getName();
 24+
 25+ /**
 26+ * @return true if the client library is compiled in
 27+ */
 28+ abstract function isCompiled();
 29+
 30+ /**
 31+ * Get an array of MW configuration globals that will be configured by this class.
 32+ */
 33+ public function getGlobalNames() {
 34+ return $this->globalNames;
 35+ }
 36+
 37+ /**
 38+ * Get HTML for a web form that configures this database. Configuration
 39+ * at this time should be the minimum needed to connect and test
 40+ * whether install or upgrade is required.
 41+ *
 42+ * If this is called, $this->parent can be assumed to be a WebInstaller
 43+ */
 44+ abstract function getConnectForm();
 45+
 46+ /**
 47+ * Set variables based on the request array, assuming it was submitted
 48+ * via the form returned by getConnectForm(). Validate the connection
 49+ * settings by attempting to connect with them.
 50+ *
 51+ * If this is called, $this->parent can be assumed to be a WebInstaller
 52+ *
 53+ * @return Status
 54+ */
 55+ abstract function submitConnectForm();
 56+
 57+ /**
 58+ * Get HTML for a web form that retrieves settings used for installation.
 59+ * $this->parent can be assumed to be a WebInstaller.
 60+ * If the DB type has no settings beyond those already configured with
 61+ * getConnectForm(), this should return false.
 62+ */
 63+ abstract function getSettingsForm();
 64+
 65+ /**
 66+ * Set variables based on the request array, assuming it was submitted via
 67+ * the form return by getSettingsForm().
 68+ * @return Status
 69+ */
 70+ abstract function submitSettingsForm();
 71+
 72+ /**
 73+ * Connect to the database using the administrative user/password currently
 74+ * defined in the session. On success, return the connection, on failure,
 75+ * return a Status object.
 76+ *
 77+ * This may be called multiple times, so the result should be cached.
 78+ */
 79+ abstract function getConnection();
 80+
 81+ /**
 82+ * Create the database and return a Status object indicating success or
 83+ * failure.
 84+ *
 85+ * @return Status
 86+ */
 87+ abstract function setupDatabase();
 88+
 89+ /**
 90+ * Create database tables from scratch
 91+ * @return \type Status
 92+ */
 93+ abstract function createTables();
 94+
 95+ /**
 96+ * Perform database upgrades
 97+ * @todo make abstract
 98+ */
 99+ /*abstract*/ function doUpgrade() {
 100+ return false;
 101+ }
 102+
 103+ /**
 104+ * Return any table options to be applied to all tables that don't
 105+ * override them
 106+ * @return Array
 107+ */
 108+ function getTableOptions() {
 109+ return array();
 110+ }
 111+
 112+ /**
 113+ * Get the DBMS-specific options for LocalSettings.php generation.
 114+ * @return String
 115+ */
 116+ abstract function getLocalSettings();
 117+
 118+ /**
 119+ * Construct and initialise parent.
 120+ * This is typically only called from Installer::getDBInstaller()
 121+ */
 122+ function __construct( $parent ) {
 123+ $this->parent = $parent;
 124+ }
 125+
 126+ /**
 127+ * Convenience function
 128+ * Check if a named extension is present
 129+ */
 130+ function checkExtension( $name ) {
 131+ wfSuppressWarnings();
 132+ $compiled = extension_loaded( $name )
 133+ || ( $this->parent->haveDl() && dl( $name . '.' . PHP_SHLIB_SUFFIX ) );
 134+ wfRestoreWarnings();
 135+ return $compiled;
 136+ }
 137+
 138+ /**
 139+ * Get the internationalised name for this DBMS
 140+ */
 141+ function getReadableName() {
 142+ return wfMsg( 'config-type-' . $this->getName() );
 143+ }
 144+
 145+ /**
 146+ * Get a name=>value map of MW configuration globals that overrides
 147+ * DefaultSettings.php
 148+ */
 149+ function getGlobalDefaults() {
 150+ return array();
 151+ }
 152+
 153+ /**
 154+ * Get a name=>value map of internal variables used during installation
 155+ */
 156+ public function getInternalDefaults() {
 157+ return $this->internalDefaults;
 158+ }
 159+
 160+ /**
 161+ * Get a variable, taking local defaults into account
 162+ */
 163+ function getVar( $var, $default = null ) {
 164+ $defaults = $this->getGlobalDefaults();
 165+ $internal = $this->getInternalDefaults();
 166+ if ( isset( $defaults[$var] ) ) {
 167+ $default = $defaults[$var];
 168+ } elseif ( isset( $internal[$var] ) ) {
 169+ $default = $internal[$var];
 170+ }
 171+ return $this->parent->getVar( $var, $default );
 172+ }
 173+
 174+ /**
 175+ * Convenience alias for $this->parent->setVar()
 176+ */
 177+ function setVar( $name, $value ) {
 178+ $this->parent->setVar( $name, $value );
 179+ }
 180+
 181+ /**
 182+ * Get a labelled text box to configure a local variable
 183+ */
 184+ function getTextBox( $var, $label, $attribs = array() ) {
 185+ $name = $this->getName() . '_' . $var;
 186+ $value = $this->getVar( $var );
 187+ return $this->parent->getTextBox( array(
 188+ 'var' => $var,
 189+ 'label' => $label,
 190+ 'attribs' => $attribs,
 191+ 'controlName' => $name,
 192+ 'value' => $value
 193+ ) );
 194+ }
 195+
 196+ /**
 197+ * Get a labelled password box to configure a local variable
 198+ * Implements password hiding
 199+ */
 200+ function getPasswordBox( $var, $label, $attribs = array() ) {
 201+ $name = $this->getName() . '_' . $var;
 202+ $value = $this->getVar( $var );
 203+ return $this->parent->getPasswordBox( array(
 204+ 'var' => $var,
 205+ 'label' => $label,
 206+ 'attribs' => $attribs,
 207+ 'controlName' => $name,
 208+ 'value' => $value
 209+ ) );
 210+ }
 211+
 212+ /**
 213+ * Get a labelled checkbox to configure a local boolean variable
 214+ */
 215+ function getCheckBox( $var, $label, $attribs = array() ) {
 216+ $name = $this->getName() . '_' . $var;
 217+ $value = $this->getVar( $var );
 218+ return $this->parent->getCheckBox( array(
 219+ 'var' => $var,
 220+ 'label' => $label,
 221+ 'attribs' => $attribs,
 222+ 'controlName' => $name,
 223+ 'value' => $value,
 224+ ));
 225+ }
 226+
 227+ /**
 228+ * Get a set of labelled radio buttons
 229+ *
 230+ * @param array $params
 231+ * Parameters are:
 232+ * var: The variable to be configured (required)
 233+ * label: The message name for the label (required)
 234+ * itemLabelPrefix: The message name prefix for the item labels (required)
 235+ * values: List of allowed values (required)
 236+ * itemAttribs Array of attribute arrays, outer key is the value name (optional)
 237+ *
 238+ */
 239+ function getRadioSet( $params ) {
 240+ $params['controlName'] = $this->getName() . '_' . $params['var'];
 241+ $params['value'] = $this->getVar( $params['var'] );
 242+ return $this->parent->getRadioSet( $params );
 243+ }
 244+
 245+ /**
 246+ * Convenience function to set variables based on form data.
 247+ * Assumes that variables containing "password" in the name are (potentially
 248+ * fake) passwords.
 249+ * @param array $varNames
 250+ */
 251+ function setVarsFromRequest( $varNames ) {
 252+ return $this->parent->setVarsFromRequest( $varNames, $this->getName() . '_' );
 253+ }
 254+
 255+ /**
 256+ * Determine whether an existing installation of MediaWiki is present in
 257+ * the configured administrative connection. Returns true if there is
 258+ * such a wiki, false if the database doesn't exist.
 259+ *
 260+ * Traditionally, this is done by testing for the existence of either
 261+ * the revision table or the cur table.
 262+ *
 263+ * @return boolean
 264+ */
 265+ function needsUpgrade() {
 266+ $status = $this->getConnection();
 267+ if ( !$status->isOK() ) {
 268+ return false;
 269+ }
 270+ $conn = $status->value;
 271+ if ( !$conn->selectDB( $this->getVar( 'wgDBname' ) ) ) {
 272+ return false;
 273+ }
 274+ return $conn->tableExists( 'cur' ) || $conn->tableExists( 'revision' );
 275+ }
 276+
 277+ /**
 278+ * Get a standard install-user fieldset
 279+ */
 280+ function getInstallUserBox() {
 281+ return
 282+ Xml::openElement( 'fieldset' ) .
 283+ Xml::element( 'legend', array(), wfMsg( 'config-db-install-account' ) ) .
 284+ $this->getTextBox( '_InstallUser', 'config-db-username' ) .
 285+ $this->getPasswordBox( '_InstallPassword', 'config-db-password' ) .
 286+ $this->parent->getHelpBox( 'config-db-install-help' ) .
 287+ Xml::closeElement( 'fieldset' );
 288+ }
 289+
 290+ /**
 291+ * Submit a standard install user fieldset
 292+ */
 293+ function submitInstallUserBox() {
 294+ $this->setVarsFromRequest( array( '_InstallUser', '_InstallPassword' ) );
 295+ return Status::newGood();
 296+ }
 297+
 298+ /**
 299+ * Get a standard web-user fieldset
 300+ * @param string $noCreateMsg Message to display instead of the creation checkbox.
 301+ * Set this to false to show a creation checkbox.
 302+ */
 303+ function getWebUserBox( $noCreateMsg = false ) {
 304+ $name = $this->getName();
 305+ $s = Xml::openElement( 'fieldset' ) .
 306+ Xml::element( 'legend', array(), wfMsg( 'config-db-web-account' ) ) .
 307+ $this->getCheckBox(
 308+ '_SameAccount', 'config-db-web-account-same',
 309+ array( 'class' => 'hideShowRadio', 'rel' => 'dbOtherAccount' )
 310+ ) .
 311+ Xml::openElement( 'div', array( 'id' => 'dbOtherAccount', 'style' => 'display: none;' ) ) .
 312+ $this->getTextBox( 'wgDBuser', 'config-db-username' ) .
 313+ $this->getPasswordBox( 'wgDBpassword', 'config-db-password' ) .
 314+ $this->parent->getHelpBox( 'config-db-web-help' );
 315+ if ( $noCreateMsg ) {
 316+ $s .= $this->parent->getWarningBox( wfMsgNoTrans( $noCreateMsg ) );
 317+ } else {
 318+ $s .= $this->getCheckBox( '_CreateDBAccount', 'config-db-web-create' );
 319+ }
 320+ $s .= Xml::closeElement( 'div' ) . Xml::closeElement( 'fieldset' );
 321+ return $s;
 322+ }
 323+
 324+ /**
 325+ * Submit the form from getWebUserBox().
 326+ * @return Status
 327+ */
 328+ function submitWebUserBox() {
 329+ $this->setVarsFromRequest( array( 'wgDBuser', 'wgDBpassword',
 330+ '_SameAccount', '_CreateDBAccount' ) );
 331+ if ( $this->getVar( '_SameAccount' ) ) {
 332+ $this->setVar( 'wgDBuser', $this->getVar( '_InstallUser' ) );
 333+ $this->setVar( 'wgDBpassword', $this->getVar( '_InstallPassword' ) );
 334+ }
 335+ return Status::newGood();
 336+ }
 337+
 338+ /**
 339+ * Common function for databases that don't understand the MySQLish syntax of interwiki.sql
 340+ */
 341+ protected function populateInterwikiTable( $db ) {
 342+ global $IP;
 343+ // Originally from DatabasePostgres
 344+ $f = fopen( "$IP/maintenance/interwiki.sql", 'r' );
 345+ if ( $f == false ) {
 346+ return Status::newFatal( 'config-install-interwiki-sql' );
 347+ }
 348+ $table = $db->tableName( 'interwiki' );
 349+ $sql = "INSERT INTO $table(iw_prefix,iw_url,iw_local) VALUES ";
 350+ while ( !feof( $f ) ) {
 351+ $line = fgets( $f, 1024 );
 352+ $matches = array();
 353+ if ( !preg_match( '/^\s*(\(.+?),(\d)\)/', $line, $matches ) ) continue;
 354+ $db->query( "$sql $matches[1],$matches[2])" );
 355+ }
 356+ return Status::newGood();
 357+ }
 358+
 359+}
 360+
Property changes on: trunk/phase3/includes/installer/InstallerDBType.php
___________________________________________________________________
Added: svn:eol-style
1361 + native
Index: trunk/phase3/includes/AutoLoader.php
@@ -422,6 +422,18 @@
423423 'RepoGroup' => 'includes/filerepo/RepoGroup.php',
424424 'UnregisteredLocalFile' => 'includes/filerepo/UnregisteredLocalFile.php',
425425
 426+ # includes/installer
 427+ 'Installer' => 'includes/installer/Installer.php',
 428+ 'InstallerDBType' => 'includes/installer/InstallerDBType.php',
 429+ 'LBFactory_InstallerFake' => 'includes/installer/Installer.php',
 430+ 'LocalSettingsGenerator' => 'includes/installer/LocalSettingsGenerator.php',
 431+ 'WebInstaller' => 'includes/installer/WebInstaller.php',
 432+ 'WebInstallerOutput' => 'includes/installer/WebInstallerOutput.php',
 433+ 'MysqlInstaller' => 'includes/installer/MysqlInstaller.php',
 434+ 'PostgresInstaller' => 'includes/installer/PostgresInstaller.php',
 435+ 'SqliteInstaller' => 'includes/installer/SqliteInstaller.php',
 436+ 'OracleInstaller' => 'includes/installer/OracleInstaller.php',
 437+
426438 # includes/media
427439 'BitmapHandler' => 'includes/media/Bitmap.php',
428440 'BitmapHandler_ClientOnly' => 'includes/media/Bitmap_ClientOnly.php',
Index: trunk/phase3/includes/DefaultSettings.php
@@ -625,12 +625,6 @@
626626 /** To override default SQLite data directory ($docroot/../data) */
627627 $wgSQLiteDataDir = '';
628628
629 -/** Default directory mode for SQLite data directory on creation.
630 - * Note that this is different from the default directory mode used
631 - * elsewhere.
632 - */
633 -$wgSQLiteDataDirMode = 0700;
634 -
635629 /**
636630 * Make all database connections secretly go to localhost. Fool the load balancer
637631 * thinking there is an arbitrarily large cluster of servers to connect to.
Property changes on: trunk/phase3/includes
___________________________________________________________________
Modified: svn:mergeinfo
638632 Merged /branches/new-installer/phase3/includes:r43664-66004
Index: trunk/phase3/config/new-index.php
@@ -0,0 +1,55 @@
 2+<?php
 3+
 4+define( 'MW_NO_DB', 1 );
 5+define( 'MW_NO_SESSION', 1 );
 6+define( 'MW_CONFIG_CALLBACK', 'wfInstallerConfig' );
 7+
 8+function wfInstallerConfig() {
 9+ // Don't access the database
 10+ $GLOBALS['wgUseDatabaseMessages'] = false;
 11+ // Debug-friendly
 12+ $GLOBALS['wgShowExceptionDetails'] = true;
 13+ // Don't break forms
 14+ $GLOBALS['wgExternalLinkTarget'] = '_blank';
 15+
 16+ // Extended debugging. Maybe disable before release?
 17+ $GLOBALS['wgShowSQLErrors'] = true;
 18+ $GLOBALS['wgShowDBErrorBacktrace'] = true;
 19+}
 20+
 21+chdir( ".." );
 22+require( './includes/WebStart.php' );
 23+require_once( './maintenance/updaters.inc' ); // sigh...
 24+
 25+// Disable the i18n cache and LoadBalancer
 26+Language::getLocalisationCache()->disableBackend();
 27+LBFactory::disableBackend();
 28+
 29+// Load the installer's i18n file
 30+$wgExtensionMessagesFiles['MediawikiInstaller'] = './includes/installer/Installer.i18n.php';
 31+
 32+$installer = new WebInstaller( $wgRequest );
 33+$wgParser->setHook( 'doclink', array( $installer, 'docLink' ) );
 34+
 35+if ( !$installer->startSession() ) {
 36+ $installer->finish();
 37+ exit;
 38+}
 39+
 40+$session = isset( $_SESSION['installData'] ) ? $_SESSION['installData'] : array();
 41+
 42+if ( isset( $session['settings']['_UserLang'] ) ) {
 43+ $langCode = $session['settings']['_UserLang'];
 44+} elseif ( !is_null( $wgRequest->getVal( 'UserLang' ) ) ) {
 45+ $langCode = $wgRequest->getVal( 'UserLang' );
 46+} else {
 47+ $langCode = 'en';
 48+}
 49+$wgLang = Language::factory( $langCode );
 50+
 51+$wgMetaNamespace = $wgCanonicalNamespaceNames[NS_PROJECT];
 52+
 53+$session = $installer->execute( $session );
 54+
 55+$_SESSION['installData'] = $session;
 56+
Property changes on: trunk/phase3/config/new-index.php
___________________________________________________________________
Added: svn:eol-style
157 + native
Property changes on: trunk/phase3
___________________________________________________________________
Modified: svn:mergeinfo
258 Merged /branches/new-installer/phase3:r43664-66004

Follow-up revisions

RevisionCommit summaryAuthorDate
r66019Fix r66008: don't declare wfArrayMap() twicecatrope14:24, 7 May 2010

Comments

#Comment by Tim Starling (talk | contribs)   00:42, 7 July 2010

I think we should limit the scope of this project to make sure it's usable before the release of 1.17. If that means cutting corners in the install/upgrade backend, then so be it. I don't think we should have unusable development code in the release branches.

Status & tagging log