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