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