xref: /plugin/upgrade/admin.php (revision f378cb7e43e1af8d99db54c1ca376b671b37d0fe)
134aae6dbSAndreas Gohr<?php
234aae6dbSAndreas Gohr/**
3d391262fSAndreas Gohr * DokuWiki Plugin upgrade (Admin Component)
434aae6dbSAndreas Gohr *
534aae6dbSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
634aae6dbSAndreas Gohr * @author  Andreas Gohr <andi@splitbrain.org>
734aae6dbSAndreas Gohr */
834aae6dbSAndreas Gohr
934aae6dbSAndreas Gohr// must be run within Dokuwiki
1034aae6dbSAndreas Gohrif(!defined('DOKU_INC')) die();
1134aae6dbSAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/');
1234aae6dbSAndreas Gohrrequire_once DOKU_PLUGIN.'admin.php';
13d391262fSAndreas Gohrrequire_once DOKU_PLUGIN.'upgrade/VerboseTarLib.class.php';
1434aae6dbSAndreas Gohr
15ff284f1fSAndreas Gohrclass admin_plugin_upgrade extends DokuWiki_Admin_Plugin {
1634aae6dbSAndreas Gohr    private $tgzurl;
1734aae6dbSAndreas Gohr    private $tgzfile;
1834aae6dbSAndreas Gohr    private $tgzdir;
19*f378cb7eSAndreas Gohr    private $tgzversion;
20*f378cb7eSAndreas Gohr    private $pluginversion;
2134aae6dbSAndreas Gohr
2234aae6dbSAndreas Gohr    public function __construct() {
2334aae6dbSAndreas Gohr        global $conf;
2434aae6dbSAndreas Gohr
2534aae6dbSAndreas Gohr        $branch = 'stable';
2634aae6dbSAndreas Gohr
27bd08ebd1SAndreas Gohr        $this->tgzurl  = "https://github.com/splitbrain/dokuwiki/archive/$branch.tar.gz";
28d391262fSAndreas Gohr        $this->tgzfile = $conf['tmpdir'].'/dokuwiki-upgrade.tgz';
29d391262fSAndreas Gohr        $this->tgzdir  = $conf['tmpdir'].'/dokuwiki-upgrade/';
30*f378cb7eSAndreas Gohr        $this->tgzversion = "https://raw.githubusercontent.com/splitbrain/dokuwiki/$branch/VERSION";
31*f378cb7eSAndreas Gohr        $this->pluginversion = "https://raw.githubusercontent.com/splitbrain/dokuwiki-plugin-upgrade/master/plugin.info.txt";
3234aae6dbSAndreas Gohr    }
3334aae6dbSAndreas Gohr
34bd08ebd1SAndreas Gohr    public function getMenuSort() {
35bd08ebd1SAndreas Gohr        return 555;
36bd08ebd1SAndreas Gohr    }
3734aae6dbSAndreas Gohr
3841163f44SAndreas Gohr    public function handle() {
3941163f44SAndreas Gohr        if($_REQUEST['step'] && !checkSecurityToken()) {
4041163f44SAndreas Gohr            unset($_REQUEST['step']);
4141163f44SAndreas Gohr        }
4234aae6dbSAndreas Gohr    }
4334aae6dbSAndreas Gohr
4434aae6dbSAndreas Gohr    public function html() {
4534aae6dbSAndreas Gohr        $abrt = false;
4634aae6dbSAndreas Gohr        $next = false;
4734aae6dbSAndreas Gohr
4834aae6dbSAndreas Gohr        echo '<h1>'.$this->getLang('menu').'</h1>';
4934aae6dbSAndreas Gohr
50d391262fSAndreas Gohr        $this->_say('<div id="plugin__upgrade">');
5175e9d164SAndreas Gohr        // enable auto scroll
5275e9d164SAndreas Gohr        ?>
5375e9d164SAndreas Gohr        <script language="javascript" type="text/javascript">
54d391262fSAndreas Gohr            var plugin_upgrade = window.setInterval(function () {
55d4376367SAndreas Gohr                var obj = document.getElementById('plugin__upgrade');
5675e9d164SAndreas Gohr                if (obj) obj.scrollTop = obj.scrollHeight;
5775e9d164SAndreas Gohr            }, 25);
5875e9d164SAndreas Gohr        </script>
5975e9d164SAndreas Gohr        <?php
6075e9d164SAndreas Gohr
6175e9d164SAndreas Gohr        // handle current step
6222c39b33SAndreas Gohr        $this->_stepit($abrt, $next);
6334aae6dbSAndreas Gohr
6475e9d164SAndreas Gohr        // disable auto scroll
6575e9d164SAndreas Gohr        ?>
6675e9d164SAndreas Gohr        <script language="javascript" type="text/javascript">
6775e9d164SAndreas Gohr            window.setTimeout(function () {
68d391262fSAndreas Gohr                window.clearInterval(plugin_upgrade);
6975e9d164SAndreas Gohr            }, 50);
7075e9d164SAndreas Gohr        </script>
7175e9d164SAndreas Gohr        <?php
7275e9d164SAndreas Gohr        $this->_say('</div>');
7375e9d164SAndreas Gohr
74d391262fSAndreas Gohr        echo '<form action="" method="get" id="plugin__upgrade_form">';
7534aae6dbSAndreas Gohr        echo '<input type="hidden" name="do" value="admin" />';
76d391262fSAndreas Gohr        echo '<input type="hidden" name="page" value="upgrade" />';
7741163f44SAndreas Gohr        echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />';
7875e9d164SAndreas Gohr        if($next) echo '<input type="submit" name="step['.$next.']" value="Continue" class="button continue" />';
7975e9d164SAndreas Gohr        if($abrt) echo '<input type="submit" name="step[cancel]" value="Abort" class="button abort" />';
8034aae6dbSAndreas Gohr        echo '</form>';
8134aae6dbSAndreas Gohr    }
8234aae6dbSAndreas Gohr
83bd08ebd1SAndreas Gohr    /**
84bd08ebd1SAndreas Gohr     * Decides the current step and executes it
85bd08ebd1SAndreas Gohr     *
86bd08ebd1SAndreas Gohr     * @param bool $abrt
87bd08ebd1SAndreas Gohr     * @param bool $next
88bd08ebd1SAndreas Gohr     */
8934aae6dbSAndreas Gohr    private function _stepit(&$abrt, &$next) {
904bed5591SAndreas Gohr        global $conf;
914bed5591SAndreas Gohr        if($conf['safemodehack']) {
924bed5591SAndreas Gohr            $abrt = false;
934bed5591SAndreas Gohr            $next = false;
944bed5591SAndreas Gohr            echo $this->locale_xhtml('safemode');
954bed5591SAndreas Gohr        }
964bed5591SAndreas Gohr
9734aae6dbSAndreas Gohr        if(isset($_REQUEST['step']) && is_array($_REQUEST['step'])) {
9834aae6dbSAndreas Gohr            $step = array_shift(array_keys($_REQUEST['step']));
9934aae6dbSAndreas Gohr        } else {
10034aae6dbSAndreas Gohr            $step = '';
10134aae6dbSAndreas Gohr        }
10234aae6dbSAndreas Gohr
10334aae6dbSAndreas Gohr        if($step == 'cancel') {
10434aae6dbSAndreas Gohr            # cleanup
10534aae6dbSAndreas Gohr            @unlink($this->tgzfile);
1066b2d1b30SAndreas Gohr            $this->_rdel($this->tgzdir);
10734aae6dbSAndreas Gohr            $step = '';
10834aae6dbSAndreas Gohr        }
10934aae6dbSAndreas Gohr
11034aae6dbSAndreas Gohr        if($step) {
11134aae6dbSAndreas Gohr            $abrt = true;
11234aae6dbSAndreas Gohr            $next = false;
113*f378cb7eSAndreas Gohr            if($step == 'version') {
114*f378cb7eSAndreas Gohr                $this->_step_version();
115*f378cb7eSAndreas Gohr                $next = 'download';
116*f378cb7eSAndreas Gohr            } elseif(!file_exists($this->tgzfile)) {
11734aae6dbSAndreas Gohr                if($this->_step_download()) $next = 'unpack';
11834aae6dbSAndreas Gohr            } elseif(!is_dir($this->tgzdir)) {
11934aae6dbSAndreas Gohr                if($this->_step_unpack()) $next = 'check';
12034aae6dbSAndreas Gohr            } elseif($step != 'upgrade') {
1213c38de15SAndreas Gohr                if($this->_step_check()) $next = 'upgrade';
12234aae6dbSAndreas Gohr            } elseif($step == 'upgrade') {
1233c38de15SAndreas Gohr                if($this->_step_copy()) $next = 'cancel';
12434aae6dbSAndreas Gohr            } else {
12575e9d164SAndreas Gohr                echo 'uhm. what happened? where am I? This should not happen';
12634aae6dbSAndreas Gohr            }
12734aae6dbSAndreas Gohr        } else {
12834aae6dbSAndreas Gohr            # first time run, show intro
12934aae6dbSAndreas Gohr            echo $this->locale_xhtml('step0');
13034aae6dbSAndreas Gohr            $abrt = false;
131*f378cb7eSAndreas Gohr            $next = 'version';
13234aae6dbSAndreas Gohr        }
13334aae6dbSAndreas Gohr    }
13434aae6dbSAndreas Gohr
135bd08ebd1SAndreas Gohr    /**
136bd08ebd1SAndreas Gohr     * Output the given arguments using vsprintf and flush buffers
137bd08ebd1SAndreas Gohr     */
13834aae6dbSAndreas Gohr    private function _say() {
13934aae6dbSAndreas Gohr        $args = func_get_args();
14034aae6dbSAndreas Gohr        echo vsprintf(array_shift($args)."<br />\n", $args);
14134aae6dbSAndreas Gohr        flush();
14234aae6dbSAndreas Gohr        ob_flush();
14334aae6dbSAndreas Gohr    }
14434aae6dbSAndreas Gohr
1456b2d1b30SAndreas Gohr    /**
1466b2d1b30SAndreas Gohr     * Recursive delete
1476b2d1b30SAndreas Gohr     *
1489285faa5SAndreas Gohr     * @author Jon Hassall
1499285faa5SAndreas Gohr     * @link   http://de.php.net/manual/en/function.unlink.php#87045
1506b2d1b30SAndreas Gohr     */
1519285faa5SAndreas Gohr    private function _rdel($dir) {
1529285faa5SAndreas Gohr        if(!$dh = @opendir($dir)) {
153bd08ebd1SAndreas Gohr            return false;
1549285faa5SAndreas Gohr        }
1559285faa5SAndreas Gohr        while(false !== ($obj = readdir($dh))) {
1569285faa5SAndreas Gohr            if($obj == '.' || $obj == '..') continue;
1579285faa5SAndreas Gohr
1589285faa5SAndreas Gohr            if(!@unlink($dir.'/'.$obj)) {
1599285faa5SAndreas Gohr                $this->_rdel($dir.'/'.$obj);
1609285faa5SAndreas Gohr            }
1619285faa5SAndreas Gohr        }
1629285faa5SAndreas Gohr        closedir($dh);
163e32047e3SAndreas Gohr        return @rmdir($dir);
1646b2d1b30SAndreas Gohr    }
1656b2d1b30SAndreas Gohr
166bd08ebd1SAndreas Gohr    /**
167*f378cb7eSAndreas Gohr     * Check various versions
168*f378cb7eSAndreas Gohr     *
169*f378cb7eSAndreas Gohr     * @return bool
170*f378cb7eSAndreas Gohr     */
171*f378cb7eSAndreas Gohr    private function _step_version() {
172*f378cb7eSAndreas Gohr        $ok = true;
173*f378cb7eSAndreas Gohr
174*f378cb7eSAndreas Gohr        // check if PHP is up to date
175*f378cb7eSAndreas Gohr        if(version_compare(phpversion(),'5.2.0','<')){
176*f378cb7eSAndreas Gohr            $this->_say('<div class="error">'.$this->getLang('vs_php').'</div>');
177*f378cb7eSAndreas Gohr            $ok = false;
178*f378cb7eSAndreas Gohr        }
179*f378cb7eSAndreas Gohr
180*f378cb7eSAndreas Gohr        // get the available version
181*f378cb7eSAndreas Gohr        $http          = new DokuHTTPClient();
182*f378cb7eSAndreas Gohr        $tgzversion = $http->get($this->tgzversion);
183*f378cb7eSAndreas Gohr        if(!$tgzversion) {
184*f378cb7eSAndreas Gohr            $this->_say('<div class="error">'.$this->getLang('vs_tgzno').' '.hsc($http->error).'</div>');
185*f378cb7eSAndreas Gohr            $ok = false;
186*f378cb7eSAndreas Gohr        }
187*f378cb7eSAndreas Gohr        if(!preg_match('/(^| )(\d\d\d\d-\d\d-\d\d[a-z]*)( |$)/i', $tgzversion, $m)){
188*f378cb7eSAndreas Gohr            $this->_say('<div class="error">'.$this->getLang('vs_tgzno').'</div>');
189*f378cb7eSAndreas Gohr            $ok = false;
190*f378cb7eSAndreas Gohr            $tgzversionnum = 0;
191*f378cb7eSAndreas Gohr        } else {
192*f378cb7eSAndreas Gohr            $tgzversionnum = $m[2];
193*f378cb7eSAndreas Gohr            $this->_say($this->getLang('vs_tgz'), $tgzversion);
194*f378cb7eSAndreas Gohr        }
195*f378cb7eSAndreas Gohr
196*f378cb7eSAndreas Gohr        // get the current version
197*f378cb7eSAndreas Gohr        $version = getVersion();
198*f378cb7eSAndreas Gohr        if(!preg_match('/(^| )(\d\d\d\d-\d\d-\d\d[a-z]*)( |$)/i', $version, $m)){
199*f378cb7eSAndreas Gohr            $versionnum = 0;
200*f378cb7eSAndreas Gohr        } else {
201*f378cb7eSAndreas Gohr            $versionnum = $m[2];
202*f378cb7eSAndreas Gohr        }
203*f378cb7eSAndreas Gohr        $this->_say($this->getLang('vs_local'), $version);
204*f378cb7eSAndreas Gohr
205*f378cb7eSAndreas Gohr        // compare versions
206*f378cb7eSAndreas Gohr        if(!$versionnum) {
207*f378cb7eSAndreas Gohr            $this->_say('<div class="error">'.$this->getLang('vs_localno').'</div>');
208*f378cb7eSAndreas Gohr            $ok = false;
209*f378cb7eSAndreas Gohr        } else if($tgzversionnum) {
210*f378cb7eSAndreas Gohr            if($tgzversionnum < $versionnum) {
211*f378cb7eSAndreas Gohr                $this->_say('<div class="error">'.$this->getLang('vs_newer').'</div>');
212*f378cb7eSAndreas Gohr                $ok = false;
213*f378cb7eSAndreas Gohr            } elseif ($tgzversionnum == $versionnum) {
214*f378cb7eSAndreas Gohr                $this->_say('<div class="error">'.$this->getLang('vs_same').'</div>');
215*f378cb7eSAndreas Gohr                $ok = false;
216*f378cb7eSAndreas Gohr            }
217*f378cb7eSAndreas Gohr        }
218*f378cb7eSAndreas Gohr
219*f378cb7eSAndreas Gohr        // check plugin version
220*f378cb7eSAndreas Gohr        $pluginversion = $http->get($this->pluginversion);
221*f378cb7eSAndreas Gohr        if($pluginversion) {
222*f378cb7eSAndreas Gohr            $plugininfo = linesToHash(explode("\n", $pluginversion));
223*f378cb7eSAndreas Gohr            $myinfo = $this->getInfo();
224*f378cb7eSAndreas Gohr            if($plugininfo['date'] > $myinfo['date']) {
225*f378cb7eSAndreas Gohr                $this->_say('<div class="error">'.$this->getLang('vs_plugin').'</div>');
226*f378cb7eSAndreas Gohr                $ok = false;
227*f378cb7eSAndreas Gohr            }
228*f378cb7eSAndreas Gohr        }
229*f378cb7eSAndreas Gohr
230*f378cb7eSAndreas Gohr
231*f378cb7eSAndreas Gohr        return $ok;
232*f378cb7eSAndreas Gohr    }
233*f378cb7eSAndreas Gohr
234*f378cb7eSAndreas Gohr
235*f378cb7eSAndreas Gohr    /**
236bd08ebd1SAndreas Gohr     * Download the tarball
237bd08ebd1SAndreas Gohr     *
238bd08ebd1SAndreas Gohr     * @return bool
239bd08ebd1SAndreas Gohr     */
24034aae6dbSAndreas Gohr    private function _step_download() {
2413c38de15SAndreas Gohr        $this->_say($this->getLang('dl_from'), $this->tgzurl);
24234aae6dbSAndreas Gohr
24334aae6dbSAndreas Gohr        @set_time_limit(120);
24434aae6dbSAndreas Gohr        @ignore_user_abort();
24534aae6dbSAndreas Gohr
24634aae6dbSAndreas Gohr        $http          = new DokuHTTPClient();
24734aae6dbSAndreas Gohr        $http->timeout = 120;
24834aae6dbSAndreas Gohr        $data          = $http->get($this->tgzurl);
24934aae6dbSAndreas Gohr
25034aae6dbSAndreas Gohr        if(!$data) {
25134aae6dbSAndreas Gohr            $this->_say($http->error);
2523c38de15SAndreas Gohr            $this->_say($this->getLang('dl_fail'));
25334aae6dbSAndreas Gohr            return false;
25434aae6dbSAndreas Gohr        }
25534aae6dbSAndreas Gohr
25634aae6dbSAndreas Gohr        if(!io_saveFile($this->tgzfile, $data)) {
2573c38de15SAndreas Gohr            $this->_say($this->getLang('dl_fail'));
25834aae6dbSAndreas Gohr            return false;
25934aae6dbSAndreas Gohr        }
26034aae6dbSAndreas Gohr
261a7b56078SAndreas Gohr        $this->_say($this->getLang('dl_done'), filesize_h(strlen($data)));
2623c38de15SAndreas Gohr
26334aae6dbSAndreas Gohr        return true;
26434aae6dbSAndreas Gohr    }
26534aae6dbSAndreas Gohr
266bd08ebd1SAndreas Gohr    /**
267bd08ebd1SAndreas Gohr     * Unpack the tarball
268bd08ebd1SAndreas Gohr     *
269bd08ebd1SAndreas Gohr     * @return bool
270bd08ebd1SAndreas Gohr     */
27134aae6dbSAndreas Gohr    private function _step_unpack() {
27234aae6dbSAndreas Gohr        global $conf;
2733c38de15SAndreas Gohr        $this->_say('<b>'.$this->getLang('pk_extract').'</b>');
27434aae6dbSAndreas Gohr
27534aae6dbSAndreas Gohr        @set_time_limit(120);
27634aae6dbSAndreas Gohr        @ignore_user_abort();
27734aae6dbSAndreas Gohr
27834aae6dbSAndreas Gohr        $tar = new VerboseTarLib($this->tgzfile);
27934aae6dbSAndreas Gohr        if($tar->_initerror < 0) {
28034aae6dbSAndreas Gohr            $this->_say($tar->TarErrorStr($tar->_initerror));
2813c38de15SAndreas Gohr            $this->_say($this->getLang('pk_fail'));
28234aae6dbSAndreas Gohr            return false;
28334aae6dbSAndreas Gohr        }
28434aae6dbSAndreas Gohr
28534aae6dbSAndreas Gohr        $ok = $tar->Extract(VerboseTarLib::FULL_ARCHIVE, $this->tgzdir, 1, $conf['fmode'], '/^(_cs|_test|\.gitignore)/');
28634aae6dbSAndreas Gohr        if($ok < 1) {
28734aae6dbSAndreas Gohr            $this->_say($tar->TarErrorStr($ok));
2883c38de15SAndreas Gohr            $this->_say($this->getLang('pk_fail'));
28934aae6dbSAndreas Gohr            return false;
29034aae6dbSAndreas Gohr        }
29134aae6dbSAndreas Gohr
2923c38de15SAndreas Gohr        $this->_say($this->getLang('pk_done'));
293738c0102SAndreas Gohr
294bd08ebd1SAndreas Gohr        $this->_say(
295bd08ebd1SAndreas Gohr            $this->getLang('pk_version'),
296738c0102SAndreas Gohr            hsc(file_get_contents($this->tgzdir.'/VERSION')),
297bd08ebd1SAndreas Gohr            getVersion()
298bd08ebd1SAndreas Gohr        );
29934aae6dbSAndreas Gohr        return true;
30034aae6dbSAndreas Gohr    }
30134aae6dbSAndreas Gohr
302bd08ebd1SAndreas Gohr    /**
303bd08ebd1SAndreas Gohr     * Check permissions of files to change
304bd08ebd1SAndreas Gohr     *
305bd08ebd1SAndreas Gohr     * @return bool
306bd08ebd1SAndreas Gohr     */
3073c38de15SAndreas Gohr    private function _step_check() {
3083c38de15SAndreas Gohr        $this->_say($this->getLang('ck_start'));
3093c38de15SAndreas Gohr        $ok = $this->_traverse('', true);
31034aae6dbSAndreas Gohr        if($ok) {
3113c38de15SAndreas Gohr            $this->_say('<b>'.$this->getLang('ck_done').'</b>');
31234aae6dbSAndreas Gohr        } else {
3133c38de15SAndreas Gohr            $this->_say('<b>'.$this->getLang('ck_fail').'</b>');
31434aae6dbSAndreas Gohr        }
3153c38de15SAndreas Gohr        return $ok;
3163c38de15SAndreas Gohr    }
31734aae6dbSAndreas Gohr
318bd08ebd1SAndreas Gohr    /**
319bd08ebd1SAndreas Gohr     * Copy over new files
320bd08ebd1SAndreas Gohr     *
321bd08ebd1SAndreas Gohr     * @return bool
322bd08ebd1SAndreas Gohr     */
3233c38de15SAndreas Gohr    private function _step_copy() {
3243c38de15SAndreas Gohr        $this->_say($this->getLang('cp_start'));
3253c38de15SAndreas Gohr        $ok = $this->_traverse('', false);
3263c38de15SAndreas Gohr        if($ok) {
3273c38de15SAndreas Gohr            $this->_say('<b>'.$this->getLang('cp_done').'</b>');
32863712694SAndreas Gohr            $this->_rmold();
329e32047e3SAndreas Gohr            $this->_say('<b>'.$this->getLang('finish').'</b>');
33034aae6dbSAndreas Gohr        } else {
3313c38de15SAndreas Gohr            $this->_say('<b>'.$this->getLang('cp_fail').'</b>');
33234aae6dbSAndreas Gohr        }
33334aae6dbSAndreas Gohr        return $ok;
33434aae6dbSAndreas Gohr    }
33534aae6dbSAndreas Gohr
336bd08ebd1SAndreas Gohr    /**
337bd08ebd1SAndreas Gohr     * Delete outdated files
338bd08ebd1SAndreas Gohr     */
33963712694SAndreas Gohr    private function _rmold() {
34063712694SAndreas Gohr        $list = file($this->tgzdir.'data/deleted.files');
34163712694SAndreas Gohr        foreach($list as $line) {
34263712694SAndreas Gohr            $line = trim(preg_replace('/#.*$/', '', $line));
34363712694SAndreas Gohr            if(!$line) continue;
34463712694SAndreas Gohr            $file = DOKU_INC.$line;
34563712694SAndreas Gohr            if(!file_exists($file)) continue;
34663712694SAndreas Gohr            if((is_dir($file) && $this->_rdel($file)) ||
347bd08ebd1SAndreas Gohr                @unlink($file)
348bd08ebd1SAndreas Gohr            ) {
349e32047e3SAndreas Gohr                $this->_say($this->getLang('rm_done'), hsc($line));
35063712694SAndreas Gohr            } else {
351e32047e3SAndreas Gohr                $this->_say($this->getLang('rm_fail'), hsc($line));
35263712694SAndreas Gohr            }
35363712694SAndreas Gohr        }
35463712694SAndreas Gohr    }
35563712694SAndreas Gohr
356bd08ebd1SAndreas Gohr    /**
357bd08ebd1SAndreas Gohr     * Traverse over the given dir and compare it to the DokuWiki dir
358bd08ebd1SAndreas Gohr     *
359bd08ebd1SAndreas Gohr     * Checks what files need an update, tests for writability and copies
360bd08ebd1SAndreas Gohr     *
361bd08ebd1SAndreas Gohr     * @param string $dir
362bd08ebd1SAndreas Gohr     * @param bool $dryrun do not copy but only check permissions
363bd08ebd1SAndreas Gohr     * @return bool
364bd08ebd1SAndreas Gohr     */
36534aae6dbSAndreas Gohr    private function _traverse($dir, $dryrun) {
36634aae6dbSAndreas Gohr        $base = $this->tgzdir;
36734aae6dbSAndreas Gohr        $ok   = true;
36834aae6dbSAndreas Gohr
36934aae6dbSAndreas Gohr        $dh = @opendir($base.'/'.$dir);
370bd08ebd1SAndreas Gohr        if(!$dh) return false;
37134aae6dbSAndreas Gohr        while(($file = readdir($dh)) !== false) {
37234aae6dbSAndreas Gohr            if($file == '.' || $file == '..') continue;
37334aae6dbSAndreas Gohr            $from = "$base/$dir/$file";
37434aae6dbSAndreas Gohr            $to   = DOKU_INC."$dir/$file";
37534aae6dbSAndreas Gohr
37634aae6dbSAndreas Gohr            if(is_dir($from)) {
37734aae6dbSAndreas Gohr                if($dryrun) {
37834aae6dbSAndreas Gohr                    // just check for writability
37934aae6dbSAndreas Gohr                    if(!is_dir($to)) {
38034aae6dbSAndreas Gohr                        if(is_dir(dirname($to)) && !is_writable(dirname($to))) {
381a7b56078SAndreas Gohr                            $this->_say('<b>'.$this->getLang('tv_noperm').'</b>', hsc("$dir/$file"));
38234aae6dbSAndreas Gohr                            $ok = false;
38334aae6dbSAndreas Gohr                        }
38434aae6dbSAndreas Gohr                    }
38534aae6dbSAndreas Gohr                }
38634aae6dbSAndreas Gohr
38734aae6dbSAndreas Gohr                // recursion
38834aae6dbSAndreas Gohr                if(!$this->_traverse("$dir/$file", $dryrun)) {
38934aae6dbSAndreas Gohr                    $ok = false;
39034aae6dbSAndreas Gohr                }
39134aae6dbSAndreas Gohr            } else {
392f2fa6d10SAndreas Gohr                $fmd5 = md5(@file_get_contents($from));
393f2fa6d10SAndreas Gohr                $tmd5 = md5(@file_get_contents($to));
3946deeb3b1SAndreas Gohr                if($fmd5 != $tmd5 || !file_exists($to)) {
39534aae6dbSAndreas Gohr                    if($dryrun) {
39634aae6dbSAndreas Gohr                        // just check for writability
39734aae6dbSAndreas Gohr                        if((file_exists($to) && !is_writable($to)) ||
398bd08ebd1SAndreas Gohr                            (!file_exists($to) && is_dir(dirname($to)) && !is_writable(dirname($to)))
399bd08ebd1SAndreas Gohr                        ) {
40034aae6dbSAndreas Gohr
401a7b56078SAndreas Gohr                            $this->_say('<b>'.$this->getLang('tv_noperm').'</b>', hsc("$dir/$file"));
40234aae6dbSAndreas Gohr                            $ok = false;
40334aae6dbSAndreas Gohr                        } else {
4043c38de15SAndreas Gohr                            $this->_say($this->getLang('tv_upd'), hsc("$dir/$file"));
40534aae6dbSAndreas Gohr                        }
40634aae6dbSAndreas Gohr                    } else {
40734aae6dbSAndreas Gohr                        // check dir
40834aae6dbSAndreas Gohr                        if(io_mkdir_p(dirname($to))) {
40934aae6dbSAndreas Gohr                            // copy
41034aae6dbSAndreas Gohr                            if(!copy($from, $to)) {
4113c38de15SAndreas Gohr                                $this->_say('<b>'.$this->getLang('tv_nocopy').'</b>', hsc("$dir/$file"));
41234aae6dbSAndreas Gohr                                $ok = false;
41334aae6dbSAndreas Gohr                            } else {
4143c38de15SAndreas Gohr                                $this->_say($this->getLang('tv_done'), hsc("$dir/$file"));
41534aae6dbSAndreas Gohr                            }
41634aae6dbSAndreas Gohr                        } else {
4173c38de15SAndreas Gohr                            $this->_say('<b>'.$this->getLang('tv_nodir').'</b>', hsc("$dir"));
41834aae6dbSAndreas Gohr                            $ok = false;
41934aae6dbSAndreas Gohr                        }
42034aae6dbSAndreas Gohr                    }
42134aae6dbSAndreas Gohr                }
42234aae6dbSAndreas Gohr            }
42334aae6dbSAndreas Gohr        }
42434aae6dbSAndreas Gohr        closedir($dh);
42534aae6dbSAndreas Gohr        return $ok;
42634aae6dbSAndreas Gohr    }
42734aae6dbSAndreas Gohr}
42834aae6dbSAndreas Gohr
42934aae6dbSAndreas Gohr// vim:ts=4:sw=4:et:enc=utf-8:
430