Browse Source

Updated system, new API

markseu 6 years ago
parent
commit
d51be4b9fe

+ 2 - 6
system/extensions/bundle.php

@@ -4,7 +4,7 @@
 // This file may be used and distributed under the terms of the public license.
 // This file may be used and distributed under the terms of the public license.
 
 
 class YellowBundle {
 class YellowBundle {
-    const VERSION = "0.8.2";
+    const VERSION = "0.8.3";
     const TYPE = "feature";
     const TYPE = "feature";
     public $yellow;         //access to API
     public $yellow;         //access to API
 
 
@@ -96,7 +96,6 @@ class YellowBundle {
             }
             }
         }
         }
         if (!empty($fileNames)) {
         if (!empty($fileNames)) {
-            $this->yellow->toolbox->timerStart($time);
             $id = substru(md5(implode($fileNames).$base), 0, 10);
             $id = substru(md5(implode($fileNames).$base), 0, 10);
             $fileNameBundle = $this->yellow->system->get("resourceDir")."bundle-$id.min.$type";;
             $fileNameBundle = $this->yellow->system->get("resourceDir")."bundle-$id.min.$type";;
             $locationBundle = $base.$this->yellow->system->get("resourceLocation")."bundle-$id.min.$type";
             $locationBundle = $base.$this->yellow->system->get("resourceLocation")."bundle-$id.min.$type";
@@ -124,10 +123,7 @@ class YellowBundle {
                     $this->yellow->page->error(500, "Can't write file '$fileNameBundle'!");
                     $this->yellow->page->error(500, "Can't write file '$fileNameBundle'!");
                 }
                 }
             }
             }
-            $this->yellow->toolbox->timerStop($time);
-            if (defined("DEBUG") && DEBUG>=2) {
-                $data["debug"] = "YellowBundle::processBundle file:$fileNameBundle time:$time ms<br/>\n";
-            }
+            if (defined("DEBUG") && DEBUG>=2) $data["debug"] = "YellowBundle::processBundle file:$fileNameBundle<br/>\n";
         }
         }
         return $data;
         return $data;
     }
     }

+ 5 - 6
system/extensions/command.php

