1*4e3e87e4SAndreas Gohr<?php 2*4e3e87e4SAndreas Gohr/** 3*4e3e87e4SAndreas Gohr * DokuWiki Plugin upgrade (Helper Component) 4*4e3e87e4SAndreas Gohr * 5*4e3e87e4SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6*4e3e87e4SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 7*4e3e87e4SAndreas Gohr */ 8*4e3e87e4SAndreas Gohr 9*4e3e87e4SAndreas Gohruse dokuwiki\plugin\upgrade\HTTP\DokuHTTPClient; 10*4e3e87e4SAndreas Gohruse splitbrain\PHPArchive\FileInfo; 11*4e3e87e4SAndreas Gohruse splitbrain\PHPArchive\Tar; 12*4e3e87e4SAndreas Gohr 13*4e3e87e4SAndreas Gohrclass helper_plugin_upgrade extends DokuWiki_Plugin 14*4e3e87e4SAndreas Gohr{ 15*4e3e87e4SAndreas Gohr /** @var string download URL for the new DokuWiki release */ 16*4e3e87e4SAndreas Gohr public $tgzurl; 17*4e3e87e4SAndreas Gohr /** @var string full path to where the file will be downloaded to */ 18*4e3e87e4SAndreas Gohr public $tgzfile; 19*4e3e87e4SAndreas Gohr /** @var string full path to where the file will be extracted to */ 20*4e3e87e4SAndreas Gohr public $tgzdir; 21*4e3e87e4SAndreas Gohr /** @var string URL to the VERSION file of the new DokuWiki release */ 22*4e3e87e4SAndreas Gohr public $tgzversion; 23*4e3e87e4SAndreas Gohr /** @var string URL to the plugin.info.txt file of the upgrade plugin */ 24*4e3e87e4SAndreas Gohr public $pluginversion; 25*4e3e87e4SAndreas Gohr 26*4e3e87e4SAndreas Gohr /** @var admin_plugin_upgrade|cli_plugin_upgrade */ 27*4e3e87e4SAndreas Gohr protected $logger; 28*4e3e87e4SAndreas Gohr 29*4e3e87e4SAndreas Gohr public function __construct() 30*4e3e87e4SAndreas Gohr { 31*4e3e87e4SAndreas Gohr global $conf; 32*4e3e87e4SAndreas Gohr 33*4e3e87e4SAndreas Gohr $branch = 'stable'; 34*4e3e87e4SAndreas Gohr 35*4e3e87e4SAndreas Gohr $this->tgzurl = "https://github.com/splitbrain/dokuwiki/archive/$branch.tar.gz"; 36*4e3e87e4SAndreas Gohr $this->tgzfile = $conf['tmpdir'] . '/dokuwiki-upgrade.tgz'; 37*4e3e87e4SAndreas Gohr $this->tgzdir = $conf['tmpdir'] . '/dokuwiki-upgrade/'; 38*4e3e87e4SAndreas Gohr $this->tgzversion = "https://raw.githubusercontent.com/splitbrain/dokuwiki/$branch/VERSION"; 39*4e3e87e4SAndreas Gohr $this->pluginversion = "https://raw.githubusercontent.com/splitbrain/dokuwiki-plugin-upgrade/master/plugin.info.txt"; 40*4e3e87e4SAndreas Gohr } 41*4e3e87e4SAndreas Gohr 42*4e3e87e4SAndreas Gohr /** 43*4e3e87e4SAndreas Gohr * @param admin_plugin_upgrade|cli_plugin_upgrade $logger Logger object 44*4e3e87e4SAndreas Gohr * @return void 45*4e3e87e4SAndreas Gohr */ 46*4e3e87e4SAndreas Gohr public function setLogger($logger) 47*4e3e87e4SAndreas Gohr { 48*4e3e87e4SAndreas Gohr $this->logger = $logger; 49*4e3e87e4SAndreas Gohr } 50*4e3e87e4SAndreas Gohr 51*4e3e87e4SAndreas Gohr // region Steps 52*4e3e87e4SAndreas Gohr 53*4e3e87e4SAndreas Gohr /** 54*4e3e87e4SAndreas Gohr * Check various versions 55*4e3e87e4SAndreas Gohr * 56*4e3e87e4SAndreas Gohr * @return bool 57*4e3e87e4SAndreas Gohr */ 58*4e3e87e4SAndreas Gohr public function checkVersions() 59*4e3e87e4SAndreas Gohr { 60*4e3e87e4SAndreas Gohr $ok = true; 61*4e3e87e4SAndreas Gohr 62*4e3e87e4SAndreas Gohr // we need SSL - only newer HTTPClients check that themselves 63*4e3e87e4SAndreas Gohr if (!in_array('ssl', stream_get_transports())) { 64*4e3e87e4SAndreas Gohr $this->log('error', $this->getLang('vs_ssl')); 65*4e3e87e4SAndreas Gohr $ok = false; 66*4e3e87e4SAndreas Gohr } 67*4e3e87e4SAndreas Gohr 68*4e3e87e4SAndreas Gohr // get the available version 69*4e3e87e4SAndreas Gohr $http = new DokuHTTPClient(); 70*4e3e87e4SAndreas Gohr $tgzversion = trim($http->get($this->tgzversion)); 71*4e3e87e4SAndreas Gohr if (!$tgzversion) { 72*4e3e87e4SAndreas Gohr $this->log('error', $this->getLang('vs_tgzno') . ' ' . hsc($http->error)); 73*4e3e87e4SAndreas Gohr $ok = false; 74*4e3e87e4SAndreas Gohr } 75*4e3e87e4SAndreas Gohr $tgzversionnum = $this->dateFromVersion($tgzversion); 76*4e3e87e4SAndreas Gohr if ($tgzversionnum === 0) { 77*4e3e87e4SAndreas Gohr $this->log('error', $this->getLang('vs_tgzno')); 78*4e3e87e4SAndreas Gohr $ok = false; 79*4e3e87e4SAndreas Gohr } else { 80*4e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('vs_tgz'), $tgzversion); 81*4e3e87e4SAndreas Gohr } 82*4e3e87e4SAndreas Gohr 83*4e3e87e4SAndreas Gohr // get the current version 84*4e3e87e4SAndreas Gohr $versiondata = getVersionData(); 85*4e3e87e4SAndreas Gohr $version = trim($versiondata['date']); 86*4e3e87e4SAndreas Gohr $versionnum = $this->dateFromVersion($version); 87*4e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('vs_local'), $version); 88*4e3e87e4SAndreas Gohr 89*4e3e87e4SAndreas Gohr // compare versions 90*4e3e87e4SAndreas Gohr if (!$versionnum) { 91*4e3e87e4SAndreas Gohr $this->log('warning', $this->getLang('vs_localno')); 92*4e3e87e4SAndreas Gohr $ok = false; 93*4e3e87e4SAndreas Gohr } else if ($tgzversionnum) { 94*4e3e87e4SAndreas Gohr if ($tgzversionnum < $versionnum) { 95*4e3e87e4SAndreas Gohr $this->log('warning', $this->getLang('vs_newer')); 96*4e3e87e4SAndreas Gohr $ok = false; 97*4e3e87e4SAndreas Gohr } elseif ($tgzversionnum == $versionnum && $tgzversion == $version) { 98*4e3e87e4SAndreas Gohr $this->log('warning', $this->getLang('vs_same')); 99*4e3e87e4SAndreas Gohr $ok = false; 100*4e3e87e4SAndreas Gohr } 101*4e3e87e4SAndreas Gohr } 102*4e3e87e4SAndreas Gohr 103*4e3e87e4SAndreas Gohr // check plugin version 104*4e3e87e4SAndreas Gohr $pluginversion = $http->get($this->pluginversion); 105*4e3e87e4SAndreas Gohr if ($pluginversion) { 106*4e3e87e4SAndreas Gohr $plugininfo = linesToHash(explode("\n", $pluginversion)); 107*4e3e87e4SAndreas Gohr $myinfo = $this->getInfo(); 108*4e3e87e4SAndreas Gohr if ($plugininfo['date'] > $myinfo['date']) { 109*4e3e87e4SAndreas Gohr $this->log('warning', $this->getLang('vs_plugin'), $plugininfo['date']); 110*4e3e87e4SAndreas Gohr $ok = false; 111*4e3e87e4SAndreas Gohr } 112*4e3e87e4SAndreas Gohr } 113*4e3e87e4SAndreas Gohr 114*4e3e87e4SAndreas Gohr // check if PHP is up to date 115*4e3e87e4SAndreas Gohr $minphp = '7.2'; // FIXME get this from the composer file upstream 116*4e3e87e4SAndreas Gohr if (version_compare(phpversion(), $minphp, '<')) { 117*4e3e87e4SAndreas Gohr $this->log('error', $this->getLang('vs_php'), $minphp, phpversion()); 118*4e3e87e4SAndreas Gohr $ok = false; 119*4e3e87e4SAndreas Gohr } 120*4e3e87e4SAndreas Gohr 121*4e3e87e4SAndreas Gohr return $ok; 122*4e3e87e4SAndreas Gohr } 123*4e3e87e4SAndreas Gohr 124*4e3e87e4SAndreas Gohr /** 125*4e3e87e4SAndreas Gohr * Download the tarball 126*4e3e87e4SAndreas Gohr * 127*4e3e87e4SAndreas Gohr * @return bool 128*4e3e87e4SAndreas Gohr */ 129*4e3e87e4SAndreas Gohr public function downloadTarball() 130*4e3e87e4SAndreas Gohr { 131*4e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('dl_from'), $this->tgzurl); 132*4e3e87e4SAndreas Gohr 133*4e3e87e4SAndreas Gohr @set_time_limit(300); 134*4e3e87e4SAndreas Gohr @ignore_user_abort(); 135*4e3e87e4SAndreas Gohr 136*4e3e87e4SAndreas Gohr $http = new DokuHTTPClient(); 137*4e3e87e4SAndreas Gohr $http->timeout = 300; 138*4e3e87e4SAndreas Gohr $data = $http->get($this->tgzurl); 139*4e3e87e4SAndreas Gohr 140*4e3e87e4SAndreas Gohr if (!$data) { 141*4e3e87e4SAndreas Gohr $this->log('error', $http->error); 142*4e3e87e4SAndreas Gohr $this->log('error', $this->getLang('dl_fail')); 143*4e3e87e4SAndreas Gohr return false; 144*4e3e87e4SAndreas Gohr } 145*4e3e87e4SAndreas Gohr 146*4e3e87e4SAndreas Gohr if (!io_saveFile($this->tgzfile, $data)) { 147*4e3e87e4SAndreas Gohr $this->log('error', $this->getLang('dl_fail')); 148*4e3e87e4SAndreas Gohr return false; 149*4e3e87e4SAndreas Gohr } 150*4e3e87e4SAndreas Gohr 151*4e3e87e4SAndreas Gohr $this->log('success', $this->getLang('dl_done'), filesize_h(strlen($data))); 152*4e3e87e4SAndreas Gohr return true; 153*4e3e87e4SAndreas Gohr } 154*4e3e87e4SAndreas Gohr 155*4e3e87e4SAndreas Gohr /** 156*4e3e87e4SAndreas Gohr * Unpack the tarball 157*4e3e87e4SAndreas Gohr * 158*4e3e87e4SAndreas Gohr * @return bool 159*4e3e87e4SAndreas Gohr */ 160*4e3e87e4SAndreas Gohr public function extractTarball() 161*4e3e87e4SAndreas Gohr { 162*4e3e87e4SAndreas Gohr $this->log('notice', '<b>' . $this->getLang('pk_extract') . '</b>'); 163*4e3e87e4SAndreas Gohr 164*4e3e87e4SAndreas Gohr @set_time_limit(300); 165*4e3e87e4SAndreas Gohr @ignore_user_abort(); 166*4e3e87e4SAndreas Gohr 167*4e3e87e4SAndreas Gohr try { 168*4e3e87e4SAndreas Gohr $tar = new Tar(); 169*4e3e87e4SAndreas Gohr $tar->setCallback(function ($file) { 170*4e3e87e4SAndreas Gohr /** @var FileInfo $file */ 171*4e3e87e4SAndreas Gohr $this->log('info', $file->getPath()); 172*4e3e87e4SAndreas Gohr }); 173*4e3e87e4SAndreas Gohr $tar->open($this->tgzfile); 174*4e3e87e4SAndreas Gohr $tar->extract($this->tgzdir, 1); 175*4e3e87e4SAndreas Gohr $tar->close(); 176*4e3e87e4SAndreas Gohr } catch (Exception $e) { 177*4e3e87e4SAndreas Gohr $this->log('error', $e->getMessage()); 178*4e3e87e4SAndreas Gohr $this->log('error', $this->getLang('pk_fail')); 179*4e3e87e4SAndreas Gohr return false; 180*4e3e87e4SAndreas Gohr } 181*4e3e87e4SAndreas Gohr 182*4e3e87e4SAndreas Gohr $this->log('success', $this->getLang('pk_done')); 183*4e3e87e4SAndreas Gohr 184*4e3e87e4SAndreas Gohr $this->log( 185*4e3e87e4SAndreas Gohr 'notice', 186*4e3e87e4SAndreas Gohr $this->getLang('pk_version'), 187*4e3e87e4SAndreas Gohr hsc(file_get_contents($this->tgzdir . '/VERSION')), 188*4e3e87e4SAndreas Gohr getVersion() 189*4e3e87e4SAndreas Gohr ); 190*4e3e87e4SAndreas Gohr return true; 191*4e3e87e4SAndreas Gohr } 192*4e3e87e4SAndreas Gohr 193*4e3e87e4SAndreas Gohr /** 194*4e3e87e4SAndreas Gohr * Check permissions of files to change 195*4e3e87e4SAndreas Gohr * 196*4e3e87e4SAndreas Gohr * @return bool 197*4e3e87e4SAndreas Gohr */ 198*4e3e87e4SAndreas Gohr public function checkPermissions() 199*4e3e87e4SAndreas Gohr { 200*4e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('ck_start')); 201*4e3e87e4SAndreas Gohr $ok = $this->traverseCheckAndCopy('', true); 202*4e3e87e4SAndreas Gohr if ($ok) { 203*4e3e87e4SAndreas Gohr $this->log('success', '<b>' . $this->getLang('ck_done') . '</b>'); 204*4e3e87e4SAndreas Gohr } else { 205*4e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('ck_fail') . '</b>'); 206*4e3e87e4SAndreas Gohr } 207*4e3e87e4SAndreas Gohr return $ok; 208*4e3e87e4SAndreas Gohr } 209*4e3e87e4SAndreas Gohr 210*4e3e87e4SAndreas Gohr /** 211*4e3e87e4SAndreas Gohr * Copy over new files 212*4e3e87e4SAndreas Gohr * 213*4e3e87e4SAndreas Gohr * @return bool 214*4e3e87e4SAndreas Gohr */ 215*4e3e87e4SAndreas Gohr public function copyFiles() 216*4e3e87e4SAndreas Gohr { 217*4e3e87e4SAndreas Gohr $this->log('notice', $this->getLang('cp_start')); 218*4e3e87e4SAndreas Gohr $ok = $this->traverseCheckAndCopy('', false); 219*4e3e87e4SAndreas Gohr if ($ok) { 220*4e3e87e4SAndreas Gohr $this->log('success', '<b>' . $this->getLang('cp_done') . '</b>'); 221*4e3e87e4SAndreas Gohr } else { 222*4e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('cp_fail') . '</b>'); 223*4e3e87e4SAndreas Gohr } 224*4e3e87e4SAndreas Gohr return $ok; 225*4e3e87e4SAndreas Gohr } 226*4e3e87e4SAndreas Gohr 227*4e3e87e4SAndreas Gohr /** 228*4e3e87e4SAndreas Gohr * Delete outdated files 229*4e3e87e4SAndreas Gohr */ 230*4e3e87e4SAndreas Gohr public function deleteObsoleteFiles() 231*4e3e87e4SAndreas Gohr { 232*4e3e87e4SAndreas Gohr global $conf; 233*4e3e87e4SAndreas Gohr 234*4e3e87e4SAndreas Gohr $list = file($this->tgzdir . 'data/deleted.files'); 235*4e3e87e4SAndreas Gohr foreach ($list as $line) { 236*4e3e87e4SAndreas Gohr $line = trim(preg_replace('/#.*$/', '', $line)); 237*4e3e87e4SAndreas Gohr if (!$line) continue; 238*4e3e87e4SAndreas Gohr $file = DOKU_INC . $line; 239*4e3e87e4SAndreas Gohr if (!file_exists($file)) continue; 240*4e3e87e4SAndreas Gohr 241*4e3e87e4SAndreas Gohr // check that the given file is a case sensitive match 242*4e3e87e4SAndreas Gohr if (basename(realpath($file)) != basename($file)) { 243*4e3e87e4SAndreas Gohr $this->log('info', $this->getLang('rm_mismatch'), hsc($line)); 244*4e3e87e4SAndreas Gohr continue; 245*4e3e87e4SAndreas Gohr } 246*4e3e87e4SAndreas Gohr 247*4e3e87e4SAndreas Gohr if ((is_dir($file) && $this->recursiveDelete($file)) || 248*4e3e87e4SAndreas Gohr @unlink($file) 249*4e3e87e4SAndreas Gohr ) { 250*4e3e87e4SAndreas Gohr $this->log('info', $this->getLang('rm_done'), hsc($line)); 251*4e3e87e4SAndreas Gohr } else { 252*4e3e87e4SAndreas Gohr $this->log('error', $this->getLang('rm_fail'), hsc($line)); 253*4e3e87e4SAndreas Gohr } 254*4e3e87e4SAndreas Gohr } 255*4e3e87e4SAndreas Gohr // delete install 256*4e3e87e4SAndreas Gohr @unlink(DOKU_INC . 'install.php'); 257*4e3e87e4SAndreas Gohr 258*4e3e87e4SAndreas Gohr // make sure update message will be gone 259*4e3e87e4SAndreas Gohr @touch(DOKU_INC . 'doku.php'); 260*4e3e87e4SAndreas Gohr @unlink($conf['cachedir'] . '/messages.txt'); 261*4e3e87e4SAndreas Gohr 262*4e3e87e4SAndreas Gohr // clear opcache 263*4e3e87e4SAndreas Gohr if (function_exists('opcache_reset')) { 264*4e3e87e4SAndreas Gohr opcache_reset(); 265*4e3e87e4SAndreas Gohr } 266*4e3e87e4SAndreas Gohr 267*4e3e87e4SAndreas Gohr $this->log('success', '<b>' . $this->getLang('finish') . '</b>'); 268*4e3e87e4SAndreas Gohr return true; 269*4e3e87e4SAndreas Gohr } 270*4e3e87e4SAndreas Gohr 271*4e3e87e4SAndreas Gohr /** 272*4e3e87e4SAndreas Gohr * Remove the downloaded and extracted files 273*4e3e87e4SAndreas Gohr * 274*4e3e87e4SAndreas Gohr * @return bool 275*4e3e87e4SAndreas Gohr */ 276*4e3e87e4SAndreas Gohr public function cleanUp() 277*4e3e87e4SAndreas Gohr { 278*4e3e87e4SAndreas Gohr @unlink($this->tgzfile); 279*4e3e87e4SAndreas Gohr $this->recursiveDelete($this->tgzdir); 280*4e3e87e4SAndreas Gohr return true; 281*4e3e87e4SAndreas Gohr } 282*4e3e87e4SAndreas Gohr 283*4e3e87e4SAndreas Gohr // endregion 284*4e3e87e4SAndreas Gohr 285*4e3e87e4SAndreas Gohr /** 286*4e3e87e4SAndreas Gohr * Traverse over the given dir and compare it to the DokuWiki dir 287*4e3e87e4SAndreas Gohr * 288*4e3e87e4SAndreas Gohr * Checks what files need an update, tests for writability and copies 289*4e3e87e4SAndreas Gohr * 290*4e3e87e4SAndreas Gohr * @param string $dir 291*4e3e87e4SAndreas Gohr * @param bool $dryrun do not copy but only check permissions 292*4e3e87e4SAndreas Gohr * @return bool 293*4e3e87e4SAndreas Gohr */ 294*4e3e87e4SAndreas Gohr private function traverseCheckAndCopy($dir, $dryrun) 295*4e3e87e4SAndreas Gohr { 296*4e3e87e4SAndreas Gohr $base = $this->tgzdir; 297*4e3e87e4SAndreas Gohr $ok = true; 298*4e3e87e4SAndreas Gohr 299*4e3e87e4SAndreas Gohr $dh = @opendir($base . '/' . $dir); 300*4e3e87e4SAndreas Gohr if (!$dh) return false; 301*4e3e87e4SAndreas Gohr while (($file = readdir($dh)) !== false) { 302*4e3e87e4SAndreas Gohr if ($file == '.' || $file == '..') continue; 303*4e3e87e4SAndreas Gohr $from = "$base/$dir/$file"; 304*4e3e87e4SAndreas Gohr $to = DOKU_INC . "$dir/$file"; 305*4e3e87e4SAndreas Gohr 306*4e3e87e4SAndreas Gohr if (is_dir($from)) { 307*4e3e87e4SAndreas Gohr if ($dryrun) { 308*4e3e87e4SAndreas Gohr // just check for writability 309*4e3e87e4SAndreas Gohr if (!is_dir($to)) { 310*4e3e87e4SAndreas Gohr if (is_dir(dirname($to)) && !is_writable(dirname($to))) { 311*4e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_noperm') . '</b>', hsc("$dir/$file")); 312*4e3e87e4SAndreas Gohr $ok = false; 313*4e3e87e4SAndreas Gohr } 314*4e3e87e4SAndreas Gohr } 315*4e3e87e4SAndreas Gohr } 316*4e3e87e4SAndreas Gohr 317*4e3e87e4SAndreas Gohr // recursion 318*4e3e87e4SAndreas Gohr if (!$this->traverseCheckAndCopy("$dir/$file", $dryrun)) { 319*4e3e87e4SAndreas Gohr $ok = false; 320*4e3e87e4SAndreas Gohr } 321*4e3e87e4SAndreas Gohr } else { 322*4e3e87e4SAndreas Gohr $fmd5 = md5(@file_get_contents($from)); 323*4e3e87e4SAndreas Gohr $tmd5 = md5(@file_get_contents($to)); 324*4e3e87e4SAndreas Gohr if ($fmd5 != $tmd5 || !file_exists($to)) { 325*4e3e87e4SAndreas Gohr if ($dryrun) { 326*4e3e87e4SAndreas Gohr // just check for writability 327*4e3e87e4SAndreas Gohr if ((file_exists($to) && !is_writable($to)) || 328*4e3e87e4SAndreas Gohr (!file_exists($to) && is_dir(dirname($to)) && !is_writable(dirname($to))) 329*4e3e87e4SAndreas Gohr ) { 330*4e3e87e4SAndreas Gohr 331*4e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_noperm') . '</b>', hsc("$dir/$file")); 332*4e3e87e4SAndreas Gohr $ok = false; 333*4e3e87e4SAndreas Gohr } else { 334*4e3e87e4SAndreas Gohr $this->log('info', $this->getLang('tv_upd'), hsc("$dir/$file")); 335*4e3e87e4SAndreas Gohr } 336*4e3e87e4SAndreas Gohr } else { 337*4e3e87e4SAndreas Gohr // check dir 338*4e3e87e4SAndreas Gohr if (io_mkdir_p(dirname($to))) { 339*4e3e87e4SAndreas Gohr // remove existing (avoid case sensitivity problems) 340*4e3e87e4SAndreas Gohr if (file_exists($to) && !@unlink($to)) { 341*4e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_nodel') . '</b>', hsc("$dir/$file")); 342*4e3e87e4SAndreas Gohr $ok = false; 343*4e3e87e4SAndreas Gohr } 344*4e3e87e4SAndreas Gohr // copy 345*4e3e87e4SAndreas Gohr if (!copy($from, $to)) { 346*4e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_nocopy') . '</b>', hsc("$dir/$file")); 347*4e3e87e4SAndreas Gohr $ok = false; 348*4e3e87e4SAndreas Gohr } else { 349*4e3e87e4SAndreas Gohr $this->log('info', $this->getLang('tv_done'), hsc("$dir/$file")); 350*4e3e87e4SAndreas Gohr } 351*4e3e87e4SAndreas Gohr } else { 352*4e3e87e4SAndreas Gohr $this->log('error', '<b>' . $this->getLang('tv_nodir') . '</b>', hsc("$dir")); 353*4e3e87e4SAndreas Gohr $ok = false; 354*4e3e87e4SAndreas Gohr } 355*4e3e87e4SAndreas Gohr } 356*4e3e87e4SAndreas Gohr } 357*4e3e87e4SAndreas Gohr } 358*4e3e87e4SAndreas Gohr } 359*4e3e87e4SAndreas Gohr closedir($dh); 360*4e3e87e4SAndreas Gohr return $ok; 361*4e3e87e4SAndreas Gohr } 362*4e3e87e4SAndreas Gohr 363*4e3e87e4SAndreas Gohr // region utilities 364*4e3e87e4SAndreas Gohr 365*4e3e87e4SAndreas Gohr /** 366*4e3e87e4SAndreas Gohr * Figure out the release date from the version string 367*4e3e87e4SAndreas Gohr * 368*4e3e87e4SAndreas Gohr * @param $version 369*4e3e87e4SAndreas Gohr * @return int|string returns 0 if the version can't be read 370*4e3e87e4SAndreas Gohr */ 371*4e3e87e4SAndreas Gohr protected function dateFromVersion($version) 372*4e3e87e4SAndreas Gohr { 373*4e3e87e4SAndreas Gohr if (preg_match('/(^|\D)(\d\d\d\d-\d\d-\d\d)(\D|$)/i', $version, $m)) { 374*4e3e87e4SAndreas Gohr return $m[2]; 375*4e3e87e4SAndreas Gohr } 376*4e3e87e4SAndreas Gohr return 0; 377*4e3e87e4SAndreas Gohr } 378*4e3e87e4SAndreas Gohr 379*4e3e87e4SAndreas Gohr /** 380*4e3e87e4SAndreas Gohr * Recursive delete 381*4e3e87e4SAndreas Gohr * 382*4e3e87e4SAndreas Gohr * @author Jon Hassall 383*4e3e87e4SAndreas Gohr * @link http://de.php.net/manual/en/function.unlink.php#87045 384*4e3e87e4SAndreas Gohr */ 385*4e3e87e4SAndreas Gohr protected function recursiveDelete($dir) 386*4e3e87e4SAndreas Gohr { 387*4e3e87e4SAndreas Gohr if (!$dh = @opendir($dir)) { 388*4e3e87e4SAndreas Gohr return false; 389*4e3e87e4SAndreas Gohr } 390*4e3e87e4SAndreas Gohr while (false !== ($obj = readdir($dh))) { 391*4e3e87e4SAndreas Gohr if ($obj == '.' || $obj == '..') continue; 392*4e3e87e4SAndreas Gohr 393*4e3e87e4SAndreas Gohr if (!@unlink($dir . '/' . $obj)) { 394*4e3e87e4SAndreas Gohr $this->recursiveDelete($dir . '/' . $obj); 395*4e3e87e4SAndreas Gohr } 396*4e3e87e4SAndreas Gohr } 397*4e3e87e4SAndreas Gohr closedir($dh); 398*4e3e87e4SAndreas Gohr return @rmdir($dir); 399*4e3e87e4SAndreas Gohr } 400*4e3e87e4SAndreas Gohr 401*4e3e87e4SAndreas Gohr /** 402*4e3e87e4SAndreas Gohr * Log a message 403*4e3e87e4SAndreas Gohr * 404*4e3e87e4SAndreas Gohr * @param string ...$level, $msg 405*4e3e87e4SAndreas Gohr */ 406*4e3e87e4SAndreas Gohr protected function log() 407*4e3e87e4SAndreas Gohr { 408*4e3e87e4SAndreas Gohr $args = func_get_args(); 409*4e3e87e4SAndreas Gohr $level = array_shift($args); 410*4e3e87e4SAndreas Gohr $msg = array_shift($args); 411*4e3e87e4SAndreas Gohr $msg = vsprintf($msg, $args); 412*4e3e87e4SAndreas Gohr if ($this->logger) $this->logger->log($level, $msg); 413*4e3e87e4SAndreas Gohr } 414*4e3e87e4SAndreas Gohr 415*4e3e87e4SAndreas Gohr // endregion 416*4e3e87e4SAndreas Gohr} 417