Browse Source

System update (better installation)

markseu 9 years ago
parent
commit
c5f44f4b64
4 changed files with 202 additions and 46 deletions
  1. 1 0
      system/config/config.ini
  2. 5 5
      system/plugins/commandline.php
  3. 55 30
      system/plugins/core.php
  4. 141 11
      system/plugins/update.php

+ 1 - 0
system/config/config.ini

@@ -22,6 +22,7 @@ ThemeDir: system/themes/
 AssetDir: system/themes/assets/
 AssetDir: system/themes/assets/
 SnippetDir: system/themes/snippets/
 SnippetDir: system/themes/snippets/
 TemplateDir: system/themes/templates/
 TemplateDir: system/themes/templates/
+TrashDir: system/trash/
 MediaDir: media/
 MediaDir: media/
 ImageDir: media/images/
 ImageDir: media/images/
 StaticDir: cache/
 StaticDir: cache/

+ 5 - 5
system/plugins/commandline.php

@@ -177,17 +177,17 @@ class YellowCommandline
 			++$this->errors;
 			++$this->errors;
 			echo "ERROR building location '$location', ".$this->yellow->page->getStatusCode(true)."\n";
 			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;
 		return $statusCode;
 	}
 	}
 	
 	
 	// Analyse static file, detect locations with arguments
 	// Analyse static file, detect locations with arguments
-	function analyseStaticFile($text)
+	function analyseStaticFile($rawData)
 	{
 	{
 		$serverName = $this->yellow->config->get("serverName");
 		$serverName = $this->yellow->config->get("serverName");
 		$serverBase = $this->yellow->config->get("serverBase");
 		$serverBase = $this->yellow->config->get("serverBase");
 		$pagination = $this->yellow->config->get("contentPagination");
 		$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)
 		foreach($matches[2] as $match)
 		{
 		{
 			if(preg_match("/^(.*?)#(.*)$/", $match, $tokens)) $match = $tokens[1];
 			if(preg_match("/^(.*?)#(.*)$/", $match, $tokens)) $match = $tokens[1];
@@ -205,14 +205,14 @@ class YellowCommandline
 				if(is_null($this->locationsArgs[$location]))
 				if(is_null($this->locationsArgs[$location]))
 				{
 				{
 					$this->locationsArgs[$location] = $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 {
 			} else {
 				$location = rtrim($location, "0..9");
 				$location = rtrim($location, "0..9");
 				if(is_null($this->locationsArgsPagination[$location]))
 				if(is_null($this->locationsArgsPagination[$location]))
 				{
 				{
 					$this->locationsArgsPagination[$location] = $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";
 				}
 				}
 			}
 			}
 		}
 		}

+ 55 - 30
system/plugins/core.php

@@ -47,6 +47,7 @@ class YellowCore
 		$this->config->setDefault("assetDir", "system/themes/assets/");
 		$this->config->setDefault("assetDir", "system/themes/assets/");
 		$this->config->setDefault("snippetDir", "system/themes/snippets/");
 		$this->config->setDefault("snippetDir", "system/themes/snippets/");
 		$this->config->setDefault("templateDir", "system/themes/templates/");
 		$this->config->setDefault("templateDir", "system/themes/templates/");
+		$this->config->setDefault("trashDir", "system/trash/");
 		$this->config->setDefault("mediaDir", "media/");
 		$this->config->setDefault("mediaDir", "media/");
 		$this->config->setDefault("imageDir", "media/images/");
 		$this->config->setDefault("imageDir", "media/images/");
 		$this->config->setDefault("staticDir", "cache/");
 		$this->config->setDefault("staticDir", "cache/");
@@ -175,7 +176,7 @@ class YellowCore
 	}
 	}
 	
 	
 	// Read page
 	// 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)
 		if($statusCode >= 400)
 		{
 		{
@@ -261,13 +262,13 @@ class YellowCore
 			}
 			}
 		}
 		}
 		$this->toolbox->timerStop($time);
 		$this->toolbox->timerStop($time);
-		if(defined("DEBUG") && DEBUG>=1) echo "YellowCore::command time:$time ms<br/>\n";
 		if($statusCode == 0)
 		if($statusCode == 0)
 		{
 		{
 			$statusCode = 400;
 			$statusCode = 400;
-			list($name, $command) = func_get_args();
+			list($command) = func_get_args();
 			echo "Yellow $command: Command not found\n";
 			echo "Yellow $command: Command not found\n";
 		}
 		}
+		if(defined("DEBUG") && DEBUG>=1) echo "YellowCore::command time:$time ms<br/>\n";
 		return $statusCode;
 		return $statusCode;
 	}
 	}
 	
 	
@@ -332,7 +333,7 @@ class YellowCore
 	// Return static file from cache if available
 	// Return static file from cache if available
 	function getStaticFileFromCache($location, $fileName, $cacheable)
 	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();
 			$location .= $this->toolbox->getLocationArgs();
 			$fileNameStatic = rtrim($this->config->get("staticDir"), '/').$location;
 			$fileNameStatic = rtrim($this->config->get("staticDir"), '/').$location;
