* (bug 9993) Force $wgShowExceptionDetails on during installation
[lhc/web/wiklou.git] / config / index.php
1 <?php
2
3 # MediaWiki web-based config/installation
4 # Copyright (C) 2004 Brion Vibber <brion@pobox.com>, 2006 Rob Church <robchur@gmail.com>
5 # http://www.mediawiki.org/
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along
18 # with this program; if not, write to the Free Software Foundation, Inc.,
19 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 # http://www.gnu.org/copyleft/gpl.html
21
22 error_reporting( E_ALL );
23 header( "Content-type: text/html; charset=utf-8" );
24 @ini_set( "display_errors", true );
25
26 # In case of errors, let output be clean.
27 $wgRequestTime = microtime( true );
28
29 # Attempt to set up the include path, to fix problems with relative includes
30 $IP = dirname( dirname( __FILE__ ) );
31 define( 'MW_INSTALL_PATH', $IP );
32 $sep = PATH_SEPARATOR;
33 if( !ini_set( "include_path", ".$sep$IP$sep$IP/includes$sep$IP/languages" ) ) {
34 set_include_path( ".$sep$IP$sep$IP/includes$sep$IP/languages" );
35 }
36
37 # Define an entry point and include some files
38 define( "MEDIAWIKI", true );
39 define( "MEDIAWIKI_INSTALL", true );
40
41 // Run version checks before including other files
42 // so people don't see a scary parse error.
43 require_once( "install-utils.inc" );
44 install_version_checks();
45
46 require_once( "includes/Defines.php" );
47 require_once( "includes/DefaultSettings.php" );
48 require_once( "includes/AutoLoader.php" );
49 require_once( "includes/MagicWord.php" );
50 require_once( "includes/Namespace.php" );
51 require_once( "includes/ProfilerStub.php" );
52 require_once( "includes/GlobalFunctions.php" );
53 require_once( "includes/Hooks.php" );
54
55 # If we get an exception, the user needs to know
56 # all the details
57 $wgShowExceptionDetails = true;
58
59 ## Databases we support:
60
61 $ourdb = array();
62 $ourdb['mysql']['fullname'] = 'MySQL';
63 $ourdb['mysql']['havedriver'] = 0;
64 $ourdb['mysql']['compile'] = 'mysql';
65 $ourdb['mysql']['bgcolor'] = '#ffe5a7';
66 $ourdb['mysql']['rootuser'] = 'root';
67
68 $ourdb['postgres']['fullname'] = 'PostgreSQL';
69 $ourdb['postgres']['havedriver'] = 0;
70 $ourdb['postgres']['compile'] = 'pgsql';
71 $ourdb['postgres']['bgcolor'] = '#aaccff';
72 $ourdb['postgres']['rootuser'] = 'postgres';
73
74 ?>
75 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
76 <html>
77 <head>
78 <meta http-equiv="Content-type" content="text/html; charset=utf-8">
79 <title>MediaWiki <?php echo( $wgVersion ); ?> Installation</title>
80 <style type="text/css">
81
82 @import "../skins/monobook/main.css";
83
84 .env-check {
85 font-size: 90%;
86 margin: 1em 0 1em 2.5em;
87 }
88
89 .config-section {
90 margin-top: 2em;
91 }
92
93 .config-section label.column {
94 clear: left;
95 font-weight: bold;
96 width: 13em;
97 float: left;
98 text-align: right;
99 padding-right: 1em;
100 padding-top: .2em;
101 }
102
103 .config-input {
104 clear: left;
105 zoom: 100%; /* IE hack */
106 }
107
108 .config-section .config-desc {
109 clear: left;
110 margin: 0 0 2em 18em;
111 padding-top: 1em;
112 font-size: 85%;
113 }
114
115 .iput-text, .iput-password {
116 width: 14em;
117 margin-right: 1em;
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 .error-top {
129 color: red;
130 background-color: #FFF0F0;
131 border: 2px solid red;
132 font-size: 130%;
133 font-weight: bold;
134 padding: 1em 1.5em;
135 margin: 2em 0 1em;
136 }
137
138 ul.plain {
139 list-style-type: none;
140 list-style-image: none;
141 float: left;
142 margin: 0;
143 padding: 0;
144 }
145
146 .btn-install {
147 font-weight: bold;
148 font-size: 110%;
149 padding: .2em .3em;
150 }
151
152 .license {
153 font-size: 85%;
154 padding-top: 3em;
155 }
156
157 </style>
158 <script type="text/javascript">
159 <!--
160 function hideall() {
161 <?php foreach (array_keys($ourdb) as $db) {
162 echo "\n document.getElementById('$db').style.display='none';";
163 }
164 ?>
165
166 }
167 function toggleDBarea(id,defaultroot) {
168 hideall();
169 var dbarea = document.getElementById(id).style;
170 dbarea.display = (dbarea.display == 'none') ? 'block' : 'none';
171 var db = document.getElementById('RootUser');
172 if (defaultroot) {
173 <?php foreach (array_keys($ourdb) as $db) {
174 echo " if (id == '$db') { db.value = '".$ourdb[$db]['rootuser']."';}\n";
175 }?>
176 }
177 }
178 // -->
179 </script>
180 </head>
181
182 <body>
183 <div id="globalWrapper">
184 <div id="column-content">
185 <div id="content">
186 <div id="bodyContent">
187
188 <h1>MediaWiki <?php print $wgVersion ?> Installation</h1>
189
190 <?php
191
192 /* Check for existing configurations and bug out! */
193
194 if( file_exists( "../LocalSettings.php" ) ) {
195 dieout( "<p><strong>Setup has completed, <a href='../index.php'>your wiki</a> is configured.</strong></p>
196
197 <p>Please delete the /config directory for extra security.</p></div></div></div></div>" );
198 }
199
200 if( file_exists( "./LocalSettings.php" ) ) {
201 writeSuccessMessage();
202
203 dieout( '' );
204 }
205
206 if( !is_writable( "." ) ) {
207 dieout( "<h2>Can't write config file, aborting</h2>
208
209 <p>In order to configure the wiki you have to make the <tt>config</tt> subdirectory
210 writable by the web server. Once configuration is done you'll move the created
211 <tt>LocalSettings.php</tt> to the parent directory, and for added safety you can
212 then remove the <tt>config</tt> subdirectory entirely.</p>
213
214 <p>To make the directory writable on a Unix/Linux system:</p>
215
216 <pre>
217 cd <i>/path/to/wiki</i>
218 chmod a+w config
219 </pre>
220
221 <p>Afterwards retry to start the <a href=\"\">setup</a>.</p>" );
222 }
223
224
225 require_once( "install-utils.inc" );
226 require_once( "maintenance/updaters.inc" );
227
228 class ConfigData {
229 function getEncoded( $data ) {
230 # removing latin1 support, no need...
231 return $data;
232 }
233 function getSitename() { return $this->getEncoded( $this->Sitename ); }
234 function getSysopName() { return $this->getEncoded( $this->SysopName ); }
235 function getSysopPass() { return $this->getEncoded( $this->SysopPass ); }
236
237 function setSchema( $schema ) {
238 $this->DBschema = $schema;
239 switch ( $this->DBschema ) {
240 case 'mysql5':
241 $this->DBTableOptions = 'ENGINE=InnoDB, DEFAULT CHARSET=utf8';
242 $this->DBmysql5 = 'true';
243 break;
244 case 'mysql5-binary':
245 $this->DBTableOptions = 'ENGINE=InnoDB, DEFAULT CHARSET=binary';
246 $this->DBmysql5 = 'true';
247 break;
248 default:
249 $this->DBTableOptions = 'TYPE=InnoDB';
250 $this->DBmysql5 = 'false';
251 }
252 # Set the global for use during install
253 global $wgDBTableOptions;
254 $wgDBTableOptions = $this->DBTableOptions;
255 }
256 }
257
258 ?>
259
260 <ul>
261 <li>
262 <b>Don't forget security updates!</b> Keep an eye on the
263 <a href="http://mail.wikimedia.org/mailman/listinfo/mediawiki-announce">low-traffic
264 release announcements mailing list</a>.
265 </li>
266 </ul>
267
268
269 <h2>Checking environment...</h2>
270 <p><em>Please include all of the lines below when reporting installation problems.</em></p>
271 <ul class="env-check">
272 <?php
273 $endl = "
274 ";
275 define( 'MW_NO_OUTPUT_BUFFER', 1 );
276 $conf = new ConfigData;
277
278 install_version_checks();
279 $self = 'Installer'; # Maintenance script name, to please Setup.php
280
281 print "<li>PHP " . phpversion() . " installed</li>\n";
282
283 error_reporting( 0 );
284 $phpdatabases = array();
285 foreach (array_keys($ourdb) as $db) {
286 $compname = $ourdb[$db]['compile'];
287 if (extension_loaded($compname) or dl($compname . '.' . PHP_SHLIB_SUFFIX)) {
288 array_push($phpdatabases, $db);
289 $ourdb[$db]['havedriver'] = 1;
290 }
291 }
292 error_reporting( E_ALL );
293
294 if (!$phpdatabases) {
295 print "Could not find a suitable database driver!<ul>";
296 foreach (array_keys($ourdb) AS $db) {
297 $comp = $ourdb[$db]['compile'];
298 $full = $ourdb[$db]['fullname'];
299 print "<li>For <b>$full</b>, compile PHP using <b>--with-$comp</b>, "
300 ."or install the $comp.so module</li>\n";
301 }
302 dieout( "</ul></ul>" );
303 }
304
305 print "<li>Found database drivers for:";
306 foreach (array_keys($ourdb) AS $db) {
307 if ($ourdb[$db]['havedriver']) {
308 $DefaultDBtype = $db;
309 print " ".$ourdb[$db]['fullname'];
310 }
311 }
312 print "</li>\n";
313 if (count($phpdatabases) != 1)
314 $DefaultDBtype = '';
315
316 if( ini_get( "register_globals" ) ) {
317 ?>
318 <li>
319 <div style="font-size:110%">
320 <strong class="error">Warning:</strong>
321 <strong>PHP's <tt><a href="http://php.net/register_globals">register_globals</a></tt> option is enabled. Disable it if you can.</strong>
322 </div>
323 MediaWiki will work, but your server is more exposed to PHP-based security vulnerabilities.
324 </li>
325 <?php
326 }
327
328 $fatal = false;
329
330 if( ini_get( "magic_quotes_runtime" ) ) {
331 $fatal = true;
332 ?><li class='error'><strong>Fatal: <a href='http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime'>magic_quotes_runtime</a> is active!</strong>
333 This option corrupts data input unpredictably; you cannot install or use
334 MediaWiki unless this option is disabled.
335 <?php
336 }
337
338 if( ini_get( "magic_quotes_sybase" ) ) {
339 $fatal = true;
340 ?><li class='error'><strong>Fatal: <a href='http://www.php.net/manual/en/ref.sybase.php#ini.magic-quotes-sybase'>magic_quotes_sybase</a> is active!</strong>
341 This option corrupts data input unpredictably; you cannot install or use
342 MediaWiki unless this option is disabled.
343 <?php
344 }
345
346 if( ini_get( "mbstring.func_overload" ) ) {
347 $fatal = true;
348 ?><li class='error'><strong>Fatal: <a href='http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload'>mbstring.func_overload</a> is active!</strong>
349 This option causes errors and may corrupt data unpredictably;
350 you cannot install or use MediaWiki unless this option is disabled.
351 <?php
352 }
353
354 if( ini_get( "zend.ze1_compatibility_mode" ) ) {
355 $fatal = true;
356 ?><li class="error"><strong>Fatal: <a href="http://www.php.net/manual/en/ini.core.php">zend.ze1_compatibility_mode</a> is active!</strong>
357 This option causes horrible bugs with MediaWiki; you cannot install or use
358 MediaWiki unless this option is disabled.
359 <?php
360 }
361
362
363 if( $fatal ) {
364 dieout( "</ul><p>Cannot install MediaWiki.</p>" );
365 }
366
367 if( ini_get( "safe_mode" ) ) {
368 $conf->safeMode = true;
369 ?>
370 <li><b class='error'>Warning:</b> <strong>PHP's
371 <a href='http://www.php.net/features.safe-mode'>safe mode</a> is active.</strong>
372 You may have problems caused by this, particularly if using image uploads.
373 </li>
374 <?php
375 } else {
376 $conf->safeMode = false;
377 }
378
379 $sapi = php_sapi_name();
380 print "<li>PHP server API is $sapi; ";
381 if( $wgUsePathInfo ) {
382 print "ok, using pretty URLs (<tt>index.php/Page_Title</tt>)";
383 } else {
384 print "using ugly URLs (<tt>index.php?title=Page_Title</tt>)";
385 }
386 print "</li>\n";
387
388 $conf->xml = function_exists( "utf8_encode" );
389 if( $conf->xml ) {
390 print "<li>Have XML / Latin1-UTF-8 conversion support.</li>\n";
391 } else {
392 dieout( "PHP's XML module is missing; the wiki requires functions in
393 this module and won't work in this configuration.
394 If you're running Mandrake, install the php-xml package." );
395 }
396
397 # Check for session support
398 if( !function_exists( 'session_name' ) )
399 dieout( "PHP's session module is missing. MediaWiki requires session support in order to function." );
400
401 # session.save_path doesn't *have* to be set, but if it is, and it's
402 # not valid/writable/etc. then it can cause problems
403 $sessionSavePath = mw_get_session_save_path();
404 $ssp = htmlspecialchars( $sessionSavePath );
405 # Warn the user if it's not set, but let them proceed
406 if( !$sessionSavePath ) {
407 print "<li><strong>Warning:</strong> A value for <tt>session.save_path</tt>
408 has not been set in PHP.ini. If the default value causes problems with
409 saving session data, set it to a valid path which is read/write/execute
410 for the user your web server is running under.</li>";
411 } elseif ( is_dir( $sessionSavePath ) && is_writable( $sessionSavePath ) ) {
412 # All good? Let the user know
413 print "<li>Session save path (<tt>{$ssp}</tt>) appears to be valid.</li>";
414 } else {
415 # Something not right? Warn the user, but let them proceed
416 print "<li><strong>Warning:</strong> Your <tt>session.save_path</tt> value (<tt>{$ssp}</tt>)
417 appears to be invalid or is not writable. PHP needs to be able to save data to
418 this location for correct session operation.</li>";
419 }
420
421 # Check for PCRE support
422 if( !function_exists( 'preg_match' ) )
423 dieout( "The PCRE support module appears to be missing. MediaWiki requires the
424 Perl-compatible regular expression functions." );
425
426 $memlimit = ini_get( "memory_limit" );
427 $conf->raiseMemory = false;
428 if( empty( $memlimit ) || $memlimit == -1 ) {
429 print "<li>PHP is configured with no <tt>memory_limit</tt>.</li>\n";
430 } else {
431 print "<li>PHP's <tt>memory_limit</tt> is " . htmlspecialchars( $memlimit ) . ". ";
432 $n = intval( $memlimit );
433 if( preg_match( '/^([0-9]+)[Mm]$/', trim( $memlimit ), $m ) ) {
434 $n = intval( $m[1] * (1024*1024) );
435 }
436 if( $n < 20*1024*1024 ) {
437 print "Attempting to raise limit to 20M... ";
438 if( false === ini_set( "memory_limit", "20M" ) ) {
439 print "failed.<br /><b>" . htmlspecialchars( $memlimit ) . " seems too low, installation may fail!</b>";
440 } else {
441 $conf->raiseMemory = true;
442 print "ok.";
443 }
444 }
445 print "</li>\n";
446 }
447
448 $conf->turck = function_exists( 'mmcache_get' );
449 if ( $conf->turck ) {
450 print "<li><a href=\"http://turck-mmcache.sourceforge.net/\">Turck MMCache</a> installed</li>\n";
451 }
452
453 $conf->apc = function_exists('apc_fetch');
454 if ($conf->apc ) {
455 print "<li><a href=\"http://www.php.net/apc\">APC</a> installed</li>";
456 }
457
458 $conf->eaccel = function_exists( 'eaccelerator_get' );
459 if ( $conf->eaccel ) {
460 $conf->turck = 'eaccelerator';
461 print "<li><a href=\"http://eaccelerator.sourceforge.net/\">eAccelerator</a> installed</li>\n";
462 }
463
464 if( !$conf->turck && !$conf->eaccel && !$conf->apc ) {
465 echo( '<li>Couldn\'t find <a href="http://turck-mmcache.sourceforge.net">Turck MMCache</a>,
466 <a href="http://eaccelerator.sourceforge.net">eAccelerator</a>, or
467 <a href="http://www.php.net/apc">APC</a>. Object caching functions cannot be used.</li>' );
468 }
469
470 $conf->diff3 = false;
471 $diff3locations = array_merge(
472 array(
473 "/usr/bin",
474 "/usr/local/bin",
475 "/opt/csw/bin",
476 "/usr/gnu/bin",
477 "/usr/sfw/bin" ),
478 explode( $sep, getenv( "PATH" ) ) );
479 $diff3names = array( "gdiff3", "diff3", "diff3.exe" );
480
481 $diff3versioninfo = array( '$1 --version 2>&1', 'diff3 (GNU diffutils)' );
482 foreach ($diff3locations as $loc) {
483 $exe = locate_executable($loc, $diff3names, $diff3versioninfo);
484 if ($exe !== false) {
485 $conf->diff3 = $exe;
486 break;
487 }
488 }
489
490 if ($conf->diff3)
491 print "<li>Found GNU diff3: <tt>$conf->diff3</tt>.</li>";
492 else
493 print "<li>GNU diff3 not found.</li>";
494
495 $conf->ImageMagick = false;
496 $imcheck = array( "/usr/bin", "/opt/csw/bin", "/usr/local/bin", "/sw/bin", "/opt/local/bin" );
497 foreach( $imcheck as $dir ) {
498 $im = "$dir/convert";
499 if( file_exists( $im ) ) {
500 print "<li>Found ImageMagick: <tt>$im</tt>; image thumbnailing will be enabled if you enable uploads.</li>\n";
501 $conf->ImageMagick = $im;
502 break;
503 }
504 }
505
506 $conf->HaveGD = function_exists( "imagejpeg" );
507 if( $conf->HaveGD ) {
508 print "<li>Found GD graphics library built-in";
509 if( !$conf->ImageMagick ) {
510 print ", image thumbnailing will be enabled if you enable uploads";
511 }
512 print ".</li>\n";
513 } else {
514 if( !$conf->ImageMagick ) {
515 print "<li>Couldn't find GD library or ImageMagick; image thumbnailing disabled.</li>\n";
516 }
517 }
518
519 $conf->IP = dirname( dirname( __FILE__ ) );
520 print "<li>Installation directory: <tt>" . htmlspecialchars( $conf->IP ) . "</tt></li>\n";
521
522
523 // PHP_SELF isn't available sometimes, such as when PHP is CGI but
524 // cgi.fix_pathinfo is disabled. In that case, fall back to SCRIPT_NAME
525 // to get the path to the current script... hopefully it's reliable. SIGH
526 $path = ($_SERVER["PHP_SELF"] === '')
527 ? $_SERVER["SCRIPT_NAME"]
528 : $_SERVER["PHP_SELF"];
529 $conf->ScriptPath = preg_replace( '{^(.*)/config.*$}', '$1', $path );
530 print "<li>Script URI path: <tt>" . htmlspecialchars( $conf->ScriptPath ) . "</tt></li>\n";
531
532 print "<li style='font-weight:bold;color:green;font-size:110%'>Environment checked. You can install MediaWiki.</li>\n";
533 $conf->posted = ($_SERVER["REQUEST_METHOD"] == "POST");
534
535 $conf->Sitename = ucfirst( importPost( "Sitename", "" ) );
536 $defaultEmail = empty( $_SERVER["SERVER_ADMIN"] )
537 ? 'root@localhost'
538 : $_SERVER["SERVER_ADMIN"];
539 $conf->EmergencyContact = importPost( "EmergencyContact", $defaultEmail );
540 $conf->DBtype = importPost( "DBtype", $DefaultDBtype );
541 ?>
542
543 <?php
544 $conf->DBserver = importPost( "DBserver", "localhost" );
545 $conf->DBname = importPost( "DBname", "wikidb" );
546 $conf->DBuser = importPost( "DBuser", "wikiuser" );
547 $conf->DBpassword = importPost( "DBpassword" );
548 $conf->DBpassword2 = importPost( "DBpassword2" );
549 $conf->SysopName = importPost( "SysopName", "WikiSysop" );
550 $conf->SysopPass = importPost( "SysopPass" );
551 $conf->SysopPass2 = importPost( "SysopPass2" );
552 $conf->RootUser = importPost( "RootUser", "root" );
553 $conf->RootPW = importPost( "RootPW", "" );
554 $useRoot = importCheck( 'useroot', false );
555 $conf->LanguageCode = importPost( "LanguageCode", "en" );
556
557 ## MySQL specific:
558 $conf->DBprefix = importPost( "DBprefix" );
559 $conf->setSchema( importPost( "DBschema", "mysql4" ) );
560
561 ## Postgres specific:
562 $conf->DBport = importPost( "DBport", "5432" );
563 $conf->DBmwschema = importPost( "DBmwschema", "mediawiki" );
564 $conf->DBts2schema = importPost( "DBts2schema", "public" );
565
566 /* Check for validity */
567 $errs = array();
568
569 if( $conf->Sitename == "" || $conf->Sitename == "MediaWiki" || $conf->Sitename == "Mediawiki" ) {
570 $errs["Sitename"] = "Must not be blank or \"MediaWiki\"";
571 }
572 if( $conf->DBuser == "" ) {
573 $errs["DBuser"] = "Must not be blank";
574 }
575 if( ($conf->DBtype == 'mysql') && (strlen($conf->DBuser) > 16) ) {
576 $errs["DBuser"] = "Username too long";
577 }
578 if( $conf->DBpassword == "" && $conf->DBtype != "postgres" ) {
579 $errs["DBpassword"] = "Must not be blank";
580 }
581 if( $conf->DBpassword != $conf->DBpassword2 ) {
582 $errs["DBpassword2"] = "Passwords don't match!";
583 }
584 if( !preg_match( '/^[A-Za-z_0-9]*$/', $conf->DBprefix ) ) {
585 $errs["DBprefix"] = "Invalid table prefix";
586 }
587
588 error_reporting( E_ALL );
589
590 /**
591 * Initialise $wgLang and $wgContLang to something so we can
592 * call case-folding methods. Per Brion, this is English for
593 * now, although we could be clever and initialise to the
594 * user-selected language.
595 */
596 $wgContLang = Language::factory( 'en' );
597 $wgLang = $wgContLang;
598
599 /**
600 * We're messing about with users, so we need a stub
601 * authentication plugin...
602 */
603 $wgAuth = new AuthPlugin();
604
605 /**
606 * Validate the initial administrator account; username,
607 * password checks, etc.
608 */
609 if( $conf->SysopName ) {
610 # Check that the user can be created
611 $u = User::newFromName( $conf->SysopName );
612 if( $u instanceof User ) {
613 # Various password checks
614 if( $conf->SysopPass != '' ) {
615 if( $conf->SysopPass == $conf->SysopPass2 ) {
616 if( !$u->isValidPassword( $conf->SysopPass ) ) {
617 $errs['SysopPass'] = "Bad password";
618 }
619 } else {
620 $errs['SysopPass2'] = "Passwords don't match";
621 }
622 } else {
623 $errs['SysopPass'] = "Cannot be blank";
624 }
625 unset( $u );
626 } else {
627 $errs['SysopName'] = "Bad username";
628 }
629 }
630
631 $conf->License = importRequest( "License", "none" );
632 if( $conf->License == "gfdl" ) {
633 $conf->RightsUrl = "http://www.gnu.org/copyleft/fdl.html";
634 $conf->RightsText = "GNU Free Documentation License 1.2";
635 $conf->RightsCode = "gfdl";
636 $conf->RightsIcon = '${wgScriptPath}/skins/common/images/gnu-fdl.png';
637 } elseif( $conf->License == "none" ) {
638 $conf->RightsUrl = $conf->RightsText = $conf->RightsCode = $conf->RightsIcon = "";
639 } else {
640 $conf->RightsUrl = importRequest( "RightsUrl", "" );
641 $conf->RightsText = importRequest( "RightsText", "" );
642 $conf->RightsCode = importRequest( "RightsCode", "" );
643 $conf->RightsIcon = importRequest( "RightsIcon", "" );
644 }
645
646 $conf->Shm = importRequest( "Shm", "none" );
647 $conf->MCServers = importRequest( "MCServers" );
648
649 /* Test memcached servers */
650
651 if ( $conf->Shm == 'memcached' && $conf->MCServers ) {
652 $conf->MCServerArray = array_map( 'trim', explode( ',', $conf->MCServers ) );
653 foreach ( $conf->MCServerArray as $server ) {
654 $error = testMemcachedServer( $server );
655 if ( $error ) {
656 $errs["MCServers"] = $error;
657 break;
658 }
659 }
660 } else if ( $conf->Shm == 'memcached' ) {
661 $errs["MCServers"] = "Please specify at least one server if you wish to use memcached";
662 }
663
664 /* default values for installation */
665 $conf->Email = importRequest("Email", "email_enabled");
666 $conf->Emailuser = importRequest("Emailuser", "emailuser_enabled");
667 $conf->Enotif = importRequest("Enotif", "enotif_allpages");
668 $conf->Eauthent = importRequest("Eauthent", "eauthent_enabled");
669
670 if( $conf->posted && ( 0 == count( $errs ) ) ) {
671 do { /* So we can 'continue' to end prematurely */
672 $conf->Root = ($conf->RootPW != "");
673
674 /* Load up the settings and get installin' */
675 $local = writeLocalSettings( $conf );
676 echo "<li style=\"list-style: none\">\n";
677 echo "<p><b>Generating configuration file...</b></p>\n";
678 echo "</li>\n";
679
680 $wgCommandLineMode = false;
681 chdir( ".." );
682 $ok = eval( $local );
683 if( $ok === false ) {
684 dieout( "Errors in generated configuration; " .
685 "most likely due to a bug in the installer... " .
686 "Config file was: " .
687 "<pre>" .
688 htmlspecialchars( $local ) .
689 "</pre>" .
690 "</ul>" );
691 }
692 $conf->DBtypename = '';
693 foreach (array_keys($ourdb) as $db) {
694 if ($conf->DBtype === $db)
695 $conf->DBtypename = $ourdb[$db]['fullname'];
696 }
697 if ( ! strlen($conf->DBtype)) {
698 $errs["DBpicktype"] = "Please choose a database type";
699 continue;
700 }
701
702 if (! $conf->DBtypename) {
703 $errs["DBtype"] = "Unknown database type '$conf->DBtype'";
704 continue;
705 }
706 print "<li>Database type: {$conf->DBtypename}</li>\n";
707 $dbclass = 'Database'.ucfirst($conf->DBtype);
708 $wgDBtype = $conf->DBtype;
709 $wgDBadminuser = "root";
710 $wgDBadminpassword = $conf->RootPW;
711
712 ## Mysql specific:
713 $wgDBprefix = $conf->DBprefix;
714
715 ## Postgres specific:
716 $wgDBport = $conf->DBport;
717 $wgDBmwschema = $conf->DBmwschema;
718 $wgDBts2schema = $conf->DBts2schema;
719
720 $wgCommandLineMode = true;
721 $wgUseDatabaseMessages = false; /* FIXME: For database failure */
722 require_once( "includes/Setup.php" );
723 chdir( "config" );
724
725 $wgTitle = Title::newFromText( "Installation script" );
726 error_reporting( E_ALL );
727 print "<li>Loading class: $dbclass";
728 $dbc = new $dbclass;
729
730 if( $conf->DBtype == 'mysql' ) {
731 $mysqlOldClient = version_compare( mysql_get_client_info(), "4.1.0", "lt" );
732 if( $mysqlOldClient ) {
733 print "<li><b>PHP is linked with old MySQL client libraries. If you are
734 using a MySQL 4.1 server and have problems connecting to the database,
735 see <a href='http://dev.mysql.com/doc/mysql/en/old-client.html'
736 >http://dev.mysql.com/doc/mysql/en/old-client.html</a> for help.</b></li>\n";
737 }
738 $ok = true; # Let's be optimistic
739
740 # Decide if we're going to use the superuser or the regular database user
741 $conf->Root = $useRoot;
742 if( $conf->Root ) {
743 $db_user = $conf->RootUser;
744 $db_pass = $conf->RootPW;
745 } else {
746 $db_user = $wgDBuser;
747 $db_pass = $wgDBpassword;
748 }
749
750 # Attempt to connect
751 echo( "<li>Attempting to connect to database server as $db_user..." );
752 $wgDatabase = Database::newFromParams( $wgDBserver, $db_user, $db_pass, '', 1 );
753
754 # Check the connection and respond to errors
755 if( $wgDatabase->isOpen() ) {
756 # Seems OK
757 $ok = true;
758 $wgDBadminuser = $db_user;
759 $wgDBadminpassword = $db_pass;
760 echo( "success.</li>\n" );
761 $wgDatabase->ignoreErrors( true );
762 $myver = $wgDatabase->getServerVersion();
763 } else {
764 # There were errors, report them and back out
765 $ok = false;
766 $errno = mysql_errno();
767 $errtx = htmlspecialchars( mysql_error() );
768 switch( $errno ) {
769 case 1045:
770 case 2000:
771 echo( "failed due to authentication errors. Check passwords.</li>" );
772 if( $conf->Root ) {
773 # The superuser details are wrong
774 $errs["RootUser"] = "Check username";
775 $errs["RootPW"] = "and password";
776 } else {
777 # The regular user details are wrong
778 $errs["DBuser"] = "Check username";
779 $errs["DBpassword"] = "and password";
780 }
781 break;
782 case 2002:
783 case 2003:
784 default:
785 # General connection problem
786 echo( "failed with error [$errno] $errtx.</li>\n" );
787 $errs["DBserver"] = "Connection failed";
788 break;
789 } # switch
790 } #conn. att.
791
792 if( !$ok ) { continue; }
793
794 } else /* not mysql */ {
795 error_reporting( E_ALL );
796 $wgSuperUser = '';
797 ## Possible connect as a superuser
798 if( $useRoot ) {
799 $wgDBsuperuser = $conf->RootUser;
800 echo( "<li>Attempting to connect to database \"postgres\" as superuser \"$wgDBsuperuser\"..." );
801 $wgDatabase = $dbc->newFromParams($wgDBserver, $wgDBsuperuser, $conf->RootPW, "postgres", 1);
802 if (!$wgDatabase->isOpen()) {
803 print " error: " . $wgDatabase->lastError() . "</li>\n";
804 $errs["DBserver"] = "Could not connect to database as superuser";
805 $errs["RootUser"] = "Check username";
806 $errs["RootPW"] = "and password";
807 continue;
808 }
809 }
810 echo( "<li>Attempting to connect to database \"$wgDBname\" as \"$wgDBuser\"..." );
811 $wgDatabase = $dbc->newFromParams($wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, 1);
812 if (!$wgDatabase->isOpen()) {
813 print " error: " . $wgDatabase->lastError() . "</li>\n";
814 } else {
815 $myver = $wgDatabase->getServerVersion();
816 }
817 }
818
819 if ( !$wgDatabase->isOpen() ) {
820 $errs["DBserver"] = "Couldn't connect to database";
821 continue;
822 }
823
824 print "<li>Connected to $myver";
825 if ($conf->DBtype == 'mysql') {
826 if( version_compare( $myver, "4.0.14" ) < 0 ) {
827 dieout( " -- mysql 4.0.14 or later required. Aborting." );
828 }
829 $mysqlNewAuth = version_compare( $myver, "4.1.0", "ge" );
830 if( $mysqlNewAuth && $mysqlOldClient ) {
831 print "; <b class='error'>You are using MySQL 4.1 server, but PHP is linked
832 to old client libraries; if you have trouble with authentication, see
833 <a href='http://dev.mysql.com/doc/mysql/en/old-client.html'
834 >http://dev.mysql.com/doc/mysql/en/old-client.html</a> for help.</b>";
835 }
836 if( $wgDBmysql5 ) {
837 if( $mysqlNewAuth ) {
838 print "; enabling MySQL 4.1/5.0 charset mode";
839 } else {
840 print "; <b class='error'>MySQL 4.1/5.0 charset mode enabled,
841 but older version detected; will likely fail.</b>";
842 }
843 }
844 print "</li>\n";
845
846 @$sel = $wgDatabase->selectDB( $wgDBname );
847 if( $sel ) {
848 print "<li>Database <tt>" . htmlspecialchars( $wgDBname ) . "</tt> exists</li>\n";
849 } else {
850 $err = mysql_errno();
851 $databaseSafe = htmlspecialchars( $wgDBname );
852 if( $err == 1102 /* Invalid database name */ ) {
853 print "<ul><li><strong>{$databaseSafe}</strong> is not a valid database name.</li></ul>";
854 continue;
855 } elseif( $err != 1049 /* Database doesn't exist */ ) {
856 print "<ul><li>Error selecting database <strong>{$databaseSafe}</strong>: {$err} ";
857 print htmlspecialchars( mysql_error() ) . "</li></ul>";
858 continue;
859 }
860 print "<li>Attempting to create database...</li>";
861 $res = $wgDatabase->query( "CREATE DATABASE `$wgDBname`" );
862 if( !$res ) {
863 print "<li>Couldn't create database <tt>" .
864 htmlspecialchars( $wgDBname ) .
865 "</tt>; try with root access or check your username/pass.</li>\n";
866 $errs["RootPW"] = "&lt;- Enter";
867 continue;
868 }
869 print "<li>Created database <tt>" . htmlspecialchars( $wgDBname ) . "</tt></li>\n";
870 }
871 $wgDatabase->selectDB( $wgDBname );
872 }
873 else if ($conf->DBtype == 'postgres') {
874 if( version_compare( $myver, "PostgreSQL 8.0" ) < 0 ) {
875 dieout( " <b>Postgres 8.0 or later is required</b>. Aborting.</li></ul>" );
876 }
877 }
878
879 if( $wgDatabase->tableExists( "cur" ) || $wgDatabase->tableExists( "revision" ) ) {
880 print "<li>There are already MediaWiki tables in this database. Checking if updates are needed...</li>\n";
881
882 if ( $conf->DBtype == 'mysql') {
883
884 # Determine existing default character set
885 if ( $wgDatabase->tableExists( "revision" ) ) {
886 $revision = $wgDatabase->escapeLike( $conf->DBprefix . 'revision' );
887 $res = $wgDatabase->query( "SHOW TABLE STATUS LIKE '$revision'" );
888 $row = $wgDatabase->fetchObject( $res );
889 if ( !$row ) {
890 echo "<li>SHOW TABLE STATUS query failed!</li>\n";
891 $existingSchema = false;
892 } elseif ( preg_match( '/^latin1/', $row->Collation ) ) {
893 $existingSchema = 'mysql4';
894 } elseif ( preg_match( '/^utf8/', $row->Collation ) ) {
895 $existingSchema = 'mysql5';
896 } elseif ( preg_match( '/^binary/', $row->Collation ) ) {
897 $existingSchema = 'mysql5-binary';
898 } else {
899 $existingSchema = false;
900 echo "<li><strong>Warning:</strong> Unrecognised existing collation</li>\n";
901 }
902 if ( $existingSchema && $existingSchema != $conf->DBschema ) {
903 print "<li><strong>Warning:</strong> you requested the {$conf->DBschema} schema, " .
904 "but the existing database has the $existingSchema schema. This upgrade script ".
905 "can't convert it, so it will remain $existingSchema.</li>\n";
906 $conf->setSchema( $existingSchema );
907 }
908 }
909
910 # Create user if required
911 if ( $conf->Root ) {
912 $conn = $dbc->newFromParams( $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, 1 );
913 if ( $conn->isOpen() ) {
914 print "<li>DB user account ok</li>\n";
915 $conn->close();
916 } else {
917 print "<li>Granting user permissions...";
918 if( $mysqlOldClient && $mysqlNewAuth ) {
919 print " <b class='error'>If the next step fails, see <a href='http://dev.mysql.com/doc/mysql/en/old-client.html'>http://dev.mysql.com/doc/mysql/en/old-client.html</a> for help.</b>";
920 }
921 print "</li>\n";
922 dbsource( "../maintenance/users.sql", $wgDatabase );
923 }
924 }
925 }
926 print "</ul><pre>\n";
927 chdir( ".." );
928 flush();
929 do_all_updates();
930 chdir( "config" );
931 print "</pre>\n";
932 print "<ul><li>Finished update checks.</li>\n";
933 } else {
934 # FIXME: Check for errors
935 print "<li>Creating tables...";
936 if ($conf->DBtype == 'mysql') {
937 dbsource( "../maintenance/tables.sql", $wgDatabase );
938 dbsource( "../maintenance/interwiki.sql", $wgDatabase );
939 } else if ($conf->DBtype == 'postgres') {
940 $wgDatabase->setup_database();
941 }
942 else {
943 $errs["DBtype"] = "Do not know how to handle database type '$conf->DBtype'";
944 continue;
945 }
946
947 print " done.</li>\n";
948
949 print "<li>Initializing data...</li>\n";
950 $wgDatabase->insert( 'site_stats',
951 array ( 'ss_row_id' => 1,
952 'ss_total_views' => 0,
953 'ss_total_edits' => 0,
954 'ss_good_articles' => 0 ) );
955
956 # Set up the "regular user" account *if we can, and if we need to*
957 if( $conf->Root and $conf->DBtype == 'mysql') {
958 # See if we need to
959 $wgDatabase2 = $dbc->newFromParams( $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, 1 );
960 if( $wgDatabase2->isOpen() ) {
961 # Nope, just close the test connection and continue
962 $wgDatabase2->close();
963 echo( "<li>User $wgDBuser exists. Skipping grants.</li>\n" );
964 } else {
965 # Yes, so run the grants
966 echo( "<li>Granting user permissions to $wgDBuser on $wgDBname..." );
967 dbsource( "../maintenance/users.sql", $wgDatabase );
968 echo( "success.</li>\n" );
969 }
970 }
971
972 if( $conf->SysopName ) {
973 $u = User::newFromName( $conf->getSysopName() );
974 if ( !$u ) {
975 print "<li><strong class=\"error\">Warning:</strong> Skipped sysop account creation - invalid username!</li>\n";
976 }
977 else if ( 0 == $u->idForName() ) {
978 $u->addToDatabase();
979 $u->setPassword( $conf->getSysopPass() );
980 $u->saveSettings();
981
982 $u->addGroup( "sysop" );
983 $u->addGroup( "bureaucrat" );
984
985 print "<li>Created sysop account <tt>" .
986 htmlspecialchars( $conf->SysopName ) . "</tt>.</li>\n";
987 } else {
988 print "<li>Could not create user - already exists!</li>\n";
989 }
990 } else {
991 print "<li>Skipped sysop account creation, no name given.</li>\n";
992 }
993
994 $titleobj = Title::newFromText( wfMsgNoDB( "mainpage" ) );
995 $article = new Article( $titleobj );
996 $newid = $article->insertOn( $wgDatabase );
997 $revision = new Revision( array(
998 'page' => $newid,
999 'text' => wfMsg( 'mainpagetext' ) . "\n\n" . wfMsgNoTrans( 'mainpagedocfooter' ),
1000 'comment' => '',
1001 'user' => 0,
1002 'user_text' => 'MediaWiki default',
1003 ) );
1004 $revid = $revision->insertOn( $wgDatabase );
1005 $article->updateRevisionOn( $wgDatabase, $revision );
1006 }
1007
1008 /* Write out the config file now that all is well */
1009 print "<li style=\"list-style: none\">\n";
1010 print "<p>Creating LocalSettings.php...</p>\n\n";
1011 $localSettings = "<" . "?php$endl$local";
1012 // Fix up a common line-ending problem (due to CVS on Windows)
1013 $localSettings = str_replace( "\r\n", "\n", $localSettings );
1014 $f = fopen( "LocalSettings.php", 'xt' );
1015
1016 if( $f == false ) {
1017 dieout( "<p>Couldn't write out LocalSettings.php. Check that the directory permissions are correct and that there isn't already a file of that name here...</p>\n" .
1018 "<p>Here's the file that would have been written, try to paste it into place manually:</p>\n" .
1019 "<pre>\n" . htmlspecialchars( $localSettings ) . "</pre>\n" );
1020 }
1021 if(fwrite( $f, $localSettings ) ) {
1022 fclose( $f );
1023 writeSuccessMessage();
1024 } else {
1025 fclose( $f );
1026 die("<p class='error'>An error occured while writing the config/LocalSettings.php file. Check user rights and disk space then try again.</p>\n");
1027
1028 }
1029 print "</li>\n";
1030
1031 } while( false );
1032 }
1033 ?>
1034 </ul>
1035
1036
1037 <?php
1038
1039 if( count( $errs ) ) {
1040 /* Display options form */
1041
1042 if( $conf->posted ) {
1043 echo "<p class='error-top'>Something's not quite right yet; make sure everything below is filled out correctly.</p>\n";
1044 }
1045 ?>
1046
1047 <form action="index.php" name="config" method="post">
1048
1049
1050 <h2>Site config</h2>
1051
1052 <div class="config-section">
1053 <div class="config-input">
1054 <?php
1055 aField( $conf, "Sitename", "Wiki name:" );
1056 ?>
1057 </div>
1058 <p class="config-desc">
1059 Preferably a short word without punctuation, i.e. "Wikipedia".<br />
1060 Will appear as the namespace name for "meta" pages, and throughout the interface.
1061 </p>
1062
1063 <div class="config-input">
1064 <?php
1065 aField( $conf, "EmergencyContact", "Contact e-mail:" );
1066 ?>
1067 </div>
1068 <p class="config-desc">
1069 Displayed to users in some error messages, used as the return address for password reminders, and used as the default sender address of e-mail notifications.
1070 </p>
1071
1072 <div class="config-input">
1073 <label class='column' for="LanguageCode">Language:</label>
1074 <select id="LanguageCode" name="LanguageCode">
1075
1076 <?php
1077 $list = getLanguageList();
1078 foreach( $list as $code => $name ) {
1079 $sel = ($code == $conf->LanguageCode) ? 'selected="selected"' : '';
1080 echo "\t\t<option value=\"$code\" $sel>$name</option>\n";
1081 }
1082 ?>
1083 </select>
1084 </div>
1085 <p class="config-desc">
1086 Select the language for your wiki's interface. Some localizations aren't fully complete. Unicode (UTF-8) is used for all localizations.
1087 </p>
1088
1089 <div class="config-input">
1090 <label class='column'>Copyright/license:</label>
1091
1092 <ul class="plain">
1093 <li><?php aField( $conf, "License", "No license metadata", "radio", "none" ); ?></li>
1094 <li><?php aField( $conf, "License", "GNU Free Documentation License 1.2 (Wikipedia-compatible)", "radio", "gfdl" ); ?></li>
1095 <li><?php
1096 aField( $conf, "License", "A Creative Commons license - ", "radio", "cc" );
1097 $partner = "MediaWiki";
1098 $exit = urlencode( "$wgServer{$conf->ScriptPath}/config/index.php?License=cc&RightsUrl=[license_url]&RightsText=[license_name]&RightsCode=[license_code]&RightsIcon=[license_button]" );
1099 $icon = urlencode( "$wgServer$wgUploadPath/wiki.png" );
1100 $ccApp = htmlspecialchars( "http://creativecommons.org/license/?partner=$partner&exit_url=$exit&partner_icon_url=$icon" );
1101 print "<a href=\"$ccApp\" target='_blank'>choose</a>";
1102 ?>
1103 <?php if( $conf->License == "cc" ) { ?>
1104 <ul>
1105 <li><?php aField( $conf, "RightsIcon", "<img src=\"" . htmlspecialchars( $conf->RightsIcon ) . "\" alt='(Creative Commons icon)' />", "hidden" ); ?></li>
1106 <li><?php aField( $conf, "RightsText", htmlspecialchars( $conf->RightsText ), "hidden" ); ?></li>
1107 <li><?php aField( $conf, "RightsCode", "code: " . htmlspecialchars( $conf->RightsCode ), "hidden" ); ?></li>
1108 <li><?php aField( $conf, "RightsUrl", "<a href=\"" . htmlspecialchars( $conf->RightsUrl ) . "\">" . htmlspecialchars( $conf->RightsUrl ) . "</a>", "hidden" ); ?></li>
1109 </ul>
1110 <?php } ?>
1111 </li>
1112 </ul>
1113 </div>
1114 <p class="config-desc">
1115 A notice, icon, and machine-readable copyright metadata will be displayed for the license you pick.
1116 </p>
1117
1118
1119 <div class="config-input">
1120 <?php aField( $conf, "SysopName", "Admin username:" ) ?>
1121 </div>
1122 <div class="config-input">
1123 <?php aField( $conf, "SysopPass", "Password:", "password" ) ?>
1124 </div>
1125 <div class="config-input">
1126 <?php aField( $conf, "SysopPass2", "Password confirm:", "password" ) ?>
1127 </div>
1128 <p class="config-desc">
1129 An admin can lock/delete pages, block users from editing, and do other maintenance tasks.<br />
1130 A new account will be added only when creating a new wiki database.
1131 </p>
1132 <p class="config-desc">
1133 The password cannot be the same as the username.
1134 </p>
1135
1136 <div class="config-input">
1137 <label class='column'>Shared memory caching:</label>
1138
1139 <ul class="plain">
1140 <li><?php aField( $conf, "Shm", "No caching", "radio", "none" ); ?></li>
1141 <?php
1142 if ( $conf->turck ) {
1143 echo "<li>";
1144 aField( $conf, "Shm", "Turck MMCache", "radio", "turck" );
1145 echo "</li>";
1146 }
1147 if ( $conf->apc ) {
1148 echo "<li>";
1149 aField( $conf, "Shm", "APC", "radio", "apc" );
1150 echo "</li>";
1151 }
1152 if ( $conf->eaccel ) {
1153 echo "<li>";
1154 aField( $conf, "Shm", "eAccelerator", "radio", "eaccel" );
1155 echo "</li>";
1156 }
1157 ?>
1158 <li><?php aField( $conf, "Shm", "Memcached", "radio", "memcached" ); ?></li>
1159 </ul>
1160 <div style="clear:left"><?php aField( $conf, "MCServers", "Memcached servers:", "text" ) ?></div>
1161 </div>
1162 <p class="config-desc">
1163 Using a shared memory system such as Turck MMCache, APC, eAccelerator, or Memcached
1164 will speed up MediaWiki significantly. Memcached is the best solution but needs to be
1165 installed. Specify the server addresses and ports in a comma-separated list. Only
1166 use Turck shared memory if the wiki will be running on a single Apache server.
1167 </p>
1168 </div>
1169
1170 <h2>E-mail, e-mail notification and authentication setup</h2>
1171
1172 <div class="config-section">
1173 <div class="config-input">
1174 <label class='column'>E-mail features (global):</label>
1175 <ul class="plain">
1176 <li><?php aField( $conf, "Email", "Enabled", "radio", "email_enabled" ); ?></li>
1177 <li><?php aField( $conf, "Email", "Disabled", "radio", "email_disabled" ); ?></li>
1178 </ul>
1179 </div>
1180 <p class="config-desc">
1181 Use this to disable all e-mail functions (password reminders, user-to-user e-mail, and e-mail notifications)
1182 if sending mail doesn't work on your server.
1183 </p>
1184
1185 <div class="config-input">
1186 <label class='column'>User-to-user e-mail:</label>
1187 <ul class="plain">
1188 <li><?php aField( $conf, "Emailuser", "Enabled", "radio", "emailuser_enabled" ); ?></li>
1189 <li><?php aField( $conf, "Emailuser", "Disabled", "radio", "emailuser_disabled" ); ?></li>
1190 </ul>
1191 </div>
1192 <p class="config-desc">
1193 The user-to-user e-mail feature (Special:Emailuser) lets the wiki act as a relay to allow users to exchange e-mail without publicly advertising their e-mail address.
1194 </p>
1195 <div class="config-input">
1196 <label class='column'>E-mail notification about changes:</label>
1197 <ul class="plain">
1198 <li><?php aField( $conf, "Enotif", "Disabled", "radio", "enotif_disabled" ); ?></li>
1199 <li><?php aField( $conf, "Enotif", "Enabled for changes to user discussion pages only", "radio", "enotif_usertalk" ); ?></li>
1200 <li><?php aField( $conf, "Enotif", "Enabled for changes to user discussion pages, and to pages on watchlists (not recommended for large wikis)", "radio", "enotif_allpages" ); ?></li>
1201 </ul>
1202 </div>
1203 <div class="config-desc">
1204 <p>
1205 For this feature to work, an e-mail address must be present for the user account, and the notification
1206 options in the user's preferences must be enabled. Also note the
1207 authentication option below. When testing the feature, keep in mind that your own changes will never trigger notifications to be sent to yourself.</p>
1208
1209 <p>There are additional options for fine tuning in /includes/DefaultSettings.php; copy these to your LocalSettings.php and edit them there to change them.</p>
1210 </div>
1211
1212 <div class="config-input">
1213 <label class='column'>E-mail address authentication:</label>
1214 <ul class="plain">
1215 <li><?php aField( $conf, "Eauthent", "Disabled", "radio", "eauthent_disabled" ); ?></li>
1216 <li><?php aField( $conf, "Eauthent", "Enabled", "radio", "eauthent_enabled" ); ?></li>
1217 </ul>
1218 </div>
1219 <div class="config-desc">
1220 <p>If this option is enabled, users have to confirm their e-mail address using a magic link sent to them whenever they set or change it, and only authenticated e-mail addresses can receive mails from other users and/or
1221 change notification mails. Setting this option is <B>recommended</B> for public wikis because of potential abuse of the e-mail features above.</p>
1222 </div>
1223
1224 </div>
1225
1226 <h2>Database config</h2>
1227
1228 <div class="config-section">
1229 <div class="config-input">
1230 <label class='column'>Database type:</label>
1231 <?php if (isset($errs['DBpicktype'])) print "<span class='error'>$errs[DBpicktype]</span>\n"; ?>
1232 <ul class='plain'><?php database_picker($conf) ?></ul>
1233 </div>
1234
1235 <div class="config-input" style="clear:left"><?php
1236 aField( $conf, "DBserver", "Database host:" );
1237 ?></div>
1238 <p class="config-desc">
1239 If your database server isn't on your web server, enter the name or IP address here.
1240 </p>
1241
1242 <div class="config-input"><?php
1243 aField( $conf, "DBname", "Database name:" );
1244 ?></div>
1245 <div class="config-input"><?php
1246 aField( $conf, "DBuser", "DB username:" );
1247 ?></div>
1248 <div class="config-input"><?php
1249 aField( $conf, "DBpassword", "DB password:", "password" );
1250 ?></div>
1251 <div class="config-input"><?php
1252 aField( $conf, "DBpassword2", "DB password confirm:", "password" );
1253 ?></div>
1254 <p class="config-desc">
1255 If you only have a single user account and database available,
1256 enter those here. If you have database root access (see below)
1257 you can specify new accounts/databases to be created. This account
1258 will not be created if it pre-exists. If this is the case, ensure that it
1259 has SELECT, INSERT, UPDATE, and DELETE permissions on the MediaWiki database.
1260 </p>
1261
1262 <div class="config-input">
1263 <label class="column">Superuser account:</label>
1264 <input type="checkbox" name="useroot" id="useroot" <?php if( $useRoot ) { ?>checked="checked" <?php } ?>/>
1265 &nbsp;<label for="useroot">Use superuser account</label>
1266 </div>
1267 <div class="config-input">
1268 <?php
1269 aField( $conf, "RootUser", "Superuser name:", "superuser" );
1270 ?>
1271 </div>
1272 <div class="config-input">
1273 <?php
1274 aField( $conf, "RootPW", "Superuser password:", "password" );
1275 ?>
1276 </div>
1277
1278 <p class="config-desc">
1279 If the database user specified above does not exist, or does not have access to create
1280 the database (if needed) or tables within it, please check the box and provide details
1281 of a superuser account, such as <strong>root</strong>, which does.
1282 </p>
1283
1284 <?php database_switcher('mysql'); ?>
1285 <div class="config-input"><?php
1286 aField( $conf, "DBprefix", "Database table prefix:" );
1287 ?></div>
1288 <div class="config-desc">
1289 <p>If you need to share one database between multiple wikis, or
1290 between MediaWiki and another web application, you may choose to
1291 add a prefix to all the table names to avoid conflicts.</p>
1292
1293 <p>Avoid exotic characters; something like <tt>mw_</tt> is good.</p>
1294 </div>
1295
1296 <div class="config-input"><label class="column">Database charset</label>
1297 <div>Select one:</div>
1298 <ul class="plain">
1299 <li><?php aField( $conf, "DBschema", "Backwards-compatible UTF-8", "radio", "mysql4" ); ?></li>
1300 <li><?php aField( $conf, "DBschema", "Experimental MySQL 4.1/5.0 UTF-8", "radio", "mysql5" ); ?></li>
1301 <li><?php aField( $conf, "DBschema", "Experimental MySQL 4.1/5.0 binary", "radio", "mysql5-binary" ); ?></li>
1302 </ul>
1303 </div>
1304 <p class="config-desc">
1305 <b>EXPERIMENTAL:</b> You can enable explicit Unicode charset support
1306 for MySQL 4.1 and 5.0 servers. This is not well tested and may
1307 cause things to break. <b>If upgrading an older installation, leave
1308 in backwards-compatible mode.</b>
1309 </p>
1310 </div>
1311
1312 <?php database_switcher('postgres'); ?>
1313 <div class="config-input"><?php
1314 aField( $conf, "DBport", "Database port:" );
1315 ?></div>
1316 <div class="config-input"><?php
1317 aField( $conf, "DBmwschema", "Schema for mediawiki:" );
1318 ?></div>
1319 <div class="config-input"><?php
1320 aField( $conf, "DBts2schema", "Schema for tsearch2:" );
1321 ?></div>
1322 <div class="config-desc">
1323 <p>The username specified above (at "DB username") will have its search path set to the above schemas,
1324 so it is recommended that you create a new user. The above schemas are generally correct:
1325 only change them if you are sure you need to.</p>
1326 </div>
1327 </div>
1328
1329 <div class="config-input" style="padding:2em 0 3em">
1330 <label class='column'>&nbsp;</label>
1331 <input type="submit" value="Install MediaWiki!" class="btn-install" />
1332 </div>
1333
1334 </div>
1335
1336 <script type="text/javascript">
1337 window.onload = toggleDBarea('<?php echo $conf->DBtype; ?>',
1338 <?php
1339 ## If they passed in a root user name, don't populate it on page load
1340 echo strlen(importPost('RootUser', '')) ? 0 : 1;
1341 ?>);
1342 </script>
1343
1344 </form>
1345
1346 <?php
1347 }
1348
1349 /* -------------------------------------------------------------------------------------- */
1350 function writeSuccessMessage() {
1351 if ( ini_get( 'safe_mode' ) && !ini_get( 'open_basedir' ) ) {
1352 echo <<<EOT
1353 <p>Installation successful!</p>
1354 <p>To complete the installation, please do the following:
1355 <ol>
1356 <li>Download config/LocalSettings.php with your FTP client or file manager</li>
1357 <li>Upload it to the parent directory</li>
1358 <li>Delete config/LocalSettings.php</li>
1359 <li>Start using <a href='../index.php'>your wiki</a>!
1360 </ol>
1361 <p>If you are in a shared hosting environment, do <strong>not</strong> just move LocalSettings.php
1362 remotely. LocalSettings.php is currently owned by the user your webserver is running under,
1363 which means that anyone on the same server can read your database password! Downloading
1364 it and uploading it again will hopefully change the ownership to a user ID specific to you.</p>
1365 EOT;
1366 } else {
1367 echo "<p><span style='font-weight:bold;color:green;font-size:110%'>Installation successful!</span> Move the <tt>config/LocalSettings.php</tt> file into the parent directory, then follow
1368 <strong><a href='../index.php'>this link</a></strong> to your wiki.</p>\n";
1369 }
1370 }
1371
1372
1373 function escapePhpString( $string ) {
1374 return strtr( $string,
1375 array(
1376 "\n" => "\\n",
1377 "\r" => "\\r",
1378 "\t" => "\\t",
1379 "\\" => "\\\\",
1380 "\$" => "\\\$",
1381 "\"" => "\\\""
1382 ));
1383 }
1384
1385 function writeLocalSettings( $conf ) {
1386 $conf->PasswordSender = $conf->EmergencyContact;
1387 $magic = ($conf->ImageMagick ? "" : "# ");
1388 $convert = ($conf->ImageMagick ? $conf->ImageMagick : "/usr/bin/convert" );
1389 $rights = ($conf->RightsUrl) ? "" : "# ";
1390 $hashedUploads = $conf->safeMode ? '' : '# ';
1391
1392 switch ( $conf->Shm ) {
1393 case 'memcached':
1394 $cacheType = 'CACHE_MEMCACHED';
1395 $mcservers = var_export( $conf->MCServerArray, true );
1396 break;
1397 case 'turck':
1398 case 'apc':
1399 case 'eaccel':
1400 $cacheType = 'CACHE_ACCEL';
1401 $mcservers = 'array()';
1402 break;
1403 default:
1404 $cacheType = 'CACHE_NONE';
1405 $mcservers = 'array()';
1406 }
1407
1408 if ( $conf->Email == 'email_enabled' ) {
1409 $enableemail = 'true';
1410 $enableuseremail = ( $conf->Emailuser == 'emailuser_enabled' ) ? 'true' : 'false' ;
1411 $eauthent = ( $conf->Eauthent == 'eauthent_enabled' ) ? 'true' : 'false' ;
1412 switch ( $conf->Enotif ) {
1413 case 'enotif_usertalk':
1414 $enotifusertalk = 'true';
1415 $enotifwatchlist = 'false';
1416 break;
1417 case 'enotif_allpages':
1418 $enotifusertalk = 'true';
1419 $enotifwatchlist = 'true';
1420 break;
1421 default:
1422 $enotifusertalk = 'false';
1423 $enotifwatchlist = 'false';
1424 }
1425 } else {
1426 $enableuseremail = 'false';
1427 $enableemail = 'false';
1428 $eauthent = 'false';
1429 $enotifusertalk = 'false';
1430 $enotifwatchlist = 'false';
1431 }
1432
1433 $file = @fopen( "/dev/urandom", "r" );
1434 if ( $file ) {
1435 $secretKey = bin2hex( fread( $file, 32 ) );
1436 fclose( $file );
1437 } else {
1438 $secretKey = "";
1439 for ( $i=0; $i<8; $i++ ) {
1440 $secretKey .= dechex(mt_rand(0, 0x7fffffff));
1441 }
1442 print "<li>Warning: \$wgSecretKey key is insecure, generated with mt_rand(). Consider changing it manually.</li>\n";
1443 }
1444
1445 # Add slashes to strings for double quoting
1446 $slconf = array_map( "escapePhpString", get_object_vars( $conf ) );
1447 if( $conf->License == 'gfdl' ) {
1448 # Needs literal string interpolation for the current style path
1449 $slconf['RightsIcon'] = $conf->RightsIcon;
1450 }
1451
1452 $localsettings = "
1453 # This file was automatically generated by the MediaWiki installer.
1454 # If you make manual changes, please keep track in case you need to
1455 # recreate them later.
1456 #
1457 # See includes/DefaultSettings.php for all configurable settings
1458 # and their default values, but don't forget to make changes in _this_
1459 # file, not there.
1460
1461 # If you customize your file layout, set \$IP to the directory that contains
1462 # the other MediaWiki files. It will be used as a base to locate files.
1463 if( defined( 'MW_INSTALL_PATH' ) ) {
1464 \$IP = MW_INSTALL_PATH;
1465 } else {
1466 \$IP = dirname( __FILE__ );
1467 }
1468
1469 \$path = array( \$IP, \"\$IP/includes\", \"\$IP/languages\" );
1470 set_include_path( implode( PATH_SEPARATOR, \$path ) . PATH_SEPARATOR . get_include_path() );
1471
1472 require_once( \"includes/DefaultSettings.php\" );
1473
1474 # If PHP's memory limit is very low, some operations may fail.
1475 " . ($conf->raiseMemory ? '' : '# ' ) . "ini_set( 'memory_limit', '20M' );" . "
1476
1477 if ( \$wgCommandLineMode ) {
1478 if ( isset( \$_SERVER ) && array_key_exists( 'REQUEST_METHOD', \$_SERVER ) ) {
1479 die( \"This script must be run from the command line\\n\" );
1480 }
1481 }
1482 ## Uncomment this to disable output compression
1483 # \$wgDisableOutputCompression = true;
1484
1485 \$wgSitename = \"{$slconf['Sitename']}\";
1486
1487 ## The URL base path to the directory containing the wiki;
1488 ## defaults for all runtime URL paths are based off of this.
1489 \$wgScriptPath = \"{$slconf['ScriptPath']}\";
1490
1491 ## For more information on customizing the URLs please see:
1492 ## http://www.mediawiki.org/wiki/Manual:Short_URL
1493
1494 \$wgEnableEmail = $enableemail;
1495 \$wgEnableUserEmail = $enableuseremail;
1496
1497 \$wgEmergencyContact = \"{$slconf['EmergencyContact']}\";
1498 \$wgPasswordSender = \"{$slconf['PasswordSender']}\";
1499
1500 ## For a detailed description of the following switches see
1501 ## http://meta.wikimedia.org/Enotif and http://meta.wikimedia.org/Eauthent
1502 ## There are many more options for fine tuning available see
1503 ## /includes/DefaultSettings.php
1504 ## UPO means: this is also a user preference option
1505 \$wgEnotifUserTalk = $enotifusertalk; # UPO
1506 \$wgEnotifWatchlist = $enotifwatchlist; # UPO
1507 \$wgEmailAuthentication = $eauthent;
1508
1509 \$wgDBtype = \"{$slconf['DBtype']}\";
1510 \$wgDBserver = \"{$slconf['DBserver']}\";
1511 \$wgDBname = \"{$slconf['DBname']}\";
1512 \$wgDBuser = \"{$slconf['DBuser']}\";
1513 \$wgDBpassword = \"{$slconf['DBpassword']}\";
1514
1515 # MySQL specific settings
1516 \$wgDBprefix = \"{$slconf['DBprefix']}\";
1517
1518 # MySQL table options to use during installation or update
1519 \$wgDBTableOptions = \"{$slconf['DBTableOptions']}\";
1520
1521 # Experimental charset support for MySQL 4.1/5.0.
1522 \$wgDBmysql5 = {$conf->DBmysql5};
1523
1524 # Postgres specific settings
1525 \$wgDBport = \"{$slconf['DBport']}\";
1526 \$wgDBmwschema = \"{$slconf['DBmwschema']}\";
1527 \$wgDBts2schema = \"{$slconf['DBts2schema']}\";
1528
1529 ## Shared memory settings
1530 \$wgMainCacheType = $cacheType;
1531 \$wgMemCachedServers = $mcservers;
1532
1533 ## To enable image uploads, make sure the 'images' directory
1534 ## is writable, then set this to true:
1535 \$wgEnableUploads = false;
1536 {$magic}\$wgUseImageMagick = true;
1537 {$magic}\$wgImageMagickConvertCommand = \"{$convert}\";
1538
1539 ## If you want to use image uploads under safe mode,
1540 ## create the directories images/archive, images/thumb and
1541 ## images/temp, and make them all writable. Then uncomment
1542 ## this, if it's not already uncommented:
1543 {$hashedUploads}\$wgHashedUploadDirectory = false;
1544
1545 ## If you have the appropriate support software installed
1546 ## you can enable inline LaTeX equations:
1547 \$wgUseTeX = false;
1548
1549 \$wgLocalInterwiki = \$wgSitename;
1550
1551 \$wgLanguageCode = \"{$slconf['LanguageCode']}\";
1552
1553 \$wgProxyKey = \"$secretKey\";
1554
1555 ## Default skin: you can change the default skin. Use the internal symbolic
1556 ## names, ie 'standard', 'nostalgia', 'cologneblue', 'monobook':
1557 \$wgDefaultSkin = 'monobook';
1558
1559 ## For attaching licensing metadata to pages, and displaying an
1560 ## appropriate copyright notice / icon. GNU Free Documentation
1561 ## License and Creative Commons licenses are supported so far.
1562 {$rights}\$wgEnableCreativeCommonsRdf = true;
1563 \$wgRightsPage = \"\"; # Set to the title of a wiki page that describes your license/copyright
1564 \$wgRightsUrl = \"{$slconf['RightsUrl']}\";
1565 \$wgRightsText = \"{$slconf['RightsText']}\";
1566 \$wgRightsIcon = \"{$slconf['RightsIcon']}\";
1567 # \$wgRightsCode = \"{$slconf['RightsCode']}\"; # Not yet used
1568
1569 \$wgDiff3 = \"{$slconf['diff3']}\";
1570
1571 # When you make changes to this configuration file, this will make
1572 # sure that cached pages are cleared.
1573 \$configdate = gmdate( 'YmdHis', @filemtime( __FILE__ ) );
1574 \$wgCacheEpoch = max( \$wgCacheEpoch, \$configdate );
1575 "; ## End of setting the $localsettings string
1576
1577 // Keep things in Unix line endings internally;
1578 // the system will write out as local text type.
1579 return str_replace( "\r\n", "\n", $localsettings );
1580 }
1581
1582 function dieout( $text ) {
1583 die( $text . "\n\n</body>\n</html>" );
1584 }
1585
1586 function importVar( &$var, $name, $default = "" ) {
1587 if( isset( $var[$name] ) ) {
1588 $retval = $var[$name];
1589 if ( get_magic_quotes_gpc() ) {
1590 $retval = stripslashes( $retval );
1591 }
1592 } else {
1593 $retval = $default;
1594 }
1595 return $retval;
1596 }
1597
1598 function importPost( $name, $default = "" ) {
1599 return importVar( $_POST, $name, $default );
1600 }
1601
1602 function importCheck( $name ) {
1603 return isset( $_POST[$name] );
1604 }
1605
1606 function importRequest( $name, $default = "" ) {
1607 return importVar( $_REQUEST, $name, $default );
1608 }
1609
1610 $radioCount = 0;
1611
1612 function aField( &$conf, $field, $text, $type = "text", $value = "", $onclick = '' ) {
1613 global $radioCount;
1614 if( $type != "" ) {
1615 $xtype = "type=\"$type\"";
1616 } else {
1617 $xtype = "";
1618 }
1619
1620 $id = $field;
1621 $nolabel = ($type == "radio") || ($type == "hidden");
1622
1623 if ($type == 'radio')
1624 $id .= $radioCount++;
1625
1626 if( $nolabel ) {
1627 echo "\t\t<label>";
1628 } else {
1629 echo "\t\t<label class='column' for=\"$id\">$text</label>\n";
1630 }
1631
1632 if( $type == "radio" && $value == $conf->$field ) {
1633 $checked = "checked='checked'";
1634 } else {
1635 $checked = "";
1636 }
1637 echo "\t\t<input $xtype name=\"$field\" id=\"$id\" class=\"iput-$type\" $checked ";
1638 if ($onclick) {
1639 echo " onclick='toggleDBarea(\"$value\",1)' " ;
1640 }
1641 echo "value=\"";
1642 if( $type == "radio" ) {
1643 echo htmlspecialchars( $value );
1644 } else {
1645 echo htmlspecialchars( $conf->$field );
1646 }
1647
1648
1649 echo "\" />\n";
1650 if( $nolabel ) {
1651 echo " $text</label>\n";
1652 }
1653
1654 global $errs;
1655 if(isset($errs[$field])) echo "<span class='error'>" . $errs[$field] . "</span>\n";
1656 }
1657
1658 function getLanguageList() {
1659 global $wgLanguageNames;
1660 if( !isset( $wgLanguageNames ) ) {
1661 require_once( "languages/Names.php" );
1662 }
1663
1664 $codes = array();
1665
1666 $d = opendir( "../languages/messages" );
1667 /* In case we are called from the root directory */
1668 if (!$d)
1669 $d = opendir( "languages/messages");
1670 while( false !== ($f = readdir( $d ) ) ) {
1671 $m = array();
1672 if( preg_match( '/Messages([A-Z][a-z_]+)\.php$/', $f, $m ) ) {
1673 $code = str_replace( '_', '-', strtolower( $m[1] ) );
1674 if( isset( $wgLanguageNames[$code] ) ) {
1675 $name = $code . ' - ' . $wgLanguageNames[$code];
1676 } else {
1677 $name = $code;
1678 }
1679 $codes[$code] = $name;
1680 }
1681 }
1682 closedir( $d );
1683 ksort( $codes );
1684 return $codes;
1685 }
1686
1687 #Check for location of an executable
1688 # @param string $loc single location to check
1689 # @param array $names filenames to check for.
1690 # @param mixed $versioninfo array of details to use when checking version, use false for no version checking
1691 function locate_executable($loc, $names, $versioninfo = false) {
1692 if (!is_array($names))
1693 $names = array($names);
1694
1695 foreach ($names as $name) {
1696 $command = "$loc".DIRECTORY_SEPARATOR."$name";
1697 if (file_exists($command)) {
1698 if (!$versioninfo)
1699 return $command;
1700
1701 $file = str_replace('$1', $command, $versioninfo[0]);
1702 if (strstr(`$file`, $versioninfo[1]) !== false)
1703 return $command;
1704 }
1705 }
1706 return false;
1707 }
1708
1709 # Test a memcached server
1710 function testMemcachedServer( $server ) {
1711 $hostport = explode(":", $server);
1712 $errstr = false;
1713 $fp = false;
1714 if ( !function_exists( 'fsockopen' ) ) {
1715 $errstr = "Can't connect to memcached, fsockopen() not present";
1716 }
1717 if ( !$errstr && count( $hostport ) != 2 ) {
1718 $errstr = 'Please specify host and port';
1719 var_dump( $hostport );
1720 }
1721 if ( !$errstr ) {
1722 list( $host, $port ) = $hostport;
1723 $errno = 0;
1724 $fsockerr = '';
1725
1726 $fp = @fsockopen( $host, $port, $errno, $fsockerr, 1.0 );
1727 if ( $fp === false ) {
1728 $errstr = "Cannot connect to memcached on $host:$port : $fsockerr";
1729 }
1730 }
1731 if ( !$errstr ) {
1732 $command = "version\r\n";
1733 $bytes = fwrite( $fp, $command );
1734 if ( $bytes != strlen( $command ) ) {
1735 $errstr = "Cannot write to memcached socket on $host:$port";
1736 }
1737 }
1738 if ( !$errstr ) {
1739 $expected = "VERSION ";
1740 $response = fread( $fp, strlen( $expected ) );
1741 if ( $response != $expected ) {
1742 $errstr = "Didn't get correct memcached response from $host:$port";
1743 }
1744 }
1745 if ( $fp ) {
1746 fclose( $fp );
1747 }
1748 if ( !$errstr ) {
1749 echo "<li>Connected to memcached on $host:$port successfully";
1750 }
1751 return $errstr;
1752 }
1753
1754 function database_picker($conf) {
1755 global $ourdb;
1756 print "\n";
1757 foreach(array_keys($ourdb) as $db) {
1758 if ($ourdb[$db]['havedriver']) {
1759 print "<li>";
1760 aField( $conf, "DBtype", $ourdb[$db]['fullname'], 'radio', $db, 'onclick');
1761 print "</li>\n";
1762 }
1763 }
1764 print "\n";
1765 }
1766
1767 function database_switcher($db) {
1768 global $ourdb;
1769 $color = $ourdb[$db]['bgcolor'];
1770 $full = $ourdb[$db]['fullname'];
1771 print "<div id='$db' style='display:none; background: $color'>\n";
1772 print "<h3>$full specific options:</h3>\n";
1773 }
1774
1775 function printListItem( $item ) {
1776 print "<li>$item</li>";
1777 }
1778
1779 ?>
1780
1781 <div class="license">
1782 <hr>
1783 <p>This program is free software; you can redistribute it and/or modify
1784 it under the terms of the GNU General Public License as published by
1785 the Free Software Foundation; either version 2 of the License, or
1786 (at your option) any later version.</p>
1787
1788 <p>This program is distributed in the hope that it will be useful,
1789 but WITHOUT ANY WARRANTY; without even the implied warranty of
1790 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1791 GNU General Public License for more details.</p>
1792
1793 <p>You should have received <a href="../COPYING">a copy of the GNU General Public License</a>
1794 along with this program; if not, write to the Free Software
1795 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1796 or <a href="http://www.gnu.org/copyleft/gpl.html">read it online</a></p>
1797 </div>
1798
1799 </div></div></div>
1800
1801
1802 <div id="column-one">
1803 <div class="portlet" id="p-logo">
1804 <a style="background-image: url(../skins/common/images/mediawiki.png);"
1805 href="http://www.mediawiki.org/"
1806 title="Main Page"></a>
1807 </div>
1808 <script type="text/javascript"> if (window.isMSIE55) fixalpha(); </script>
1809 <div class='portlet'><div class='pBody'>
1810 <ul>
1811 <li><strong><a href="http://www.mediawiki.org/">MediaWiki home</a></strong></li>
1812 <li><a href="../README">Readme</a></li>
1813 <li><a href="../RELEASE-NOTES">Release notes</a></li>
1814 <li><a href="../docs/">Documentation</a></li>
1815 <li><a href="http://meta.wikipedia.org/wiki/MediaWiki_User's_Guide">User's Guide</a></li>
1816 <li><a href="http://meta.wikimedia.org/wiki/MediaWiki_FAQ">FAQ</a></li>
1817 </ul>
1818 <p style="font-size:90%;margin-top:1em">MediaWiki is Copyright &copy; 2001-2007 by Magnus Manske, Brion Vibber, Lee Daniel Crocker, Tim Starling, Erik M&ouml;ller, Gabriel Wicke and others.</p>
1819 </div></div>
1820 </div>
1821
1822 </div>
1823
1824 </body>
1825 </html>