@@ -4,8 +4,9 @@
 // This file may be used and distributed under the terms of the public license.
 // This file may be used and distributed under the terms of the public license.
 
 
 class YellowCommand {
 class YellowCommand {
-    const VERSION = "0.8.2";
+    const VERSION = "0.8.3";
     const TYPE = "feature";
     const TYPE = "feature";
+    const PRIORITY = "3";
     public $yellow;                     //access to API
     public $yellow;                     //access to API
     public $files;                      //number of files
     public $files;                      //number of files
     public $links;                      //number of links
     public $links;                      //number of links
@@ -440,10 +441,8 @@ class YellowCommand {
     public function broadcastCommand($args) {
     public function broadcastCommand($args) {
         $statusCode = 0;
         $statusCode = 0;
         foreach ($this->yellow->extensions->extensions as $key=>$value) {
         foreach ($this->yellow->extensions->extensions as $key=>$value) {
-            if ($key=="command") continue;
-            if (method_exists($value["obj"], "onCommand")) {
-                $statusCode = $value["obj"]->onCommand(func_get_args());
-                if ($statusCode!=0) break;
+            if (method_exists($value["obj"], "onCommand") && $key!="command") {
+                $statusCode = max($statusCode, $value["obj"]->onCommand(func_get_args()));
             }
             }
         }
         }
         return $statusCode;
         return $statusCode;
@@ -456,7 +455,7 @@ class YellowCommand {
         list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($url);
         list($scheme, $address, $base) = $this->yellow->lookup->getUrlInformation($url);
         if ($scheme=="http" && !empty($address)) {
         if ($scheme=="http" && !empty($address)) {
             if (!preg_match("/\:\d+$/", $address)) $address .= ":8000";
             if (!preg_match("/\:\d+$/", $address)) $address .= ":8000";
-            echo "Starting built-in web server on $scheme://$address\n";
+            echo "Starting built-in web server on $scheme://$address/\n";
             echo "Press Ctrl-C to quit...\n";
             echo "Press Ctrl-C to quit...\n";
             system("php -S $address yellow.php", $returnStatus);
             system("php -S $address yellow.php", $returnStatus);
             $statusCode = $returnStatus!=0 ? 500 : 200;
             $statusCode = $returnStatus!=0 ? 500 : 200;

+ 64 - 25
system/extensions/core.php

@@ -4,7 +4,7 @@
 // This file may be used and distributed under the terms of the public license.
 // This file may be used and distributed under the terms of the public license.
 
 
 class YellowCore {
 class YellowCore {
-    const VERSION = "0.8.2";
+    const VERSION = "0.8.3";
     const TYPE = "feature";
     const TYPE = "feature";
     public $page;           //current page
     public $page;           //current page
     public $content;        //content files from file system
     public $content;        //content files from file system
@@ -75,9 +75,9 @@ class YellowCore {
         $this->system->setDefault("downloadExtension", ".download");
         $this->system->setDefault("downloadExtension", ".download");
         $this->system->setDefault("systemFile", "system.ini");
         $this->system->setDefault("systemFile", "system.ini");
         $this->system->setDefault("textFile", "text.ini");
         $this->system->setDefault("textFile", "text.ini");
+        $this->system->setDefault("logFile", "yellow.log");
         $this->system->setDefault("safeMode", "0");
         $this->system->setDefault("safeMode", "0");
         $this->system->setDefault("multiLanguageMode", "0");
         $this->system->setDefault("multiLanguageMode", "0");
-        $this->system->setDefault("startupUpdate", "none");
         $this->system->setDefault("serverUrl", "");
         $this->system->setDefault("serverUrl", "");
     }
     }
     
     
@@ -87,9 +87,9 @@ class YellowCore {
     
     
     // Handle initialisation
     // Handle initialisation
     public function load() {
     public function load() {
-        if (defined("DEBUG") && DEBUG>=2) {
+        if (defined("DEBUG") && DEBUG>=3) {
             $serverVersion = $this->toolbox->getServerVersion();
             $serverVersion = $this->toolbox->getServerVersion();
-            echo "Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion<br/>\n";
+            echo "YellowCore::load Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion<br/>\n";
         }
         }
         $this->toolbox->timerStart($time);
         $this->toolbox->timerStart($time);
         $this->system->load($this->system->get("settingDir").$this->system->get("systemFile"));
         $this->system->load($this->system->get("settingDir").$this->system->get("systemFile"));
@@ -295,13 +295,11 @@ class YellowCore {
     // Handle startup
     // Handle startup
     public function startup() {
     public function startup() {
         $this->updateFileSystem(); //TODO: remove later, for backwards compatibility
         $this->updateFileSystem(); //TODO: remove later, for backwards compatibility
-        $tokens = explode(",", $this->system->get("startupUpdate"));
         foreach ($this->extensions->extensions as $key=>$value) {
         foreach ($this->extensions->extensions as $key=>$value) {
-            if (method_exists($value["obj"], "onStartup")) $value["obj"]->onStartup(in_array($key, $tokens));
+            if (method_exists($value["obj"], "onStartup")) $value["obj"]->onStartup();
         }
         }
-        if ($this->system->get("startupUpdate")!="none") {
-            $fileName = $this->system->get("settingDir").$this->system->get("systemFile");
-            $this->system->save($fileName, array("startupUpdate" => "none"));
+        foreach ($this->extensions->extensions as $key=>$value) {
+            if (method_exists($value["obj"], "onUpdate")) $value["obj"]->onUpdate("startup");
         }
         }
     }
     }
     
     
@@ -317,7 +315,8 @@ class YellowCore {
         $fileData = $fileDataNew = $this->toolbox->readFile("yellow.php");
         $fileData = $fileDataNew = $this->toolbox->readFile("yellow.php");
         $fileDataNew = str_replace("system/plugins/core.php", "system/extensions/core.php", $fileData);
         $fileDataNew = str_replace("system/plugins/core.php", "system/extensions/core.php", $fileData);
         if (is_dir("system/config/") || is_dir("system/themes/") || is_dir("system/plugins/") || $fileData!=$fileDataNew) {
         if (is_dir("system/config/") || is_dir("system/themes/") || is_dir("system/plugins/") || $fileData!=$fileDataNew) {
-            $fileNameError = "system/settings/system-error.log";
+            $statusCode = 200;
+            $this->log("info", "Update file system");
             if (is_dir("system/config/")) {
             if (is_dir("system/config/")) {
                 foreach ($this->toolbox->getDirectoryEntriesRecursive("system/config/", "/.*/", true, false) as $entry) {
                 foreach ($this->toolbox->getDirectoryEntriesRecursive("system/config/", "/.*/", true, false) as $entry) {
                     $entryNew = str_replace("system/config/", "system/settings/", $entry);
                     $entryNew = str_replace("system/config/", "system/settings/", $entry);
@@ -325,7 +324,8 @@ class YellowCore {
                     if (!is_file($entryNew)) $this->toolbox->copyFile($entry, $entryNew, true);
                     if (!is_file($entryNew)) $this->toolbox->copyFile($entry, $entryNew, true);
                 }
                 }
                 if (!$this->toolbox->deleteDirectory("system/config/", "system/trash/")) {
                 if (!$this->toolbox->deleteDirectory("system/config/", "system/trash/")) {
-                    $fileDataError .= "ERROR deleting folder 'system/config/'!\n";
+                    $statusCode = 500;
+                    $this->log("error", "Can't delete folder 'system/config/'!");
                 }
                 }
             }
             }
             if (is_dir("system/themes/")) {
             if (is_dir("system/themes/")) {
@@ -350,7 +350,8 @@ class YellowCore {
                     if (!is_file($entryNew)) $this->toolbox->copyFile($entry, $entryNew, true);
                     if (!is_file($entryNew)) $this->toolbox->copyFile($entry, $entryNew, true);
                 }
                 }
                 if (!$this->toolbox->deleteDirectory("system/themes/", "system/trash/")) {
                 if (!$this->toolbox->deleteDirectory("system/themes/", "system/trash/")) {
-                    $fileDataError .= "ERROR deleting folder 'system/themes/'!\n";
+                    $statusCode = 500;
+                    $this->log("error", "Can't delete folder 'system/themes/'!");
                 }
                 }
             }
             }
             if (is_dir("system/plugins/")) {
             if (is_dir("system/plugins/")) {
@@ -359,12 +360,14 @@ class YellowCore {
                     if (!is_file($entryNew)) $this->toolbox->copyFile($entry, $entryNew, true);
                     if (!is_file($entryNew)) $this->toolbox->copyFile($entry, $entryNew, true);
                 }
                 }
                 if (!$this->toolbox->deleteDirectory("system/plugins/", "system/trash/")) {
                 if (!$this->toolbox->deleteDirectory("system/plugins/", "system/trash/")) {
-                    $fileDataError .= "ERROR deleting folder 'system/plugins/'!\n";
+                    $statusCode = 500;
+                    $this->log("error", "Can't delete folder 'system/plugins/'!");
                 }
                 }
             }
             }
             if (function_exists("opcache_reset")) opcache_reset();
             if (function_exists("opcache_reset")) opcache_reset();
             if ($fileData!=$fileDataNew && !$this->toolbox->createFile("yellow.php", $fileDataNew)) {
             if ($fileData!=$fileDataNew && !$this->toolbox->createFile("yellow.php", $fileDataNew)) {
-                $fileDataError .= "ERROR writing file 'yellow.php'!\n";
+                $statusCode = 500;
+                $this->log("error", "Can't write file 'yellow.php'!");
             }
             }
             foreach ($this->toolbox->getDirectoryEntries("system/extensions/", "/^.*\.php$/", true, false) as $entry) {
             foreach ($this->toolbox->getDirectoryEntries("system/extensions/", "/^.*\.php$/", true, false) as $entry) {
                 $fileData = $fileDataNew = $this->toolbox->readFile($entry);
                 $fileData = $fileDataNew = $this->toolbox->readFile($entry);
@@ -372,18 +375,32 @@ class YellowCore {
                 if (preg_match("/^core\.php$/", basename($entry))) continue;
                 if (preg_match("/^core\.php$/", basename($entry))) continue;
                 if ($fileData!=$fileDataNew) $this->toolbox->createFile($entry, $fileDataNew);
                 if ($fileData!=$fileDataNew) $this->toolbox->createFile($entry, $fileDataNew);
             }
             }
-            $this->system->save("system/settings/system.ini", array("startupUpdate" => "update"));
-            if (!empty($fileDataError)) $this->toolbox->createFile($fileNameError, $fileDataError);
-            @header($this->toolbox->getHttpStatusFormatted(empty($fileDataError) ? 200 : 500));
-            die(empty($fileDataError) ? "System has been updated. Please update your website one more time.\n" :
-                "System has not been updated. Please check errors in file '$fileNameError'!\n");
+            $this->system->save("system/settings/system.ini", array("updateNotification" => "update/update"));
+            @header($this->toolbox->getHttpStatusFormatted($statusCode));
+            die($statusCode==200 ? "System has been updated. Please update your website one more time.\n" :
+                "System has not been updated. Please check errors in file 'system/extensions/yellow.log'!\n");
+        }
+    }
+    
+    // Handle logging
+    public function log($action, $message) {
+        $statusCode = 0;
+        foreach ($this->extensions->extensions as $key=>$value) {
+            if (method_exists($value["obj"], "onLog")) {
+                $statusCode = $value["obj"]->onLog($action, $message);
+                if ($statusCode!=0) break;
+            }
+        }
+        if ($statusCode==0) {
+            $line = date("Y-m-d H:i:s")." ".trim($action)." ".trim($message)."\n";
+            $this->toolbox->appendFile($this->system->get("extensionDir").$this->system->get("logFile"), $line);
         }
         }
     }
     }
     
     
     // Include layout
     // Include layout
     public function layout($name, $args = null) {
     public function layout($name, $args = null) {
         $this->lookup->layoutArgs = func_get_args();
         $this->lookup->layoutArgs = func_get_args();
-        $this->page->includePageLayout($name);
+        $this->page->includeLayout($name);
     }
     }
 
 
     public function snippet($name, $args = null) {  //TODO: remove later, for backwards compatibility
     public function snippet($name, $args = null) {  //TODO: remove later, for backwards compatibility
@@ -565,9 +582,9 @@ class YellowPage {
     public function parseContent($sizeMax = 0) {
     public function parseContent($sizeMax = 0) {
         if (!is_object($this->parser)) {
         if (!is_object($this->parser)) {
             if ($this->yellow->extensions->isExisting($this->get("parser"))) {
             if ($this->yellow->extensions->isExisting($this->get("parser"))) {
-                $extension = $this->yellow->extensions->extensions[$this->get("parser")];
-                if (method_exists($extension["obj"], "onParseContentRaw")) {
-                    $this->parser = $extension["obj"];
+                $value = $this->yellow->extensions->extensions[$this->get("parser")];
+                if (method_exists($value["obj"], "onParseContentRaw")) {
+                    $this->parser = $value["obj"];
                     $this->parserData = $this->getContent(true, $sizeMax);
                     $this->parserData = $this->getContent(true, $sizeMax);
                     $this->parserData = preg_replace("/@pageRead/i", $this->get("pageRead"), $this->parserData);
                     $this->parserData = preg_replace("/@pageRead/i", $this->get("pageRead"), $this->parserData);
                     $this->parserData = preg_replace("/@pageEdit/i", $this->get("pageEdit"), $this->parserData);
                     $this->parserData = preg_replace("/@pageEdit/i", $this->get("pageEdit"), $this->parserData);
@@ -681,22 +698,24 @@ class YellowPage {
         }
         }
         if (is_null($this->outputData)) {
         if (is_null($this->outputData)) {
             ob_start();
             ob_start();
-            $this->includePageLayout($name);
+            $this->includeLayout($name);
             $this->outputData = ob_get_contents();
             $this->outputData = ob_get_contents();
             ob_end_clean();
             ob_end_clean();
         }
         }
     }
     }
     
     
     // Include page layout
     // Include page layout
-    public function includePageLayout($name) {
+    public function includeLayout($name) {
         $fileNameLayoutBasic = $this->yellow->system->get("layoutDir").$this->yellow->lookup->normaliseName($name).".html";
         $fileNameLayoutBasic = $this->yellow->system->get("layoutDir").$this->yellow->lookup->normaliseName($name).".html";
         $fileNameLayoutTheme = $this->yellow->system->get("layoutDir").
         $fileNameLayoutTheme = $this->yellow->system->get("layoutDir").
             $this->yellow->lookup->normaliseName($name)."-".$this->yellow->lookup->normaliseName($this->get("theme")).".html";
             $this->yellow->lookup->normaliseName($name)."-".$this->yellow->lookup->normaliseName($this->get("theme")).".html";
         if (is_file($fileNameLayoutTheme)) {
         if (is_file($fileNameLayoutTheme)) {
+            if (defined("DEBUG") && DEBUG>=2) echo "YellowPage::includeLayout file:$fileNameLayoutTheme<br>\n";
             $this->setLastModified(filemtime($fileNameLayoutTheme));
             $this->setLastModified(filemtime($fileNameLayoutTheme));
             global $yellow; //TODO: remove later, for backwards compatibility
             global $yellow; //TODO: remove later, for backwards compatibility
             require($fileNameLayoutTheme);
             require($fileNameLayoutTheme);
         } elseif (is_file($fileNameLayoutBasic)) {
         } elseif (is_file($fileNameLayoutBasic)) {
+            if (defined("DEBUG") && DEBUG>=2) echo "YellowPage::includeLayout file:$fileNameLayoutBasic<br>\n";
             $this->setLastModified(filemtime($fileNameLayoutBasic));
             $this->setLastModified(filemtime($fileNameLayoutBasic));
             global $yellow; //TODO: remove later, for backwards compatibility
             global $yellow; //TODO: remove later, for backwards compatibility
             require($fileNameLayoutBasic);
             require($fileNameLayoutBasic);
@@ -2605,6 +2624,26 @@ class YellowToolbox {
         return $ok;
         return $ok;
     }
     }
     
     
+    // Append file
+    public function appendFile($fileName, $fileData, $mkdir = false) {
+        $ok = false;
+        if ($mkdir) {
+            $path = dirname($fileName);
+            if (!empty($path) && !is_dir($path)) @mkdir($path, 0777, true);
+        }
+        $fileHandle = @fopen($fileName, "ab");
+        if ($fileHandle) {
+            clearstatcache(true, $fileName);
+            if (flock($fileHandle, LOCK_EX)) {
+                fwrite($fileHandle, $fileData);
+                flock($fileHandle, LOCK_UN);
+            }
+            fclose($fileHandle);
+            $ok = true;
+        }
+        return $ok;
+    }
+    
     // Copy file
     // Copy file
     public function copyFile($fileNameSource, $fileNameDestination, $mkdir = false) {
     public function copyFile($fileNameSource, $fileNameDestination, $mkdir = false) {
         clearstatcache();
         clearstatcache();

+ 5 - 5
system/extensions/edit.js

@@ -331,7 +331,7 @@ yellow.edit = {
         var showFields = paneStatus!="next" && paneStatus!="done";
         var showFields = paneStatus!="next" && paneStatus!="done";
         switch (paneId) {
         switch (paneId) {
             case "yellow-pane-login":
             case "yellow-pane-login":
-                if (yellow.system.editLoginRestrictions) {
+                if (yellow.system.editLoginRestriction) {
                     yellow.toolbox.setVisible(document.getElementById("yellow-pane-login-signup"), false);
                     yellow.toolbox.setVisible(document.getElementById("yellow-pane-login-signup"), false);
                 }
                 }
                 break;
                 break;
@@ -389,12 +389,12 @@ yellow.edit = {
                         yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-toolbar-title"), false);
                         yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-toolbar-title"), false);
                         this.updateToolbar(0, "yellow-toolbar-checked");
                         this.updateToolbar(0, "yellow-toolbar-checked");
                     }
                     }
-                    if (yellow.system.userRestrictions) {
+                    if (yellow.system.userRestriction) {
                         yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-send"), false);
                         yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-send"), false);
                         document.getElementById("yellow-pane-edit-text").readOnly = true;
                         document.getElementById("yellow-pane-edit-text").readOnly = true;
                     }
                     }
                 }
                 }
-                if (!yellow.system.userRestrictions) {
+                if (!yellow.system.userRestriction) {
                     var key, className;
                     var key, className;
                     switch (this.getAction(paneId, paneAction)) {
                     switch (this.getAction(paneId, paneAction)) {
                         case "create":    key = "CreateButton"; className = "yellow-toolbar-btn yellow-toolbar-btn-create"; break;
                         case "create":    key = "CreateButton"; className = "yellow-toolbar-btn yellow-toolbar-btn-create"; break;
@@ -556,7 +556,7 @@ yellow.edit = {
         if (yellow.system.debug) console.log("yellow.edit.processToolbar status:"+status);
         if (yellow.system.debug) console.log("yellow.edit.processToolbar status:"+status);
         var elementText = document.getElementById("yellow-pane-edit-text");
         var elementText = document.getElementById("yellow-pane-edit-text");
         var elementPreview = document.getElementById("yellow-pane-edit-preview");
         var elementPreview = document.getElementById("yellow-pane-edit-preview");
-        if (!yellow.system.userRestrictions && this.paneAction!="delete" && !yellow.toolbox.isVisible(elementPreview)) {
+        if (!yellow.system.userRestriction && this.paneAction!="delete" && !yellow.toolbox.isVisible(elementPreview)) {
             switch (status) {
             switch (status) {
                 case "h1":              yellow.editor.setMarkdown(elementText, "# ", "insert-multiline-block", true); break;
                 case "h1":              yellow.editor.setMarkdown(elementText, "# ", "insert-multiline-block", true); break;
                 case "h2":              yellow.editor.setMarkdown(elementText, "## ", "insert-multiline-block", true); break;
                 case "h2":              yellow.editor.setMarkdown(elementText, "## ", "insert-multiline-block", true); break;
@@ -581,7 +581,7 @@ yellow.edit = {
             }
             }
         }
         }
         if (status=="preview") this.showPreview(elementText, elementPreview);
         if (status=="preview") this.showPreview(elementText, elementPreview);
-        if (status=="save" && !yellow.system.userRestrictions && this.paneAction!="delete") this.action("send");
+        if (status=="save" && !yellow.system.userRestriction && this.paneAction!="delete") this.action("send");
         if (status=="help") window.open(this.getText("HelpUrl", "yellow"), "_blank");
         if (status=="help") window.open(this.getText("HelpUrl", "yellow"), "_blank");
         if (status=="markdown") window.open(this.getText("MarkdownUrl", "yellow"), "_blank");
         if (status=="markdown") window.open(this.getText("MarkdownUrl", "yellow"), "_blank");
         if (status=="format" || status=="heading" || status=="list" || status=="emojiawesome" || status=="fontawesome") {
         if (status=="format" || status=="heading" || status=="list" || status=="emojiawesome" || status=="fontawesome") {

+ 57 - 57
system/extensions/edit.php

@@ -4,7 +4,7 @@
 // This file may be used and distributed under the terms of the public license.
 // This file may be used and distributed under the terms of the public license.
 
 
 class YellowEdit {
 class YellowEdit {
-    const VERSION = "0.8.2";
+    const VERSION = "0.8.3";
     const TYPE = "feature";
     const TYPE = "feature";
     public $yellow;         //access to API
     public $yellow;         //access to API
     public $response;       //web response
     public $response;       //web response
@@ -29,35 +29,11 @@ class YellowEdit {
         $this->yellow->system->setDefault("editUserHashCost", "10");
         $this->yellow->system->setDefault("editUserHashCost", "10");
         $this->yellow->system->setDefault("editUserHome", "/");
         $this->yellow->system->setDefault("editUserHome", "/");
         $this->yellow->system->setDefault("editNewFile", "page-new-(.*).md");
         $this->yellow->system->setDefault("editNewFile", "page-new-(.*).md");
-        $this->yellow->system->setDefault("editLoginRestrictions", "0");
+        $this->yellow->system->setDefault("editLoginRestriction", "0");
         $this->yellow->system->setDefault("editLoginSessionTimeout", "2592000");
         $this->yellow->system->setDefault("editLoginSessionTimeout", "2592000");
         $this->yellow->system->setDefault("editBruteForceProtection", "25");
         $this->yellow->system->setDefault("editBruteForceProtection", "25");
         $this->users->load($this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile"));
         $this->users->load($this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile"));
     }
     }
-
-    // Handle startup
-    public function onStartup($update) {
-        if ($update) {
-            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
-            $fileData = $this->yellow->toolbox->readFile($fileNameUser);
-            foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
-                preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-                if (!empty($matches[1]) && !empty($matches[2]) && $matches[1][0]!="#") {
-                    list($hash, $name, $language, $status, $stamp, $modified, $errors, $pending, $home) = explode(",", $matches[2]);
-                    if ($status!="active" && $status!="inactive") {
-                        unset($this->users->users[$matches[1]]);
-                        continue;
-                    }
-                    $pending = "none";
-                    $this->users->set($matches[1], $hash, $name, $language, $status, $stamp, $modified, $errors, $pending, $home);
-                    $fileDataNew .= "$matches[1]: $hash,$name,$language,$status,$stamp,$modified,$errors,$pending,$home\n";
-                } else {
-                    $fileDataNew .= $line;
-                }
-            }
-            if ($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileNameUser, $fileDataNew);
-        }
-    }
     
     
     // Handle request
     // Handle request
     public function onRequest($scheme, $address, $base, $location, $fileName) {
     public function onRequest($scheme, $address, $base, $location, $fileName) {
@@ -133,6 +109,30 @@ class YellowEdit {
         return "user [option email password name]\n";
         return "user [option email password name]\n";
     }
     }
 
 
+    // Handle update
+    public function onUpdate($action) {
+        if ($action=="update") {
+            $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
+            $fileData = $this->yellow->toolbox->readFile($fileNameUser);
+            foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
+                preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
+                if (!empty($matches[1]) && !empty($matches[2]) && $matches[1][0]!="#") {
+                    list($hash, $name, $language, $status, $stamp, $modified, $errors, $pending, $home) = explode(",", $matches[2]);
+                    if ($status!="active" && $status!="inactive") {
+                        unset($this->users->users[$matches[1]]);
+                        continue;
+                    }
+                    $pending = "none";
+                    $this->users->set($matches[1], $hash, $name, $language, $status, $stamp, $modified, $errors, $pending, $home);
+                    $fileDataNew .= "$matches[1]: $hash,$name,$language,$status,$stamp,$modified,$errors,$pending,$home\n";
+                } else {
+                    $fileDataNew .= $line;
+                }
+            }
+            if ($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileNameUser, $fileDataNew);
+        }
+    }
+    
     // Process command to update user account
     // Process command to update user account
     public function processCommandUser($args) {
     public function processCommandUser($args) {
         list($command, $option) = $args;
         list($command, $option) = $args;
@@ -276,7 +276,7 @@ class YellowEdit {
                 $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
                 $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
                 $statusCode = $this->yellow->sendStatus(301, $location);
                 $statusCode = $this->yellow->sendStatus(301, $location);
             } else {
             } else {
-                $this->yellow->page->error($this->response->isUserRestrictions() ? 404 : 434);
+                $this->yellow->page->error($this->response->isUserRestriction() ? 404 : 434);
                 $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
                 $statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
             }
             }
         }
         }
@@ -325,7 +325,7 @@ class YellowEdit {
         $consent = trim($_REQUEST["consent"]);
         $consent = trim($_REQUEST["consent"]);
         if (empty($name) || empty($email) || empty($password) || empty($consent)) $this->response->status = "incomplete";
         if (empty($name) || empty($email) || empty($password) || empty($consent)) $this->response->status = "incomplete";
         if ($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
         if ($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
-        if ($this->response->status=="ok" && $this->response->isLoginRestrictions()) $this->response->status = "next";
+        if ($this->response->status=="ok" && $this->response->isLoginRestriction()) $this->response->status = "next";
         if ($this->response->status=="ok" && $this->users->isTaken($email)) $this->response->status = "next";
         if ($this->response->status=="ok" && $this->users->isTaken($email)) $this->response->status = "next";
         if ($this->response->status=="ok") {
         if ($this->response->status=="ok") {
             $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
@@ -639,7 +639,7 @@ class YellowEdit {
     // Process request to create page
     // Process request to create page
     public function processRequestCreate($scheme, $address, $base, $location, $fileName) {
     public function processRequestCreate($scheme, $address, $base, $location, $fileName) {
         $statusCode = 0;
         $statusCode = 0;
-        if (!$this->response->isUserRestrictions() && !empty($_REQUEST["rawdataedit"])) {
+        if (!$this->response->isUserRestriction() && !empty($_REQUEST["rawdataedit"])) {
             $this->response->rawDataSource = $_REQUEST["rawdatasource"];
             $this->response->rawDataSource = $_REQUEST["rawdatasource"];
             $this->response->rawDataEdit = $_REQUEST["rawdatasource"];
             $this->response->rawDataEdit = $_REQUEST["rawdatasource"];
             $this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
             $this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
@@ -665,7 +665,7 @@ class YellowEdit {
     // Process request to edit page
     // Process request to edit page
     public function processRequestEdit($scheme, $address, $base, $location, $fileName) {
     public function processRequestEdit($scheme, $address, $base, $location, $fileName) {
         $statusCode = 0;
         $statusCode = 0;
-        if (!$this->response->isUserRestrictions() && !empty($_REQUEST["rawdataedit"])) {
+        if (!$this->response->isUserRestriction() && !empty($_REQUEST["rawdataedit"])) {
             $this->response->rawDataSource = $_REQUEST["rawdatasource"];
             $this->response->rawDataSource = $_REQUEST["rawdatasource"];
             $this->response->rawDataEdit = $_REQUEST["rawdataedit"];
             $this->response->rawDataEdit = $_REQUEST["rawdataedit"];
             $this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
             $this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
@@ -703,7 +703,7 @@ class YellowEdit {
     // Process request to delete page
     // Process request to delete page
     public function processRequestDelete($scheme, $address, $base, $location, $fileName) {
     public function processRequestDelete($scheme, $address, $base, $location, $fileName) {
         $statusCode = 0;
         $statusCode = 0;
-        if (!$this->response->isUserRestrictions() && is_file($fileName)) {
+        if (!$this->response->isUserRestriction() && is_file($fileName)) {
             $this->response->rawDataSource = $_REQUEST["rawdatasource"];
             $this->response->rawDataSource = $_REQUEST["rawdatasource"];
             $this->response->rawDataEdit = $_REQUEST["rawdatasource"];
             $this->response->rawDataEdit = $_REQUEST["rawdatasource"];
             $this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
             $this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
@@ -756,7 +756,7 @@ class YellowEdit {
         $fileSizeMax = $this->yellow->toolbox->getNumberBytes(ini_get("upload_max_filesize"));
         $fileSizeMax = $this->yellow->toolbox->getNumberBytes(ini_get("upload_max_filesize"));
         $extension = strtoloweru(($pos = strrposu($fileNameShort, ".")) ? substru($fileNameShort, $pos) : "");
         $extension = strtoloweru(($pos = strrposu($fileNameShort, ".")) ? substru($fileNameShort, $pos) : "");
         $extensions = preg_split("/\s*,\s*/", $this->yellow->system->get("editUploadExtensions"));
         $extensions = preg_split("/\s*,\s*/", $this->yellow->system->get("editUploadExtensions"));
-        if (!$this->response->isUserRestrictions() && is_uploaded_file($fileNameTemp) &&
+        if (!$this->response->isUserRestriction() && is_uploaded_file($fileNameTemp) &&
            filesize($fileNameTemp)<=$fileSizeMax && in_array($extension, $extensions)) {
            filesize($fileNameTemp)<=$fileSizeMax && in_array($extension, $extensions)) {
             $file = $this->response->getFileUpload($scheme, $address, $base, $location, $fileNameTemp, $fileNameShort);
             $file = $this->response->getFileUpload($scheme, $address, $base, $location, $fileNameTemp, $fileNameShort);
             if (!$file->isError() && $this->yellow->toolbox->copyFile($fileNameTemp, $file->fileName, true)) {
             if (!$file->isError() && $this->yellow->toolbox->copyFile($fileNameTemp, $file->fileName, true)) {
@@ -787,7 +787,7 @@ class YellowEdit {
                 if ($this->users->checkAuthLogin($email, $password)) {
                 if ($this->users->checkAuthLogin($email, $password)) {
                     $this->response->createCookies($scheme, $address, $base, $email);
                     $this->response->createCookies($scheme, $address, $base, $email);
                     $this->response->userEmail = $email;
                     $this->response->userEmail = $email;
-                    $this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
+                    $this->response->userRestriction = $this->getUserRestriction($email, $location, $fileName);
                     $this->response->language = $this->getUserLanguage($email);
                     $this->response->language = $this->getUserLanguage($email);
                 } else {
                 } else {
                     $this->response->userFailedError = "login";
                     $this->response->userFailedError = "login";
@@ -797,7 +797,7 @@ class YellowEdit {
             } elseif (isset($_COOKIE["authtoken"]) && isset($_COOKIE["csrftoken"])) {
             } elseif (isset($_COOKIE["authtoken"]) && isset($_COOKIE["csrftoken"])) {
                 if ($this->users->checkAuthToken($_COOKIE["authtoken"], $_COOKIE["csrftoken"], $_POST["csrftoken"], $_REQUEST["action"]=="")) {
                 if ($this->users->checkAuthToken($_COOKIE["authtoken"], $_COOKIE["csrftoken"], $_POST["csrftoken"], $_REQUEST["action"]=="")) {
                     $this->response->userEmail = $email = $this->users->getAuthEmail($_COOKIE["authtoken"]);
                     $this->response->userEmail = $email = $this->users->getAuthEmail($_COOKIE["authtoken"]);
-                    $this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
+                    $this->response->userRestriction = $this->getUserRestriction($email, $location, $fileName);
                     $this->response->language = $this->getUserLanguage($email);
                     $this->response->language = $this->getUserLanguage($email);
                 } else {
                 } else {
                     $this->response->userFailedError = "auth";
                     $this->response->userFailedError = "auth";
@@ -892,20 +892,20 @@ class YellowEdit {
         return $status;
         return $status;
     }
     }
     
     
-    // Return user restrictions
-    public function getUserRestrictions($email, $location, $fileName) {
-        $userRestrictions = null;
+    // Return user restriction
+    public function getUserRestriction($email, $location, $fileName) {
+        $userRestriction = null;
         foreach ($this->yellow->extensions->extensions as $key=>$value) {
         foreach ($this->yellow->extensions->extensions as $key=>$value) {
-            if (method_exists($value["obj"], "onEditUserRestrictions")) {
-                $userRestrictions = $value["obj"]->onEditUserRestrictions($email, $location, $fileName, $this->users);
-                if (!is_null($userRestrictions)) break;
+            if (method_exists($value["obj"], "onEditUserRestriction")) {
+                $userRestriction = $value["obj"]->onEditUserRestriction($email, $location, $fileName, $this->users);
+                if (!is_null($userRestriction)) break;
             }
             }
         }
         }
-        if (is_null($userRestrictions)) {
-            $userRestrictions = substru($location, 0, strlenu($this->users->getHome($email)))!=$this->users->getHome($email);
-            $userRestrictions |= empty($fileName) || strlenu(dirname($fileName))>128 || strlenu(basename($fileName))>128;
+        if (is_null($userRestriction)) {
+            $userRestriction = substru($location, 0, strlenu($this->users->getHome($email)))!=$this->users->getHome($email);
+            $userRestriction |= empty($fileName) || strlenu(dirname($fileName))>128 || strlenu(basename($fileName))>128;
         }
         }
-        return $userRestrictions;
+        return $userRestriction;
     }
     }
     
     
     // Return user language
     // Return user language
@@ -928,7 +928,7 @@ class YellowResponse {
     public $extension;          //access to extension
     public $extension;          //access to extension
     public $active;             //location is active? (boolean)
     public $active;             //location is active? (boolean)
     public $userEmail;          //user email
     public $userEmail;          //user email
-    public $userRestrictions;   //user can change page? (boolean)
+    public $userRestriction;    //user with restriction? (boolean)
     public $userFailedError;    //error of failed authentication
     public $userFailedError;    //error of failed authentication
     public $userFailedEmail;    //email of failed authentication
     public $userFailedEmail;    //email of failed authentication
     public $userFailedExpire;   //expiration time of failed authentication
     public $userFailedExpire;   //expiration time of failed authentication
@@ -967,7 +967,7 @@ class YellowResponse {
         } else {
         } else {
             $page->fileName = $this->getPageNewFile($page->location);
             $page->fileName = $this->getPageNewFile($page->location);
         }
         }
-        if ($this->extension->getUserRestrictions($this->userEmail, $page->location, $page->fileName)) {
+        if ($this->extension->getUserRestriction($this->userEmail, $page->location, $page->fileName)) {
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
         }
         }
         return $page;
         return $page;
@@ -994,8 +994,8 @@ class YellowResponse {
             }
             }
         }
         }
         if (empty($page->rawData)) $page->error(500, "Page has been modified by someone else!");
         if (empty($page->rawData)) $page->error(500, "Page has been modified by someone else!");
-        if ($this->extension->getUserRestrictions($this->userEmail, $page->location, $page->fileName) ||
-            $this->extension->getUserRestrictions($this->userEmail, $pageSource->location, $pageSource->fileName)) {
+        if ($this->extension->getUserRestriction($this->userEmail, $page->location, $page->fileName) ||
+            $this->extension->getUserRestriction($this->userEmail, $pageSource->location, $pageSource->fileName)) {
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
         }
         }
         return $page;
         return $page;
@@ -1007,7 +1007,7 @@ class YellowResponse {
         $page->setRequestInformation($scheme, $address, $base, $location, $fileName);
         $page->setRequestInformation($scheme, $address, $base, $location, $fileName);
         $page->parseData($this->normaliseLines($rawData, $endOfLine), false, 0);
         $page->parseData($this->normaliseLines($rawData, $endOfLine), false, 0);
         $this->editContentFile($page, "delete");
         $this->editContentFile($page, "delete");
-        if ($this->extension->getUserRestrictions($this->userEmail, $page->location, $page->fileName)) {
+        if ($this->extension->getUserRestriction($this->userEmail, $page->location, $page->fileName)) {
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
             $page->error(500, "Page '".$page->get("title")."' is restricted!");
         }
         }
         return $page;
         return $page;
@@ -1080,7 +1080,7 @@ class YellowResponse {
             $data["userLanguage"] = $this->extension->users->getLanguage($this->userEmail);
             $data["userLanguage"] = $this->extension->users->getLanguage($this->userEmail);
             $data["userStatus"] = $this->extension->users->getStatus($this->userEmail);
             $data["userStatus"] = $this->extension->users->getStatus($this->userEmail);
             $data["userHome"] = $this->extension->users->getHome($this->userEmail);
             $data["userHome"] = $this->extension->users->getHome($this->userEmail);
-            $data["userRestrictions"] = intval($this->isUserRestrictions());
+            $data["userRestriction"] = intval($this->isUserRestriction());
             $data["userWebmaster"] = intval($this->isUserWebmaster());
             $data["userWebmaster"] = intval($this->isUserWebmaster());
             $data["serverScheme"] = $this->yellow->system->get("serverScheme");
             $data["serverScheme"] = $this->yellow->system->get("serverScheme");
             $data["serverAddress"] = $this->yellow->system->get("serverAddress");
             $data["serverAddress"] = $this->yellow->system->get("serverAddress");
@@ -1103,7 +1103,7 @@ class YellowResponse {
         } else {
         } else {
             $data["editLoginEmail"] = $this->yellow->page->get("editLoginEmail");
             $data["editLoginEmail"] = $this->yellow->page->get("editLoginEmail");
             $data["editLoginPassword"] = $this->yellow->page->get("editLoginPassword");
             $data["editLoginPassword"] = $this->yellow->page->get("editLoginPassword");
-            $data["editLoginRestrictions"] = intval($this->isLoginRestrictions());
+            $data["editLoginRestriction"] = intval($this->isLoginRestriction());
         }
         }
         if (defined("DEBUG") && DEBUG>=1) $data["debug"] = DEBUG;
         if (defined("DEBUG") && DEBUG>=1) $data["debug"] = DEBUG;
         return $data;
         return $data;
@@ -1437,14 +1437,14 @@ class YellowResponse {
         return !empty($this->userEmail) && $this->userEmail==$this->yellow->system->get("email");
         return !empty($this->userEmail) && $this->userEmail==$this->yellow->system->get("email");
     }
     }
     
     
-    // Check if user has restrictions
-    public function isUserRestrictions() {
-        return empty($this->userEmail) || $this->userRestrictions;
+    // Check if user with restriction
+    public function isUserRestriction() {
+        return empty($this->userEmail) || $this->userRestriction;
     }
     }
     
     
-    // Check if login has restrictions
-    public function isLoginRestrictions() {
-        return $this->yellow->system->get("editLoginRestrictions");
+    // Check if login with restriction
+    public function isLoginRestriction() {
+        return $this->yellow->system->get("editLoginRestriction");
     }
     }
 }
 }
 
 

+ 46 - 16
system/extensions/install.php

@@ -4,7 +4,7 @@
 // This file may be used and distributed under the terms of the public license.
 // This file may be used and distributed under the terms of the public license.
 
 
 class YellowInstall {
 class YellowInstall {
-    const VERSION = "0.8.2";
+    const VERSION = "0.8.3";
     const TYPE = "feature";
     const TYPE = "feature";
     const PRIORITY = "1";
     const PRIORITY = "1";
     public $yellow;                 //access to API
     public $yellow;                 //access to API
@@ -33,7 +33,8 @@ class YellowInstall {
     
     
     // Process command to install website
     // Process command to install website
     public function processCommandInstall() {
     public function processCommandInstall() {
-        $statusCode = $this->updateLanguages();
+        $statusCode = $this->updateLog();
+        if ($statusCode==200) $statusCode = $this->updateLanguage();
         if ($statusCode==200) $statusCode = $this->updateSettings($this->getSystemData());
         if ($statusCode==200) $statusCode = $this->updateSettings($this->getSystemData());
         if ($statusCode==200) $statusCode = $this->removeFiles();
         if ($statusCode==200) $statusCode = $this->removeFiles();
         if ($statusCode==200) {
         if ($statusCode==200) {
@@ -47,16 +48,16 @@ class YellowInstall {
     
     
     // Process request to install website
     // Process request to install website
     public function processRequestInstall($scheme, $address, $base, $location, $fileName) {
     public function processRequestInstall($scheme, $address, $base, $location, $fileName) {
-        $statusCode = 0;
         $name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
         $name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
         $email = trim($_REQUEST["email"]);
         $email = trim($_REQUEST["email"]);
         $password = trim($_REQUEST["password"]);
         $password = trim($_REQUEST["password"]);
         $language = trim($_REQUEST["language"]);
         $language = trim($_REQUEST["language"]);
         $extension = trim($_REQUEST["extension"]);
         $extension = trim($_REQUEST["extension"]);
         $status = trim($_REQUEST["status"]);
         $status = trim($_REQUEST["status"]);
+        $statusCode = $this->updateLog();
+        $statusCode = max($statusCode, $this->updateLanguage());
         $this->yellow->content->pages["root/"] = array();
         $this->yellow->content->pages["root/"] = array();
         $this->yellow->page = new YellowPage($this->yellow);
         $this->yellow->page = new YellowPage($this->yellow);
-        $statusCode = $this->updateLanguages();
         $this->yellow->page->setRequestInformation($scheme, $address, $base, $location, $fileName);
         $this->yellow->page->setRequestInformation($scheme, $address, $base, $location, $fileName);
         $this->yellow->page->parseData($this->getRawDataInstall(), false, $statusCode, $this->yellow->page->get("pageError"));
         $this->yellow->page->parseData($this->getRawDataInstall(), false, $statusCode, $this->yellow->page->get("pageError"));
         $this->yellow->page->safeMode = false;
         $this->yellow->page->safeMode = false;
@@ -65,8 +66,8 @@ class YellowInstall {
         if ($status=="ok") $status = $this->updateContent($language, "Home", "/")==200 ? "ok" : "error";
         if ($status=="ok") $status = $this->updateContent($language, "Home", "/")==200 ? "ok" : "error";
         if ($status=="ok") $status = $this->updateContent($language, "About", "/about/")==200 ? "ok" : "error";
         if ($status=="ok") $status = $this->updateContent($language, "About", "/about/")==200 ? "ok" : "error";
         if ($status=="ok") $status = $this->updateContent($language, "Footer", "/shared/footer")==200 ? "ok" : "error";
         if ($status=="ok") $status = $this->updateContent($language, "Footer", "/shared/footer")==200 ? "ok" : "error";
-        if ($status=="ok") $status = $this->updateSettings($this->getSystemData()) ? "ok" : "error";
-        if ($status=="ok") $status = $this->removeFiles() ? "done" : "error";
+        if ($status=="ok") $status = $this->updateSettings($this->getSystemData())==200 ? "ok" : "error";
+        if ($status=="ok") $status = $this->removeFiles()==200 ? "done" : "error";
         if ($status=="done") {
         if ($status=="done") {
             $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
             $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
             $statusCode = $this->yellow->sendStatus(303, $location);
             $statusCode = $this->yellow->sendStatus(303, $location);
@@ -76,24 +77,44 @@ class YellowInstall {
         return $statusCode;
         return $statusCode;
     }
     }
     
     
-    // Update languages
-    public function updateLanguages() {
+    // Update log
+    public function updateLog() {
+        $statusCode = 200;
+        $fileName = $this->yellow->system->get("extensionDir").$this->yellow->system->get("logFile");
+        if (!is_file($fileName)) {
+            $serverVersion = $this->yellow->toolbox->getServerVersion();
+            $this->yellow->log("info", "Datenstrom Yellow ".YellowCore::VERSION.", PHP ".PHP_VERSION.", $serverVersion");
+            if (!$this->yellow->isCommandLine()) {
+                $server = $this->yellow->toolbox->getServerVersion(true);
+                $this->yellow->log("info", "Checked $server server configuration");
+            }
+            if (!is_file($fileName)) {
+                $statusCode = 500;
+                $this->yellow->page->error(500, "Can't write file '$fileName'!");
+            }
+        }
+        return $statusCode;
+    }
+    
+    // Update language
+    public function updateLanguage() {
         $statusCode = 200;
         $statusCode = 200;
         $path = $this->yellow->system->get("extensionDir")."install-languages.zip";
         $path = $this->yellow->system->get("extensionDir")."install-languages.zip";
         if (is_file($path) && $this->yellow->extensions->isExisting("update")) {
         if (is_file($path) && $this->yellow->extensions->isExisting("update")) {
             $zip = new ZipArchive();
             $zip = new ZipArchive();
             if ($zip->open($path)===true) {
             if ($zip->open($path)===true) {
-                if (defined("DEBUG") && DEBUG>=2) echo "YellowInstall::updateLanguages file:$path<br/>\n";
                 $languages = $this->detectBrowserLanguages("en, de, fr");
                 $languages = $this->detectBrowserLanguages("en, de, fr");
                 $languagesFound = array();
                 $languagesFound = array();
                 foreach ($languages as $language) $languagesFound[$language] = "";
                 foreach ($languages as $language) $languagesFound[$language] = "";
                 if (preg_match("#^(.*\/).*?$#", $zip->getNameIndex(0), $matches)) $pathBase = $matches[1];
                 if (preg_match("#^(.*\/).*?$#", $zip->getNameIndex(0), $matches)) $pathBase = $matches[1];
                 $fileData = $zip->getFromName($pathBase.$this->yellow->system->get("updateExtensionFile"));
                 $fileData = $zip->getFromName($pathBase.$this->yellow->system->get("updateExtensionFile"));
-                if (empty($fileData)) $fileData = $zip->getFromName($pathBase.$this->yellow->system->get("updateInformationFile")); //TODO: remove later, for backwards compatibility
                 foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                     preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                     preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                     if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
                     if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
-                        list($dummy, $entry) = explode("/", $matches[1], 2);
+                        list($dummy, $entry) = explode(",", $matches[2], 3);
+                        if (ctype_upper($matches[1][0])) {  //TODO: remove later, converts old format
+                            list($dummy, $entry) = explode("/", $matches[1], 2);
+                        }
                         $flags = explode(",", $matches[2]);
                         $flags = explode(",", $matches[2]);
                         $language = array_pop($flags);
                         $language = array_pop($flags);
                         if (preg_match("/^(.*)\.php$/", basename($entry), $tokens) && in_array($language, $languages)) {
                         if (preg_match("/^(.*)\.php$/", basename($entry), $tokens) && in_array($language, $languages)) {
@@ -107,8 +128,12 @@ class YellowInstall {
                     if (lcfirst($matches[1])=="extension") $extension = lcfirst($matches[2]);
                     if (lcfirst($matches[1])=="extension") $extension = lcfirst($matches[2]);
                     if (lcfirst($matches[1])=="published") $modified = strtotime($matches[2]);
                     if (lcfirst($matches[1])=="published") $modified = strtotime($matches[2]);
                     if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
                     if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
-                        list($dummy, $entry) = explode("/", $matches[1], 2);
-                        list($fileName) = explode(",", $matches[2], 2);
+                        $fileName = $matches[1];
+                        list($dummy, $entry) = explode(",", $matches[2], 3);
+                        if (ctype_upper($matches[1][0])) {  //TODO: remove later, converts old format
+                            list($dummy, $entry) = explode("/", $matches[1], 2);
+                            list($fileName) = explode(",", $matches[2], 2);
+                        }
                         $fileData = $zip->getFromName($pathBase.basename($entry));
                         $fileData = $zip->getFromName($pathBase.basename($entry));
                         if (preg_match("/^(.*).php$/", basename($entry), $tokens) && in_array($tokens[1], $languagesFound)) {
                         if (preg_match("/^(.*).php$/", basename($entry), $tokens) && in_array($tokens[1], $languagesFound)) {
                             $statusCode = $this->yellow->extensions->get("update")->updateExtensionFile($fileName, $fileData,
                             $statusCode = $this->yellow->extensions->get("update")->updateExtensionFile($fileName, $fileData,
@@ -117,7 +142,9 @@ class YellowInstall {
                         if (preg_match("/^(.*)-language\.txt$/", basename($entry), $tokens) && in_array($tokens[1], $languagesFound)) {
                         if (preg_match("/^(.*)-language\.txt$/", basename($entry), $tokens) && in_array($tokens[1], $languagesFound)) {
                             $statusCode = $this->yellow->extensions->get("update")->updateExtensionFile($fileName, $fileData,
                             $statusCode = $this->yellow->extensions->get("update")->updateExtensionFile($fileName, $fileData,
                                 $modified, 0, 0, "create,update", false, $extension);
                                 $modified, 0, 0, "create,update", false, $extension);
+                            $this->yellow->log($statusCode==200 ? "info" : "error", "Install language '".ucfirst($tokens[1])."'");
                         }
                         }
+                        if ($statusCode!=200) break;
                     }
                     }
                 }
                 }
                 $zip->close();
                 $zip->close();
@@ -137,8 +164,11 @@ class YellowInstall {
         $statusCode = 200;
         $statusCode = 200;
         if (!empty($email) && !empty($password) && $this->yellow->extensions->isExisting("edit")) {
         if (!empty($email) && !empty($password) && $this->yellow->extensions->isExisting("edit")) {
             $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
             $fileNameUser = $this->yellow->system->get("settingDir").$this->yellow->system->get("editUserFile");
-            $status = $this->yellow->extensions->get("edit")->users->save($fileNameUser, $email, $password, $name, $language) ? "ok" : "error";
-            if ($status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
+            if (!$this->yellow->extensions->get("edit")->users->save($fileNameUser, $email, $password, $name, $language)) {
+                $statusCode = 500;
+                $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
+            }
+            $this->yellow->log($statusCode==200 ? "info" : "error", "Install webmaster '".strtok($name, " ")."'");
         }
         }
         return $statusCode;
         return $statusCode;
     }
     }
@@ -151,7 +181,7 @@ class YellowInstall {
             foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) {
             foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) {
                 if (preg_match("/^install-(.*?)\./", basename($entry), $matches)) {
                 if (preg_match("/^install-(.*?)\./", basename($entry), $matches)) {
                     if (strtoloweru($matches[1])==strtoloweru($extension)) {
                     if (strtoloweru($matches[1])==strtoloweru($extension)) {
-                        $statusCode = $this->yellow->extensions->get("update")->updateExtensionArchive($entry);
+                        $statusCode = $this->yellow->extensions->get("update")->updateExtensionArchive($entry, "install");
                         break;
                         break;
                     }
                     }
                 }
                 }

+ 165 - 125
system/extensions/update.php

@@ -4,7 +4,7 @@
 // This file may be used and distributed under the terms of the public license.
 // This file may be used and distributed under the terms of the public license.
 
 
 class YellowUpdate {
 class YellowUpdate {
-    const VERSION = "0.8.3";
+    const VERSION = "0.8.4";
     const TYPE = "feature";
     const TYPE = "feature";
     const PRIORITY = "2";
     const PRIORITY = "2";
     public $yellow;                 //access to API
     public $yellow;                 //access to API
@@ -18,12 +18,46 @@ class YellowUpdate {
         $this->yellow->system->setDefault("updateExtensionFile", "extension.ini");
         $this->yellow->system->setDefault("updateExtensionFile", "extension.ini");
         $this->yellow->system->setDefault("updateVersionFile", "version.ini");
         $this->yellow->system->setDefault("updateVersionFile", "version.ini");
         $this->yellow->system->setDefault("updateWaffleFile", "waffle.ini");
         $this->yellow->system->setDefault("updateWaffleFile", "waffle.ini");
+        $this->yellow->system->setDefault("updateNotification", "none");
     }
     }
     
     
-    // Handle startup
-    public function onStartup($update) {
-        if ($update) {  //TODO: remove later, converts old API in layouts
-            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+    // Handle request
+    public function onRequest($scheme, $address, $base, $location, $fileName) {
+        $statusCode = 0;
+        if ($this->yellow->lookup->isContentFile($fileName) && $this->isExtensionPending()) {
+            $statusCode = $this->processRequestPending($scheme, $address, $base, $location, $fileName);
+        }
+        return $statusCode;
+    }
+    
+    // Handle command
+    public function onCommand($args) {
+        $statusCode = 0;
+        if ($this->isExtensionPending()) $statusCode = $this->processCommandPending();
+        if ($statusCode==0) {
+            list($command) = $args;
+            switch ($command) {
+                case "clean":       $statusCode = $this->processCommandClean($args); break;
+                case "install":     $statusCode = $this->processCommandInstall($args); break;
+                case "uninstall":   $statusCode = $this->processCommandUninstall($args); break;
+                case "update":      $statusCode = $this->processCommandUpdate($args); break;
+                default:            $statusCode = 0; break;
+            }
+        }
+        return $statusCode;
+    }
+    
+    // Handle command help
+    public function onCommandHelp() {
+        $help .= "install [extension]\n";
+        $help .= "uninstall [extension]\n";
+        $help .= "update [extension]\n";
+        return $help;
+    }
+
+    // Handle update
+    public function onUpdate($action) {
+        if ($action=="update") {  //TODO: remove later, converts old API in layouts
             if ($this->yellow->system->isExisting("templateDir")) {
             if ($this->yellow->system->isExisting("templateDir")) {
                 $path = $this->yellow->system->get("layoutDir");
                 $path = $this->yellow->system->get("layoutDir");
                 foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.html$/", true, false) as $entry) {
                 foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.html$/", true, false) as $entry) {
@@ -39,26 +73,22 @@ class YellowUpdate {
                     $fileDataNew = str_replace("\"template\"", "\"layout\"", $fileDataNew);
                     $fileDataNew = str_replace("\"template\"", "\"layout\"", $fileDataNew);
                     $fileDataNew = str_replace("\"page template-\"", "\"page layout-\"", $fileDataNew);
                     $fileDataNew = str_replace("\"page template-\"", "\"page layout-\"", $fileDataNew);
                     if ($fileData!=$fileDataNew && !$this->yellow->toolbox->createFile($entry, $fileDataNew)) {
                     if ($fileData!=$fileDataNew && !$this->yellow->toolbox->createFile($entry, $fileDataNew)) {
-                        $fileDataError .= "ERROR writing file '$entry'!\n";
+                        $this->yellow->log("error", "Can't write file '$entry'!");
                     }
                     }
                 }
                 }
-                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
             }
             }
         }
         }
-        if ($update) {  //TODO: remove later, converts old website icon
-            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+        if ($action=="update") {  //TODO: remove later, converts old website icon
             if ($this->yellow->system->isExisting("siteicon")) {
             if ($this->yellow->system->isExisting("siteicon")) {
                 $theme = $this->yellow->system->get("theme");
                 $theme = $this->yellow->system->get("theme");
                 $fileName = $this->yellow->system->get("resourceDir")."icon.png";
                 $fileName = $this->yellow->system->get("resourceDir")."icon.png";
                 $fileNameNew = $this->yellow->system->get("resourceDir").$this->yellow->lookup->normaliseName($theme)."-icon.png";
                 $fileNameNew = $this->yellow->system->get("resourceDir").$this->yellow->lookup->normaliseName($theme)."-icon.png";
                 if (is_file($fileName) && !$this->yellow->toolbox->renameFile($fileName, $fileNameNew)) {
                 if (is_file($fileName) && !$this->yellow->toolbox->renameFile($fileName, $fileNameNew)) {
-                    $fileDataError .= "ERROR renaming file '$fileName'!\n";
+                    $this->yellow->log("error", "Can't rename file '$fileName'!");
                 }
                 }
-                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
             }
             }
         }
         }
-        if ($update) {  //TODO: remove later, converts old language files
-            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+        if ($action=="update") {  //TODO: remove later, converts old language files
             if ($this->yellow->system->isExisting("languageFile")) {
             if ($this->yellow->system->isExisting("languageFile")) {
                 $path = $this->yellow->system->get("extensionDir");
                 $path = $this->yellow->system->get("extensionDir");
                 foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.txt$/", true, false) as $entry) {
                 foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.txt$/", true, false) as $entry) {
@@ -67,48 +97,44 @@ class YellowUpdate {
                     if (!empty($languageName)) {
                     if (!empty($languageName)) {
                         $entryNew = $path.$languageName."-language.txt";
                         $entryNew = $path.$languageName."-language.txt";
                         if (!$this->yellow->toolbox->renameFile($entry, $entryNew)) {
                         if (!$this->yellow->toolbox->renameFile($entry, $entryNew)) {
-                            $fileDataError .= "ERROR renaming file '$entry'!\n";
+                            $this->yellow->log("error", "Can't rename file '$entry'!");
                         }
                         }
                         $fileNameNew = $path.$languageName.".php";
                         $fileNameNew = $path.$languageName.".php";
                         $fileDataNew = "<?php\n\nclass Yellow".ucfirst($languageName)." {\nconst VERSION = \"0.8.2\";\nconst TYPE = \"language\";\n}\n";
                         $fileDataNew = "<?php\n\nclass Yellow".ucfirst($languageName)." {\nconst VERSION = \"0.8.2\";\nconst TYPE = \"language\";\n}\n";
                         if (!$this->yellow->toolbox->createFile($fileNameNew, $fileDataNew)) {
                         if (!$this->yellow->toolbox->createFile($fileNameNew, $fileDataNew)) {
-                            $fileDataError .= "ERROR writing file '$fileNameNew'!\n";
+                            $this->yellow->log("error", "Can't write file '$fileNameNew'!");
                         }
                         }
                     }
                     }
                 }
                 }
                 $fileName = $this->yellow->system->get("extensionDir")."language.php";
                 $fileName = $this->yellow->system->get("extensionDir")."language.php";
                 if (is_file($fileName) && !$this->yellow->toolbox->deleteFile($fileName, $this->yellow->system->get("trashDir"))) {
                 if (is_file($fileName) && !$this->yellow->toolbox->deleteFile($fileName, $this->yellow->system->get("trashDir"))) {
-                    $fileDataError .= "ERROR deleting file '$fileName'!\n";
+                    $this->yellow->log("error", "Can't delete file '$fileName'!");
                 }
                 }
-                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
             }
             }
         }
         }
-        if ($update) {  //TODO: remove later, converts old Markdown files
-            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+        if ($action=="update") {  //TODO: remove later, converts old Markdown files
             if ($this->yellow->system->get("contentDefaultFile")=="page.txt") {
             if ($this->yellow->system->get("contentDefaultFile")=="page.txt") {
                 $settings = array("contentDefaultFile" => "page.md", "contentExtension" => ".md", "editNewFile" => "page-new-(.*).md");
                 $settings = array("contentDefaultFile" => "page.md", "contentExtension" => ".md", "editNewFile" => "page-new-(.*).md");
                 $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
                 $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
                 if (!$this->yellow->system->save($fileName, $settings)) {
                 if (!$this->yellow->system->save($fileName, $settings)) {
-                    $fileDataError .= "ERROR writing file '$fileName'!\n";
+                    $this->yellow->log("error", "Can't write file '$fileName'!");
                 }
                 }
                 $path = $this->yellow->system->get("contentDir");
                 $path = $this->yellow->system->get("contentDir");
                 foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.txt$/", true, false) as $entry) {
                 foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.txt$/", true, false) as $entry) {
                     if (!$this->yellow->toolbox->renameFile($entry, str_replace(".txt", ".md", $entry))) {
                     if (!$this->yellow->toolbox->renameFile($entry, str_replace(".txt", ".md", $entry))) {
-                        $fileDataError .= "ERROR renaming file '$entry'!\n";
+                        $this->yellow->log("error", "Can't rename file '$entry'!");
                     }
                     }
                 }
                 }
                 $path = $this->yellow->system->get("settingDir");
                 $path = $this->yellow->system->get("settingDir");
                 foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.txt$/", true, false) as $entry) {
                 foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.txt$/", true, false) as $entry) {
                     if (!$this->yellow->toolbox->renameFile($entry, str_replace(".txt", ".md", $entry))) {
                     if (!$this->yellow->toolbox->renameFile($entry, str_replace(".txt", ".md", $entry))) {
-                        $fileDataError .= "ERROR renaming file '$entry!'\n";
+                        $this->yellow->log("error", "Can't rename file '$entry'!");
                     }
                     }
                 }
                 }
-                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
                 $_GET["clean-url"] = "system-updated";
                 $_GET["clean-url"] = "system-updated";
             }
             }
         }
         }
-        if ($update) {  //TODO: remove later, converts old template setting
-            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+        if ($action=="update") {  //TODO: remove later, converts old template setting
             if ($this->yellow->system->isExisting("template")) {
             if ($this->yellow->system->isExisting("template")) {
                 $path = $this->yellow->system->get("contentDir");
                 $path = $this->yellow->system->get("contentDir");
                 foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.md$/", true, false) as $entry) {
                 foreach ($this->yellow->toolbox->getDirectoryEntriesRecursive($path, "/^.*\.md$/", true, false) as $entry) {
@@ -116,35 +142,33 @@ class YellowUpdate {
                     $fileDataNew = preg_replace("/Template:/i", "Layout:", $fileDataNew);
                     $fileDataNew = preg_replace("/Template:/i", "Layout:", $fileDataNew);
                     $fileDataNew = preg_replace("/TemplateNew:/i", "LayoutNew:", $fileDataNew);
                     $fileDataNew = preg_replace("/TemplateNew:/i", "LayoutNew:", $fileDataNew);
                     if ($fileData!=$fileDataNew && !$this->yellow->toolbox->createFile($entry, $fileDataNew)) {
                     if ($fileData!=$fileDataNew && !$this->yellow->toolbox->createFile($entry, $fileDataNew)) {
-                        $fileDataError .= "ERROR writing file '$entry'!\n";
+                        $this->yellow->log("error", "Can't write file '$entry'!");
                     }
                     }
                 }
                 }
-                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
                 $_GET["clean-url"] = "system-updated";
                 $_GET["clean-url"] = "system-updated";
             }
             }
         }
         }
-        if ($update) {  //TODO: remove later, updates shared pages
-            $fileNameError = $this->yellow->system->get("settingDir")."system-error.log";
+        if ($action=="update") {  //TODO: remove later, updates shared pages
             $pathSetting = $this->yellow->system->get("settingDir");
             $pathSetting = $this->yellow->system->get("settingDir");
             $pathShared = $this->yellow->system->get("contentDir").$this->yellow->system->get("contentSharedDir");
             $pathShared = $this->yellow->system->get("contentDir").$this->yellow->system->get("contentSharedDir");
             if (count($this->yellow->toolbox->getDirectoryEntries($pathSetting, "/.*/", false, false))>3) {
             if (count($this->yellow->toolbox->getDirectoryEntries($pathSetting, "/.*/", false, false))>3) {
                 $regex = "/^page-error-(.*)\.md$/";
                 $regex = "/^page-error-(.*)\.md$/";
                 foreach ($this->yellow->toolbox->getDirectoryEntries($pathSetting, $regex, true, false) as $entry) {
                 foreach ($this->yellow->toolbox->getDirectoryEntries($pathSetting, $regex, true, false) as $entry) {
                     if (!$this->yellow->toolbox->deleteFile($entry, $this->yellow->system->get("trashDir"))) {
                     if (!$this->yellow->toolbox->deleteFile($entry, $this->yellow->system->get("trashDir"))) {
-                        $fileDataError .= "ERROR deleting file '$entry'!\n";
+                        $this->yellow->log("error", "Can't delete file '$entry'!");
                     }
                     }
                 }
                 }
                 $regex = "/^page-new-(.*)\.md$/";
                 $regex = "/^page-new-(.*)\.md$/";
                 foreach ($this->yellow->toolbox->getDirectoryEntries($pathSetting, $regex, true, false) as $entry) {
                 foreach ($this->yellow->toolbox->getDirectoryEntries($pathSetting, $regex, true, false) as $entry) {
                     if (!$this->yellow->toolbox->renameFile($entry, str_replace($pathSetting, $pathShared, $entry), true)) {
                     if (!$this->yellow->toolbox->renameFile($entry, str_replace($pathSetting, $pathShared, $entry), true)) {
-                        $fileDataError .= "ERROR moving file '$entry'!\n";
+                        $this->yellow->log("error", "Can't move file '$entry'!");
                     }
                     }
                 }
                 }
                 $fileNameHeader = $pathShared."header.md";
                 $fileNameHeader = $pathShared."header.md";
                 if (!is_file($fileNameHeader) && $this->yellow->system->isExisting("tagline")) {
                 if (!is_file($fileNameHeader) && $this->yellow->system->isExisting("tagline")) {
                     $fileDataHeader = "---\nTitle: Header\nStatus: hidden\n---\n".$this->yellow->system->get("tagline");
                     $fileDataHeader = "---\nTitle: Header\nStatus: hidden\n---\n".$this->yellow->system->get("tagline");
                     if (!$this->yellow->toolbox->createFile($fileNameHeader, $fileDataHeader, true)) {
                     if (!$this->yellow->toolbox->createFile($fileNameHeader, $fileDataHeader, true)) {
-                        $fileDataError .= "ERROR writing file '$fileNameHeader'!\n";
+                        $this->yellow->log("error", "Can't write file '$fileNameHeader'!");
                     }
                     }
                 }
                 }
                 $fileNameFooter = $pathShared."footer.md";
                 $fileNameFooter = $pathShared."footer.md";
@@ -152,75 +176,63 @@ class YellowUpdate {
                     $fileDataFooter = "---\nTitle: Footer\nStatus: hidden\n---\n";
                     $fileDataFooter = "---\nTitle: Footer\nStatus: hidden\n---\n";
                     $fileDataFooter .= $this->yellow->text->getText("InstallFooterText", $this->yellow->system->get("language"));
                     $fileDataFooter .= $this->yellow->text->getText("InstallFooterText", $this->yellow->system->get("language"));
                     if (!$this->yellow->toolbox->createFile($fileNameFooter, $fileDataFooter, true)) {
                     if (!$this->yellow->toolbox->createFile($fileNameFooter, $fileDataFooter, true)) {
-                        $fileDataError .= "ERROR writing file '$fileNameFooter'!\n";
+                        $this->yellow->log("error", "Can't write file '$fileNameFooter'!");
                     }
                     }
                 }
                 }
                 $this->updateContentMultiLanguage("shared-pages");
                 $this->updateContentMultiLanguage("shared-pages");
-                if (!empty($fileDataError)) $this->yellow->toolbox->createFile($fileNameError, $fileDataError);
             }
             }
         }
         }
-        if ($update) {
-            $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
-            $fileData = $this->yellow->toolbox->readFile($fileName);
-            $fileDataHeader = $fileDataSettings = $fileDataFooter = "";
-            $settings = new YellowDataCollection();
-            $settings->exchangeArray($this->yellow->system->settingsDefaults->getArrayCopy());
-            foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
-                preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-                if (empty($fileDataHeader) && preg_match("/^\#/", $line)) {
-                    $fileDataHeader = $line;
-                } elseif (!empty($matches[1]) && !is_null($settings[$matches[1]])) {
-                    $settings[$matches[1]] = $matches[2];
-                } elseif (!empty($matches[1]) && $matches[1][0]!="#") {
-                    $fileDataFooter .= "# $line";
-                } elseif (!empty($matches[1])) {
-                    $fileDataFooter .= $line;
-                }
-            }
-            unset($settings["systemFile"]);
-            foreach ($settings as $key=>$value) {
-                $fileDataSettings .= ucfirst($key).(strempty($value) ? ":\n" : ": $value\n");
-                if ($key=="updateWaffleFile") $fileDataSettings .= "\n";
+        if ($action=="update") {  //TODO: remove later, converts old editor setting
+            if ($this->yellow->system->isExisting("editLoginRestrictions")) {
+                $editLoginRestriction = $this->yellow->system->get("editLoginRestrictions");
+                $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+                $this->yellow->system->save($fileName, array("editLoginRestriction" => $editLoginRestriction));
             }
             }
-            if (!empty($fileDataHeader)) $fileDataHeader .= "\n";
-            if (!empty($fileDataFooter)) $fileDataSettings .= "\n";
-            $fileDataNew = $fileDataHeader.$fileDataSettings.$fileDataFooter;
-            if ($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileName, $fileDataNew);
         }
         }
-    }
-    
-    // Handle request
-    public function onRequest($scheme, $address, $base, $location, $fileName) {
-        $statusCode = 0;
-        if ($this->yellow->lookup->isContentFile($fileName) && $this->isExtensionPending()) {
-            $statusCode = $this->processRequestPending($scheme, $address, $base, $location, $fileName);
+        if ($action=="startup") {  //TODO: remove later, converts old startup setting
+            if ($this->yellow->system->isExisting("startupUpdate")) {
+                $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+                $this->yellow->system->save($fileName, array("startupUpdate"=>"none", "updateNotification" => "update/update"));
+            }
         }
         }
-        return $statusCode;
-    }
-    
-    // Handle command
-    public function onCommand($args) {
-        $statusCode = 0;
-        if ($this->isExtensionPending()) $statusCode = $this->processCommandPending();
-        if ($statusCode==0) {
-            list($command) = $args;
-            switch ($command) {
-                case "clean":       $statusCode = $this->processCommandClean($args); break;
-                case "install":     $statusCode = $this->processCommandInstall($args); break;
-                case "uninstall":   $statusCode = $this->processCommandUninstall($args); break;
-                case "update":      $statusCode = $this->processCommandUpdate($args); break;
-                default:            $statusCode = 0; break;
+        if ($action=="startup") {
+            if ($this->yellow->system->get("updateNotification")!="none") {
+                foreach (explode(",", $this->yellow->system->get("updateNotification")) as $token) {
+                    list($extension, $action) = explode("/", $token, 2);
+                    if ($this->yellow->extensions->isExisting($extension) && ($action!="startup" && $action!="uninstall")) {
+                        $value = $this->yellow->extensions->extensions[$extension];
+                        if (method_exists($value["obj"], "onUpdate")) $value["obj"]->onUpdate($action);
+                    }
+                }
+                $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+                $this->yellow->system->save($fileName, array("updateNotification" => "none"));
+                $fileData = $this->yellow->toolbox->readFile($fileName);
+                $fileDataHeader = $fileDataSettings = $fileDataFooter = "";
+                $settings = new YellowDataCollection();
+                $settings->exchangeArray($this->yellow->system->settingsDefaults->getArrayCopy());
+                foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
+                    preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
+                    if (empty($fileDataHeader) && preg_match("/^\#/", $line)) {
+                        $fileDataHeader = $line;
+                    } elseif (!empty($matches[1]) && !is_null($settings[$matches[1]])) {
+                        $settings[$matches[1]] = $matches[2];
+                    } elseif (!empty($matches[1]) && $matches[1][0]!="#") {
+                        $fileDataFooter .= "# $line";
+                    } elseif (!empty($matches[1])) {
+                        $fileDataFooter .= $line;
+                    }
+                }
+                unset($settings["systemFile"]);
+                foreach ($settings as $key=>$value) {
+                    $fileDataSettings .= ucfirst($key).(strempty($value) ? ":\n" : ": $value\n");
+                    if ($key=="updateNotification") $fileDataSettings .= "\n";
+                }
+                if (!empty($fileDataHeader)) $fileDataHeader .= "\n";
+                if (!empty($fileDataFooter)) $fileDataSettings .= "\n";
+                $fileDataNew = $fileDataHeader.$fileDataSettings.$fileDataFooter;
+                if ($fileData!=$fileDataNew) $this->yellow->toolbox->createFile($fileName, $fileDataNew);
             }
             }
         }
         }
-        return $statusCode;
-    }
-    
-    // Handle command help
-    public function onCommandHelp() {
-        $help .= "install [extension]\n";
-        $help .= "uninstall [extension]\n";
-        $help .= "update [extension]\n";
-        return $help;
     }
     }
     
     
     // Process command to clean downloads
     // Process command to clean downloads
@@ -245,7 +257,7 @@ class YellowUpdate {
             $this->updates = 0;
             $this->updates = 0;
             list($statusCode, $data) = $this->getInstallInformation($extensions);
             list($statusCode, $data) = $this->getInstallInformation($extensions);
             if ($statusCode==200) $statusCode = $this->downloadExtensions($data);
             if ($statusCode==200) $statusCode = $this->downloadExtensions($data);
-            if ($statusCode==200) $statusCode = $this->updateExtensions();
+            if ($statusCode==200) $statusCode = $this->updateExtensions("install");
             if ($statusCode>=400) echo "ERROR installing files: ".$this->yellow->page->get("pageError")."\n";
             if ($statusCode>=400) echo "ERROR installing files: ".$this->yellow->page->get("pageError")."\n";
             echo "Yellow $command: Website ".($statusCode!=200 ? "not " : "")."updated";
             echo "Yellow $command: Website ".($statusCode!=200 ? "not " : "")."updated";
             echo ", $this->updates extension".($this->updates!=1 ? "s" : "")." installed\n";
             echo ", $this->updates extension".($this->updates!=1 ? "s" : "")." installed\n";
@@ -278,7 +290,7 @@ class YellowUpdate {
         if ($statusCode!=200 || !empty($data)) {
         if ($statusCode!=200 || !empty($data)) {
             $this->updates = 0;
             $this->updates = 0;
             if ($statusCode==200) $statusCode = $this->downloadExtensions($data);
             if ($statusCode==200) $statusCode = $this->downloadExtensions($data);
-            if ($statusCode==200) $statusCode = $this->updateExtensions($force);
+            if ($statusCode==200) $statusCode = $this->updateExtensions("update", $force);
             if ($statusCode>=400) echo "ERROR updating files: ".$this->yellow->page->get("pageError")."\n";
             if ($statusCode>=400) echo "ERROR updating files: ".$this->yellow->page->get("pageError")."\n";
             echo "Yellow $command: Website ".($statusCode!=200 ? "not " : "")."updated";
             echo "Yellow $command: Website ".($statusCode!=200 ? "not " : "")."updated";
             echo ", $this->updates update".($this->updates!=1 ? "s" : "")." installed\n";
             echo ", $this->updates update".($this->updates!=1 ? "s" : "")." installed\n";
@@ -288,17 +300,17 @@ class YellowUpdate {
         return $statusCode;
         return $statusCode;
     }
     }
     
     
-    // Process command to update website with pending extension
+    // Process command to install pending extension
     public function processCommandPending() {
     public function processCommandPending() {
-        $statusCode = $this->updateExtensions();
+        $statusCode = $this->updateExtensions("install");
         if ($statusCode!=200) echo "ERROR updating files: ".$this->yellow->page->get("pageError")."\n";
         if ($statusCode!=200) echo "ERROR updating files: ".$this->yellow->page->get("pageError")."\n";
         echo "Your website has ".($statusCode!=200 ? "not " : "")."been updated: Please run command again\n";
         echo "Your website has ".($statusCode!=200 ? "not " : "")."been updated: Please run command again\n";
         return $statusCode;
         return $statusCode;
     }
     }
     
     
-    // Process request to update website with pending extension
+    // Process request to install pending extension
     public function processRequestPending($scheme, $address, $base, $location, $fileName) {
     public function processRequestPending($scheme, $address, $base, $location, $fileName) {
-        $statusCode = $this->updateExtensions();
+        $statusCode = $this->updateExtensions("install");
         if ($statusCode==200) {
         if ($statusCode==200) {
             $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
             $location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
             $statusCode = $this->yellow->sendStatus(303, $location);
             $statusCode = $this->yellow->sendStatus(303, $location);
@@ -306,6 +318,25 @@ class YellowUpdate {
         return $statusCode;
         return $statusCode;
     }
     }
     
     
+    // Process update notification
+    public function processUpdateNotification($extension, $action) {
+        $statusCode = 200;
+        if ($this->yellow->extensions->isExisting($extension) && $action=="uninstall") {
+            $value = $this->yellow->extensions->extensions[$extension];
+            if (method_exists($value["obj"], "onUpdate")) $value["obj"]->onUpdate($action);
+        }
+        $updateNotification = $this->yellow->system->get("updateNotification");
+        if ($updateNotification=="none") $updateNotification = "";
+        if (!empty($updateNotification)) $updateNotification .= ",";
+        $updateNotification .= "$extension/$action";
+        $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
+        if (!$this->yellow->system->save($fileName, array("updateNotification" => $updateNotification))) {
+            $statusCode = 500;
+            $this->yellow->page->error(500, "Can't write file '$fileName'!");
+        }
+        return $statusCode;
+    }
+    
     // Return extension information
     // Return extension information
     public function getExtensionInformation($args) {
     public function getExtensionInformation($args) {
         $command = array_shift($args);
         $command = array_shift($args);
@@ -453,12 +484,12 @@ class YellowUpdate {
     }
     }
 
 
     // Update extensions
     // Update extensions
-    public function updateExtensions($force = false) {
+    public function updateExtensions($action, $force = false) {
         $statusCode = 200;
         $statusCode = 200;
         if (function_exists("opcache_reset")) opcache_reset();
         if (function_exists("opcache_reset")) opcache_reset();
         $path = $this->yellow->system->get("extensionDir");
         $path = $this->yellow->system->get("extensionDir");
         foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) {
         foreach ($this->yellow->toolbox->getDirectoryEntries($path, "/^.*\.zip$/", true, false) as $entry) {
-            $statusCode = max($statusCode, $this->updateExtensionArchive($entry, $force));
+            $statusCode = max($statusCode, $this->updateExtensionArchive($entry, $action, $force));
             if (!$this->yellow->toolbox->deleteFile($entry)) {
             if (!$this->yellow->toolbox->deleteFile($entry)) {
                 $statusCode = 500;
                 $statusCode = 500;
                 $this->yellow->page->error($statusCode, "Can't delete file '$entry'!");
                 $this->yellow->page->error($statusCode, "Can't delete file '$entry'!");
@@ -468,7 +499,7 @@ class YellowUpdate {
     }
     }
 
 
     // Update extension from archive
     // Update extension from archive
-    public function updateExtensionArchive($path, $force = false) {
+    public function updateExtensionArchive($path, $action, $force = false) {
         $statusCode = 200;
         $statusCode = 200;
         $zip = new ZipArchive();
         $zip = new ZipArchive();
         if ($zip->open($path)===true) {
         if ($zip->open($path)===true) {
@@ -478,12 +509,19 @@ class YellowUpdate {
             if (empty($fileData)) $fileData = $zip->getFromName($pathBase.$this->yellow->system->get("updateInformationFile")); //TODO: remove later, for backwards compatibility
             if (empty($fileData)) $fileData = $zip->getFromName($pathBase.$this->yellow->system->get("updateInformationFile")); //TODO: remove later, for backwards compatibility
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
-                if (!empty($matches[1]) && !empty($matches[2])) {
-                    list($fileName) = explode(",", $matches[2], 2);
+                if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
+                    $fileName = $matches[1];
                     if (is_file($fileName)) {
                     if (is_file($fileName)) {
                         $lastPublished = filemtime($fileName);
                         $lastPublished = filemtime($fileName);
                         break;
                         break;
                     }
                     }
+                    if (ctype_upper($matches[1][0])) {  //TODO: remove later, converts old format
+                        list($fileName) = explode(",", $matches[2], 2);
+                        if (is_file($fileName)) {
+                            $lastPublished = filemtime($fileName);
+                            break;
+                        }
+                    }
                 }
                 }
             }
             }
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
@@ -491,10 +529,15 @@ class YellowUpdate {
                 if (lcfirst($matches[1])=="extension") $extension = lcfirst($matches[2]);
                 if (lcfirst($matches[1])=="extension") $extension = lcfirst($matches[2]);
                 if (lcfirst($matches[1])=="plugin") $extension = lcfirst(substru($matches[2], 6)); //TODO: remove later, for backwards compatibility
                 if (lcfirst($matches[1])=="plugin") $extension = lcfirst(substru($matches[2], 6)); //TODO: remove later, for backwards compatibility
                 if (lcfirst($matches[1])=="theme") $extension = lcfirst(substru($matches[2], 11)); //TODO: remove later, for backwards compatibility
                 if (lcfirst($matches[1])=="theme") $extension = lcfirst(substru($matches[2], 11)); //TODO: remove later, for backwards compatibility
+                if (lcfirst($matches[1])=="version") $version = lcfirst($matches[2]);
                 if (lcfirst($matches[1])=="published") $modified = strtotime($matches[2]);
                 if (lcfirst($matches[1])=="published") $modified = strtotime($matches[2]);
                 if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
                 if (!empty($matches[1]) && !empty($matches[2]) && strposu($matches[1], "/")) {
-                    list($dummy, $entry) = explode("/", $matches[1], 2);
-                    list($fileName, $flags) = explode(",", $matches[2], 2);
+                    $fileName = $matches[1];
+                    list($dummy, $entry, $flags) = explode(",", $matches[2], 3);
+                    if (ctype_upper($matches[1][0])) {  //TODO: remove later, converts old format
+                        list($dummy, $entry) = explode("/", $matches[1], 2);
+                        list($fileName, $flags) = explode(",", $matches[2], 2);
+                    }
                     $fileData = $zip->getFromName($pathBase.basename($entry));
                     $fileData = $zip->getFromName($pathBase.basename($entry));
                     $lastModified = $this->yellow->toolbox->getFileModified($fileName);
                     $lastModified = $this->yellow->toolbox->getFileModified($fileName);
                     $statusCode = $this->updateExtensionFile($fileName, $fileData, $modified, $lastModified, $lastPublished, $flags, $force, $extension);
                     $statusCode = $this->updateExtensionFile($fileName, $fileData, $modified, $lastModified, $lastPublished, $flags, $force, $extension);
@@ -502,8 +545,9 @@ class YellowUpdate {
                 }
                 }
             }
             }
             $zip->close();
             $zip->close();
-            if ($statusCode==200) $statusCode = $this->updateContentMultiLanguage($extension);
-            if ($statusCode==200) $statusCode = $this->updateStartupNotification($extension);
+            $statusCode = max($statusCode, $this->updateContentMultiLanguage($extension));
+            $statusCode = max($statusCode, $this->processUpdateNotification($extension, $action));
+            $this->yellow->log($statusCode==200 ? "info" : "error", ucfirst($action)." extension '".ucfirst($extension)." $version'");
             ++$this->updates;
             ++$this->updates;
         } else {
         } else {
             $statusCode = 500;
             $statusCode = 500;
@@ -595,20 +639,6 @@ class YellowUpdate {
         return $statusCode;
         return $statusCode;
     }
     }
     
     
-    // Update notification for next startup
-    public function updateStartupNotification($extension) {
-        $statusCode = 200;
-        $startupUpdate = $this->yellow->system->get("startupUpdate");
-        if ($startupUpdate=="none") $startupUpdate = "update";
-        if ($extension!="update") $startupUpdate .= ",$extension";
-        $fileName = $this->yellow->system->get("settingDir").$this->yellow->system->get("systemFile");
-        if (!$this->yellow->system->save($fileName, array("startupUpdate" => $startupUpdate))) {
-            $statusCode = 500;
-            $this->yellow->page->error(500, "Can't write file '$fileName'!");
-        }
-        return $statusCode;
-    }
-    
     // Remove extensions
     // Remove extensions
     public function removeExtensions($data) {
     public function removeExtensions($data) {
         $statusCode = 200;
         $statusCode = 200;
@@ -617,9 +647,11 @@ class YellowUpdate {
             foreach (preg_split("/\s*,\s*/", $value) as $fileName) {
             foreach (preg_split("/\s*,\s*/", $value) as $fileName) {
                 $statusCode = max($statusCode, $this->removeExtensionsFile($fileName, $key));
                 $statusCode = max($statusCode, $this->removeExtensionsFile($fileName, $key));
             }
             }
+            $statusCode = max($statusCode, $this->processUpdateNotification($key, "uninstall"));
+            $version = $this->yellow->extensions->isExisting($key) ? $this->yellow->extensions->extensions[$key]["version"] : "";
+            $this->yellow->log($statusCode==200 ? "info" : "error", "Uninstall extension '".ucfirst($key)." $version'");
             ++$this->updates;
             ++$this->updates;
         }
         }
-        if ($statusCode==200) $statusCode = $this->updateStartupNotification("update");
         return $statusCode;
         return $statusCode;
     }
     }
     
     
@@ -671,8 +703,12 @@ class YellowUpdate {
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 if (!empty($matches[1]) && !empty($matches[2])) {
                 if (!empty($matches[1]) && !empty($matches[2])) {
-                    list($extension) = explode("/", lcfirst($matches[1]));
-                    list($fileName) = explode(",", $matches[2], 2);
+                    $fileName = $matches[1];
+                    list($extension) = explode(",", lcfirst($matches[2]), 3);
+                    if (ctype_upper($matches[1][0])) {  //TODO: remove later, converts old format
+                        list($extension) = explode("/", lcfirst($matches[1]));
+                        list($fileName) = explode(",", $matches[2], 2);
+                    }
                     if (!is_null($data[$extension])) $data[$extension] .= ",";
                     if (!is_null($data[$extension])) $data[$extension] .= ",";
                     $data[$extension] .= $fileName;
                     $data[$extension] .= $fileName;
                 }
                 }
@@ -691,8 +727,12 @@ class YellowUpdate {
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
             foreach ($this->yellow->toolbox->getTextLines($fileData) as $line) {
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 preg_match("/^\s*(.*?)\s*:\s*(.*?)\s*$/", $line, $matches);
                 if (!empty($matches[1]) && !empty($matches[2])) {
                 if (!empty($matches[1]) && !empty($matches[2])) {
-                    list($extensionNew) = explode("/", lcfirst($matches[1]));
-                    list($fileName, $flags) = explode(",", $matches[2], 2);
+                    $fileName = $matches[1];
+                    list($extensionNew, $dummy, $flags) = explode(",", lcfirst($matches[2]), 3);
+                    if (ctype_upper($matches[1][0])) {  //TODO: remove later, converts old format
+                        list($extensionNew) = explode("/", lcfirst($matches[1]));
+                        list($fileName, $flags) = explode(",", $matches[2], 2);
+                    }
                     if ($extension!=$extensionNew) {
                     if ($extension!=$extensionNew) {
                         $extension = $extensionNew;
                         $extension = $extensionNew;
                         $lastPublished = $this->yellow->toolbox->getFileModified($fileName);
                         $lastPublished = $this->yellow->toolbox->getFileModified($fileName);

+ 3 - 2
system/settings/system.ini

@@ -40,15 +40,16 @@ ContentDefaultFile: page.md
 ContentExtension: .md
 ContentExtension: .md
 DownloadExtension: .download
 DownloadExtension: .download
 TextFile: text.ini
 TextFile: text.ini
+LogFile: yellow.log
 SafeMode: 0
 SafeMode: 0
 MultiLanguageMode: 0
 MultiLanguageMode: 0
-StartupUpdate: none
 ServerUrl:
 ServerUrl:
 UpdateExtensionUrl: https://github.com/datenstrom/yellow-extensions
 UpdateExtensionUrl: https://github.com/datenstrom/yellow-extensions
 UpdateInformationFile: update.ini
 UpdateInformationFile: update.ini
 UpdateExtensionFile: extension.ini
 UpdateExtensionFile: extension.ini
 UpdateVersionFile: version.ini
 UpdateVersionFile: version.ini
 UpdateWaffleFile: waffle.ini
 UpdateWaffleFile: waffle.ini
+UpdateNotification: none
 
 
 BundleAndMinify: 1
 BundleAndMinify: 1
 EditLocation: /edit/
 EditLocation: /edit/
@@ -63,7 +64,7 @@ EditUserHashAlgorithm: bcrypt
 EditUserHashCost: 10
 EditUserHashCost: 10
 EditUserHome: /
 EditUserHome: /
 EditNewFile: page-new-(.*).md
 EditNewFile: page-new-(.*).md
-EditLoginRestrictions: 0
+EditLoginRestriction: 0
 EditLoginSessionTimeout: 2592000
 EditLoginSessionTimeout: 2592000
 EditBruteForceProtection: 25
 EditBruteForceProtection: 25
 ImageAlt: Image
 ImageAlt: Image