]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - configurator.php
read configurator desc from config-dist.ini, update desc, fix some warnings
[SourceForge/phpwiki.git] / configurator.php
1 <?php // $Id: configurator.php,v 1.38 2005-09-15 05:56:12 rurban Exp $
2 /*
3  * Copyright 2002,2003,2005 $ThePhpWikiProgrammingTeam
4  * Copyright 2002 Martin Geisler <gimpster@gimpster.com> 
5  *
6  * This file is part of PhpWiki.
7  * Parts of this file were based on PHPWeather's configurator.php file.
8  *   http://sourceforge.net/projects/phpweather/
9  *
10  * PhpWiki is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * PhpWiki is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with PhpWiki; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 /**
26  * Starts automatically the first time by IniConfig("config/config.ini") 
27  * if it doesn't exist.
28  *
29  * DONE:
30  * o Initial expand ?show=_part1 (the part id)
31  * o read config-default.ini and use this as default_values
32  * o commented / optional: non-default values should not be commented!
33  *                         default values if optional can be omitted.
34  * o validate input (fix javascript, add POST checks)
35  * o start this automatically the first time
36  * o fix include_path
37  *
38  * 1.3.11 TODO: (or 1.3.12?)
39  * o parse_ini_file("config-dist.ini") for the commented vars
40  * o check automatically for commented and optional vars
41  * o mixin class for commented 
42  * o fix SQL quotes, AUTH_ORDER quotes and file forward slashes
43  * o posted values validation, extend js validation for sane DB values
44  * o read config-dist.ini into sections, comments, and optional/required settings
45  *
46  * A file config/config.ini will be automatically generated, if writable.
47  *
48  * NOTE: If you have a starterscript outside PHPWIKI_DIR but no 
49  * config/config.ini yet (very unlikely!), you must define DATA_PATH in the 
50  * starterscript, otherwise the webpath to configurator is unknown, and 
51  * subsequent requests will fail. (POST to save the INI)
52  */
53
54 global $HTTP_SERVER_VARS, $HTTP_POST_VARS, $tdwidth;
55 if (empty($_GET)) $_GET =& $GLOBALS['HTTP_GET_VARS'];
56 if (empty($_ENV)) $_ENV =& $GLOBALS['HTTP_ENV_VARS'];
57
58 if (empty($configurator))
59     $configurator = "configurator.php";
60 if (!strstr($HTTP_SERVER_VARS["SCRIPT_NAME"], $configurator) and defined('DATA_PATH'))
61     $configurator = DATA_PATH . "/" . $configurator;
62 $scriptname = str_replace('configurator.php', 'index.php', $HTTP_SERVER_VARS["SCRIPT_NAME"]);
63
64 $tdwidth = 700;
65 $config_file = (substr(PHP_OS,0,3) == 'WIN') ? 'config\\config.ini' : 'config/config.ini';
66 $fs_config_file = dirname(__FILE__) . (substr(PHP_OS,0,3) == 'WIN' ? '\\' : '/') . $config_file;
67 if (isset($HTTP_POST_VARS['create']))  header('Location: '.$configurator.'?show=_part1&create=1#create');
68
69 // helpers from lib/WikiUser/HttpAuth.php
70 if (!function_exists('_http_user')) {
71     function _http_user() {
72         if (!isset($_SERVER))
73             $_SERVER = $GLOBALS['HTTP_SERVER_VARS'];
74         if (!empty($_SERVER['PHP_AUTH_USER']))
75             return array($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
76         if (!empty($_SERVER['REMOTE_USER']))
77             return array($_SERVER['REMOTE_USER'], $_SERVER['PHP_AUTH_PW']);
78         if (!empty($GLOBALS['HTTP_ENV_VARS']['REMOTE_USER']))
79             return array($GLOBALS['HTTP_ENV_VARS']['REMOTE_USER'], 
80                          $GLOBALS['HTTP_ENV_VARS']['PHP_AUTH_PW']);
81         if (!empty($GLOBALS['REMOTE_USER']))
82             return array($GLOBALS['REMOTE_USER'], $GLOBALS['PHP_AUTH_PW']);
83             
84         // MsWindows IIS:
85         if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
86             list($userid, $passwd) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
87             return array($userid, $passwd);
88         }
89         return array('','');
90     }
91     function _http_logout() {
92         if (!isset($_SERVER))
93             $_SERVER =& $GLOBALS['HTTP_SERVER_VARS'];
94         // maybe we should random the realm to really force a logout. but the next login will fail.
95         // better_srand(); $realm = microtime().rand();
96         header('WWW-Authenticate: Basic realm="'.WIKI_NAME.'"');
97         if (strstr(php_sapi_name(), 'apache'))
98             header('HTTP/1.0 401 Unauthorized'); 
99         else    
100             header("Status: 401 Access Denied"); //IIS and CGI need that
101         unset($GLOBALS['REMOTE_USER']);
102         unset($_SERVER['PHP_AUTH_USER']);
103         unset($_SERVER['PHP_AUTH_PW']);
104
105         trigger_error("Permission denied. Require ADMIN_USER.", E_USER_ERROR);
106         exit();
107     }
108 }
109
110 // If config.ini exists, we require ADMIN_USER access by faking HttpAuth. 
111 // So nobody can see or reset the password(s).
112 if (file_exists($fs_config_file)) {
113     // Require admin user
114     if (!defined('ADMIN_USER') or !defined('ADMIN_PASSWD')) {
115         if (!function_exists("IniConfig")) {
116             include_once("lib/prepend.php");
117             include_once("lib/IniConfig.php");
118         }
119         IniConfig($fs_config_file);
120     }
121     if (!defined('ADMIN_USER') or ADMIN_USER == '') {
122         trigger_error("Configuration problem:\nADMIN_USER not defined in \"$fs_config_file\".\n"
123                       . "Cannot continue: You have to fix that manually.", E_USER_ERROR);
124         exit();
125     }
126
127     list($admin_user, $admin_pw) = _http_user();
128     //$required_user = ADMIN_USER;
129     if (empty($admin_user) or $admin_user != ADMIN_USER)
130     {
131         _http_logout();
132     }
133     // check password
134     if (ENCRYPTED_PASSWD and function_exists('crypt')) {
135         if (crypt($admin_pw, ADMIN_PASSWD) != ADMIN_PASSWD) 
136             _http_logout();
137     } elseif ($admin_pw != ADMIN_PASSWD) {
138         _http_logout();
139     }
140 } else {
141     if (!function_exists("IniConfig")) {
142         include_once("lib/prepend.php");
143         include_once("lib/IniConfig.php");
144     }
145     $def_file = (substr(PHP_OS,0,3) == 'WIN') ? 'config\\config-default.ini' : 'config/config-default.ini';
146     $fs_def_file = dirname(__FILE__) . (substr(PHP_OS,0,3) == 'WIN' ? '\\' : '/') . $def_file;
147     IniConfig($fs_def_file);
148 }
149
150 echo "<","?xml version=\"1.0\" encoding=\"'iso-8859-1'\"?",">\n";
151 ?>
152 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
153   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
154 <html xmlns="http://www.w3.org/1999/xhtml">
155 <head>
156 <!-- $Id: configurator.php,v 1.38 2005-09-15 05:56:12 rurban Exp $ -->
157 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
158 <title>Configuration tool for PhpWiki <?php echo $config_file ?></title>
159 <style type="text/css" media="screen">
160 <!--
161 /* TABLE { border: thin solid black } */
162 body { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 80%; }
163 pre { font-size: 120%; }
164 td { border: thin solid black }
165 tr { border: none }
166 div.hint { border: thin solid red, background-color: #eeeeee; }
167 tr.hidden { border: none; display: none; }
168 td.part { background-color: #eeeeee; color: inherit; }
169 td.instructions { background-color: #ffffee; width: <?php echo $tdwidth ?>px; color: inherit; }
170 td.unchangeable-variable-top   { border-bottom: none; background-color: #ffffee; color:inherit; }
171 td.unchangeable-variable-left  { border-top: none; background-color: #ffffee; color:inherit; }
172 -->
173 </style>
174 <script language="JavaScript" type="text/javascript">
175 <!--
176 function update(accepted, error, value, output) {
177   var msg = document.getElementById(output);
178   if (accepted) {
179     /* MSIE 5.0 fails here */
180     if (msg && msg.innerHTML) { msg.innerHTML = "<font color=\"green\">Input accepted.</font>"; }
181   } else {
182     while ((index = error.indexOf("%s")) > -1) {
183       error = error.substring(0, index) + value + error.substring(index+2);
184     }
185     if (msg) { msg.innerHTML = "<font color=\"red\">" + error + "</font>"; }
186   }
187   if (submit = document.getElementById('submit')) submit.disabled = accepted ? false : true;
188 }
189
190 function validate(error, value, output, field) {
191   update(field.value == value, error, field.value, output);
192 }
193
194 function validate_ereg(error, ereg, output, field) {
195   regex = new RegExp(ereg);
196   update(regex.test(field.value), error, field.value, output);
197 }
198
199 function validate_range(error, low, high, empty_ok, output, field) {
200   update((empty_ok == 1 && field.value == "") ||
201          (field.value >= low && field.value <= high),
202          error, field.value, output);
203 }
204
205 function toggle_group(id) {
206   var text = document.getElementById(id + "_text");
207   var do_hide = false;
208   if (text.innerHTML == "Hide options.") {
209     do_hide = true;
210     text.innerHTML = "Show options.";
211   } else {
212     text.innerHTML = "Hide options.";
213   }
214
215   var rows = document.getElementsByTagName('tr');
216   var i = 0;
217   for (i = 0; i < rows.length; i++) {
218     var tr = rows[i];
219     if (tr.className == 'header' && tr.id == id) {
220       i++;
221       break;
222     }
223   }
224   for (; i < rows.length; i++) {
225     var tr = rows[i];
226     if (tr.className == 'header')
227       break;
228     tr.className = do_hide ? 'hidden': 'nonhidden';
229   }
230 }
231
232 function do_init() {
233   // Hide all groups.  We do this via JavaScript to avoid
234   // hiding the groups if JavaScript is not supported...
235   var rows = document.getElementsByTagName('tr');
236   var show = '<?php echo $_GET["show"] ?>';
237   for (var i = 0; i < rows.length; i++) {
238     var tr = rows[i];
239     if (tr.className == 'header')
240         if (!show || tr.id != show)
241             toggle_group(tr.id);
242   }
243
244   // Select text in textarea upon focus
245   var area = document.getElementById('config-output');
246   if (area) {
247     listener = { handleEvent: function (e) { area.select(); } };
248     area.addEventListener('focus', listener, false);
249   }
250 }
251   
252 -->
253 </script>
254 </head>
255 <body onload="do_init();">
256
257       <h1>Configuration for PhpWiki <?php echo $config_file ?></h1>
258
259 <div class="hint">
260     Using this configurator.php is experimental!<br>
261     On any configuration problems, please edit the resulting config.ini manually.
262 </div>
263
264 <?php
265 //define('DEBUG', 1);
266 /**
267  * The Configurator is a php script to aid in the configuration of PhpWiki.
268  * Parts of this file were based on PHPWeather's configurator.php file.
269  *   http://sourceforge.net/projects/phpweather/
270  *
271  * TO CHANGE THE CONFIGURATION OF YOUR PHPWIKI, DO *NOT* MODIFY THIS FILE!
272  * more instructions go here
273  *
274  * Todo: 
275  *   * fix include_path
276  *   * eval config.ini to get the actual settings.
277  */
278
279 //////////////////////////////
280 // begin configuration options
281
282 /**
283  * Notes for the description parameter of $property:
284  *
285  * - Descriptive text will be changed into comments (preceeded by ; )
286  *   for the final output to config.ini.
287  *
288  * - Only a limited set of html is allowed: pre, dl dt dd; it will be
289  *   stripped from the final output.
290  *
291  * - Line breaks and spacing will be preserved for the final output.
292  *
293  * - Double line breaks are automatically converted to paragraphs
294  *   for the html version of the descriptive text.
295  *
296  * - Double-quotes and dollar signs in the descriptive text must be
297  *   escaped: \" and \$. Instead of escaping double-quotes you can use 
298  *   single (') quotes for the enclosing quotes. 
299  *
300  * - Special characters like < and > must use html entities,
301  *   they will be converted back to characters for the final output.
302  */
303
304 $SEPARATOR = ";=========================================================================";
305
306 $preamble = "
307 ; This is the main configuration file for PhpWiki in INI-style format.
308 ; Note that certain characters are used as comment char and therefore 
309 ; these entries must be in double-quotes. Such as \":\", \";\", \",\" and \"|\"
310 ; Take special care for DBAUTH_ sql statements. (Part 3a)
311 ;
312 ; This file is divided into several parts: Each one has different configuration 
313 ; settings you can change; in all cases the default should work on your system,
314 ; however, we recommend you tailor things to your particular setting.
315 ; Here undefined definitions get defined by config-default.ini settings.
316 ";
317
318 $properties["Part Zero"] =
319 new part('_part0', $SEPARATOR."\n", "
320 Part Zero: (optional)
321 Latest Development and Tricky Options");
322
323 if (defined('INCLUDE_PATH'))
324     $include_path = INCLUDE_PATH;
325 else {
326   if (substr(PHP_OS,0,3) == 'WIN') {
327       $include_path = dirname(__FILE__) . ';' . ini_get('include_path');
328       if (strchr(ini_get('include_path'),'/'))
329           $include_path = strtr($include_path,'\\','/');
330   } else {
331     $include_path = dirname(__FILE__) . ':' . ini_get('include_path');
332   }
333 }
334
335 $properties["PHP include_path"] =
336 new _define('INCLUDE_PATH', $include_path);
337
338 // TODO: convert this a checkbox row as in tests/unit/test.pgp
339 $properties["DEBUG"] =
340 new numeric_define_optional('DEBUG', DEBUG);
341
342 // TODO: bring the default to the front
343 $properties["ENABLE_USER_NEW"] =
344 new boolean_define_commented_optional
345 ('ENABLE_USER_NEW', 
346  array('true'  => "Enabled",
347        'false' => "Disabled."));
348
349 $properties["ENABLE_PAGEPERM"] =
350 new boolean_define_commented_optional
351 ('ENABLE_PAGEPERM', 
352  array('true'  => "Enabled",
353        'false' => "Disabled."));
354
355 $properties["ENABLE_EDIT_TOOLBAR"] =
356 new boolean_define_commented_optional
357 ('ENABLE_EDIT_TOOLBAR', 
358  array('true'  => "Enabled",
359        'false' => "Disabled."));
360
361 $properties["JS_SEARCHREPLACE"] =
362 new boolean_define_commented_optional
363 ('JS_SEARCHREPLACE', 
364  array('true'  => "Enabled",
365        'false' => "Disabled"));
366
367 $properties["ENABLE_DOUBLECLICKEDIT"] =
368 new boolean_define_commented_optional
369 ('ENABLE_DOUBLECLICKEDIT', 
370  array('true'  => "Enabled",
371        'false' => "Disabled"));
372
373 $properties["ENABLE_XHTML_XML"] =
374 new boolean_define_commented_optional
375 ('ENABLE_XHTML_XML', 
376  array('false' => "Disabled",
377        'true'  => "Enabled"));
378
379 $properties["USECACHE"] =
380 new boolean_define_commented_optional
381 ('USECACHE', 
382  array('true'  => "Enabled",
383        'false' => "Disabled"));
384
385 $properties["ENABLE_SPAMASSASSIN"] =
386 new boolean_define_commented_optional
387 ('ENABLE_SPAMASSASSIN', 
388  array('true'  => "Enabled",
389        'false' => "Disabled"));
390
391 $properties["GOOGLE_LINKS_NOFOLLOW"] =
392 new boolean_define_commented_optional
393 ('GOOGLE_LINKS_NOFOLLOW', 
394  array('true'  => "Enabled",
395        'false' => "Disabled"));
396
397 $properties["ENABLE_LIVESEARCH"] =
398 new boolean_define_commented_optional
399 ('ENABLE_LIVESEARCH', 
400  array('true'  => "Enabled",
401        'false' => "Disabled"));
402
403 $properties["ENABLE_ACDROPDOWN"] =
404 new boolean_define_commented_optional
405 ('ENABLE_ACDROPDOWN', 
406  array('true'  => "Enabled",
407        'false' => "Disabled"));
408
409 $properties["ENABLE_DISCUSSION_LINK"] =
410 new boolean_define_commented_optional
411 ('ENABLE_DISCUSSION_LINK', 
412  array('true'  => "Enabled",
413        'false' => "Disabled"));
414
415 $properties["ENABLE_CAPTCHA"] =
416 new boolean_define_commented_optional
417 ('ENABLE_CAPTCHA', 
418  array('true'  => "Enabled",
419        'false' => "Disabled"));
420
421 $properties["USE_SAFE_DBSESSION"] =
422 new boolean_define_commented_optional
423 ('USE_SAFE_DBSESSION', 
424  array('false' => "Disabled",
425        'true'  => "Enabled"));
426
427 $properties["Part One"] =
428 new part('_part1', $SEPARATOR."\n", "
429 Part One: Authentication and security settings. See Part Three for more.");
430
431 $properties["Wiki Name"] =
432 new _define_optional('WIKI_NAME', WIKI_NAME);
433
434 $properties["Admin Username"] =
435 new _define_notempty('ADMIN_USER', ADMIN_USER, "
436 You must set this! Username and password of the administrator.",
437 "onchange=\"validate_ereg('Sorry, ADMIN_USER cannot be empty.', '^.+$', 'ADMIN_USER', this);\"");
438
439 $properties["Admin Password"] =
440 new _define_password('ADMIN_PASSWD', ADMIN_PASSWD, "
441 You must set this! 
442 For heaven's sake pick a good password.
443
444 If your version of PHP supports encrypted passwords, your password will be
445 automatically encrypted within the generated config file. 
446 Use the \"Create Random Password\" button to create a good (random) password.
447
448 ADMIN_PASSWD is ignored on HttpAuth",
449 "onchange=\"validate_ereg('Sorry, ADMIN_PASSWD must be at least 4 chars long.', '^....+$', 'ADMIN_PASSWD', this);\"");
450
451 $properties["Encrypted Passwords"] =
452 new boolean_define
453 ('ENCRYPTED_PASSWD',
454  array('true'  => "true.  use crypt for all passwords",
455        'false' => "false. use plaintest passwords (not recommended)"));
456
457 $properties["Reverse DNS"] =
458 new boolean_define_optional
459 ('ENABLE_REVERSE_DNS',
460  array('true'  => "true. perform additional reverse dns lookups",
461        'false' => "false. just record the address as given by the httpd server"));
462
463 $properties["ZIPdump Authentication"] =
464 new boolean_define_optional('ZIPDUMP_AUTH', 
465                     array('false' => "false. Everyone may download zip dumps",
466                           'true'  => "true. Only admin may download zip dumps"));
467
468 $properties["Enable RawHtml Plugin"] =
469 new boolean_define_commented_optional
470 ('ENABLE_RAW_HTML', 
471  array('true'  => "Enabled",
472        'false' => "Disabled"));
473
474 $properties["Allow RawHtml Plugin only on locked pages"] =
475 new boolean_define_commented_optional
476 ('ENABLE_RAW_HTML_LOCKEDONLY', 
477  array('true'  => "Enabled",
478        'false' => "Disabled"));
479
480 $properties["Allow RawHtml Plugin if safe HTML code"] =
481 new boolean_define_commented_optional
482 ('ENABLE_RAW_HTML_SAFE', 
483  array('true'  => "Enabled",
484        'false' => "Disabled"), "
485 If this is set, all unsafe html code is stripped automatically (experimental!)
486 See <a href=\"http://chxo.com/scripts/safe_html-test.php\" target=\"_new\">chxo.com/scripts/safe_html-test.php</a>
487 ");
488
489 $properties["Maximum Upload Size"] =
490 new numeric_define_optional('MAX_UPLOAD_SIZE', MAX_UPLOAD_SIZE /*"16 * 1024 * 1024"*/, "
491 The maximum file upload size.");
492
493 $properties["Minor Edit Timeout"] =
494 new numeric_define_optional('MINOR_EDIT_TIMEOUT', MINOR_EDIT_TIMEOUT /*"7 * 24 * 3600"*/, "
495 If the last edit is older than MINOR_EDIT_TIMEOUT seconds, the
496 default state for the \"minor edit\" checkbox on the edit page form
497 will be off.");
498
499 $properties["Disabled Actions"] =
500 new array_define('DISABLED_ACTIONS', DISABLED_ACTIONS /*array()*/, "
501 Actions listed in this array will not be allowed. Actions are:
502 browse, create, diff, dumphtml, dumpserial, edit, loadfile, lock, remove, 
503 unlock, upload, viewsource, zip, ziphtml");
504
505 $properties["Access Log File"] =
506 new _define_commented_optional('ACCESS_LOG', ACCESS_LOG /*"/var/logs/wiki_access.log"*/, "
507 PhpWiki can generate an access_log (in \"NCSA combined log\" format)
508 for you. If you want one, define this to the name of the log file,
509 such as /tmp/wiki_access_log. Preferred is to use SQL access logging as below.
510
511 Default: empty - no access log file will be generated.");
512
513 $properties["Access Log SQL"] =
514 new _define_selection(
515 'ACCESS_LOG_SQL', 
516 array('0' => 'disable',
517       '1' => 'read only',
518       '2' => 'read + write'), "
519 PhpWiki can read and/or write apache-style mod_log_sql accesslog tables for faster
520 abuse detection and referer lists. 
521 See http://www.outoforder.cc/projects/apache/mod_log_sql/docs-2.0/#id2756178
522
523 If defined (e.g. 1) only read-access is done via SQL. 
524 If flag 2 is set, phpwiki also writes. (Default on SQL or ADODB)
525 This must use DATABASE_TYPE = SQL or ADODB.
526 ");
527
528 $properties["Compress Output"] =
529 new boolean_define_commented_optional
530 ( 'COMPRESS_OUTPUT', 
531   array(''      => 'GZIP compress when PhpWiki thinks appropriate.',
532         'false' => 'Never compress output.',
533         'true'  => 'Always try to compress output.'),
534 "
535 By default PhpWiki will try to have PHP compress it's output
536 before sending it to the browser (if you have a recent enough
537 version of PHP and the action and the browser supports it.)
538
539 Define COMPRESS_OUTPUT to false to prevent output compression at all.
540
541 Define COMPRESS_OUTPUT to true to force output compression,
542 even if we think your version of PHP does this in a buggy
543 fashion.
544
545 Leave it undefined to leave the choice up to PhpWiki.");
546
547 $properties["HTTP Cache Control"] =
548 new _define_selection_optional
549 ('CACHE_CONTROL',
550  array('LOOSE' => 'LOOSE',
551        'STRICT' => 'STRICT',
552        'NO_CACHE' => 'NO_CACHE',
553        'ALLOW_STALE' => 'ALLOW_STALE'),
554 "
555 HTTP CACHE_CONTROL
556
557 This controls how PhpWiki sets the HTTP cache control
558 headers (Expires: and Cache-Control:) 
559
560 Choose one of:
561
562 <dl>
563 <dt>NO_CACHE</dt>
564 <dd>This is roughly the old (pre 1.3.4) behaviour.  PhpWiki will
565     instruct proxies and browsers never to cache PhpWiki output.</dd>
566
567 <dt>STRICT</dt>
568 <dd>Cached pages will be invalidated whenever the database global
569     timestamp changes.  This should behave just like NONE (modulo
570     bugs in PhpWiki and your proxies and browsers), except that
571     things will be slightly more efficient.</dd>
572
573 <dt>LOOSE</dt>
574 <dd>Cached pages will be invalidated whenever they are edited,
575     or, if the pages include plugins, when the plugin output could
576     concievably have changed.
577
578     <p>Behavior should be much like STRICT, except that sometimes
579        wikilinks will show up as undefined (with the question mark)
580        when in fact they refer to (recently) created pages.
581        (Hitting your browsers reload or perhaps shift-reload button
582        should fix the problem.)</p></dd>
583
584 <dt>ALLOW_STALE</dt>
585 <dd>Proxies and browsers will be allowed to used stale pages.
586     (The timeout for stale pages is controlled by CACHE_CONTROL_MAX_AGE.)
587
588     <p>This setting will result in quirky behavior.  When you edit a
589        page your changes may not show up until you shift-reload the
590        page, etc...</p>
591
592     <p>This setting is generally not advisable, however it may be useful
593        in certain cases (e.g. if your wiki gets lots of page views,
594        and few edits by knowledgable people who won't freak over the quirks.)</p>
595 </dd>
596
597 The default is currently LOOSE.");
598
599 // FIXME: should be numeric_define_optional
600 $properties["HTTP Cache Control Max Age"] =
601 new numeric_define_optional('CACHE_CONTROL_MAX_AGE', CACHE_CONTROL_MAX_AGE,
602             "
603 Maximum page staleness, in seconds.");
604
605 $properties["Markup Caching"] =
606 new boolean_define_commented_optional
607 ('WIKIDB_NOCACHE_MARKUP',
608  array('false' => 'Enable markup cache',
609        'true'  => 'Disable markup cache'),
610 "
611 MARKUP CACHING
612
613 PhpWiki normally caches a preparsed version (i.e. mostly
614 converted to HTML) of the most recent version of each page.
615 (Parsing the wiki-markup takes a fair amount of CPU.)
616
617 Define WIKIDB_NOCACHE_MARKUP to true to disable the
618 caching of marked-up page content.
619
620 Note that you can also disable markup caching on a per-page
621 temporary basis by addinging a query arg of '?nocache=1'
622 to the URL to the page.  (Use '?nocache=purge' to completely
623 discard the cached version of the page.)
624
625 You can also purge the cached markup globally by using the
626 \"Purge Markup Cache\" button on the PhpWikiAdministration page.");
627
628 $properties["Path for PHP Session Support"] =
629     new _define_optional('SESSION_SAVE_PATH', defined('SESSION_SAVE_PATH') ? SESSION_SAVE_PATH : ini_get('session.save_path'), "
630 The login code now uses PHP session support. Usually, the default
631 configuration of PHP is to store the session state information in
632 /tmp. That probably will work fine, but fails e.g. on clustered
633 servers where each server has their own distinct /tmp (this is the
634 case on SourceForge's project web server.) You can specify an
635 alternate directory in which to store state information like so
636 (whatever user your httpd runs as must have read/write permission
637 in this directory).
638
639 On USE_DB_SESSION = true you can ignore this.
640 ");
641
642 ///////// database selection
643
644 $properties["Part Two"] =
645 new part('_part2', $SEPARATOR."\n", "
646
647 Part Two:
648 Database Configuration
649 ");
650
651 $properties["Database Type"] =
652 new _define_selection("DATABASE_TYPE",
653               array('dba'   => "dba",
654                     'SQL'   => "SQL PEAR",
655                     'ADODB' => "SQL ADODB",
656                     'PDO'   => "PDO (php5 only)",
657                     'file'   => "flatfile",
658                     'cvs'   => "CVS File handler"), "
659 Select the database backend type:
660 Choose dba (default) to use one of the standard UNIX dba libraries. This is the fastest.
661 Choose ADODB or SQL to use an SQL database with ADODB or PEAR.
662 Choose PDO on php5 to use an SQL database.
663 flatfile is simple and slow.
664 CVS is highly experimental and slow.
665 Recommended is dba or SQL: PEAR or ADODB.");
666
667 $properties["SQL DSN Setup"] =
668 new unchangeable_variable('_sqldsnstuff', "", "
669 For SQL based backends, specify the database as a DSN
670 The most general form of a DSN looks like:
671 <pre>
672   phptype(dbsyntax)://username:password@protocol+hostspec/database?option=value
673 </pre>
674 For a MySQL database, the following should work:
675 <pre>
676    mysql://user:password@host/databasename
677 </pre>
678 To connect over a unix socket, use something like
679 <pre>
680    mysql://user:password@unix(/path/to/socket)/databasename
681 </pre>
682 <pre>
683   DATABASE_DSN = mysql://guest@:/var/lib/mysql/mysql.sock/phpwiki
684   DATABASE_DSN = mysql://guest@localhost/phpwiki
685   DATABASE_DSN = pgsql://localhost/user_phpwiki
686 </pre>");
687
688 // Choose ADODB or SQL to use an SQL database with ADODB or PEAR.
689 // Choose dba to use one of the standard UNIX dbm libraries.
690
691 $properties["SQL Type"] =
692 new _variable_selection('_dsn_sqltype',
693               array('mysql'  => "MySQL",
694                     'pgsql'  => "PostgreSQL",
695                     'mssql'  => "Microsoft SQL Server",
696                     'oci8'   => "Oracle 8",
697                     'mysqli' => "mysqli (only ADODB)",
698                     'mysqlt' => "mysqlt (only ADODB)",
699                     'ODBC'   => "ODBC (only ADODB or PDO)",
700                     'firebird' => "Firebird (only PDO)",
701                     'oracle'  => "Oracle (only PDO)",
702 ), "
703 SQL DB types. The DSN hosttype.");
704
705 $properties["SQL User"] =
706 new _variable('_dsn_sqluser', "wikiuser", "
707 SQL User Id:");
708
709 $properties["SQL Password"] =
710 new _variable('_dsn_sqlpass', "", "
711 SQL Password:");
712
713 $properties["SQL Database Host"] =
714 new _variable('_dsn_sqlhostorsock', "localhost", "
715 SQL Database Hostname:
716
717 To connect over a local named socket, use something like
718 <pre>
719   unix(/var/lib/mysql/mysql.sock)
720 </pre>
721 here. 
722 mysql on Windows via named pipes might need 127.0.0.1");
723
724 $properties["SQL Database Name"] =
725 new _variable('_dsn_sqldbname', "phpwiki", "
726 SQL Database Name:");
727
728 $dsn_sqltype = $properties["SQL Type"]->value();
729 $dsn_sqluser = $properties["SQL User"]->value();
730 $dsn_sqlpass = $properties["SQL Password"]->value();
731 $dsn_sqlhostorsock = $properties["SQL Database Host"]->value();
732 $dsn_sqldbname = $properties["SQL Database Name"]->value();
733 $dsn_sqlstring = $dsn_sqltype."://{$dsn_sqluser}:{$dsn_sqlpass}@{$dsn_sqlhostorsock}/{$dsn_sqldbname}";
734
735 $properties["SQL dsn"] =
736 new unchangeable_define("DATABASE_DSN", 
737                         "DATABASE_DSN = \"$dsn_sqlstring\"", "
738 Calculated from the settings above:");
739
740 $properties["Filename / Table name Prefix"] =
741 new _define_commented("DATABASE_PREFIX", DATABASE_PREFIX, "
742 Used by all DB types:
743
744 Prefix for filenames or table names, e.g. \"phpwiki_\"
745
746 Currently <b>you MUST EDIT THE SQL file too!</b> (in the schemas/
747 directory because we aren't doing on the fly sql generation
748 during the installation.");
749
750 $properties["DB Session table"] =
751 new _define_optional("DATABASE_SESSION_TABLE", DATABASE_SESSION_TABLE, "
752 Tablename to store session information. Only supported by SQL backends.
753
754 A word of warning - any prefix defined above will be prepended to whatever is given here.
755 ");
756
757 //TODO: $TEMP
758 $temp = !empty($_ENV['TEMP']) ? $_ENV['TEMP'] : "/tmp";
759 $properties["dba directory"] =
760 new _define("DATABASE_DIRECTORY", $temp, "
761 dba directory:");
762
763 // TODO: list the available methods
764 $properties["dba handler"] =
765 new _define_selection('DATABASE_DBA_HANDLER',
766               array('gdbm' => "Gdbm - GNU database manager (recommended)",
767                     'dbm'  => "DBM - Redhat default. On sf.net there's dbm and gdbm",
768                     'db2'  => "DB2 - Sleepycat Software's DB2",
769                     'db3'  => "DB3 - Sleepycat Software's DB3. Default on Windows but not on every Linux",
770                     'db4'  => "DB4 - Sleepycat Software's DB4."), "
771 Use 'gdbm', 'dbm', 'db2', 'db3' or 'db4' depending on your DBA handler methods supported: <br >  "
772                       . (function_exists("dba_handlers") ? join(", ",dba_handlers()) : ""));
773
774 $properties["dba timeout"] =
775 new numeric_define("DATABASE_TIMEOUT", DATABASE_TIMEOUT, "
776 Recommended values are 10-20 seconds. The more load the server has, the higher the timeout.");
777
778 $properties["DATABASE_PERSISTENT"] =
779 new boolean_define_commented_optional
780 ('DATABASE_PERSISTENT', 
781  array('false' => "Disabled",
782        'true'  => "Enabled"), "
783 Use persistent database connections for SQL databases, if the database backend supports it.
784 Not recommended for heavily loaded servers.
785 Default: false");
786
787 ///////////////////
788
789 $properties["Page Revisions"] =
790 new unchangeable_variable('_parttworevisions', "", "
791
792 Section 2a: Archive Cleanup
793 The next section controls how many old revisions of each page are kept in the database.
794
795 There are two basic classes of revisions: major and minor. Which
796 class a revision belongs in is determined by whether the author
797 checked the \"this is a minor revision\" checkbox when they saved the
798 page.
799  
800 There is, additionally, a third class of revisions: author
801 revisions. The most recent non-mergable revision from each distinct
802 author is and author revision.
803
804 The expiry parameters for each of those three classes of revisions
805 can be adjusted seperately. For each class there are five
806 parameters (usually, only two or three of the five are actually
807 set) which control how long those revisions are kept in the
808 database.
809 <dl>
810    <dt>max_keep:</dt> <dd>If set, this specifies an absolute maximum for the
811             number of archived revisions of that class. This is
812             meant to be used as a safety cap when a non-zero
813             min_age is specified. It should be set relatively high,
814             and it's purpose is to prevent malicious or accidental
815             database overflow due to someone causing an
816             unreasonable number of edits in a short period of time.</dd>
817
818   <dt>min_age:</dt>  <dd>Revisions younger than this (based upon the supplanted
819             date) will be kept unless max_keep is exceeded. The age
820             should be specified in days. It should be a
821             non-negative, real number,</dd>
822
823   <dt>min_keep:</dt> <dd>At least this many revisions will be kept.</dd>
824
825   <dt>keep:</dt>     <dd>No more than this many revisions will be kept.</dd>
826
827   <dt>max_age:</dt>  <dd>No revision older than this age will be kept.</dd>
828 </dl>
829 Supplanted date: Revisions are timestamped at the instant that they
830 cease being the current revision. Revision age is computed using
831 this timestamp, not the edit time of the page.
832
833 Merging: When a minor revision is deleted, if the preceding
834 revision is by the same author, the minor revision is merged with
835 the preceding revision before it is deleted. Essentially: this
836 replaces the content (and supplanted timestamp) of the previous
837 revision with the content after the merged minor edit, the rest of
838 the page metadata for the preceding version (summary, mtime, ...)
839 is not changed.
840 ");
841
842 // For now the expiration parameters are statically inserted as
843 // an unchangeable property. You'll have to edit the resulting
844 // config file if you really want to change these from the default.
845
846 $properties["Major Edits: keep minumum days"] =
847     new numeric_define("MAJOR_MIN_KEEP", MAJOR_MIN_KEEP, "
848 Default: Keep at least for unlimited time. 
849 Set to 0 to enable archive cleanup");
850 $properties["Minor Edits: keep minumum days"] =
851     new numeric_define("MINOR_MIN_KEEP", MINOR_MIN_KEEP, "
852 Default: Keep at least for unlimited time. 
853 Set to 0 to enable archive cleanup");
854
855 $properties["Major Edits: how many"] =
856     new numeric_define("MAJOR_KEEP", MAJOR_KEEP, "
857 Keep up to 8 major edits");
858 $properties["Major Edits: how many days"] =
859     new numeric_define("MAJOR_MAX_AGE", MAJOR_MAX_AGE, "
860 keep them no longer than a month");
861
862 $properties["Minor Edits: how many"] =
863     new numeric_define("MINOR_KEEP", MINOR_KEEP, "
864 Keep up to 4 minor edits");
865 $properties["Minor Edits: how many days"] =
866     new numeric_define("MINOR_MAX_AGE", "7", "
867 keep them no longer than a week");
868
869 $properties["per Author: how many"] =
870     new numeric_define("AUTHOR_KEEP", "8", "
871 Keep the latest contributions of the last 8 authors,");
872 $properties["per Author: how many days"] =
873     new numeric_define("AUTHOR_MAX_AGE", "365", "
874 up to a year.");
875 $properties["per Author: keep minumum days"] =
876     new numeric_define("AUTHOR_MIN_AGE", "7", "
877 Additionally, (in the case of a particularly active page) try to
878 keep the latest contributions of all authors in the last week (even if there are more than eight of them,)");
879 $properties["per Author: max revisions"] =
880     new numeric_define("AUTHOR_MAX_KEEP", "20", "
881 but in no case keep more than twenty unique author revisions.");
882
883 /////////////////////////////////////////////////////////////////////
884
885 $properties["Part Three"] =
886 new part('_part3', $SEPARATOR."\n", "
887
888 Part Three: (optional)
889 Basic User Authentication Setup
890 ");
891
892 $properties["Publicly viewable"] =
893 new boolean_define_optional('ALLOW_ANON_USER',
894                     array('true'  => "true. Permit anonymous view. (Default)",
895                           'false' => "false. Force login even on view (strictly private)"), "
896 If ALLOW_ANON_USER is false, you have to login before viewing any page or doing any other action on a page.");
897
898 $properties["Allow anonymous edit"] =
899 new boolean_define_optional('ALLOW_ANON_EDIT',
900                     array('true'  => "true. Permit anonymous users to edit. (Default)",
901                           'false' => "false. Force login on edit (moderately locked)"), "
902 If ALLOW_ANON_EDIT is false, you have to login before editing or changing any page. See below.");
903
904 $properties["Allow Bogo Login"] =
905 new boolean_define_optional('ALLOW_BOGO_LOGIN',
906                     array('true'  => "true. Users may Sign In with any WikiWord, without password. (Default)",
907                           'false' => "false. Require stricter authentication."), "
908 If ALLOW_BOGO_LOGIN is false, you may not login with any wikiword username and empty password. 
909 If true, users are allowed to create themselves with any WikiWord username. See below.");
910
911 $properties["Allow User Passwords"] =
912 new boolean_define_optional('ALLOW_USER_PASSWORDS',
913                     array('true'  => "True user authentication with password checking. (Default)",
914                           'false' => "false. Ignore authentication settings below."), "
915 If ALLOW_USER_PASSWORDS is true, the authentication settings below define where and how to 
916 check against given username/passwords. For completely security disable BOGO_LOGIN and ANON_EDIT above.");
917
918 $properties["Allow User Passwords"] =
919     new array_define('USER_AUTH_ORDER', array("PersonalPage", "Db"), "
920 Many different methods can be used to check user's passwords. 
921 Try any of these in the given order:
922 <dl>
923 <dt>BogoLogin</dt>
924         <dd>WikiWord username, with no *actual* password checking,
925         although the user will still have to enter one.</dd>
926 <dt>PersonalPage</dt>
927         <dd>Store passwords in the users homepage metadata (simple)</dd>
928 <dt>Db</dt>
929         <dd>Use DBAUTH_AUTH_* (see below) with PearDB or ADODB only.</dd>
930 <dt>LDAP</dt>
931         <dd>Authenticate against LDAP_AUTH_HOST with LDAP_BASE_DN.</dd>
932 <dt>IMAP</dt>
933         <dd>Authenticate against IMAP_AUTH_HOST (email account)</dd>
934 <dt>POP3</dt>
935         <dd>Authenticate against POP3_AUTH_HOST (email account)</dd>
936 <dt>Session</dt>
937         <dd>Get username and level from a PHP session variable. (e.g. for gforge)</dd>
938 <dt>File</dt>
939         <dd>Store username:crypted-passwords in .htaccess like files. 
940          Use Apache's htpasswd to manage this file.</dd>
941 <dt>HttpAuth</dt>
942         <dd>Use the protection by the webserver (.htaccess/.htpasswd) (experimental)
943         Enforcing HTTP Auth not yet. Note that the ADMIN_USER should exist also.
944         Using HttpAuth disables all other methods and no userauth sessions are used.</dd>
945 </dl>
946
947 Several of these methods can be used together, in the manner specified by
948 USER_AUTH_POLICY, below.  To specify multiple authentication methods,
949 separate the name of each one with colons.
950 <pre>
951   USER_AUTH_ORDER = 'PersonalPage : Db'
952   USER_AUTH_ORDER = 'BogoLogin : PersonalPage'
953 </pre>");
954
955 $properties["PASSWORD_LENGTH_MINIMUM"] =
956     new numeric_define("PASSWORD_LENGTH_MINIMUM", "6", "
957 For 'security' purposes, you can specify that a password be at least a
958 certain number of characters long.  This applies even to the BogoLogin method. 
959 Default: 0 (to allow immediate passwordless BogoLogin)");
960
961 $properties["USER_AUTH_POLICY"] =
962 new _define_selection('USER_AUTH_POLICY',
963               array('first-only' => "first-only - use only the first method in USER_AUTH_ORDER",
964                     'old'       => "old - ignore USER_AUTH_ORDER (legacy)",
965                     'strict'    => "strict - check all methods for userid + password (recommended)",
966                     'stacked'   => "stacked - check all methods for userid, and if found for password"), "
967 The following policies are available for user authentication:
968 <dl>
969 <dt>first-only</dt>
970         <dd>use only the first method in USER_AUTH_ORDER</dd>
971 <dt>old</dt>
972         <dd>ignore USER_AUTH_ORDER and try to use all available 
973         methods as in the previous PhpWiki releases (slow)</dd>
974 <dt>strict</dt>
975         <dd>check if the user exists for all methods: 
976         on the first existing user, try the password. 
977         dont try the other methods on failure then</dd>
978 <dt>stacked</dt>
979         <dd>check the given user - password combination for all
980         methods and return true on the first success.</dd></dl>");
981
982 ///////////////////
983
984 $properties["Part Three A"] =
985 new part('_part3a', $SEPARATOR."\n", "
986
987 Part Three A: (optional)
988 Group Membership");
989
990 $properties["Group membership"] =
991 new _define_selection("GROUP_METHOD",
992               array('WIKIPAGE' => "WIKIPAGE - List at \"CategoryGroup\". (Slowest, but easiest to maintain)",
993                     '"NONE"'   => "NONE - Disable group membership (Fastest)",
994                     'DB'       => "DB - SQL Database, Optionally external. See USERS/GROUPS queries",
995                     'FILE'     => "Flatfile. See AUTH_GROUP_FILE below.",
996                     'LDAP'     => "LDAP - See \"LDAP authentication options\" above. (Experimental)"), "
997 Group membership.  PhpWiki supports defining permissions for a group as
998 well as for individual users.  This defines how group membership information
999 is obtained.  Supported values are:
1000 <dl>
1001 <dt>\"NONE\"</dt>
1002           <dd>Disable group membership (Fastest). Note the required quoting.</dd>
1003 <dt>WIKIPAGE</dt>
1004           <dd>Define groups as list at \"CategoryGroup\". (Slowest, but easiest to maintain)</dd>
1005 <dt>DB</dt>
1006           <dd>Stored in an SQL database. Optionally external. See USERS/GROUPS queries</dd>
1007 <dt>FILE</dt>
1008           <dd>Flatfile. See AUTH_GROUP_FILE below.</dd>
1009 <dt>LDAP</dt>
1010           <dd>LDAP groups. See \"LDAP authentication options\" above and 
1011           lib/WikiGroup.php. (experimental)</dd></dl>");
1012
1013 $properties["CATEGORY_GROUP_PAGE"] =
1014   new _define_optional('CATEGORY_GROUP_PAGE', _("CategoryGroup"), "
1015 If GROUP_METHOD = WIKIPAGE:
1016
1017 Page where all groups are listed.");
1018
1019 $properties["AUTH_GROUP_FILE"] =
1020   new _define_optional('AUTH_GROUP_FILE', _("/etc/groups"), "
1021 For GROUP_METHOD = FILE, the file given below is referenced to obtain
1022 group membership information.  It should be in the same format as the
1023 standard unix /etc/groups(5) file.");
1024
1025 $properties["Part Three B"] =
1026 new part('_part3b', $SEPARATOR."\n", "
1027
1028 Part Three B: (optional)
1029 External database authentication and authorization.
1030
1031 If USER_AUTH_ORDER includes Db, or GROUP_METHOD = DB, the options listed
1032 below define the SQL queries used to obtain the information out of the
1033 database, and (optionally) store the information back to the DB.");
1034
1035 $properties["DBAUTH_AUTH_DSN"] =
1036   new _define_optional('DBAUTH_AUTH_DSN', $dsn_sqlstring, "
1037 A database DSN to connect to.  Defaults to the DSN specified for the Wiki as a whole.");
1038
1039 $properties["User Exists Query"] =
1040   new _define('DBAUTH_AUTH_USER_EXISTS', "SELECT userid FROM user WHERE userid='\$userid'", "
1041 USER/PASSWORD queries:
1042
1043 For USER_AUTH_POLICY=strict and the Db method is required");
1044
1045 $properties["Check Query"] =
1046   new _define_optional('DBAUTH_AUTH_CHECK', "SELECT IF(passwd='\$password',1,0) AS ok FROM user WHERE userid='\$userid'", "
1047
1048 Check to see if the supplied username/password pair is OK
1049
1050 Plaintext passwords: (DBAUTH_AUTH_CRYPT_METHOD = plain)<br>
1051 ; DBAUTH_AUTH_CHECK = \"SELECT IF(passwd='\$password',1,0) AS ok FROM user WHERE userid='\$userid'\"
1052
1053 database-hashed passwords (more secure):<br>
1054 ; DBAUTH_AUTH_CHECK = \"SELECT IF(passwd=PASSWORD('\$password'),1,0) AS ok FROM user WHERE userid='\$userid'\"");
1055
1056 $properties["Crypt Method"] =
1057 new _define_selection_optional
1058 ('DBAUTH_AUTH_CRYPT_METHOD',
1059  array('plain' => 'plain',
1060        'crypt' => 'crypt'), "
1061 If you want to use Unix crypt()ed passwords, you can use DBAUTH_AUTH_CHECK
1062 to get the password out of the database with a simple SELECT query, and
1063 specify DBAUTH_AUTH_USER_EXISTS and DBAUTH_AUTH_CRYPT_METHOD:
1064
1065 ; DBAUTH_AUTH_CHECK = \"SELECT passwd FROM user where userid='\$userid'\" <br>
1066 ; DBAUTH_AUTH_CRYPT_METHOD = crypt");
1067
1068 $properties["Update the user's authentication credential"] =
1069     new _define('DBAUTH_AUTH_UPDATE', "UPDATE user SET passwd='\$password' WHERE userid='\$userid'", "
1070 If this is not defined but DBAUTH_AUTH_CHECK is, then the user will be unable to update their
1071 password.
1072
1073 Plaintext passwords:<br>
1074   DBAUTH_AUTH_UPDATE = \"UPDATE user SET passwd='\$password' WHERE userid='\$userid'\"<br>
1075 Database-hashed passwords:<br>
1076   DBAUTH_AUTH_UPDATE = \"UPDATE user SET passwd=PASSWORD('\$password') WHERE userid='\$userid'\"");
1077
1078 $properties["Allow the user to create their own account"] =
1079     new _define_optional('DBAUTH_AUTH_CREATE', "INSERT INTO user SET passwd=PASSWORD('\$password'),userid='\$userid'", "
1080 If this is empty, Db users cannot subscribe by their own.");
1081
1082 $properties["USER/PREFERENCE queries"] =
1083     new _define_optional('DBAUTH_PREF_SELECT', "SELECT prefs FROM user WHERE userid='\$userid'", "
1084 If you choose to store your preferences in an external database, enable
1085 the following queries.  Note that if you choose to store user preferences
1086 in the 'user' table, only registered users get their prefs from the database,
1087 self-created users do not.  Better to use the special 'pref' table.
1088
1089 The prefs field stores the serialized form of the user's preferences array,
1090 to ease the complication of storage.
1091 <pre>
1092   DBAUTH_PREF_SELECT = \"SELECT prefs FROM user WHERE userid='\$userid'\"
1093   DBAUTH_PREF_SELECT = \"SELECT prefs FROM pref WHERE userid='\$userid'\"
1094 </pre>");
1095
1096 $properties["Update the user's preferences"] =
1097     new _define_optional('DBAUTH_PREF_UPDATE', "UPDATE user SET prefs='\$pref_blob' WHERE userid='\$userid'", "
1098 Note that REPLACE works only with mysql and destroy all other columns!
1099
1100 Mysql: DBAUTH_PREF_UPDATE = \"REPLACE INTO pref SET prefs='\$pref_blob',userid='\$userid'\"");
1101
1102 $properties["USERS/GROUPS queries"] =
1103     new _define_optional('DBAUTH_IS_MEMBER', "SELECT user FROM user WHERE user='\$userid' AND group='\$groupname'", "
1104 You can define 1:n or n:m user<=>group relations, as you wish.
1105
1106 Sample configurations:
1107
1108 only one group per user (1:n):<br>
1109    DBAUTH_IS_MEMBER = \"SELECT user FROM user WHERE user='\$userid' AND group='\$groupname'\"<br>
1110    DBAUTH_GROUP_MEMBERS = \"SELECT user FROM user WHERE group='\$groupname'\"<br>
1111    DBAUTH_USER_GROUPS = \"SELECT group FROM user WHERE user='\$userid'\"<br>
1112 multiple groups per user (n:m):<br>
1113    DBAUTH_IS_MEMBER = \"SELECT userid FROM member WHERE userid='\$userid' AND groupname='\$groupname'\"<br>
1114    DBAUTH_GROUP_MEMBERS = \"SELECT DISTINCT userid FROM member WHERE groupname='\$groupname'\"<br>
1115    DBAUTH_USER_GROUPS = \"SELECT groupname FROM member WHERE userid='\$userid'\"<br>");
1116 $properties["DBAUTH_GROUP_MEMBERS"] =
1117     new _define_optional('DBAUTH_GROUP_MEMBERS', "SELECT user FROM user WHERE group='\$groupname'", "");
1118 $properties["DBAUTH_USER_GROUPS"] =
1119     new _define_optional('DBAUTH_USER_GROUPS', "SELECT group FROM user WHERE user='\$userid'", "");
1120
1121 if (function_exists('ldap_connect')) {
1122
1123 $properties["LDAP AUTH Host"] =
1124   new _define_optional('LDAP_AUTH_HOST', "ldap://localhost:389", "
1125 If USER_AUTH_ORDER contains Ldap:
1126
1127 The LDAP server to connect to.  Can either be a hostname, or a complete
1128 URL to the server (useful if you want to use ldaps or specify a different
1129 port number).");
1130
1131 $properties["LDAP BASE DN"] =
1132   new _define_optional('LDAP_BASE_DN', "ou=mycompany.com,o=My Company", "
1133 The organizational or domain BASE DN: e.g. \"dc=mydomain,dc=com\".
1134
1135 Note: ou=Users and ou=Groups are used for GroupLdap Membership
1136 Better use LDAP_OU_USERS and LDAP_OU_GROUP with GROUP_METHOD=LDAP.");
1137
1138 $properties["LDAP SET OPTION"] =
1139     new _define_optional('LDAP_SET_OPTION', "LDAP_OPT_PROTOCOL_VERSION=3:LDAP_OPT_REFERRALS=0", "
1140 Some LDAP servers need some more options, such as the Windows Active
1141 Directory Server.  Specify the options (as allowed by the PHP LDAP module)
1142 and their values as NAME=value pairs separated by colons.");
1143
1144 $properties["LDAP AUTH USER"] =
1145     new _define_optional('LDAP_AUTH_USER', "CN=ldapuser,ou=Users,o=Development,dc=mycompany.com", "
1146 DN to initially bind to the LDAP server as. This is needed if the server doesn't 
1147 allow anonymous queries. (Windows Active Directory Server)");
1148
1149 $properties["LDAP AUTH PASSWORD"] =
1150     new _define_optional('LDAP_AUTH_PASSWORD', "secret", "
1151 Password to use to initially bind to the LDAP server, as the DN 
1152 specified in the LDAP_AUTH_USER option (above).");
1153
1154 $properties["LDAP SEARCH FIELD"] =
1155     new _define_optional('LDAP_SEARCH_FIELD', "uid", "
1156 If you want to match usernames against an attribute other than uid,
1157 specify it here. Default: uid
1158
1159 e.g.: LDAP_SEARCH_FIELD = sAMAccountName");
1160
1161 $properties["LDAP OU USERS"] =
1162     new _define_optional('LDAP_OU_USERS', "ou=Users", "
1163 If you have an organizational unit for all users, define it here.
1164 This narrows the search, and is needed for LDAP group membership (if GROUP_METHOD=LDAP)
1165 Default: ou=Users");
1166
1167 $properties["LDAP OU GROUP"] =
1168     new _define_optional('LDAP_OU_GROUP', "ou=Groups", "
1169 If you have an organizational unit for all groups, define it here.
1170 This narrows the search, and is needed for LDAP group membership (if GROUP_METHOD=LDAP)
1171 The entries in this ou must have a gidNumber and cn attribute.
1172 Default: ou=Groups");
1173
1174 } else { // function_exists('ldap_connect')
1175
1176 $properties["LDAP Authentication"] =
1177 new unchangeable_define('LDAP Authentication', "
1178 ; If USER_AUTH_ORDER contains Ldap:
1179
1180 ; The LDAP server to connect to.  Can either be a hostname, or a complete
1181 ; URL to the server (useful if you want to use ldaps or specify a different
1182 ; port number).
1183 ;LDAP_AUTH_HOST = \"ldap://localhost:389\"
1184
1185 ; The organizational or domain BASE DN: e.g. \"dc=mydomain,dc=com\".
1186 ;
1187 ; Note: ou=Users and ou=Groups are used for GroupLdap Membership
1188 ; Better use LDAP_OU_USERS and LDAP_OU_GROUP with GROUP_METHOD=LDAP.
1189 ;LDAP_BASE_DN = \"ou=Users,o=Development,dc=mycompany.com\"
1190
1191 ; Some LDAP servers need some more options, such as the Windows Active
1192 ; Directory Server.  Specify the options (as allowed by the PHP LDAP module)
1193 ; and their values as NAME=value pairs separated by colons.
1194 ; LDAP_SET_OPTION = \"LDAP_OPT_PROTOCOL_VERSION=3:LDAP_OPT_REFERRALS=0\"
1195
1196 ; DN to initially bind to the LDAP server as. This is needed if the server doesn't 
1197 ; allow anonymous queries. (Windows Active Directory Server)
1198 ; LDAP_AUTH_USER = \"CN=ldapuser,ou=Users,o=Development,dc=mycompany.com\"
1199
1200 ; Password to use to initially bind to the LDAP server, as the DN 
1201 ; specified in the LDAP_AUTH_USER option (above).
1202 ; LDAP_AUTH_PASSWORD = secret
1203
1204 ; If you want to match usernames against an attribute other than uid,
1205 ; specify it here. Default: uid
1206 ; LDAP_SEARCH_FIELD = sAMAccountName
1207
1208 ; If you have an organizational unit for all users, define it here.
1209 ; This narrows the search, and is needed for LDAP group membership (if GROUP_METHOD=LDAP)
1210 ; Default: ou=Users
1211 ; LDAP_OU_USERS = ou=Users
1212
1213 ; If you have an organizational unit for all groups, define it here.
1214 ; This narrows the search, and is needed for LDAP group membership (if GROUP_METHOD=LDAP)
1215 ; The entries in this ou must have a gidNumber and cn attribute.
1216 ; Default: ou=Groups
1217 ; LDAP_OU_GROUP = ou=Groups", "
1218 ; Ignored. No LDAP support in this php. configure --with-ldap");
1219 }
1220
1221 if (function_exists('imap_open')) {
1222
1223 $properties["IMAP Auth Host"] =
1224   new _define_optional('IMAP_AUTH_HOST', 'localhost:143/imap/notls', "
1225 If USER_AUTH_ORDER contains IMAP:
1226
1227 The IMAP server to check usernames from. Defaults to localhost.
1228
1229 Some IMAP_AUTH_HOST samples:
1230   localhost, localhost:143/imap/notls, 
1231   localhost:993/imap/ssl/novalidate-cert (SuSE refuses non-SSL conections)");
1232
1233 } else { // function_exists('imap_open')
1234
1235 $properties["IMAP Authentication"] =
1236   new unchangeable_define('IMAP_AUTH_HOST',"
1237 ; If USER_AUTH_ORDER contains IMAP:
1238 ; The IMAP server to check usernames from. Defaults to localhost.
1239
1240 ; Some IMAP_AUTH_HOST samples:
1241 ;   localhost, localhost:143/imap/notls, 
1242 ;   localhost:993/imap/ssl/novalidate-cert (SuSE refuses non-SSL conections)
1243 ;IMAP_AUTH_HOST = localhost:143/imap/notls", "
1244 Ignored. No IMAP support in this php. configure --with-imap");
1245
1246 }
1247
1248 $properties["POP3 Authentication"] =
1249   new _define_optional('POP3_AUTH_HOST', 'localhost:110', "
1250 If USER_AUTH_ORDER contains POP3:
1251
1252 The POP3 mail server to check usernames and passwords against.");
1253 $properties["File Authentication"] =
1254   new _define_optional('AUTH_USER_FILE', '/etc/shadow', "
1255 If USER_AUTH_ORDER contains File:
1256
1257 File to read for authentication information.
1258 Popular choices are /etc/shadow and /etc/httpd/.htpasswd");
1259
1260 $properties["File Storable?"] =
1261 new boolean_define_commented_optional
1262 ('AUTH_USER_FILE_STORABLE',
1263  array('false'  => "Disabled",
1264        'true'   => "Enabled"), "
1265 Defines whether the user is able to change their own password via PhpWiki.
1266 Note that this means that the webserver user must be able to write to the
1267 file specified in AUTH_USER_FILE.");
1268
1269 $properties["Session Auth USER"] =
1270   new _define_optional('AUTH_SESS_USER', 'userid', "
1271 If USER_AUTH_ORDER contains Session:
1272
1273 Name of the session variable which holds the already authenticated username.
1274 Sample: 'userid', 'user[username]', 'user->username'");
1275
1276 $properties["Session Auth LEVEL"] =
1277   new numeric_define('AUTH_SESS_LEVEL', '2', "
1278 Which level will the user be? 1 = Bogo or 2 = Pass");
1279
1280 /////////////////////////////////////////////////////////////////////
1281
1282 $properties["Part Four"] =
1283 new part('_part4', $SEPARATOR."\n", "
1284
1285 Part Four:
1286 Page appearance and layout");
1287
1288 $properties["Theme"] =
1289 new _define_selection_optional('THEME',
1290               array('default'  => "default",
1291                     'MacOSX'   => "MacOSX",
1292                     'smaller'  => 'smaller',
1293                     'Wordpress'=> 'Wordpress',
1294                     'Portland' => "Portland",
1295                     'Sidebar'  => "Sidebar",
1296                     'Crao'     => 'Crao',
1297                     'wikilens' => 'wikilens (Ratings)',
1298                     'shamino_com' => 'shamino_com',
1299                     'SpaceWiki' => "SpaceWiki",
1300                     'Hawaiian' => "Hawaiian",
1301                     'MonoBook'  => 'MonoBook [experimental]',
1302                     'blog'      => 'blog [experimental]',
1303                     ), "
1304 THEME
1305
1306 Most of the page appearance is controlled by files in the theme
1307 subdirectory.
1308
1309 There are a number of pre-defined themes shipped with PhpWiki.
1310 Or you may create your own (e.g. by copying and then modifying one of
1311 stock themes.)
1312 <pre>
1313   THEME = default
1314   THEME = MacOSX
1315   THEME = smaller
1316   THEME = Wordpress
1317   THEME = Portland
1318   THEME = Sidebar
1319   THEME = Crao
1320   THEME = wikilens (Ratings)
1321   THEME = Hawaiian
1322   THEME = SpaceWiki
1323   THEME = Hawaiian
1324 </pre>
1325   
1326 Problems:
1327 <pre>
1328   THEME = MonoBook (WikiPedia) [experimental. MSIE problems]
1329   THEME = blog     (Kubrick)   [experimental. Several links missing]
1330 </pre>");
1331
1332 $properties["Character Set"] =
1333 new _define_optional('CHARSET', 'iso-8859-1', "
1334 Select a valid charset name to be inserted into the xml/html pages, 
1335 and to reference links to the stylesheets (css). For more info see: 
1336 http://www.iana.org/assignments/character-sets. Note that PhpWiki 
1337 has been extensively tested only with the latin1 (iso-8859-1) 
1338 character set.
1339
1340 If you change the default from iso-8859-1 PhpWiki may not work 
1341 properly and it will require code modifications. However, character 
1342 sets similar to iso-8859-1 may work with little or no modification 
1343 depending on your setup. The database must also support the same 
1344 charset, and of course the same is true for the web browser. (Some 
1345 work is in progress hopefully to allow more flexibility in this 
1346 area in the future).");
1347
1348 $properties["Language"] =
1349 new _define_selection_optional('DEFAULT_LANGUAGE',
1350                array('en' => "English",
1351                      ''   => "<empty> (user-specific)",
1352                      'fr' => "Fran~is",
1353                      'de' => "Deutsch",
1354                      'nl' => "Nederlands",
1355                      'es' => "Espa~l",
1356                      'sv' => "Svenska",
1357                      'it' => "Italiano",
1358                      'ja' => "Japanese",
1359                      'zh' => "Chinese"), "
1360 Select your language/locale - default language is \"en\" for English.
1361 Other languages available:<pre>
1362 English \"en\"  (English    - HomePage)
1363 German  \"de\" (Deutsch    - StartSeite)
1364 French  \"fr\" (Fran~is   - Accueil)
1365 Dutch   \"nl\" (Nederlands - ThuisPagina)
1366 Spanish \"es\" (Espa~l    - P~inaPrincipal)
1367 Swedish \"sv\" (Svenska    - Framsida)
1368 Italian \"it\" (Italiano   - PaginaPrincipale)
1369 Japanese \"ja\" (Japanese   - ~~~~~~)
1370 Chinese  \"zh\" (Chinese)
1371 </pre>
1372 If you set DEFAULT_LANGUAGE to the empty string, your systems default language
1373 (as determined by the applicable environment variables) will be
1374 used.");
1375
1376 $properties["Wiki Page Source"] =
1377 new _define_optional('WIKI_PGSRC', 'pgsrc', "
1378 WIKI_PGSRC -- specifies the source for the initial page contents of
1379 the Wiki. The setting of WIKI_PGSRC only has effect when the wiki is
1380 accessed for the first time (or after clearing the database.)
1381 WIKI_PGSRC can either name a directory or a zip file. In either case
1382 WIKI_PGSRC is scanned for files -- one file per page.
1383 <pre>
1384 // Default (old) behavior:
1385 define('WIKI_PGSRC', 'pgsrc'); 
1386 // New style:
1387 define('WIKI_PGSRC', 'wiki.zip'); 
1388 define('WIKI_PGSRC', 
1389        '../Logs/Hamwiki/hamwiki-20010830.zip'); 
1390 </pre>");
1391
1392 /*
1393 $properties["Default Wiki Page Source"] =
1394 new _define('DEFAULT_WIKI_PGSRC', 'pgsrc', "
1395 DEFAULT_WIKI_PGSRC is only used when the language is *not* the
1396 default (English) and when reading from a directory: in that case
1397 some English pages are inserted into the wiki as well.
1398 DEFAULT_WIKI_PGSRC defines where the English pages reside.
1399
1400 FIXME: is this really needed?
1401 ");
1402
1403 $properties["Generic Pages"] =
1404 new array_variable('GenericPages', array('ReleaseNotes', 'SteveWainstead', 'TestPage'), "
1405 These are the pages which will get loaded from DEFAULT_WIKI_PGSRC.      
1406
1407 FIXME: is this really needed?  Cannot we just copy these pages into
1408 the localized pgsrc?
1409 ");
1410 */
1411
1412 ///////////////////
1413
1414 $properties["Part Five"] =
1415 new part('_part5', $SEPARATOR."\n", "
1416
1417 Part Five:
1418 Mark-up options");
1419
1420 $properties["Allowed Protocols"] =
1421 new list_define('ALLOWED_PROTOCOLS', 'http|https|mailto|ftp|news|nntp|ssh|gopher', "
1422 Allowed protocols for links - be careful not to allow \"javascript:\"
1423 URL of these types will be automatically linked.
1424 within a named link [name|uri] one more protocol is defined: phpwiki");
1425
1426 $properties["Inline Images"] =
1427 new list_define('INLINE_IMAGES', 'png|jpg|gif', "
1428 URLs ending with the following extension should be inlined as images. 
1429 Scripts shoud not be allowed!");
1430
1431 $properties["WikiName Regexp"] =
1432 new _define('WIKI_NAME_REGEXP', "(?<![[:alnum:]])(?:[[:upper:]][[:lower:]]+){2,}(?![[:alnum:]])", "
1433 Perl regexp for WikiNames (\"bumpy words\")
1434 (?&lt;!..) &amp; (?!...) used instead of '\b' because \b matches '_' as well");
1435
1436 $properties["Subpage Separator"] =
1437 new _define_optional('SUBPAGE_SEPARATOR', '"/"', "
1438 One character which seperates pages from subpages. Defaults to '/', but '.' or ':' were also used.",
1439 "onchange=\"validate_ereg('Sorry, \'%s\' must be a single character. Currently only :, / or .', '^[/:.]$', 'SUBPAGE_SEPARATOR', this);\""
1440 );
1441
1442 $properties["InterWiki Map File"] =
1443 new _define('INTERWIKI_MAP_FILE', 'lib/interwiki.map', "
1444 InterWiki linking -- wiki-style links to other wikis on the web
1445
1446 The map will be taken from a page name InterWikiMap.
1447 If that page is not found (or is not locked), or map
1448 data can not be found in it, then the file specified
1449 by INTERWIKI_MAP_FILE (if any) will be used.");
1450
1451 $properties["WARN_NONPUBLIC_INTERWIKIMAP"] =
1452 new boolean_define('WARN_NONPUBLIC_INTERWIKIMAP',   
1453         array('true'  => "true",
1454               'false' => "false"), "
1455 Display a warning if the internal lib/interwiki.map is used, and 
1456 not the public InterWikiMap page. This map is not readable from outside.");
1457
1458
1459 $properties["Keyword Link Regexp"] =
1460 new _define_optional('KEYWORDS', '\"Category* OR Topic*\"', "
1461 Search term used for automatic page classification by keyword extraction.
1462
1463 Any links on a page to pages whose names match this search 
1464 will be used keywords in the keywords html meta tag. This is an aid to
1465 classification by search engines. The value of the match is
1466 used as the keyword.
1467
1468 The default behavior is to match Category* or Topic* links.");
1469
1470 $properties["Author and Copyright Site Navigation Links"] =
1471 new _define_commented_optional('COPYRIGHTPAGE_TITLE', "GNU General Public License", "
1472
1473 These will be inserted as <link rel> tags in the html header of
1474 every page, for search engines and for browsers like Mozilla which
1475 take advantage of link rel site navigation.
1476
1477 If you have your own copyright and contact information pages change
1478 these as appropriate.");
1479
1480 $properties["COPYRIGHTPAGE URL"] =
1481 new _define_commented_optional('COPYRIGHTPAGE_URL', "http://www.gnu.org/copyleft/gpl.html#SEC1", "
1482
1483 Other useful alternatives to consider:
1484 <pre>
1485  COPYRIGHTPAGE_TITLE = \"GNU Free Documentation License\"
1486  COPYRIGHTPAGE_URL = \"http://www.gnu.org/copyleft/fdl.html\"
1487  COPYRIGHTPAGE_TITLE = \"Creative Commons License 2.0\"
1488  COPYRIGHTPAGE_URL = \"http://creativecommons.org/licenses/by/2.0/\"</pre>
1489 See http://creativecommons.org/learn/licenses/ for variations");
1490
1491 $properties["AUTHORPAGE_TITLE"] =
1492     new _define_commented_optional('AUTHORPAGE_TITLE', "The PhpWiki Programming Team", "
1493 Default Author Names");
1494 $properties["AUTHORPAGE_URL"] =
1495     new _define_commented_optional('AUTHORPAGE_URL', "http://phpwiki.org/ThePhpWikiProgrammingTeam", "
1496 Default Author URL");
1497
1498 $properties["TOC_FULL_SYNTAX"] =
1499 new boolean_define_optional
1500 ('TOC_FULL_SYNTAX', 
1501  array('true'  => "Enabled",
1502        'false' => "Disabled"), "
1503 Allow full markup in headers to be parsed by the CreateToc plugin.
1504
1505 If false you may not use WikiWords or [] links or any other markup in 
1506 headers in pages with the CreateToc plugin. But if false the parsing is 
1507 faster and more stable.");
1508
1509 $properties["ENABLE_MARKUP_COLOR"] =
1510 new boolean_define_optional
1511 ('ENABLE_MARKUP_COLOR', 
1512  array('true'  => "Enabled",
1513        'false' => "Disabled"), "
1514 If disabled the %color=... %% syntax will be disabled. Since 1.3.11
1515 Default: true");
1516
1517 $properties["ENABLE_MARKUP_TEMPLATE"] =
1518 new boolean_define_optional
1519 ('ENABLE_MARKUP_TEMPLATE', 
1520  array('true'  => "Enabled",
1521        'false' => "Disabled"), "
1522 Enable mediawiki-style {{TemplatePage|vars=value|...}} syntax. Since 1.3.11
1523 Default: undefined. Enabled automatically on the MonoBook theme if undefined.");
1524
1525 ///////////////////
1526
1527 $properties["Part Six"] =
1528 new part('_part6', $SEPARATOR."\n", "
1529
1530 Part Six (optional):
1531 URL options -- you can probably skip this section.
1532
1533 For a pretty wiki (no index.php in the url) set a seperate DATA_PATH.");
1534
1535 global $HTTP_SERVER_VARS;
1536 $properties["Server Name"] =
1537 new _define_commented_optional('SERVER_NAME', $HTTP_SERVER_VARS['SERVER_NAME'], "
1538 Canonical name of the server on which this PhpWiki resides.");
1539
1540 $properties["Server Port"] =
1541 new numeric_define_commented('SERVER_PORT', $HTTP_SERVER_VARS['SERVER_PORT'], "
1542 Canonical httpd port of the server on which this PhpWiki resides.",
1543 "onchange=\"validate_ereg('Sorry, \'%s\' is no valid port number.', '^[0-9]+$', 'SERVER_PORT', this);\"");
1544
1545 $properties["Script Name"] =
1546 new _define_commented_optional('SCRIPT_NAME', $scriptname, "
1547 Relative URL (from the server root) of the PhpWiki script.");
1548
1549 $properties["Data Path"] =
1550 new _define_commented_optional('DATA_PATH', dirname($scriptname), "
1551 URL of the PhpWiki install directory.  (You only need to set this
1552 if you've moved index.php out of the install directory.)  This can
1553 be either a relative URL (from the directory where the top-level
1554 PhpWiki script is) or an absolute one.");
1555
1556
1557 $properties["PhpWiki Install Directory"] =
1558 new _define_commented_optional('PHPWIKI_DIR', dirname(__FILE__), "
1559 Path to the PhpWiki install directory.  This is the local
1560 filesystem counterpart to DATA_PATH.  (If you have to set
1561 DATA_PATH, your probably have to set this as well.)  This can be
1562 either an absolute path, or a relative path interpreted from the
1563 directory where the top-level PhpWiki script (normally index.php)
1564 resides.");
1565
1566 $properties["Use PATH_INFO"] =
1567 new _define_selection_optional_commented('USE_PATH_INFO', 
1568                     array(''      => 'automatic',
1569                           'true'  => 'use PATH_INFO',
1570                           'false' => 'do not use PATH_INFO'), "
1571 PhpWiki will try to use short urls to pages, eg 
1572 http://www.example.com/index.php/HomePage
1573 If you want to use urls like 
1574 http://www.example.com/index.php?pagename=HomePage
1575 then define 'USE_PATH_INFO' as false by uncommenting the line below.
1576 NB:  If you are using Apache >= 2.0.30, then you may need to to use
1577 the directive \"AcceptPathInfo On\" in your Apache configuration file
1578 (or in an appropriate <.htaccess> file) for the short urls to work:  
1579 See http://httpd.apache.org/docs-2.0/mod/core.html#acceptpathinfo
1580
1581 See also http://phpwiki.sourceforge.net/phpwiki/PrettyWiki for more ideas
1582 on prettifying your urls.
1583
1584 Default: PhpWiki will try to divine whether use of PATH_INFO
1585 is supported in by your webserver/PHP configuration, and will
1586 use PATH_INFO if it thinks that is possible.");
1587
1588 $properties["Virtual Path"] =
1589 new _define_commented_optional('VIRTUAL_PATH', '/SomeWiki', "
1590 VIRTUAL_PATH is the canonical URL path under which your your wiki
1591 appears. Normally this is the same as dirname(SCRIPT_NAME), however
1592 using e.g. seperate starter scripts, apaches mod_actions (or mod_rewrite), 
1593 you can make it something different.
1594
1595 If you do this, you should set VIRTUAL_PATH here or in the starter scripts.
1596
1597 E.g. your phpwiki might be installed at at /scripts/phpwiki/index.php,
1598 but you've made it accessible through eg. /wiki/HomePage.
1599
1600 One way to do this is to create a directory named 'wiki' in your
1601 server root. The directory contains only one file: an .htaccess
1602 file which reads something like:
1603 <pre>
1604     Action x-phpwiki-page /scripts/phpwiki/index.php
1605     SetHandler x-phpwiki-page
1606     DirectoryIndex /scripts/phpwiki/index.php
1607 </pre>
1608 In that case you should set VIRTUAL_PATH to '/wiki'.
1609
1610 (VIRTUAL_PATH is only used if USE_PATH_INFO is true.)
1611 ");
1612
1613 ///////////////////
1614
1615 $properties["Part Seven"] =
1616 new part('_part7', $SEPARATOR."\n", "
1617
1618 Part Seven:
1619
1620 Miscellaneous settings
1621 ");
1622
1623 $properties["Strict Mailable Pagedumps"] =
1624 new boolean_define_optional
1625 ('STRICT_MAILABLE_PAGEDUMPS', 
1626  array('false' => "binary",
1627        'true'  => "quoted-printable"),
1628 "
1629 If you define this to true, (MIME-type) page-dumps (either zip dumps,
1630 or \"dumps to directory\" will be encoded using the quoted-printable
1631 encoding.  If you're actually thinking of mailing the raw page dumps,
1632 then this might be useful, since (among other things,) it ensures
1633 that all lines in the message body are under 80 characters in length.
1634
1635 Also, setting this will cause a few additional mail headers
1636 to be generated, so that the resulting dumps are valid
1637 RFC 2822 e-mail messages.
1638
1639 Probably, you can just leave this set to false, in which case you get
1640 raw ('binary' content-encoding) page dumps.");
1641
1642 $properties["HTML Dump Filename Suffix"] =
1643 new _define_optional('HTML_DUMP_SUFFIX', ".html", "
1644 Here you can change the filename suffix used for XHTML page dumps.
1645 If you don't want any suffix just comment this out.");
1646
1647 $properties["Default local Dump Directory"] =
1648 new _define_optional('DEFAULT_DUMP_DIR', "/tmp/wikidump", "
1649 Specify the default directory for local backups.");
1650
1651 $properties["Default local HTML Dump Directory"] =
1652 new _define_optional('HTML_DUMP_DIR', "/tmp/wikidumphtml", "
1653 Specify the default directory for local XHTML dumps.");
1654
1655 $properties["Pagename of Recent Changes"] =
1656 new _define_optional('RECENT_CHANGES', 'RecentChanges', "
1657 Page name of RecentChanges page.  Used for RSS Auto-discovery.");
1658
1659 $properties["Disable HTTP Redirects"] =
1660 new boolean_define_commented_optional
1661 ('DISABLE_HTTP_REDIRECT',
1662  array('false' => 'Enable HTTP Redirects',
1663        'true' => 'Disable HTTP Redirects'),
1664 "
1665 (You probably don't need to touch this.)
1666
1667 PhpWiki uses HTTP redirects for some of it's functionality.
1668 (e.g. after saving changes, PhpWiki redirects your browser to
1669 view the page you just saved.)
1670
1671 Some web service providers (notably free European Lycos) don't seem to
1672 allow these redirects.  (On Lycos the result in an \"Internal Server Error\"
1673 report.)  In that case you can set DISABLE_HTTP_REDIRECT to true.
1674 (In which case, PhpWiki will revert to sneakier tricks to try to
1675 redirect the browser...)");
1676
1677 $properties["Disable GETIMAGESIZE"] =
1678 new boolean_define_commented_optional
1679 ('DISABLE_GETIMAGESIZE',
1680  array('false' => 'Enable',
1681        'true'  => 'Disable'), "
1682 Set GETIMAGESIZE to disabled, if your php fails to calculate the size on 
1683 inlined images, or you don't want to disable too small images to be inlined.
1684
1685 Per default too small ploaded or external images are not displayed, 
1686 to prevent from external 1 pixel spam.");
1687
1688 $properties["EDITING_POLICY"] =
1689   new _define_optional('EDITING_POLICY', "EditingPolicy", "
1690 An interim page which gets displayed on every edit attempt, if it exists.");
1691
1692 $properties["ENABLE_MODERATEDPAGE_ALL"] =
1693 new boolean_define_commented_optional
1694 ('ENABLE_MODERATEDPAGE_ALL',
1695  array('false' => 'Disable',
1696        'true'  => 'Enable'), "
1697 ");
1698
1699 $properties["FORTUNE_DIR"] =
1700   new _define_commented_optional('FORTUNE_DIR', "/usr/share/fortune", "
1701 ");
1702 $properties["DBADMIN_USER"] =
1703   new _define_commented_optional('DBADMIN_USER', "", "
1704 ");
1705 $properties["DBADMIN_PASSWD"] =
1706   new _define_commented_optional('DBADMIN_PASSWD', "", "
1707 ");
1708 $properties["USE_EXTERNAL_HTML2PDF"] =
1709   new _define_commented_optional('USE_EXTERNAL_HTML2PDF', "htmldoc --quiet --format pdf14 --no-toc --no-title %s", "
1710 ");
1711 $properties["BABYCART_PATH"] =
1712   new _define_commented_optional('BABYCART_PATH', "/usr/local/bin/babycart", "
1713 ");
1714
1715 $properties["Part Seven A"] =
1716 new part('_part7a', $SEPARATOR."\n", "
1717
1718 Part Seven A:
1719
1720 Cached Plugin Settings. (pear Cache)
1721 ");
1722
1723 $properties["pear Cache USECACHE"] =
1724 new boolean_define_optional('PLUGIN_CACHED_USECACHE', 
1725                     array('true'  => 'Enabled',
1726                           'false' => 'Disabled'), "
1727 Enable or disable pear caching of plugins.");
1728 $properties["pear Cache Database Container"] =
1729 new _define_selection_optional('PLUGIN_CACHED_DATABASE', 
1730                                array('file' => 'file'), "
1731 Curently only file is supported. 
1732 db, trifile and imgfile might be supported, but you must hack that by yourself.");
1733
1734 $properties["pear Cache cache directory"] =
1735 new _define_commented_optional('PLUGIN_CACHED_CACHE_DIR', "/tmp/cache", "
1736 Should be writable to the webserver.");
1737 $properties["pear Cache Filename Prefix"] =
1738 new _define_optional('PLUGIN_CACHED_FILENAME_PREFIX', "phpwiki", "");
1739 $properties["pear Cache HIGHWATER"] =
1740 new numeric_define_optional('PLUGIN_CACHED_HIGHWATER', "4194304", "
1741 Garbage collection parameter.");
1742 $properties["pear Cache LOWWATER"] =
1743 new numeric_define_optional('PLUGIN_CACHED_LOWWATER', "3145728", "
1744 Garbage collection parameter.");
1745 $properties["pear Cache MAXLIFETIME"] =
1746 new numeric_define_optional('PLUGIN_CACHED_MAXLIFETIME', "2592000", "
1747 Garbage collection parameter.");
1748 $properties["pear Cache MAXARGLEN"] =
1749 new numeric_define_optional('PLUGIN_CACHED_MAXARGLEN', "1000", "
1750 max. generated url length.");
1751 $properties["pear Cache FORCE_SYNCMAP"] =
1752 new boolean_define_optional('PLUGIN_CACHED_FORCE_SYNCMAP', 
1753                     array('true'  => 'Enabled',
1754                           'false' => 'Disabled'), "");
1755 $properties["pear Cache IMGTYPES"] =
1756 new list_define('PLUGIN_CACHED_IMGTYPES', "png|gif|gd|gd2|jpeg|wbmp|xbm|xpm", "
1757 Handle those image types via GD handles. Check your GD supported image types.");
1758
1759 $end = "\n".$SEPARATOR."\n";
1760
1761 // performance hack
1762 text_from_dist("_MAGIC_CLOSE_FILE");
1763
1764 // end of configuration options
1765 ///////////////////////////////
1766 // begin class definitions
1767
1768 /**
1769  * A basic config-dist.ini configuration line in the form of a variable. 
1770  * (not needed anymore, we have only defines)
1771  *
1772  * Produces a string in the form "$name = value;"
1773  * e.g.:
1774  * $WikiNameRegexp = "value";
1775  */
1776 class _variable {
1777
1778     var $config_item_name;
1779     var $default_value;
1780     var $description;
1781     var $prefix;
1782     var $jscheck;
1783
1784     function _variable($config_item_name, $default_value, $description = '', $jscheck = '') {
1785         $this->config_item_name = $config_item_name;
1786         if (!$description)
1787             $description = text_from_dist($config_item_name);
1788         $this->description = $description;
1789         if (defined($config_item_name) 
1790             and !preg_match("/(selection|boolean)/", get_class($this))
1791             and !preg_match("/(SCRIPT_NAME|VIRTUAL_PATH)/", $config_item_name))
1792             $this->default_value = constant($config_item_name); // ignore given default value
1793         elseif ($config_item_name == $default_value)
1794             $this->default_value = '';
1795         else
1796             $this->default_value = $default_value;
1797         $this->jscheck = $jscheck;
1798         if (preg_match("/variable/i",get_class($this)))
1799             $this->prefix = "\$";
1800         elseif (preg_match("/ini_set/i",get_class($this)))
1801             $this->prefix = "ini_get: ";
1802         else
1803             $this->prefix = "";
1804     }
1805
1806     function value() {
1807       global $HTTP_POST_VARS;
1808       if (isset($HTTP_POST_VARS[$this->config_item_name]))
1809           return $HTTP_POST_VARS[$this->config_item_name];
1810       else 
1811           return $this->default_value;
1812     }
1813
1814     function _config_format($value) {
1815         return '';
1816         $v = $this->get_config_item_name();
1817         // handle arrays: a|b --> a['b']
1818         if (strpos($v, '|')) {
1819             list($a, $b) = explode('|', $v);
1820             $v = sprintf("%s['%s']", $a, $b);
1821         }
1822         if (preg_match("/[\"']/", $value))
1823             $value = '"' . $value . '"';
1824         return sprintf("%s = \"%s\"", $v, $value);
1825     }
1826
1827     function get_config_item_name() {
1828         return $this->config_item_name;
1829     }
1830
1831     function get_config_item_id() {
1832         return str_replace('|', '-', $this->config_item_name);
1833     }
1834
1835     function get_config_item_header() {
1836        if (strchr($this->config_item_name,'|')) {
1837           list($var,$param) = explode('|',$this->config_item_name);
1838           return "<b>" . $this->prefix . $var . "['" . $param . "']</b><br />";
1839        }
1840        elseif ($this->config_item_name[0] != '_')
1841           return "<b>" . $this->prefix . $this->config_item_name . "</b><br />";
1842        else 
1843           return '';
1844     }
1845
1846     function _get_description() {
1847         return $this->description;
1848     }
1849
1850     function _get_config_line($posted_value) {
1851         return "\n" . $this->_config_format($posted_value);
1852     }
1853
1854     function get_config($posted_value) {
1855         $d = stripHtml($this->_get_description());
1856         $d = str_replace("\n", "\n; ", $d) . $this->_get_config_line($posted_value) ."\n";
1857         return $d;
1858     }
1859
1860     function get_instructions($title) {
1861         global $tdwidth;
1862         $i = "<h3>" . $title . "</h3>\n    " . nl2p($this->_get_description()) . "\n";
1863         return "<tr>\n<td width=\"$tdwidth\" class=\"instructions\">\n" . $i . "</td>\n";
1864     }
1865
1866     function get_html() {
1867         $size = strlen($this->default_value) > 45 ? 90 : 50;
1868         return $this->get_config_item_header() . 
1869             "<input type=\"text\" size=\"$50\" name=\"" . $this->get_config_item_name() . "\" value=\"" . htmlspecialchars($this->default_value) . "\" " . 
1870             $this->jscheck . " />" . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1871     }
1872 }
1873
1874 class unchangeable_variable
1875 extends _variable {
1876     function _config_format($value) {
1877         return "";
1878     }
1879     // function get_html() { return false; }
1880     function get_html() {
1881         return $this->get_config_item_header() . 
1882         "<em>Not editable.</em>" . 
1883         "<pre>" . $this->default_value."</pre>";
1884     }
1885     function _get_config_line($posted_value) {
1886         if ($this->description)
1887             $n = "\n";
1888         return "${n}".$this->default_value;
1889     }
1890     function get_instructions($title) {
1891         global $tdwidth;
1892         $i = "<h3>" . $title . "</h3>\n    " . nl2p($this->_get_description()) . "\n";
1893         // $i .= "<em>Not editable.</em><br />\n<pre>" . $this->default_value."</pre>";
1894         return '<tr><td width="100%" class="unchangeable-variable-top" colspan="2">'."\n".$i."</td></tr>\n" 
1895         . '<tr style="border-top: none;"><td class="unchangeable-variable-left" width="'.$tdwidth.'">&nbsp;</td>';
1896     }
1897 }
1898
1899 class unchangeable_define
1900 extends unchangeable_variable {
1901     function _config_format($value) {
1902         return "";
1903     }
1904 }
1905 class unchangeable_ini_set
1906 extends unchangeable_variable {
1907     function _config_format($value) {
1908         return "";
1909     }
1910 }
1911
1912 class _variable_selection
1913 extends _variable {
1914     function value() {
1915         global $HTTP_POST_VARS;
1916         if (!empty($HTTP_POST_VARS[$this->config_item_name]))
1917             return $HTTP_POST_VARS[$this->config_item_name];
1918         else {
1919             list($option, $label) = each($this->default_value);
1920             return $option;
1921         }
1922     }
1923     function get_html() {
1924         $output = $this->get_config_item_header();
1925         $output .= '<select name="' . $this->get_config_item_name() . "\">\n";
1926         /* The first option is the default */
1927         $values = $this->default_value;
1928         if (defined($this->get_config_item_name()))
1929             $this->default_value = constant($this->get_config_item_name());
1930         else
1931             $this->default_value = null;
1932         while(list($option, $label) = each($values)) {
1933             if (!is_null($this->default_value) and $this->default_value === $option)
1934                 $output .= "  <option value=\"$option\" selected=\"selected\">$label</option>\n";
1935             else
1936                 $output .= "  <option value=\"$option\">$label</option>\n";
1937         }
1938         $output .= "</select>\n";
1939         return $output;
1940     }
1941 }
1942
1943
1944 class _define
1945 extends _variable {
1946     function _config_format($value) {
1947         return sprintf("%s = \"%s\"", $this->get_config_item_name(), $value);
1948     }
1949     function _get_config_line($posted_value) {
1950         if ($this->description)
1951             $n = "\n";
1952         if ($posted_value == '')
1953             return "${n};" . $this->_config_format("");
1954         else
1955             return "${n}" . $this->_config_format($posted_value);
1956     }
1957     function get_html() {
1958         $size = strlen($this->default_value) > 45 ? 90 : 50;
1959         return $this->get_config_item_header() 
1960             . "<input type=\"text\" size=\"$size\" name=\"" . htmlentities($this->get_config_item_name()) 
1961             . "\" value=\"" . htmlentities($this->default_value) . "\" {$this->jscheck} />" 
1962             . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
1963     }
1964 }
1965
1966 class _define_commented
1967 extends _define {
1968     function _get_config_line($posted_value) {
1969         if ($this->description)
1970             $n = "\n";
1971         if ($posted_value == $this->default_value)
1972             return "${n};" . $this->_config_format($posted_value);
1973         elseif ($posted_value == '')
1974             return "${n};" . $this->_config_format("");
1975         else
1976             return "${n}" . $this->_config_format($posted_value);
1977     }
1978 }
1979
1980 /** 
1981  * We don't use _optional anymore, because INI-style config's don't need that. 
1982  * IniConfig.php does the optional logic now.
1983  * But we use _optional for config-default.ini options
1984  */
1985 class _define_commented_optional
1986 extends _define_commented { }
1987
1988 class _define_optional
1989 extends _define { }
1990
1991 class _define_notempty
1992 extends _define {
1993     function get_html() {
1994         $s = $this->get_config_item_header() 
1995             . "<input type=\"text\" size=\"50\" name=\"" . $this->get_config_item_name() 
1996             . "\" value=\"" . $this->default_value . "\" {$this->jscheck} />";
1997         if (empty($this->default_value))
1998             return $s . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Cannot be empty.</p>";
1999         else
2000             return $s . "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2001     }
2002 }
2003
2004 class _variable_commented
2005 extends _variable {
2006     function _get_config_line($posted_value) {
2007         if ($this->description)
2008             $n = "\n";
2009         if ($posted_value == $this->default_value)
2010             return "${n};" . $this->_config_format($posted_value);
2011         elseif ($posted_value == '')
2012             return "${n};" . $this->_config_format("");
2013         else
2014             return "${n}" . $this->_config_format($posted_value);
2015     }
2016 }
2017
2018 class numeric_define
2019 extends _define {
2020
2021     function numeric_define($config_item_name, $default_value, $description = '', $jscheck = '') {
2022         $this->_define($config_item_name, $default_value, $description, $jscheck);
2023         if (!$jscheck)
2024             $this->jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' is not an integer.', '^[-+]?[0-9]+$', '" . $this->get_config_item_name() . "', this);\"";
2025     }
2026     function _config_format($value) {
2027         //return sprintf("define('%s', %s);", $this->get_config_item_name(), $value);
2028         return sprintf("%s = %s", $this->get_config_item_name(), $value);
2029     }
2030     function _get_config_line($posted_value) {
2031         if ($this->description)
2032             $n = "\n";
2033         if ($posted_value == '')
2034             return "${n};" . $this->_config_format('0');
2035         else
2036             return "${n}" . $this->_config_format($posted_value);
2037     }
2038 }
2039
2040 class numeric_define_optional
2041 extends numeric_define {}
2042
2043 class numeric_define_commented
2044 extends numeric_define {
2045     function _get_config_line($posted_value) {
2046         if ($this->description)
2047             $n = "\n";
2048         if ($posted_value == $this->default_value)
2049             return "${n};" . $this->_config_format($posted_value);
2050         elseif ($posted_value == '')
2051             return "${n};" . $this->_config_format('0');
2052         else
2053             return "${n}" . $this->_config_format($posted_value);
2054     }
2055 }
2056
2057 class _define_selection
2058 extends _variable_selection {
2059     function _config_format($value) {
2060         return sprintf("%s = %s", $this->get_config_item_name(), $value);
2061     }
2062     function _get_config_line($posted_value) {
2063         return _define::_get_config_line($posted_value);
2064     }
2065     function get_html() {
2066         return _variable_selection::get_html();
2067     }
2068 }
2069
2070 class _define_selection_optional
2071 extends _define_selection { }
2072
2073 class _variable_selection_optional
2074 extends _variable_selection { }
2075
2076 class _define_selection_optional_commented
2077 extends _define_selection_optional { 
2078     function _get_config_line($posted_value) {
2079         if ($this->description)
2080             $n = "\n";
2081         if ($posted_value == $this->default_value)
2082             return "${n};" . $this->_config_format($posted_value);
2083         elseif ($posted_value == '')
2084             return "${n};" . $this->_config_format("");
2085         else
2086             return "${n}" . $this->_config_format($posted_value);
2087     }
2088 }
2089
2090 class _define_password
2091 extends _define {
2092
2093     function _define_password($config_item_name, $default_value, $description = '', $jscheck = '') {
2094         if ($config_item_name == $default_value) $default_value = '';
2095         $this->_define($config_item_name, $default_value, $description, $jscheck);
2096         if (!$jscheck)
2097             $this->jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' cannot be empty.', '^.+$', '" 
2098                 . $this->get_config_item_name() . "', this);\"";
2099     }
2100     function _get_config_line($posted_value) {
2101         if ($this->description)
2102             $n = "\n";
2103         if ($posted_value == '') {
2104             $p = "${n};" . $this->_config_format("");
2105             $p .= "\n; If you used the passencrypt.php utility to encode the password";
2106             $p .= "\n; then uncomment this line:";
2107             $p .= "\n;ENCRYPTED_PASSWD = true";
2108             return $p;
2109         } else {
2110             if (function_exists('crypt')) {
2111                 $salt_length = max(CRYPT_SALT_LENGTH,
2112                                     2 * CRYPT_STD_DES,
2113                                     9 * CRYPT_EXT_DES,
2114                                    12 * CRYPT_MD5,
2115                                    16 * CRYPT_BLOWFISH);
2116                 // generate an encrypted password
2117                 $crypt_pass = crypt($posted_value, rand_ascii($salt_length));
2118                 $p = "${n}" . $this->_config_format($crypt_pass);
2119                 return $p . "\nENCRYPTED_PASSWD = true";
2120             } else {
2121                 $p = "${n}" . $this->_config_format($posted_value);
2122                 $p .= "\n; Encrypted passwords cannot be used:";
2123                 $p .= "\n; 'function crypt()' not available in this version of php";
2124                 $p .= "\nENCRYPTED_PASSWD = false";
2125                 return $p;
2126             }
2127         }
2128     }
2129     function get_html() {
2130         return _variable_password::get_html();
2131     }
2132 }
2133
2134 class _define_password_optional
2135 extends _define_password { }
2136
2137 class _variable_password
2138 extends _variable {
2139     function _variable_password($config_item_name, $default_value, $description = '', $jscheck = '') {
2140         if ($config_item_name == $default_value) $default_value = '';
2141         $this->_define($config_item_name, $default_value, $description, $jscheck);
2142         if (!$jscheck)
2143             $this->jscheck = "onchange=\"validate_ereg('Sorry, \'%s\' cannot be empty.', '^.+$', '" . $this->get_config_item_name() . "', this);\"";
2144     }
2145     function get_html() {
2146         global $HTTP_POST_VARS, $HTTP_GET_VARS;
2147         $s = $this->get_config_item_header();
2148         if (isset($HTTP_POST_VARS['create']) or isset($HTTP_GET_VARS['create'])) {
2149             $new_password = random_good_password();
2150             $this->default_value = $new_password;
2151             $s .= "Created password: <strong>$new_password</strong><br />&nbsp;<br />";
2152         }
2153         // dont re-encrypt already encrypted passwords
2154         $value = $this->value();
2155         $encrypted = !empty($GLOBALS['properties']["Encrypted Passwords"]) and 
2156                      $GLOBALS['properties']["Encrypted Passwords"]->value();
2157         if (empty($value))
2158             $encrypted = false;
2159         $s .= "<input type=\"". ($encrypted ? "text" : "password") . "\" name=\"" . $this->get_config_item_name()
2160            . "\" value=\"" . $value . "\" {$this->jscheck} />" 
2161            . "&nbsp;&nbsp;<input type=\"submit\" name=\"create\" value=\"Create Random Password\" />";
2162         if (empty($value))
2163             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Cannot be empty.</p>";
2164         elseif (strlen($this->default_value) < 4)
2165             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: red\">Must be longer than 4 chars.</p>";
2166         else
2167             $s .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2168         return $s;
2169     }
2170 }
2171
2172 class list_variable
2173 extends _variable {
2174     function _get_config_line($posted_value) {
2175         // split the phrase by any number of commas or space characters,
2176         // which include " ", \r, \t, \n and \f
2177         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
2178         $list_values = join("|", $list_values);
2179         return _variable::_get_config_line($list_values);
2180     }
2181     function get_html() {
2182         $list_values = explode("|", $this->default_value);
2183         $rows = max(3, count($list_values) +1);
2184         $list_values = join("\n", $list_values);
2185         $ta = $this->get_config_item_header();
2186         $ta .= "<textarea cols=\"18\" rows=\"". $rows ."\" name=\"".$this->get_config_item_name()."\" {$this->jscheck}>";
2187         $ta .= $list_values . "</textarea>";
2188         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2189         return $ta;
2190     }
2191 }
2192
2193 class list_define
2194 extends _define {
2195     function _get_config_line($posted_value) {
2196         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
2197         $list_values = join("|", $list_values);
2198         return _variable::_get_config_line($list_values);
2199     }
2200     function get_html() {
2201         $list_values = explode("|", $this->default_value);
2202         $rows = max(3, count($list_values) +1);
2203         $list_values = join("\n", $list_values);
2204         $ta = $this->get_config_item_header();
2205         $ta .= "<textarea cols=\"18\" rows=\"". $rows ."\" name=\"".$this->get_config_item_name()."\" {$this->jscheck}>";
2206         $ta .= $list_values . "</textarea>";
2207         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2208         return $ta;
2209     }
2210 }
2211
2212 class array_variable
2213 extends _variable {
2214     function _config_format($value) {
2215         return sprintf("%s = \"%s\"", $this->get_config_item_name(), 
2216                        is_array($value) ? join(':', $value) : $value);
2217     }
2218     function _get_config_line($posted_value) {
2219         // split the phrase by any number of commas or space characters,
2220         // which include " ", \r, \t, \n and \f
2221         $list_values = preg_split("/[\s,]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
2222         if (!empty($list_values)) {
2223             $list_values = "'".join("', '", $list_values)."'";
2224             return "\n" . $this->_config_format($list_values);
2225         } else
2226             return "\n;" . $this->_config_format('');
2227     }
2228     function get_html() {
2229         $list_values = join("\n", $this->default_value);
2230         $rows = max(3, count($this->default_value) +1);
2231         $ta = $this->get_config_item_header();
2232         $ta .= "<textarea cols=\"18\" rows=\"". $rows ."\" name=\"".$this->get_config_item_name()."\" {$this->jscheck}>";
2233         $ta .= $list_values . "</textarea>";
2234         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2235         return $ta;
2236     }
2237 }
2238
2239 class array_define
2240 extends _define {
2241     function _config_format($value) {
2242         return sprintf("%s = \"%s\"", $this->get_config_item_name(), 
2243                        is_array($value) ? join(' : ', $value) : $value);
2244     }
2245     function _get_config_line($posted_value) {
2246         // split the phrase by any number of commas or space characters,
2247         // which include " ", \r, \t, \n and \f
2248         $list_values = preg_split("/[\s,:]+/", $posted_value, -1, PREG_SPLIT_NO_EMPTY);
2249         if (!empty($list_values)) {
2250             $list_values = "'".join("' : '", $list_values)."'";
2251             return "\n" . $this->_config_format($list_values);
2252         } else
2253             return "\n;" . $this->_config_format('');
2254     }
2255     function get_html() {
2256         if (!$this->default_value)
2257             $this->default_value = array();
2258         elseif (is_string($this->default_value))
2259             $this->default_value = preg_split("/[\s,:]+/", $this->default_value, -1, PREG_SPLIT_NO_EMPTY);
2260         $list_values = join(" : \n", $this->default_value);
2261         $rows = max(3, count($this->default_value) + 1);
2262         $ta = $this->get_config_item_header();
2263         $ta .= "<textarea cols=\"18\" rows=\"". $rows ."\" name=\"".$this->get_config_item_name()."\" {$this->jscheck}>";
2264         $ta .= $list_values . "</textarea>";
2265         $ta .= "<p id=\"" . $this->get_config_item_id() . "\" style=\"color: green\">Input accepted.</p>";
2266         return $ta;
2267     }
2268 }
2269
2270 /*
2271 class _ini_set
2272 extends _variable {
2273     function value() {
2274         global $HTTP_POST_VARS;
2275         if ($v = $HTTP_POST_VARS[$this->config_item_name])
2276             return $v;
2277         else {
2278             return ini_get($this->get_config_item_name);
2279         }
2280     }
2281     function _config_format($value) {
2282         return sprintf("ini_set('%s', '%s');", $this->get_config_item_name(), $value);
2283     }
2284     function _get_config_line($posted_value) {
2285         if ($posted_value && ! $posted_value == $this->default_value)
2286             return "\n" . $this->_config_format($posted_value);
2287         else
2288             return "\n;" . $this->_config_format($this->default_value);
2289     }
2290 }
2291 */
2292
2293 class boolean_define
2294 extends _define {
2295     function _get_config_line($posted_value) {
2296         if ($this->description)
2297             $n = "\n";
2298         return "${n}" . $this->_config_format($posted_value);
2299     }
2300     function _config_format($value) {
2301         if (strtolower(trim($value)) == 'false')
2302             $value = false;
2303         return sprintf("%s = %s", $this->get_config_item_name(),
2304                        (bool)$value ? 'true' : 'false');
2305     }
2306     function get_html() {
2307         $output = $this->get_config_item_header();
2308         $output .= '<select name="' . $this->get_config_item_name() . "\" {$this->jscheck}>\n";
2309         $values = $this->default_value;
2310         if (defined($this->get_config_item_name()))
2311             $this->default_value = constant($this->get_config_item_name());
2312         else {
2313             $this->default_value = null;
2314             list($option, $label) = each($values);
2315             $output .= "  <option value=\"$option\" selected=\"selected\">$label</option>\n";
2316         }
2317         /* There can usually, only be two options, there can be
2318          * three options in the case of a boolean_define_commented_optional */
2319         while (list($option, $label) = each($values)) {
2320             if (!is_null($this->default_value) and $this->default_value === $option)
2321                 $output .= "  <option value=\"$option\" selected=\"selected\">$label</option>\n";
2322             else
2323                 $output .= "  <option value=\"$option\">$label</option>\n";
2324         }
2325         $output .= "</select>\n";
2326         return $output;
2327     }
2328 }
2329
2330 class boolean_define_optional
2331 extends boolean_define {}
2332
2333 class boolean_define_commented
2334 extends boolean_define {
2335     function _get_config_line($posted_value) {
2336         if ($this->description)
2337             $n = "\n";
2338         list($default_value, $label) = each($this->default_value);
2339         if ($posted_value == $default_value)
2340             return "${n};" . $this->_config_format($posted_value);
2341         elseif ($posted_value == '')
2342             return "${n};" . $this->_config_format('false');
2343         else
2344             return "${n}" . $this->_config_format($posted_value);
2345     }
2346 }
2347
2348 class boolean_define_commented_optional
2349 extends boolean_define_commented {}
2350
2351 class part
2352 extends _variable {
2353     function value () { return; }
2354     function get_config($posted_value) {
2355         $d = stripHtml($this->_get_description());
2356         global $SEPARATOR;
2357         return "\n".$SEPARATOR . str_replace("\n", "\n; ", $d) ."\n".$this->default_value;
2358     }
2359     function get_instructions($title) {
2360         $id = preg_replace("/\W/","",$this->config_item_name);
2361         $group_name = preg_replace("/\W/","",$title);
2362         $i = "<tr class=\"header\" id=\"$id\">\n<td class=\"part\" width=\"100%\" colspan=\"2\" bgcolor=\"#eeeeee\">\n";
2363         $i .= "<h2>" . $title . "</h2>\n    " . nl2p($this->_get_description()) ."\n";
2364         $i .= "<p><a href=\"javascript:toggle_group('$id')\" id=\"{$id}_text\">Hide options.</a></p>";
2365         return  $i ."</td>\n";
2366     }
2367     function get_html() {
2368         return "";
2369     }
2370 }
2371
2372 // html utility functions
2373 function nl2p($text) {
2374   preg_match_all("@\s*(<pre>.*?</pre>|<dl>.*?</dl>|.*?(?=\n\n|<pre>|<dl>|$))@s",
2375                  $text, $m, PREG_PATTERN_ORDER);
2376
2377   $text = '';
2378   foreach ($m[1] as $par) {
2379     if (!($par = trim($par)))
2380       continue;
2381     if (!preg_match('/^<(pre|dl)>/', $par))
2382       $par = "<p>$par</p>";
2383     $text .= $par;
2384   }
2385   return $text;
2386 }
2387
2388 function text_from_dist($var) {
2389     static $distfile = 0;
2390     static $f;
2391     
2392     if (!$distfile) {
2393         $sep = (substr(PHP_OS,0,3) == 'WIN' ? '\\' : '/');
2394         $distfile = dirname(__FILE__) . $sep . "config" . $sep . "config-dist.ini";
2395         $f = fopen($distfile, "r");
2396     }
2397     if ($var == '_MAGIC_CLOSE_FILE') {
2398         fclose($f);
2399         return;
2400     }
2401     // if all vars would be in natural order as in the config-dist this would not be needed.
2402     fseek($f, 0); 
2403     $par = "\n";
2404     while (!feof($f)) {
2405         $s = fgets($f);
2406         if (preg_match("/^; \w/", $s)) {
2407             $par .= (substr($s,2) . " ");
2408         } elseif (preg_match("/^;\s*$/", $s)) {
2409             $par .= "\n\n";
2410         }
2411         if (preg_match("/^;?".preg_quote($var)."\s*=/", $s))
2412             return $par;
2413         if (preg_match("/^\s*$/", $s)) // new paragraph
2414             $par = "\n";
2415     }
2416     return '';
2417 }
2418
2419 function stripHtml($text) {
2420         $d = str_replace("<pre>", "", $text);
2421         $d = str_replace("</pre>", "", $d);
2422         $d = str_replace("<dl>", "", $d);
2423         $d = str_replace("</dl>", "", $d);
2424         $d = str_replace("<dt>", "", $d);
2425         $d = str_replace("</dt>", "", $d);
2426         $d = str_replace("<dd>", "", $d);
2427         $d = str_replace("</dd>", "", $d);
2428         $d = str_replace("<p>", "", $d);
2429         $d = str_replace("</p>", "", $d);
2430         //restore html entities into characters
2431         // http://www.php.net/manual/en/function.htmlentities.php
2432         $trans = get_html_translation_table (HTML_ENTITIES);
2433         $trans = array_flip ($trans);
2434         $d = strtr($d, $trans);
2435         return $d;
2436 }
2437
2438 include_once(dirname(__FILE__)."/lib/stdlib.php");
2439
2440 ////
2441 // Function to create better user passwords (much larger keyspace),
2442 // suitable for user passwords.
2443 // Sequence of random ASCII numbers, letters and some special chars.
2444 // Note: There exist other algorithms for easy-to-remember passwords.
2445 function random_good_password ($minlength = 5, $maxlength = 8) {
2446   $newpass = '';
2447   // assume ASCII ordering (not valid on EBCDIC systems!)
2448   $valid_chars = "!#%&+-.0123456789=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
2449   $start = ord($valid_chars);
2450   $end   = ord(substr($valid_chars,-1));
2451   better_srand();
2452   if (function_exists('mt_rand')) // mersenne twister
2453       $length = mt_rand($minlength, $maxlength);
2454   else  // the usually bad glibc rand()
2455       $length = rand($minlength, $maxlength);
2456   while ($length > 0) {
2457       if (function_exists('mt_rand'))
2458           $newchar = mt_rand($start, $end);
2459       else
2460           $newchar = rand($start, $end);
2461       if (! strrpos($valid_chars,$newchar) ) continue; // skip holes
2462       $newpass .= sprintf("%c", $newchar);
2463       $length--;
2464   }
2465   return($newpass);
2466 }
2467
2468 // debugging
2469 function printArray($a) {
2470     echo "<hr />\n<pre>\n";
2471     print_r($a);
2472     echo "\n</pre>\n<hr />\n";
2473 }
2474
2475 // end of class definitions
2476 /////////////////////////////
2477 // begin auto generation code
2478
2479 if (!function_exists('is_a')) {
2480   function is_a($object, $class) {
2481     $class = strtolower($class);
2482     return (get_class($object) == $class) or is_subclass_of($object, $class);
2483   }
2484 }
2485
2486
2487 if (!empty($HTTP_POST_VARS['action']) 
2488     and $HTTP_POST_VARS['action'] == 'make_config'
2489     and !empty($HTTP_POST_VARS['ADMIN_USER'])
2490     and !empty($HTTP_POST_VARS['ADMIN_PASSWD'])
2491     )
2492 {
2493
2494     $timestamp = date ('dS of F, Y H:i:s');
2495
2496     $config = "
2497 ; This is a local configuration file for PhpWiki.
2498 ; It was automatically generated by the configurator script
2499 ; on the $timestamp.
2500 ;
2501 ; $preamble
2502 ";
2503
2504     $posted = $GLOBALS['HTTP_POST_VARS'];
2505     /*if (defined('DEBUG'))
2506      printArray($GLOBALS['HTTP_POST_VARS']);*/
2507
2508     foreach ($properties as $option_name => $a) {
2509         $posted_value = stripslashes($posted[$a->config_item_name]);
2510         $config .= $properties[$option_name]->get_config($posted_value);
2511     }
2512
2513     $config .= $end;
2514
2515     if (is_writable($fs_config_file)) {
2516       // We first check if the config-file exists.
2517       if (file_exists($fs_config_file)) {
2518         // We make a backup copy of the file
2519         $new_filename = preg_replace('/\.ini$/', '-' . time() . '.ini', $fs_config_file);
2520         if (@copy($fs_config_file, $new_filename)) {
2521             $fp = @fopen($fs_config_file, 'w');
2522         }
2523       } else {
2524         $fp = @fopen($fs_config_file, 'w');
2525       }
2526     }
2527     else {
2528       $fp = false;
2529     }
2530     
2531     if ($fp) {
2532         fputs($fp, $config);
2533         fclose($fp);
2534         echo "<p>The configuration was written to <code><b>$config_file</b></code>.</p>\n";
2535         if ($new_filename) {
2536             echo "<p>A backup was made to <code><b>$new_filename</b></code>.</p>\n";
2537         } else {
2538             ; //echo "<p><strong>You must rename or copy this</strong> <code><b>$config_file</b></code> <strong>file to</strong> <code><b>config/config.ini</b></code>.</p>\n";
2539         }
2540     } else {
2541         echo "<p>The configuration file could <b>not</b> be written.<br />\n",
2542             " You should copy the above configuration to a file, ",
2543             "and manually save it as <code><b>config/config.ini</b></code>.</p>\n";
2544     }
2545
2546     echo "<hr />\n<p>Here's the configuration file based on your answers:</p>\n";
2547     echo "<form method=\"get\" action=\"", $configurator, "\">\n";
2548     echo "<textarea id='config-output' readonly='readonly' style='width:100%;' rows='30' cols='100'>\n";
2549     echo htmlentities($config);
2550     echo "</textarea></form>\n";
2551     echo "<hr />\n";
2552
2553     echo "<p>To make any corrections, <a href=\"configurator.php\">edit the settings again</a>.</p>\n";
2554
2555 } else { // first time or create password
2556     $posted = $GLOBALS['HTTP_POST_VARS'];
2557     // No action has been specified - we make a form.
2558
2559     echo '
2560 <form action="',$configurator,'" method="post">
2561 <input type="hidden" name="action" value="make_config" />
2562 <table cellpadding="4" cellspacing="0">
2563 ';
2564
2565     while (list($property, $obj) = each($properties)) {
2566         echo $obj->get_instructions($property);
2567         if ($h = $obj->get_html()) {
2568             if (defined('DEBUG') and DEBUG)  $h = get_class($obj) . "<br />\n" . $h;
2569             echo "<td>".$h."</td>\n";
2570         }
2571         echo '</tr>';
2572     }
2573
2574     echo '
2575 </table>
2576 <p><input type="submit" id="submit" value="Save ',$config_file,'" /> <input type="reset" value="Clear" /></p>
2577 </form>
2578 ';
2579 }
2580 ?>
2581 </body>
2582 </html>