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