From 4e1d990b918df84b94714021ba79e87b87ef0800 Mon Sep 17 00:00:00 2001 From: Matthias Vogel Date: Tue, 15 Jul 2014 17:38:39 +0200 Subject: [PATCH 1/6] added AutoUpdate --- cache/installedVersion.json | 3 + system/admin/views/updated-to.html.php | 5 + system/htmly.php | 21 +++++ system/includes/functions.php | 8 ++ system/includes/updater.php | 161 +++++++++++++++++++++++++++++++++ 5 files changed, 198 insertions(+) create mode 100644 cache/installedVersion.json create mode 100644 system/admin/views/updated-to.html.php create mode 100644 system/includes/updater.php diff --git a/cache/installedVersion.json b/cache/installedVersion.json new file mode 100644 index 0000000..2d86412 --- /dev/null +++ b/cache/installedVersion.json @@ -0,0 +1,3 @@ +{ + "tag_name": "v2.1" +} \ No newline at end of file diff --git a/system/admin/views/updated-to.html.php b/system/admin/views/updated-to.html.php new file mode 100644 index 0000000..c11dc91 --- /dev/null +++ b/system/admin/views/updated-to.html.php @@ -0,0 +1,5 @@ +printOne(); + +?> \ No newline at end of file diff --git a/system/htmly.php b/system/htmly.php index 9720f68..0c29618 100644 --- a/system/htmly.php +++ b/system/htmly.php @@ -6,6 +6,7 @@ date_default_timezone_set('Asia/Jakarta'); // Explicitly including the dispatch framework, // and our functions.php file require 'system/includes/dispatch.php'; +require 'system/includes/updater.php'; require 'system/includes/functions.php'; require 'system/admin/admin.php'; require 'system/includes/session.php'; @@ -1109,6 +1110,26 @@ get('/feed/opml',function(){ }); +get('/admin/update/now/:csrf',function($CSRF){ + + $proper = is_csrf_proper($CSRF); + $updater = new Updater; + if( login() && $proper && $updater->updateAble()) + { + $updater->update(); + config('views.root', 'system/admin/views'); + render('updated-to', array( + 'head_contents' => head_contents('Updated - ' . blog_title(), blog_description(), site_url()), + 'updater' => $updater, + )); + } + else + { + $login = site_url() . 'login'; + header("location: $login"); + } +}); + // If we get here, it means that // nothing has been matched above diff --git a/system/includes/functions.php b/system/includes/functions.php index 1644e78..0af8f2b 100644 --- a/system/includes/functions.php +++ b/system/includes/functions.php @@ -1673,6 +1673,10 @@ function toolbar() { $role = user('role', $user); $base = site_url(); + $CSRF = get_csrf(); + + $updater = new Updater; + echo << EOF; @@ -1686,6 +1690,10 @@ EOF; echo '
  • Import
  • '; echo '
  • Backup
  • '; echo '
  • Clear cache
  • '; + if( $updater->updateAble()) + { + echo '
  • UpdateMe[' . $updater->getName() . ']
  • '; + } echo '
  • Logout
  • '; echo ''; diff --git a/system/includes/updater.php b/system/includes/updater.php new file mode 100644 index 0000000..d0db34f --- /dev/null +++ b/system/includes/updater.php @@ -0,0 +1,161 @@ +fileName = $fileName; + $this->holdTime = $holdTime; + } + + public function is() + { + if(! file_exists($this->fileName)) + return false; + if(filemtime($this->fileName) < ( time() - $this->holdTime ) ) + { + unlink($this->fileName); + return false; + } + return true; + } + public function get() + { + return file_get_contents($this->fileName); + } + public function set($content) + { + file_put_contents($this->fileName,$content); + } +} + +class Updater +{ + protected $cachedInfo = "cache/downloadInfo.json"; + protected $versionFile = "cache/installedVersion.json"; + protected $zipFile = "cache/tmpZipFile.zip"; + + protected $infos = []; + + public function __construct() + { + if(! file_exists("cache/")) + { + mkdir("cache/"); + } + $this->cachedInfo = new CacheOneFile($this->cachedInfo); + $this->infos = $this->getInfos(); + } + + protected function getInfos() + { + $path = "https://api.github.com/repos/danpros/htmly/releases"; + if($this->cachedInfo->is()) + { + $fileContent = $this->cachedInfo->get(); + } + else + { + $fileContent = @file_get_contents($path,false, stream_context_create(['http'=>['header'=>"User-Agent: Awesome-Update-My-Self\r\n"]])); + if($fileContent == false) + { + return []; + } + $json = json_decode($fileContent,true); + $fileContent = json_encode($json, JSON_PRETTY_PRINT); + $this->cachedInfo->set($fileContent); + return $json; + } + return json_decode($fileContent,true); + } + + public function updateAble() + { + if(empty($this->infos)) + return false; + + if(file_exists($this->versionFile)) + { + $fileContent = file_get_contents($this->versionFile); + $current = json_decode($fileContent,true); + + if(isset($current['id']) && $current['id'] == $this->infos[0]['id']) + return false; + if(isset($current['tag_name']) && $current['tag_name'] == $this->infos[0]['tag_name']) + return false; + } + return true; + } + + public function update() + { + if($this->updateAble()) + { + if($this->download("https://github.com/danpros/htmly/archive/" . $this->infos[0]['tag_name'] . ".zip")) + { + if($this->unZip()) + { + unlink($this->zipFile); + file_put_contents($this->versionFile, json_encode([ + "id" => $this->infos[0]['id'], + "tag_name" => $this->infos[0]['tag_name'] + ], JSON_PRETTY_PRINT)); + return true; + } + } + } + return false; + } + protected function download($url) + { + $file = @fopen($url, 'r'); + if($file == false) + return false; + file_put_contents($this->zipFile, $file); + return true; + } + protected function unZip() + { + $path = $this->zipFile; + $zip = new ZipArchive; + if ($zip->open($path) === true) { + $cutLength = strlen($zip->getNameIndex(0)); + for($i = 1; $i < $zip->numFiles; $i++) {//iterate throw the Zip + $fileName = $zip->getNameIndex($i); + if($zip->statIndex($i)["crc"] == 0) + { + $dirName = substr($fileName,$cutLength); + if(! file_exists($dirName)) + { + //mkdir($dirName); + } + } + else{ + //copy("zip://".$path."#".$filename, substr($filename,$cutLength)); + } + } + $zip->close(); + return true; + } + else{ + return false; + } + } + + public function printOne() + { + $releases = $this->infos; + $string = "

    Updated to

    "; + $string .= "

    [" . $releases[0]['tag_name'] . "] " . $releases[0]['name'] . "

    \n"; + $string .= "

    " . $releases[0]['body'] . "

    \n"; + return $string; + } + + public function getName() + { + return $this->infos[0]['tag_name']; + } +} \ No newline at end of file From 3d268072fc2cba0e337da684cdf86eb6db3c4281 Mon Sep 17 00:00:00 2001 From: Matthias Vogel Date: Tue, 15 Jul 2014 17:43:37 +0200 Subject: [PATCH 2/6] Improved downward compatibility --- cache/installedVersion.json | 1 + system/includes/updater.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cache/installedVersion.json b/cache/installedVersion.json index 2d86412..54985e8 100644 --- a/cache/installedVersion.json +++ b/cache/installedVersion.json @@ -1,3 +1,4 @@ { + "id": 397789, "tag_name": "v2.1" } \ No newline at end of file diff --git a/system/includes/updater.php b/system/includes/updater.php index d0db34f..8e4bcbb 100644 --- a/system/includes/updater.php +++ b/system/includes/updater.php @@ -130,11 +130,11 @@ class Updater $dirName = substr($fileName,$cutLength); if(! file_exists($dirName)) { - //mkdir($dirName); + mkdir($dirName); } } else{ - //copy("zip://".$path."#".$filename, substr($filename,$cutLength)); + copy("zip://".$path."#".$filename, substr($filename,$cutLength)); } } $zip->close(); From b8cac0d2fb098b440f930f05e29f0ab9ac472214 Mon Sep 17 00:00:00 2001 From: Matthias Vogel Date: Wed, 16 Jul 2014 07:02:41 +0200 Subject: [PATCH 3/6] update process improved --- system/includes/functions.php | 2 +- system/includes/updater.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/system/includes/functions.php b/system/includes/functions.php index 0af8f2b..23f9aad 100644 --- a/system/includes/functions.php +++ b/system/includes/functions.php @@ -1692,7 +1692,7 @@ EOF; echo '
  • Clear cache
  • '; if( $updater->updateAble()) { - echo '
  • UpdateMe[' . $updater->getName() . ']
  • '; + echo '
  • Update to ' . $updater->getName() . '
  • '; } echo '
  • Logout
  • '; diff --git a/system/includes/updater.php b/system/includes/updater.php index 8e4bcbb..fe53f9f 100644 --- a/system/includes/updater.php +++ b/system/includes/updater.php @@ -119,7 +119,8 @@ class Updater } protected function unZip() { - $path = $this->zipFile; + $path = dirname($_SERVER['SCRIPT_FILENAME']) . "/" . $this->zipFile; + $zip = new ZipArchive; if ($zip->open($path) === true) { $cutLength = strlen($zip->getNameIndex(0)); @@ -134,7 +135,7 @@ class Updater } } else{ - copy("zip://".$path."#".$filename, substr($filename,$cutLength)); + copy("zip://".$path."#".$fileName, substr($fileName,$cutLength)); } } $zip->close(); From 4e18083722db5ebf1fa133b6898bc8726feadc96 Mon Sep 17 00:00:00 2001 From: Matthias Vogel Date: Thu, 17 Jul 2014 07:35:40 +0200 Subject: [PATCH 4/6] PHP 5.3 > openssl needed --- system/includes/updater.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/system/includes/updater.php b/system/includes/updater.php index fe53f9f..d4957ad 100644 --- a/system/includes/updater.php +++ b/system/includes/updater.php @@ -38,7 +38,7 @@ class Updater protected $versionFile = "cache/installedVersion.json"; protected $zipFile = "cache/tmpZipFile.zip"; - protected $infos = []; + protected $infos = array(); public function __construct() { @@ -59,10 +59,16 @@ class Updater } else { - $fileContent = @file_get_contents($path,false, stream_context_create(['http'=>['header'=>"User-Agent: Awesome-Update-My-Self\r\n"]])); - if($fileContent == false) + $fileContent = file_get_contents($path,false, stream_context_create( + array( + 'http' => array( + 'header'=>"User-Agent: Awesome-Update-My-Self\r\n" + ) + ) + )); + if($fileContent === false) { - return []; + return array(); } $json = json_decode($fileContent,true); $fileContent = json_encode($json, JSON_PRETTY_PRINT); @@ -99,10 +105,10 @@ class Updater if($this->unZip()) { unlink($this->zipFile); - file_put_contents($this->versionFile, json_encode([ + file_put_contents($this->versionFile, json_encode(array( "id" => $this->infos[0]['id'], "tag_name" => $this->infos[0]['tag_name'] - ], JSON_PRETTY_PRINT)); + ), JSON_PRETTY_PRINT)); return true; } } @@ -126,7 +132,8 @@ class Updater $cutLength = strlen($zip->getNameIndex(0)); for($i = 1; $i < $zip->numFiles; $i++) {//iterate throw the Zip $fileName = $zip->getNameIndex($i); - if($zip->statIndex($i)["crc"] == 0) + $stat = $zip->statIndex($i); + if($stat["crc"] == 0) { $dirName = substr($fileName,$cutLength); if(! file_exists($dirName)) From 1b5e52e497d4b9d146cf5cb739ebd562c9976d1f Mon Sep 17 00:00:00 2001 From: Matthias Vogel Date: Thu, 17 Jul 2014 07:47:03 +0200 Subject: [PATCH 5/6] fix no https wrapper errors --- system/includes/updater.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/system/includes/updater.php b/system/includes/updater.php index d4957ad..e00762f 100644 --- a/system/includes/updater.php +++ b/system/includes/updater.php @@ -59,7 +59,11 @@ class Updater } else { - $fileContent = file_get_contents($path,false, stream_context_create( + if(!in_array('https', stream_get_wrappers())) + { + return array(); + } + $fileContent = @file_get_contents($path,false, stream_context_create( array( 'http' => array( 'header'=>"User-Agent: Awesome-Update-My-Self\r\n" @@ -80,6 +84,8 @@ class Updater public function updateAble() { + if(!in_array('https', stream_get_wrappers())) + return false; if(empty($this->infos)) return false; From f1ec5a0566b337f52367402de7a4b7d709404c5d Mon Sep 17 00:00:00 2001 From: Matthias Vogel Date: Thu, 17 Jul 2014 17:08:42 +0200 Subject: [PATCH 6/6] Fix: Issue #58 Error logs --- system/includes/dispatch.php | 70 +++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/system/includes/dispatch.php b/system/includes/dispatch.php index 81df1d4..9b269c5 100644 --- a/system/includes/dispatch.php +++ b/system/includes/dispatch.php @@ -272,53 +272,51 @@ function content($value = null) { } function render($view, $locals = null, $layout = null) { + $login = login(); + if(!$login) { + $c = str_replace('/', '#', str_replace('?', '~', $_SERVER['REQUEST_URI'])); + $dir = 'cache/page'; + $cachefile = $dir. '/' . $c . '.cache'; + if(is_dir($dir) === false) { + mkdir($dir, 0777, true); + } + } - if(!login()) { - $c = str_replace('/', '#', str_replace('?', '~', $_SERVER['REQUEST_URI'])); - $dir = 'cache/page'; - $cachefile = $dir. '/' . $c . '.cache'; - if(is_dir($dir) === false) { - mkdir($dir, 0777, true); - } - } + if (is_array($locals) && count($locals)) { + extract($locals, EXTR_SKIP); + } - if (is_array($locals) && count($locals)) { - extract($locals, EXTR_SKIP); - } + if (($view_root = config('views.root')) == null) + error(500, "[views.root] is not set"); - if (($view_root = config('views.root')) == null) - error(500, "[views.root] is not set"); + ob_start(); + include "{$view_root}/{$view}.html.php"; + content(trim(ob_get_clean())); - ob_start(); - include "{$view_root}/{$view}.html.php"; - content(trim(ob_get_clean())); + if ($layout !== false) { - if ($layout !== false) { + if ($layout == null) { + $layout = config('views.layout'); + $layout = ($layout == null) ? 'layout' : $layout; + } - if ($layout == null) { - $layout = config('views.layout'); - $layout = ($layout == null) ? 'layout' : $layout; - } + $layout = "{$view_root}/{$layout}.html.php"; - $layout = "{$view_root}/{$layout}.html.php"; + header('Content-type: text/html; charset=utf-8'); - header('Content-type: text/html; charset=utf-8'); + ob_start(); + require $layout; - ob_start(); - require $layout; - - if(!login()) { - if (!file_exists($cachefile)) { - file_put_contents($cachefile, ob_get_contents()); - } + if(!$login) { + if (!file_exists($cachefile)) { + file_put_contents($cachefile, ob_get_contents()); + } } - echo trim(ob_get_clean()); - - } else { - echo content(); - } - + echo trim(ob_get_clean()); + } else { + echo content(); + } } function json($obj, $code = 200) {