14e3e87e4SAndreas Gohr<?php 2*8dab6045SAndreas Gohr 34e3e87e4SAndreas Gohr/** 44e3e87e4SAndreas Gohr * DokuWiki Plugin upgrade (Helper Component) 54e3e87e4SAndreas Gohr * 64e3e87e4SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 74e3e87e4SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 84e3e87e4SAndreas Gohr */ 94e3e87e4SAndreas Gohr 104e3e87e4SAndreas Gohruse dokuwiki\plugin\upgrade\HTTP\DokuHTTPClient; 114e3e87e4SAndreas Gohruse splitbrain\PHPArchive\FileInfo; 124e3e87e4SAndreas Gohruse splitbrain\PHPArchive\Tar; 134e3e87e4SAndreas Gohr 144e3e87e4SAndreas Gohrclass helper_plugin_upgrade extends DokuWiki_Plugin 154e3e87e4SAndreas Gohr{ 164e3e87e4SAndreas Gohr /** @var string download URL for the new DokuWiki release */ 174e3e87e4SAndreas Gohr public $tgzurl; 184e3e87e4SAndreas Gohr /** @var string full path to where the file will be downloaded to */ 194e3e87e4SAndreas Gohr public $tgzfile; 204e3e87e4SAndreas Gohr /** @var string full path to where the file will be extracted to */ 214e3e87e4SAndreas Gohr public $tgzdir; 224e3e87e4SAndreas Gohr /** @var string URL to the VERSION file of the new DokuWiki release */ 234e3e87e4SAndreas Gohr public $tgzversion; 246741b585SAndreas Gohr /** @var string URL to the composer.json file of the new DokuWiki release */ 254cefc146SAndreas Gohr protected $composer; 264e3e87e4SAndreas Gohr /** @var string URL to the plugin.info.txt file of the upgrade plugin */ 274e3e87e4SAndreas Gohr public $pluginversion; 284e3e87e4SAndreas Gohr 294e3e87e4SAndreas Gohr /** @var admin_plugin_upgrade|cli_plugin_upgrade */ 304e3e87e4SAndreas Gohr protected $logger; 314e3e87e4SAndreas Gohr 324e3e87e4SAndreas Gohr public function __construct() 334e3e87e4SAndreas Gohr { 344e3e87e4SAndreas Gohr global $conf; 354e3e87e4SAndreas Gohr 364e3e87e4SAndreas Gohr $branch = 'stable'; 374e3e87e4SAndreas Gohr 384e3e87e4SAndreas Gohr $this->tgzurl = "https://github.com/splitbrain/dokuwiki/archive/$branch.tar.gz"; 394e3e87e4SAndreas Gohr $this->tgzfile = $conf['tmpdir'] . '/dokuwiki-upgrade.tgz'; 404e3e87e4SAndreas Gohr $this->tgzdir = $conf['tmpdir'] . '/dokuwiki-upgrade/'; 414e3e87e4SAndreas Gohr $this->tgzversion = "https://raw.githubusercontent.com/splitbrain/dokuwiki/$branch/VERSION"; 426741b585SAndreas Gohr $this->composer = "https://raw.githubusercontent.com/splitbrain/dokuwiki/$branch/composer.json"; 434e3e87e4SAndreas Gohr $this->pluginversion = "https://raw.githubusercontent.com/splitbrain/dokuwiki-plugin-upgrade/master/plugin.info.txt"; 444e3e87e4SAndreas Gohr } 454e3e87e4SAndreas Gohr 464e3e87e4SAndreas Gohr /** 474e3e87e4SAndreas Gohr * @param admin_plugin_upgrade|cli_plugin_upgrade $logger Logger object 484e3e87e4SAndreas Gohr * @return void 494e3e87e4SAndreas Gohr */ 504e3e87e4SAndreas Gohr public function setLogger($logger) 514e3e87e4SAndreas Gohr { 524e3e87e4SAndreas Gohr $this->logger = $logger; 534e3e87e4SAndreas Gohr } 544e3e87e4SAndreas Gohr 554e3e87e4SAndreas Gohr // region Steps 564e3e87e4SAndreas Gohr 574e3e87e4SAndreas Gohr /** 584e3e87e4SAndreas Gohr * Check various versions 594e3e87e4SAndreas Gohr * 604e3e87e4SAndreas Gohr * @return bool 614e3e87e4SAndreas Gohr */ 624e3e87e4SAndreas Gohr public function checkVersions() 634e3e87e4SAndreas Gohr { 644e3e87e4SAndreas Gohr $ok = true; 654e3e87e4SAndreas Gohr 664e3e87e4SAndreas Gohr // we need SSL - only newer HTTPClients check that themselves 674e3e87e4SAndreas Gohr if (!in_array('ssl', stream_get_transports())) { 684e3e87e4SAndreas Gohr $this->log('error', $this->getLang('vs_ssl')); 694e3e87e4SAndreas Gohr $ok = false; 704e3e87e4SAndreas Gohr } 714e3e87e4SAndreas Gohr 724e3e87e4SAndreas Gohr // get the available version 734e3e87e4SAndreas Gohr $http = new DokuHTTPClient(); 744e3e87e4SAndreas Gohr $tgzversion = trim($http->get($this->tgzversion)); 754e3e87e4SAndreas Gohr if (!$tgzversion) { 764e3e87e4SAndreas Gohr $this->log('error', $this->getLang('vs_tgzno') . ' ' . hsc($http->error)); 774e3e87e4SAndreas Gohr $ok = false; 784e3e87e4SAndreas Gohr } 794e3e87e4SAndreas Gohr $tgzversionnum = $this->dateFromVersion($tgzversion); 804e3e87e4SAndreas Gohr if ($tgzversionnum === 0) { 814e3e87e4SAndreas Gohr $this->log('error', $this->getLang('vs_tgzno')); 824e3e87e4SAndreas Gohr $ok = false; 834e3e87e4SAndreas Gohr } else { 844e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('vs_tgz'), $tgzversion); 854e3e87e4SAndreas Gohr } 864e3e87e4SAndreas Gohr 874e3e87e4SAndreas Gohr // get the current version 884e3e87e4SAndreas Gohr $versiondata = getVersionData(); 894e3e87e4SAndreas Gohr $version = trim($versiondata['date']); 904e3e87e4SAndreas Gohr $versionnum = $this->dateFromVersion($version); 914e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('vs_local'), $version); 924e3e87e4SAndreas Gohr 934e3e87e4SAndreas Gohr // compare versions 944e3e87e4SAndreas Gohr if (!$versionnum) { 954e3e87e4SAndreas Gohr $this->log('warning', $this->getLang('vs_localno')); 964e3e87e4SAndreas Gohr $ok = false; 974e3e87e4SAndreas Gohr } elseif ($tgzversionnum) { 984e3e87e4SAndreas Gohr if ($tgzversionnum < $versionnum) { 994e3e87e4SAndreas Gohr $this->log('warning', $this->getLang('vs_newer')); 1004e3e87e4SAndreas Gohr $ok = false; 1014e3e87e4SAndreas Gohr } elseif ($tgzversionnum == $versionnum && $tgzversion == $version) { 1024e3e87e4SAndreas Gohr $this->log('warning', $this->getLang('vs_same')); 1034e3e87e4SAndreas Gohr $ok = false; 1044e3e87e4SAndreas Gohr } 1054e3e87e4SAndreas Gohr } 1064e3e87e4SAndreas Gohr 1074e3e87e4SAndreas Gohr // check plugin version 1084e3e87e4SAndreas Gohr $pluginversion = $http->get($this->pluginversion); 1094e3e87e4SAndreas Gohr if ($pluginversion) { 1104e3e87e4SAndreas Gohr $plugininfo = linesToHash(explode("\n", $pluginversion)); 1114e3e87e4SAndreas Gohr $myinfo = $this->getInfo(); 1124e3e87e4SAndreas Gohr if ($plugininfo['date'] > $myinfo['date']) { 1134e3e87e4SAndreas Gohr $this->log('warning', $this->getLang('vs_plugin'), $plugininfo['date']); 1144e3e87e4SAndreas Gohr $ok = false; 1154e3e87e4SAndreas Gohr } 1164e3e87e4SAndreas Gohr } 1174e3e87e4SAndreas Gohr 1184e3e87e4SAndreas Gohr // check if PHP is up to date 1196741b585SAndreas Gohr $json = $http->get($this->composer); 1206741b585SAndreas Gohr $data = json_decode($json, true); 1216741b585SAndreas Gohr $minphp = $data['config']['platform']['php']; 1224e3e87e4SAndreas Gohr if (version_compare(phpversion(), $minphp, '<')) { 1234e3e87e4SAndreas Gohr $this->log('error', $this->getLang('vs_php'), $minphp, phpversion()); 1244e3e87e4SAndreas Gohr $ok = false; 1254e3e87e4SAndreas Gohr } 1264e3e87e4SAndreas Gohr 1274e3e87e4SAndreas Gohr return $ok; 1284e3e87e4SAndreas Gohr } 1294e3e87e4SAndreas Gohr 1304e3e87e4SAndreas Gohr /** 1314e3e87e4SAndreas Gohr * Download the tarball 1324e3e87e4SAndreas Gohr * 1334e3e87e4SAndreas Gohr * @return bool 1344e3e87e4SAndreas Gohr */ 1354e3e87e4SAndreas Gohr public function downloadTarball() 1364e3e87e4SAndreas Gohr { 1374e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('dl_from'), $this->tgzurl); 1384e3e87e4SAndreas Gohr 1394e3e87e4SAndreas Gohr @set_time_limit(300); 1404e3e87e4SAndreas Gohr @ignore_user_abort(); 1414e3e87e4SAndreas Gohr 1424e3e87e4SAndreas Gohr $http = new DokuHTTPClient(); 1434e3e87e4SAndreas Gohr $http->timeout = 300; 1444e3e87e4SAndreas Gohr $data = $http->get($this->tgzurl); 1454e3e87e4SAndreas Gohr 1464e3e87e4SAndreas Gohr if (!$data) { 1474e3e87e4SAndreas Gohr $this->log('error', $http->error); 1484e3e87e4SAndreas Gohr $this->log('error', $this->getLang('dl_fail')); 1494e3e87e4SAndreas Gohr return false; 1504e3e87e4SAndreas Gohr } 1514e3e87e4SAndreas Gohr 152fc9fd1daSAndreas Gohr io_mkdir_p(dirname($this->tgzfile)); 153fc9fd1daSAndreas Gohr if (!file_put_contents($this->tgzfile, $data)) { 1544e3e87e4SAndreas Gohr $this->log('error', $this->getLang('dl_fail')); 1554e3e87e4SAndreas Gohr return false; 1564e3e87e4SAndreas Gohr } 1574e3e87e4SAndreas Gohr 1584e3e87e4SAndreas Gohr $this->log('success', $this->getLang('dl_done'), filesize_h(strlen($data))); 1594e3e87e4SAndreas Gohr return true; 1604e3e87e4SAndreas Gohr } 1614e3e87e4SAndreas Gohr 1624e3e87e4SAndreas Gohr /** 1634e3e87e4SAndreas Gohr * Unpack the tarball 1644e3e87e4SAndreas Gohr * 1654e3e87e4SAndreas Gohr * @return bool 1664e3e87e4SAndreas Gohr */ 1674e3e87e4SAndreas Gohr public function extractTarball() 1684e3e87e4SAndreas Gohr { 1694e3e87e4SAndreas Gohr $this->log('notice', '<b>' . $this->getLang('pk_extract') . '</b>'); 1704e3e87e4SAndreas Gohr 1714e3e87e4SAndreas Gohr @set_time_limit(300); 1724e3e87e4SAndreas Gohr @ignore_user_abort(); 1734e3e87e4SAndreas Gohr 1744e3e87e4SAndreas Gohr try { 1754e3e87e4SAndreas Gohr $tar = new Tar(); 1764e3e87e4SAndreas Gohr $tar->setCallback(function ($file) { 1774e3e87e4SAndreas Gohr /** @var FileInfo $file */ 1784e3e87e4SAndreas Gohr $this->log('info', $file->getPath()); 1794e3e87e4SAndreas Gohr }); 1804e3e87e4SAndreas Gohr $tar->open($this->tgzfile); 1814e3e87e4SAndreas Gohr $tar->extract($this->tgzdir, 1); 1824e3e87e4SAndreas Gohr $tar->close(); 1834e3e87e4SAndreas Gohr } catch (Exception $e) { 1844e3e87e4SAndreas Gohr $this->log('error', $e->getMessage()); 1854e3e87e4SAndreas Gohr $this->log('error', $this->getLang('pk_fail')); 1864e3e87e4SAndreas Gohr return false; 1874e3e87e4SAndreas Gohr } 1884e3e87e4SAndreas Gohr 1894e3e87e4SAndreas Gohr $this->log('success', $this->getLang('pk_done')); 1904e3e87e4SAndreas Gohr 1914e3e87e4SAndreas Gohr $this->log( 1924e3e87e4SAndreas Gohr 'notice', 1934e3e87e4SAndreas Gohr $this->getLang('pk_version'), 1944e3e87e4SAndreas Gohr hsc(file_get_contents($this->tgzdir . '/VERSION')), 1954e3e87e4SAndreas Gohr getVersion() 1964e3e87e4SAndreas Gohr ); 1974e3e87e4SAndreas Gohr return true; 1984e3e87e4SAndreas Gohr } 1994e3e87e4SAndreas Gohr 2004e3e87e4SAndreas Gohr /** 2014e3e87e4SAndreas Gohr * Check permissions of files to change 2024e3e87e4SAndreas Gohr * 2034e3e87e4SAndreas Gohr * @return bool 2044e3e87e4SAndreas Gohr */ 2054e3e87e4SAndreas Gohr public function checkPermissions() 2064e3e87e4SAndreas Gohr { 2074e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('ck_start')); 2084e3e87e4SAndreas Gohr $ok = $this->traverseCheckAndCopy('', true); 2094e3e87e4SAndreas Gohr if ($ok) { 2104e3e87e4SAndreas Gohr $this->log('success', '<b>' . $this->getLang('ck_done') . '</b>'); 2114e3e87e4SAndreas Gohr } else { 2124e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('ck_fail') . '</b>'); 2134e3e87e4SAndreas Gohr } 2144e3e87e4SAndreas Gohr return $ok; 2154e3e87e4SAndreas Gohr } 2164e3e87e4SAndreas Gohr 2174e3e87e4SAndreas Gohr /** 2184e3e87e4SAndreas Gohr * Copy over new files 2194e3e87e4SAndreas Gohr * 2204e3e87e4SAndreas Gohr * @return bool 2214e3e87e4SAndreas Gohr */ 2224e3e87e4SAndreas Gohr public function copyFiles() 2234e3e87e4SAndreas Gohr { 2244e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('cp_start')); 2254e3e87e4SAndreas Gohr $ok = $this->traverseCheckAndCopy('', false); 2264e3e87e4SAndreas Gohr if ($ok) { 2274e3e87e4SAndreas Gohr $this->log('success', '<b>' . $this->getLang('cp_done') . '</b>'); 2284e3e87e4SAndreas Gohr } else { 2294e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('cp_fail') . '</b>'); 2304e3e87e4SAndreas Gohr } 2314e3e87e4SAndreas Gohr return $ok; 2324e3e87e4SAndreas Gohr } 2334e3e87e4SAndreas Gohr 2344e3e87e4SAndreas Gohr /** 2354e3e87e4SAndreas Gohr * Delete outdated files 2364e3e87e4SAndreas Gohr */ 2374e3e87e4SAndreas Gohr public function deleteObsoleteFiles() 2384e3e87e4SAndreas Gohr { 2394e3e87e4SAndreas Gohr global $conf; 2404e3e87e4SAndreas Gohr 2414e3e87e4SAndreas Gohr $list = file($this->tgzdir . 'data/deleted.files'); 2424e3e87e4SAndreas Gohr foreach ($list as $line) { 2434e3e87e4SAndreas Gohr $line = trim(preg_replace('/#.*$/', '', $line)); 2444e3e87e4SAndreas Gohr if (!$line) continue; 2454e3e87e4SAndreas Gohr $file = DOKU_INC . $line; 2464e3e87e4SAndreas Gohr if (!file_exists($file)) continue; 2474e3e87e4SAndreas Gohr 2484e3e87e4SAndreas Gohr // check that the given file is a case sensitive match 2494e3e87e4SAndreas Gohr if (basename(realpath($file)) != basename($file)) { 2504e3e87e4SAndreas Gohr $this->log('info', $this->getLang('rm_mismatch'), hsc($line)); 2514e3e87e4SAndreas Gohr continue; 2524e3e87e4SAndreas Gohr } 2534e3e87e4SAndreas Gohr 254*8dab6045SAndreas Gohr if ( 255*8dab6045SAndreas Gohr (is_dir($file) && $this->recursiveDelete($file)) || 2564e3e87e4SAndreas Gohr @unlink($file) 2574e3e87e4SAndreas Gohr ) { 2584e3e87e4SAndreas Gohr $this->log('info', $this->getLang('rm_done'), hsc($line)); 2594e3e87e4SAndreas Gohr } else { 2604e3e87e4SAndreas Gohr $this->log('error', $this->getLang('rm_fail'), hsc($line)); 2614e3e87e4SAndreas Gohr } 2624e3e87e4SAndreas Gohr } 2634e3e87e4SAndreas Gohr // delete install 2644e3e87e4SAndreas Gohr @unlink(DOKU_INC . 'install.php'); 2654e3e87e4SAndreas Gohr 2664e3e87e4SAndreas Gohr // make sure update message will be gone 2674e3e87e4SAndreas Gohr @touch(DOKU_INC . 'doku.php'); 2684e3e87e4SAndreas Gohr @unlink($conf['cachedir'] . '/messages.txt'); 2694e3e87e4SAndreas Gohr 2704e3e87e4SAndreas Gohr // clear opcache 2714e3e87e4SAndreas Gohr if (function_exists('opcache_reset')) { 2724e3e87e4SAndreas Gohr opcache_reset(); 2734e3e87e4SAndreas Gohr } 2744e3e87e4SAndreas Gohr 2754e3e87e4SAndreas Gohr $this->log('success', '<b>' . $this->getLang('finish') . '</b>'); 2764e3e87e4SAndreas Gohr return true; 2774e3e87e4SAndreas Gohr } 2784e3e87e4SAndreas Gohr 2794e3e87e4SAndreas Gohr /** 2804e3e87e4SAndreas Gohr * Remove the downloaded and extracted files 2814e3e87e4SAndreas Gohr * 2824e3e87e4SAndreas Gohr * @return bool 2834e3e87e4SAndreas Gohr */ 2844e3e87e4SAndreas Gohr public function cleanUp() 2854e3e87e4SAndreas Gohr { 2864e3e87e4SAndreas Gohr @unlink($this->tgzfile); 2874e3e87e4SAndreas Gohr $this->recursiveDelete($this->tgzdir); 2884e3e87e4SAndreas Gohr return true; 2894e3e87e4SAndreas Gohr } 2904e3e87e4SAndreas Gohr 2914e3e87e4SAndreas Gohr // endregion 2924e3e87e4SAndreas Gohr 2934e3e87e4SAndreas Gohr /** 2944e3e87e4SAndreas Gohr * Traverse over the given dir and compare it to the DokuWiki dir 2954e3e87e4SAndreas Gohr * 2964e3e87e4SAndreas Gohr * Checks what files need an update, tests for writability and copies 2974e3e87e4SAndreas Gohr * 2984e3e87e4SAndreas Gohr * @param string $dir 2994e3e87e4SAndreas Gohr * @param bool $dryrun do not copy but only check permissions 3004e3e87e4SAndreas Gohr * @return bool 3014e3e87e4SAndreas Gohr */ 3024e3e87e4SAndreas Gohr private function traverseCheckAndCopy($dir, $dryrun) 3034e3e87e4SAndreas Gohr { 3044e3e87e4SAndreas Gohr $base = $this->tgzdir; 3054e3e87e4SAndreas Gohr $ok = true; 3064e3e87e4SAndreas Gohr 3074e3e87e4SAndreas Gohr $dh = @opendir($base . '/' . $dir); 3084e3e87e4SAndreas Gohr if (!$dh) return false; 3094e3e87e4SAndreas Gohr while (($file = readdir($dh)) !== false) { 3104e3e87e4SAndreas Gohr if ($file == '.' || $file == '..') continue; 3114e3e87e4SAndreas Gohr $from = "$base/$dir/$file"; 3124e3e87e4SAndreas Gohr $to = DOKU_INC . "$dir/$file"; 3134e3e87e4SAndreas Gohr 3144e3e87e4SAndreas Gohr if (is_dir($from)) { 3154e3e87e4SAndreas Gohr if ($dryrun) { 3164e3e87e4SAndreas Gohr // just check for writability 3174e3e87e4SAndreas Gohr if (!is_dir($to)) { 3184e3e87e4SAndreas Gohr if (is_dir(dirname($to)) && !is_writable(dirname($to))) { 3194e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_noperm') . '</b>', hsc("$dir/$file")); 3204e3e87e4SAndreas Gohr $ok = false; 3214e3e87e4SAndreas Gohr } 3224e3e87e4SAndreas Gohr } 3234e3e87e4SAndreas Gohr } 3244e3e87e4SAndreas Gohr 3254e3e87e4SAndreas Gohr // recursion 3264e3e87e4SAndreas Gohr if (!$this->traverseCheckAndCopy("$dir/$file", $dryrun)) { 3274e3e87e4SAndreas Gohr $ok = false; 3284e3e87e4SAndreas Gohr } 3294e3e87e4SAndreas Gohr } else { 3304e3e87e4SAndreas Gohr $fmd5 = md5(@file_get_contents($from)); 3314e3e87e4SAndreas Gohr $tmd5 = md5(@file_get_contents($to)); 3324e3e87e4SAndreas Gohr if ($fmd5 != $tmd5 || !file_exists($to)) { 3334e3e87e4SAndreas Gohr if ($dryrun) { 3344e3e87e4SAndreas Gohr // just check for writability 335*8dab6045SAndreas Gohr if ( 336*8dab6045SAndreas Gohr (file_exists($to) && !is_writable($to)) || 3374e3e87e4SAndreas Gohr (!file_exists($to) && is_dir(dirname($to)) && !is_writable(dirname($to))) 3384e3e87e4SAndreas Gohr ) { 3394e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_noperm') . '</b>', hsc("$dir/$file")); 3404e3e87e4SAndreas Gohr $ok = false; 3414e3e87e4SAndreas Gohr } else { 3424e3e87e4SAndreas Gohr $this->log('info', $this->getLang('tv_upd'), hsc("$dir/$file")); 3434e3e87e4SAndreas Gohr } 3444e3e87e4SAndreas Gohr } else { 3454e3e87e4SAndreas Gohr // check dir 3464e3e87e4SAndreas Gohr if (io_mkdir_p(dirname($to))) { 3474e3e87e4SAndreas Gohr // remove existing (avoid case sensitivity problems) 3484e3e87e4SAndreas Gohr if (file_exists($to) && !@unlink($to)) { 3494e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_nodel') . '</b>', hsc("$dir/$file")); 3504e3e87e4SAndreas Gohr $ok = false; 3514e3e87e4SAndreas Gohr } 3524e3e87e4SAndreas Gohr // copy 3534e3e87e4SAndreas Gohr if (!copy($from, $to)) { 3544e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_nocopy') . '</b>', hsc("$dir/$file")); 3554e3e87e4SAndreas Gohr $ok = false; 3564e3e87e4SAndreas Gohr } else { 3574e3e87e4SAndreas Gohr $this->log('info', $this->getLang('tv_done'), hsc("$dir/$file")); 3584e3e87e4SAndreas Gohr } 3594e3e87e4SAndreas Gohr } else { 3604e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_nodir') . '</b>', hsc("$dir")); 3614e3e87e4SAndreas Gohr $ok = false; 3624e3e87e4SAndreas Gohr } 3634e3e87e4SAndreas Gohr } 3644e3e87e4SAndreas Gohr } 3654e3e87e4SAndreas Gohr } 3664e3e87e4SAndreas Gohr } 3674e3e87e4SAndreas Gohr closedir($dh); 3684e3e87e4SAndreas Gohr return $ok; 3694e3e87e4SAndreas Gohr } 3704e3e87e4SAndreas Gohr 3714e3e87e4SAndreas Gohr // region utilities 3724e3e87e4SAndreas Gohr 3734e3e87e4SAndreas Gohr /** 3744e3e87e4SAndreas Gohr * Figure out the release date from the version string 3754e3e87e4SAndreas Gohr * 3764e3e87e4SAndreas Gohr * @param $version 3774e3e87e4SAndreas Gohr * @return int|string returns 0 if the version can't be read 3784e3e87e4SAndreas Gohr */ 3794e3e87e4SAndreas Gohr protected function dateFromVersion($version) 3804e3e87e4SAndreas Gohr { 3814e3e87e4SAndreas Gohr if (preg_match('/(^|\D)(\d\d\d\d-\d\d-\d\d)(\D|$)/i', $version, $m)) { 3824e3e87e4SAndreas Gohr return $m[2]; 3834e3e87e4SAndreas Gohr } 3844e3e87e4SAndreas Gohr return 0; 3854e3e87e4SAndreas Gohr } 3864e3e87e4SAndreas Gohr 3874e3e87e4SAndreas Gohr /** 3884e3e87e4SAndreas Gohr * Recursive delete 3894e3e87e4SAndreas Gohr * 3904e3e87e4SAndreas Gohr * @author Jon Hassall 3914e3e87e4SAndreas Gohr * @link http://de.php.net/manual/en/function.unlink.php#87045 3924e3e87e4SAndreas Gohr */ 3934e3e87e4SAndreas Gohr protected function recursiveDelete($dir) 3944e3e87e4SAndreas Gohr { 3954e3e87e4SAndreas Gohr if (!$dh = @opendir($dir)) { 3964e3e87e4SAndreas Gohr return false; 3974e3e87e4SAndreas Gohr } 3984e3e87e4SAndreas Gohr while (false !== ($obj = readdir($dh))) { 3994e3e87e4SAndreas Gohr if ($obj == '.' || $obj == '..') continue; 4004e3e87e4SAndreas Gohr 4014e3e87e4SAndreas Gohr if (!@unlink($dir . '/' . $obj)) { 4024e3e87e4SAndreas Gohr $this->recursiveDelete($dir . '/' . $obj); 4034e3e87e4SAndreas Gohr } 4044e3e87e4SAndreas Gohr } 4054e3e87e4SAndreas Gohr closedir($dh); 4064e3e87e4SAndreas Gohr return @rmdir($dir); 4074e3e87e4SAndreas Gohr } 4084e3e87e4SAndreas Gohr 4094e3e87e4SAndreas Gohr /** 4104e3e87e4SAndreas Gohr * Log a message 4114e3e87e4SAndreas Gohr * 4124e3e87e4SAndreas Gohr * @param string ...$level , $msg 4134e3e87e4SAndreas Gohr */ 4144e3e87e4SAndreas Gohr protected function log() 4154e3e87e4SAndreas Gohr { 4164e3e87e4SAndreas Gohr $args = func_get_args(); 4174e3e87e4SAndreas Gohr $level = array_shift($args); 4184e3e87e4SAndreas Gohr $msg = array_shift($args); 4194e3e87e4SAndreas Gohr $msg = vsprintf($msg, $args); 4204e3e87e4SAndreas Gohr if ($this->logger) $this->logger->log($level, $msg); 4214e3e87e4SAndreas Gohr } 4224e3e87e4SAndreas Gohr 4234e3e87e4SAndreas Gohr // endregion 4244e3e87e4SAndreas Gohr} 425