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