@@ -1868,10 +1869,7 @@ class YellowText
 			{
 			{
 				if(preg_match("/^\#/", $line)) continue;
 				if(preg_match("/^\#/", $line)) continue;
 				preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
 				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]))
 				if(!empty($language) && !empty($matches[1]) && !strempty($matches[2]))
 				{
 				{
 					$this->setText($matches[1], $matches[2], $language);
 					$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]);
 		for($i=1; $i<count($tokens); ++$i) $string .= '/'.$this->normaliseName($tokens[$i]);
 		return $location == $string;
 		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
 // Yellow toolbox with helpers
@@ -2448,26 +2457,7 @@ class YellowToolbox
 		$location = rawurldecode(($pos = strposu($location, '?')) ? substru($location, 0, $pos) : $location);
 		$location = rawurldecode(($pos = strposu($location, '?')) ? substru($location, 0, $pos) : $location);
 		if($filterStrict)
 		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();
 			$separator = $this->getLocationArgsSeparator();
 			if(preg_match("/^(.*?\/)([^\/]+$separator.*)$/", $location, $matches))
 			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
 	// Normalise location arguments
 	function normaliseArgs($text, $appendSlash = true, $filterStrict = true)
 	function normaliseArgs($text, $appendSlash = true, $filterStrict = true)
 	{
 	{
@@ -2823,9 +2838,19 @@ class YellowToolbox
 	}
 	}
 
 
 	// Delete file
 	// 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
 	// Return lines from text string

+ 141 - 11
system/plugins/update.php

@@ -5,7 +5,7 @@
 // Update plugin
 // Update plugin
 class YellowUpdate
 class YellowUpdate
 {
 {
-	const Version = "0.6.1";
+	const Version = "0.6.2";
 	var $yellow;					//access to API
 	var $yellow;					//access to API
 	
 	
 	// Handle initialisation
 	// Handle initialisation
@@ -15,7 +15,7 @@ class YellowUpdate
 		$this->yellow->config->setDefault("updatePluginsUrl", "https://github.com/datenstrom/yellow-plugins");
 		$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("updateThemesUrl", "https://github.com/datenstrom/yellow-themes");
 		$this->yellow->config->setDefault("updateVersionFile", "version.ini");
 		$this->yellow->config->setDefault("updateVersionFile", "version.ini");
-		$this->yellow->config->setDefault("updateFile", "update.ini");
+		$this->yellow->config->setDefault("updateInformationFile", "update.ini");
 	}
 	}
 	
 	
 	// Handle request
 	// Handle request
@@ -49,7 +49,7 @@ class YellowUpdate
 		return "update [FEATURE]";
 		return "update [FEATURE]";
 	}
 	}
 	
 	
-	// Update plugins and themes
+	// Show software updates
 	function updateCommand($args)
 	function updateCommand($args)
 	{
 	{
 		$statusCode = 0;
 		$statusCode = 0;
@@ -69,22 +69,138 @@ class YellowUpdate
 			echo "Yellow $command: $updates update".($updates==1 ? "":"s")." available\n";
 			echo "Yellow $command: $updates update".($updates==1 ? "":"s")." available\n";
 		} else {
 		} else {
 			echo "Yellow $command: No updates available\n";
 			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;
 		return $statusCode;
 	}
 	}
 	
 	
-	// Process request to update software
+	// Process request to install updates
 	function processRequestUpdate($serverScheme, $serverName, $base, $location, $fileName)
 	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
 	// Process request to install website
 	function processRequestInstallation($serverScheme, $serverName, $base, $location, $fileName)
 	function processRequestInstallation($serverScheme, $serverName, $base, $location, $fileName)
 	{
 	{
 		$statusCode = 0;
 		$statusCode = 0;
-		if(!$this->yellow->isStaticFile($location, $fileName, false))
+		if($this->isContentFile($fileName))
 		{
 		{
 			$fileName = $this->yellow->lookup->findFileNew($fileName,
 			$fileName = $this->yellow->lookup->findFileNew($fileName,
 				$this->yellow->config->get("webinterfaceNewFile"), $this->yellow->config->get("configDir"), "installation");
 				$this->yellow->config->get("webinterfaceNewFile"), $this->yellow->config->get("configDir"), "installation");
@@ -230,7 +346,7 @@ class YellowUpdate
 			curl_close($curlHandle);
 			curl_close($curlHandle);
 			if($statusCode == 200)
 			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)
 				foreach($this->yellow->toolbox->getTextLines($rawData) as $line)
 				{
 				{
 					preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
 					preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
@@ -238,7 +354,7 @@ class YellowUpdate
 					{
 					{
 						list($version, $url) = explode(',', $matches[2]);
 						list($version, $url) = explode(',', $matches[2]);
 						$data[$matches[1]] = $version;
 						$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 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()
 	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");
 	}
 	}
 }
 }