瀏覽代碼

Add files via upload

Daniele Bonini (皮夕): WebDev and DevOps by lots of Sim.pli.city bits 3 年之前
父節點
當前提交
fadb5a4632

+ 66 - 0
INSTALLATION.md

@@ -0,0 +1,66 @@
+# INSTALLATION
+   
+  Installing SnipSwap is more straightforward than what it could appear..   
+  
+  First, if you use Nginx as reversed proxy just point the root of your web app to /path/to/YourSnipSwap/Public   
+  where the public content is located:
+  
+  <ol>  
+  <li>The static content hosted should be just of this kind: html, css, js, png, jpg, jpeg, gif, fonts, map, ico</li>   
+  <li>Example of Nginx minimal configuration:
+      
+       
+        
+        
+     
+      server {   
+     
+        listen 80;
+        listen [::]:80;
+    
+        server_name yourname-SnipSwap.com;
+     
+        root /var/www/YourSnipSwap/Public;
+        index index.php; 
+       
+        location / {     
+          proxy_set_header Host $host;     
+          proxy_set_header X-Real_IP $remote_addr;     
+          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    
+         
+          proxy_http_version 1.1;     
+          proxy_set_header Connection "";     
+        
+          proxy_pass http://127.0.0.1:8081;        
+        }
+     
+        location ~* ^.+\.(php)$ {     
+          proxy_set_header Host $host;     
+          proxy_set_header X-Real_IP $remote_addr;     
+          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    
+         
+          proxy_http_version 1.1;     
+          proxy_set_header Connection "";     
+        
+          proxy_pass http://127.0.0.1:8081;        
+        }
+        
+        location ~* ^.+\.(js|map|css|jpg|jpeg|gif|png|ttf|woff|woff2|eot|pdf|html|htm|zip|flv|swf|ico|xml|txt|wav|mp3)$ {
+     
+          gzip on;
+          #gzip_http_version 1.1;
+          gzip_comp_level 6;
+          gzip_types text/css text/javascript application/x-javascript text/html;
+          gzip_min_length 1000;
+
+          expires 30d;
+        }      
+      }     
+     
+     
+  </li>
+  </ol>  
+  
+  Apache instead should have DocumentRoot pointing to /path/to/YourSnipSwap/Public .   
+  
+  Dan

+ 81 - 0
Private/classes/fivemode/fivemode/class.array2.inc

@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.array.inc
+ * 
+ * Array2 class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * Array2
+ *
+ * Array2 class
+ *
+ * @package  Array
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  2.0
+ * @access   public
+ */
+final class Array2
+{
+  const PHP_EMPTY = [];
+
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+  
+  /**
+   * Get an array by the given size filled with zeros
+   * 
+   * @param int $number the size of the array to generate
+   * @return array the generated array filled with zeros 
+   */
+  public static function PHP_ZEROs(int $number): array
+  {
+    $reta = self::PHP_EMPTY;
+    if ($number<=0) {
+      return $reta;
+    }
+    while ($number>0) {
+      $reta[] = 0;
+      $number--;
+    }
+    return $reta; 
+  }
+}

+ 207 - 0
Private/classes/fivemode/fivemode/class.cache.inc

@@ -0,0 +1,207 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.cache.inc
+ * 
+ * Cache class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * Cache
+ *
+ * Cache class
+ *
+ * @package  Cache
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  2.0
+ * @access   public
+ */
+final class Cache extends \Memcache 
+{
+  /**
+   * The static instance of Cache
+   *  
+   * @access private
+   * @var Cache
+   */
+  private static $_instance = null;
+
+  /**
+   * Get the static instance of Cache 
+   * 
+   * @return Cache
+   */
+  public static function &getInstance(): Cache
+  {  
+    if(!isset(self::$_instance)){
+      self::$_instance = new Cache();
+      self::$_instance->addServer(CACHE_HOST, CACHE_PORT, true);
+    }  
+    return self::$_instance;  
+  }
+
+  /**
+   * Get the service status
+   * 
+   * @return bool
+   */
+  public static function getStatus(): bool
+  {  
+    if(isset($this)){
+      if (!$this->getServerStatus(CACHE_HOST, CACHE_PORT)) {
+        return false;
+      } else {
+        return true;
+      }
+    } else if(isset(self::$_instance)){
+      if (!self::$_instance->getServerStatus(CACHE_HOST, CACHE_PORT)) {
+        return false;
+      } else {
+        return true;
+      }
+    } else {
+      return false;
+    }  
+  }
+  
+  /**
+   * Check if the static instance is set
+   * 
+   * @return bool
+   */
+  public static function issetInstance(): bool
+  {
+    return isset(self::$_instance);
+  }
+  
+  /**
+   * Unset the static instance
+   * 
+   * @return void
+   */
+  public static function unsetInstance(): void
+  {
+    self::$_instance = null;
+  }
+
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+  
+  /**
+   * Retrieve item from the cache server (decoded by json_decode)
+   * 
+   * @param string $key the key to fetch
+   * @param int $flags the flags
+   * @return array the value stored in cache
+   */
+  public function getObj(string $key, ?int $flags = null) 
+  {
+    if (!isset($flags)) {
+      return $this->get(CACHE_APP_PREFIX . $key);
+    }
+    return $this->get(CACHE_APP_PREFIX . $key, $flags);
+  }
+  
+  /**
+   * Store data in the cache server (encoded by json_encode)
+   * 
+   * @param string $key the key to associated with the item.
+   * @param mixed $var the object to store
+   * @param int $flags the flags
+   * @param int $expire expiration time, in seconds
+   * @return bool true on success or false on failure 
+   */
+  public function setObj(string $key, &$var, ?int $flags = null, ?int $expire = null): bool 
+  {
+    // cache insert
+    if (!isset($flags)) {
+      return $this->set(CACHE_APP_PREFIX . $key, $var);
+    } else if (!isset($expire)) {
+      return $this->set(CACHE_APP_PREFIX . $key, $var, $flags);
+    }
+    return $this->set(CACHE_APP_PREFIX . $key, $var, $flags, $expire);
+  }
+  
+  /**
+   * Retrieve item from the cache server (decoded by json_decode)
+   * 
+   * @param string $key the key to fetch
+   * @param int $flags the flags
+   * @return array the value stored in cache
+   */
+  public function getJ(string $key, ?int $flags = null) 
+  {
+    if (!isset($flags)) {
+      return json_decode($this->get(CACHE_APP_PREFIX . $key), true);
+    }
+    return json_decode($this->get(CACHE_APP_PREFIX . $key, $flags), true);
+  }
+  
+  /**
+   * Store data in the cache server (encoded by json_encode)
+   * 
+   * @param string $key the key to associated with the item.
+   * @param mixed $var the value to store
+   * @param int $flags the flags
+   * @param int $expire expiration time, in seconds
+   * @return bool true on success or false on failure 
+   */
+  public function setJ(string $key, &$var, ?int $flags = null, ?int $expire = null): bool
+  {
+    // cache insert
+    if (!isset($flags)) {
+      return $this->set(CACHE_APP_PREFIX . $key, json_encode($var));
+    } else if (!isset($expire)) {
+      return $this->set(CACHE_APP_PREFIX . $key, json_encode($var), $flags);
+    }
+    return $this->set(CACHE_APP_PREFIX . $key, json_encode($var), $flags, $expire);
+  }
+  
+  /**
+   * Test the validity of the "global" cache expiration time
+   * 
+   * @param string $testText the text used to generate the key for the test
+   * 
+   * @return bool true if the caching expiration time is not gone
+   */
+  //public function testLastCached($testText) {
+  //  return json_decode($this->get(md5($testText), 0), true);
+  //}  
+}

+ 168 - 0
Private/classes/fivemode/fivemode/class.catutil.inc

@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.catutil.inc
+ * 
+ * The CatUtil class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * CatUtil
+ *
+ * CatUtil class
+ *
+ * @package  Category
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  1.0
+ * @access   public
+ */
+final class CatUtil
+{
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+
+  public static function catExist($catMaskedPath): bool
+  {
+    $retval = false; 
+    
+    //chdir(APP_PATH . PHP_SLASH . $platform);
+    chdir(APP_DATA_PATH);
+    
+    $pattern = "*/data/cats/" . $catMaskedPath;
+    $aCatPaths = array_slice(glob($pattern), 0, 1);
+    
+    if(!Empty($aCatPaths)) {
+      $retval = true;
+    }
+    
+    return $retval;
+  }
+
+  public static function getCatsList(): array
+  {
+    $reta = [];
+
+    // Reading from the cache first
+    //$cache = &Cache::getInstance();
+    
+    //$cacheKey = md5("CALL spGetCatList();");
+    //$reta = $cache->getJ($cacheKey);
+    $reta = false;
+    
+    if (!$reta) {
+    
+      //chdir(APP_PATH . PHP_SLASH . $platform);
+      chdir(APP_DATA_PATH);
+    
+      $pattern = "*/data/cats/*";
+      $aCats = array_slice(glob($pattern), 0, 100);
+    
+      if(!Empty($aCats)) {
+
+        foreach($aCats as &$cat) {
+          $ipos=strripos($cat, PHP_SLASH);    
+          $cat=substr($cat, $ipos+1);          
+          $ipos=strripos($cat, PHP_TILDE);    
+          if (!$ipos) {
+            $reta[$cat] = $cat;
+          }        
+        }
+      }
+    
+      if (!Empty($reta)) {
+        sort($reta);
+      }
+    }
+
+    if (Empty($reta)) {
+      $reta = [];
+    }
+
+    // Caching the array just loaded
+    //$cache->setJ($cacheKey, $reta, 0, CACHE_EXPIRE);
+
+    return $reta;
+  }
+
+  
+  public static function getSubCatsList($parentMaskedPath): array
+  {
+    $reta = [];
+    
+    // Reading from the cache first
+    //$cache = &Cache::getInstance();
+
+    //$cacheKey = md5("CALL spGetSubCatsList($parentMaskedPath);");
+    //$reta = $cache->getJ($cacheKey);
+    $reta = false;
+    if (!$reta) {
+
+      //chdir(APP_PATH . PHP_SLASH . $platform);
+      chdir(APP_DATA_PATH);
+    
+      $pattern = "*/data/cats/" . $parentMaskedPath . PHP_TILDE . "*";
+      $aSubCats = array_slice(glob($pattern), 0, 100);
+    
+      if(!Empty($aSubCats)) {
+
+        foreach($aSubCats as &$cat) {
+          $ipos=strripos($cat, PHP_SLASH);    
+          $cat=substr($cat, $ipos+1);          
+          $reta[$cat] = $cat;
+        }
+      }
+      
+      if (!Empty($reta)) {
+        sort($reta);
+      }
+
+    }
+
+    if (Empty($reta)) {
+      $reta = [];
+    }
+
+    // Caching the array just loaded
+    //$cache->setJ($cacheKey, $reta, 0, CACHE_EXPIRE);
+
+    return $reta;
+  }
+  
+}

+ 93 - 0
Private/classes/fivemode/fivemode/class.config.inc

@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.config.inc
+ * 
+ * Config class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * Config
+ *
+ * Config class
+ *
+ * @package  Config
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  2.0
+ * @access   public
+ */
+final class Config {
+  
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+  
+  /**
+   * Get a configuration value given its path
+   * 
+   * @param string $path the configuration path, eg. "APP/NAME"
+   * @return mixed the configuration value
+   */
+  public static function get(string $path)
+  {
+    settype($key, "string");
+    settype($subkey, "string");
+    
+    $config = $GLOBALS['CONFIG'];
+    $path = explode(PHP_SLASH, $path);
+
+    if (count($path) === 1) {
+      $key = $path[0];
+      if (isset($config[$key])) {
+        return $config[$key];
+      } else {
+        return PHP_STR;
+      }
+    }
+
+    $key = $path[0];
+    $subkey = $path[1];
+
+    if (isset($config[$key][$subkey])) {
+      return $config[$key][$subkey];
+    } else {
+      return PHP_STR;
+    }  
+  }
+}

+ 186 - 0
Private/classes/fivemode/fivemode/class.cookie.inc

@@ -0,0 +1,186 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.cookie.inc
+ * 
+ * Cookie class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * Cookie
+ *
+ * Cookie class
+ *
+ * @package  Cookie
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  2.0
+ * @access   public
+ */
+final class Cookie {
+  
+  const EXPIRE_ONEDAY = 86400;
+  const EXPIRE_SEVENDAYS = 604800;
+  const EXPIRE_THIRTYDAYS = 2592000;
+  const EXPIRE_SIXMONTHS = 15768000;
+  const EXPIRE_ONEYEAR = 31536000;
+  const EXPIRE_LIFETIME = -1;
+
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+  
+  /**
+   * Check if the given cookie exists
+   *
+   * @param string $name the name of the cookie
+   * @return bool if the given cookie exist, true/false
+   */
+  static public function exists(string $name): bool
+  {
+    return isset($_COOKIE[COOKIE_PREFIX . $name]);
+  }
+
+  /**
+   * Check if the given cookie is empty
+   *
+   * @param string $name the name of the cookie
+   * @return bool if the given cookie is empty, true/false
+   */
+  static public function isEmpty(string $name): bool
+  {
+    if (!self::exists($name)) {
+      return true;
+    }
+    return empty($_COOKIE[COOKIE_PREFIX . $name]);
+  }
+
+  /**
+   * Get the value of the given cookie
+   *
+   * @param string $name the name of the cookie
+   * @param string $default the default value
+   * @return string the value of the cookie
+   */
+  static public function get(string $name, string $default = ""): string
+  {
+    return (self::exists($name) ? $_COOKIE[COOKIE_PREFIX . $name] : $default);
+  }
+
+  /**
+   * Set the value of a given cookie
+   * 
+   * @param string $name the name of the cookie
+   * @param string $value the value
+   * @param mixed $expire the expiration time
+   * @param string $path the path
+   * @param mixed $domain the domain
+   * @return bool if the cookie has been successfully set, true/false
+   */
+  static public function set(string $name, string $value, ?int $expire = self::EXPIRE_ONEYEAR, string $path = "/", $domain = false): bool
+  {
+    $retval = false;
+    
+    settype($subdomain, "string");
+    
+    if (!headers_sent())
+    {
+      if ($domain === false) {
+        //$domain = $_SERVER['HTTP_HOST'];
+        $domain = $_SERVER['HTTP_HOST'];
+        $domain = str_replace("www.", PHP_STR, strtolower($domain));
+        $isSubdomain = isSubdomainHost($subdomain);
+        if ($isSubdomain) {
+          $domain = str_replace($subdomain . ".", PHP_STR, $domain);
+        }
+      }
+      
+      if ($expire === self::EXPIRE_LIFETIME) {
+        $expire = PHP_INT_MAX;
+      } elseif (is_numeric($expire)) {
+        $expire = time() + $expire;
+      } else {
+        $expire = strtotime($expire);
+      }
+      
+      $retval = @setcookie(COOKIE_PREFIX . $name, $value, $expire, $path, $domain, false, true);
+      if ($retval) {
+        $_COOKIE[COOKIE_PREFIX . $name] = $value;
+      }
+    }
+    
+    return $retval;
+  }
+
+  /**
+   * Delete the given cookie
+   *
+   * @param string $name the name of the cookie
+   * @param string $path the path of the cookie
+   * @param mixed $domain the domain of the cookie
+   * @return bool if the cookie has been successfully deleted, true/false
+   */
+  static public function delete(string $name, string $path = "/", $domain = false): bool
+  {
+    $retval = false;
+    
+    settype($subdomain, "string");
+    
+    if (!headers_sent())
+    {
+      if (self::exists($name)) {
+        
+        if ($domain === false) {
+          //$domain = $_SERVER['HTTP_HOST'];
+          $domain = $_SERVER['HTTP_HOST'];
+          $domain = str_replace("www.", PHP_STR, strtolower($domain));
+          $isSubdomain = isSubdomainHost($subdomain);
+          if ($isSubdomain) {
+            $domain = str_replace($subdomain . ".", PHP_STR, $domain);
+          }
+        }
+
+        $retval = @setcookie(COOKIE_PREFIX . $name, "", time() - 3600, $path, $domain, false, true);
+
+        unset($_COOKIE[COOKIE_PREFIX . $name]);
+      }
+    }
+    
+    return $retval;
+  }
+}

+ 1156 - 0
Private/classes/fivemode/fivemode/class.err.inc

