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