]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - configurator.php
Fix security bugs in the RawHtml plugin.
[SourceForge/phpwiki.git] / configurator.php
1 <?php 
2 /*
3  * Todo: 
4  *   * validate input (fix javascript, add POST checks)
5  *   * start this automatically the first time
6  *   * fix include_path
7  *   * eval index-user.php or index.php to get the actual settings.
8  *   * ask to store it in index.php or index-user.php
9  * 
10  * The file index-user.php will be generated which you can use as your index.php.
11  */
12
13 $tdwidth = 700;
14 $config_file = 'index-user.php';
15 $fs_config_file = dirname(__FILE__) . (substr(PHP_OS,0,3) == 'WIN' ? '\\' : "/") . $config_file;
16 if (isset($HTTP_POST_VARS['create']))  header('Location: configurator.php?create=1#create');
17 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", 'iso-8859-1'); 
18 ?>
19 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
20   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
21 <html xmlns="http://www.w3.org/1999/xhtml">
22 <head>
23 <!-- $Id: configurator.php,v 1.17 2003-03-17 21:24:52 dairiki Exp $ -->
24 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
25 <title>Configuration tool for PhpWiki 1.3.x</title>
26 <style type="text/css" media="screen">
27 <!--
28 /* TABLE { border: thin solid black } */
29 body { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; }
30 pre { font-size: 120%; }
31 td { border: thin solid black }
32 tr { border: none }
33 tr.hidden { border: none; display: none; }
34 td.part { background-color: #eeaaaa; color: inherit; }
35 td.instructions { background-color: #ffffee; width: <?php echo $tdwidth ?>px; color: inherit; }
36 td.unchangeable-variable-top   { border-bottom: none; background-color: #eeeeee; color:inherit; }
37 td.unchangeable-variable-left  { border-top: none; background-color: #eeeeee; color:inherit; }
38 -->
39 </style>
40 <script language="JavaScript" type="text/javascript">
41 <!--
42 function update(accepted, error, value, output) {
43   if (accepted) {
44     document.getElementById(output).innerHTML = "<font color=\"green\">Input accepted.</font>";
45   } else {
46     while ((index = error.indexOf("%s")) > -1) {
47       error = error.substring(0, index) + value + error.substring(index+2);
48     }
49     document.getElementById(output).innerHTML = "<font color=\"red\">" + error + "</font>";
50   }
51 }
52
53 function validate(error, value, output, field) {
54   update(field.value == value, error, field.value, output);
55 }
56
57 function validate_ereg(error, ereg, output, field) {
58   regex = new RegExp(ereg);
59   update(regex.test(field.value), error, field.value, output);
60 }
61
62 function validate_range(error, low, high, empty_ok, output, field) {
63   update((empty_ok == 1 && field.value == "") ||
64          (field.value >= low && field.value <= high),
65          error, field.value, output);
66 }
67
68 function toggle_group(id) {
69   var text = document.getElementById(id + "_text");
70   var do_hide = false;
71   if (text.innerHTML == "Hide options.") {
72     do_hide = true;
73     text.innerHTML = "Show options.";
74   } else {
75     text.innerHTML = "Hide options.";
76   }
77
78   var rows = document.getElementsByTagName('tr');
79   var i = 0;
80   for (i = 0; i < rows.length; i++) {
81     var tr = rows[i];
82     if (tr.className == 'header' && tr.id == id) {
83       i++;
84       break;
85     }
86   }
87   for (; i < rows.length; i++) {
88     var tr = rows[i];
89     if (tr.className == 'header')
90       break;
91     tr.className = do_hide ? 'hidden': 'nonhidden';
92   }
93 }
94
95 function do_init() {
96   // Hide all groups.  We do this via JavaScript to avoid
97   // hiding the groups if JavaScript is not supported...
98   var rows = document.getElementsByTagName('tr');
99   for (var i = 0; i < rows.length; i++) {
100     var tr = rows[i];
101     if (tr.className == 'header')
102       toggle_group(tr.id);
103   }
104
105   // Select text in textarea upon focus
106   var area = document.getElementById('config-output');
107   if (area) {
108     listener = { handleEvent: function (e) { area.select(); } };
109     area.addEventListener('focus', listener, false);
110   }
111 }
112   
113 -->
114 </script>
115 </head>
116 <body onload="do_init();">
117
118 <h1>Configuration tool for PhpWiki 1.3.x</h1>
119
120 <?php
121 //define('DEBUG', 1);
122 /**
123  * The Configurator is a php script to aid in the configuration of PhpWiki.
124  * Parts of this file are based on PHPWeather's configurator.php file.
125  * http://sourceforge.net/projects/phpweather/
126  *
127  *
128  * TO CHANGE THE CONFIGURATION OF YOUR PHPWIKI, DO *NOT* MODIFY THIS FILE!
129  * more instructions go here
130  *
131  * Todo: 
132  *   * start this automatically the first time
133  *   * fix include_path
134  *   * eval index.php to get the actual settings.
135  *   * ask to store it in index.php or settings.php
136  * 
137  * The file settings.php will be generated which you can use as your index.php.
138  */
139
140
141 //////////////////////////////
142 // begin configuration options
143
144
145 /**
146  * Notes for the description parameter of $property:
147  *
148  * - Descriptive text will be changed into comments (preceeded by //)
149  *   for the final output to index.php.
150  *
151  * - Only a limited set of html is allowed: pre, dl dt dd; it will be
152  *   stripped from the final output.
153  *
154  * - Line breaks and spacing will be preserved for the final output.
155  *
156  * - Double line breaks are automatically converted to paragraphs
157  *   for the html version of the descriptive text.
158  *
159  * - Double-quotes and dollar signs in the descriptive text must be
160  *   escaped: \" and \$. Instead of escaping double-quotes you can use 
161  *   single (') quotes for the enclosing quotes. 
162  *
163  * - Special characters like < and > must use html entities,
164  *   they will be converted back to characters for the final output.
165  */
166
167 $SEPARATOR = "///////////////////////////////////////////////////////////////////";
168
169 $copyright = '
170 Copyright 1999, 2000, 2001, 2002 $ThePhpWikiProgrammingTeam = array(
171 "Steve Wainstead", "Clifford A. Adams", "Lawrence Akka", 
172 "Scott R. Anderson", "Jon Åslund", "Neil Brown", "Jeff Dairiki",
173 "Stéphane Gourichon", "Jan Hidders", "Arno Hollosi", "John Jorgensen",
174 "Antti Kaihola", "Jeremie Kass", "Carsten Klapp", "Marco Milanesi",
175 "Grant Morgan", "Jan Nieuwenhuizen", "Aredridel Niothke", 
176 "Pablo Roca Rozas", "Sandino Araico Sánchez", "Joel Uckelman", 
177 "Reini Urban", "Tim Voght", "Jochen Kalmbach");
178
179 This file is part of PhpWiki.
180
181 PhpWiki is free software; you can redistribute it and/or modify
182 it under the terms of the GNU General Public License as published by
183 the Free Software Foundation; either version 2 of the License, or
184 (at your option) any later version.
185
186 PhpWiki is distributed in the hope that it will be useful,
187 but WITHOUT ANY WARRANTY; without even the implied warranty of
188 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
189 GNU General Public License for more details.
190
191 You should have received a copy of the GNU General Public License
192 along with PhpWiki; if not, write to the Free Software
193 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
194 ';
195
196
197
198 $preamble = "
199   This is the starting file for PhpWiki. All this file does is set
200   configuration options, and at the end of the file it includes() the
201   file lib/main.php, where the real action begins.
202
203   If you include this file to override the default settings here, 
204   you must also include lib/main.php.
205
206   This file is divided into seven parts: Parts Zero, One, Two, Three,
207   Four, Five and Six. Each one has different configuration settings you can
208   change; in all cases the default should work on your system,
209   however, we recommend you tailor things to your particular setting.
210 ";
211
212
213
214 $properties["Part Zero"] =
215 new part('_part0', false, "
216 Part Zero: If PHP needs help in finding where you installed the
217 rest of the PhpWiki code, you can set the include_path here.");
218
219 if (substr(PHP_OS,0,3) == 'WIN') {
220     $include_path = dirname(__FILE__) . ';' . ini_get('include_path');
221     if (strchr(ini_get('include_path'),'/'))
222         $include_path = strtr($include_path,'\\','/');
223 } else {
224     $include_path = dirname(__FILE__) . ':' . ini_get('include_path');
225 }
226
227 $properties["PHP include_path"] =
228 new _ini_set('include_path', $include_path, "
229 Define PHP's include path so that it can find the PHP source code
230 for this PhpWiki.
231
232 You shouldn't need to do this unless you've moved index.php out
233 of the PhpWiki install directory.
234
235 Note that on Windows-based servers, you should use ; rather than :
236 as the path separator.");
237
238 $properties["Part Null"] =
239 new part('_partnullheader', "", "
240 Part Null: Don't touch this!");
241
242
243
244 $properties["Part Null Settings"] =
245 new unchangeable_variable('_partnullsettings', "
246 define ('PHPWIKI_VERSION', '1.3.5pre');
247 require \"lib/prepend.php\";
248 rcs_id('\$Id: configurator.php,v 1.17 2003-03-17 21:24:52 dairiki Exp $');", "");
249
250
251 $properties["Part One"] =
252 new part('_partone', $SEPARATOR."\n", "
253
254 Part One:
255 Authentication and security settings. See Part Three for more.
256 ");
257
258
259
260 $properties["Wiki Name"] =
261 new _define_optional('WIKI_NAME', 'PhpWiki', "
262 The name of your wiki.
263 This is used to generate a keywords meta tag in the HTML templates,
264 in bookmark titles for any bookmarks made to pages in your wiki,
265 and during RSS generation for the title of the RSS channel.");
266
267
268 $properties["Reverse DNS"] =
269 new boolean_define_optional
270 ('ENABLE_REVERSE_DNS',
271  array('true'  => "true. perform additional reverse dns lookups",
272        'false' => "false. just record the address as given by the httpd server"),
273
274 If set, we will perform reverse dns lookups to try to convert the
275 users IP number to a host name, even if the http server didn't do it for us.");
276
277 $properties["Admin Username"] =
278 new _define_optional_notempty('ADMIN_USER', "", "
279 You must set this! Username and password of the administrator.",
280 "onchange=\"validate_ereg('Sorry, ADMIN_USER cannot be empty.', '^.+$', 'ADMIN_USER', this);\"");
281
282 $properties["Admin Password"] =
283 new _define_password_optional('ADMIN_PASSWD', "", "
284 For heaven's sake pick a good password.
285 If your version of PHP supports encrypted passwords, your password will be
286 automatically encrypted within the generated config file. 
287 Use the \"Create Password\" button to create a good (random) password.",
288 "onchange=\"validate_ereg('Sorry, ADMIN_PASSWD must be at least 4 chars long.', '^....+$', 'ADMIN_PASSWD', this);\"");
289
290
291 $properties["ZIPdump Authentication"] =
292 new boolean_define_optional('ZIPDUMP_AUTH', 
293                     array('false' => "false. Everyone may download zip dumps",
294                           'true'  => "true. Only admin may download zip dumps"), "
295 If true, only the admin user can make zip dumps, else zip dumps
296 require no authentication.");
297
298 $properties["Enable Plugin RawHtml"] =
299 new boolean_define_commented_optional
300 ('ENABLE_RAW_HTML', 
301  array('true'  => "Enabled",
302        'false' => "Disabled."), "
303 Allow &lt; ?plugin RawHtml ...&gt;. Define to false to disalbe the RawHtml plugin.");
304
305 $properties["Strict Mailable Pagedumps"] =
306 new boolean_define_optional
307 ('STRICT_MAILABLE_PAGEDUMPS', 
308  array('false' => "binary",
309        'true'  => "quoted-printable"),
310 "
311 If you define this to true, (MIME-type) page-dumps (either zip dumps,
312 or \"dumps to directory\" will be encoded using the quoted-printable
313 encoding.  If you're actually thinking of mailing the raw page dumps,
314 then this might be useful, since (among other things,) it ensures
315 that all lines in the message body are under 80 characters in length.
316
317 Also, setting this will cause a few additional mail headers
318 to be generated, so that the resulting dumps are valid
319 RFC 2822 e-mail messages.
320
321 Probably, you can just leave this set to false, in which case you get
322 raw ('binary' content-encoding) page dumps.");
323
324
325
326 $properties["HTML Dump Filename Suffix"] =
327 new _variable('HTML_DUMP_SUFFIX', ".html", "
328 Here you can change the filename suffix used for XHTML page dumps.
329 If you don't want any suffix just comment this out.");
330
331
332
333 //FIXME: should be numeric_define_optional
334 $properties["Maximum Upload Size"] =
335 new numeric_define('MAX_UPLOAD_SIZE', "16 * 1024 * 1024", "
336 The maximum file upload size.");
337
338
339
340 //FIXME: should be numeric_define_optional
341 $properties["Minor Edit Timeout"] =
342 new numeric_define('MINOR_EDIT_TIMEOUT', "7 * 24 * 3600", "
343 If the last edit is older than MINOR_EDIT_TIMEOUT seconds, the
344 default state for the \"minor edit\" checkbox on the edit page form
345 will be off.");
346
347
348
349 $properties["Disabled Actions"] =
350 new array_variable('DisabledActions', array(), "
351 Actions listed in this array will not be allowed. Actions are:
352 browse, create, diff, dumphtml, dumpserial, edit, loadfile, lock, remove, 
353 unlock, upload, viewsource, zip, ziphtml");
354
355 $properties["Access Log"] =
356 new _define_commented('ACCESS_LOG', "/var/logs/wiki_access.log", "
357 PhpWiki can generate an access_log (in \"NCSA combined log\" format)
358 for you. If you want one, define this to the name of the log file,
359 such as /tmp/wiki_access_log.");
360
361 $properties["Compress Output"] =
362 new boolean_define_commented_optional
363 ( 'COMPRESS_OUTPUT', 
364   array(''  => 'Compress when PhpWiki thinks approriate.',
365         'false' => 'Never compress output.',
366         'true' => 'Always try to compress output.'),
367   "
368 By default PhpWiki will try to have PHP compress it's output
369 before sending it to the browser (if you have a recent enough
370 version of PHP and the browser supports it.)
371
372 Define COMPRESS_OUTPUT to false to prevent output compression.
373
374 Define COMPRESS_OUTPUT to true to force output compression,
375 even if we think your version of PHP does this in a buggy
376 fashion.
377
378 Leave it undefined to leave the choice up to PhpWiki.");
379
380 $properties["HTTP Cache Control"] =
381 new _define_selection_optional
382 ('CACHE_CONTROL',
383  array('LOOSE' => 'LOOSE',
384        'STRICT' => 'STRICT',
385        'NONE' => 'NONE',
386        'ALLOW_STALE' => 'ALLOW_STALE'),
387  "
388 HTTP CACHE_CONTROL
389
390 This controls how PhpWiki sets the HTTP cache control
391 headers (Expires: and Cache-Control:) 
392
393 Choose one of:
394
395 <dl>
396 <dt>NONE</dt>
397 <dd>This is roughly the old (pre 1.3.4) behavior.  PhpWiki will
398     instruct proxies and browsers never to cache PhpWiki output.</dd>
399
400 <dt>STRICT</dt>
401 <dd>Cached pages will be invalidated whenever the database global
402     timestamp changes.  This should behave just like NONE (modulo
403     bugs in PhpWiki and your proxies and browsers), except that
404     things will be slightly more efficient.</dd>
405
406 <dt>LOOSE</dt>
407 <dd>Cached pages will be invalidated whenever they are edited,
408     or, if the pages include plugins, when the plugin output could
409     concievably have changed.
410
411     <p>Behavior should be much like STRICT, except that sometimes
412        wikilinks will show up as undefined (with the question mark)
413        when in fact they refer to (recently) created pages.
414        (Hitting your browsers reload or perhaps shift-reload button
415        should fix the problem.)</p></dd>
416
417 <dt>ALLOW_STALE</dt>
418 <dd>Proxies and browsers will be allowed to used stale pages.
419     (The timeout for stale pages is controlled by CACHE_CONTROL_MAX_AGE.)
420
421     <p>This setting will result in quirky behavior.  When you edit a
422        page your changes may not show up until you shift-reload the
423        page, etc...</p>
424
425     <p>This setting is generally not advisable, however it may be useful
426        in certain cases (e.g. if your wiki gets lots of page views,
427        and few edits by knowledgable people who won't freak over the quirks.)</p>
428 </dd>
429
430 The default is currently LOOSE.");
431
432 // FIXME: should be numeric_define_optional
433 $properties["HTTP Cache Control Max Age"] =
434 new numeric_define('CACHE_CONTROL_MAX_AGE', 600,
435             "
436 Maximum page staleness, in seconds.");
437
438 $properties["Markup Caching"] =
439 new boolean_define_commented_optional
440 ('WIKIDB_NOCACHE_MARKUP',
441  array('false' => 'Enable markup cache',
442        'true' => 'Disable markup cache'),
443  "
444 MARKUP CACHING
445
446 PhpWiki normally caches a preparsed version (i.e. mostly
447 converted to HTML) of the most recent version of each page.
448 (Parsing the wiki-markup takes a fair amount of CPU.)
449
450 Define WIKIDB_NOCACHE_MARKUP to true to disable the
451 caching of marked-up page content.
452
453 Note that you can also disable markup caching on a per-page
454 temporary basis by addinging a query arg of '?nocache=1'
455 to the URL to the page.  (Use '?nocache=purge' to completely
456 discard the cached version of the page.)
457
458 You can also purge the cached markup globally by using the
459 \"Purge Markup Cache\" button on the PhpWikiAdministration page.");
460
461
462 $properties["Path for PHP Session Support"] =
463 new _ini_set('session.save_path', '/tmp', "
464 The login code now uses PHP's session support. Usually, the default
465 configuration of PHP is to store the session state information in
466 /tmp. That probably will work fine, but fails e.g. on clustered
467 servers where each server has their own distinct /tmp (this is the
468 case on SourceForge's project web server.) You can specify an
469 alternate directory in which to store state information like so
470 (whatever user your httpd runs as must have read/write permission
471 in this directory):");
472
473
474
475 $properties["Disable PHP Transparent Session ID"] =
476 new unchangeable_ini_set('session.use_trans_sid', "@ini_set('session.use_trans_sid', 0);", "
477 If your php was compiled with --enable-trans-sid it tries to
478 add a PHPSESSID query argument to all URL strings when cookie
479 support isn't detected in the client browser.  For reasons
480 which aren't entirely clear (PHP bug) this screws up the URLs
481 generated by PhpWiki.  Therefore, transparent session ids
482 should be disabled.  This next line does that.
483
484 (At the present time, you will not be able to log-in to PhpWiki,
485 or set any user preferences, unless your browser supports cookies.)");
486
487
488
489 ///////// database selection
490
491
492 $properties["Part Two"] =
493 new part('_parttwo', $SEPARATOR."\n", "
494
495 Part Two:
496 Database Selection
497 ");
498
499
500 $properties["Database Type"] =
501 new _variable_selection("DBParams|dbtype",
502               array('dba'   => "dba DBM",
503                     'SQL'   => "SQL PEAR",
504                     'ADODB' => "SQL ADODB",
505                     'cvs'   => "CVS File handler"), "
506 Select the database backend type:
507 Choose ADODB or SQL to use an SQL database with ADODB or PEAR.
508 Choose dba to use one of the standard UNIX dbm libraries.
509 CVS is not yet tested nor supported.
510 Recommended is SQL PEAR.");
511
512 $properties["Filename / Table name Prefix"] =
513 new _variable_commented("DBParams|prefix", "phpwiki_", "
514 Used by all DB types:
515
516 Prefix for filenames or table names
517
518 Currently you MUST EDIT THE SQL file too (in the schemas/
519 directory because we aren't doing on the fly sql generation
520 during the installation.");
521
522
523 $properties["SQL dsn Setup"] =
524 new unchangeable_variable('_sqldsnstuff', "", "
525 For SQL based backends, specify the database as a DSN
526 The most general form of a DSN looks like:
527 <pre>
528   phptype(dbsyntax)://username:password@protocol+hostspec/database
529 </pre>
530 For a MySQL database, the following should work:
531 <pre>
532    mysql://user:password@host/databasename
533 </pre>
534 To connect over a unix socket, use something like
535 <pre>
536    mysql://user:password@unix(/path/to/socket)/databasename
537 </pre>
538 <pre>'dsn' => 'mysql://guest@:/var/lib/mysql/mysql.sock/test',
539 'dsn' => 'mysql://guest@localhost/test',
540 'dsn' => 'pgsql://localhost/test',</pre>");
541
542 // Choose ADODB or SQL to use an SQL database with ADODB or PEAR.
543 // Choose dba to use one of the standard UNIX dbm libraries.
544
545 $properties["SQL Type"] =
546 new _variable_selection('_dsn_sqltype',
547               array('mysql' => "MySQL",
548                     'pgsql' => "PostgreSQL"), "
549 SQL DB types");
550
551
552
553 $properties["SQL User"] =
554 new _variable('_dsn_sqluser', "wikiuser", "
555 SQL User Id:");
556
557
558
559 $properties["SQL Password"] =
560 new _variable('_dsn_sqlpass', "", "
561 SQL Password:");
562
563
564
565 $properties["SQL Database Host"] =
566 new _variable('_dsn_sqlhostorsock', "localhost", "
567 SQL Database Hostname:
568
569 To connect over a local named socket, use something like
570 <pre>
571   unix(/var/lib/mysql/mysql.sock)
572 </pre>
573 here.");
574
575
576
577 $properties["SQL Database Name"] =
578 new _variable('_dsn_sqldbname', "phpwiki", "
579 SQL Database Name:");
580
581 list($dsn_sqltype,) = $properties["SQL Type"]->value();
582 $dsn_sqluser = $properties["SQL User"]->value();
583 $dsn_sqlpass = $properties["SQL Password"]->value();
584 $dsn_sqlhostorsock = $properties["SQL Database Host"]->value();
585 $dsn_sqldbname = $properties["SQL Database Name"]->value();
586
587 $properties["SQL dsn"] =
588 new unchangeable_variable("DBParams['dsn']", 
589   "\$DBParams['dsn'] = \"\$_dsn_sqltype://{$dsn_sqluser}:{$dsn_sqlpass}@{$dsn_sqlhostorsock}/{$dsn_sqldbname}\";", "");
590
591 $properties["dba directory"] =
592 new _variable("DBParams|directory", "/tmp", "
593 dba directory:");
594
595
596 $properties["dba handler"] =
597 new _variable_selection('DBParams|dba_handler',
598               array('gdbm' => "Gdbm - GNU database manager",
599                     'dbm'  => "DBM - Redhat default. On sf.net there's dbm and gdbm",
600                     'db2'  => "DB2 - Sleepycat Software's DB2",
601                     'db3'  => "DB3 - Sleepycat Software's DB3. Fine on Windows but not on every Linux"), "
602 Use 'gdbm', 'dbm', 'db2' or 'db3' depending on your DBA handler methods supported:");
603
604 $properties["dba timeout"] =
605 new _variable("DBParams|timeout", "20", "
606 Recommended values are 20 or 5.");
607
608
609
610 ///////////////////
611
612
613
614 $properties["Page Revisions"] =
615 new unchangeable_variable('_parttworevisions', "", "
616
617 The next section controls how many old revisions of each page are
618 kept in the database.
619
620 There are two basic classes of revisions: major and minor. Which
621 class a revision belongs in is determined by whether the author
622 checked the \"this is a minor revision\" checkbox when they saved the
623 page.
624  
625 There is, additionally, a third class of revisions: author
626 revisions. The most recent non-mergable revision from each distinct
627 author is and author revision.
628
629 The expiry parameters for each of those three classes of revisions
630 can be adjusted seperately. For each class there are five
631 parameters (usually, only two or three of the five are actually
632 set) which control how long those revisions are kept in the
633 database.
634 <dl>
635    <dt>max_keep:</dt> <dd>If set, this specifies an absolute maximum for the
636             number of archived revisions of that class. This is
637             meant to be used as a safety cap when a non-zero
638             min_age is specified. It should be set relatively high,
639             and it's purpose is to prevent malicious or accidental
640             database overflow due to someone causing an
641             unreasonable number of edits in a short period of time.</dd>
642
643   <dt>min_age:</dt>  <dd>Revisions younger than this (based upon the supplanted
644             date) will be kept unless max_keep is exceeded. The age
645             should be specified in days. It should be a
646             non-negative, real number,</dd>
647
648   <dt>min_keep:</dt> <dd>At least this many revisions will be kept.</dd>
649
650   <dt>keep:</dt>     <dd>No more than this many revisions will be kept.</dd>
651
652   <dt>max_age:</dt>  <dd>No revision older than this age will be kept.</dd>
653 </dl>
654 Supplanted date: Revisions are timestamped at the instant that they
655 cease being the current revision. Revision age is computed using
656 this timestamp, not the edit time of the page.
657
658 Merging: When a minor revision is deleted, if the preceding
659 revision is by the same author, the minor revision is merged with
660 the preceding revision before it is deleted. Essentially: this
661 replaces the content (and supplanted timestamp) of the previous
662 revision with the content after the merged minor edit, the rest of
663 the page metadata for the preceding version (summary, mtime, ...)
664 is not changed.
665 ");
666
667
668 // For now the expiration parameters are statically inserted as
669 // an unchangeable property. You'll have to edit the resulting
670 // config file if you really want to change these from the default.
671
672 $properties["Expiration Parameters for Major Edits"] =
673 new unchangeable_variable('ExpireParams|major',
674 "\$ExpireParams['major'] = array('max_age' => 32,
675                                'keep'    => 8);", "
676 Keep up to 8 major edits, but keep them no longer than a month.");
677
678 $properties["Expiration Parameters for Minor Edits"] =
679 new unchangeable_variable('ExpireParams|minor',
680 "\$ExpireParams['minor'] = array('max_age' => 7,
681                                'keep'    => 4);", "
682 Keep up to 4 minor edits, but keep them no longer than a week.");
683
684
685
686 $properties["Expiration Parameters by Author"] =
687 new unchangeable_variable('ExpireParams|author',
688 "\$ExpireParams['author'] = array('max_age'  => 365,
689                                 'keep'     => 8,
690                                 'min_age'  => 7,
691                                 'max_keep' => 20);", "
692 Keep the latest contributions of the last 8 authors up to a year.
693 Additionally, (in the case of a particularly active page) try to
694 keep the latest contributions of all authors in the last week (even
695 if there are more than eight of them,) but in no case keep more
696 than twenty unique author revisions.");
697
698 /////////////////////////////////////////////////////////////////////
699
700 $properties["Part Three"] =
701 new part('_partthree', $SEPARATOR."\n", "
702
703 Part Three: (optional)
704 User Authentication
705 ");
706
707 $properties["User Authentication"] =
708 new boolean_define_optional('ALLOW_USER_LOGIN',
709                     array('true'  => "true. Check any defined passwords. (Default)",
710                           'false' => "false. Don't check passwords. Legacy &lt; 1.3.4"), "
711 If ALLOW_USER_LOGIN is true, any defined internal and external
712 authentication method is tried. 
713 If not, we don't care about passwords, but check the next two constants.");
714
715 $properties["HTTP Authentication"] =
716 new boolean_define_optional('ALLOW_HTTP_AUTH_LOGIN',
717                     array('false' => "false. Ignore HTTP Authentication. (Default)",
718                           'true'  => "true. Allow .htpasswd users login automatically."), "
719 The wiki can be optionally be protected by HTTP Auth. Use the username and password 
720 from there, and if this fails, try the other methods also.");
721
722 $properties["Strict Login"] =
723 new boolean_define_optional('ALLOW_BOGO_LOGIN',
724                     array('true'  => "Users may Sign In with any WikiWord",
725                           'false' => "Only admin may Sign In"), "
726 If ALLOW_BOGO_LOGIN is true, users are allowed to login (with
727 any/no password) using any userid which: 1) is not the ADMIN_USER,
728 2) is a valid WikiWord (matches \$WikiNameRegexp.)
729 If true, users may be created by themselves. Otherwise we need seperate auth. 
730 This might be renamed to ALLOW_SELF_REGISTRATION");
731
732 $properties["Require Sign In Before Editing"] =
733 new boolean_define_optional('REQUIRE_SIGNIN_BEFORE_EDIT',
734                     array('false' => "Do not require Sign In",
735                           'true'  => "Require Sign In"), "
736 If set, then if an anonymous user attempts to edit a page he will
737 be required to sign in.  (If ALLOW_BOGO_LOGIN is true, of course,
738 no password is required, but the user must still sign in under
739 some sort of BogoUserId.)");
740
741 if (function_exists('ldap_connect')) {
742 $properties["LDAP Authentication"] =
743   new boolean_define_optional('ALLOW_LDAP_LOGIN',
744                     array('true'  => "Allow LDAP Authentication",
745                           'false' => "Ignore LDAP"), "
746 LDAP Authentication
747 ");
748 $properties["LDAP Host"] =
749   new _define_optional('LDAP_AUTH_HOST', "localhost", "");
750 $properties["LDAP Root Search"] =
751   new _define_optional('LDAP_AUTH_SEARCH', "ou=mycompany.com,o=My Company", "
752 Give the right LDAP root search information in the next statement.");
753
754 } else {
755
756 $properties["LDAP Authentication"] =
757 new unchangeable_define('ALLOW_LDAP_LOGIN', "
758 if (!defined('ALLOW_LDAP_LOGIN')) define('ALLOW_LDAP_LOGIN', true and function_exists('ldap_connect'));
759 if (!defined('LDAP_AUTH_HOST'))   define('LDAP_AUTH_HOST', 'localhost');
760 // Give the right LDAP root search information in the next statement. 
761 if (!defined('LDAP_AUTH_SEARCH')) define('LDAP_AUTH_SEARCH', 'ou=mycompany.com,o=My Company');
762 ", "
763 Ignored. No LDAP support in this php. configure --with-ldap");
764 }
765
766 if (function_exists('imap_open')) {
767 $properties["IMAP Authentication"] =
768   new boolean_define_optional('ALLOW_IMAP_LOGIN',
769                     array('true'  => "Allow IMAP Authentication",
770                           'false' => "Ignore IMAP"), "
771 IMAP Authentication
772 ");
773 $properties["IMAP Host"] =
774   new _define_optional('IMAP_AUTH_HOST', 'localhost', '');
775 } else {
776 $properties["IMAP Authentication"] =
777   new unchangeable_define('ALLOW_IMAP_LOGIN',"
778 // IMAP auth: check userid/passwords from a imap server, defaults to localhost
779 if (!defined('ALLOW_IMAP_LOGIN')) define('ALLOW_IMAP_LOGIN', true and function_exists('imap_open'));
780 if (!defined('IMAP_AUTH_HOST'))   define('IMAP_AUTH_HOST', 'localhost');
781 ", "Ignored. No IMAP support in this php. configure --with-imap");
782 }
783
784
785 /////////////////////////////////////////////////////////////////////
786
787 $properties["Part Four"] =
788 new part('_partfour', $SEPARATOR."\n", "
789
790 Part Four:
791 Page appearance and layout
792 ");
793
794
795
796 $properties["Theme"] =
797 new _define_selection_optional('THEME',
798               array('default'  => "default",
799                     'Hawaiian' => "Hawaiian",
800                     'MacOSX'   => "MacOSX",
801                     'Portland' => "Portland",
802                     'Sidebar'  => "Sidebar",
803                     'SpaceWiki' => "SpaceWiki"), "
804 THEME
805
806 Most of the page appearance is controlled by files in the theme
807 subdirectory.
808
809 There are a number of pre-defined themes shipped with PhpWiki.
810 Or you may create your own (e.g. by copying and then modifying one of
811 stock themes.)
812
813 Pick one.
814 <pre>
815 define('THEME', 'default');
816 define('THEME', 'Hawaiian');
817 define('THEME', 'MacOSX');
818 define('THEME', 'Portland');
819 define('THEME', 'Sidebar');
820 define('THEME', 'SpaceWiki');</pre>");
821
822
823
824 $properties["Character Set"] =
825 new _define_optional('CHARSET', 'iso-8859-1', "
826 Select a valid charset name to be inserted into the xml/html pages, 
827 and to reference links to the stylesheets (css). For more info see: 
828 http://www.iana.org/assignments/character-sets. Note that PhpWiki 
829 has been extensively tested only with the latin1 (iso-8859-1) 
830 character set.
831
832 If you change the default from iso-8859-1 PhpWiki may not work 
833 properly and it will require code modifications. However, character 
834 sets similar to iso-8859-1 may work with little or no modification 
835 depending on your setup. The database must also support the same 
836 charset, and of course the same is true for the web browser. (Some 
837 work is in progress hopefully to allow more flexibility in this 
838 area in the future).");
839
840
841
842 $properties["Language"] =
843 new _define_selection_optional('DEFAULT_LANGUAGE',
844               array('en' => "English",
845                     'nl' => "Nederlands",
846                     'es' => "Español",
847                     'fr' => "Français",
848                     'de' => "Deutsch",
849                     'sv' => "Svenska",
850                     'it' => "Italiano",
851                     ''   => "none"), "
852 Select your language/locale - default language is \"en\" for English.
853 Other languages available:<pre>
854 English \"en\"  (English    - HomePage)
855 Dutch   \"nl\" (Nederlands - ThuisPagina)
856 Spanish \"es\" (Español    - PáginaPrincipal)
857 French  \"fr\" (Français   - Accueil)
858 German  \"de\" (Deutsch    - StartSeite)
859 Swedish \"sv\" (Svenska    - Framsida)
860 Italian \"it\" (Italiano   - PaginaPrincipale)
861 </pre>
862 If you set DEFAULT_LANGUAGE to the empty string, your systems default language
863 (as determined by the applicable environment variables) will be
864 used.");
865
866 $properties["Wiki Page Source"] =
867 new _define_optional('WIKI_PGSRC', 'pgsrc', "
868 WIKI_PGSRC -- specifies the source for the initial page contents of
869 the Wiki. The setting of WIKI_PGSRC only has effect when the wiki is
870 accessed for the first time (or after clearing the database.)
871 WIKI_PGSRC can either name a directory or a zip file. In either case
872 WIKI_PGSRC is scanned for files -- one file per page.
873 <pre>
874 // Default (old) behavior:
875 define('WIKI_PGSRC', 'pgsrc'); 
876 // New style:
877 define('WIKI_PGSRC', 'wiki.zip'); 
878 define('WIKI_PGSRC', 
879        '../Logs/Hamwiki/hamwiki-20010830.zip'); 
880 </pre>");
881
882
883
884 $properties["Default Wiki Page Source"] =
885 new _define('DEFAULT_WIKI_PGSRC', 'pgsrc', "
886 DEFAULT_WIKI_PGSRC is only used when the language is *not* the
887 default (English) and when reading from a directory: in that case
888 some English pages are inserted into the wiki as well.
889 DEFAULT_WIKI_PGSRC defines where the English pages reside.
890
891 FIXME: is this really needed?
892 ");
893
894
895
896 $properties["Generic Pages"] =
897 new array_variable('GenericPages', array('ReleaseNotes', 'SteveWainstead', 'TestPage'), "
898 These are the pages which will get loaded from DEFAULT_WIKI_PGSRC.      
899
900 FIXME: is this really needed?  Can't we just copy these pages into
901 the localized pgsrc?
902 ");
903
904
905
906
907 $properties["Part Five"] =
908 new part('_partfive', $SEPARATOR."\n", "
909
910 Part Five:
911 Mark-up options.
912 ");
913
914
915
916 $properties["Allowed Protocols"] =
917 new list_variable('AllowedProtocols', 'http|https|mailto|ftp|news|nntp|ssh|gopher', "
918 allowed protocols for links - be careful not to allow \"javascript:\"
919 URL of these types will be automatically linked.
920 within a named link [name|uri] one more protocol is defined: phpwiki");
921
922
923
924 $properties["Inline Images"] =
925 new list_variable('InlineImages', 'png|jpg|gif', "
926 URLs ending with the following extension should be inlined as images");
927
928
929
930 $properties["WikiName Regexp"] =
931 new _variable('WikiNameRegexp', "(?<![[:alnum:]])(?:[[:upper:]][[:lower:]]+){2,}(?![[:alnum:]])", "
932 Perl regexp for WikiNames (\"bumpy words\")
933 (?&lt;!..) &amp; (?!...) used instead of '\b' because \b matches '_' as well");
934
935 $properties["Subpage Separator"] =
936 new _define_optional('SUBPAGE_SEPARATOR', '/', "
937 One character which seperates pages from subpages. Defaults to '/', but '.' or ':' were also used.",
938 "onchange=\"validate_ereg('Sorry, \'%s\' must be a single character. Currently only :, / or .', '^[/:.]$', 'SUBPAGE_SEPARATOR', this);\""
939 );
940
941 $properties["InterWiki Map File"] =
942 new _define('INTERWIKI_MAP_FILE', 'lib/interwiki.map', "
943 InterWiki linking -- wiki-style links to other wikis on the web
944
945 The map will be taken from a page name InterWikiMap.
946 If that page is not found (or is not locked), or map
947 data can not be found in it, then the file specified
948 by INTERWIKI_MAP_FILE (if any) will be used.");
949
950 $properties["WARN_NONPUBLIC_INTERWIKIMAP"] =
951 new boolean_define('WARN_NONPUBLIC_INTERWIKIMAP',   
952         array('true'  => "true",
953                           'false' => "false"), "
954 Display a warning if the internal lib/interwiki.map is used, and 
955 not the public InterWikiMap page. This map is not readable from outside.");
956
957 $properties["Keyword Link Regexp"] =
958 new _variable('KeywordLinkRegexp',
959               '(?<=^Category|^Topic)[[:upper:]].*$',
960               "
961 Regexp used for automatic keyword extraction.
962
963 Any links on a page to pages whose names match this regexp will
964 be used keywords in the keywords meta tag.  (This is an aid to
965 classification by search engines.)  The value of the match is
966 used as the keyword.
967
968 The default behavior is to match Category* and Topic* links.");
969
970 $properties["Part Six"] =
971 new part('_partsix', $SEPARATOR."\n", "
972
973 Part Six (optional):
974 URL options -- you can probably skip this section.
975 ");
976
977 $properties["Server Name"] =
978 new _define_commented_optional('SERVER_NAME', $HTTP_SERVER_VARS['SERVER_NAME'], "
979 Canonical name and httpd port of the server on which this PhpWiki
980 resides.");
981
982
983
984 $properties["Server Port"] =
985 new numeric_define_commented('SERVER_PORT', $HTTP_SERVER_VARS['SERVER_PORT'], "",
986 "onchange=\"validate_ereg('Sorry, \'%s\' is no valid port number.', '^[0-9]+$', 'SERVER_PORT', this);\"");
987
988 $scriptname = preg_replace('/configurator.php/','index.php',$HTTP_SERVER_VARS["SCRIPT_NAME"]);
989
990 $properties["Script Name"] =
991 new _define_commented_optional('SCRIPT_NAME', $scriptname, "
992 Relative URL (from the server root) of the PhpWiki script.");
993
994 $properties["Data Path"] =
995 new _define_commented_optional('DATA_PATH', dirname($scriptname), "
996 URL of the PhpWiki install directory.  (You only need to set this
997 if you've moved index.php out of the install directory.)  This can
998 be either a relative URL (from the directory where the top-level
999 PhpWiki script is) or an absolute one.");
1000
1001
1002
1003 $properties["PhpWiki Install Directory"] =
1004 new _define_commented_optional('PHPWIKI_DIR', dirname(__FILE__), "
1005 Path to the PhpWiki install directory.  This is the local
1006 filesystem counterpart to DATA_PATH.  (If you have to set
1007 DATA_PATH, your probably have to set this as well.)  This can be
1008 either an absolute path, or a relative path interpreted from the
1009 directory where the top-level PhpWiki script (normally index.php)
1010 resides.");
1011
1012
1013
1014 $properties["Use PATH_INFO"] =
1015 new boolean_define_commented_optional('USE_PATH_INFO', 
1016                     array('true'  => 'use PATH_INFO',
1017                           'false' => 'do not use PATH_INFO'), "
1018 Define to 'true' to use PATH_INFO to pass the pagenames.
1019 e.g. http://www.some.where/index.php/HomePage instead
1020 of http://www.some.where/index.php?pagename=HomePage
1021 FIXME: more docs (maybe in README). Default: true");
1022
1023
1024
1025 $properties["Virtual Path"] =
1026 new _define_commented_optional('VIRTUAL_PATH', '/SomeWiki', "
1027 VIRTUAL_PATH is the canonical URL path under which your your wiki
1028 appears. Normally this is the same as dirname(SCRIPT_NAME), however
1029 using, e.g. apaches mod_actions (or mod_rewrite), you can make it
1030 something different.
1031
1032 If you do this, you should set VIRTUAL_PATH here.
1033
1034 E.g. your phpwiki might be installed at at /scripts/phpwiki/index.php,
1035 but you've made it accessible through eg. /wiki/HomePage.
1036
1037 One way to do this is to create a directory named 'wiki' in your
1038 server root. The directory contains only one file: an .htaccess
1039 file which reads something like:
1040 <pre>
1041     Action x-phpwiki-page /scripts/phpwiki/index.php
1042     SetHandler x-phpwiki-page
1043     DirectoryIndex /scripts/phpwiki/index.php
1044 </pre>
1045 In that case you should set VIRTUAL_PATH to '/wiki'.
1046
1047 (VIRTUAL_PATH is only used if USE_PATH_INFO is true.)
1048 ");
1049
1050
1051 $properties["Part Seven"] =
1052 new part('_partseven', $SEPARATOR."\n", "
1053
1054 Part Seven:
1055
1056 Miscellaneous settings
1057 ");
1058
1059 $properties["Pagename of Recent Changes"] =
1060 new _define_optional('RECENT_CHANGES', 'RecentChanges', "
1061 Page name of RecentChanges page.  Used for RSS Auto-discovery.");
1062
1063 $properties["Disable HTTP Redirects"] =
1064 new boolean_define_commented_optional
1065 ('DISABLE_HTTP_REDIRECT',
1066  array('false' => 'Enable HTTP Redirects',
1067        'true' => 'Disable HTTP Redirects'),
1068 "
1069 (You probably don't need to touch this.)
1070
1071 PhpWiki uses HTTP redirects for some of it's functionality.
1072 (e.g. after saving changes, PhpWiki redirects your browser to
1073 view the page you just saved.)
1074
1075 Some web service providers (notably free European Lycos) don't seem to
1076 allow these redirects.  (On Lycos the result in an \"Internal Server Error\"
1077 report.)  In that case you can set DISABLE_HTTP_REDIRECT to true.
1078 (In which case, PhpWiki will revert to sneakier tricks to try to
1079 redirect the browser...)");
1080
1081 $end = "
1082
1083 $SEPARATOR
1084 // Check if we were included by some other wiki version (getimg, en, ...) 
1085 // or not. 
1086 // If the server requested this index.php fire up the code by loading lib/main.php.
1087 // Parallel wiki scripts can now simply include /index.php for the 
1088 // main configuration, extend or redefine some settings and 
1089 // load lib/main.php by themselves. 
1090 // This overcomes the index as config problem.
1091 $SEPARATOR
1092
1093 // This doesn't work with php as CGI yet!
1094 if (defined('VIRTUAL_PATH') and defined('USE_PATH_INFO')) {
1095     if (\$HTTP_SERVER_VARS['SCRIPT_NAME'] == VIRTUAL_PATH) {
1096         include \"lib/main.php\";
1097     }
1098 } else {
1099     if (defined('SCRIPT_NAME') and 
1100         (\$HTTP_SERVER_VARS['SCRIPT_NAME'] == SCRIPT_NAME)) {
1101         include \"lib/main.php\";
1102     } elseif (strstr(\$HTTP_SERVER_VARS['PHP_SELF'],'index.php')) {
1103         include \"lib/main.php\";
1104     }
1105 }
1106
1107 // (c-file-style: \"gnu\")
1108 // Local Variables:
1109 // mode: php
1110 // tab-width: 8
1111 // c-basic-offset: 4
1112 // c-hanging-comment-ender-p: nil
1113 // indent-tabs-mode: nil
1114 // End:   
1115 ?>
1116 ";
1117
1118
1119
1120 // end of configuration options
1121 ///////////////////////////////
1122 // begin class definitions
1123
1124 /**
1125  * A basic index.php configuration line in the form of a variable.
1126  *
1127  * Produces a string in the form "$name = value;"
1128  * e.g.:
1129  * $WikiNameRegexp = "value";
1130  */
1131 class _variable {
1132
1133     var $config_item_name;
1134     var $default_value;
1135     var $description;
1136     var $prefix;
1137     var $jscheck;
1138
1139     function _variable($config_item_name, $default_value, $description, $jscheck = '') {
1140         $this->config_item_name = $config_item_name;
1141         $this->description = $description;
1142         $this->default_value = $default_value;
1143         $this->jscheck = $jscheck;
1144         if (preg_match("/variable/i",get_class($this)))
1145             $this->prefix = "\$";
1146         elseif (preg_match("/ini_set/i",get_class($this)))
1147             $this->prefix = "ini_get: ";
1148         else
1149             $this->prefix = "";
1150     }
1151
1152     function value() {
1153       global $HTTP_POST_VARS;
1154       if (isset($HTTP_POST_VARS[$this->config_item_name]))
1155           return $HTTP_POST_VARS[$this->config_item_name];
1156       else 
1157           return $this->default_value;
1158     }
1159
1160     function _config_format($value) {
1161         $v = $this->get_config_item_name();
1162         // handle arrays: a|b --> a['b']
1163         if (strpos($v, '|')) {
1164             list($a, $b) = explode('|', $v);
1165             $v = sprintf("%s['%s']", $a, $b);
1166         }
1167         return sprintf("\$%s = \"%s\";", $v, $value);
1168     }
1169
1170     function get_config_item_name() {
1171         return $this->config_item_name;
1172     }
1173
1174     function get_config_item_id() {
1175         return str_replace('|', '-', $this->config_item_name);
1176     }
1177
1178     function get_config_item_header() {
1179        if (strchr($this->config_item_name,'|')) {
1180           list($var,$param) = explode('|',$this->config_item_name);
1181           return "<b>" . $this->prefix . $var . "['" . $param . "']</b><br />";
1182        }
1183        elseif ($this->config_item_name[0] != '_')
1184           return "<b>" . $this->prefix . $this->config_item_name . "</b><br />";
1185        else 
1186           return '';
1187     }
1188
1189     function _get_description() {
1190         return $this->description;
1191     }
1192
1193     function _get_config_line($posted_value) {
1194         return "\n" . $this->_config_format($posted_value);
1195     }
1196
1197     function get_config($posted_value) {
1198         $d = stripHtml($this->_get_description());
1199         $d = str_replace("\n", "\n// ", $d) . $this->_get_config_line($posted_value) ."\n";
1200         return $d;
1201     }
1202
1203     function get_instructions($title) {
1204         global $tdwidth;
1205         $i = "<h3>" . $title . "</h3>\n    " . nl2p($this->_get_description()) . "\n";
1206         return "<tr>\n<td width=\"$tdwidth\" class=\"instructions\">\n" . $i . "</td>\n";
1207     }
1208
1209     function get_html() {
1210         return $this->get_config_item_header() . 
1211             "<input type=\"text\" size=\"50\" name=\"" . $this->get_config_item_name() . "\" value=\"" . htmlspecialchars($this->default_value) . "\" " . 
1212             $this->jscheck . " />" . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1213     }
1214 }
1215
1216 class unchangeable_variable
1217 extends _variable {
1218     function _config_format($value) {
1219         return "";
1220     }
1221     // function get_html() { return false; }
1222     function get_html() {
1223         return $this->get_config_item_header() . 
1224         "<em>Not editable.</em>" . 
1225         "<pre>" . $this->default_value."</pre>";
1226     }
1227     function _get_config_line($posted_value) {
1228         if ($this->description)
1229             $n = "\n";
1230         return "${n}".$this->default_value;
1231     }
1232     function get_instructions($title) {
1233         global $tdwidth;
1234         $i = "<h3>" . $title . "</h3>\n    " . nl2p($this->_get_description()) . "\n";
1235         // $i = $i ."<em>Not editable.</em><br />\n<pre>" . $this->default_value."</pre>";
1236         return "<tr><td width=\"100%\" class=\"unchangeable-variable-top\" colspan=\"2\">\n".$i ."</td></tr>\n".
1237         "<tr style=\"border-top: none;\"><td class=\"unchangeable-variable-left\" width=\"$tdwidth\" bgcolor=\"#eeeeee\">&nbsp;</td>";
1238     }
1239 }
1240
1241 class unchangeable_define
1242 extends unchangeable_variable {
1243     function _config_format($value) {
1244         return "";
1245     }
1246 }
1247 class unchangeable_ini_set
1248 extends unchangeable_variable {
1249     function _config_format($value) {
1250         return "";
1251     }
1252 }
1253
1254
1255 class _variable_selection
1256 extends _variable {
1257     function value() {
1258         global $HTTP_POST_VARS;
1259         if (!empty($HTTP_POST_VARS[$this->config_item_name]))
1260             return $HTTP_POST_VARS[$this->config_item_name];
1261         else {
1262             list($option, $label) = current($this->default_value);
1263             return $this->$option;
1264         }
1265     }
1266     function get_html() {
1267         $output = $this->get_config_item_header();
1268         $output .= '<select name="' . $this->get_config_item_name() . "\">\n";
1269         /* The first option is the default */
1270         while(list($option, $label) = each($this->default_value)) {
1271             $output .= "  <option value=\"$option\">$label</option>\n";
1272         }
1273         $output .= "</select>\n";
1274         return $output;
1275     }
1276 }
1277
1278
1279 class _define
1280 extends _variable {
1281     function _config_format($value) {
1282         return sprintf("define('%s', '%s');", $this->get_config_item_name(), $value);
1283     }
1284     function _get_config_line($posted_value) {
1285         if ($this->description)
1286             $n = "\n";
1287         if ($posted_value == '')
1288             return "${n}//" . $this->_config_format("");
1289         else
1290             return "${n}" . $this->_config_format($posted_value);
1291     }
1292     function get_html() {
1293         return $this->get_config_item_header() . 
1294             "<input type=\"text\" size=\"50\" name=\"" . $this->get_config_item_name() . "\" value=\"" . $this->default_value . "\" {$this->jscheck} />" .
1295             "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1296     }
1297 }
1298
1299 class _define_commented
1300 extends _define {
1301     function _get_config_line($posted_value) {
1302         if ($this->description)
1303             $n = "\n";
1304         if ($posted_value == $this->default_value)
1305             return "${n}//" . $this->_config_format($posted_value);
1306         else if ($posted_value == '')
1307             return "${n}//" . $this->_config_format("");
1308         else
1309             return "${n}" . $this->_config_format($posted_value);
1310     }
1311 }
1312
1313 class _define_commented_optional
1314 extends _define_commented {
1315     function _config_format($value) {
1316         $name = $this->get_config_item_name();
1317         return sprintf("if (!defined('%s')) define('%s', '%s');", $name, $name, $value);
1318     }
1319 }
1320
1321 class _define_optional
1322 extends _define {
1323     function _config_format($value) {
1324         $name = $this->get_config_item_name();
1325         return sprintf("if (!defined('%s')) define('%s', '%s');", $name, $name, $value);
1326     }
1327 }
1328
1329 class _define_optional_notempty
1330 extends _define_optional {
1331     function get_html() {
1332         $s = $this->get_config_item_header() . 
1333             "<input type=\"text\" size=\"50\" name=\"" . $this->get_config_item_name() . "\" value=\"" . $this->default_value . "\" {$this->jscheck} />";
1334         if (empty($this->default_value))
1335             return $s . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Cannot be empty.</p>";
1336         else
1337             return $s . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1338     }
1339 }
1340
1341 class _variable_commented
1342 extends _variable {
1343     function _get_config_line($posted_value) {
1344         if ($this->description)
1345             $n = "\n";
1346         if ($posted_value == $this->default_value)
1347             return "${n}//" . $this->_config_format($posted_value);
1348         else if ($posted_value == '')
1349             return "${n}//" . $this->_config_format("");
1350         else
1351             return "${n}" . $this->_config_format($posted_value);
1352     }
1353 }
1354
1355 class numeric_define_commented
1356 extends _define {
1357     //    var $jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' is not an integer.', '^[-+]?[0-9]+$', '" . $this->get_config_item_name() . "', this);\"";
1358
1359     function get_html() {
1360         return numeric_define::get_html();
1361     }
1362     function _get_config_line($posted_value) {
1363         if ($this->description)
1364             $n = "\n";
1365         if ($posted_value == $this->default_value)
1366             return "${n}//" . $this->_config_format($posted_value);
1367         else if ($posted_value == '')
1368             return "${n}//" . $this->_config_format('0');
1369         else
1370             return "${n}" . $this->_config_format($posted_value);
1371     }
1372 }
1373
1374 class _define_selection
1375 extends _variable_selection {
1376     function _config_format($value) {
1377         return sprintf("define('%s', '%s');", $this->get_config_item_name(), $value);
1378     }
1379     function _get_config_line($posted_value) {
1380         return _define::_get_config_line($posted_value);
1381     }
1382     function get_html() {
1383         return _variable_selection::get_html();
1384     }
1385 }
1386
1387 class _define_selection_optional
1388 extends _define_selection {
1389     function _config_format($value) {
1390         $name = $this->get_config_item_name();
1391         return sprintf("if (!defined('%s')) define('%s', '%s');", $name, $name, $value);
1392     }
1393 }
1394
1395 class _variable_selection_optional
1396 extends _variable_selection {
1397     function _config_format($value) {
1398         $v = $this->get_config_item_name();
1399         // handle arrays: a|b --> a['b']
1400         if (strpos($v, '|')) {
1401             list($a, $b) = explode('|', $v);
1402             $v = sprintf("%s['%s']", $a, $b);
1403         }
1404         return sprintf("if (!isset(\$%s)) { \$%s = \"%s\"; }", $v, $v, $value);
1405     }
1406 }
1407
1408 class _define_password
1409 extends _define {
1410     //    var $jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' cannot be empty.', '^.+$', '" . $this->get_config_item_name() . "', this);\"";
1411
1412     function _get_config_line($posted_value) {
1413         if ($this->description)
1414             $n = "\n";
1415         if ($posted_value == '') {
1416             $p = "${n}//" . $this->_config_format("");
1417             $p = $p . "\n// If you used the passencrypt.php utility to encode the password";
1418             $p = $p . "\n// then uncomment this line:";
1419             $p = $p . "\n//if (!defined('ENCRYPTED_PASSWD')) define('ENCRYPTED_PASSWD', true);";
1420             return $p;
1421         } else {
1422             if (function_exists('crypt')) {
1423                 $salt_length = max(CRYPT_SALT_LENGTH,
1424                                     2 * CRYPT_STD_DES,
1425                                     9 * CRYPT_EXT_DES,
1426                                    12 * CRYPT_MD5,
1427                                    16 * CRYPT_BLOWFISH);
1428                 // generate an encrypted password
1429                 $crypt_pass = crypt($posted_value, rand_ascii($salt_length));
1430                 $p = "${n}" . $this->_config_format($crypt_pass);
1431                 return $p . "\ndefine('ENCRYPTED_PASSWD', true);";
1432             } else {
1433                 $p = "${n}" . $this->_config_format($posted_value);
1434                 $p = $p . "\n// Encrypted passwords cannot be used:";
1435                 $p = $p . "\n// 'function crypt()' not available in this version of php";
1436                 $p = $p . "\ndefine('ENCRYPTED_PASSWD', false);";
1437                 return $p;
1438             }
1439         }
1440     }
1441     function get_html() {
1442         return _variable_password::get_html();
1443     }
1444 }
1445
1446 class _define_password_optional
1447 extends _define_password {
1448     function _config_format($value) {
1449         $name = $this->get_config_item_name();
1450         return sprintf("if (!defined('%s')) define('%s', '%s');", $name, $name, $value);
1451     }
1452 }
1453
1454
1455 class _variable_password
1456 extends _variable {
1457     //    var $jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' cannot be empty.', '^.+$', '" . $this->get_config_item_name() . "', this);\"";
1458
1459     function get_html() {
1460         global $HTTP_POST_VARS, $HTTP_GET_VARS;
1461         $s = $this->get_config_item_header();
1462         if (isset($HTTP_POST_VARS['create']) or isset($HTTP_GET_VARS['create'])) {
1463             $new_password = random_good_password();
1464             $this->default_value = $new_password;
1465             $s .= "Created password: <strong>$new_password</strong><br />&nbsp;<br />";
1466         }
1467         $s .= "<input type=\"password\" name=\"" . $this->get_config_item_name() . "\" value=\"" . $this->default_value . "\" {$this->jscheck} />" . 
1468 "&nbsp;&nbsp;<input type=\"submit\" name=\"create\" value=\"Create Password\" />";
1469         if (empty($this->default_value))
1470             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Cannot be empty.</p>";
1471         elseif (strlen($this->default_value) < 4)
1472             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Must be longer than 4 chars.</p>";
1473         else
1474             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1475         return $s;
1476     }
1477 }
1478
1479 class numeric_define
1480 extends _define {
1481     //    var $jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' is not an integer.', '^[-+]?[0-9]+$', '" . $this->get_config_item_name() . "', this);\"";
1482
1483     function _config_format($value) {
1484         return sprintf("define('%s', %s);", $this->get_config_item_name(), $value);
1485     }
1486     function _get_config_line($posted_value) {
1487         if ($this->description)
1488             $n = "\n";
1489         if ($posted_value == '')
1490             return "${n}//" . $this->_config_format('0');
1491         else
1492             return "${n}" . $this->_config_format($posted_value);
1493     }
1494 }
1495
1496 class list_variable
1497 extends _variable {
1498     function _get_config_line($posted_value) {
1499         // split the phrase by any number of commas or space characters,
1500         // which include " ", \r, \t, \n and \f
1501         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
1502         $list_values = join("|", $list_values);
1503         return _variable::_get_config_line($list_values);
1504     }
1505     function get_html() {
1506         $list_values = explode("|", $this->default_value);
1507         $rows = max(3, count($list_values) +1);
1508         $list_values = join("\n", $list_values);
1509         $ta = $this->get_config_item_header();
1510         $ta .= "<textarea cols=\"18\" rows=\"". $rows ."\" name=\"".$this->get_config_item_name()."\" {$this->jscheck}>";
1511         $ta .= $list_values . "</textarea>";
1512         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1513         return $ta;
1514     }
1515 }
1516
1517 class array_variable
1518 extends _variable {
1519     function _config_format($value) {
1520         return sprintf("\$%s = array(%s);", $this->get_config_item_name(), $value);
1521     }
1522     function _get_config_line($posted_value) {
1523         // split the phrase by any number of commas or space characters,
1524         // which include " ", \r, \t, \n and \f
1525         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
1526         if (!empty($list_values)) {
1527             $list_values = "'".join("', '", $list_values)."'";
1528             return "\n" . $this->_config_format($list_values);
1529         } else
1530             return "\n//" . $this->_config_format('');
1531     }
1532     function get_html() {
1533         $list_values = join("\n", $this->default_value);
1534         $rows = max(3, count($this->default_value) +1);
1535         $ta = $this->get_config_item_header();
1536         $ta .= "<textarea cols=\"18\" rows=\"". $rows ."\" name=\"".$this->get_config_item_name()."\" {$this->jscheck}>";
1537         $ta .= $list_values . "</textarea>";
1538         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1539         return $ta;
1540     }
1541
1542 }
1543
1544 class _ini_set
1545 extends _variable {
1546     function value() {
1547         global $HTTP_POST_VARS;
1548         if ($v = $HTTP_POST_VARS[$this->config_item_name])
1549             return $v;
1550         else {
1551             return ini_get($this->get_config_item_name);
1552         }
1553     }
1554     function _config_format($value) {
1555         return sprintf("ini_set('%s', '%s');", $this->get_config_item_name(), $value);
1556     }
1557     function _get_config_line($posted_value) {
1558         if ($posted_value && ! $posted_value == $this->default_value)
1559             return "\n" . $this->_config_format($posted_value);
1560         else
1561             return "\n//" . $this->_config_format($this->default_value);
1562     }
1563 }
1564
1565 class boolean_define
1566 extends _define {
1567     function _get_config_line($posted_value) {
1568         if ($this->description)
1569             $n = "\n";
1570         return "${n}" . $this->_config_format($posted_value);
1571     }
1572     function _config_format($value) {
1573         if (strtolower(trim($value)) == 'false')
1574             $value = false;
1575         return sprintf("define('%s', %s);", $this->get_config_item_name(),
1576                        (bool)$value ? 'true' : 'false');
1577     }
1578     function get_html() {
1579         $output = $this->get_config_item_header();
1580         $output .= '<select name="' . $this->get_config_item_name() . "\" {$this->jscheck}>\n";
1581         /* The first option is the default */
1582         list($option, $label) = each($this->default_value);
1583         $output .= "  <option value=\"$option\" selected='selected'>$label</option>\n";
1584         /* There can usually, only be two options, there can be
1585          * three options in the case of a boolean_define_commented_optional */
1586         while (list($option, $label) = each($this->default_value)) 
1587           $output .= "  <option value=\"$option\">$label</option>\n";
1588         $output .= "</select>\n";
1589         return $output;
1590     }
1591 }
1592
1593 class boolean_define_optional
1594 extends boolean_define {
1595     function _config_format($value) {
1596         $name = $this->get_config_item_name();
1597         return "if (!defined('$name')) " . boolean_define::_config_format($value);
1598     }
1599 }
1600
1601 class boolean_define_commented
1602 extends boolean_define {
1603     function _get_config_line($posted_value) {
1604         if ($this->description)
1605             $n = "\n";
1606         list($default_value, $label) = each($this->default_value);
1607         if ($posted_value == $default_value)
1608             return "${n}//" . $this->_config_format($posted_value);
1609         else if ($posted_value == '')
1610             return "${n}//" . $this->_config_format('false');
1611         else
1612             return "${n}" . $this->_config_format($posted_value);
1613     }
1614 }
1615
1616 class boolean_define_commented_optional
1617 extends boolean_define_commented {
1618     function _config_format($value) {
1619         $name = $this->get_config_item_name();
1620         return "if (!defined('$name')) " . boolean_define_commented::_config_format($value);
1621     }
1622 }
1623
1624 class part
1625 extends _variable {
1626     function value () { return; }
1627     function get_config($posted_value) {
1628         $d = stripHtml($this->_get_description());
1629         global $SEPARATOR;
1630         return "\n".$SEPARATOR . str_replace("\n", "\n// ", $d) ."\n$this->default_value";
1631     }
1632     function get_instructions($title) {
1633         $group_name = preg_replace("/\W/","",$title);
1634         $i = "<tr class='header' id='$group_name'>\n<td class=\"part\" width=\"100%\" colspan=\"2\" bgcolor=\"#eeaaaa\">\n";
1635         $i .= "<h2>" . $title . "</h2>\n    " . nl2p($this->_get_description()) ."\n";
1636         $i .= "<p><a href=\"javascript:toggle_group('$group_name')\" id=\"{$group_name}_text\">Hide options.</a></p>";
1637         return  $i ."</td>\n";
1638     }
1639     function get_html() {
1640         return "";
1641     }
1642 }
1643
1644 // html utility functions
1645 function nl2p($text) {
1646   preg_match_all("@\s*(<pre>.*?</pre>|<dl>.*?</dl>|.*?(?=\n\n|<pre>|<dl>|$))@s",
1647                  $text, $m, PREG_PATTERN_ORDER);
1648
1649   $text = '';
1650   foreach ($m[1] as $par) {
1651     if (!($par = trim($par)))
1652       continue;
1653     if (!preg_match('/^<(pre|dl)>/', $par))
1654       $par = "<p>$par</p>";
1655     $text .= $par;
1656   }
1657   return $text;
1658 }
1659
1660 function stripHtml($text) {
1661         $d = str_replace("<pre>", "", $text);
1662         $d = str_replace("</pre>", "", $d);
1663         $d = str_replace("<dl>", "", $d);
1664         $d = str_replace("</dl>", "", $d);
1665         $d = str_replace("<dt>", "", $d);
1666         $d = str_replace("</dt>", "", $d);
1667         $d = str_replace("<dd>", "", $d);
1668         $d = str_replace("</dd>", "", $d);
1669         $d = str_replace("<p>", "", $d);
1670         $d = str_replace("</p>", "", $d);
1671         //restore html entities into characters
1672         // http://www.php.net/manual/en/function.htmlentities.php
1673         $trans = get_html_translation_table (HTML_ENTITIES);
1674         $trans = array_flip ($trans);
1675         $d = strtr($d, $trans);
1676         return $d;
1677 }
1678
1679 /**
1680  * Seed the random number generator.
1681  *
1682  * better_srand() ensures the randomizer is seeded only once.
1683  * 
1684  * How random do you want it? See:
1685  * http://www.php.net/manual/en/function.srand.php
1686  * http://www.php.net/manual/en/function.mt-srand.php
1687  */
1688 function better_srand($seed = '') {
1689     static $wascalled = FALSE;
1690     if (!$wascalled) {
1691         if ($seed === '') {
1692             list($usec,$sec)=explode(" ",microtime());
1693             if ($usec > 0.1) 
1694                 $seed = (double) $usec * $sec;
1695             else // once in a while use the combined LCG entropy
1696                 $seed = (double) 1000000 * substr(uniqid("",true),13);
1697         }
1698         if (function_exists('mt_srand')) {
1699             mt_srand($seed); // mersenne twister
1700         } else {
1701             srand($seed);    
1702         }
1703         $wascalled = TRUE;
1704     }
1705 }
1706
1707 function rand_ascii($length = 1) {
1708     better_srand();
1709     $s = "";
1710     for ($i = 1; $i <= $length; $i++) {
1711         // return only typeable 7 bit ascii, avoid quotes
1712         if (function_exists('mt_rand'))
1713             // the usually bad glibc srand()
1714             $s .= chr(mt_rand(40, 126)); 
1715         else
1716             $s .= chr(rand(40, 126));
1717     }
1718     return $s;
1719 }
1720
1721 ////
1722 // Function to create better user passwords (much larger keyspace),
1723 // suitable for user passwords.
1724 // Sequence of random ASCII numbers, letters and some special chars.
1725 // Note: There exist other algorithms for easy-to-remember passwords.
1726 function random_good_password ($minlength = 5, $maxlength = 8) {
1727   $newpass = '';
1728   // assume ASCII ordering (not valid on EBCDIC systems!)
1729   $valid_chars = "!#%&+-.0123456789=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
1730   $start = ord($valid_chars);
1731   $end   = ord(substr($valid_chars,-1));
1732   better_srand();
1733   if (function_exists('mt_rand')) // mersenne twister
1734       $length = mt_rand($minlength, $maxlength);
1735   else  // the usually bad glibc rand()
1736       $length = rand($minlength, $maxlength);
1737   while ($length > 0) {
1738       if (function_exists('mt_rand'))
1739           $newchar = mt_rand($start, $end);
1740       else
1741           $newchar = rand($start, $end);
1742       if (! strrpos($valid_chars,$newchar) ) continue; // skip holes
1743       $newpass .= sprintf("%c",$newchar);
1744       $length--;
1745   }
1746   return($newpass);
1747 }
1748
1749 // debugging
1750 function printArray($a) {
1751     echo "<hr />\n<pre>\n";
1752     print_r($a);
1753     echo "\n</pre>\n<hr />\n";
1754 }
1755
1756 // end of class definitions
1757 /////////////////////////////
1758 // begin auto generation code
1759
1760 if (!function_exists('is_a'))
1761 {
1762   function is_a($object, $class)
1763   {
1764     $class = strtolower($class);
1765     return (get_class($object) == $class) or is_subclass_of($object, $class);
1766   }
1767 }
1768
1769
1770 if (@$HTTP_POST_VARS['action'] == 'make_config') {
1771
1772     $timestamp = date ('dS of F, Y H:i:s');
1773
1774     $config = "<?php
1775 /* This is a local configuration file for PhpWiki.
1776  * It was automatically generated by the configurator script
1777  * on the $timestamp.
1778  */
1779
1780 /*$copyright*/
1781
1782 /////////////////////////////////////////////////////////////////////
1783 /*$preamble*/
1784 ";
1785
1786     $posted = $GLOBALS['HTTP_POST_VARS'];
1787
1788     if (defined('DEBUG'))
1789         printArray($GLOBALS['HTTP_POST_VARS']);
1790
1791     foreach($properties as $option_name => $a) {
1792         $posted_value = $posted[$a->config_item_name];
1793         $config .= $properties[$option_name]->get_config($posted_value);
1794     }
1795
1796     if (defined('DEBUG')) {
1797         $diemsg = "The configurator.php is provided for testing purposes only.
1798 You can't use this file with your PhpWiki server yet!!";
1799         $config .= "\ndie(\"$diemsg\");\n";
1800     }
1801     $config .= $end;
1802
1803     // I think writing this config file is a big security hole.
1804     // If this is installed in such a way that it can write an index-user.php,
1805     // then anyone can create a working index-user.php with, e.g. any
1806     // admin user and pw of their choosing...
1807     //
1808     // So I'm disabling it...
1809
1810     if (defined(ENABLE_FILE_OUTPUT) and ENABLE_FILE_OUPUT) {
1811       /* We first check if the config-file exists. */
1812       if (file_exists($fs_config_file)) {
1813         /* We make a backup copy of the file */
1814         // $config_file = 'index-user.php';
1815         $new_filename = preg_replace('/\.php$/', time() . '.php', $fs_config_file);
1816         if (@copy($fs_config_file, $new_filename)) {
1817             $fp = @fopen($fs_config_file, 'w');
1818         }
1819       } else {
1820         $fp = @fopen($fs_config_file, 'w');
1821       }
1822     }
1823     else {
1824       $fp = false;
1825     }
1826     
1827
1828     if ($fp) {
1829         fputs($fp, $config);
1830         fclose($fp);
1831         echo "<p>The configuration was written to <code><b>$config_file</b></code>.</p>\n";
1832         if ($new_filename) {
1833             echo "<p>A backup was made to <code><b>$new_filename</b></code>.</p>\n";
1834         }
1835         echo "<p><strong>You must rename or copy this</strong> <code><b>$config_file</b></code> <strong>file to</strong> <code><b>index.php</b></code>.</p>\n";
1836     } else {
1837         echo "<p>A configuration file could <b>not</b> be written. You should copy the above configuration to a file, and manually save it as <code><b>index.php</b></code>.</p>\n";
1838     }
1839
1840     echo "<hr />\n<p>Here's the configuration file based on your answers:</p>\n";
1841     echo "<form method='get' action='$PHP_SELF'>\n";
1842     echo "<textarea id='config-output' readonly='readonly' style='width:100%;' rows='30' cols='100'>\n";
1843     echo htmlentities($config);
1844     echo "</textarea></form>\n";
1845     echo "<hr />\n";
1846
1847     echo "<p>To make any corrections, <a href=\"configurator.php\">edit the settings again</a>.</p>\n";
1848
1849 } else { // first time or create password
1850     $posted = $GLOBALS['HTTP_POST_VARS'];
1851     /* No action has been specified - we make a form. */
1852
1853     echo '
1854 <form action="configurator.php" method="post">
1855 <input type="hidden" name="action" value="make_config" />
1856 <table cellpadding="4" cellspacing="0">
1857 ';
1858
1859     while(list($property, $obj) = each($properties)) {
1860         echo $obj->get_instructions($property);
1861         if ($h = $obj->get_html()) {
1862             if (defined('DEBUG'))  $h = get_class($obj) . "<br />\n" . $h;
1863             echo "<td>".$h."</td>\n";
1864         }
1865         echo '</tr>';
1866     }
1867
1868     echo '
1869 </table>
1870 <p><input type="submit" value="Save ',$config_file,'" /> <input type="reset" value="Clear" /></p>
1871 </form>
1872 ';
1873 }
1874 ?>
1875 </body>
1876 </html>