@@ -0,0 +1,1156 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.err.inc
+ * 
+ * Err class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * Err
+ *
+ * Err class
+ *
+ * @package  Error
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  2.0
+ * @access   public
+ */
+final class Err 
+{
+  const ERR_REQMETHOD = "aL968iHaFEqRil8u6mFf1MpV1c681q3L";
+  const ERR_Q = "pCgzogPXvWzVqqYxL62U7iqjUo8VQAL1";  
+  const ERR_CSRFTOKEN = "830V0HWl2OInNb7Rm3KkK0wE07bpH43f";
+  const ERR_RESETTOKEN = "VugoUE8c71mc5v9118Xx8lGF3g5Q6PJD";
+  const ERR_ACTIVATIONTOKEN = "QN2CkNda9Q6LZ27muf4g79956ml6U4Y7";
+  const ERR_USERNAME = "113MXP20HBNGlEPHHHX14QICDzOzojrU";  
+  const ERR_EMAIL = "46XnbH6vr4j74myYnVTN05VtGmBjL6MQ";
+  const ERR_PASSWORD = "M9F28Mb0zyNJb5PXm55Rdexm4J10rPaK"; 
+  const ERR_CONFIRMPASSWORD = "03iKDr6sqM02jwc3tGeLvcL5f9qfjjVN";   
+  const ERR_ERR = "ZB5R981mz24K29RgNn8uZMr1Vjs055x9";  
+  const ERR_MAILER = "RolA9Gf6d24i9x7IO6iUbft666980L01";    
+  const ERR_GENERAL = "uEh1RE49t6qn91101aZvS4xbZ9TlGLeF";
+  const ERR_ACTIVATION_UNAFFECTED = "x8E68M61ts4y4C6vCUgBzYFo2xJ35k5j";
+  const ERR_INPUT = "J1SfED4zF8zg3g5O5FwNwUv6se5Q575r";
+  const ERR_USER_EXISTS = "914UgIj1duRGg128685BDSF6BX8xb9rE";  
+  const ERR_EMAIL_EXISTS = "4q2It72ei9lc36CKWjo2o12aA6A4j0OX";
+  const ERR_USERNAMEEMAIL = "PhKZ496q7YAWyDsxmu785Qqwq8KZZs5A";
+  const ERR_LOGIN = "89OIg13286oOOg9xB0IpH5QJN7iq59E0";
+  const ERR_NO_FILE1 = "FqkYQ1lC8T6aMeMW7RcP59186MqNr6eV";
+  const ERR_INI_SIZE = "l4tjbCfQu8H62Z9DiIr44ACO4kC5iFaK";
+  const ERR_FORM_SIZE = "U5L22gw2dXmN901G1IKGTVJ9O8dw19ea";
+  const ERR_PARTIAL = "tUxsOG6lvd60U893C8aQB6Z72883M6S1";
+  const ERR_NO_FILE2 = "8nUS01tMNreY2SC61g57V5E120a2f8wd";
+  const ERR_NO_TMP_DIR = "4U4DfRK1JwWoyk6T9Qa4h773smDrhx78";
+  const ERR_CANT_WRITE = "FSdmAd9TMeG7YKGcN8Vb4ooto78j94xQ";
+  const ERR_EXTENSIONv = "vFrK8k1VnKw449Ftu3QJX32f7VLi0gkh";
+  const ERR_UPLOAD = "axC6XDh5J38D9mtH6eC13fDAQeVh50gy";
+  const ERR_FILE_NAME = "I25q7cDjr7hT9y9IeXTJRC6Al52kjTsj";
+  const ERR_FILE_TYPE = "7nV9J44C1Ms3f31V0B33TNxW2C3yGlXa";
+  const ERR_FILE_TMPPATH = "7p95KtqF0rpS9f5pgwaUJSe9gL1s482T";
+  const ERR_FILE_SIZE = "QapHtKQJjv2m2kOVt5g5465126wd3I0y";
+  const ERR_USER_SESSION = "0AcGK57R4bjfTI8k7Y0fZFE4ETQ1MBrX";
+  const ERR_NAME = "x11exQg6Lygl4Yz47R78FRIw799quH5P";
+  const ERR_CURRENTPAGE = "9V2QCOkw9CWPHrNGZin8Ms6WX96H64mL";
+  const ERR_MAXVISIBLEPAGES = "Q6ttpCa69RW3YNE98ZT8E6ub62TW1Ci0";
+  const ERR_ITEMSPERPAGE = "slTlreOPn10VU0I8eq5xeo6yu133rr1A";  
+  const ERR_LANDINGPAGE = "oDsf279T556WuF0dWnI5Lep0rWb538x7";   
+  const ERR_TOTITEMS = "2iW0vpAN1YcXBN5sHzu5BbqUY8cKf2C2";   
+  const ERR_ID = "0OdS5agNpvMUb7S5K7JH4vRRkQ1Af75n";  
+  const ERR_QUERYORDER = "rknXwuwe79bpJcl4b3HsdJuTKMXbeiA8";   
+  const ERR_QUERYCOUNT = "l71XwgU1oQR80m8ad0c51771g84Tmfkj";
+  const ERR_QUERYOFFSET = "Xt2yxZFvRJzjJR8i4rHPeUQWdjj64ni8";
+  const ERR_LANGUAGE = "qXG07iz29D4139Dv82nyfidZ0rb3Nx55";
+  const ERR_UPDATE_TYPE = "XXj4FfRg75x9G52drcuNn4wFN9PA5O68";
+  const ERR_CLASS_PARAMETER = "mM6kv48j9YoRzxvoSghGjZzA81P7ZW6D";
+  const ERR_SID = "yY2jO7dA34yN8l8XY4y6LvR562IKw8K3";
+  const ERR_URL = "ji8tlwybgLIWXn39WjMr3Btjq55hO264";
+  const ERR_URL_EXISTS = "E1W6hIt1NIvKKE5J4Ie4OMIS1w7guAaY";
+  const ERR_LICENSE = "3n3eWwLS8O15B2hcENR1V9oEz6N1Urg7";
+  const ERR_VALUE = "mfpf4YB51hwLRcbHCO75iOIjFLf62Adt";
+  const ERR_SCRIPT = "FOv6rNC0zZ9hJAcQci203NfLxE5I1Dx5";
+  const ERR_KEY = "a0r15FBV1sMkLSJjZPGNG4jfD1ZEZ8Bt";
+  const ERR_DEFLANG_VALUE = "mt0ky5w877E1r61uPHR8Kyy3L2Qucap7";
+  const ERR_DOUBLE_RESOURCE = "P8gDL50HN9953pGc10Is1nr6pZDIr928";
+  const ERR_WORD = "sQ5zfY64zYjR06k4p11csawH1yTE497y";
+  const ERR_DOUBLE_WORD = "rE7Y56ZoV40DjEn5hY20PWRBFItKdHG9";
+  const ERR_WARNING = "PIzM4pxF3AaoO7H84bSCs4DMDQtmzqxE";
+  const ERR_FILTER = "3yGn0aF50m4641P63IR5ZEhBtEi1THM3";
+  const ERR_PRIMCAT = "4fdWHXEjlKNuPrv9avpr7I82iR8Hp5Yn";
+  const ERR_SECONDCAT = "4299KiwIac5BjMt3tYF1XS9z1pLQ2c1X";
+  const ERR_THIRDCAT = "94pQUGKmHa808R1R4w5Lw9xTl0kZdAf1";
+  const ERR_FOURTHCAT = "p4PVCH3XWqZyFf4a9JZarb85Eyg9DeBm";
+  const ERR_FIFTHCAT = "iYug27oaLzbkN4bblgvIsoXSn1LdHb3H";
+  const ERR_NEWCAT = "75AR87Rb31V091498o8nZyF5YW38wac2";
+  const ERR_NEWCAT_TEXT = "270k4NIym160Y7v04Xueq67Fiz1390Q7";
+  const ERR_NEWSUBCATS = "Jf5r0xB5F94O0G1kHD961Eh7KJ0747Ct";
+  const ERR_IMAGETYPE = "LreYdjhbuP9ZiooW7F1vhhLRtyS9cITq";
+  const ERR_IMAGETYPE_CAT = "03C0uwNu9Y8Wp45SG5N5brPKUFRswdM8";
+  const ERR_CLASSIFI_OP = "9beQuuTu0bb693naFr0pqSPXn416P9w5";
+  const ERR_DEFAULT_CLASSIFI = "zkMvjN1CKDk8mDNKT1v4j2Iy8xuEhq0i";
+  const ERR_MODIFIER = "71o01reqwGec1h8tC5URmLQxOo5SQ1Iw";
+  const ERR_IMAGE_CAT = "gi17u1zT0Lu1r4HVRm9yBxn8dc1d0Gzv";
+  const ERR_IMAGE = "S5KvIB5NJdv7b55Kj80CbdPZ8zV85t6e";
+  const ERR_APPROVED = "40zz08totKa01oChY50Q5BpEgJiK52GZ";
+  const ERR_DEBUG_INFO = "hDy3Fo92hJV5tV12GQc6dc8crSFu8Y4d";
+  const ERR_REFERER = "bYNB81774j5kJuZUb6D06XmF8UupjRWJ";
+  const ERR_USER = "7ZnLN90x4IPqZL4s51cRJB0564v557Os";
+  const ERR_MEDIATYPE = "s3405pWyyg64d0aD6Q2WPZM8Z1R75XFg";
+  const ERR_SUBJECT = "PDF79vr5D67dcGQvw9tBR7qw8NQ63121";
+  const ERR_FROM = "ZrLvAPcWk1Do6lsMe0RKm8ObquXk2E9L";
+  const ERR_TO = "PcThvAYl3Fp7JRsCVe4Lm9sM0CQe4GVi";
+  const ERR_RTYPE = "GNpSauDWf1Hj5pJtNa1DSf5HWjr8KcvP";
+  const ERR_EXPW = "01DSf5HWjMoQsg2ATI7EYpJtNaTgvAXI";
+  
+  public static $A_ERR_NO = [
+    'ERR_REQMETHOD' => "aL968iHaFEqRil8u6mFf1MpV1c681q3L",
+    'ERR_Q' => "pCgzogPXvWzVqqYxL62U7iqjUo8VQAL1",  
+    'ERR_CSRFTOKEN' => "830V0HWl2OInNb7Rm3KkK0wE07bpH43f",
+    'ERR_RESETTOKEN' => "VugoUE8c71mc5v9118Xx8lGF3g5Q6PJD",
+    'ERR_ACTIVATIONTOKEN' => "QN2CkNda9Q6LZ27muf4g79956ml6U4Y7",
+    'ERR_USERNAME' => "113MXP20HBNGlEPHHHX14QICDzOzojrU",  
+    'ERR_EMAIL' => "46XnbH6vr4j74myYnVTN05VtGmBjL6MQ",
+    'ERR_PASSWORD' => "M9F28Mb0zyNJb5PXm55Rdexm4J10rPaK", 
+    'ERR_CONFIRMPASSWORD' => "03iKDr6sqM02jwc3tGeLvcL5f9qfjjVN",   
+    'ERR_ERR' => "ZB5R981mz24K29RgNn8uZMr1Vjs055x9",  
+    'ERR_MAILER' => "RolA9Gf6d24i9x7IO6iUbft666980L01",    
+    'ERR_GENERAL' => "uEh1RE49t6qn91101aZvS4xbZ9TlGLeF",
+    'ERR_ACTIVATION_UNAFFECTED' => "x8E68M61ts4y4C6vCUgBzYFo2xJ35k5j",
+    'ERR_INPUT' => "J1SfED4zF8zg3g5O5FwNwUv6se5Q575r",
+    'ERR_USER_EXISTS' => "914UgIj1duRGg128685BDSF6BX8xb9rE",  
+    'ERR_EMAIL_EXISTS' => "4q2It72ei9lc36CKWjo2o12aA6A4j0OX",
+    'ERR_USERNAMEEMAIL' => "PhKZ496q7YAWyDsxmu785Qqwq8KZZs5A",
+    'ERR_LOGIN' => "89OIg13286oOOg9xB0IpH5QJN7iq59E0",
+    'ERR_NO_FILE1' => "FqkYQ1lC8T6aMeMW7RcP59186MqNr6eV",
+    'ERR_INI_SIZE' => "l4tjbCfQu8H62Z9DiIr44ACO4kC5iFaK",
+    'ERR_FORM_SIZE' => "U5L22gw2dXmN901G1IKGTVJ9O8dw19ea",
+    'ERR_PARTIAL' => "tUxsOG6lvd60U893C8aQB6Z72883M6S1",
+    'ERR_NO_FILE2' => "8nUS01tMNreY2SC61g57V5E120a2f8wd",
+    'ERR_NO_TMP_DIR' => "4U4DfRK1JwWoyk6T9Qa4h773smDrhx78",
+    'ERR_CANT_WRITE' => "FSdmAd9TMeG7YKGcN8Vb4ooto78j94xQ",
+    'ERR_EXTENSION' => "vFrK8k1VnKw449Ftu3QJX32f7VLi0gkh",
+    'ERR_UPLOAD' => "axC6XDh5J38D9mtH6eC13fDAQeVh50gy",
+    'ERR_FILE_NAME'=> "I25q7cDjr7hT9y9IeXTJRC6Al52kjTsj",
+    'ERR_FILE_TYPE' => "7nV9J44C1Ms3f31V0B33TNxW2C3yGlXa",
+    'ERR_FILE_TMPPATH' => "7p95KtqF0rpS9f5pgwaUJSe9gL1s482T",
+    'ERR_FILE_SIZE' => "QapHtKQJjv2m2kOVt5g5465126wd3I0y",
+    'ERR_USER_SESSION' => "0AcGK57R4bjfTI8k7Y0fZFE4ETQ1MBrX",
+    'ERR_NAME' => "x11exQg6Lygl4Yz47R78FRIw799quH5P",
+    'ERR_CURRENTPAGE' => "9V2QCOkw9CWPHrNGZin8Ms6WX96H64mL",
+    'ERR_MAXVISIBLEPAGES' => "Q6ttpCa69RW3YNE98ZT8E6ub62TW1Ci0",
+    'ERR_ITEMSPERPAGE' => "slTlreOPn10VU0I8eq5xeo6yu133rr1A",  
+    'ERR_LANDINGPAGE' => "oDsf279T556WuF0dWnI5Lep0rWb538x7",   
+    'ERR_TOTITEMS' => "2iW0vpAN1YcXBN5sHzu5BbqUY8cKf2C2",   
+    'ERR_ID' => "0OdS5agNpvMUb7S5K7JH4vRRkQ1Af75n",  
+    'ERR_QUERYORDER' => "rknXwuwe79bpJcl4b3HsdJuTKMXbeiA8",   
+    'ERR_QUERYCOUNT' => "l71XwgU1oQR80m8ad0c51771g84Tmfkj",
+    'ERR_QUERYOFFSET' => "Xt2yxZFvRJzjJR8i4rHPeUQWdjj64ni8",
+    'ERR_LANGUAGE' => "qXG07iz29D4139Dv82nyfidZ0rb3Nx55", 
+    'ERR_UPDATE_TYPE' => "XXj4FfRg75x9G52drcuNn4wFN9PA5O68",
+    'ERR_CLASS_PARAMETER' => "mM6kv48j9YoRzxvoSghGjZzA81P7ZW6D",
+    'ERR_SID' => "yY2jO7dA34yN8l8XY4y6LvR562IKw8K3",
+    'ERR_URL' => "ji8tlwybgLIWXn39WjMr3Btjq55hO264",
+    'ERR_URL_EXISTS' => "E1W6hIt1NIvKKE5J4Ie4OMIS1w7guAaY",
+    'ERR_LICENSE' => "3n3eWwLS8O15B2hcENR1V9oEz6N1Urg7",
+    'ERR_VALUE' => "mfpf4YB51hwLRcbHCO75iOIjFLf62Adt",    
+    'ERR_SCRIPT' => "FOv6rNC0zZ9hJAcQci203NfLxE5I1Dx5",
+    'ERR_KEY' => "a0r15FBV1sMkLSJjZPGNG4jfD1ZEZ8Bt",
+    'ERR_DEFLANG_VALUE' => "mt0ky5w877E1r61uPHR8Kyy3L2Qucap7",
+    'ERR_DOUBLE_RESOURCE' => "P8gDL50HN9953pGc10Is1nr6pZDIr928",  
+    'ERR_WORD' => "sQ5zfY64zYjR06k4p11csawH1yTE497y",
+    'ERR_DOUBLE_WORD' => "rE7Y56ZoV40DjEn5hY20PWRBFItKdHG9",
+    'ERR_FILTER' => "3yGn0aF50m4641P63IR5ZEhBtEi1THM3",  
+    'ERR_PRIMCAT' => "4fdWHXEjlKNuPrv9avpr7I82iR8Hp5Yn",
+    'ERR_SECONDCAT' => "4299KiwIac5BjMt3tYF1XS9z1pLQ2c1X",
+    'ERR_THIRDCAT' => "94pQUGKmHa808R1R4w5Lw9xTl0kZdAf1",
+    'ERR_FOURTHCAT' => "p4PVCH3XWqZyFf4a9JZarb85Eyg9DeBm",
+    'ERR_FIFTHCAT' => "iYug27oaLzbkN4bblgvIsoXSn1LdHb3H",  
+    'ERR_NEWCAT' => "75AR87Rb31V091498o8nZyF5YW38wac2",
+    'ERR_NEWCAT_TEXT' => "270k4NIym160Y7v04Xueq67Fiz1390Q7",
+    'ERR_NEWSUBCATS' => "Jf5r0xB5F94O0G1kHD961Eh7KJ0747Ct",
+    'ERR_IMAGETYPE' => "LreYdjhbuP9ZiooW7F1vhhLRtyS9cITq",  
+    'ERR_IMAGETYPE_CAT' => "03C0uwNu9Y8Wp45SG5N5brPKUFRswdM8",
+    'ERR_CLASSIFI_OP' => "9beQuuTu0bb693naFr0pqSPXn416P9w5",
+    'ERR_DEFAULT_CLASSIFI' => "zkMvjN1CKDk8mDNKT1v4j2Iy8xuEhq0i",
+    'ERR_MODIFIER' => "71o01reqwGec1h8tC5URmLQxOo5SQ1Iw",
+    'ERR_IMAGE_CAT' => "gi17u1zT0Lu1r4HVRm9yBxn8dc1d0Gzv",
+    'ERR_IMAGE' => "S5KvIB5NJdv7b55Kj80CbdPZ8zV85t6e",  
+    'ERR_APPROVED' => "40zz08totKa01oChY50Q5BpEgJiK52GZ",
+    'ERR_DEBUG_INFO' => "hDy3Fo92hJV5tV12GQc6dc8crSFu8Y4d",
+    'ERR_REFERER' => "bYNB81774j5kJuZUb6D06XmF8UupjRWJ",
+    'ERR_USER' => "7ZnLN90x4IPqZL4s51cRJB0564v557Os",  
+    'ERR_MEDIATYPE' => "s3405pWyyg64d0aD6Q2WPZM8Z1R75XFg",
+    'ERR_SUBJECT' => "PDF79vr5D67dcGQvw9tBR7qw8NQ63121",  
+    'ERR_FROM' => "ZrLvAPcWk1Do6lsMe0RKm8ObquXk2E9L",
+    'ERR_TO' => "PcThvAYl3Fp7JRsCVe4Lm9sM0CQe4GVi",
+    'ERR_RTYPE' => "GNpSauDWf1Hj5pJtNa1DSf5HWjr8KcvP",
+    'ERR_EXPW' => "01DSf5HWjMoQsg2ATI7EYpJtNaTgvAXI"
+  ];
+
+/*
+  public static $A_ERR_MSG = [
+    'ERR_REQMETHOD' => "Invalid request method.",
+    'ERR_Q' => "Invalid search query.",
+    'ERR_CSRFTOKEN' => "Page has expired.",
+    'ERR_RESETTOKEN' => "Invalid reset token.", 
+    'ERR_ACTIVATIONTOKEN' => "Invalid activation token.", 
+    'ERR_USERNAME' => "Invalid username.",  
+    'ERR_EMAIL' => "Invalid email address.",
+    'ERR_PASSWORD' => "Invalid password (almost 8 chars long).", 
+    'ERR_CONFIRMPASSWORD' => "Password doesn't match.",  
+    'ERR_ERR' => "Invalid error.",
+    'ERR_MAILER' => "Mailer error.",
+    'ERR_GENERAL' => "Unexpected error happened.",
+    'ERR_ACTIVATION_UNAFFECTED' => "Account already active.",
+    'ERR_INPUT' => "Invalid input data.",
+    'ERR_USER_EXISTS' => "User already exist.",  
+    'ERR_EMAIL_EXISTS' => "Email already registred.",
+    'ERR_USERNAMEEMAIL' => "Invalid username/email.",
+    'ERR_LOGIN' => "Invalid login information.",    
+    'ERR_NO_FILE1' => "No file uploaded.",
+    'ERR_INI_SIZE' => "File exceeded size limit.",
+    'ERR_FORM_SIZE' => "File exceeded size limit.",
+    'ERR_PARTIAL' => "File only partially uploaded.",
+    'ERR_NO_FILE2' => "One or more files are missing.",
+    'ERR_NO_TMP_DIR' => "TMP dir doesn't exist.",
+    'ERR_CANT_WRITE' => "Failed to write to disk.",
+    'ERR_EXTENSION' => "Something stopped the file upload.",
+    'ERR_UPLOAD' => "Invalid upload.",
+    'ERR_FILE_NAME'=> "Invalid file name.",
+    'ERR_FILE_TYPE' => "Invalid file type.",
+    'ERR_FILE_TMPPATH' => "Invalid TMP path.",
+    'ERR_FILE_SIZE' => "Invalid file size.",
+    'ERR_USER_SESSION' => "Invalid user session.",
+    'ERR_NAME' => "Invalid name.",
+    'ERR_CURRENTPAGE' => "Invalid current page.",
+    'ERR_MAXVISIBLEPAGES' => "Invalid max visible pages.",
+    'ERR_ITEMSPERPAGE' => "Invalid items per page.",  
+    'ERR_LANDINGPAGE' => "Invalid landing page.",   
+    'ERR_TOTITEMS' => "Invalid total items.",   
+    'ERR_ID' => "Invalid id.",
+    'ERR_QUERYORDER' => "Invalid query order.",   
+    'ERR_QUERYCOUNT' => "Invalid query count.",
+    'ERR_QUERYOFFSET' => "Invalid query offset.",
+    'ERR_LANGUAGE' => "Invalid language.",
+    'ERR_UPDATE_TYPE' => "Invalid update type.",
+    'ERR_PARAM1' => "Invalid first parameter.",
+    'ERR_SID' => "Invalid search id.",
+    'ERR_URL' => "Invalid url.",
+    'ERR_URL_EXISTS' => "Url already registred.",
+    'ERR_LICENSE' => "Invalid license.",
+    'ERR_VALUE' => "Invalid value.",
+    'ERR_SCRIPT' => "Invalid script.",
+    'ERR_KEY' => "Invalid key.",
+    'ERR_DEFLANG_VALUE' => "Invalid default language value.",
+    'ERR_DOUBLE_RESOURCE' => "Resource already exists."  
+  ];
+  */
+  public static $A_ERR_MSG = [];
+
+  public static $A_ERR_EXTDES_MSG = [];
+  
+  /**
+   * the instance of the object 
+   * 
+   * @access private 
+   * @var Err
+   */
+  private static $_instance = null;  
+  
+  /**
+   * Reference to the previous error handler
+   * 
+   * @access public
+   * @var string  
+   */
+  private static $_old_error_handler;
+
+  /**
+   * Param1 of the previous error handler
+   * 
+   * @access public
+   * @var string  
+   */
+  private static $_old_error_handler_param1 = null;
+
+  /**
+   * Param2 of the previous error handler
+   * 
+   * @access public
+   * @var string  
+   */
+  private static $_old_error_handler_param2 = null;
+
+  /**
+   * Exception handler / trigger in the form of anonymous function
+   * 
+   * @access public 
+   * @var function
+   */
+  private static $_throw1;
+
+  /**
+   * Error handler / trigger in the form of anonymous function
+   * 
+   * @access public 
+   * @var function
+   */
+  private static $_trigger_error1;
+  
+  /**
+   * Default constructor
+   */
+  private function __construct()
+  {
+    self::$_old_error_handler = PHP_STR;
+    
+    //if (User::issetInstance()) {
+    //  $user = &User::getInstance();
+    //  $lang = (string)$user->getLanguage();
+    //} else {
+      $lang = (string)Session::get("lang", APP_DEF_LANG);
+    //}
+    
+    /*  
+    $cache = &Cache::getInstance();
+    
+    // Read from the cache first
+    $cacheKey = md5("CALL spGetErrResources('$lang','ERR')");
+    $aErrResources = $cache->getJ($cacheKey);
+    if (!$aErrResources) {
+
+      $db = &DB::getInstance();
+      
+      $sSQL = "CALL spGetErrResources(?, ?)";
+
+      $aErrResources = $db->select_SP($sSQL, [
+          ["s", $lang],
+          ["s", "ERR"]
+      ]);
+    }
+    // Store the data into the cache
+    $cache->setJ($cacheKey, $aErrResources, 0, CACHE_EXPIRE);
+
+    if (!empty($aErrResources)) {
+      foreach ($aErrResources as &$res) {    
+        //echo "Loading.." . $res['key'] . " = " . $res['value'] . "<br>";
+        self::$A_ERR_MSG[$res['key']] = $res['value']; 
+      }
+    }  
+
+    // Read from the cache first
+    $cacheKey = md5("CALL spGetErrResources('$lang','EXTDES')");
+    $aErrResources = $cache->getJ($cacheKey);
+    if (!$aErrResources) {
+
+      $db = &DB::getInstance();
+      
+      $sSQL = "CALL spGetErrResources(?, ?)";
+
+      $aErrResources = $db->select_SP($sSQL, [
+          ["s", $lang],
+          ["s", "EXTDES"]
+      ]);
+    }
+    // Store the data into the cache
+    $cache->setJ($cacheKey, $aErrResources, 0, CACHE_EXPIRE);
+
+    if (!empty($aErrResources)) {
+      foreach ($aErrResources as &$res) {    
+        //echo "Loading.." . $res['key'] . " = " . $res['value'] . "<br>";
+        self::$A_ERR_EXTDES_MSG[$res['key']] = $res['value']; 
+      }
+    } 
+     * 
+     */
+      
+  }
+
+  /**
+   * Get an instance of the resources object
+   * 
+   * @return object
+   */
+  private static function &getInstance(): Err 
+  {
+    if (!isset(self::$_instance)) {
+      self::$_instance = new Err();
+    }
+    return self::$_instance;
+  }
+  
+  /**
+   * Check if the static instance is set
+   * 
+   * @return bool
+   */
+  public static function issetInstance(): bool
+  {
+    return isset(self::$_instance);
+  }
+  
+  /**
+   * Unset the static instance
+   * 
+   * @return void
+   */
+  public static function unsetInstance(): void
+  {
+    unset(self::$_instance);
+  }
+
+  /**
+   * Load the error descriptions and other constants
+   * 
+   * @return void 
+   */
+  public static function load(): void
+  {
+      self::getInstance();
+  }
+  
+  /**
+   * Set the default error and exception handlers 
+   *
+   * @return void
+   * @access public
+   */ 
+  public static function setDefaultHandlers(): void 
+  {
+    // Assigning the error handling function..
+  
+    // Load the error resources..
+    self::load();
+
+    // Saving reference to the current error handler..
+    self::$_old_error_handler = "setDefaultHandlers";
+    self::$_old_error_handler_param1 = null;
+    self::$_old_error_handler_param2 = null;
+    
+    /**
+     * Error handling function
+     *
+     * @param string $errNo the number of the error
+     * @param string $errMsg the error message
+     * @param string $errScript the script where the error happened
+     * @param integer $errLine the line of code of the error
+     * @return bool
+     */
+    self::$_trigger_error1 = static function ($errNo, ?string $errMsg, ?string $errScript, ?int $errLine): bool 
+    {
+
+      $errKey = array_search($errNo, self::$A_ERR_NO);
+
+      // Log error
+      //$logfilename = ini_get("error_log");
+      //if (is_writable($logfilename)) {
+       // $logdata = "";
+       // date format: [18-Sep-2016 11:18:47 Europe/Rome]  
+       // $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "+++ERROR ($errNo): $errMsg : in script $errScript, line $errLine\n";
+       // $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "Ending script...\n";
+       // file_put_contents($logfilename, $logdata, FILE_APPEND);
+      //}  
+
+      error_log(strtoupper(APP_NAME) . " " . "+++ERROR ($errNo): $errMsg : in script $errScript, line $errLine");
+
+      // Logging the stack trace..
+      $aDebugTrace = debug_backtrace();
+      
+      if (count($aDebugTrace)>0) {
+        
+        $aDebugTrace = array_reverse($aDebugTrace);
+        array_pop($aDebugTrace); // "<-- closure()
+        //array_pop($aDebugTrace); // "<-- trigger_error()
+        
+        error_log(strtoupper(APP_NAME) . " " . "+++Stack trace:");
+
+        $i = 1;
+        foreach ($aDebugTrace as $trace) {
+          error_log(strtoupper(APP_NAME) . " " . "+++" . $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], ""));
+          $i=$i+1;
+        }
+      }
+
+      error_log(strtoupper(APP_NAME) . " " . "+++Ending script...");
+
+
+      // Display error
+      if (DEBUG) {
+        echo "ERROR ($errNo): "  . Page::HTMLencode($errMsg, true) . ": in script $errScript, line $errLine<br>";
+
+        // Printing the stack trace..
+        if (count($aDebugTrace)>0) {
+        
+          echo "Stack trace:" . "<br>";
+          
+          $i = 1;
+          foreach ($aDebugTrace as $trace) {
+            echo $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], "") . "<br>";
+            $i=$i+1;
+          }
+        }
+        
+      } else {
+        if (isset(self::$A_ERR_MSG[$errKey])) { 
+          echo Page::HTMLencode(self::$A_ERR_MSG[$errKey], true) . " in script " . basename($errScript) . ", line $errLine<br>";
+        } else { 
+          echo "Unexpected Error in script ".  basename($errScript) . ", line $errLine<br>";
+        } 
+      }
+      echo "Ending script...<br>";
+      
+      if (!TESTING) {
+        exit(1);
+      } else {
+        throw new Exception($errMsg);
+      }
+      
+      return true;
+    };
+
+    // Registering the error handling function..
+    set_error_handler(self::$_trigger_error1);
+    
+    
+    // Assigning the exception handling function..
+    
+    /**
+     * Exception handling function
+     *
+     * @param Exception $e the exception thrown
+     * @return void
+     */
+    self::$_throw1 = static function (\Throwable $e): void 
+    {
+  
+      $errNo=$e->getCode(); 
+      $errMsg=$e->getMessage();
+      $errScript=$e->getFile();
+      $errLine=$e->getLine(); 
+
+      $errKey = array_search($errNo, self::$A_ERR_NO);
+
+      // Log error
+      //$logfilename = ini_get("error_log");
+      //if (is_writable($logfilename)) {
+       // $logdata = "";
+       // date format: [18-Sep-2016 11:18:47 Europe/Rome]  
+        //$logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "+++ERROR ($errNo): $errMsg : in script $errScript, line $errLine\n";
+        //$logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "Ending script...\n";
+        //file_put_contents($logfilename, $logdata, FILE_APPEND);
+      //}
+
+      error_log(strtoupper(APP_NAME) . " " . "+++ERROR ($errNo): $errMsg : in script $errScript, line $errLine");
+
+      // Logging the stack trace..
+      $aDebugTrace = $e->getTrace();
+      
+      if (count($aDebugTrace)>0) {
+ 
+        $aDebugTrace = array_reverse($aDebugTrace);
+        
+        error_log(strtoupper(APP_NAME) . " " . "+++Stack trace:");
+
+        $i = 1;
+        foreach ($aDebugTrace as $trace) {
+          error_log(strtoupper(APP_NAME) . " " . "+++" . $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], ""));
+          $i=$i+1;
+        }
+      }
+
+      error_log(strtoupper(APP_NAME) . " " . "+++Ending script...");
+
+      // Display error
+      if (DEBUG) {
+        echo "ERROR ($errNo): " . Page::HTMLencode($errMsg, true) . ": in script $errScript, line $errLine<br>";
+
+        // Printing the stack trace..
+        if (count($aDebugTrace)>0) {
+ 
+          echo "Stack trace:" . "<br>";
+          
+          $i = 1;
+          foreach ($aDebugTrace as $trace) {
+            echo $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], "") . "<br>";
+            $i=$i+1;
+          }
+        }
+        
+      } else {
+        if (isset(self::$A_ERR_MSG[$errKey])) { 
+          echo Page::HTMLencode(self::$A_ERR_MSG[$errKey], true) . " in script " . basename($errScript) . ", line $errLine<br>";
+        } else { 
+          echo "Unexpected Error in script ".  basename($errScript) . ", line $errLine<br>";
+        } 
+      }
+      echo "Ending script...<br>";
+
+      if (!TESTING) {
+        exit(1);
+      } else {
+        throw new Exception($errMsg);
+      }
+
+    };
+    
+    // Registering the exception handling function
+    set_exception_handler(self::$_throw1);
+    
+  }
+
+  /**
+   * Set the error handlers to redirect to a page 
+   *
+   * @param  string  $landingPage the landing page to redirect to
+   * @param  string  $queryString additional query string to pass in the redirect
+   * @return void
+   * @access public
+   */ 
+  public static function setRedirectHandlers(string $landingPage, ?string $queryString = ""): void 
+  {
+
+    // Assigning the error handling function..
+    
+    // Load the error resources..
+    self::load();
+
+    // Saving reference to the current error handler..
+    self::$_old_error_handler = "setRedirectHandlers";
+    self::$_old_error_handler_param1 = $landingPage;
+    self::$_old_error_handler_param2 = $queryString;
+
+    /**
+     * Error handling function
+     *
+     * @param string $errNo the number of the error
+     * @param string $errMsg the error message
+     * @param string $errScript the script where the error happened
+     * @param integer $errLine the line of code of the error
+     * @return bool
+     */
+    self::$_trigger_error1 = static function ($errNo, string $errMsg, ?string $errScript, ?int $errLine) use ($landingPage, $queryString): bool 
+    {
+      
+      // Log error
+      //$logfilename = ini_get("error_log");
+      //if (is_writable($logfilename)) {
+        //$logdata = "";
+        // date format: [18-Sep-2016 11:18:47 Europe/Rome]        
+        //$logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine\n";
+        //$logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "Redirecting...\n";
+        //file_put_contents($logfilename, $logdata, FILE_APPEND);
+      //}
+
+      error_log(strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine");
+      
+      // Logging the stack trace..
+      $aDebugTrace = debug_backtrace();
+      
+      if (count($aDebugTrace)>0) {
+        
+        $aDebugTrace = array_reverse($aDebugTrace);
+        array_pop($aDebugTrace); // "<-- closure()
+        //array_pop($aDebugTrace); // "<-- trigger_error()
+        
+        error_log(strtoupper(APP_NAME) . " Stack trace:");
+
+        $i = 1;
+        foreach ($aDebugTrace as $trace) {
+          error_log(strtoupper(APP_NAME) . " " . $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], ""));
+          $i=$i+1;
+        }
+      }
+      
+      error_log(strtoupper(APP_NAME) . " " . "Redirecting...");
+
+      //Redirect with error..
+      if (DEBUG || ADMIN) { 
+        
+        //Buffering stack trace..
+        $errStack = "";
+        if (count($aDebugTrace)>0) {
+        
+          $errStack = "Stack trace:" . "<br>";
+          
+          $i = 1;
+          foreach ($aDebugTrace as $trace) {
+            $errStack .= $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], "") . "<br>";
+            $i=$i+1;
+          }
+        }
+        
+        Page::redirect($landingPage . (stripos($landingPage, "?")>0 ? "&" : "?") . "uid=" . uniqid(rand(), true) . ($queryString!="" ? "&". $queryString : "") . "&errNo=" . urlencode($errNo) . "&errMsg=" . urlencode($errMsg) . "&errScript=" . urlencode($errScript) . "&errLine=" . urlencode($errLine) . "&errStack=" . urlencode($errStack));
+      } else {
+        Page::redirect($landingPage . (stripos($landingPage, "?")>0 ? "&" : "?") . "uid=" . uniqid(rand(), true) . ($queryString!="" ? "&". $queryString : "") . "&errNo=" . urlencode($errNo));
+      }  
+
+      if (!TESTING) {
+        exit(1);
+      } else {
+        throw new Exception($errMsg);
+      }
+      
+      return true;
+    };
+
+    // Registering the error handling function..
+    set_error_handler(self::$_trigger_error1);
+    
+    
+    // Assigning the exception handling function..
+    
+    /**
+     * Exception handling function
+     *
+     * @param Exception $e the exception thrown
+     * @return void
+     */
+    self::$_throw1 = static function (\Throwable $e) use ($landingPage, $queryString): void
+    {
+  
+      $errNo=$e->getCode(); 
+      $errMsg=$e->getMessage();
+      $errScript=$e->getFile();
+      $errLine=$e->getLine(); 
+
+      // Log error
+      //$logfilename = ini_get("error_log");
+      //if (is_writable($logfilename)) {
+       // $logdata = "";
+       // date format: [18-Sep-2016 11:18:47 Europe/Rome]  
+       // $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script $errScript, line $errLine\n";
+       // $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "Ending script...\n";
+        //file_put_contents($logfilename, $logdata, FILE_APPEND);
+      //}
+
+      error_log(strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine");
+      
+      // Logging the stack trace..
+      $aDebugTrace = $e->getTrace();
+      
+      if (count($aDebugTrace)>0) {
+ 
+        $aDebugTrace = array_reverse($aDebugTrace);
+        
+        error_log(strtoupper(APP_NAME) . " Stack trace:");
+
+        $i = 1;
+        foreach ($aDebugTrace as $trace) {
+          error_log(strtoupper(APP_NAME) . " " . $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], ""));
+          $i=$i+1;
+        }
+      }
+        
+      error_log(strtoupper(APP_NAME) . " " . "Redirecting...");
+
+      //Redirect with error..
+      if (DEBUG || ADMIN) { 
+
+        //Buffering stack trace..
+        $errStack = "";
+        if (count($aDebugTrace)>0) {
+        
+          $errStack = "Stack trace:" . "<br>";
+          
+          $i = 1;
+          foreach ($aDebugTrace as $trace) {
+            $errStack .= $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], "") . "<br>";
+            $i=$i+1;
+          }
+        }
+
+        Page::redirect($landingPage . (stripos($landingPage, "?")>0 ? "&" : "?") . "uid=" . uniqid(rand(), true) . ($queryString!="" ? "&". $queryString : "") . "&errNo=" . urlencode($errNo) . "&errMsg=" . urlencode($errMsg) . "&errScript=" . urlencode($errScript) . "&errLine=" . urlencode($errLine) . "&errStack=" . urlencode($errStack));
+      } else {
+        Page::redirect($landingPage . (stripos($landingPage, "?")>0 ? "&" : "?") . "uid=" . uniqid(rand(), true) . ($queryString!="" ? "&". $queryString : "") . "&errNo=" . urlencode($errNo));
+      }   
+
+      if (!TESTING) {
+        exit(1);
+      } else {     
+        throw new Exception($errMsg);
+      }
+    };
+    
+    // Registering the exception handling function
+    set_exception_handler(self::$_throw1);
+  }
+  
+  /**
+   * Set the error handlers to json  
+   *
+   * @return void
+   * @access public
+   */ 
+  public static function setJSONHandlers(): void 
+  {
+
+    // Assigning the error handling function..
+    
+    // Load the error resources..
+    self::load();
+
+    // Saving reference to the current error handler..
+    self::$_old_error_handler = "setJSONHandlers";
+    self::$_old_error_handler_param1 = null;
+    self::$_old_error_handler_param2 = null;
+
+    /**
+     * Error handling function
+     *
+     * @param string $errNo the number of the error
+     * @param string $errMsg the error message
+     * @param string $errScript the script where the error happened
+     * @param integer $errLine the line of code of the error
+     * @return bool
+     */
+    self::$_trigger_error1 = static function ($errNo, string $errMsg, ?string $errScript, ?int $errLine): bool 
+    {
+      
+      // Log error
+      //$logfilename = ini_get("error_log");
+      //if (is_writable($logfilename)) {
+      //  $logdata = "";
+        // date format: [18-Sep-2016 11:18:47 Europe/Rome]        
+      //  $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine\n";
+      //  $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "Redirecting...\n";
+      //  file_put_contents($logfilename, $logdata, FILE_APPEND);
+      //}
+
+      error_log(strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine");
+
+      // Logging the stack trace..
+      $aDebugTrace = debug_backtrace();
+      
+      if (count($aDebugTrace)>0) {
+        
+        $aDebugTrace = array_reverse($aDebugTrace);
+        array_pop($aDebugTrace); // "<-- closure()
+        //array_pop($aDebugTrace); // "<-- trigger_error()
+        
+        error_log(strtoupper(APP_NAME) . " Stack trace:");
+
+        $i = 1;
+        foreach ($aDebugTrace as $trace) {
+          error_log(strtoupper(APP_NAME) . " " . $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], ""));
+          $i=$i+1;
+        }
+      }
+      
+      error_log(strtoupper(APP_NAME) . " " . "Ending Json...");
+     
+      //Json encode the error..
+      if (DEBUG || ADMIN) { 
+        
+        //Buffering stack trace..
+        $errStack = "";
+        if (count($aDebugTrace)>0) {
+        
+          $errStack = "Stack trace:" . "<br>";
+          
+          $i = 1;
+          foreach ($aDebugTrace as $trace) {
+            $errStack .= $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], "") . "<br>";
+            $i=$i+1;
+          }
+        }
+        
+        echo json_encode([$errNo, $errMsg, $errScript, $errLine, $errStack]);
+      } else {
+        echo json_encode([$errNo]);
+      }  
+
+      if (!TESTING) {
+        exit(1);
+      } else {
+        throw new Exception($errMsg);
+      }
+      
+      return true;
+    };
+    
+    // Registering the error handling function..
+    set_error_handler(self::$_trigger_error1);
+    
+    
+    // Assigning the exception handling function..
+    
+    /**
+     * Exception handling function
+     *
+     * @param Exception $e the exception thrown
+     * @return void
+     */
+    self::$_throw1 = static function (\Throwable $e): void 
+    {
+  
+      $errNo=$e->getCode(); 
+      $errMsg=$e->getMessage();
+      $errScript=$e->getFile();
+      $errLine=$e->getLine(); 
+
+      // Log error
+      //$logfilename = ini_get("error_log");
+      //if (is_writable($logfilename)) {
+      //  $logdata = "";
+       // date format: [18-Sep-2016 11:18:47 Europe/Rome]  
+      //  $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script $errScript, line $errLine\n";
+      //  $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "Ending script...\n";
+      //  file_put_contents($logfilename, $logdata, FILE_APPEND);
+      //}
+
+      error_log(strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine");
+
+      // Logging the stack trace..
+      $aDebugTrace = $e->getTrace();
+      
+      if (count($aDebugTrace)>0) {
+ 
+        $aDebugTrace = array_reverse($aDebugTrace);
+        
+        error_log(strtoupper(APP_NAME) . " Stack trace:");
+
+        $i = 1;
+        foreach ($aDebugTrace as $trace) {
+          error_log(strtoupper(APP_NAME) . " " . $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], ""));
+          $i=$i+1;
+        }
+      }
+
+      error_log(strtoupper(APP_NAME) . " " . "Ending Json...");
+
+      //Json encode the error..
+      if (DEBUG || ADMIN) { 
+
+        //Buffering stack trace..
+        $errStack = "";
+        if (count($aDebugTrace)>0) {
+        
+          $errStack = "Stack trace:" . "<br>";
+          
+          $i = 1;
+          foreach ($aDebugTrace as $trace) {
+            $errStack .= $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], "") . "<br>";
+            $i=$i+1;
+          }
+        }
+
+        echo json_encode([$errNo, $errMsg, $errScript, $errLine, $errStack]);
+      } else {
+        echo json_encode([$errNo]);
+      }  
+
+      if (!TESTING) {
+        exit(1);
+      } else {    
+        throw new Exception($errMsg);
+      }
+
+    };
+    
+    // Registering the exception handling function
+    set_exception_handler(self::$_throw1);
+  
+  }
+
+  /**
+   * Set the error handlers to log the error only  
+   *
+   * @return void
+   * @access public
+   */ 
+  public static function setLogOnlyHandlers(): void 
+  {
+
+    // Assigning the error handling function..
+    
+    // Load the error resources..
+    self::load();
+
+    /**
+     * Error handling function
+     *
+     * @param string $errNo the number of the error
+     * @param string $errMsg the error message
+     * @param string $errScript the script where the error happened
+     * @param integer $errLine the line of code of the error
+     * @return bool
+     */
+    self::$_trigger_error1 = static function ($errNo, string $errMsg, ?string $errScript, ?int $errLine): bool
+    {
+      
+      // Log error
+      //$logfilename = ini_get("error_log");
+      //if (is_writable($logfilename)) {
+      //  $logdata = "";
+        // date format: [18-Sep-2016 11:18:47 Europe/Rome]        
+      //  $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine\n";
+      //  $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "Continuing...\n";
+      //  file_put_contents($logfilename, $logdata, FILE_APPEND);
+      //}
+      
+      error_log(strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine");
+
+      // Logging the stack trace..
+      $aDebugTrace = debug_backtrace();
+      
+      if (count($aDebugTrace)>0) {
+        
+        $aDebugTrace = array_reverse($aDebugTrace);
+        array_pop($aDebugTrace); // "<-- closure()
+        //array_pop($aDebugTrace); // "<-- trigger_error()
+        
+        error_log(strtoupper(APP_NAME) . " Stack trace:");
+
+        $i = 1;
+        foreach ($aDebugTrace as $trace) {
+          error_log(strtoupper(APP_NAME) . " " . $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], ""));
+          $i=$i+1;
+        }
+      }
+      
+      error_log(strtoupper(APP_NAME) . " " . "Continuing...");
+
+      return true;
+      
+    };
+
+    // Registering the error handling function..
+    set_error_handler(self::$_trigger_error1);
+    
+    
+    // Assigning the exception handling function..
+    
+    /**
+     * Exception handling function
+     *
+     * @param Exception $e the exception thrown
+     * @return void
+     */
+    self::$_throw1 = static function (\Throwable $e): void 
+    {
+  
+      $errNo=$e->getCode(); 
+      $errMsg=$e->getMessage();
+      $errScript=$e->getFile();
+      $errLine=$e->getLine(); 
+
+      // Log error
+      //$logfilename = ini_get("error_log");
+      //if (is_writable($logfilename)) {
+      //  $logdata = "";
+       // date format: [18-Sep-2016 11:18:47 Europe/Rome]  
+      //  $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script $errScript, line $errLine\n";
+      //  $logdata .= "[" . date("d-M-Y H:i:s e") . "]" . " " . strtoupper(APP_NAME) . " " . "Ending script...\n";
+      //  file_put_contents($logfilename, $logdata, FILE_APPEND);
+      //}
+      
+      error_log(strtoupper(APP_NAME) . " " . "ERROR ($errNo): $errMsg : in script " . $errScript . ", line $errLine");
+
+      // Logging the stack trace..
+      $aDebugTrace = $e->getTrace();
+      
+      if (count($aDebugTrace)>0) {
+ 
+        $aDebugTrace = array_reverse($aDebugTrace);
+        
+        error_log(strtoupper(APP_NAME) . " Stack trace:");
+
+        $i = 1;
+        foreach ($aDebugTrace as $trace) {
+          error_log(strtoupper(APP_NAME) . " " . $i . " " . $trace['function'] . "()" . " " . ((isset($trace['file'])) ? $trace['file'] . ":" : "") . isset1($trace['line'], ""));
+          $i=$i+1;
+        }
+      }
+      
+      error_log(strtoupper(APP_NAME) . " " . "Continuing...");
+    };
+    
+    // Registering the exception handling function
+    set_exception_handler(self::$_throw1);
+  }
+
+  /**
+   * Set back the error handlers  
+   *
+   * @return void
+   * @access public
+   */ 
+  public static function setPreviousHandlers(): void 
+  {
+    //restore_error_handler();
+    //restore_exception_handler();
+    
+    // Restoring previous error handlers..
+    if (self::$_old_error_handler === "setDefaultHandlers") {
+      self::setDefaultHandlers();
+    } else if (self::$_old_error_handler === "setRedirectHandlers") {
+      self::setRedirectHandlers(self::$_old_error_handler_param1, self::$_old_error_handler_param2);
+    } else if (self::$_old_error_handler === "setJSONHandlers") {
+      self::setJSONHandlers();
+    }
+  }  
+  
+  /**
+   * Error trigger 
+   *
+   * @param string $errNo the number of the error
+   * @param string $errMsg the error message
+   * @param string $errScript the script where the error happened
+   * @param integer $errLine the line of code of the error
+   * @return void
+   * @access public
+   */
+  public static function trigger_error1($errNo, string $errMsg, ?string $errScript, ?int $errLine): bool 
+  {
+    $trigger_error1 = self::$_trigger_error1;
+    
+    $trigger_error1($errNo, $errMsg, $errScript, $errLine);
+    
+    return true;
+  }
+  
+  /**
+   * Exception trigger 
+   *
+   * @param Exception $e the exception to trigger
+   * @return void
+   * @access public
+   */
+  public static function throw1(\Throwable $e) 
+  {
+    $throw1 = self::$_throw1;
+    
+    $throw1($e);
+  }
+}

