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