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