+ 92 - 0
Private/classes/fivemode/fivemode/class.errutil.inc

@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.errutil.inc
+ * 
+ * ErrUtil class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * ErrUtil
+ *
+ * Error utilities class
+ *
+ * @package  Err
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  2.0
+ * @access   public
+ */
+final class ErrUtil 
+{
+  
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+  
+  /**
+   * Check if the given error is valid
+   *
+   * @param string $err the number of error
+   * @param string $errKey the error key
+   * @param string $errMsg the error message
+   * @return boolean if the given error is valid or not
+   */
+  public static function isValidError(string $err, ?string &$errKey = null, ?string &$errMsg = null): bool 
+  {
+    if ($err==="") {
+      return false;
+    }
+
+    if (isset($errKey) && isset($errMsg)) {
+      $errKey = array_search($err, Err::$A_ERR_NO);
+      if ($errKey) {
+        $errMsg = Err::$A_ERR_MSG[$errKey];
+        return true;
+      } else {
+        return false;
+      }
+    } else {
+      if (array_search($err, Err::$A_ERR_NO, true)) {
+        return true;
+      } else {
+        return false;
+      }
+    }
+  }
+}

+ 364 - 0
Private/classes/fivemode/fivemode/class.linkutil.inc

@@ -0,0 +1,364 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.linkutil.inc
+ * 
+ * The LinkUtil class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * LinkUtil
+ *
+ * LinkUtil class
+ *
+ * @package  Link
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  1.0
+ * @access   public
+ */
+final class LinkUtil
+{
+  /**
+   * DEBUG FLAG 
+   */
+  private const DEBUG_THIS = true;
+  
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+  
+  /**
+   * Clean the chunk of the tag path array
+   *
+   * @return void
+   * @access private
+   */
+  private static function cleanTagPathArrayChunk(&$array): void 
+  {
+    foreach($array as $entry) {
+      $ipos = mb_strrpos($entry, PHP_SLASH);
+      $entry = left($entry, $ipos);
+    }  
+  }  
+  
+  
+  public static function getLinkList($q, $catMaskedPath): array
+  {
+    $reta = [];
+    
+    $aLangs = [PHP_EN];
+    
+    $searchCriteria = trim(strtolower($q));
+    
+    if ($searchCriteria==="*" || $searchCriteria === "tutte" || $searchCriteria === "所有的") {
+      $searchCriteria = "all";
+    }
+
+    $searchCriteria = str_cleanplurals($searchCriteria); 
+
+    $aKeywords = explode(PHP_SPACE, $searchCriteria);
+
+    // Cleaning words from the exclusion list..
+    if ($searchCriteria !== "all") {
+
+      foreach ($aLangs as & $langEntry) {
+        $exclusionList = Config::get("SEARCH/WORD_EXCLUSION_LIST_" . $langEntry);
+
+        $i=0;
+        foreach($aKeywords as $word) {
+
+          if (mb_stripos($exclusionList, "|" . $word . "|")) {
+            //echo_ifdebug(self::DEBUG_this, "excluded word: " . $word . "<br>");
+
+            $searchCriteria = str_replace(PHP_SPACE . $word . PHP_SPACE, PHP_SPACE, PHP_SPACE . $searchCriteria . PHP_SPACE);
+            $searchCriteria = strtolower($searchCriteria);
+
+            unset($aKeywords[$i]);
+          }
+
+          $i++;
+        }      
+      }
+
+      $searchCriteria = str_cleanphrase_M($searchCriteria);
+      
+    }
+        
+    $aKeywords = explode(PHP_SPACE, $searchCriteria);
+        
+    $aRepoDataPaths = Array2::PHP_EMPTY;
+    
+    //chdir(APP_PATH . PHP_SLASH . $platform);
+    chdir(APP_DATA_PATH);
+        
+    //echo("platform=" . $platform . "<br>");
+    //echo("q=" . $q . "<br>");
+    
+    //if ($q!==PHP_STR) {
+    //  $pattern = "*" . $q . "*/data/cats/" . $catMaskedPath;
+    //} else {
+    //  $pattern = "*/data/cats/" . $catMaskedPath;
+    //}  
+    //$aPaths = array_slice(glob($pattern), 0, 100);
+
+    $pattern = "*/data/cats/" . $catMaskedPath;
+    $aPaths = array_slice(glob($pattern), 0, 100);
+    
+    //echo_ifdebug(true, $pattern . "<br>");
+    //var_dump_ifdebug(true, $aPaths);
+    
+    if(!Empty($aPaths)) {
+
+      self::cleanTagPathArrayChunk($aPaths);
+      
+      //Processing the tags..     
+      foreach ($aPaths as &$fsEntry) {
+
+        $repoDataDir = PHP_STR;
+        $ipos = mb_stripos1($fsEntry, PHP_SLASH);
+        $ipos = mb_stripos1($fsEntry, PHP_SLASH, $ipos + 1);
+        $repoDataDir = left($fsEntry, $ipos -1);
+
+        $ipos = mb_strrpos($repoDataDir, PHP_SLASH);
+        $repoFullPath = left($repoDataDir, $ipos);
+
+        if (!is_link($repoFullPath)) {
+        
+          //echo_ifdebug(self::DEBUG_this, "Tags > first match:" . $repoDataDir . "<br>");
+
+          $bMatchPhrase = true;
+          foreach ($aKeywords as &$word) {
+            
+            $tagPattern1 = $repoDataDir . "/tags/" . $word;
+            $tagPattern2 = $repoDataDir . "/tags/" . $word . "s";
+            $tagPattern3 = $repoDataDir . "/tags/" . $word . "es";
+            $tagPattern4 = "____";
+            if (right($word,1) === "y") {
+              $tagPattern4 = $repoDataDir . "/tags/" . left($word, strlen($word)-1) . "ies";
+            }  
+            
+            //if (!glob($tagPattern)) {
+            if (trim($searchCriteria)==="all") {
+              
+            } else if (!is_readable($tagPattern1) && !is_readable($tagPattern2) && !is_readable($tagPattern3) && !is_readable($tagPattern4)) {
+              //echo_ifdebug(self::DEBUG_this, "$tagPattern1<br>");
+              //echo_ifdebug(self::DEBUG_this, "$tagPattern2<br>");
+              //echo_ifdebug(self::DEBUG_this, "$tagPattern3<br>");
+              //echo_ifdebug(self::DEBUG_this, "$tagPattern4<br>");
+              $bMatchPhrase = false;
+              break;
+            }
+          }
+
+          if ($bMatchPhrase) { 
+            // Adding the tag path to the final array od data paths..
+            //echo_ifdebug(self::DEBUG_this, "Tags > result: included!!<br>");
+            $aRepoDataPaths[$repoDataDir] = $repoDataDir;
+          } else {
+            //echo_ifdebug(self::DEBUG_this, "Tags > result: Not included.<br>");
+          }  
+        }  
+      }    
+      
+      $iresults = 0; 
+      foreach($aRepoDataPaths as $path) {
+        
+        $iFields = 0;
+        
+        $name = PHP_STR;
+        $title = PHP_STR;
+        $link = PHP_STR;
+        $label = PHP_STR;
+        $desc = PHP_STR;
+        $thumb = PHP_STR;
+        $image = PHP_STR;
+        $code = PHP_STR;
+        $guid = PHP_STR;
+        
+        $ipos = mb_stripos($path, PHP_SLASH, 2);
+        $basedir = substr($path, 0, $ipos);
+        
+        //name
+        $name = trim($basedir, PHP_SLASH); 
+        $iFields++;
+        
+        //title
+        $pattern = $basedir . PHP_SLASH . "data". PHP_SLASH . "title" . PHP_SLASH . "*";
+        $aTitlePaths = array_slice(glob($pattern), 0, 1);
+        if (!Empty($aTitlePaths)) {
+          $titlePath = $aTitlePaths[0];
+          $ipos = strripos($titlePath, PHP_SLASH);
+          $title = substr($titlePath, $ipos+1);
+          $iFields++;
+        } 
+       
+        //link        
+        $pattern = $basedir . PHP_SLASH . "data". PHP_SLASH . "link" . PHP_SLASH . "*";
+        $aLinkPaths = array_slice(glob($pattern), 0, 1);
+        if (!Empty($aLinkPaths)) {
+          $linkPath = $aLinkPaths[0];
+          $ipos = strripos($linkPath, PHP_SLASH);
+          $link = substr($linkPath, $ipos+1);
+          $iFields++;
+        } 
+        
+        //label
+        $pattern = $basedir . PHP_SLASH . "data". PHP_SLASH . "label" . PHP_SLASH . "*";
+        $aLabelPaths = array_slice(glob($pattern), 0, 1);
+        if (!Empty($aLabelPaths)) {
+          $labelPath = $aLabelPaths[0];
+          $ipos = strripos($labelPath, PHP_SLASH);
+          $label = substr($labelPath, $ipos+1);
+          $iFields++;
+        } 
+        
+        //desc
+        $pattern = $basedir . PHP_SLASH . "data". PHP_SLASH . "desc" . PHP_SLASH . "*";
+        $aDescPaths = array_slice(glob($pattern), 0, 1);
+        if (!Empty($aDescPaths)) {
+          $descPath = $aDescPaths[0];
+          $ipos = strripos($descPath, PHP_SLASH);
+          $desc = substr($descPath, $ipos+1);
+          $iFields++;
+        } 
+
+        //thumb
+        //$pattern = APP_PATH . PHP_SLASH . "static" . PHP_SLASH . "404". PHP_SLASH . $name . PHP_UNDERSCORE . "sm" . ".*";
+        $pattern = APP_PATH . PHP_SLASH . "img". PHP_SLASH . $name . PHP_UNDERSCORE . "sm" . ".*";
+        $aThumbPaths = array_slice(glob($pattern), 0, 1);
+        if (!Empty($aThumbPaths)) {
+          $thumbPath = $aThumbPaths[0];
+          $ipos = strripos($thumbPath, PHP_SLASH);
+          $thumb = substr($thumbPath, $ipos+1);
+          $iFields++;
+        } else {
+          $thumb = "code_sm.png";
+          $iFields++;
+        } 
+        
+        //image
+        //$pattern = APP_PATH . PHP_SLASH . "static" . PHP_SLASH . "404". PHP_SLASH . $name . ".*";
+        $pattern = APP_PATH . PHP_SLASH . "img". PHP_SLASH . $name . ".*";
+        $aImagePaths = array_slice(glob($pattern), 0, 1);
+        if (!Empty($aImagePaths)) {
+          $imagePath = $aImagePaths[0];
+          $ipos = strripos($imagePath, PHP_SLASH);
+          $image = substr($imagePath, $ipos+1);
+          $iFields++;
+        } else {
+          $image = "code.png";
+          $iFields++;
+        } 
+
+        //code
+        $pattern = $basedir . PHP_SLASH . "data". PHP_SLASH . "code" . PHP_SLASH . "code.txt";
+        $aCodePaths = array_slice(glob($pattern), 0, 1);
+        if (!Empty($aCodePaths)) {
+          $codePath = $aCodePaths[0];
+          //$ipos = strripos($codePath, PHP_SLASH);
+          //$image = substr($imagePath, $ipos+1);
+          $code = file_get_contents(APP_DATA_PATH . PHP_SLASH . $codePath);
+          $iFields++;
+        } else {
+          $code = PHP_STR;
+          $iFields++;
+        }
+        
+        //tags
+        $pattern = $basedir . PHP_SLASH . "data". PHP_SLASH . "tags" . PHP_SLASH . "*";
+        $aTagPaths = glob($pattern);
+        if (!Empty($aTagPaths)) {
+          $bFound = false;
+          $tags = "";
+          foreach($aTagPaths as $tagPath) {
+            $ipos = strripos($tagPath, PHP_SLASH);
+            $tags .= substr($tagPath, $ipos+1) . PHP_SPACE;
+            $bFound = true;
+          }  
+          if ($bFound) {
+            $tags = rtrim($tags, PHP_SPACE);
+            $iFields++;
+          }
+        }         
+
+        //guid
+        $pattern = $basedir . PHP_SLASH . "data". PHP_SLASH . "guid" . PHP_SLASH . "*";
+        $aGuidPaths = array_slice(glob($pattern), 0, 1);
+        if (!Empty($aGuidPaths)) {
+          $guidPath = $aGuidPaths[0];
+          $ipos = strripos($guidPath, PHP_SLASH);
+          $guid = substr($guidPath, $ipos+1);
+          $iFields++;
+        } 
+
+        //cats
+        $pattern = $basedir . PHP_SLASH . "data". PHP_SLASH . "cats" . PHP_SLASH . "*";
+        $aCatPaths = glob($pattern);
+        if (!Empty($aCatPaths)) {
+          $bFound = false;
+          $cats = "";
+          foreach($aCatPaths as $catPath) {
+            $ipos = strripos($catPath, PHP_SLASH);
+            $cats .= substr($catPath, $ipos+1) . PHP_SPACE;
+            $bFound = true;
+          }  
+          if ($bFound) {
+            $cats = rtrim($cats, PHP_SPACE);
+            $iFields++;
+          }
+        }  
+        
+        if ($iFields===11) {
+          //for ($i=0;$i<=50;$i++) {
+            if (!array_key_exists($name, $reta)) {
+              $reta[$name] = ['name' => $name, 'title' => $title, 'desc' => $desc, 'label' => $label, 'link' => $link, 'thumb' => $thumb, 'image' => $image, 'code' => $code, 'tags' => $tags, 'guid' => $guid, 'cats' => $cats];
+              $iresults++;
+            }  
+          //}  
+        }  
+        
+        if ($iresults>=50) {
+          break;
+        }
+      }
+    }
+    
+    return $reta;
+  }
+}

