xref: /plugin/upgrade/admin.php (revision 9bbe795a9b6df9f69d0d47c1980743682c4c7b78)
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;
19f378cb7eSAndreas Gohr    private $tgzversion;
20f378cb7eSAndreas 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/';
30f378cb7eSAndreas Gohr        $this->tgzversion    = "https://raw.githubusercontent.com/splitbrain/dokuwiki/$branch/VERSION";
31f378cb7eSAndreas 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
5006dc93a8SAndreas Gohr        global $conf;
5106dc93a8SAndreas Gohr        if($conf['safemodehack']) {
5206dc93a8SAndreas Gohr            $abrt = false;
5306dc93a8SAndreas Gohr            $next = false;
5406dc93a8SAndreas Gohr            echo $this->locale_xhtml('safemode');
5506dc93a8SAndreas Gohr            return;
5606dc93a8SAndreas Gohr        }
5706dc93a8SAndreas Gohr
58d391262fSAndreas Gohr        $this->_say('<div id="plugin__upgrade">');
5975e9d164SAndreas Gohr        // enable auto scroll
6075e9d164SAndreas Gohr        ?>
6175e9d164SAndreas Gohr        <script language="javascript" type="text/javascript">
62d391262fSAndreas Gohr            var plugin_upgrade = window.setInterval(function () {
63d4376367SAndreas Gohr                var obj = document.getElementById('plugin__upgrade');
6475e9d164SAndreas Gohr                if (obj) obj.scrollTop = obj.scrollHeight;
6575e9d164SAndreas Gohr            }, 25);
6675e9d164SAndreas Gohr        </script>
6775e9d164SAndreas Gohr        <?php
6875e9d164SAndreas Gohr
6975e9d164SAndreas Gohr        // handle current step
7022c39b33SAndreas Gohr        $this->_stepit($abrt, $next);
7134aae6dbSAndreas Gohr
7275e9d164SAndreas Gohr        // disable auto scroll
7375e9d164SAndreas Gohr        ?>
7475e9d164SAndreas Gohr        <script language="javascript" type="text/javascript">
7575e9d164SAndreas Gohr            window.setTimeout(function () {
76d391262fSAndreas Gohr                window.clearInterval(plugin_upgrade);
7775e9d164SAndreas Gohr            }, 50);
7875e9d164SAndreas Gohr        </script>
7975e9d164SAndreas Gohr        <?php
8075e9d164SAndreas Gohr        $this->_say('</div>');
8175e9d164SAndreas Gohr
82d391262fSAndreas Gohr        echo '<form action="" method="get" id="plugin__upgrade_form">';
8334aae6dbSAndreas Gohr        echo '<input type="hidden" name="do" value="admin" />';
84d391262fSAndreas Gohr        echo '<input type="hidden" name="page" value="upgrade" />';
8541163f44SAndreas Gohr        echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />';
866e7afd39SAndreas Gohr        if($next) echo '<input type="submit" name="step['.$next.']" value="'.$this->getLang('btn_continue').' ➡" class="button continue" />';
876e7afd39SAndreas Gohr        if($abrt) echo '<input type="submit" name="step[cancel]" value="✖ '.$this->getLang('btn_abort').'" class="button abort" />';
8834aae6dbSAndreas Gohr        echo '</form>';
89eb52c46aSAndreas Gohr
90eb52c46aSAndreas Gohr        $this->_progress($next);
91eb52c46aSAndreas Gohr    }
92eb52c46aSAndreas Gohr
93eb52c46aSAndreas Gohr    /**
94eb52c46aSAndreas Gohr     * Display a progress bar of all steps
95eb52c46aSAndreas Gohr     *
96eb52c46aSAndreas Gohr     * @param string $next the next step
97eb52c46aSAndreas Gohr     */
98eb52c46aSAndreas Gohr    private function _progress($next) {
99eb52c46aSAndreas Gohr        $steps  = array('version', 'download', 'unpack', 'check', 'upgrade');
100eb52c46aSAndreas Gohr        $active = true;
101eb52c46aSAndreas Gohr        $count = 0;
102eb52c46aSAndreas Gohr
103eb52c46aSAndreas Gohr        echo '<div id="plugin__upgrade_meter"><ol>';
104eb52c46aSAndreas Gohr        foreach($steps as $step) {
105eb52c46aSAndreas Gohr            $count++;
106eb52c46aSAndreas Gohr            if($step == $next) $active = false;
107eb52c46aSAndreas Gohr            if($active) {
108eb52c46aSAndreas Gohr                echo '<li class="active">';
109eb52c46aSAndreas Gohr                echo '<span class="step">✔</span>';
110eb52c46aSAndreas Gohr            } else {
111eb52c46aSAndreas Gohr                echo '<li>';
112eb52c46aSAndreas Gohr                echo '<span class="step">'.$count.'</span>';
113eb52c46aSAndreas Gohr            }
114eb52c46aSAndreas Gohr
115eb52c46aSAndreas Gohr            echo '<span class="stage">'.$this->getLang('step_'.$step).'</span>';
116eb52c46aSAndreas Gohr            echo '</li>';
117eb52c46aSAndreas Gohr        }
118eb52c46aSAndreas Gohr        echo '</ol></div>';
11934aae6dbSAndreas Gohr    }
12034aae6dbSAndreas Gohr
121bd08ebd1SAndreas Gohr    /**
122bd08ebd1SAndreas Gohr     * Decides the current step and executes it
123bd08ebd1SAndreas Gohr     *
124bd08ebd1SAndreas Gohr     * @param bool $abrt
125bd08ebd1SAndreas Gohr     * @param bool $next
126bd08ebd1SAndreas Gohr     */
12734aae6dbSAndreas Gohr    private function _stepit(&$abrt, &$next) {
1284bed5591SAndreas Gohr
12934aae6dbSAndreas Gohr        if(isset($_REQUEST['step']) && is_array($_REQUEST['step'])) {
13034aae6dbSAndreas Gohr            $step = array_shift(array_keys($_REQUEST['step']));
13134aae6dbSAndreas Gohr        } else {
13234aae6dbSAndreas Gohr            $step = '';
13334aae6dbSAndreas Gohr        }
13434aae6dbSAndreas Gohr
13534aae6dbSAndreas Gohr        if($step == 'cancel') {
13634aae6dbSAndreas Gohr            # cleanup
13734aae6dbSAndreas Gohr            @unlink($this->tgzfile);
1386b2d1b30SAndreas Gohr            $this->_rdel($this->tgzdir);
13934aae6dbSAndreas Gohr            $step = '';
14034aae6dbSAndreas Gohr        }
14134aae6dbSAndreas Gohr
14234aae6dbSAndreas Gohr        if($step) {
14334aae6dbSAndreas Gohr            $abrt = true;
14434aae6dbSAndreas Gohr            $next = false;
145f378cb7eSAndreas Gohr            if($step == 'version') {
146f378cb7eSAndreas Gohr                $this->_step_version();
147f378cb7eSAndreas Gohr                $next = 'download';
148f378cb7eSAndreas Gohr            } elseif(!file_exists($this->tgzfile)) {
14934aae6dbSAndreas Gohr                if($this->_step_download()) $next = 'unpack';
15034aae6dbSAndreas Gohr            } elseif(!is_dir($this->tgzdir)) {
15134aae6dbSAndreas Gohr                if($this->_step_unpack()) $next = 'check';
15234aae6dbSAndreas Gohr            } elseif($step != 'upgrade') {
1533c38de15SAndreas Gohr                if($this->_step_check()) $next = 'upgrade';
15434aae6dbSAndreas Gohr            } elseif($step == 'upgrade') {
1553c38de15SAndreas Gohr                if($this->_step_copy()) $next = 'cancel';
15634aae6dbSAndreas Gohr            } else {
15775e9d164SAndreas Gohr                echo 'uhm. what happened? where am I? This should not happen';
15834aae6dbSAndreas Gohr            }
15934aae6dbSAndreas Gohr        } else {
16034aae6dbSAndreas Gohr            # first time run, show intro
16134aae6dbSAndreas Gohr            echo $this->locale_xhtml('step0');
16234aae6dbSAndreas Gohr            $abrt = false;
163f378cb7eSAndreas Gohr            $next = 'version';
16434aae6dbSAndreas Gohr        }
16534aae6dbSAndreas Gohr    }
16634aae6dbSAndreas Gohr
167bd08ebd1SAndreas Gohr    /**
168bd08ebd1SAndreas Gohr     * Output the given arguments using vsprintf and flush buffers
169bd08ebd1SAndreas Gohr     */
170d04a99cdSAndreas Gohr    public static function _say() {
17134aae6dbSAndreas Gohr        $args = func_get_args();
1726e7afd39SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="16" height="16" alt="" /> ';
1736e7afd39SAndreas Gohr        echo vsprintf(array_shift($args)."<br />\n", $args);
1746e7afd39SAndreas Gohr        flush();
1756e7afd39SAndreas Gohr        ob_flush();
1766e7afd39SAndreas Gohr    }
1776e7afd39SAndreas Gohr
1786e7afd39SAndreas Gohr    /**
1796e7afd39SAndreas Gohr     * Print a warning using the given arguments with vsprintf and flush buffers
1806e7afd39SAndreas Gohr     */
181d04a99cdSAndreas Gohr    public static function _warn() {
1826e7afd39SAndreas Gohr        $args = func_get_args();
1836e7afd39SAndreas Gohr        echo '<img src="'.DOKU_BASE.'lib/images/error.png" width="16" height="16" alt="!" /> ';
18434aae6dbSAndreas Gohr        echo vsprintf(array_shift($args)."<br />\n", $args);
18534aae6dbSAndreas Gohr        flush();
18634aae6dbSAndreas Gohr        ob_flush();
18734aae6dbSAndreas Gohr    }
18834aae6dbSAndreas Gohr
1896b2d1b30SAndreas Gohr    /**
1906b2d1b30SAndreas Gohr     * Recursive delete
1916b2d1b30SAndreas Gohr     *
1929285faa5SAndreas Gohr     * @author Jon Hassall
1939285faa5SAndreas Gohr     * @link   http://de.php.net/manual/en/function.unlink.php#87045
1946b2d1b30SAndreas Gohr     */
1959285faa5SAndreas Gohr    private function _rdel($dir) {
1969285faa5SAndreas Gohr        if(!$dh = @opendir($dir)) {
197bd08ebd1SAndreas Gohr            return false;
1989285faa5SAndreas Gohr        }
1999285faa5SAndreas Gohr        while(false !== ($obj = readdir($dh))) {
2009285faa5SAndreas Gohr            if($obj == '.' || $obj == '..') continue;
2019285faa5SAndreas Gohr
2029285faa5SAndreas Gohr            if(!@unlink($dir.'/'.$obj)) {
2039285faa5SAndreas Gohr                $this->_rdel($dir.'/'.$obj);
2049285faa5SAndreas Gohr            }
2059285faa5SAndreas Gohr        }
2069285faa5SAndreas Gohr        closedir($dh);
207e32047e3SAndreas Gohr        return @rmdir($dir);
2086b2d1b30SAndreas Gohr    }
2096b2d1b30SAndreas Gohr
210bd08ebd1SAndreas Gohr    /**
211f378cb7eSAndreas Gohr     * Check various versions
212f378cb7eSAndreas Gohr     *
213f378cb7eSAndreas Gohr     * @return bool
214f378cb7eSAndreas Gohr     */
215f378cb7eSAndreas Gohr    private function _step_version() {
216f378cb7eSAndreas Gohr        $ok = true;
217f378cb7eSAndreas Gohr
218c37aa5dcSAndreas Gohr        // we need SSL - only newer HTTPClients check that themselves
219c37aa5dcSAndreas Gohr        if(!in_array('ssl', stream_get_transports())) {
220c37aa5dcSAndreas Gohr            $this->_warn($this->getLang('vs_ssl'));
221c37aa5dcSAndreas Gohr            $ok = false;
222c37aa5dcSAndreas Gohr        }
223c37aa5dcSAndreas Gohr
224f378cb7eSAndreas Gohr        // get the available version
225f378cb7eSAndreas Gohr        $http       = new DokuHTTPClient();
226f378cb7eSAndreas Gohr        $tgzversion = $http->get($this->tgzversion);
227f378cb7eSAndreas Gohr        if(!$tgzversion) {
2286e7afd39SAndreas Gohr            $this->_warn($this->getLang('vs_tgzno').' '.hsc($http->error));
229f378cb7eSAndreas Gohr            $ok = false;
230f378cb7eSAndreas Gohr        }
231f378cb7eSAndreas Gohr        if(!preg_match('/(^| )(\d\d\d\d-\d\d-\d\d[a-z]*)( |$)/i', $tgzversion, $m)) {
2326e7afd39SAndreas Gohr            $this->_warn($this->getLang('vs_tgzno'));
233f378cb7eSAndreas Gohr            $ok            = false;
234f378cb7eSAndreas Gohr            $tgzversionnum = 0;
235f378cb7eSAndreas Gohr        } else {
236f378cb7eSAndreas Gohr            $tgzversionnum = $m[2];
237f378cb7eSAndreas Gohr            $this->_say($this->getLang('vs_tgz'), $tgzversion);
238f378cb7eSAndreas Gohr        }
239f378cb7eSAndreas Gohr
240f378cb7eSAndreas Gohr        // get the current version
241f378cb7eSAndreas Gohr        $version = getVersion();
242f378cb7eSAndreas Gohr        if(!preg_match('/(^| )(\d\d\d\d-\d\d-\d\d[a-z]*)( |$)/i', $version, $m)) {
243f378cb7eSAndreas Gohr            $versionnum = 0;
244f378cb7eSAndreas Gohr        } else {
245f378cb7eSAndreas Gohr            $versionnum = $m[2];
246f378cb7eSAndreas Gohr        }
247f378cb7eSAndreas Gohr        $this->_say($this->getLang('vs_local'), $version);
248f378cb7eSAndreas Gohr
249f378cb7eSAndreas Gohr        // compare versions
250f378cb7eSAndreas Gohr        if(!$versionnum) {
2516e7afd39SAndreas Gohr            $this->_warn($this->getLang('vs_localno'));
252f378cb7eSAndreas Gohr            $ok = false;
253f378cb7eSAndreas Gohr        } else if($tgzversionnum) {
254f378cb7eSAndreas Gohr            if($tgzversionnum < $versionnum) {
2556e7afd39SAndreas Gohr                $this->_warn($this->getLang('vs_newer'));
256f378cb7eSAndreas Gohr                $ok = false;
257f378cb7eSAndreas Gohr            } elseif($tgzversionnum == $versionnum) {
2586e7afd39SAndreas Gohr                $this->_warn($this->getLang('vs_same'));
259f378cb7eSAndreas Gohr                $ok = false;
260f378cb7eSAndreas Gohr            }
261f378cb7eSAndreas Gohr        }
262f378cb7eSAndreas Gohr
263f378cb7eSAndreas Gohr        // check plugin version
264f378cb7eSAndreas Gohr        $pluginversion = $http->get($this->pluginversion);
265f378cb7eSAndreas Gohr        if($pluginversion) {
266f378cb7eSAndreas Gohr            $plugininfo = linesToHash(explode("\n", $pluginversion));
267f378cb7eSAndreas Gohr            $myinfo     = $this->getInfo();
268f378cb7eSAndreas Gohr            if($plugininfo['date'] > $myinfo['date']) {
2697cb119ecSAndreas Gohr                $this->_warn($this->getLang('vs_plugin'), $plugininfo['date']);
270f378cb7eSAndreas Gohr                $ok = false;
271f378cb7eSAndreas Gohr            }
272f378cb7eSAndreas Gohr        }
273f378cb7eSAndreas Gohr
274*9bbe795aSAndreas Gohr        // next release will need 5.3
275*9bbe795aSAndreas Gohr        if($tgzversionnum > '2014-09-29z') {
276*9bbe795aSAndreas Gohr            $minphp = '5.3.0';
277*9bbe795aSAndreas Gohr        } else {
278*9bbe795aSAndreas Gohr            $minphp = '5.2.0';
279*9bbe795aSAndreas Gohr        }
280*9bbe795aSAndreas Gohr
281*9bbe795aSAndreas Gohr        // check if PHP is up to date
282*9bbe795aSAndreas Gohr        if(version_compare(phpversion(), $minphp, '<')) {
283*9bbe795aSAndreas Gohr            $this->_warn($this->getLang('vs_php'));
284*9bbe795aSAndreas Gohr            $ok = false;
285*9bbe795aSAndreas Gohr        }
286*9bbe795aSAndreas Gohr
287f378cb7eSAndreas Gohr        return $ok;
288f378cb7eSAndreas Gohr    }
289f378cb7eSAndreas Gohr
290f378cb7eSAndreas Gohr    /**
291bd08ebd1SAndreas Gohr     * Download the tarball
292bd08ebd1SAndreas Gohr     *
293bd08ebd1SAndreas Gohr     * @return bool
294bd08ebd1SAndreas Gohr     */
29534aae6dbSAndreas Gohr    private function _step_download() {
2963c38de15SAndreas Gohr        $this->_say($this->getLang('dl_from'), $this->tgzurl);
29734aae6dbSAndreas Gohr
29834aae6dbSAndreas Gohr        @set_time_limit(120);
29934aae6dbSAndreas Gohr        @ignore_user_abort();
30034aae6dbSAndreas Gohr
30134aae6dbSAndreas Gohr        $http          = new DokuHTTPClient();
30234aae6dbSAndreas Gohr        $http->timeout = 120;
30334aae6dbSAndreas Gohr        $data          = $http->get($this->tgzurl);
30434aae6dbSAndreas Gohr
30534aae6dbSAndreas Gohr        if(!$data) {
3066e7afd39SAndreas Gohr            $this->_warn($http->error);
3076e7afd39SAndreas Gohr            $this->_warn($this->getLang('dl_fail'));
30834aae6dbSAndreas Gohr            return false;
30934aae6dbSAndreas Gohr        }
31034aae6dbSAndreas Gohr
31134aae6dbSAndreas Gohr        if(!io_saveFile($this->tgzfile, $data)) {
3126e7afd39SAndreas Gohr            $this->_warn($this->getLang('dl_fail'));
31334aae6dbSAndreas Gohr            return false;
31434aae6dbSAndreas Gohr        }
31534aae6dbSAndreas Gohr
316a7b56078SAndreas Gohr        $this->_say($this->getLang('dl_done'), filesize_h(strlen($data)));
3173c38de15SAndreas Gohr
31834aae6dbSAndreas Gohr        return true;
31934aae6dbSAndreas Gohr    }
32034aae6dbSAndreas Gohr
321bd08ebd1SAndreas Gohr    /**
322bd08ebd1SAndreas Gohr     * Unpack the tarball
323bd08ebd1SAndreas Gohr     *
324bd08ebd1SAndreas Gohr     * @return bool
325bd08ebd1SAndreas Gohr     */
32634aae6dbSAndreas Gohr    private function _step_unpack() {
3273c38de15SAndreas Gohr        $this->_say('<b>'.$this->getLang('pk_extract').'</b>');
32834aae6dbSAndreas Gohr
32934aae6dbSAndreas Gohr        @set_time_limit(120);
33034aae6dbSAndreas Gohr        @ignore_user_abort();
33134aae6dbSAndreas Gohr
332d04a99cdSAndreas Gohr        try {
333d04a99cdSAndreas Gohr            $tar = new VerboseTar();
334d04a99cdSAndreas Gohr            $tar->open($this->tgzfile);
335d04a99cdSAndreas Gohr            $tar->extract($this->tgzdir, 1);
336d04a99cdSAndreas Gohr            $tar->close();
337d04a99cdSAndreas Gohr        } catch (Exception $e) {
338d04a99cdSAndreas Gohr            $this->_warn($e->getMessage());
3396e7afd39SAndreas Gohr            $this->_warn($this->getLang('pk_fail'));
34034aae6dbSAndreas Gohr            return false;
34134aae6dbSAndreas Gohr        }
34234aae6dbSAndreas Gohr
3433c38de15SAndreas Gohr        $this->_say($this->getLang('pk_done'));
344738c0102SAndreas Gohr
345bd08ebd1SAndreas Gohr        $this->_say(
346bd08ebd1SAndreas Gohr            $this->getLang('pk_version'),
347738c0102SAndreas Gohr            hsc(file_get_contents($this->tgzdir.'/VERSION')),
348bd08ebd1SAndreas Gohr            getVersion()
349bd08ebd1SAndreas Gohr        );
35034aae6dbSAndreas Gohr        return true;
35134aae6dbSAndreas Gohr    }
35234aae6dbSAndreas Gohr
353bd08ebd1SAndreas Gohr    /**
354bd08ebd1SAndreas Gohr     * Check permissions of files to change
355bd08ebd1SAndreas Gohr     *
356bd08ebd1SAndreas Gohr     * @return bool
357bd08ebd1SAndreas Gohr     */
3583c38de15SAndreas Gohr    private function _step_check() {
3593c38de15SAndreas Gohr        $this->_say($this->getLang('ck_start'));
3603c38de15SAndreas Gohr        $ok = $this->_traverse('', true);
36134aae6dbSAndreas Gohr        if($ok) {
3623c38de15SAndreas Gohr            $this->_say('<b>'.$this->getLang('ck_done').'</b>');
36334aae6dbSAndreas Gohr        } else {
3646e7afd39SAndreas Gohr            $this->_warn('<b>'.$this->getLang('ck_fail').'</b>');
36534aae6dbSAndreas Gohr        }
3663c38de15SAndreas Gohr        return $ok;
3673c38de15SAndreas Gohr    }
36834aae6dbSAndreas Gohr
369bd08ebd1SAndreas Gohr    /**
370bd08ebd1SAndreas Gohr     * Copy over new files
371bd08ebd1SAndreas Gohr     *
372bd08ebd1SAndreas Gohr     * @return bool
373bd08ebd1SAndreas Gohr     */
3743c38de15SAndreas Gohr    private function _step_copy() {
3753c38de15SAndreas Gohr        $this->_say($this->getLang('cp_start'));
3763c38de15SAndreas Gohr        $ok = $this->_traverse('', false);
3773c38de15SAndreas Gohr        if($ok) {
3783c38de15SAndreas Gohr            $this->_say('<b>'.$this->getLang('cp_done').'</b>');
37963712694SAndreas Gohr            $this->_rmold();
380e32047e3SAndreas Gohr            $this->_say('<b>'.$this->getLang('finish').'</b>');
38134aae6dbSAndreas Gohr        } else {
3826e7afd39SAndreas Gohr            $this->_warn('<b>'.$this->getLang('cp_fail').'</b>');
38334aae6dbSAndreas Gohr        }
38434aae6dbSAndreas Gohr        return $ok;
38534aae6dbSAndreas Gohr    }
38634aae6dbSAndreas Gohr
387bd08ebd1SAndreas Gohr    /**
388bd08ebd1SAndreas Gohr     * Delete outdated files
389bd08ebd1SAndreas Gohr     */
39063712694SAndreas Gohr    private function _rmold() {
39163712694SAndreas Gohr        $list = file($this->tgzdir.'data/deleted.files');
39263712694SAndreas Gohr        foreach($list as $line) {
39363712694SAndreas Gohr            $line = trim(preg_replace('/#.*$/', '', $line));
39463712694SAndreas Gohr            if(!$line) continue;
39563712694SAndreas Gohr            $file = DOKU_INC.$line;
39663712694SAndreas Gohr            if(!file_exists($file)) continue;
39763712694SAndreas Gohr            if((is_dir($file) && $this->_rdel($file)) ||
398bd08ebd1SAndreas Gohr                @unlink($file)
399bd08ebd1SAndreas Gohr            ) {
400e32047e3SAndreas Gohr                $this->_say($this->getLang('rm_done'), hsc($line));
40163712694SAndreas Gohr            } else {
4026e7afd39SAndreas Gohr                $this->_warn($this->getLang('rm_fail'), hsc($line));
40363712694SAndreas Gohr            }
40463712694SAndreas Gohr        }
405331439fbSAndreas Gohr        // delete install
406331439fbSAndreas Gohr        @unlink(DOKU_INC.'install.php');
407de440c89SAndreas Gohr
408de440c89SAndreas Gohr        // make sure update message will be gone
409de440c89SAndreas Gohr        @touch(DOKU_INC.'doku.php');
41063712694SAndreas Gohr    }
41163712694SAndreas Gohr
412bd08ebd1SAndreas Gohr    /**
413bd08ebd1SAndreas Gohr     * Traverse over the given dir and compare it to the DokuWiki dir
414bd08ebd1SAndreas Gohr     *
415bd08ebd1SAndreas Gohr     * Checks what files need an update, tests for writability and copies
416bd08ebd1SAndreas Gohr     *
417bd08ebd1SAndreas Gohr     * @param string $dir
418bd08ebd1SAndreas Gohr     * @param bool   $dryrun do not copy but only check permissions
419bd08ebd1SAndreas Gohr     * @return bool
420bd08ebd1SAndreas Gohr     */
42134aae6dbSAndreas Gohr    private function _traverse($dir, $dryrun) {
42234aae6dbSAndreas Gohr        $base = $this->tgzdir;
42334aae6dbSAndreas Gohr        $ok   = true;
42434aae6dbSAndreas Gohr
42534aae6dbSAndreas Gohr        $dh = @opendir($base.'/'.$dir);
426bd08ebd1SAndreas Gohr        if(!$dh) return false;
42734aae6dbSAndreas Gohr        while(($file = readdir($dh)) !== false) {
42834aae6dbSAndreas Gohr            if($file == '.' || $file == '..') continue;
42934aae6dbSAndreas Gohr            $from = "$base/$dir/$file";
43034aae6dbSAndreas Gohr            $to   = DOKU_INC."$dir/$file";
43134aae6dbSAndreas Gohr
43234aae6dbSAndreas Gohr            if(is_dir($from)) {
43334aae6dbSAndreas Gohr                if($dryrun) {
43434aae6dbSAndreas Gohr                    // just check for writability
43534aae6dbSAndreas Gohr                    if(!is_dir($to)) {
43634aae6dbSAndreas Gohr                        if(is_dir(dirname($to)) && !is_writable(dirname($to))) {
4376e7afd39SAndreas Gohr                            $this->_warn('<b>'.$this->getLang('tv_noperm').'</b>', hsc("$dir/$file"));
43834aae6dbSAndreas Gohr                            $ok = false;
43934aae6dbSAndreas Gohr                        }
44034aae6dbSAndreas Gohr                    }
44134aae6dbSAndreas Gohr                }
44234aae6dbSAndreas Gohr
44334aae6dbSAndreas Gohr                // recursion
44434aae6dbSAndreas Gohr                if(!$this->_traverse("$dir/$file", $dryrun)) {
44534aae6dbSAndreas Gohr                    $ok = false;
44634aae6dbSAndreas Gohr                }
44734aae6dbSAndreas Gohr            } else {
448f2fa6d10SAndreas Gohr                $fmd5 = md5(@file_get_contents($from));
449f2fa6d10SAndreas Gohr                $tmd5 = md5(@file_get_contents($to));
4506deeb3b1SAndreas Gohr                if($fmd5 != $tmd5 || !file_exists($to)) {
45134aae6dbSAndreas Gohr                    if($dryrun) {
45234aae6dbSAndreas Gohr                        // just check for writability
45334aae6dbSAndreas Gohr                        if((file_exists($to) && !is_writable($to)) ||
454bd08ebd1SAndreas Gohr                            (!file_exists($to) && is_dir(dirname($to)) && !is_writable(dirname($to)))
455bd08ebd1SAndreas Gohr                        ) {
45634aae6dbSAndreas Gohr
4576e7afd39SAndreas Gohr                            $this->_warn('<b>'.$this->getLang('tv_noperm').'</b>', hsc("$dir/$file"));
45834aae6dbSAndreas Gohr                            $ok = false;
45934aae6dbSAndreas Gohr                        } else {
4603c38de15SAndreas Gohr                            $this->_say($this->getLang('tv_upd'), hsc("$dir/$file"));
46134aae6dbSAndreas Gohr                        }
46234aae6dbSAndreas Gohr                    } else {
46334aae6dbSAndreas Gohr                        // check dir
46434aae6dbSAndreas Gohr                        if(io_mkdir_p(dirname($to))) {
46534aae6dbSAndreas Gohr                            // copy
46634aae6dbSAndreas Gohr                            if(!copy($from, $to)) {
4676e7afd39SAndreas Gohr                                $this->_warn('<b>'.$this->getLang('tv_nocopy').'</b>', hsc("$dir/$file"));
46834aae6dbSAndreas Gohr                                $ok = false;
46934aae6dbSAndreas Gohr                            } else {
4703c38de15SAndreas Gohr                                $this->_say($this->getLang('tv_done'), hsc("$dir/$file"));
47134aae6dbSAndreas Gohr                            }
47234aae6dbSAndreas Gohr                        } else {
4736e7afd39SAndreas Gohr                            $this->_warn('<b>'.$this->getLang('tv_nodir').'</b>', hsc("$dir"));
47434aae6dbSAndreas Gohr                            $ok = false;
47534aae6dbSAndreas Gohr                        }
47634aae6dbSAndreas Gohr                    }
47734aae6dbSAndreas Gohr                }
47834aae6dbSAndreas Gohr            }
47934aae6dbSAndreas Gohr        }
48034aae6dbSAndreas Gohr        closedir($dh);
48134aae6dbSAndreas Gohr        return $ok;
48234aae6dbSAndreas Gohr    }
48334aae6dbSAndreas Gohr}
48434aae6dbSAndreas Gohr
48534aae6dbSAndreas Gohr// vim:ts=4:sw=4:et:enc=utf-8:
486