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