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