mikuli.cz

:)
git clone https://git.sr.ht/~ashymad/mikuli.cz
Log | Files | Refs

commit c5f44f4b6448383dccf05697434e291ff99d7a9a
parent 182d682f876520e573300b0d7adaeb1acb53f142
Author: markseu <mark2011@mayberg.se>
Date:   Sun, 10 Jul 2016 20:44:02 +0200

System update (better installation)

Diffstat:
Msystem/config/config.ini | 1+
Msystem/plugins/commandline.php | 10+++++-----
Msystem/plugins/core.php | 85+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msystem/plugins/update.php | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
4 files changed, 202 insertions(+), 46 deletions(-)

diff --git a/system/config/config.ini b/system/config/config.ini @@ -22,6 +22,7 @@ ThemeDir: system/themes/ AssetDir: system/themes/assets/ SnippetDir: system/themes/snippets/ TemplateDir: system/themes/templates/ +TrashDir: system/trash/ MediaDir: media/ ImageDir: media/images/ StaticDir: cache/ diff --git a/system/plugins/commandline.php b/system/plugins/commandline.php @@ -177,17 +177,17 @@ class YellowCommandline ++$this->errors; echo "ERROR building location '$location', ".$this->yellow->page->getStatusCode(true)."\n"; } - if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticFile status:$statusCode location:$location\n"; + if(defined("DEBUG") && DEBUG>=1) echo "YellowCommandline::buildStaticFile status:$statusCode location:$location<br/>\n"; return $statusCode; } // Analyse static file, detect locations with arguments - function analyseStaticFile($text) + function analyseStaticFile($rawData) { $serverName = $this->yellow->config->get("serverName"); $serverBase = $this->yellow->config->get("serverBase"); $pagination = $this->yellow->config->get("contentPagination"); - preg_match_all("/<(.*?)href=\"([^\"]+)\"(.*?)>/i", $text, $matches); + preg_match_all("/<(.*?)href=\"([^\"]+)\"(.*?)>/i", $rawData, $matches); foreach($matches[2] as $match) { if(preg_match("/^(.*?)#(.*)$/", $match, $tokens)) $match = $tokens[1]; @@ -205,14 +205,14 @@ class YellowCommandline if(is_null($this->locationsArgs[$location])) { $this->locationsArgs[$location] = $location; - if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticFile detected location:$location\n"; + if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticFile detected location:$location<br/>\n"; } } else { $location = rtrim($location, "0..9"); if(is_null($this->locationsArgsPagination[$location])) { $this->locationsArgsPagination[$location] = $location; - if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticFile detected location:$location\n"; + if(defined("DEBUG") && DEBUG>=2) echo "YellowCommandline::analyseStaticFile detected location:$location<br/>\n"; } } } diff --git a/system/plugins/core.php b/system/plugins/core.php @@ -47,6 +47,7 @@ class YellowCore $this->config->setDefault("assetDir", "system/themes/assets/"); $this->config->setDefault("snippetDir", "system/themes/snippets/"); $this->config->setDefault("templateDir", "system/themes/templates/"); + $this->config->setDefault("trashDir", "system/trash/"); $this->config->setDefault("mediaDir", "media/"); $this->config->setDefault("imageDir", "media/images/"); $this->config->setDefault("staticDir", "cache/"); @@ -175,7 +176,7 @@ class YellowCore } // Read page - function readPage($serverScheme, $serverName, $base, $location, $fileName, $cacheable, $statusCode, $pageError = "") + function readPage($serverScheme, $serverName, $base, $location, $fileName, $cacheable, $statusCode, $pageError) { if($statusCode >= 400) { @@ -261,13 +262,13 @@ class YellowCore } } $this->toolbox->timerStop($time); - if(defined("DEBUG") && DEBUG>=1) echo "YellowCore::command time:$time ms<br/>\n"; if($statusCode == 0) { $statusCode = 400; - list($name, $command) = func_get_args(); + list($command) = func_get_args(); echo "Yellow $command: Command not found\n"; } + if(defined("DEBUG") && DEBUG>=1) echo "YellowCore::command time:$time ms<br/>\n"; return $statusCode; } @@ -332,7 +333,7 @@ class YellowCore // Return static file from cache if available function getStaticFileFromCache($location, $fileName, $cacheable) { - if(PHP_SAPI!="cli" && is_readable($fileName) && $cacheable) + if(is_readable($fileName) && $cacheable && PHP_SAPI!="cli") { $location .= $this->toolbox->getLocationArgs(); $fileNameStatic = rtrim($this->config->get("staticDir"), '/').$location; @@ -1868,10 +1869,7 @@ class YellowText { if(preg_match("/^\#/", $line)) continue; preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); - if(empty($language)) - { - if(lcfirst($matches[1])=="language" && !strempty($matches[2])) $language = $matches[2]; - } + if(lcfirst($matches[1])=="language" && !strempty($matches[2])) $language = $matches[2]; if(!empty($language) && !empty($matches[1]) && !strempty($matches[2])) { $this->setText($matches[1], $matches[2], $language); @@ -2399,6 +2397,17 @@ class YellowLookup for($i=1; $i<count($tokens); ++$i) $string .= '/'.$this->normaliseName($tokens[$i]); return $location == $string; } + + // Check if file is valid + function isValidFile($fileName) + { + $contentDirLength = strlenu($this->yellow->config->get("contentDir")); + $mediaDirLength = strlenu($this->yellow->config->get("mediaDir")); + $systemDirLength = strlenu($this->yellow->config->get("systemDir")); + return substru($fileName, 0, $contentDirLength) == $this->yellow->config->get("contentDir") || + substru($fileName, 0, $mediaDirLength) == $this->yellow->config->get("mediaDir") || + substru($fileName, 0, $systemDirLength) == $this->yellow->config->get("systemDir"); + } } // Yellow toolbox with helpers @@ -2448,26 +2457,7 @@ class YellowToolbox $location = rawurldecode(($pos = strposu($location, '?')) ? substru($location, 0, $pos) : $location); if($filterStrict) { - $locationFiltered = ""; - if($location[0] != '/') $location = '/'.$location; - for($pos=0; $pos<strlenb($location); ++$pos) - { - if($location[$pos] == '/') - { - if($location[$pos+1] == '/') continue; - if($location[$pos+1] == '.') - { - $posNew = $pos+1; while($location[$posNew] == '.') ++$posNew; - if($location[$posNew]=='/' || $location[$posNew]=='') - { - $pos = $posNew-1; - continue; - } - } - } - $locationFiltered .= $location[$pos]; - } - $location = $locationFiltered; + $location = $this->normaliseTokens($location, true); $separator = $this->getLocationArgsSeparator(); if(preg_match("/^(.*?\/)([^\/]+$separator.*)$/", $location, $matches)) { @@ -2596,6 +2586,31 @@ class YellowToolbox } } + // Normalise path or location, take care of relative path tokens + function normaliseTokens($text, $prependSlash = false) + { + $textFiltered = ""; + if($prependSlash && $text[0]!='/') $textFiltered .= '/'; + for($pos=0; $pos<strlenb($text); ++$pos) + { + if($text[$pos]=='/' || $pos==0) + { + if($text[$pos+1] == '/') continue; + if($text[$pos+1] == '.') + { + $posNew = $pos+1; while($text[$posNew] == '.') ++$posNew; + if($text[$posNew]=='/' || $text[$posNew]=='') + { + $pos = $posNew-1; + continue; + } + } + } + $textFiltered .= $text[$pos]; + } + return $textFiltered; + } + // Normalise location arguments function normaliseArgs($text, $appendSlash = true, $filterStrict = true) { @@ -2823,9 +2838,19 @@ class YellowToolbox } // Delete file - function deleteFile($fileName) + function deleteFile($fileName, $pathTrash = "") { - return @unlink($fileName); + if(empty($pathTrash)) + { + $ok = @unlink($fileName); + } else { + $fileNameDest = $pathTrash; + $fileNameDest .= pathinfo($fileName, PATHINFO_FILENAME); + $fileNameDest .= "-".str_replace(array(" ", ":"), "-", date("Y-m-d H:i:s", filemtime($fileName))); + $fileNameDest .= ".".pathinfo($fileName, PATHINFO_EXTENSION); + $ok = $this->renameFile($fileName, $fileNameDest, true); + } + return $ok; } // Return lines from text string diff --git a/system/plugins/update.php b/system/plugins/update.php @@ -5,7 +5,7 @@ // Update plugin class YellowUpdate { - const Version = "0.6.1"; + const Version = "0.6.2"; var $yellow; //access to API // Handle initialisation @@ -15,7 +15,7 @@ class YellowUpdate $this->yellow->config->setDefault("updatePluginsUrl", "https://github.com/datenstrom/yellow-plugins"); $this->yellow->config->setDefault("updateThemesUrl", "https://github.com/datenstrom/yellow-themes"); $this->yellow->config->setDefault("updateVersionFile", "version.ini"); - $this->yellow->config->setDefault("updateFile", "update.ini"); + $this->yellow->config->setDefault("updateInformationFile", "update.ini"); } // Handle request @@ -49,7 +49,7 @@ class YellowUpdate return "update [FEATURE]"; } - // Update plugins and themes + // Show software updates function updateCommand($args) { $statusCode = 0; @@ -69,22 +69,138 @@ class YellowUpdate echo "Yellow $command: $updates update".($updates==1 ? "":"s")." available\n"; } else { echo "Yellow $command: No updates available\n"; - + } + return $statusCode; + } + + // Update software + function update() + { + $statusCode = 0; + $path = $this->yellow->config->get("pluginDir"); + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) + { + if(defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::update file:$entry<br/>\n"; + $statusCode = max($statusCode, $this->updateSoftwareArchive($entry)); + } + $path = $this->yellow->config->get("themeDir"); + foreach($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) + { + if(defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::update file:$entry<br/>\n"; + $statusCode = max($statusCode, $this->updateSoftwareArchive($entry)); + } + return $statusCode; + } + + // Update software from archive + function updateSoftwareArchive($path) + { + $statusCode = 0; + $zip = new ZipArchive(); + if($zip->open($path) === true) + { + $fileNameInformation = $this->yellow->config->get("updateInformationFile"); + for($i=0; $i<$zip->numFiles; ++$i) + { + $fileName = $zip->getNameIndex($i); + if(empty($pathBase) && substru($fileName, -1, 1)=="/") $pathBase = $fileName; + if($fileName == $pathBase.$fileNameInformation) + { + $fileData = $zip->getFromIndex($i); + break; + } + } + foreach($this->yellow->toolbox->getTextLines($fileData) as $line) + { + if(preg_match("/^\#/", $line)) continue; + preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); + if(lcfirst($matches[1])=="plugin" || lcfirst($matches[1])=="theme") $software = $matches[2]; + if(!empty($software) && !empty($matches[1]) && !empty($matches[2])) + { + list($fileName, $flags) = explode(',', $matches[2], 2); + $modified = $zip->statName($pathBase.$fileName)["mtime"]; + $rawData = $zip->getFromName($pathBase.$fileName); + $statusCode = $this->updateSoftwareFile($matches[1], $modified, $rawData, $flags, $software); + if($statusCode != 200) break; + } + } + $zip->close(); + if($statusCode==200 && !$this->yellow->toolbox->deleteFile($path)) + { + $statusCode = 500; + $this->yellow->page->error($statusCode, "Can't delete file '$path'!"); + + } + } + return $statusCode; + } + + // Update software file + function updateSoftwareFile($fileName, $modified, $rawData, $flags, $software) + { + $statusCode = 200; + $fileName = $this->yellow->toolbox->normaliseTokens($fileName); + if($this->yellow->lookup->isValidFile($fileName) && !empty($flags)) + { + $create = $update = $delete = false; + if(preg_match("/create/i", $flags) && !empty($rawData)) $create = true; + if(preg_match("/update/i", $flags) && !empty($rawData)) $update = true; + if(preg_match("/delete/i", $flags)) $delete = true; + if(preg_match("/optional/i", $flags) && $this->isSoftware($software)) $create = $update = $delete = false; + if($create && !is_file($fileName)) + { + if(!$this->yellow->toolbox->createFile($fileName, $rawData, true) || + !$this->yellow->toolbox->modifyFile($fileName, $modified)) + { + $statusCode = 500; + $this->yellow->page->error($statusCode, "Can't create file '$fileName'!"); + } + } + if($update && is_file($fileName)) + { + if(!$this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir")) || + !$this->yellow->toolbox->createFile($fileName, $rawData) || + !$this->yellow->toolbox->modifyFile($fileName, $modified)) + { + $statusCode = 500; + $this->yellow->page->error($statusCode, "Can't update file '$fileName'!"); + } + } + if($delete && is_file($fileName)) + { + if(!$this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir"))) + { + $statusCode = 500; + $this->yellow->page->error($statusCode, "Can't delete file '$fileName'!"); + } + } + if(defined("DEBUG") && DEBUG>=3) echo "YellowUpdate::updateSoftwareFile file:$fileName flags:$flags<br/>\n"; } return $statusCode; } - // Process request to update software + // Process request to install updates function processRequestUpdate($serverScheme, $serverName, $base, $location, $fileName) { - return 0; + $statusCode = 0; + if($this->isContentFile($fileName)) + { + $statusCode = $this->update(); + if($statusCode == 200) + { + $statusCode = 303; + $location = $this->yellow->lookup->normaliseUrl($serverScheme, $serverName, $base, $location); + $this->yellow->sendStatus($statusCode, $location); + } + } + return $statusCode; } // Process request to install website function processRequestInstallation($serverScheme, $serverName, $base, $location, $fileName) { $statusCode = 0; - if(!$this->yellow->isStaticFile($location, $fileName, false)) + if($this->isContentFile($fileName)) { $fileName = $this->yellow->lookup->findFileNew($fileName, $this->yellow->config->get("webinterfaceNewFile"), $this->yellow->config->get("configDir"), "installation"); @@ -230,7 +346,7 @@ class YellowUpdate curl_close($curlHandle); if($statusCode == 200) { - if(defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::getSoftwareVersion location:$urlVersion\n"; + if(defined("DEBUG") && DEBUG>=2) echo "YellowUpdate::getSoftwareVersionFromUrl location:$url\n"; foreach($this->yellow->toolbox->getTextLines($rawData) as $line) { preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches); @@ -238,7 +354,7 @@ class YellowUpdate { list($version, $url) = explode(',', $matches[2]); $data[$matches[1]] = $version; - if(defined("DEBUG") && DEBUG>=3) echo "YellowUpdate::getSoftwareVersion $matches[1]:$version\n"; + if(defined("DEBUG") && DEBUG>=3) echo "YellowUpdate::getSoftwareVersionFromUrl $matches[1]:$version\n"; } } } @@ -251,10 +367,24 @@ class YellowUpdate return array($statusCode, $data); } - // Return if installation is necessary + // Check if software exists + function isSoftware($software) + { + $data = $this->yellow->plugins->getData(); + return !is_null($data[$software]); + } + + // Check if installation requested function isInstallation() { - return PHP_SAPI!="cli" && $this->yellow->config->get("installationMode"); + return $this->yellow->config->get("installationMode") && PHP_SAPI!="cli"; + } + + // Check if content file + function isContentFile($fileName) + { + $contentDirLength = strlenu($this->yellow->config->get("contentDir")); + return substru($fileName, 0, $contentDirLength) == $this->yellow->config->get("contentDir"); } }