+ 346 - 0
Private/classes/fivemode/fivemode/class.page.inc

@@ -0,0 +1,346 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.page.inc
+ * 
+ * Page class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * Page
+ *
+ * Page class
+ *
+ * @package  Page
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  2.0
+ * @access   public
+ */
+final class Page 
+{
+  
+  const URL_OUTPUT_RAW = 1;
+  const URL_OUTPUT_FORMATTED = 2;
+  const URL_OUTPUT_TEXT = 3;
+  
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+  
+  /**
+   * The buffer for the javascript of page footer
+   *  
+   * @access private
+   * @var Array
+   */
+  private static $aFooterJSBuffer = Array2::PHP_EMPTY;
+  
+  /**
+   * Add the given javascript code to the page buffer
+   * 
+   * @param string $JScode the JS code to add in the page footer
+   */
+  public static function addToJSBuffer(string $JScode): void
+  {
+    self::$aFooterJSBuffer[] = $JScode;
+  }
+
+  /**
+   * Clear the page buffer for the javascript code
+   */
+  public static function clearJSBuffer(): void 
+  {
+    self::$aFooterJSBuffer = Array2::PHP_EMPTY;
+  }
+
+  /**
+   * Display the content of the page buffer for the javascript code
+   */
+  public static function displayJSBuffer(): void
+  {
+    foreach(self::$aFooterJSBuffer as $JScode) {
+      echo $JScode . PHP_EOL. PHP_EOL;
+    }  
+  }
+  
+  /**
+   * Enable the links of the given text
+   * 
+   * @param string $text the text being parsed for links
+   * @return the text with enabled links
+   */
+  public static function enableEmailLinks(string $text, bool $masked): string
+  {
+    settype($text, "string");
+    settype($masked, "boolean");
+    
+    $callable_masked = function($aResults) {
+      $result = implode(PHP_STR, $aResults); 
+      return "<a href='mailto:$result'>" . mb_strrichr($result, "@", true) . "@.." . mb_strrichr($result, ".", false) . "</a>";
+    };
+
+    $callable_unmasked = function($aResults) {
+      $result = implode(PHP_STR, $aResults); 
+      return "<a href='mailto:$result'>$result</a>";
+    };
+
+    $regexPattern = "/(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+@((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}/";
+    
+    if ($masked) {
+      $callable = $callable_masked;
+    } else {
+      $callable = $callable_unmasked;
+    } 
+    
+    return preg_replace_callback($regexPattern, $callable, $text);
+  }  
+
+  /**
+   * Enable the links of the given text
+   * 
+   * @param string $text the text being parsed for links
+   * @return the text with enabled links
+   */
+  public static function enableLinks(string $text): string
+  {
+    //return preg_replace("/(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,8})([\/\w \.-]*)$/", "\\0&nbsp;<a href='\\0' target=\"_blank\">[#1]</a>", $text);
+    return preg_replace("/(https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,8})(\/?.+)?$/", "<span style='color:darkgray; background:#E0E0E0;'>\\0&nbsp;[&nbsp;<a href='\\0' target=\"_blank\" style=\"font-size: large;\">@</a>&nbsp;]</span>", $text);
+  }  
+  
+  /**
+   * Enable the links of the given text
+   * 
+   * @param string $text the text being parsed for links
+   * @return the text with enabled links
+   */
+  public static function getFirstEnabledLink(string $text, bool $formatted = true): string
+  {
+    $matches = [];
+    $bDFLTLINK = false;
+    //return preg_replace("/(https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,8})(\/?.+)?$/", "<span style='color:darkgray; background:#E0E0E0;'>\\0&nbsp;[&nbsp;<a href='\\0' target=\"_blank\" style=\"font-size: large;\">@</a>&nbsp;]</span>", $text);
+    //$preg_retval = preg_match("/(https?:\/\/[\da-z\.-]+\.[a-z\.]{2,8}(\/?.+)?)$/", $text, $matches);
+    $preg_retval = preg_match("/((https?:\/\/)?[\w\.-]+\.[a-z\.]{2,8}(\/?.+)?)$/", $text, $matches);
+    if ($preg_retval>=1) {
+      //return preg_replace("/^(https?:\/\/)(([\da-z\.-]+)\.([a-z\.]{2,8}))(\/?[.]+)?$/", "<a class='link-image' href='\\0' target='_blank'>\\2</a>", $matches[1]);
+      $url = $matches[1];
+    } else {
+      //return preg_replace("/^(https?:\/\/)(([\da-z\.-]+)\.([a-z\.]{2,8}))(\/?[.]+)?$/", "<a class='link-image' href='\\0' target='_blank'>\\2</a>", ENGINE_DFLTLINK);
+      $url = ENGINE_DFLTLINK;
+    }  
+
+    if (mb_stripos1($url, ENGINE_DFLTLINK)) {
+      $bDFLTLINK = true;
+    }  
+    
+    $url = str_replace(PHP_TILDE, PHP_SLASH, $url);
+    
+    $urlText = preg_replace("/(https?:\/\/)(([\da-z\.-]+)\.([a-z\.]{2,8}))(\/?.+)?$/", "\\2", $url);
+    
+    if ($formatted) {
+      /*
+      if ($bDFLTLINK) { 
+        return "[AD]&nbsp;<a class='link-image' href='http://" . $url . "' target='_blank'>" . (mb_strlen($urlText)<=26 ? $urlText : left($urlText, 10) . ".." . right($urlText, 14)) . "</a>";
+      } else {  
+        return "<a class='link-image' href='http://" . $url . "' target='_blank'>" . (mb_strlen($urlText)<=26 ? $urlText : left($urlText, 10) . ".." . right($urlText, 14)) . "</a>";
+      } */
+      
+      if ($bDFLTLINK) { 
+        return "[AD]&nbsp;<a class='link-image' onclick='openLink(\"http://" . $url . "\",\"_blank\")'>" . (mb_strlen($urlText)<=26 ? $urlText : left($urlText, 10) . ".." . right($urlText, 14)) . "</a>";
+      } else {  
+        return "<a class='link-image' onclick='openLink(\"http://" . $url . "\",\"_blank\")'>" . (mb_strlen($urlText)<=26 ? $urlText : left($urlText, 10) . ".." . right($urlText, 14)) . "</a>";
+      }  
+      
+    } else {
+      return $urlText; 
+    }  
+  }
+  
+  /**
+   * Get the gallery url
+   * 
+   * @param string $desc the text being parsed for links
+   * @param int $output the kind of output
+   * @return the text with enabled links
+   */
+  public static function getGalleryUrl(string $desc, int $output = self::URL_OUTPUT_FORMATTED): string
+  {
+    $matches = [];
+    $bDFLTLINK = false;
+
+    $preg_retval = preg_match("/((https?:\/\/)?[\w\.-]+\.[a-z\.]{2,8}(\/?.+)?)$/", $desc, $matches);
+    if ($preg_retval>=1) {
+      $url = $matches[1];
+    } else {
+      $url = ENGINE_DFLTLINK;
+    }  
+
+    if ($output === self::URL_OUTPUT_RAW) {
+      return $url;      
+    }
+    
+    if (mb_stripos1($url, ENGINE_DFLTLINK)) {
+      $bDFLTLINK = true;
+    }  
+    
+    $url = str_replace(PHP_TILDE, PHP_SLASH, $url);
+    
+    $urlText = preg_replace("/(https?:\/\/)(([\da-z\.-]+)\.([a-z\.]{2,8}))(\/?.+)?$/", "\\2", $url);
+    
+    if ($output === self::URL_OUTPUT_FORMATTED) {
+      
+      if ($bDFLTLINK) { 
+        return "[AD]&nbsp;<a class='link-image' onclick='openLink(\"http://" . $url . "\",\"_blank\")'>" . (mb_strlen($urlText)<=26 ? $urlText : left($urlText, 10) . ".." . right($urlText, 14)) . "</a>";
+      } else {  
+        return "<a class='link-image' onclick='openLink(\"http://" . $url . "\",\"_blank\")'>" . (mb_strlen($urlText)<=26 ? $urlText : left($urlText, 10) . ".." . right($urlText, 14)) . "</a>";
+      }  
+      
+    } else {
+      return $urlText; 
+    }  
+  }
+  
+  
+  /**
+   * Encode any HTML of a given string
+   * 
+   * @param string $s the string to encode
+   * @param bool $withBR keep the BR tag, true/false
+   * @return string the string encoded
+   */
+  public static function HTMLencode(?string $s, bool $withBR = false): string 
+  {
+    if (!isset($s)) {
+      return PHP_STR;
+    }
+    
+    $s = str_ireplace("&#39;", "'", $s); 
+    $s = str_ireplace("&#34;", "\"", $s);
+    $s = str_ireplace("\\n", chr(10), $s);
+    $s = htmlspecialchars($s, ENT_QUOTES |ENT_IGNORE | ENT_HTML5, "UTF-8");
+    
+    if ($withBR) {
+      $s = str_ireplace(chr(10), PHP_BR, $s);
+    }  
+    
+    return $s;
+  }
+  
+  /**
+   * Set headers to no cache
+   * 
+   * @param integer $interval the interval in seconds
+   */
+  public static function setNoCacheHeaders(): void 
+  {
+    // Backwards Compatibility for HTTP/1.0 clients
+    header("Expires: 0");
+    header("Pragma: no-cache");
+    // HTTP/1.1 support
+    header("Cache-Control: no-cache,no-store,max-age=0,s-maxage=0,must-revalidate");
+  }
+  
+  /**
+   * Set headers to private cache
+   * 
+   * @param integer $interval the interval in seconds
+   */
+  public static function setPrivateCacheHeaders(int $interval = 300): void
+  {
+    $now = time();
+    $pretty_lmtime = gmdate("D, d M Y H:i:s", $now) . " GMT";
+    $pretty_extime = gmdate("D, d M Y H:i:s", $now + $interval) . " GMT";
+    // Backwards Compatibility for HTTP/1.0 clients
+    header("Last Modified: $pretty_lmtime");
+    header("Expires: $pretty_extime");
+    header("Pragma: ");
+    // HTTP/1.1 support
+    header("Cache-Control: private,max-age=$interval,s-maxage=0");
+  }
+  
+  /**
+   * Set headers to public cache
+   * 
+   * @param integer $interval the interval in seconds
+   */
+  public static function setPublicCacheHeaders(int $interval = 300): void
+  {
+    $now = time();
+    $pretty_lmtime = gmdate("D, d M Y H:i:s", $now) . " GMT";
+    $pretty_extime = gmdate("D, d M Y H:i:s", $now + $interval) . " GMT";
+    // Backwards Compatibility for HTTP/1.0 clients
+    header("Last Modified: $pretty_lmtime");
+    header("Expires: $pretty_extime");
+    header("Pragma: ");
+    // HTTP/1.1 support
+    header("Cache-Control: public,max-age=$interval");
+  }
+  
+  /** 
+   * Make a redirect
+   * 
+   * @param string $newUrl the url to redirect to
+   */
+  public static function redirect(string $newUrl): void  
+  {
+    if (headers_sent()) {
+      echo("<script>window.location.replace('" . $newUrl . "');</script>");
+    } else {
+      header("HTTP/1.0 302 Redirect");
+      header('Location: ' . $newUrl);
+    } 
+    exit();
+  }
+
+  /** 
+   * Make a permanent redirect
+   * 
+   * @param string $newUrl the url to redirect to
+   */
+  public static function redirectPerm(string $newUrl): void  
+  {
+    if (headers_sent()) {
+      echo("<script>window.location.replace('" . $newUrl . "');</script>");
+    } else {
+      header("HTTP/1.0 301 Moved Permanently");
+      header('Location: ' . $newUrl);
+    } 
+    exit();
+  }
+  
+}

