*/
// must be run within Dokuwiki
if (!defined('DOKU_INC')) die();
if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once DOKU_PLUGIN.'admin.php';
require_once DOKU_PLUGIN.'upgrade/VerboseTarLib.class.php';
class admin_plugin_upgrade extends DokuWiki_Admin_Plugin {
private $tgzurl;
private $tgzfile;
private $tgzdir;
public function __construct(){
global $conf;
$branch = 'stable';
$this->tgzurl = 'http://github.com/splitbrain/dokuwiki/tarball/'.$branch;
$this->tgzfile = $conf['tmpdir'].'/dokuwiki-upgrade.tgz';
$this->tgzdir = $conf['tmpdir'].'/dokuwiki-upgrade/';
}
public function getMenuSort() { return 555; }
public function handle() {
if($_REQUEST['step'] && !checkSecurityToken()){
unset($_REQUEST['step']);
}
}
public function html() {
global $ID;
$abrt = false;
$next = false;
echo '
' . $this->getLang('menu') . '
';
$this->_say('');
// enable auto scroll
?>
_stepit(&$abrt, &$next);
// disable auto scroll
?>
_say('
');
echo '';
}
private function _stepit(&$abrt, &$next){
global $conf;
if($conf['safemodehack']){
$abrt = false;
$next = false;
echo $this->locale_xhtml('safemode');
}
if(isset($_REQUEST['step']) && is_array($_REQUEST['step'])){
$step = array_shift(array_keys($_REQUEST['step']));
}else{
$step = '';
}
if($step == 'cancel'){
# cleanup
@unlink($this->tgzfile);
$this->_rdel($this->tgzdir);
$step = '';
}
if($step){
$abrt = true;
$next = false;
if(!file_exists($this->tgzfile)){
if($this->_step_download()) $next = 'unpack';
}elseif(!is_dir($this->tgzdir)){
if($this->_step_unpack()) $next = 'check';
}elseif($step != 'upgrade'){
if($this->_step_check()) $next = 'upgrade';
}elseif($step == 'upgrade'){
if($this->_step_copy()) $next = 'cancel';
}else{
echo 'uhm. what happened? where am I? This should not happen';
}
}else{
# first time run, show intro
echo $this->locale_xhtml('step0');
$abrt = false;
$next = 'download';
}
}
private function _say(){
$args = func_get_args();
echo vsprintf(array_shift($args)."
\n",$args);
flush();
ob_flush();
}
/**
* Recursive delete
*
* @author Jon Hassall
* @link http://de.php.net/manual/en/function.unlink.php#87045
*/
private function _rdel($dir) {
if(!$dh = @opendir($dir)) {
return;
}
while (false !== ($obj = readdir($dh))) {
if($obj == '.' || $obj == '..') continue;
if (!@unlink($dir . '/' . $obj)) {
$this->_rdel($dir.'/'.$obj);
}
}
closedir($dh);
@rmdir($dir);
}
private function _step_download(){
$this->_say($this->getLang('dl_from'),$this->tgzurl);
@set_time_limit(120);
@ignore_user_abort();
$http = new DokuHTTPClient();
$http->timeout = 120;
$data = $http->get($this->tgzurl);
if(!$data){
$this->_say($http->error);
$this->_say($this->getLang('dl_fail'));
return false;
}
if(!io_saveFile($this->tgzfile,$data)){
$this->_say($this->getLang('dl_fail'));
return false;
}
$this->_say($this->getLang('dl_done',filesize_h(strlen($data)));
return true;
}
private function _step_unpack(){
global $conf;
$this->_say(''.$this->getLang('pk_extract').'');
@set_time_limit(120);
@ignore_user_abort();
$tar = new VerboseTarLib($this->tgzfile);
if($tar->_initerror < 0){
$this->_say($tar->TarErrorStr($tar->_initerror));
$this->_say($this->getLang('pk_fail'));
return false;
}
$ok = $tar->Extract(VerboseTarLib::FULL_ARCHIVE,$this->tgzdir,1,$conf['fmode'],'/^(_cs|_test|\.gitignore)/');
if($ok < 1){
$this->_say($tar->TarErrorStr($ok));
$this->_say($this->getLang('pk_fail'));
return false;
}
$this->_say($this->getLang('pk_done'));
$this->_say($this->getLang('pk_version'),
hsc(file_get_contents($this->tgzdir.'/VERSION')),
getVersion());
return true;
}
private function _step_check(){
$this->_say($this->getLang('ck_start'));
$ok = $this->_traverse('',true);
#FIXME check unused files
if($ok){
$this->_say(''.$this->getLang('ck_done').'');
}else{
$this->_say(''.$this->getLang('ck_fail').'');
}
return $ok;
}
private function _step_copy(){
$this->_say($this->getLang('cp_start'));
$ok = $this->_traverse('',false);
if($ok){
$this->_say(''.$this->getLang('cp_done').'');
#FIXME delete unused files
}else{
$this->_say(''.$this->getLang('cp_fail').'');
}
return $ok;
}
private function _traverse($dir,$dryrun){
$base = $this->tgzdir;
$ok = true;
$dh = @opendir($base.'/'.$dir);
if(!$dh) return;
while(($file = readdir($dh)) !== false){
if($file == '.' || $file == '..') continue;
$from = "$base/$dir/$file";
$to = DOKU_INC."$dir/$file";
if(is_dir($from)){
if($dryrun){
// just check for writability
if(!is_dir($to)){
if(is_dir(dirname($to)) && !is_writable(dirname($to))){
$this->_say(''.$this->getLang('tv_noperm').''),hsc("$dir/$file"));
$ok = false;
}
}
}
// recursion
if(!$this->_traverse("$dir/$file",$dryrun)){
$ok = false;
}
}else{
$fmd5 = md5(@file_get_contents($from));
$tmd5 = md5(@file_get_contents($to));
if($fmd5 != $tmd5){
if($dryrun){
// just check for writability
if( (file_exists($to) && !is_writable($to)) ||
(!file_exists($to) && is_dir(dirname($to)) && !is_writable(dirname($to))) ){
$this->_say(''.$this->getLang('tv_noperm').''),hsc("$dir/$file"));
$ok = false;
}else{
$this->_say($this->getLang('tv_upd'),hsc("$dir/$file"));
}
}else{
// check dir
if(io_mkdir_p(dirname($to))){
// copy
if(!copy($from,$to)){
$this->_say(''.$this->getLang('tv_nocopy').'',hsc("$dir/$file"));
$ok = false;
}else{
$this->_say($this->getLang('tv_done'),hsc("$dir/$file"));
}
}else{
$this->_say(''.$this->getLang('tv_nodir').'',hsc("$dir"));
$ok = false;
}
}
}
}
}
closedir($dh);
return $ok;
}
}
// vim:ts=4:sw=4:et:enc=utf-8: