xref: /dokuwiki/install.php (revision 2af726d3d50169d07b960a42ffbb6719701c9307)
1<?php
2/**
3 * Dokuwiki installation assistance
4 *
5 * @author      Chris Smith <chris@jalakai.co.uk>
6 */
7
8if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/');
9if(!defined('DOKU_CONF')) define('DOKU_CONF',DOKU_INC.'conf/');
10if(!defined('DOKU_LOCAL')) define('DOKU_LOCAL',DOKU_INC.'conf/');
11
12// load and initialize the core system
13require_once(DOKU_INC.'inc/init.php');
14
15// check for error reporting override or set error reporting to sane values
16if (!defined('DOKU_E_LEVEL')) { error_reporting(E_ALL ^ E_NOTICE); }
17else { error_reporting(DOKU_E_LEVEL); }
18
19// kill magic quotes
20if (get_magic_quotes_gpc() && !defined('MAGIC_QUOTES_STRIPPED')) {
21    if (!empty($_GET))    remove_magic_quotes($_GET);
22    if (!empty($_POST))   remove_magic_quotes($_POST);
23    if (!empty($_COOKIE)) remove_magic_quotes($_COOKIE);
24    if (!empty($_REQUEST)) remove_magic_quotes($_REQUEST);
25    @ini_set('magic_quotes_gpc', 0);
26    define('MAGIC_QUOTES_STRIPPED',1);
27}
28if (function_exists('set_magic_quotes_runtime')) @set_magic_quotes_runtime(0);
29@ini_set('magic_quotes_sybase',0);
30
31// language strings
32require_once(DOKU_INC.'inc/lang/en/lang.php');
33if(isset($_REQUEST['l']) && !is_array($_REQUEST['l'])) {
34    $LC = preg_replace('/[^a-z\-]+/','',$_REQUEST['l']);
35}
36if(empty($LC)) $LC = 'en';
37if($LC && $LC != 'en' ) {
38    require_once(DOKU_INC.'inc/lang/'.$LC.'/lang.php');
39}
40
41// initialise variables ...
42$error = array();
43
44$dokuwiki_hash = array(
45    '2005-09-22'   => 'e33223e957b0b0a130d0520db08f8fb7',
46    '2006-03-05'   => '51295727f79ab9af309a2fd9e0b61acc',
47    '2006-03-09'   => '51295727f79ab9af309a2fd9e0b61acc',
48    '2006-11-06'   => 'b3a8af76845977c2000d85d6990dd72b',
49    '2007-05-24'   => 'd80f2740c84c4a6a791fd3c7a353536f',
50    '2007-06-26'   => 'b3ca19c7a654823144119980be73cd77',
51    '2008-05-04'   => '1e5c42eac3219d9e21927c39e3240aad',
52    '2009-02-14'   => 'ec8c04210732a14fdfce0f7f6eead865',
53    '2009-12-25'   => '993c4b2b385643efe5abf8e7010e11f4',
54    '2010-11-07'   => '7921d48195f4db21b8ead6d9bea801b8',
55    '2011-05-25'   => '4241865472edb6fa14a1227721008072',
56    '2011-11-10'   => 'b46ff19a7587966ac4df61cbab1b8b31',
57    '2012-01-25'   => '72c083c73608fc43c586901fd5dabb74',
58    '2012-09-10'   => 'eb0b3fc90056fbc12bac6f49f7764df3',
59    '2013-05-10'   => '7b62b75245f57f122d3e0f8ed7989623',
60    '2013-12-08'   => '263c76af309fbf083867c18a34ff5214',
61    '2014-05-05'   => '263c76af309fbf083867c18a34ff5214',
62    '2015-08-10'   => '263c76af309fbf083867c18a34ff5214',
63    '2016-06-26'   => 'fd3abb6d89853dacb032907e619fbd73',
64    '2017-02-19'   => 'e4f2f5a34c9dbcd96a5ecc8f2df25bd9'
65);
66
67
68// begin output
69header('Content-Type: text/html; charset=utf-8');
70?>
71<!DOCTYPE html>
72<html lang="<?php echo $LC?>" dir="<?php echo $lang['direction']?>">
73<head>
74    <meta charset="utf-8" />
75    <title><?php echo $lang['i_installer']?></title>
76    <style type="text/css">
77        body { width: 90%; margin: 0 auto; font: 84% Verdana, Helvetica, Arial, sans-serif; }
78        img { border: none }
79        br.cl { clear:both; }
80        code { font-size: 110%; color: #800000; }
81        fieldset { border: none }
82        label { display: block; margin-top: 0.5em; }
83        select.text, input.text { width: 30em; margin: 0 0.5em; }
84        a {text-decoration: none}
85    </style>
86    <script type="text/javascript">
87        function acltoggle(){
88            var cb = document.getElementById('acl');
89            var fs = document.getElementById('acldep');
90            if(!cb || !fs) return;
91            if(cb.checked){
92                fs.style.display = '';
93            }else{
94                fs.style.display = 'none';
95            }
96        }
97        window.onload = function(){
98            acltoggle();
99            var cb = document.getElementById('acl');
100            if(cb) cb.onchange = acltoggle;
101        };
102    </script>
103</head>
104<body style="">
105    <h1 style="float:left">
106        <img src="lib/exe/fetch.php?media=wiki:dokuwiki-128.png"
107             style="vertical-align: middle;" alt="" height="64" width="64" />
108        <?php echo $lang['i_installer']?>
109    </h1>
110    <div style="float:right; margin: 1em;">
111        <?php langsel()?>
112    </div>
113    <br class="cl" />
114
115    <div style="float: right; width: 34%;">
116        <?php
117            if(file_exists(DOKU_INC.'inc/lang/'.$LC.'/install.html')){
118                include(DOKU_INC.'inc/lang/'.$LC.'/install.html');
119            }else{
120                print "<div lang=\"en\" dir=\"ltr\">\n";
121                include(DOKU_INC.'inc/lang/en/install.html');
122                print "</div>\n";
123            }
124        ?>
125        <a style="background: transparent url(data/security.png) left top no-repeat;
126                  display: block; width:380px; height:73px; border:none; clear:both;"
127           target="_blank"
128           href="http://www.dokuwiki.org/security#web_access_security"></a>
129    </div>
130
131    <div style="float: left; width: 58%;">
132        <?php
133            if(! (check_functions() && check_permissions()) ){
134                echo '<p>'.$lang['i_problems'].'</p>';
135                print_errors();
136                print_retry();
137            }elseif(!check_configs()){
138                echo '<p>'.$lang['i_modified'].'</p>';
139                print_errors();
140            }elseif(check_data($_REQUEST['d'])){
141                // check_data has sanitized all input parameters
142                if(!store_data($_REQUEST['d'])){
143                    echo '<p>'.$lang['i_failure'].'</p>';
144                    print_errors();
145                }else{
146                    echo '<p>'.$lang['i_success'].'</p>';
147                }
148            }else{
149                print_errors();
150                print_form($_REQUEST['d']);
151            }
152        ?>
153    </div>
154
155
156<div style="clear: both">
157  <a href="http://dokuwiki.org/"><img src="lib/tpl/dokuwiki/images/button-dw.png" alt="driven by DokuWiki" /></a>
158  <a href="http://php.net"><img src="lib/tpl/dokuwiki/images/button-php.gif" alt="powered by PHP" /></a>
159</div>
160</body>
161</html>
162<?php
163
164/**
165 * Print the input form
166 *
167 * @param array $d submitted entry 'd' of request data
168 */
169function print_form($d){
170    global $lang;
171    global $LC;
172
173    include(DOKU_CONF.'license.php');
174
175    if(!is_array($d)) $d = array();
176    $d = array_map('htmlspecialchars',$d);
177
178    if(!isset($d['acl'])) $d['acl']=1;
179    if(!isset($d['pop'])) $d['pop']=1;
180
181    ?>
182    <form action="" method="post">
183    <input type="hidden" name="l" value="<?php echo $LC ?>" />
184    <fieldset>
185        <label for="title"><?php echo $lang['i_wikiname']?>
186        <input type="text" name="d[title]" id="title" value="<?php echo $d['title'] ?>" style="width: 20em;" />
187        </label>
188
189        <fieldset style="margin-top: 1em;">
190            <label for="acl">
191            <input type="checkbox" name="d[acl]" id="acl" <?php echo(($d['acl'] ? ' checked="checked"' : ''));?> />
192            <?php echo $lang['i_enableacl']?></label>
193
194            <fieldset id="acldep">
195                <label for="superuser"><?php echo $lang['i_superuser']?></label>
196                <input class="text" type="text" name="d[superuser]" id="superuser" value="<?php echo $d['superuser'] ?>" />
197
198                <label for="fullname"><?php echo $lang['fullname']?></label>
199                <input class="text" type="text" name="d[fullname]" id="fullname" value="<?php echo $d['fullname'] ?>" />
200
201                <label for="email"><?php echo $lang['email']?></label>
202                <input class="text" type="text" name="d[email]" id="email" value="<?php echo $d['email'] ?>" />
203
204                <label for="password"><?php echo $lang['pass']?></label>
205                <input class="text" type="password" name="d[password]" id="password" />
206
207                <label for="confirm"><?php echo $lang['passchk']?></label>
208                <input class="text" type="password" name="d[confirm]" id="confirm" />
209
210                <label for="policy"><?php echo $lang['i_policy']?></label>
211                <select class="text" name="d[policy]" id="policy">
212                    <option value="0" <?php echo ($d['policy'] == 0)?'selected="selected"':'' ?>><?php echo $lang['i_pol0']?></option>
213                    <option value="1" <?php echo ($d['policy'] == 1)?'selected="selected"':'' ?>><?php echo $lang['i_pol1']?></option>
214                    <option value="2" <?php echo ($d['policy'] == 2)?'selected="selected"':'' ?>><?php echo $lang['i_pol2']?></option>
215                </select>
216
217                <label for="allowreg">
218                    <input type="checkbox" name="d[allowreg]" id="allowreg" <?php echo(($d['allowreg'] ? ' checked="checked"' : ''));?> />
219                    <?php echo $lang['i_allowreg']?>
220                </label>
221            </fieldset>
222        </fieldset>
223
224        <fieldset>
225            <p><?php echo $lang['i_license']?></p>
226            <?php
227            array_push($license,array('name' => $lang['i_license_none'], 'url'=>''));
228            if(empty($d['license'])) $d['license'] = 'cc-by-sa';
229            foreach($license as $key => $lic){
230                echo '<label for="lic_'.$key.'">';
231                echo '<input type="radio" name="d[license]" value="'.htmlspecialchars($key).'" id="lic_'.$key.'"'.
232                     (($d['license'] === $key)?' checked="checked"':'').'>';
233                echo htmlspecialchars($lic['name']);
234                if($lic['url']) echo ' <a href="'.$lic['url'].'" target="_blank"><sup>[?]</sup></a>';
235                echo '</label>';
236            }
237            ?>
238        </fieldset>
239
240        <fieldset>
241            <p><?php echo $lang['i_pop_field']?></p>
242            <label for="pop">
243                <input type="checkbox" name="d[pop]" id="pop" <?php echo(($d['pop'] ? ' checked="checked"' : ''));?> />
244                <?php echo $lang['i_pop_label']?> <a href="http://www.dokuwiki.org/popularity" target="_blank"><sup>[?]</sup></a>
245            </label>
246        </fieldset>
247
248    </fieldset>
249    <fieldset id="process">
250        <button type="submit" name="submit"><?php echo $lang['btn_save']?></button>
251    </fieldset>
252    </form>
253    <?php
254}
255
256function print_retry() {
257    global $lang;
258    global $LC;
259    ?>
260    <form action="" method="get">
261      <fieldset>
262        <input type="hidden" name="l" value="<?php echo $LC ?>" />
263        <button type="submit"><?php echo $lang['i_retry'];?></button>
264      </fieldset>
265    </form>
266    <?php
267}
268
269/**
270 * Check validity of data
271 *
272 * @author Andreas Gohr
273 *
274 * @param array $d
275 * @return bool ok?
276 */
277function check_data(&$d){
278    static $form_default = array(
279        'title'     => '',
280        'acl'       => '1',
281        'superuser' => '',
282        'fullname'  => '',
283        'email'     => '',
284        'password'  => '',
285        'confirm'   => '',
286        'policy'    => '0',
287        'allowreg'  => '0',
288        'license'   => 'cc-by-sa'
289    );
290    global $lang;
291    global $error;
292
293    if(!is_array($d)) $d = array();
294    foreach($d as $k => $v) {
295        if(is_array($v))
296            unset($d[$k]);
297        else
298            $d[$k] = (string)$v;
299    }
300
301    //autolowercase the username
302    $d['superuser'] = isset($d['superuser']) ? strtolower($d['superuser']) : "";
303
304    $ok = false;
305
306    if(isset($_REQUEST['submit'])) {
307        $ok = true;
308
309        // check input
310        if(empty($d['title'])){
311            $error[] = sprintf($lang['i_badval'],$lang['i_wikiname']);
312            $ok      = false;
313        }
314        if(isset($d['acl'])){
315            if(!preg_match('/^[a-z0-9_]+$/',$d['superuser'])){
316                $error[] = sprintf($lang['i_badval'],$lang['i_superuser']);
317                $ok      = false;
318            }
319            if(empty($d['password'])){
320                $error[] = sprintf($lang['i_badval'],$lang['pass']);
321                $ok      = false;
322            }
323            elseif(!isset($d['confirm']) || $d['confirm'] != $d['password']){
324                $error[] = sprintf($lang['i_badval'],$lang['passchk']);
325                $ok      = false;
326            }
327            if(empty($d['fullname']) || strstr($d['fullname'],':')){
328                $error[] = sprintf($lang['i_badval'],$lang['fullname']);
329                $ok      = false;
330            }
331            if(empty($d['email']) || strstr($d['email'],':') || !strstr($d['email'],'@')){
332                $error[] = sprintf($lang['i_badval'],$lang['email']);
333                $ok      = false;
334            }
335        }
336    }
337    $d = array_merge($form_default, $d);
338    return $ok;
339}
340
341/**
342 * Writes the data to the config files
343 *
344 * @author  Chris Smith <chris@jalakai.co.uk>
345 *
346 * @param array $d
347 * @return bool
348 */
349function store_data($d){
350    global $LC;
351    $ok = true;
352    $d['policy'] = (int) $d['policy'];
353
354    // create local.php
355    $now    = gmdate('r');
356    $output = <<<EOT
357<?php
358/**
359 * Dokuwiki's Main Configuration File - Local Settings
360 * Auto-generated by install script
361 * Date: $now
362 */
363
364EOT;
365    // add any config options set by a previous installer
366    $preset = __DIR__.'/install.conf';
367    if(file_exists($preset)){
368        $output .= "# preset config options\n";
369        $output .= file_get_contents($preset);
370        $output .= "\n\n";
371        $output .= "# options selected in installer\n";
372        @unlink($preset);
373    }
374
375    $output .= '$conf[\'title\'] = \''.addslashes($d['title'])."';\n";
376    $output .= '$conf[\'lang\'] = \''.addslashes($LC)."';\n";
377    $output .= '$conf[\'license\'] = \''.addslashes($d['license'])."';\n";
378    if($d['acl']){
379        $output .= '$conf[\'useacl\'] = 1'.";\n";
380        $output .= "\$conf['superuser'] = '@admin';\n";
381    }
382    if(!$d['allowreg']){
383        $output .= '$conf[\'disableactions\'] = \'register\''.";\n";
384    }
385    $ok = $ok && fileWrite(DOKU_LOCAL.'local.php',$output);
386
387    if ($d['acl']) {
388        // hash the password
389        $phash = new PassHash();
390        $pass = $phash->hash_smd5($d['password']);
391
392        // create users.auth.php
393        // --- user:SMD5password:Real Name:email:groups,comma,seperated
394        $output = join(":",array($d['superuser'], $pass, $d['fullname'], $d['email'], 'admin,user'));
395        $output = @file_get_contents(DOKU_CONF.'users.auth.php.dist')."\n$output\n";
396        $ok = $ok && fileWrite(DOKU_LOCAL.'users.auth.php', $output);
397
398        // create acl.auth.php
399        $output = <<<EOT
400# acl.auth.php
401# <?php exit()?>
402# Don't modify the lines above
403#
404# Access Control Lists
405#
406# Auto-generated by install script
407# Date: $now
408
409EOT;
410        if($d['policy'] == 2){
411            $output .=  "*               @ALL          0\n";
412            $output .=  "*               @user         8\n";
413        }elseif($d['policy'] == 1){
414            $output .=  "*               @ALL          1\n";
415            $output .=  "*               @user         8\n";
416        }else{
417            $output .=  "*               @ALL          8\n";
418        }
419        $ok = $ok && fileWrite(DOKU_LOCAL.'acl.auth.php', $output);
420    }
421
422    // enable popularity submission
423    if($d['pop']){
424        @touch(DOKU_INC.'data/cache/autosubmit.txt');
425    }
426
427    // disable auth plugins til needed
428    $output = <<<EOT
429<?php
430/*
431 * Local plugin enable/disable settings
432 *
433 * Auto-generated by install script
434 * Date: $now
435 */
436
437\$plugins['authad']    = 0;
438\$plugins['authldap']  = 0;
439\$plugins['authmysql'] = 0;
440\$plugins['authpgsql'] = 0;
441
442EOT;
443    $ok = $ok && fileWrite(DOKU_LOCAL.'plugins.local.php', $output);
444
445    return $ok;
446}
447
448/**
449 * Write the given content to a file
450 *
451 * @author  Chris Smith <chris@jalakai.co.uk>
452 *
453 * @param string $filename
454 * @param string $data
455 * @return bool
456 */
457function fileWrite($filename, $data) {
458    global $error;
459    global $lang;
460
461    if (($fp = @fopen($filename, 'wb')) === false) {
462        $filename = str_replace($_SERVER['DOCUMENT_ROOT'],'{DOCUMENT_ROOT}/', $filename);
463        $error[]  = sprintf($lang['i_writeerr'],$filename);
464        return false;
465    }
466
467    if (!empty($data)) { fwrite($fp, $data);  }
468    fclose($fp);
469    return true;
470}
471
472
473/**
474 * check installation dependent local config files and tests for a known
475 * unmodified main config file
476 *
477 * @author      Chris Smith <chris@jalakai.co.uk>
478 *
479 * @return bool
480 */
481function check_configs(){
482    global $error;
483    global $lang;
484    global $dokuwiki_hash;
485
486    $ok = true;
487
488    $config_files = array(
489        'local' => DOKU_LOCAL.'local.php',
490        'users' => DOKU_LOCAL.'users.auth.php',
491        'auth'  => DOKU_LOCAL.'acl.auth.php'
492    );
493
494    // main dokuwiki config file (conf/dokuwiki.php) must not have been modified
495    $installation_hash = md5(preg_replace("/(\015\012)|(\015)/","\012",
496                             @file_get_contents(DOKU_CONF.'dokuwiki.php')));
497    if (!in_array($installation_hash, $dokuwiki_hash)) {
498        $error[] = sprintf($lang['i_badhash'],$installation_hash);
499        $ok = false;
500    }
501
502    // configs shouldn't exist
503    foreach ($config_files as $file) {
504        if (file_exists($file) && filesize($file)) {
505            $file    = str_replace($_SERVER['DOCUMENT_ROOT'],'{DOCUMENT_ROOT}/', $file);
506            $error[] = sprintf($lang['i_confexists'],$file);
507            $ok      = false;
508        }
509    }
510    return $ok;
511}
512
513
514/**
515 * Check other installation dir/file permission requirements
516 *
517 * @author      Chris Smith <chris@jalakai.co.uk>
518 *
519 * @return bool
520 */
521function check_permissions(){
522    global $error;
523    global $lang;
524
525    $dirs = array(
526        'conf'        => DOKU_LOCAL,
527        'data'        => DOKU_INC.'data',
528        'pages'       => DOKU_INC.'data/pages',
529        'attic'       => DOKU_INC.'data/attic',
530        'media'       => DOKU_INC.'data/media',
531        'media_attic' => DOKU_INC.'data/media_attic',
532        'media_meta'  => DOKU_INC.'data/media_meta',
533        'meta'        => DOKU_INC.'data/meta',
534        'cache'       => DOKU_INC.'data/cache',
535        'locks'       => DOKU_INC.'data/locks',
536        'index'       => DOKU_INC.'data/index',
537        'tmp'         => DOKU_INC.'data/tmp'
538    );
539
540    $ok = true;
541    foreach($dirs as $dir){
542        if(!file_exists("$dir/.") || !is_writable($dir)){
543            $dir     = str_replace($_SERVER['DOCUMENT_ROOT'],'{DOCUMENT_ROOT}', $dir);
544            $error[] = sprintf($lang['i_permfail'],$dir);
545            $ok      = false;
546        }
547    }
548    return $ok;
549}
550
551/**
552 * Check the availability of functions used in DokuWiki and the PHP version
553 *
554 * @author Andreas Gohr <andi@splitbrain.org>
555 *
556 * @return bool
557 */
558function check_functions(){
559    global $error;
560    global $lang;
561    $ok = true;
562
563    if(version_compare(phpversion(),'5.3.3','<')){
564        $error[] = sprintf($lang['i_phpver'],phpversion(),'5.3.3');
565        $ok = false;
566    }
567
568    if(ini_get('mbstring.func_overload') != 0){
569        $error[] = $lang['i_mbfuncoverload'];
570        $ok = false;
571    }
572
573    $funcs = explode(' ','addslashes call_user_func chmod copy fgets '.
574                         'file file_exists fseek flush filesize ftell fopen '.
575                         'glob header ignore_user_abort ini_get mail mkdir '.
576                         'ob_start opendir parse_ini_file readfile realpath '.
577                         'rename rmdir serialize session_start unlink usleep '.
578                         'preg_replace file_get_contents htmlspecialchars_decode '.
579                         'spl_autoload_register stream_select fsockopen pack');
580
581    if (!function_exists('mb_substr')) {
582        $funcs[] = 'utf8_encode';
583        $funcs[] = 'utf8_decode';
584    }
585
586    foreach($funcs as $func){
587        if(!function_exists($func)){
588            $error[] = sprintf($lang['i_funcna'],$func);
589            $ok = false;
590        }
591    }
592    return $ok;
593}
594
595/**
596 * Print language selection
597 *
598 * @author Andreas Gohr <andi@splitbrain.org>
599 */
600function langsel(){
601    global $lang;
602    global $LC;
603
604    $dir = DOKU_INC.'inc/lang';
605    $dh  = opendir($dir);
606    if(!$dh) return;
607
608    $langs = array();
609    while (($file = readdir($dh)) !== false) {
610        if(preg_match('/^[\._]/',$file)) continue;
611        if(is_dir($dir.'/'.$file) && file_exists($dir.'/'.$file.'/lang.php')){
612            $langs[] = $file;
613        }
614    }
615    closedir($dh);
616    sort($langs);
617
618    echo '<form action="">';
619    echo $lang['i_chooselang'];
620    echo ': <select name="l" onchange="submit()">';
621    foreach($langs as $l){
622        $sel = ($l == $LC) ? 'selected="selected"' : '';
623        echo '<option value="'.$l.'" '.$sel.'>'.$l.'</option>';
624    }
625    echo '</select> ';
626    echo '<button type="submit">'.$lang['btn_update'].'</button>';
627    echo '</form>';
628}
629
630/**
631 * Print global error array
632 *
633 * @author Andreas Gohr <andi@splitbrain.org>
634 */
635function print_errors(){
636    global $error;
637    if(!empty($error)) {
638        echo '<ul>';
639        foreach ($error as $err){
640            echo "<li>$err</li>";
641        }
642        echo '</ul>';
643    }
644}
645