+ 223 - 0
Private/classes/fivemode/fivemode/class.session.inc

@@ -0,0 +1,223 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * class.session.inc
+ * 
+ * Session class.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+namespace fivemode\fivemode;
+
+/**
+ * Session
+ *
+ * Session class
+ *
+ * @package  Session
+ * @author   Daniele Bonini <my25mb@aol.com>
+ * @version  2.0
+ * @access   public
+ */
+final class Session 
+{
+  /**
+   * Default constructor
+   * 
+   * @return void
+   */
+  private function __construct()
+  {
+  }
+
+  /**
+   * Check if the given session variable exists
+   * 
+   * @param string  $key the key of the variable
+   * @return bool  if the session variable exists, true/false
+   * @access public
+   */
+  public static function exists(string $key): bool 
+  {
+    return isset($_SESSION[$key]) ? true : false;
+      
+  }
+  
+  /**
+   * Check if the session is started
+   * 
+   * @return bool  if the session is started, true/false
+   * @access public
+   */
+  public static function isStarted(): bool
+  {
+    return isset($_SESSION) ? true : false;
+  }
+
+  /**
+   * Check if the session is active
+   * 
+   * @return bool  if the session is active, true/false
+   * @access public
+   */
+  public static function isActive(): bool
+  {
+    return session_status() === PHP_SESSION_ACTIVE ? true : false;
+  }
+  
+  /**
+   * Start the session
+   * 
+   * @return void
+   * @access public
+   */
+  public static function start(): void
+  {
+    if (!self::isStarted()) {
+      session_name(SESSION_NAME);
+    }
+    if (!self::isActive()) {
+      session_start();
+    }
+  }
+
+  /**
+   * Start the session with a new context
+   * 
+   * @return void
+   * @access public
+   */
+  public static function startWithNewContext(): void
+  {
+    if (!self::isStarted()) {
+      session_name(SESSION_NAME);
+    }
+    if (!self::isActive()) {
+      session_start();
+    }
+    session_regenerate_id(true);    
+  }
+  
+  /**
+   * Start the session in editing mode
+   * 
+   * @return void
+   * @access public
+   */
+  public static function startEditing(): void
+  {
+    if (!self::isActive()) {
+      session_start();
+    }
+  }
+
+  /**
+   * Retrieve the value of the given session variable
+   * 
+   * @param string  $key the key of session variable to retrieve
+   * @param mixed  $default a default value
+   * @return mixed  the value
+   * @access public
+   */
+  public static function get(string $key, $default=false) 
+  {
+    if (self::exists($key)) {
+      return $_SESSION[$key];
+    } else {
+      return $default;
+    }
+  }
+  
+  /**
+   * Set the value of the given session variable
+   * 
+   * @param string  $key the key of the session variable
+   * @param mixed  $value the new value to assign
+   * @return void
+   * @access public
+   */
+  public static function set(string $key, $value): void
+  {
+    $_SESSION[$key] = $value;
+  }
+
+  /**
+   * Unset the given session variable
+   * 
+   * @param string  $key the key of the session variable
+   * @return void
+   * @access public
+   */
+  public static function unset1(string $key): void 
+  {
+    if (self::exists($key)) {
+      unset($_SESSION[$key]);
+    }
+  }
+
+  /**
+   * Release the write handle of the session
+   * 
+   * @return void
+   * @access public
+   */
+  public static function closeEditing(): void
+  {
+    self::close();
+  }
+
+  /**
+   * Close the session
+   * 
+   * @return void
+   * @access public
+   */
+  public static function close(): void
+  {
+    if (self::isActive()) {
+      session_write_close();
+    }
+  }
+  
+  /**
+   * Destroy the session
+   * 
+   * @return void
+   * @access public
+   */
+  public static function destory(): void
+  {
+    self::start();
+
+    session_unset();
+    session_destroy();
+  }
+}

+ 160 - 0
Private/config/config.inc.sample

@@ -0,0 +1,160 @@
+<?php
+
+/**
+ * Copyright 2021, 2024 5 Mode
+ *
+ * This file is part of SnipSwap.
+ *
+ * SnipSwap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * SnipSwap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.  
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with SnipSwap. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * config.inc
+ * 
+ * Configuration settings.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+  */
+
+define('DEBUG', true);
+define('TESTING', false);
+
+//define('CACHE_HOST', "172.20.0.3");
+//define('CACHE_PORT', "11211");
+//define('CACHE_EXPIRE', 24);
+//define('CACHE_APP_PREFIX', "SS_tosqefv0ct_");
+
+define('APP_NAME', "SnipSwap");
+define('APP_HOST', "yourname-snipwap.com");
+define('APP_PATH', "/var/www/YourWebApp/Public");
+define('APP_SCRIPT_PATH', "/var/www/YourWebApp/Private/scripts");
+define('APP_AJAX_PATH', "/var/www/YourWebApp/Private/scripts_ajax");
+define('APP_ERROR_PATH', "/var/www/YourWebApp/Private/error");
+define('APP_DATA_PATH', "/var/www/YourWebApp/Private/repo");
+define('APP_TEMPLATE_PATH', "/var/www/YourWebApp/Private/templates");
+define('APP_SCRIPTS_WITHOUT_HEADER', "~||");
+define('APP_SCRIPTS_WITHOUT_SEARCH_MENU', "~|err-401|err-404|");
+define('APP_LICENSE', <<<LICENSETEXT
+Copyright 2021, 2024 5 Mode
+
+This file is part of SnipSwap.
+
+SnipSwap is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+SnipSwap is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.  
+ 
+You should have received a copy of the GNU General Public License
+along with SnipSwap. If not, see <https://www.gnu.org/licenses/>.
+LICENSETEXT
+);
+define('APP_DEF_LANG', "en-US");
+define('APP_LOCALE', "EN");
+define('APP_MAX_DFT_NEW_SNIPS', 15);
+
+define('SESSION_NAME', "SS_3445501");
+define('SESSION_TIMEOUT', 1800);
+
+define('BUSINESS_DFT_LABEL', "5 Mode");
+define('BUSINESS_DFT_LINK', "5mode.com");
+define('BUSINESS_DFT_EMAIL', "my25mb@aol.com");
+
+// sha256 password
+// pw: password
+define('EDITOR_PASSWORD', "");
+
+define('SEARCH_WORD_EXCLUSION_LIST_en-US', "~|a|an|of|at|in|on|inside|from|by|to|the|for|with|within|many|much|few|some|any|and|or|how|like|where|what|who|when|which|why|whose|that|this|these|those|about|");
+define('SEARCH_WORD_EXCLUSION_LIST_zh-CN', "~|一个|一双|一只|一本|一台|一块|一堆|一听|一串|一条|一盏|的|在|里|上|从|自|到|为|给|很多|很少|一些|任何|和|或者|怎么样|像|哪里|什么时候|什么|谁|哪个|为什么|谁的|那个|这个|这些|那些|关于|"); 
+define('SEARCH_WORD_EXCLUSION_LIST_es-ES', "~|un|una|uno|de|en|sobre|dentro|desde|del|dela|dele|delo|a|para|el|la|lo|los|las|por|tras|muchos|mucho|unos|unas|como|donde|que|quien|cuando|cual|cuyo|cuya|este|estos|esta|estas|esto|aquel|aquellos|aquella|aquellas|aquello|acerca|");
+define('SEARCH_WORD_EXCLUSION_LIST_it-IT', "~|un|una|uno|di|del|dell|dello|della|delle||degli|dei|a|ad|al|all|allo|alla|alle|agli|ai|in|nel|nello|nella|nelle|nell|negli|nei|su|sul|sullo|sulla|sulle|sugli|sui|dentro|da|dal|dall|dallo|dalla|dalle|dagli|dai|i|il|lo|la|le|gli|con|col|per|via|tra|fra|molti|molto|alcuni|e|ed|o|come|dove|cosa|chi|quando|quale|quali|perche|purche|cui|che|questo|quello|quei|quegli|circa|");
+define('SEARCH_WORD_EXCLUSION_LIST_fr-FR', "~|un|une|de|a|en|dans|sur|dedans|des|depuit|le|la|les|pour|entre|beaucoup|tres|comme|comment|que|qui|quand|quel|quelle|quelles|pourquoi|ce|ces|cet|cette|");
+
+
+$CONFIG = [
+  'DEBUG' => true,
+  'TESTING' => false,
+    
+//  'CACHE' => [
+//      'HOST' => "172.20.0.3",
+//      'PORT' => "11211",
+//      'EXPIRE' => 45,
+//      'APP_PREFIX' => "SS_tosqefv0ct_",
+//      ],
+
+  'APP' => [
+      'NAME' => "SnipSwap",
+      'HOST' => "youname-snipswap.com",
+      'PATH' => "/var/www/YourWebApp/Public",
+      'SCRIPT_PATH' => "/var/www/YourWebApp/Private/scripts",
+      'AJAX_PATH' => "/var/www/YourWebApp/Private/scripts_ajax",
+      'ERROR_PATH' => "/var/www/YourWebApp/Private/error",
+      'DATA_PATH' => "/var/www/YourWebApp/Private/repo",
+      'TEMPLATE_PATH' => "/var/www/YourWebApp/Private/templates",
+      'SCRIPTS_WITHOUT_HEADER' => "~||",
+      'SCRIPTS_WITHOUT_SEARCH_MENU' => "~|err-401|err-404|",
+      'LICENSE' => <<<LICENSETEXT
+Copyright 2021, 2024 5 Mode
+
+This file is part of SnipSwap.
+
+SnipSwap is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+SnipSwap is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.  
+ 
+You should have received a copy of the GNU General Public License
+along with SnipSwap. If not, see <https://www.gnu.org/licenses/>.
+LICENSETEXT
+             ,
+      'DEF_LANG' => "en-US",
+      'LOCALE' => "EN",
+      'MAX_DFT_NEW_SNIPS' => 15
+            ],
+
+  'SESSION' => [  
+      'NAME' => "SS_3445501",  
+      'TIMEOUT' => 1800
+           ],
+
+  'BUSINESS' => [
+      'DFT_LABEL' => "5 Mode",
+      'DFT_LINK' => "5mode.com",
+      'DFT_EMAIL' => "my25mb@aol.com"
+           ],
+    
+  'EDITOR' => [
+      // sha256 password
+      // pw: password
+      'PASSWORD' => ""
+           ],
+    
+  'SEARCH' => [
+      'WORD_EXCLUSION_LIST_en-US' => "~|a|an|of|at|in|on|inside|from|by|to|the|for|with|within|many|much|few|some|any|and|or|how|like|where|what|who|when|which|why|whose|that|this|these|those|about|",
+      'WORD_EXCLUSION_LIST_zh-CN' => "~|一个|一双|一只|一本|一台|一块|一堆|一听|一串|一条|一盏|的|在|里|上|从|自|到|为|给|很多|很少|一些|任何|和|或者|怎么样|像|哪里|什么时候|什么|谁|哪个|为什么|谁的|那个|这个|这些|那些|关于|", 
+      'WORD_EXCLUSION_LIST_es-ES' => "~|un|una|uno|de|en|sobre|dentro|desde|del|dela|dele|delo|a|para|el|la|lo|los|las|por|tras|muchos|mucho|unos|unas|como|donde|que|quien|cuando|cual|cuyo|cuya|este|estos|esta|estas|esto|aquel|aquellos|aquella|aquellas|aquello|acerca|",
+      'WORD_EXCLUSION_LIST_it-IT' => "~|un|una|uno|di|del|dell|dello|della|delle|degli|dei|a|ad|al|all|allo|alla|alle|agli|ai|in|nel|nello|nella|nelle|nell|negli|nei|su|sul|sullo|sulla|sulle|sugli|sui|dentro|da|dal|dall|dallo|dalla|dalle|dagli|dai|i|il|lo|la|le|gli|con|col|per|via|tra|fra|molti|molto|alcuni|e|ed|o|come|dove|cosa|chi|quando|quale|quali|perche|purche|cui|che|questo|quello|quei|quegli|circa|",
+      'WORD_EXCLUSION_LIST_fr-FR' => "~|un|une|de|a|en|dans|sur|dedans|des|depuit|le|la|les|pour|entre|beaucoup|tres|comme|comment|que|qui|quand|quel|quelle|quelles|pourquoi|ce|ces|cet|cette|"
+           ]
+];
+
+

+ 67 - 0
Private/config/const.php.inc

@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * Copyright 2021, 2024 5 Mode
+ *
+ * This file is part of SnipSwap.
+ *
+ * SnipSwap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * SnipSwap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.  
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with SnipSwap. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * const.php.inc
+ * 
+ * Additional PHP constants.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+  */
+
+if (!defined("PHP_BR")) {
+  define('PHP_BR', "<br>");
+}
+if (!defined("PHP_CN")) {
+  define('PHP_CN', "zh-CN");
+}
+if (!defined("PHP_EN")) {
+  define('PHP_EN', "en-US");
+}
+if (!defined("PHP_ES")) {
+  define('PHP_ES', "es-ES");
+}
+if (!defined("PHP_FR")) {
+  define('PHP_FR', "fr-FR");
+}
+if (!defined("PHP_HYPHEN")) {
+  define('PHP_HYPHEN', "-");
+}
+if (!defined("PHP_IT")) {
+  define('PHP_IT', "it-IT");
+}
+if (!defined("PHP_PIPE")) {
+  define('PHP_PIPE', "|");
+}
+if (!defined("PHP_SLASH")) {
+  define('PHP_SLASH', "/");
+}
+if (!defined("PHP_SPACE")) {
+  define('PHP_SPACE', " ");
+}
+if (!defined("PHP_STR")) {
+  define('PHP_STR', "");
+}
+if (!defined("PHP_TILDE")) {
+  define('PHP_TILDE', "~");
+}
+if (!defined("PHP_UNDERSCORE")) {
+  define('PHP_UNDERSCORE', "_");
+}

+ 351 - 0
Private/core/init.inc

