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