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