@@ -0,0 +1,351 @@
+<?php
+
+/**
+ * Copyright 2021, 2024 5 Mode
+ *
+ * This file is part of SnipSwap.
+ *
+ * SnipSwap is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * SnipSwap is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.  
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with SnipSwap. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * init.inc
+ * 
+ * Initialization file.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode   
+ */
+
+//use fivemode\fivemode\Cache;
+use fivemode\fivemode\Err;
+use fivemode\fivemode\Page;
+use fivemode\fivemode\Session;
+
+$ctrlName = strtolower(rtrim(substr(filter_input(INPUT_GET, "url", FILTER_SANITIZE_STRING), 0, 300), "/"));
+if ($ctrlName === "") {
+  $ctrlName = "home";
+}
+
+error_reporting(E_ALL & ~ (E_WARNING | E_NOTICE | E_STRICT | E_DEPRECATED));  
+ini_set('display_startup_errors',1);  
+ini_set('display_errors',1);  
+ini_set('log_errors',1); 
+
+
+// CONFIGURATION
+define("CONFIG_PATH", __DIR__ . DIRECTORY_SEPARATOR . ".." . DIRECTORY_SEPARATOR . "config");
+
+require CONFIG_PATH . DIRECTORY_SEPARATOR . "config.inc";
+require CONFIG_PATH . DIRECTORY_SEPARATOR . "const.php.inc";
+
+define("FUNCTIONS_PATH", __DIR__ . DIRECTORY_SEPARATOR . ".." . DIRECTORY_SEPARATOR . "functions");
+
+require FUNCTIONS_PATH . DIRECTORY_SEPARATOR . "func.file.inc";
+
+// Checking a little the configuration..
+if (!file_exists(APP_DATA_PATH)) {
+  die("Data folder doesn't exist. You must create a data folder in your web app private path and configure it properly inside the config file.");
+}	
+if (!file_exists(APP_TEMPLATE_PATH)) {
+  die("Template folder doesn't exist. You must have a tempate folder in your web app private path and configure it properly inside the config file.");
+}	
+if (EDITOR_PASSWORD === "" || (strlen(EDITOR_PASSWORD) < 64)) {
+  die("Editor password must be set (with a sha256, 64 chars min length). You must generate an editor password and configure it properly inside the config file.");
+}  
+
+$pattern = APP_DATA_PATH . PHP_SLASH . "*";
+$aPaths = glob($pattern);
+if (count($aPaths) <= 1 ) {
+  // Generating data from the template..
+
+  for ($n=1;$n<=APP_MAX_DFT_NEW_SNIPS;$n++) { 
+
+    if ($n<10) {
+      $baseName = "snip" . "00" . $n;
+    } else if ($n<100) {
+      $baseName = "snip" . "0" . $n;
+    } else {
+      $baseName = "snip" . $n;
+    }    
+    
+    $path = APP_DATA_PATH . PHP_SLASH . $baseName . PHP_SLASH . $baseName . ".xml";
+    if (!is_readable($path)) {
+      // -- generating snipNNN.xml
+      
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName);
+
+      $newTitle = $baseName;
+      $newDesc = $baseName;
+      //$newCode = "<![CDATA[function hello() {\nprintf('Hello world!');\n}]]>";
+      $newCode = "<![CDATA[\n// Example code\nfunction hello() {\n  echo('Hello world!');\n}\n]]>";
+      $newCats = "examples";
+      $newTags = "hello helloworld";
+      $newLabel = BUSINESS_DFT_LABEL;
+      $newLink = BUSINESS_DFT_LINK;
+      $newEmail = BUSINESS_DFT_EMAIL;
+      $newGuid = mb_substr(hash("sha256", mt_rand() . mt_rand() . APP_SALT, false), 0, 32);
+      $newPassword = EDITOR_PASSWORD; 
+      
+      // GNENERATING XML DATA
+      copy(APP_TEMPLATE_PATH . "/snip.xml.amp.template", APP_DATA_PATH . PHP_SLASH . $baseName . PHP_SLASH . $baseName . ".xml");
+      //chmod(APP_DATA_PATH . PHP_SLASH . $baseName . PHP_SLASH . $baseName . ".xml", 0777);
+      
+      $xmlStr = file_get_contents(APP_DATA_PATH . PHP_SLASH . $baseName . PHP_SLASH . $baseName . ".xml");
+      
+      $xmlStr = str_replace("<title></title>", "<title>" . $newTitle . "</title>", $xmlStr);
+      $xmlStr = str_replace("<desc></desc>", "<desc>" . $newDesc . "</desc>", $xmlStr);
+      $xmlStr = str_replace("<code><![CDATA[]]></code>", "<code>" . $newCode . "</code>", $xmlStr);
+      $xmlStr = str_replace("<cats></cats>", "<cats>" . $newCats . "</cats>", $xmlStr);
+      $xmlStr = str_replace("<tags></tags>", "<tags>" . $newTags . "</tags>", $xmlStr);
+      $xmlStr = str_replace("<label></label>", "<label>" . $newLabel . "</label>", $xmlStr);
+      $xmlStr = str_replace("<link></link>", "<link>" . $newLink . "</link>", $xmlStr);
+      $xmlStr = str_replace("<email></email>", "<email>" . $newEmail . "</email>", $xmlStr);
+      $xmlStr = str_replace("<guid></guid>", "<guid>" . $newGuid . "</guid>", $xmlStr);
+      $xmlStr = str_replace("<password></password>", "<password>" . $newPassword . "</password>", $xmlStr);
+      
+      file_put_contents(APP_DATA_PATH . PHP_SLASH . $baseName . PHP_SLASH . $baseName . ".xml", $xmlStr);
+    } else {
+      
+      die("Critical error. One or more example files exist. ");
+    } 
+
+    // GNENERATING FILESYSTEM DATA
+    // if the snip data folder doesn'exist I create it with all the subfolders..
+    //if (!is_readable(APP_DATA_PATH . PHP_SLASH . $baseName)) {
+    //  mkdir(APP_DATA_PATH . PHP_SLASH . $baseName);
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "title");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "desc");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "code");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "cats");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "tags");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "label");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "link");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "email");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "guid");
+      mkdir(APP_DATA_PATH . PHP_SLASH . $baseName. PHP_SLASH . "data". PHP_SLASH . "password");
+    //}      
+
+    // Saving filesystem version of the data..
+    $details = new SimpleXMLElement($xmlStr);
+
+    storeFSData($details, $baseName, "title");
+    storeFSData($details, $baseName, "desc");
+    storeFSData($details, $baseName, "code");
+    storeFSData($details, $baseName, "cats");
+    storeFSData($details, $baseName, "tags");
+    storeFSData($details, $baseName, "label");
+    storeFSData($details, $baseName, "link");
+    storeFSData($details, $baseName, "email");
+    storeFSData($details, $baseName, "guid");
+    storeFSData($details, $baseName, "password");
+      
+  }  
+}  
+
+mb_internal_encoding("UTF-8");
+
+
+// AUTOLOADER
+
+define("CLASSES_PATH", __DIR__ . DIRECTORY_SEPARATOR . ".." . DIRECTORY_SEPARATOR . "classes");
+define("INTERFACES_PATH", __DIR__ . DIRECTORY_SEPARATOR . ".." . DIRECTORY_SEPARATOR . "interfaces");
+
+/**
+ * Autoloader.
+ * 
+ * @param string $construct the name of the construct to load
+ */
+function autoloader($construct) {
+  
+  // For third-party libraries, eg. Pear
+  if (!defined("PHP_INCLUDE_PATH")) {
+    define("PHP_INCLUDE_PATH", ini_get("include_path"));
+  }
+  
+  $constructParts = explode('\\', $construct);
+  
+  // estrapolate the path from the construct name
+  $count = count($constructParts);
+  if ($count>1) {
+    $i = 0;
+    $constructPath = $constructParts[0];
+    for ($i=1; $i<($count-1); $i++) {
+      $constructPath .= DIRECTORY_SEPARATOR . $constructParts[$i];
+    }
+    $construct = $constructParts[$i];
+  }
+  
+  if (!stripos($construct, "interface")) {
+    // if it is a class
+  
+    switch ($construct) {
+      case "special_case":
+        $incPath = PHP_INCLUDE_PATH . DIRECTORY_SEPARATOR . "path/to/special_case.php";
+        break;
+      case "QRcode":
+        $incPath = CLASSES_PATH . DIRECTORY_SEPARATOR . "phpqrcode/qrlib.php";
+        //echo "incPath = $incPath" . PHP_BR;
+        break;
+      default:
+      
+        if (isset($constructPath)) {
+          $incPath = CLASSES_PATH . DIRECTORY_SEPARATOR . $constructPath . DIRECTORY_SEPARATOR . "class." . strtolower($construct) . ".inc";
+        } else {
+          $incPath = CLASSES_PATH . DIRECTORY_SEPARATOR . "class." . strtolower($construct) . ".inc";
+        }
+        
+        break;
+    }
+    
+  } else {
+    // if it is an interface
+    if (isset($constructPath)) {
+      $incPath = INTERFACES_PATH . DIRECTORY_SEPARATOR  . $constructPath . DIRECTORY_SEPARATOR . strtolower($construct) . ".inc";
+    } else {
+      $incPath = INTERFACES_PATH . DIRECTORY_SEPARATOR . strtolower($construct) . ".inc";
+    }  
+  }
+  
+  if (is_readable($incPath)) {
+    //echo "$incPath is readable" . PHP_BR;
+    require $incPath;
+  }
+  
+}
+spl_autoload_register("autoloader", true, true);
+
+
+// FUNCTIONS
+
+//define("FUNCTIONS_PATH", __DIR__.DIRECTORY_SEPARATOR."..".DIRECTORY_SEPARATOR."functions");
+
+require FUNCTIONS_PATH . DIRECTORY_SEPARATOR . "func.string.inc";
+require FUNCTIONS_PATH . DIRECTORY_SEPARATOR . "func.app.inc";
+require FUNCTIONS_PATH . DIRECTORY_SEPARATOR . "func.various.inc";
+//require FUNCTIONS_PATH . DIRECTORY_SEPARATOR . "func.file.inc";
+require FUNCTIONS_PATH . DIRECTORY_SEPARATOR . "func.filter.inc";
+require FUNCTIONS_PATH . DIRECTORY_SEPARATOR . "func.array.inc";
+
+
+// SESSION
+Session::start();
+
+$now = time();
+//if (Cookie::isEmpty("uid") || Cookie::isEmpty("uname")) {
+  if (Session::exists("timeout") && $now > Session::get("timeout")) {;
+    Session::destory();
+    // Regenerate the session..
+    Session::startWithNewContext();
+  }
+//}  
+// Session should live at most for another half of hour
+Session::set("timeout", ($now + SESSION_TIMEOUT));
+
+$serverName = $_SERVER["SERVER_NAME"];
+$qs = $_SERVER['QUERY_STRING'];
+
+// If the Session starts for the first time I set the default
+// values for 'lang','defLicense',etc..
+if (!Session::exists("lang")) {
+  Session::set("lang", APP_DEF_LANG);
+}
+
+Session::closeEditing();
+
+
+// USER INFORMATION
+
+// Check the user information present in the session and fill in the User static instance..
+//$user = UserUtil::checkSessionUserInfo();
+
+
+// ERROR HANDLING AND LOGGING
+
+if (DEBUG) {
+  error_reporting(E_ALL | E_STRICT);  
+  ini_set('display_startup_errors',1);  
+  ini_set('display_errors',1);
+  ini_set('log_errors',1); 
+} else {
+  error_reporting(E_ALL & ~ (E_WARNING | E_NOTICE | E_STRICT | E_DEPRECATED));  
+  ini_set('display_startup_errors',0);  
+  ini_set('display_errors',0);  
+  ini_set('log_errors',1); 
+}
+
+Err::setDefaultHandlers();
+
+
+// HEADERS
+
+if ($ctrlName === "search") {
+  // Set public cache with 5 minutese expiration..
+  //Page::setPublicCacheHeaders(300);
+  Page::setNoCacheHeaders();
+  
+} else {
+  // Disable the cache..
+  Page::setNoCacheHeaders();
+
+}
+
+
+// SHUTDOWN 
+
+/**
+ * Shutdown callback.
+ * 
+ * @return void
+ */
+function shutdownCallback() {
+  
+  Err::setLogOnlyHandlers();
+
+/*  
+  if (Cache::issetInstance()) {  
+    //For non-persistent connections only
+    //$cache = &Cache::getInstance();
+    //$cache->close();
+
+    Cache::unsetInstance();
+  }
+*/
+  
+}
+register_shutdown_function("shutdownCallback");
+
+// ERROR PARAMETERS
+
+//errNo
+//define("ERR_NO", substr(filter_input1(INPUT_GET, "errNo", FILTER_SANITIZE_MD5TOKEN), 0, 100));
+//if (ERR_NO!==PHP_STR && !filter_var1(ERR_NO, FILTER_VALIDATE_ERRNO)) {
+//  Err::trigger_error1(ERR::ERR_ERR, "Invalid error number: " . ERR_NO, __FILE__, __LINE__);
+//}
+
+//errKey
+//define("ERR_KEY", array_search(ERR_NO, Err::$A_ERR_NO));
+
+//errMsg
+//define("ERR_MSG", substr(filter_input1(INPUT_GET, "errMsg", FILTER_SANITIZE_ERRMSG), 0, 200));
+
+//errScript
+//define("ERR_SCRIPT", substr(filter_input(INPUT_GET, "errScript", FILTER_SANITIZE_STRING), 0, 255));
+
+//errLine
+//define("ERR_LINE",  substr(filter_input(INPUT_GET, "errLine", FILTER_SANITIZE_NUMBER_INT), 0, 5));
+
+//errStack
+//define("ERR_STACK", substr(filter_input1(INPUT_GET, "errStack", FILTER_SANITIZE_STRING_WITHBR), 0, 2000));
+
+?>

+ 6 - 0
Private/error/err-404.php

@@ -0,0 +1,6 @@
+<html>
+<head><title>404</title></head>
+<body style="background-image:url('/res/404bg.jpg'); background-size: cover; background-repeat: no-repeat;">
+&nbsp;
+</body>
+</html>

+ 89 - 0
Private/functions/func.app.inc

@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * func.app.inc
+ * 
+ * App related functions.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode    
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+use fivemode\fivemode\Config;
+
+
+/**
+ * Retrieve the list of the app hosts 
+ * 
+ * @return array the hosts array
+ */
+function getHostsArray(): array {
+  $reta = [];
+  $reta[] = APP_HOST;
+  $i = 2;
+  while (true && $i<=10) {
+    if (defined("APP_HOST" . $i)) {
+      $reta[] = Config::get("APP/HOST" . $i);
+    } else {
+      break;
+    }  
+    $i++;
+  }
+  return $reta;
+}
+
+
+/**
+ * 
+ * @return string
+ */
+function getQRCodeUri(string $styleTag): string {
+  
+  $retval = PHP_STR;
+  
+  $serverName = strtolower($_SERVER['HTTP_HOST']);
+  
+  if (mb_stripos1($serverName, "5mode.com") || mb_stripos1($serverName, "localhost")) {
+    $retval = "qrcode_5mode" . $styleTag . ".png";
+  }
+  
+  return $retval; 
+}
+
+
+function isSubdomainHost(string &$subdomain) {
+  $hostname = str_replace("www.", PHP_STR, strtolower($_SERVER['HTTP_HOST']));    
+  $ipos = mb_stripos($hostname, ".");
+  $subdomain = left($hostname, $ipos);
+  $noSubdomain = false;
+  if (($subdomain==="5mode.com")) {
+    $noSubdomain = true;
+  }
+  return !$noSubdomain;
+}

+ 176 - 0
Private/functions/func.array.inc

@@ -0,0 +1,176 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * func.array.inc
+ * 
+ * Array related functions.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode     
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+/**
+ * Fix multiple file uploaded array ($_FILE)
+ * 
+ * @param array $f the $_FILE array
+ * @return array the array fixed
+ */
+function fixMultipleFileUpload(&$f): array
+{
+    $files = array();
+    $count = count($f['name']);
+    $keys = array_keys($f);
+   
+    for($i=0;$i<$count;$i++)
+    {
+        foreach($keys as $key)
+        {
+            $files[$i][$key] = $f[$key][$i];
+        }
+    }
+    return $files;
+}
+
+/**
+ * Count the non zero elements of the given array
+ * 
+ * @param array $array
+ */
+function count_nonzeros(& $array): int 
+{
+  return count(array_filter($array));
+}  
+  
+/**
+ * Count the dimensions of the given array
+ * 
+ * @param array $array
+ * @return int the dimensions of the array
+ */
+function array_dim(array $array): int
+{
+  if (is_array(reset($array))) {
+    $retval = array_dim(reset($array)) + 1;
+  } else {
+    $retval = 1;
+  }
+
+  return $retval;
+}
+
+/**
+ * Filter false array entries replacing them with nulls
+ * 
+ * @param array $array array to filter
+ * @return array the resulting array
+ */
+function array_filter_tonull(array $array): array 
+{
+  foreach($array as & $val) {
+    if (!$val) {
+      $val = null;
+    }
+  }
+  return $array;
+}
+
+/**
+ * Return the values from a single column in the input array 
+ * filtered for value between $min and $max..
+ * 
+ * @param array $array the array being filtered
+ * @param string $column the column to filter on
+ * @param mixed $min the min val of column
+ * @param mixed $max the max val of column
+ * @return array the filtered array
+ */
+function array_numcolumn(& $array, string $column, int $min = 0, int $max = 99999999999): array 
+{
+  $GLOBALS['min'] = $min;
+  $GLOBALS['max'] = $max;
+  $array = array_filter(array_column($array, $column), function($val) {
+    if ($val>=$GLOBALS['min'] && $val<=$GLOBALS['max']) {
+      return true;
+    } else {
+      return false;
+    }
+  });
+  return $array;
+}
+
+/**
+ * Count the keys of a given array
+ * 
+ * @param array $array
+ * @return int the number of keys
+ */
+function array_keys_count(& $array): int
+{
+  return count(array_keys($array));
+}
+
+/**
+ * Append a value to the right of array until the given length
+ * 
+ * @param array $array array to pad
+ * @param mixed $val the value to the append to the array
+ * @param int $len the final length of the padded array
+ * @return void
+ */
+function array_rpad(& $array, $val, int $newlen): void 
+{
+  $i=count($array);
+  if ($i>=$newlen) {
+    return;
+  }
+  while($i<$newlen) {
+    $array[] = $val; 
+    $i++;
+  }
+}
+
+/**
+ * Searches the array for a given value and returns the corresponding key if successful
+ * otherwise null, result safe (not 0)
+ * 
+ * @param mixed $needle the value to search 
+ * @param array $array the array being searched
+ * @return mixed the key associated to the value, or null
+ */
+function array_search2($needle, & $array) 
+{
+  $retval = null;
+  foreach ($array as $key => $value) {
+    if ($value === $needle) {
+      $retval = $key;
+      break;
+    }
+  }
+  return $retval;
+}

+ 115 - 0
Private/functions/func.file.inc

@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * func.file.inc
+ * 
+ * String related functions.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+/**
+ * Copy a source file
+ * 
+ * @param string $sourceFilePath the file to copy
+ * @param string $destFilePath the destination file
+ * @return void
+ */
+function cp(string $sourceFilePath, string $destFilePath): void 
+{
+  $dataLength = 300000;
+  $hsfile = fopen($sourceFilePath, "r");
+  $hdfile = fopen($destFilePath, "w");
+  while ($data = fread($hsfile, $dataLength)) {
+    fwrite($hdfile, $data);
+  }
+  fclose($hsfile);
+  fclose($hdfile);
+}
+
+/**
+ * Store FileSystem data version of an XML snip field 
+ * 
+ * @param string $details the SimpleXML base details collection
+ * @param string $filename the basedir
+ * @param string $field the field to save
+ * @return void
+ */
+function storeFSData($details, $filename, $field) {
+
+  $datapath = APP_DATA_PATH . PHP_SLASH . $filename . PHP_SLASH . "data" . PHP_SLASH . $field;
+  chdir($datapath);
+  $pattern = "*";
+  $apath = glob($pattern);
+  foreach($apath as $path) {
+    unlink($path);
+  }  
+  switch($field) {
+    case "title":
+      file_put_contents($details->detail[0]->title, PHP_STR);
+      break;
+    case "desc":
+      file_put_contents($details->detail[0]->desc, PHP_STR);
+      break;
+    case "code":
+      file_put_contents("code.txt", $details->detail[0]->code);
+      break;
+    case "tags":
+      $tags = trim($details->detail[0]->tags);
+      $a = explode(" ", $tags);
+      foreach($a as $f) {
+        file_put_contents($f, PHP_STR);
+      }  
+      break;
+    case "cats":
+      $cats = trim($details->detail[0]->cats);
+      $a = explode(" ", $cats);
+      foreach($a as $f) {
+        file_put_contents($f, PHP_STR);
+      }  
+      break;
+    case "label":
+      file_put_contents($details->detail[1]->label, PHP_STR);
+      break;
+    case "link":
+      file_put_contents($details->detail[1]->link, PHP_STR);
+      break;
+    case "email":
+      file_put_contents($details->detail[1]->email, PHP_STR);
+      break;
+    case "guid":
+      file_put_contents($details->detail[2]->guid, PHP_STR);
+      break;
+    case "password":
+      file_put_contents($details->detail[3]->password, PHP_STR);
+      break;
+  }
+  
+}

+ 309 - 0
Private/functions/func.filter.inc

@@ -0,0 +1,309 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery, Daniele Bonini nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * func-filter.inc
+ * 
+ * Custom filtering functions.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+use fivemode\fivemode\Err;
+use fivemode\fivemode\ErrUtil;
+
+
+// Validate / sanitize a given string
+define("FILTER_SANITIZE_BOOLEAN", 1);
+define("FILTER_SANITIZE_ERRMSG", 2);
+define("FILTER_SANITIZE_FILENAME", 3);
+define("FILTER_SANITIZE_FILENAME_WITH_SPACE", 4);
+define("FILTER_SANITIZE_FILEPATH", 5);
+define("FILTER_SANITIZE_IMAGENAME", 6);
+define("FILTER_SANITIZE_LANGUAGE", 7);
+define("FILTER_SANITIZE_KEY", 8);
+define("FILTER_SANITIZE_MD5TOKEN", 9);
+define("FILTER_SANITIZE_Q", 10);
+define("FILTER_SANITIZE_QM", 11);
+define("FILTER_SANITIZE_SCRIPTNAME", 12);
+define("FILTER_SANITIZE_SHA2TOKEN", 13);
+define("FILTER_SANITIZE_STRING_WITHBR", 14);
+define("FILTER_SANITIZE_TAG", 15);
+define("FILTER_SANITIZE_TAGS", 16);
+define("FILTER_SANITIZE_URL1", 17);
+define("FILTER_SANITIZE_USERNAME", 18);
+define("FILTER_SANITIZE_FILEPATH_LESS", 19);
+define("FILTER_CLEAN_LANDINGPAGE", 100);
+define("FILTER_VALIDATE_ERRNO", 200);
+define("FILTER_VALIDATE_IMAGENAME", 201);
+define("FILTER_VALIDATE_LANGUAGE", 202);
+define("FILTER_VALIDATE_SHA2TOKEN", 203);
+define("FILTER_VALIDATE_MD5TOKEN", 204);
+define("FILTER_VALIDATE_REFID", 205);
+define("FILTER_VALIDATE_USERNAME", 206);
+define("FILTER_VALIDATE_TIMEWINDOW", 207);
+
+
+/**
+ * Sanitize a given variable
+ * 
+ * @param string $string the string to check
+ * @param integer $filter the type of filter to apply
+ * @param mixed $param (optional) for various purpose
+ * @return mixed the string filtered, a boolean if the string is validate
+ */
+function filter_var1(string $string, int $filter, $param = null) {
+  if ($string=="") {
+    return $string;
+  }  
+  switch ($filter) {
+    case FILTER_SANITIZE_BOOLEAN:
+      return preg_replace("/[^0-1]/iu", "", $string);
+    case FILTER_SANITIZE_ERRMSG:
+      return str_replace(chr(10)," ", str_replace(chr(13)," ",filter_var($string, FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_HIGH | FILTER_FLAG_STRIP_BACKTICK)));
+    case FILTER_SANITIZE_FILENAME:
+      return preg_replace("/[^\w\-.]/iu", "", $string);
+    case FILTER_SANITIZE_FILENAME_WITH_SPACE:
+      return preg_replace("/[^\w\-. ]/iu", "", $string);
+    case FILTER_SANITIZE_FILEPATH:
+      return preg_replace("/[^A-Za-z0-9-_.\/]/", "", $string);
+    case FILTER_SANITIZE_IMAGENAME:
+      return str_replace("_", "", preg_replace("/[^\w\- ]/iu", "", $string));
+    case FILTER_SANITIZE_KEY:
+      return preg_replace("/[^A-Za-z0-9-_]/", "", $string);
+    case FILTER_SANITIZE_LANGUAGE:
+      return preg_replace("/[^A-Za-z\-]/", "", $string);      
+    case FILTER_SANITIZE_MD5TOKEN:
+      return preg_replace("/[^A-Za-z0-9]/", "", $string);
+    case FILTER_SANITIZE_Q:
+      return trim(preg_replace("/[^\w\-: ]/iu", "", $string));
+    case FILTER_SANITIZE_QM:
+      return trim(preg_replace("/[^\w\.\-: ]/iu", "", $string));      
+    case FILTER_SANITIZE_SCRIPTNAME:
+      return preg_replace("/[^A-Za-z0-9-_]/", "", $string);
+    case FILTER_SANITIZE_SHA2TOKEN:
+      return preg_replace("/[^A-Za-z0-9]/", "", $string);
+    case FILTER_SANITIZE_STRING_WITHBR:
+      return str_replace("&NewLine;", "<br>", filter_var(str_replace("<br>", "&NewLine;", isset1($string,"")), FILTER_SANITIZE_STRING));
+    case FILTER_SANITIZE_TAG:
+      return preg_replace("/[^\w\-]/iu", "", $string);
+    case FILTER_SANITIZE_TAGS:
+      return preg_replace("/[^\w\- ]/iu", "", $string);
+    case FILTER_SANITIZE_URL1:
+      return preg_replace("/[^\w\-]/iu", "", $string);
+    case FILTER_SANITIZE_USERNAME:
+      return preg_replace("/[^\w\-]/", "", $string);
+    case FILTER_SANITIZE_FILEPATH_LESS:
+      $s = $string;
+      $s = str_replace("../", PHP_STR, $s);
+      $s = str_replace("..", PHP_STR, $s);
+      $s = str_replace("/", PHP_STR, $s);
+      $s = str_replace("*", PHP_STR, $s);
+      $s = str_replace("?", PHP_STR, $s);
+      $s = str_replace("%", PHP_STR, $s);
+      return trim_word($s, ['../', '..', '/', '*', '?', '%', '.']);
+    case FILTER_CLEAN_LANDINGPAGE:
+      $posLandingPage = strpos($string, "lndp");
+      $i = strpos($string, "&");
+      if ($posLandingPage===false) {
+        return $string;
+      }  
+      if ($i===false) {
+        return "";
+      } else {
+        return substr($string, $i+1); 
+      }
+      break;
+    case FILTER_VALIDATE_ERRNO:
+      if (preg_match("/^[0-9]+?$/", $string)) {
+        return true;
+      } else {
+        if (preg_match("/^([a-zA-Z0-9]{32})?$/", $string) && ErrUtil::isValidError($string)) {
+          return true;
+        } else {
+          return false;
+        }
+      }
+    case FILTER_VALIDATE_IMAGENAME:
+      return (mb_strlen($string)>=3 && mb_strlen($string)<=50 && preg_match("/^[\w\- ]+?$/iu", $string) && !stripos($string,"_"));
+    case FILTER_VALIDATE_LANGUAGE:
+      return preg_match("/^([a-z]{2}\-[A-Z]{2})?$/", $string);
+    case FILTER_VALIDATE_REFID:
+      if (!filter_var($string, FILTER_VALIDATE_INT)) {
+        return false;
+      } 
+      if (hash("sha256", $string . APP_SALT, false) != $param) {
+        return false;
+      }
+      return true;
+    case FILTER_VALIDATE_SHA2TOKEN:
+      return preg_match("/^([a-zA-Z0-9]{64})?$/", $string);
+    case FILTER_VALIDATE_MD5TOKEN:
+      return preg_match("/^([a-zA-Z0-9]{32})?$/", $string);      
+    case FILTER_VALIDATE_USERNAME:
+      return (strlen($string)>=3 && strlen($string)<=20 && preg_match("/^[\w\-]+?$/", $string));
+    case FILTER_VALIDATE_TIMEWINDOW:
+      return (strlen($string)===2 && preg_match("/^[0-9][d|w]$/", $string));
+    default:
+      Err::trigger_error1(ERR::ERR_GENERAL, "filter_var1: $filter filter: not implemented", __FILE__, __LINE__);
+      break;
+  }
+}  
+
+//INPUT_POST
+//INPUT_GET
+//INPUT_COOKIE
+//INPUT_ENV
+//INPUT_SERVER
+//INPUT_SESSION
+//INPUT_REQUEST
+
+/**
+ * Sanitize a given input string
+ * 
+ * @param integer $inputType the type of input INPUT_POST, INPUT_GET, etc.
+ * @param string $key the key of the input
+ * @param integer $filter the type of filter to apply
+ * @param mixed $param (optional) for various purpose
+ * @return mixed the string filtered, a boolean if the string is validate
+ */
+function filter_input1(int $inputType, string $key, int $filter, $param = null) {
+  
+  $input = array();  
+  switch ($inputType) {
+    case INPUT_POST:
+      $input =& $_POST;
+      break;
+    case INPUT_GET:
+      $input =& $_GET;
+      break;
+    default:
+      Err::trigger_error1(ERR::ERR_GENERAL, "filter_input1: $inputType inputType: not implemented", __FILE__, __LINE__);
+      break;
+  }
+  
+  if (!isset($input[$key])) {
+    return null;
+  }
+  
+  switch ($filter) {
+    case FILTER_SANITIZE_BOOLEAN:
+      return preg_replace("/[^0-1]/iu", "", $input[$key]);
+    case FILTER_SANITIZE_ERRMSG:
+      return str_replace(chr(10)," ", str_replace(chr(13)," ",filter_var($input[$key], FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_HIGH | FILTER_FLAG_STRIP_BACKTICK)));
+    case FILTER_SANITIZE_Q:
+      return trim(preg_replace("/[^\w\-: ]/iu", "", $input[$key]));
+    case FILTER_SANITIZE_QM:
+      return trim(preg_replace("/[^\w\.\-: ]/iu", "", $input[$key]));  
+    case FILTER_SANITIZE_MD5TOKEN:
+      return preg_replace("/[^A-Za-z0-9]/", "", $input[$key]);
+    case FILTER_SANITIZE_FILENAME:
+      return preg_replace("/[^\w\-.]/iu", "", $input[$key]);
+    case FILTER_SANITIZE_FILENAME_WITH_SPACE:
+      return preg_replace("/[^\w\-. ]/iu", "", $input[$key]);
+    case FILTER_SANITIZE_FILEPATH:
+      return preg_replace("/[^A-Za-z0-9-_.\/]/", "", $input[$key]);
+    case FILTER_SANITIZE_IMAGENAME:
+      return str_replace("_", "", preg_replace("/[^\w\- ]/iu", "", $input[$key]));      
+    case FILTER_SANITIZE_KEY:
+      return preg_replace("/[^A-Za-z0-9-_]/", "", $input[$key]);
+    case FILTER_SANITIZE_LANGUAGE:
+      return preg_replace("/[^A-Za-z\-]/", "", $input[$key]);      
+    case FILTER_SANITIZE_SCRIPTNAME:
+      return preg_replace("/[^A-Za-z0-9-_]/", "", $input[$key]);
+    case FILTER_SANITIZE_SHA2TOKEN:
+      return preg_replace("/[^A-Za-z0-9]/", "", $input[$key]);
+    case FILTER_SANITIZE_STRING_WITHBR:
+      return str_replace("&NewLine;", "<br>", filter_var(str_replace("<br>", "&NewLine;", isset1($input[$key],"")), FILTER_SANITIZE_STRING));
+    case FILTER_SANITIZE_TAG:
+      return preg_replace("/[^\w\-]/iu", "", $input[$key]);
+    case FILTER_SANITIZE_TAGS:
+      return preg_replace("/[^\w\- ]/iu", "", $input[$key]);
+    case FILTER_SANITIZE_URL1:
+      return preg_replace("/[^\w\-]/iu", "", $input[$key]);
+    case FILTER_SANITIZE_USERNAME:
+      return preg_replace("/[^\w\-]/", "", $input[$key]);
+    case FILTER_SANITIZE_FILEPATH_LESS:
+      $s = $input[$key];
+      $s = str_replace("../", PHP_STR, $s);
+      $s = str_replace("..", PHP_STR, $s);
+      $s = str_replace("/", PHP_STR, $s);
+      $s = str_replace("*", PHP_STR, $s);
+      $s = str_replace("?", PHP_STR, $s);
+      $s = str_replace("%", PHP_STR, $s);
+      return trim_word($s, ['../', '..', '/', '*', '?', '%', '.']);
+    case FILTER_CLEAN_LANDINGPAGE:
+      $posLandingPage = strpos($input[$key], "lndp");
+      $i = strpos($input[$key], "&");
+      if ($posLandingPage===false) {
+        return $input[$key];
+      }  
+      if ($i===false) {
+        return "";
+      } else {
+        return substr($input[$key], $i+1); 
+      }
+      break;
+    case FILTER_VALIDATE_ERRNO:
+      if (preg_match("/^[0-9]+?$/", $input[$key])) {
+        return true;
+      } else {
+        if (preg_match("/^([a-zA-Z0-9]{32})?$/", $input[$key]) && ErrUtil::isValidError($string)) {
+          return true;
+        } else {
+          return false;
+        }
+      }
+    case FILTER_VALIDATE_IMAGENAME:
+      return (mb_strlen($input[$key])>=3 && mb_strlen($input[$key])<=50 && preg_match("/^[\w\- ]+?$/iu", $input[$key]) && !stripos($input[$key], "_"));
+    case FILTER_VALIDATE_LANGUAGE:
+      return preg_match("/^([a-z]{2}\-[A-Z]{2})?$/", $input[$key]);
+    case FILTER_VALIDATE_REFID:
+      if (!filter_var($input[$key], FILTER_VALIDATE_INT)) {
+        return false;
+      } 
+      if (hash("sha256", $input[$key] . APP_SALT, false) != $param) {
+        return false;
+      }
+      return true;
+    case FILTER_VALIDATE_SHA2TOKEN:
+      return preg_match("/^([a-zA-Z0-9]{64})?$/", $input[$key]);
+    case FILTER_VALIDATE_MD5TOKEN:
+      return preg_match("/^([a-zA-Z0-9]{32})?$/", $input[$key]);  
+    case FILTER_VALIDATE_USERNAME:
+      return (strlen($input[$key])>=3 && strlen($input[$key])<=20 && preg_match("/^[\w\-]+?$/", $input[$key]));
+    case FILTER_VALIDATE_TIMEWINDOW:
+      return (strlen($input[$key])===2 && preg_match("/^[0-9][d|w]$/", $input[$key]));
+    default:
+      Err::trigger_error1(ERR::ERR_GENERAL, "filter_var1: $filter filter: not implemented", __FILE__, __LINE__);
+      break;
+  }
+}
+
+?>

+ 595 - 0
Private/functions/func.string.inc

@@ -0,0 +1,595 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * func.string.inc
+ * 
+ * String related functions.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+
+/**
+ * Check if the given word is a contraction 
+ * 
+ * @param string $w the word being checked
+ * @return bool if the word is a contraction, true/false
+ */
+function is_contraction(?string $w): bool 
+{
+  $retval = false;
+  if (!isset($w)) {
+    return $retval;
+  }
+  if ($w === mb_strtoupper($w)) {
+    $retval = true;
+  }
+  return $retval;
+}
+
+/**
+ * Check if the passed word is a given name 
+ * 
+ * @param string $w the word being checked
+ * @return bool if the word is a given name, true/false
+ */
+function is_givenName(?string $w): bool 
+{
+  $retval = false;
+  if (!isset($w)) {
+    return $retval;
+  }
+  if (is_ucfirst($w) && !is_contraction($w)) {
+    $retval = true;
+  }
+  return $retval;
+}
+
+
+/**
+ * Check if the given string start with a capital letter
+ * 
+ * @param string $s the string being checked
+ * @return bool if the string starts with a capital letter , true/false
+ */
+function is_ucfirst(?string $s): bool 
+{
+  $retval = false;
+  if (!isset($s)) {
+    return $retval;
+  }
+  if (ucfirst(mb_substr($s,0,1)) === mb_substr($s,0,1)) {
+    $retval = true;
+  }
+  return $retval;
+}
+
+/**
+ * Check if the letter is a vowel
+ * 
+ * @param char $letter the letter to check
+ * @return bool if the letter is vowel, true/false
+ */
+function is_vowel(string $letter): bool 
+{
+  $vowels = ['a','e','i','o','u'];
+  return in_array($letter, $vowels);
+}
+
+/**
+ * Check if the given url is a valid Facebook page
+ * 
+ * Eg:
+ * http://facebook.com/mrdanielebeta                                   
+ * http://facebook.com/pg/makeiteasyforabird
+ * 
+ * @param string $url the url to check
+ * @return bool if the url is Facebook url, true/false
+ */
+function isFacebookUrl(string $url): bool 
+{
+  $retval=false;
+  $maxLength = 60;
+  if (strlen($url)>60) {
+    return $retval;    
+  }
+  $url= strtolower($url);
+  $pattern1 = "/^http(s)?\:\/\/(www\.)?facebook\.com\/[\w\.]+$/";
+  $pattern2 = "/^http(s)?\:\/\/(www\.)?facebook\.com\/pg\/[\w\.]+$/";
+  if (preg_match($pattern1, $url) || preg_match($pattern2, $url)) {
+    $retval=true;
+  } else {
+    $retval=false;
+  }  
+  return $retval;
+}  
+
+/**
+ * Check if the given url is a valid domain url
+ * 
+ * Eg:
+ * http://danielebonini.com
+  * 
+ * @param string $url the url to check
+ * @return bool if the url is a valid domain url, true/false
+ */
+function isUrl(string $url): bool
+{
+  $retval=false;
+  $maxLength = 45;
+  if (strlen($url)>45) {
+    return $retval;    
+  }
+  $url= strtolower($url);
+  $pattern1 = "/^http(s)?\:\/\/(www\.)?\w+\.\w+$/";
+  $pattern2 = "/^http(s)?\:\/\/(www\.)?\w+\.\w+.\w+$/";
+  if (preg_match($pattern1, $url) || preg_match($pattern2, $url)) {
+    $retval=true;
+  } else {
+    $retval=false;
+  }  
+  return $retval;
+}  
+
+/**
+ * Check if the given url is a valid Youtube page
+ * 
+ * Eg:
+ * http://youtube.com/watch?v=eeerwr24334 
+ * 
+ * @param string $url the url to check
+ * @return bool if the url is Youtube url, true/false
+ */
+function isYoutubeUrl(string $url): bool 
+{
+  $retval=false;
+  $maxLength = 50;
+  if (strlen($url)>50) {
+    return $retval;    
+  }
+  $url= strtolower($url);
+  $pattern1 = "/^http(s)?\:\/\/(www\.)?youtube\.com\/watch\?v\=[\w]+$/";
+  if (preg_match($pattern1, $url)) {
+    $retval=true;
+  } else {
+    $retval=false;
+  }  
+  return $retval;
+}  
+
+/**
+ * Test if a word is of a latin language
+ * 
+ * @param string  $word the string to test
+ * @return bool  if $word is of a latin language, true/false
+ */
+function isLatinLang(string $word): bool 
+{
+  
+  //$char = mb_substr($word, 0, 1);
+  //return !preg_match("/[\x{31C0}-\x{31EF}\x{3300}-\x{33FF}\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{F900}-\x{FAFF}\x{FE30}-\x{FE4F}]{1}/u", $char);
+  
+  $isNonLatinLang = preg_match("/^[\w-]+[\x{31C0}-\x{31EF}\x{3300}-\x{33FF}\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{F900}-\x{FAFF}\x{FE30}-\x{FE4F}]+$/u", $word) ||
+                    preg_match("/^[\x{31C0}-\x{31EF}\x{3300}-\x{33FF}\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{F900}-\x{FAFF}\x{FE30}-\x{FE4F}]+$/u", $word) ||
+                    preg_match("/^[\x{31C0}-\x{31EF}\x{3300}-\x{33FF}\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{F900}-\x{FAFF}\x{FE30}-\x{FE4F}]+[\w-]+$/u", $word) ||
+                    preg_match("/^[\w-]+[\x{31C0}-\x{31EF}\x{3300}-\x{33FF}\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{F900}-\x{FAFF}\x{FE30}-\x{FE4F}]+[\w-]+$/u", $word);
+  
+  return !$isNonLatinLang;
+}
+
+function json_decode_from_db(string $json, bool $assoc = false) 
+{
+  $temp = $json;
+  $temp = str_replace('\"', '"', $temp);
+  $temp = str_replace("\'", "'", $temp);
+  $temp = str_replace("\\\\", "\\", $temp);
+  
+  return json_decode($temp, $assoc);
+}
+
+/**
+ * Left cut the given string for the specified length 
+ * 
+ * @param string $string the string being cut on the left
+ * @param int $length the length of the substring to return
+ * @return string the resulting substring    
+ */
+function left(?string $string, int $length): string 
+{
+  if (!isset($string) || $string === PHP_STR) {
+    return PHP_STR;
+  }
+  return mb_substr($string, 0, $length);
+}
+
+/**
+ * Right cut the given string for the specified length 
+ * 
+ * @param string $string the string being cut on the right
+ * @param int $length the length of the substring to return
+ * @return string the resulting substring    
+ */
+function right(?string $string, int $length): string 
+{
+  if (!isset($string) || $string === PHP_STR) {
+    return PHP_STR;
+  }  
+  return mb_substr($string, mb_strlen($string) - $length);
+}
+
+/**
+ * Get the left word of the given sentence 
+ * 
+ * @param string $phrase  the sentence being processed
+ * @return string the first word    
+ */
+function leftWord(?string $phrase): string 
+{
+  if (isset1($phrase, PHP_STR)===PHP_STR) {
+    return PHP_STR;
+  }  
+
+  $aWords = explode(PHP_SPACE, $phrase);
+  return $aWords[0]; 
+}
+
+/**
+ * Get the right word of the given sentence 
+ * 
+ * @param string $phrase  the sentence being processed
+ * @return string the last word    
+ */
+function rightWord(?string $phrase): string 
+{
+  if (isset1($phrase, PHP_STR)===PHP_STR) {
+    return PHP_STR;
+  }  
+
+  $aWords = explode(PHP_SPACE, $phrase);
+  return $aWords[count($aWords)-1];
+}
+
+
+/**
+ * Return the number of words of the given phrase
+ * 
+ * @param string $phrase
+ * @return int the number of words of the phrase
+ */
+function mb_str_word_count(string $phrase): int 
+{
+  $aWords = explode(PHP_SPACE, $phrase);
+  return count($aWords);
+}
+
+/**
+ * Finds the position of first occurrence of a string within another, 
+ * result safe (excluding 0), case insensitive
+ * 
+ * @param string $string the string being searched
+ * @param string $needle the string searched
+ * @param int $offset the position in string to start the search 
+ * @return mixed the position of the needle or False
+ */
+function mb_stripos1(string $string, string $needle, int $offset = 0) 
+{
+  return mb_stripos(PHP_TILDE . $string, $needle, $offset);
+}  
+
+/**
+ * Normalize the case of the given text 
+ * 
+ * @param string $text text to case normalize
+ * @return string the normalized text
+ */
+function str_case_normalize(?string $text): string 
+{
+  $retval = $text;
+  
+  if (!isset($text) || $text === PHP_STR) {
+    return $retval;
+  }
+  
+  $aWords = explode(PHP_SPACE, $text);
+  
+  foreach($aWords as & $word) {
+    if (strtoupper(substr($word,0,1)) === substr($word,0,1)) {
+      $word = ucfirst(strtolower($word));
+    } else {  
+      $word = strtolower($word);
+    }  
+  }
+    
+  $retval = implode(" ", $aWords);
+  
+  return $retval;
+}  
+
+/**
+ * Clean a phase removing repeated spaces and trimming it  
+ * 
+ * @param string $string the string being cleaned
+ * @return string the cleaned string
+ */
+function str_cleanphrase(string $string): string 
+{
+  //return trim(str_replace("  ", PHP_SPACE, str_replace("  ", PHP_SPACE, $string)));
+  
+  //hypen
+  $retval = str_replace(" -", PHP_HYPHEN, $string);
+  $retval = str_replace("- ", PHP_HYPHEN, $retval);
+  $retval = ltrim($retval, PHP_HYPHEN);
+  $retval = rtrim($retval, PHP_HYPHEN);
+  //space
+  $retval = trim(str_replace("  ", PHP_SPACE, str_replace("  ", PHP_SPACE, $retval)));
+  
+  return $retval;
+}  
+
+/**
+ * Clean a phase removing repeated spaces and trimming it  
+ * 
+ * @param string $string the string being cleaned
+ * @return string the cleaned string
+ */
+function str_cleanphrase_M(string $string): string 
+{
+  //return trim(str_replace("  ", PHP_SPACE, str_replace("  ", PHP_SPACE, $string)));
+  
+  //hypen
+  $retval = str_replace(" -", PHP_HYPHEN, $string);
+  $retval = str_replace("- ", PHP_HYPHEN, $retval);
+  $retval = ltrim($retval, PHP_HYPHEN);
+  $retval = rtrim($retval, PHP_HYPHEN);
+  //axterix
+  //$retval = trim(str_replace("**", "*", str_replace("**", "*", $retval)));
+  $retval = str_replace("*", PHP_SPACE, $retval);
+  //space
+  $retval = trim(str_replace("  ", PHP_SPACE, str_replace("  ", PHP_SPACE, $retval)));
+  
+  return $retval;
+}  
+
+/**
+ * Clean a phase removing the plurals  
+ * 
+ * @param string $string the string being cleaned
+ * @return string the cleaned string
+ */
+function str_cleanplurals(string $string): string 
+{
+  $aWords = explode(PHP_SPACE, $string);
+  
+  foreach($aWords as &$word) {
+    if (right($word,3)==="ies") {
+      $word = left($word, strlen($word)-3) . "y";
+    }  
+    if (right($word,3)==="hes" || right($word,3)==="xes") {
+      $word = left($word, strlen($word)-2);
+    }  
+    if (right($word,2)==="es") {
+      $word = left($word, strlen($word)-2) . "e";
+    }  
+    if (right($word,2)!=="ss" && right($word,1)==="s") {
+      $word = left($word, strlen($word)-1);
+    }  
+  }
+  
+  return implode(PHP_SPACE, $aWords);
+}  
+
+/**
+ * Break the given phrase by a word separator
+ * 
+ * @param string $phrase the phrase being broken
+ * @param string $word_separetor the word at which beginning break the phrase
+ * @param string $retFirstPart the resulting broken first part of the phrase 
+ * @param string $retReminder the remaining part of the phrase
+ * @return void
+ */
+function str_phrasebrk(string $phrase, string $word_separetor, & $retFirstPart, & $retRemainder = null): void 
+{
+  $phrase = PHP_SPACE . $phrase . PHP_SPACE;
+  $i = mb_stripos1($phrase, PHP_SPACE . $word_separetor . PHP_SPACE);
+  if ($i) {
+    $retFirstPart = trim(mb_substr($phrase, 0, $i));
+    if (isset($retRemainder)) {
+      $retRemainder = trim(mb_substr($phrase, $i));
+    }
+  } else {  
+    $retFirstPart = trim($phrase);
+    if (isset($retRemainder)) {
+      $retRemainder = PHP_STR;
+    }     
+  }
+}
+
+/**
+ * Return the given needle only if not already present in string
+ * 
+ * @param string $string
+ * @param string $needle
+ * @return string
+ */
+function str_place(string $string, string $needle): string  
+{
+   if (mb_stripos(PHP_TILDE . $string, $needle)) {
+     return PHP_STR;
+   } else {
+     return $needle;
+   }
+}
+
+/**
+ * Replace a pattern in the given string
+ * 
+ * @param string $needle the pattern searched for
+ * @param string $replace the replacement
+ * @param string $string the string being searched
+ * @param int $replacements the number of replacements to perform
+ * @return string the replaced string
+ */
+function str_replace1(string $needle, string $replace, ?string $string, int $replacements = 1): string 
+{
+  if (!isset($string) || $replacements === 0) {
+    return $string;
+  }
+  
+  if ($replacements < 0 ) {
+    $string = implode(PHP_SPACE, array_reverse(explode(PHP_SPACE, $string)));
+    $replace = implode(PHP_SPACE, array_reverse(explode(PHP_SPACE, $replace)));
+    $string = preg_replace("/$needle/i", $replace, $string, abs($replacements));
+    $string = implode(PHP_SPACE, array_reverse(explode(PHP_SPACE, $string)));
+  } else {
+    $string = preg_replace("/$needle/i", $replace, $string, abs($replacements));
+  }
+  
+  return $string;
+}
+
+/**
+ * Reverse the words in the given phrase
+ * 
+ * @param string $string the string being reversed
+ * @return string the resulting reversed string
+ */
+function str_phrase_reverse(string $string): string 
+{
+  settype($aWords, "array");
+  $aWords = explode(PHP_SPACE, $string);
+  $aWords = array_reverse($aWords);
+  return implode(PHP_SPACE, $aWords);
+}
+
+/**
+ * Finds the position of the first occurance of a word 
+ * in the given string, result safe (excluding 0), case insensitive
+ * 
+ * @param string $phrase the phrase being searched
+ * @param string $word the searched word
+ * @param int $offset the position in string to start the search 
+ * @return mixed the position of the searched word, otherwise false 
+ */
+function str_wordipos(string $phrase, string $word, int $offset = 0) 
+{
+  if ($offset<0) {
+    $offset=0;
+  }
+  $word = strtolower($word);
+  $phrase = strtolower($phrase);
+  $aWords = explode(" ", $phrase);
+  $max = count($aWords) - 1;
+  $i = $offset; 
+  while ($i <= $max) {
+    $word2 = $aWords[$i];
+    if ($word === $word2) {
+      return $i + 1;
+    }
+    $i++;
+  }
+  return false;
+}
+
+/**
+ * Remove duplicate words from a phrase
+ * 
+ * @param string $phrase the string being processed
+ * @param bool $removeRightMost if remove the right-most duplicates, true/false
+ * @return string the resulting string
+ */
+function str_word_unique(string $phrase, bool $removeRightMost = true) 
+{
+  settype($aWords, "array");
+  $aWords = explode(PHP_SPACE, $phrase);
+  if ($removeRightMost) {
+    // Remove right-most duplicates from the given string..
+    $aWords = array_unique($aWords);
+  } else {
+    // Remove left-most duplicates from the given string..
+    $aWords = array_reverse($aWords);
+    $aWords = array_unique($aWords);
+    $aWords = array_reverse($aWords);
+  }  
+  return implode(PHP_SPACE, $aWords);
+}  
+
+/**
+ * Short words by the given char limit
+ * 
+ * @param string $phrase the phrase being parsed 
+ * @param int $wordLength the word limit to set
+ * @return string  the resulting phrase
+ */
+function str_word_length(string $phrase, int $wordLength): string 
+{
+  $aWords = explode(PHP_SPACE, $phrase);
+  foreach($aWords as & $word) {
+    $word = mb_substr($word, 0, $wordLength);
+  }
+  return implode(PHP_SPACE, $aWords);
+}
+
+/**
+ * Right trim a word from the given string
+ * 
+ * @param string $phrase the string being trimmed
+ * @param array $aWords the words to remove
+ * @return string the resulting right trimmed phrase 
+ */
+function rtrim_word(string $phrase, array $aWords): string 
+{
+  $retval = PHP_SPACE . $phrase . PHP_SPACE;
+  
+  foreach ($aWords as $word) {
+    if (right($retval, mb_strlen($word) + 2) === (PHP_SPACE . $word . PHP_SPACE)) {
+      $retval = left($retval, mb_strlen($retval) - (mb_strlen($word) + 1));
+    }  
+  }  
+  
+  return str_cleanphrase($retval);
+}
+
+/**
+ * Trim a word from the given string
+ * 
+ * @param string $phrase the string being trimmed
+ * @param array $aWords the words to remove
+ * @return string the resulting trimmed phrase 
+ */
+function trim_word(string $phrase, array $aWords) {
+
+  $retval = PHP_SPACE . $phrase . PHP_SPACE;
+  
+  foreach ($aWords as $word) {
+    $retval = str_ireplace(PHP_SPACE . $word . PHP_SPACE, PHP_SPACE, $retval);
+  }  
+  
+  return str_cleanphrase($retval);
+}

+ 138 - 0
Private/functions/func.various.inc

@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * Copyright (c) 2016, 2024, 5 Mode
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither Open Gallery, Daniele Bonini nor the names of its contributors 
+ *       may be used to endorse or promote products derived from this software 
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * func.various.inc
+ * 
+ * Functions of various kind.
+ *
+ * @author Daniele Bonini <my25mb@aol.com>
+ * @copyrights (c) 2016, 2024, 5 Mode
+ * @license https://opensource.org/licenses/BSD-3-Clause 
+ */
+
+/**
+ * Replacement for echo with debug checking
+ * 
+ * @param boolean $debug_var a debug value, if true the echo will be executed 
+ * @param list $args a variable argument list
+ * @return void
+ */
+function echo_ifdebug(bool $debug_var, ...$args): void 
+{
+  if (!DEBUG || !$debug_var) {
+    return;
+  }
+  foreach($args as $arg) {
+    echo $arg;
+  }
+}
+
+function getResource(string $string, string $destLocale = "EN"): string
+{
+  
+  global $LOCALE;
+  
+  if ($destLocale === "EN") {
+    return $string; 
+  }    
+
+  if ($LOCALE[$destLocale]["Monday"]==PHP_STR) {
+    return $string; 
+  }    
+
+  return str_ireplace(array_keys($LOCALE[$destLocale]),array_values($LOCALE[$destLocale]), $string);
+}
+
+
+/**
+ * Get an integer result for a division
+ * 
+ * @param mixed $a first operand
+ * @param mixed $b second operand
+ * @return int the integer result
+ */
+function intdiv_1($a, $b): int 
+{
+  return ($a - $a % $b) / $b;
+}
+
+/**
+ * Check if the number is odd
+ * 
+ * @param mixed $a first operand
+ * @return bool if the number is odd, true/false
+ */
+function is_odd($a): bool 
+{
+  return ($a % 2) > 0;
+}
+
+/**
+ * Check if the number is pair
+ * 
+ * @param mixed $a first operand
+ * @return bool if the number is pair, true/false
+ */
+function is_pair($a): bool
+{
+  return ($a % 2) === 0;
+}
+
+
+/**
+ * Check if a variable is set with a default return
+ * 
+ * @param mixed $var the variable to check
+ * @param mixed $default the default value
+ * @return mixed the return value
+ */
+function isset1(&$var, $default=false) 
+{
+  if (isset($var)) {
+    return $var;
+  } else {
+    return $default;
+  }
+}
+
+/**
+ * Replacement for var_dump with debug checking
+ * 
+ * @param boolean $debug_var a debug value, if true the var_dump will be executed 
+ * @param list $args a variable argument list
+ * @return void
+ */
+function var_dump_ifdebug(bool $debug_var, ...$args): void 
+{
+  if (!DEBUG || !$debug_var) {
+    return;
+  }
+  foreach($args as $arg) {
+    var_dump($arg);
+  }
+}

+ 1 - 0
Private/log/php_errors.log

@@ -0,0 +1 @@
+

+ 80 - 0
dd.html

@@ -0,0 +1,80 @@
+<html>
+<head>
+  
+  <title>5 Mode: Data Disclaimer</title>
+
+  <style>
+    body {
+      background-color: lightgray;
+      margin: 0 0 0 0;
+      font-family: Monospace, Verdana, Serif;
+      font-variant-caps: titling-caps;
+    }
+    a {
+      color: orange;
+      text-decoration: transparent;
+    }
+    a:active {
+      color: orange;
+      text-decoration: transparent;
+    }
+    a:visited {
+      color: orange;
+      text-decoration: transparent;
+    }
+    a:hover {
+      color: orange;
+      text-decoration: transparent;
+    }
+    .desc {
+      color:black;
+      font-size: 1.3vw;
+      position:relative;
+      top:-3vw;
+    }
+    .hop {
+      background-color:#f6f6f6;
+      font-size:5vw;
+      /*font-family: 'Press Start 2P', cursive;*/
+      width: 100%;
+      height: 20%;
+      text-align:center;
+      cursor: pointer;
+    }
+  </style>
+  
+</head>
+
+<body>
+  
+<div class="hop "style="display:table;width:80%;height:100%;clear:both;margin:auto;">
+  <br>  
+  <span style="color:darkgray;">5 Mode: Data Disclaimer</span><br><br>
+  <p class="desc" style="padding:30px;">
+  We go to extraodinary efforts here in 5 Mode to ensure that the data within our website pages is accurate and up-to-date.<br><br>
+
+  We have unique direct touch within our company businesses and development team who provide us with product information starting
+  from before a software announcement through to its launch. Where possible, we verify this information during our review process.
+  Additionally, we love our work so we're always checking and double checking our data, often in combination with user and other
+  contributors feedback.<br><br>
+
+  Even given our herculean efforts we can not guarantee that the information on our website pages is 100% correct.<br><br>
+
+  If a particular information is vital to you, we always recommend asking and testing in a secure developing environment and the
+  best way to start is by visiting the doc of our products, and the doc of the technologies (programming language, webserver, devops,
+  etc.) you are going to use in your places.<br><br>
+
+  If you think that any information of our website is wrong or missing, please contact us <a href="http://5md.link/l/email">here</a>.<br><br>
+
+  Now for the legalese.<br><br>
+
+  5 Mode is not responsible for any errors or omissions, or for the results obtained from the use of the information contained in this website.
+  All information on this site is provided "as is" with no guarantee of completeness, accurancy, timeliness or the results obtained from the use
+  of this information. All the information contained in the linked content is of responsibility of the authors and copyrights holders of that 
+  specific content: we do not assume any responibility for any third-party content linked from this website pages.
+  </p>
+
+</div>
+
+</body>
+</html>

+ 213 - 0
index.html

@@ -0,0 +1,213 @@
+<!DOCTYPE html>
+<html lang="en-US" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	
+  <meta charset="UTF-8"/>
+  <meta name="style" content="day1"/>
+  
+  <meta name="viewport" content="width=device-width, initial-scale=1"/>
+  
+<!--
+    Copyright 2021, 2024 5 Mode
+
+    This file is part of SnipSwap.
+
+    SnipSwap is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    SnipSwap is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with SnipSwap. If not, see <https://www.gnu.org/licenses/>.
+ -->
+     
+  <title>SnipSwap: Swapping code like burgers..</title>
+	
+  <link rel="shortcut icon" href="Public/favicon.ico" />
+    
+  <meta name="description" content="Welcome to SnipSwap"/>
+  <meta name="author" content="5 Mode"/> 
+  <meta name="keywords" content="SnipSwap,snippet,code,swap.swapping,on,premise,solution"/>
+  
+  <script src="Public/js/jquery-3.6.0.min.js" type="text/javascript"></script>
+  <script src="Public/js/common.js" type="text/javascript"></script>
+  <script src="Public/js/bootstrap.min.js" type="text/javascript"></script>
+  <script src="Public/js/sha.js" type="text/javascript"></script>
+  
+  <link href="Public/css/bootstrap.min.css" type="text/css" rel="stylesheet">
+  <link href="Public/css/style.css?v=1631827555" type="text/css" rel="stylesheet">
+
+  <script>
+  
+  function showEncodedPassword() {
+    if ($("#Password").val() === "") {
+      $("#Password").addClass("emptyfield");
+      return;  
+    }
+    passw = encryptSha2( $("#Password").val() );
+    msg = "Please set your new pasword in the config file with this value:";
+    alert(msg + "\n\n" + passw);	
+  }
+  
+  function hideTitle() {
+    $("#myh1").hide("slow");
+  }
+  
+  function startApp() {
+    
+    $("#HCsplash").css("display","none");
+    
+	  //$("#HCsplash").hide("slow");
+    $(document.body).css("background","#ffffff");
+	  $("#frmHC").show();
+	}			
+
+  function _startApp() {
+    setTimeout("startApp()", 1000);    
+  }
+
+	window.addEventListener("load", function() {
+	
+    $("#frmHC").hide();
+    
+    //Splash
+    $("#HCsplash").show();	
+    
+    //$(document.body).css("background","#000000");
+	  //$("#HCsplash").show("slow");	  
+	  //setTimeout("hideTitle()", 2000);
+    //setTimeout("startApp()", 4000);
+
+	}, true);
+
+  window.addEventListener("load", function() {
+      
+    // Fisnished the Intro load the app..
+    //document.getElementById("vplayer").onended=_startApp;
+    setTimeout("_startApp()", 6000);
+  
+  });
+
+  </script>    
+       
+</head>
+<body style="background:#0d0d0d;">
+
+<div id="HCsplash" style="padding-top: 40px; text-align:center;color:#d4b0dc;font-family:'Bungee Hairline';">
+    <div id="myh1" style="position:relative; top:80px;"><H1>SnipSwap</H1></div><br><br>
+    <img src="Public/res/code.png" style="width:310px;">
+</div>  
+  
+<form id="frmHC" method="POST" target="_self" enctype="multipart/form-data" style="display:none;">
+
+<div class="header" style="margin-top:18px;">
+   <a href="http://snipwap.org" target="_self" style="color:#000000; text-decoration: none;">&nbsp;<img src="Public/res/code.png" style="width:22px;">&nbsp;SnipSwap</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/par7133/SnipSwap" style="color:#000000;"><span style="color:#119fe2">on</span> github</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="mailto:info@snipswap.org" style="color:#000000;"><span style="color:#119fe2">for</span> feedback</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="tel:+39-331-4029415" style="font-size:13px;background-color:#15c60b;border:2px solid #15c60b;color:#000000;height:27px;text-decoration:none;">&nbsp;&nbsp;get support&nbsp;&nbsp;</a>
+</div>
+	
+<div style="clear:both; float:left; padding:8px; width:15%; height:100%; text-align:center;">
+	<div style="padding-left:10px;text-align: left;">
+	  &nbsp;Download<br>	
+	  &nbsp;<a href="https://github.com/par7133/SnipSwap/archive/refs/tags/v1.0.5.zip">Release 1.0.5 (zip)</a><br>
+	  &nbsp;<a href="https://github.com/par7133/SnipSwap//archive/refs/tags/v1.0.5.tar.gz">Release 1.0.5 (tar.gz)</a><br>
+	</div>  
+    <br><br>
+    <img src="Public/res/SSgenius.png" alt="SS Genius" title="SS Genius" style="position:relative; left:+6px; width:90%; border: 1px dashed #EEEEEE;">
+    &nbsp;<br><br><br>
+    &nbsp;<input type="text" id="Password" name="Password" placeholder="password" style="font-size:10px; background:#393939; color:#ffffff; width: 90%; border-radius:3px;" value="" autocomplete="off"><br>
+     &nbsp;<a href="#" onclick="showEncodedPassword();" style="position:relative; left:-2px; top:+5px; color:#000000; font-size:12px;">Hash Me!</a>
+    <br><br><br>
+</div>
+
+<div style="float:left; width:85%;height:100%; padding:8px; border-left: 1px solid #2c2f34;">
+	
+	<div id="splash" style="border-radius:20px; position:relative; left:+3px; width:98%; background-color: #33aced; padding: 20px; margin-bottom:8px;">	
+	
+	   <button type="button" class="close" aria-label="Close" onclick="close-Splash();" style="position:relative; left:-10px;">
+        <span aria-hidden="true">&times;</span>
+     </button>
+	
+	   Hello and welcome to SnipSwap!<br><br>
+	   
+	   SnipSwap is a light, simple, "peer-to-peer" software on premise for swapping your snippets of code with others.<br><br>
+	   
+	   SnipSwap is released under GPLv3 license, it is supplied AS-IS and we do not take any responsibility for its misusage.<br><br>
+	   
+        First step, use the left side panel password field to create the hashed password to insert in the config file.<br><br>
+	   
+	   As you are going to run SnipSwap in the PHP process context, using a limited web server or phpfpm user, you must follow some simple directives for an optimal first setup:<br>
+	   <ol>
+	      <li>Check the write permissions of your "data" (repo) folder in your web app private path; and set its path in the config file.</li>
+              <li>Set the default Business Label, Link and Email of the stuff your are going to swap.</li>
+              <li>Set the MAX_DFT_NEW_SNIP value stating the max number of snippet the app is going to initially create.</li>
+	      <li>In Public/js/cube-code.js, in mystart class method, check if you are using 'http' or 'https'.</li>	   
+	   </ol>
+	   
+	   <br>	
+     
+	   Hope you can enjoy it and let us know about any feedback: <a href="mailto:info@snipswap.org" style="color:#e6d236;">info@snipswap.org</a>
+	   
+	</div>	
+  	
+	<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
+	<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>	
+	<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
+	<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>	
+	<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
+	<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>	
+	
+</div>
+
+</form>
+
+<div class="footer">
+<div id="footerCont">&nbsp;</div>
+<div id="footer"><span style="background:#E1E1E1;color:black;opacity:1.0;margin-right:10px;">&nbsp;&nbsp;<a href="dd.html">Disclaimer</a>&nbsp;&nbsp;A <a href="http://5mode.com">5 Mode</a> project and <a href="http://demo.5mode.com">WYSIWYG</a> system. Some rights reserved.</span></div>	
+</div>	
+	
+<script>
+  
+function setFooterPos2() {
+  if (document.getElementById("footerCont")) {
+    //if ($("#Password").val() === "") {  
+    //    tollerance = 48;
+    //  } else {
+    //  tollerance = 15;
+    //}
+    tollerance = 22;  	  
+    $("#footerCont").css("top", parseInt( window.innerHeight - $("#footerCont").height() - tollerance ) + "px");
+    $("#footer").css("top", parseInt( window.innerHeight - $("#footer").height() - tollerance + 6) + "px");
+  }
+}
+setFooterPos2();
+
+//window.addEventListener("load", function() {
+//    
+//  setTimeout("setFooterPos2()", 4000);
+//
+//}, true);
+  
+</script>  
+
+<!-- Yandex.Metrika counter -->
+<script type="text/javascript" >
+   (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
+   m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
+   (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
+
+   ym(88085185, "init", {
+        clickmap:true,
+        trackLinks:true,
+        accurateTrackBounce:true
+   });
+</script>
+<noscript><div><img src="https://mc.yandex.ru/watch/88085185" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
+<!-- /Yandex.Metrika counter -->
+
+</body>	 
+</html>	 
+