VvebOIDC/system/functions.php

2371 lines
59 KiB
PHP

<?php
/**
* Vvveb
*
* Copyright (C) 2022 Ziadin Givan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Vvveb;
function url($parameters, $mergeParameters = false, $useCurrentUrl = true) {
if (is_string($parameters) && $parameters) {
$result = '';
if (isset($mergeParameters['scheme'])) {
$result .= $mergeParameters['scheme'] . ':';
unset($mergeParameters['scheme']);
}
if (isset($mergeParameters['host'])) {
$result .= '//' . \Vvveb\System\Sites::url($mergeParameters['host']);
unset($mergeParameters['host']);
if (isset($mergeParameters['scheme'])) {
$result = $mergeParameters['scheme'] . ":$result";
unset($mergeParameters['scheme']);
}
}
$url = System\Routes::url($parameters, $mergeParameters);
$result .= (V_SUBDIR_INSTALL ? V_SUBDIR_INSTALL : '') . ($url ?? '');
} else {
static $url = '';
static $urlParams = [];
if ($useCurrentUrl) {
$url = parse_url($_SERVER['REQUEST_URI'] ?? '');
if (isset($url['query'])) {
parse_str($url['query'], $urlParams);
}
}
if (! is_array($parameters)) {
$parameters = [];
}
if ($mergeParameters) {
if (is_array($mergeParameters)) {
$mergeParameters = array_merge($urlParams, $mergeParameters);
} else {
$mergeParameters = $urlParams;
}
if (is_array($mergeParameters)) {
$parameters = array_merge($mergeParameters, $parameters);
}
}
$result = '';
if (isset($parameters['host'])) {
$result .= '//' . \Vvveb\System\Sites::url($parameters['host']);
unset($parameters['host']);
if (isset($parameters['scheme'])) {
$result = $parameters['scheme'] . ":$result";
unset($parameters['scheme']);
}
} else {
if (! $useCurrentUrl) {
$result .= (V_SUBDIR_INSTALL ? V_SUBDIR_INSTALL : '');
}
}
$result .= ($useCurrentUrl ? $url['path'] ?? '' : '') . ($parameters ? '?' . urldecode(http_build_query($parameters)) : '');
}
return $result;
}
function config($key = null, $default = null) {
if (is_null($key)) {
return System\Config::getInstance();
}
return System\Config::getInstance()->get($key, $default);
}
function getConfig($key = null, $default = null) {
return System\Config::getInstance()->get($key, $default);
}
function setConfig($key, $value = null) {
return System\Config::getInstance()->set($key, $value);
}
function unsetConfig($key) {
return System\Config::getInstance()->unset($key);
}
//setting
function getSetting($namespace, $key = null, $default = null, $site_id = SITE_ID) {
return System\Setting::getInstance()->get($namespace, $key, $default, $site_id);
}
function setSetting($namespace, $key = null, $value = null, $site_id = SITE_ID) {
return System\Setting::getInstance()->set($namespace, $key, $value, $site_id);
}
function deleteSetting($namespace, $key = null, $site_id = SITE_ID) {
return System\Setting::getInstance()->delete($namespace, $key, $site_id);
}
function setMultiSetting($namespace, $settings, $site_id = SITE_ID) {
return System\Setting::getInstance()->setMulti($namespace, $settings, $site_id);
}
//setting content
function getMultiSettingContent($site_id, $namespace, $key = null, $default = null, $language_id = false) {
return System\Meta\SettingContent::getInstance()->getMulti($site_id, $namespace, $key, $default, $language_id);
}
function setMultiSettingContent($site_id, $meta) {
return System\Meta\SettingContent::getInstance()->setMulti($site_id, $meta);
}
// post meta
function getPostMeta($post_id, $namespace, $key = null, $default = null) {
return System\Meta\PostMeta::getInstance()->get($post_id, $namespace, $key, $default);
}
function setPostMeta($post_id, $namespace, $key = null, $value = null) {
return System\Meta\PostMeta::getInstance()->set($post_id, $namespace, $key, $value);
}
function deletePostMeta($post_id, $namespace, $key = null) {
return System\Meta\PostMeta::getInstance()->delete($post_id, $namespace, $key);
}
function setMultiPostMeta($post_id, $namespace, $meta) {
return System\Meta\PostMeta::getInstance()->setMulti($post_id, $namespace, $meta);
}
// post meta content
function getPostContentMeta($post_id, $namespace, $key = null, $default = null, $language_id = false) {
return System\Meta\PostContentMeta::getInstance()->get($post_id, $namespace, $key, $default, $language_id);
}
function getMultiPostContentMeta($post_id, $namespace, $key = null, $default = null, $language_id = false) {
return System\Meta\PostContentMeta::getInstance()->getMulti($post_id, $namespace, $key, $default, $language_id);
}
function getMultiProductContentMeta($product_id, $namespace, $key = null, $default = null, $language_id = false) {
return System\Meta\ProductContentMeta::getInstance()->getMulti($product_id, $namespace, $key, $default, $language_id);
}
function setPostContentMeta($post_id, $namespace, $key = null, $value = null, $language_id = false) {
return System\Meta\PostContentMeta::getInstance()->set($post_id, $namespace, $key, $value, $language_id);
}
function setProductContentMeta($product_id, $namespace, $key = null, $value = null, $language_id = false) {
return System\Meta\ProductContentMeta::getInstance()->set($product_id, $namespace, $key, $value, $language_id);
}
function deletePostContentMeta($post_id, $namespace, $key = null, $language_id = false) {
return System\Meta\PostContentMeta::getInstance()->delete($post_id, $namespace, $key, $language_id);
}
function deleteProductContentMeta($product_id, $namespace, $key = null, $language_id = false) {
return System\Meta\ProductContentMeta::getInstance()->delete($product_id, $namespace, $key, $language_id);
}
function setMultiPostContentMeta($post_id, $meta) {
return System\Meta\PostContentMeta::getInstance()->setMulti($post_id, $meta);
}
function setMultiProductContentMeta($product_id, $meta) {
return System\Meta\ProductContentMeta::getInstance()->setMulti($product_id, $meta);
}
function getCurrentTemplate() {
return System\Core\View :: getInstance()->template();
}
function getUrlRoute($url) {
$urlData = \Vvveb\System\Routes::getUrlData($url);
return $urlData;
}
function getCurrentUrl() {
return $_SERVER['REQUEST_URI'] ?? '';
}
function adminPath() {
return (V_SUBDIR_INSTALL ? V_SUBDIR_INSTALL : '') . '/' . \Vvveb\config('admin.path', 'admin') . '/';
}
function publicUrlPath() {
$public_path = PUBLIC_PATH;
if (V_SUBDIR_INSTALL) {
$public_path = str_replace(V_SUBDIR_INSTALL, '', $public_path);
}
if ($public_path == '/public/' || $public_path == '/public/admin/') {
return PUBLIC_PATH;
} else {
return '/';
}
}
function themeUrlPath() {
$theme = \Vvveb\System\Core\View::getInstance()->getTheme();
//$theme = 'landing';
if (APP == 'app') {
$path = PUBLIC_THEME_PATH . 'themes/' . $theme . '/';
} else {
$path = PUBLIC_THEME_PATH . $theme . '/';
}
return $path;
}
function escUrl($url) {
return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
}
function escAttr($attr) {
return htmlspecialchars($attr);
}
function escHtml($url) {
return htmlspecialchars($url);
}
function env($key, $default = null) {
if ($env = getenv($key)) {
return $env;
} else {
return $default;
}
}
if (! function_exists('nggetext')) {
function nggetext($singular, $plural, $number) {
return ($number > 1) ? $plural : $singular;
}
}
function friendlyDate($date) {
$fileformats = [
1 => function ($i) { return __('%d second', '%d seconds', $i); },
60 => function ($i) { return __('%d minute', '%d minutes', $i); },
3600 => function ($i) { return __('%d hour', '%d hours', $i); },
86400 => function ($i) { return __('%d day', '%d days', $i); },
604800 => function ($i) { return __('%d week', '%d weeks', $i); },
2592000 => function ($i) { return __('%d month', '%d months', $i); },
31536000 => function ($i) { return __('%d year', '%d years', $i); },
315360000 => function ($i) { return __('%d decade', '%d decades', $i); },
3153600000 => function ($i) { return __('%d century', '%d centuries', $i); },
];
$time_direction = __(' ago');
if (is_string($date)) {
$date = strtotime($date);
}
$diff = time() - $date + 10;
if ($diff < 0) {
$time_direction = __(' from now');
$diff = abs($diff);
}
$lastTime = 1;
$lastText = $fileformats[1]($diff);
foreach ($fileformats as $time => $text) {
if ($diff < $time) {
$units = floor($diff / $lastTime);
return sprintf($lastText($units), $units) . $time_direction;
}
$lastText = $text;
$lastTime = $time;
}
return $date;
}
/*
Convert var.key1.key2 > var['key1']['key2']
*/
function dotToArrayKey($key) {
//var.key1.key2 > var['key1']['key2']
//var.key1 > var['key1']
return preg_replace_callback('/\.([-_\w]+)/', function ($matches) {
return "['" . str_replace("'", "\'", $matches[1]) . "']";
}, $key);
}
/*
Convert name[key] > ['name']['key']
*/
function postNameToArrayKey($key) {
$key = str_replace(['][', '[', ']'] , ['.', '.', ''], $key);
return '[\'' . str_replace('.', '\'][\'', $key) . '\']';
}
/*
Prefix array keys
*/
function prefixArrayKeys($prefix, &$array) {
if (is_array($array)) {
foreach ($array as $k => $v) {
$array["$prefix$k"] = $v;
unset($array[$k]);
}
}
return $array;
}
function filterText($data) {
return urldecode(filter_var($data, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH | FILTER_FLAG_ENCODE_LOW));
}
function session($data, $default = null) {
$session = System\Session :: getInstance();
if (! $session) {
return $default;
}
if (is_array($data)) {
foreach ($data as $key => $value) {
$session->set($key, $value);
}
} else {
$value = $session->get($data);
if ($default && $value === null) {
return $default;
}
return $value;
}
}
/*
* Regex filter to allow only matched content
*
* @param string $regex
* @param string $input
* @param integer $maxInputSize [100]
*/
function filter($regex, $input, $maxInputSize = 100) {
$matches = [];
if (preg_match($regex, substr($input, 0, $maxInputSize), $matches)) {
return $matches[0];
} else {
return false;
}
}
/**
* Shortcut for preg_match to return the matched parameter directly.
*
* @param string $regex
* @param string $input
* @param integer $level [false]
*
* @return mixed
*/
function pregMatch($regex, $input, $level = false) {
$matches = [];
//if (preg_match($regex, $input, $matches, PREG_UNMATCHED_AS_NULL | PREG_PATTERN_ORDER)) {
if (preg_match($regex, $input, $matches, PREG_UNMATCHED_AS_NULL)) {
if ($level !== false) {
return $matches[$level];
}
return $matches;
} else {
return false;
}
}
/**
* Shortcut for preg_match_all to return the matched parameters directly.
*
* @param string $regex
* @param string $input
* @param integer $level [false]
*
* @return mixed
*/
function pregMatchAll($regex, $input, $level = false) {
$matches = [];
if (preg_match_all($regex, $input, $matches, PREG_UNMATCHED_AS_NULL | PREG_PATTERN_ORDER)) {
if ($level !== false) {
return $matches[$level];
}
return $matches;
} else {
return false;
}
}
function arrayAllowValues($input, $allowedValues) {
if (! in_array($input, $allowedValues)) {
return null;
} else {
return $input;
}
}
/*
* Get values from multidimensional arrays based on path
* For example for array ['item' => ['desc' => ['name' => 'test']]] the path "item.description.name" will return "test".
*
* */
function arrayPath(array $a, $path, $default = null, $token = '.') {
$p = strtok($path, $token);
while ($p !== false) {
if (! isset($a[$p])) {
return $default;
}
$a = $a[$p];
$p = strtok($token);
}
return $a;
}
function humanReadable($text) {
if (is_string($text)) {
return ucfirst(str_replace(['_', '-', '/', '[', ']', '.'], [' ', ' ', ' - ', ' ', ' ', ' '], trim($text, ' /\-_')));
}
return $text;
}
function cleanUrl($text, $divider = '-') {
// replace non letter or digits by divider
$text = preg_replace('/[^\pL\d]+/u', $divider, $text);
// remove unwanted characters
$text = preg_replace('/[^\\-\w]+/', '', $text);
$text = trim($text, $divider);
return $text;
}
function slugify($text, $divider = '-') {
if (! $text) {
return $text;
}
// replace non letter or digits by divider
$text = preg_replace('/[^\pL\d]+/u', $divider, $text);
// transliterate
if (function_exists('iconv')) {
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
}
// remove unwanted characters
$text = preg_replace('/[^-\w]+/', '', $text);
// trim
$text = trim($text, $divider);
// remove duplicate divider
$text = preg_replace('/-+/', $divider, $text);
// lowercase
$text = strtolower($text);
return $text;
}
if (function_exists('_')) {
function __($text, $plural = false, $count = false) {
if ($plural) {
//$plural = substr($plural, 0, 1024);
$translation = ngettext($text, $plural, $count);
} else {
$translation = gettext($text);
}
return $translation;
}
} else {
function __($text, $plural = false, $count = false) {
return $text;
}
}
function isAdmin() {
return System\User\Admin::current() ? true : false;
}
function cssToXpath($selector) {
//if already xpath don't transform
//if (substr_compare($selector,'vtpl_xpath', 0, 11) == 0) return substr($selector, 12, -1);
$selector = (string) $selector;
//convert , to | union operator to allow multiple queries
$selector = str_replace(',', '|', $selector);
$cssSelector = [
// E > F: Matches any F element that is a child of an element E
'/\s*>\s*/',
// E + F: Matches any F element immediately preceded by an element
'/\s*\+\s*/',
// E F: Matches any F element that is a descendant of an E element
'/([a-zA-Z\*="\[\]#._-])\s+([a-zA-Z\*="\[\]#._-])/', //'/([a-zA-Z\*="\[\]#._-])\s+([a-zA-Z\*#._-])/',
// E:first-child: Matches element E when E is the first child of its parent
'/([a-z#\.]\w*):first-child/',
// E:nth-child() Matches the nth child element
'/([a-z#\.]\w*):nth-child\((\d+)\)/',
// E:first: Matches the first element from the set
'/([a-z#\.]\w*):first/',
// E:nth(2): Matches the nth element from the set
'/([a-z#\.]\w*):nth\((\d+)\)/',
// E[foo="warning"]: Matches any E element whose "foo" attribute value is exactly equal to "warning"
'/([a-z]\w*)\[([a-z][\w\-_]*)\="([^"]*)"]/',
// E[foo]: Matches any E element with the "foo" attribute set (whatever the value)
'/([a-z]\w*)\[([a-z][\w_\-]*)\]/',
// E[!foo]: Matches any E element without the "foo" attribute set
'/([a-z]\w*)\[!([a-z][\w\-_]*)\]/',
// [foo="warning"]: Matches any element whose "foo" attribute value is exactly equal to "warning"
'/\[([a-z][\w\-_]*)\=\"(.*)\"\]/',
// [foo*="warning"]: Matches any element whose "foo" attribute value contains the string "warning" and has other attributes
'/(?<=\])\[([a-z][\w\-_]*)\*\=\"([^"]+)\"\]/',
// [foo*="warning"]: Matches any element whose "foo" attribute value contains the string "warning"
'/\[([a-z][\w\-_]*)\*\=\"([^"]+)\"\]/',
// [foo^="warning"]: Matches any element whose "foo" attribute value begins with the string "warning"
'/\[([a-z][\w_\-]*)\^\=\"([^"]+)\"\]/',
// [foo$="warning"]: Matches any element whose "foo" attribute value ends with the string "warning"
'/\[([a-z][\w_\-]*)\$\=\"([^"]+)\"\]/',
// [foo][baz]: Matches any element with the "foo" attribute set (whatever the value)
'/(?<=\])(?<! )\[([a-z][\w_\-]*)\]/',
// [foo]: Matches any element with the "foo" attribute set (whatever the value)
'/\[([a-z][\w_\-]*)\]/',
// element[foo*]: Matches any element that starts with "foo" attribute (whatever the value)
'/(\w+)\[([a-z][\w\-]*)\*\]/',
// [foo*]: Matches any element that starts with "foo" attribute (whatever the value) and has other attributes
'/(?<=\])\[([a-z][\w\-]*)\*\]/',
// [foo*]: Matches any element that starts with "foo" attribute (whatever the value) and is a single attribute
'/(?<!\])\[([a-z][\w\-]*)\*\]/',
// div.warn*: HTML only. The same as DIV[class*="warning"]
'/([a-z]\w*|\*)\.([a-z][\w\-_]*)\*/',
// div.warning: HTML only. The same as DIV[class~="warning"]
'/([a-z]\w*|\*)\.([a-z][\w\-_]*)+/',
// .warn*: HTML only. The same as [class*="warning"]
'/\.([a-z][\w\-\_]*)\*/',
// .warning: HTML only. The same as [class~="warning"]
'/\.([a-z][\w\-\_]*)+/',
// E#myid: Matches any E element with id-attribute equal to "myid"
'/([a-z]\w*)\#([a-z][\w\-_]*)/',
// #myid: Matches any E element with id-attribute equal to "myid"
'/\#([a-z][\w\-_]*)/',
];
$xpathQuery = [
'/', //element > child
'/following-sibling::*[1]/self::', // element + precedent
'\1//\2', //element descendent
'*[1]/self::\1', //element:first-child
'*[\2]/self::\1', //element:nth-child(2)
'\1[1]', //element:first
'\1[\2]', //element:nth(2)
'\1[ contains( concat( " ", @\2, " " ), concat( " ", "\3", " " ) ) ]', //element[attribute="string"]
'\1 [ @\2 ]', //element[attribute]
'\1 [ not(@\2) ]', //element[!attribute]
'[ contains( concat( " ", @\1, " " ), concat( " ", "\2", " " ) ) ]', //[foo="warning"]
'*[ contains( concat( " ", @\1, " " ), concat( " ", "\2", " " ) ) ]', //[foo="warning"]
'*[ contains( concat( " ", @\1, " " ), "\2" ) ]', //[foo*="warning"]
'*[ contains( concat( " ", @\1, " " ), concat( " ", "\2", " " ) ) ]', //[foo^="warning"] not implemented
'*[ contains( concat( " ", @\1, " " ), concat( " ", "\2", " " ) ) ]', //[foo$="warning"] not implemented
'[ @\1 ]', //[attribute][attribute]
'*[ @\1 ]', //[attribute]
'\1 [ @*[starts-with(name(), "\2")] ]', //element[attr*]
'[ @*[starts-with(name(), "\1")] ]', //[attr*] - attribute with other attributes
'*[ @*[starts-with(name(), "\1")] ]', //[attr*] - single attribute
'\1[ contains( concat( " ", @class, " " ), concat( " ", "\2") ) ]', //element[class*="string"]
'\1[ contains( concat( " ", @class, " " ), concat( " ", "\2", " " ) ) ]', //element[class~="string"]
'*[ contains( concat( " ", @class, " " ), concat( " ", "\1") ) ]', //[class*="string"]
'*[ contains( concat( " ", @class, " " ), concat( " ", "\1", " " ) ) ]', //element[class~="string"]
'\1[ @id = "\2" ]', //element#id
'*[ @id = "\1" ]', //#id
];
$result = (string) '//' . preg_replace($cssSelector, $xpathQuery, $selector);
return $result;
}
function dashesToCamelCase($string, $dash = '-') {
return str_replace($dash, '', ucwords($string, $dash));
}
function arrayKeysToCamelCase(&$array) {
foreach ($array as $key => &$value) {
if (is_array($value)) {
$value = arrayKeysToCamelCase($value);
}
$newKey = lcfirst(dashesToCamelCase($key, '_'));
if ($newKey != $key) {
$array[$newKey] = $value;
unset($array[$key]);
}
}
return $array;
}
/**
* Remove extra spaces.
* @param mixed $string
*
* @return string
*/
function stripExtraSpaces($string) {
foreach (['\t', '\n', '\r', ' '] as $space) {
$string = preg_replace('/(' . $space . ')' . $space . '+/', '\1', $string);
}
return $string;
}
function tail($filename, $lines = 1000) {
$file = @fopen($filename, 'rb');
if ($file === false) {
return false;
}
$buffer = 4096;
$output = '';
$chunk = '';
@fseek($file, -1, SEEK_END);
if (fread($file, 1) != "\n") {
$lines -= 1;
}
while (ftell($file) > 0 && $lines >= 0) {
$seek = min(ftell($file), $buffer);
fseek($file, -$seek, SEEK_CUR);
$output = ($chunk = fread($file, $seek)) . $output;
//fseek($file, -mb_strlen($chunk, '8bit'), SEEK_CUR);
fseek($file, strlen($chunk), SEEK_CUR);
$lines -= substr_count($chunk, "\n");
}
while ($lines++ < 0) {
$output = substr($output, strpos($output, "\n") + 1);
}
fclose($file);
return trim($output);
}
/**
* Return current module name.
*
* @return string
*/
function getModuleName() {
return strtolower(\Vvveb\System\Core\FrontController::getModuleName());
}
/**
* Return current action name.
*
* @return string
*/
function getActionName() {
return strtolower(\Vvveb\System\Core\FrontController::getActionName());
}
/*
* Inserts a new key/value before the key in the array.
*
* @param $key
* The key to insert before.
* @param $array
* An array to insert in to.
* @param $new_key
* The key to insert.
* @param $new_value
* An value to insert.
*
* @return
* The new array if the key exists, otherwise the unchanged array.
*
* @see arrayInsertAfter()
*/
function arrayInsertBefore($key, array &$array, $new_key, $new_value) {
if (array_key_exists($key, $array)) {
$new = [];
foreach ($array as $k => $value) {
if ($k === $key) {
$new[$new_key] = $new_value;
}
$new[$k] = $value;
}
return $new;
}
return $array;
}
/*
* Inserts a new array before the key in the array.
*
* @param $key
* The key to insert before.
* @param $array
* An array to insert in to.
* @param $new_key
* The key to insert.
* @param $new_value
* An value to insert.
*
* @return
* The new array if the key exists, otherwise the unchanged array.
*
* @see arrayInsertAfter()
*/
function arrayInsertArrayBefore($key, array &$array, $new_array) {
if (array_key_exists($key, $array)) {
$new = [];
foreach ($array as $k => $value) {
if ($k === $key) {
$new += $new_array;
}
$new[$k] = $value;
}
return $new;
}
return $array;
}
/*
* Inserts a new key/value after the key in the array.
*
* @param $key
* The key to insert after.
* @param $array
* An array to insert in to.
* @param $new_key
* The key to insert.
* @param $new_value
* An value to insert.
*
* @return
* The new array if the key exists, otherwise the unchanged array.
*
* @see arrayInsertBefore()
*/
function arrayInsertAfter($key, array &$array, $new_key, $new_value) {
if (array_key_exists($key, $array)) {
$new = [];
foreach ($array as $k => $value) {
$new[$k] = $value;
if ($k === $key) {
$new[$new_key] = $new_value;
}
}
return $new;
}
return $array;
}
/*
* Inserts a new array after the key in the array.
*
* @param $key
* The key to insert after.
* @param $array
* An array to insert in to.
* @param $new_key
* The key to insert.
* @param $new_value
* An value to insert.
*
* @return
* The new array if the key exists, otherwise the unchanged array.
*
* @see arrayInsertBefore()
*/
function arrayInsertArrayAfter($key, array &$array, $new_array) {
if (array_key_exists($key, $array)) {
$new = [];
foreach ($array as $k => $value) {
$new[$k] = $value;
if ($k === $key) {
$new += $new_array;
}
}
return $new;
}
return $array;
}
//request
function get($key) {
return System\Core\Request::getInstance()->get[$key] ?? false;
}
/**
* Check if the page is loaded in the editor.
*
* @return boolean
*/
function isEditor() {
return isset($_GET['r']);
}
function logError($message) {
error_log($message);
}
function getThemeFolderList($theme = false) {
$skipFolders = ['src', 'source', 'backup', 'sections', 'blocks', 'inputs', 'css', 'scss', 'fonts', 'img', 'import', 'node_modules', 'screenshots', 'video', 'js'];
if (! $theme) {
$theme = \Vvveb\System\Sites::getTheme(SITE_ID) ?? 'default';
}
$themeFolder = DIR_THEMES . $theme;
$files = glob("$themeFolder/*", GLOB_ONLYDIR);
$pages['/'] = ['name' => '/', 'title' => '/', 'filename' => '/', 'file' => '/', 'path' => '/', 'folder' => $theme];
foreach ($files as $file) {
$folder = preg_replace('@^.*/themes/[^/]+/@', '', $file);
$filename = basename($file);
if (in_array($folder, $skipFolders)) {
continue;
}
//$path = PUBLIC_PATH . "themes/$theme/$folder";
$pages[$file] = ['name' => $filename, 'title' => "/$filename", 'filename' => $filename, 'file' => $filename, 'folder' => $theme];
}
return $pages;
}
function getFieldTypes() {
return
[
'basic' => [
'text' => [
'name' => __('Text'),
'icon' => 'icon-text-outline',
],
'textarea' => [
'name' => __('Textarea'),
'icon' => 'icon-document-text-outline',
],
'number' => [
'name' => __('Number'),
'icon' => 'icon-document-text-outline',
],
'range' => [
'name' => __('Range'),
'icon' => 'icon-git-commit-outline',
],
'email' => [
'name' => __('Email'),
'icon' => 'icon-mail-outline',
],
'url' => [
'name' => __('Url'),
'icon' => 'icon-link-outline',
],
'tel' => [
'name' => __('Telephone'),
'icon' => 'icon-call-outline',
],
'password' => [
'name' => __('Password'),
'icon' => 'icon-lock-open-outline',
],
'select' => [
'name' => __('Select'),
'icon' => 'icon-chevron-down-circle-outline',
],
],
'content' => [
'image' => [
'name' => __('Image'),
'icon' => 'icon-image-outline',
],
'file' => [
'name' => __('File'),
'icon' => 'icon-document-outline',
],
'wysiwyg' => [
'name' => __('Wysiwyg Editor'),
'icon' => 'icon-create-outline',
],
'oembed' => [
'name' => __('oEmbed'),
'icon' => 'icon-videocam-outline',
],
'gallery' => [
'name' => __('Gallery'),
'icon' => 'icon-images-outline',
],
],
'choice' => [
'select' => [
'name' => __('Select'),
'icon' => 'icon-chevron-down-circle-outline',
],
'checkbox' => [
'name' => __('Checkbox'),
'icon' => 'icon-checkbox-outline',
],
'radio' => [
'name' => __('Radio Button'),
'icon' => 'icon-checkmark-circle-outline',
],
'toggle' => [
'name' => __('Toggle'),
'icon' => 'icon-toggle-outline',
],
],
'relational' => [
'link' => [
'name' => __('Link'),
'icon' => 'icon-link-outline',
],
'post' => [
'name' => __('Post'),
'icon' => 'icon-document-text-outline',
],
'product' => [
'name' => __('Product'),
'icon' => 'icon-cube-outline',
],
'relationship' => [
'name' => __('Relationship'),
'icon' => 'icon-link-outline',
],
'taxonomy' => [
'name' => __('Taxonomy'),
'icon' => 'icon-apps-outline',
],
'user' => [
'name' => __('User'),
'icon' => 'icon-person-outline',
],
],
'widgets' => [
'google_map' => [
'name' => __('Google Map'),
'icon' => 'icon-map-outline',
],
'color' => [
'name' => __('Color'),
'icon' => 'icon-color-palette-outline',
],
'time' => [
'name' => __('Time'),
'icon' => 'icon-time-outline',
],
'date' => [
'name' => __('Date'),
'icon' => 'icon-today-outline',
],
'date_time' => [
'name' => __('Date time'),
'icon' => 'icon-calendar-clear-outline',
],
'month' => [
'name' => __('Month'),
'icon' => 'icon-calendar-outline',
],
'week' => [
'name' => __('week'),
'icon' => 'icon-calendar-number-outline',
],
],
'advanced' => [
'message' => [
'name' => __('Message'),
'icon' => 'icon-chevron-down-circle-outline',
],
'accordion' => [
'name' => __('Accordion'),
'icon' => 'icon-chevron-down-circle-outline',
],
'tab' => [
'name' => __('Tab'),
'icon' => 'icon-chevron-down-circle-outline',
],
],
];
}
function getDefaultTemplateList() {
return [
'index.html',
'index.coming-soon.html',
'index.maintenance.html',
'blank.html',
'error404.html',
'error500.html',
'contact.html',
'search/index.html',
'content/post.html',
'content/page.html',
'content/index.html',
'content/category.html',
'content/tag.html',
'product/index.html',
'product/product.html',
'product/category.html',
];
}
function getTemplateList($theme = null, $skip = []) {
$friendlyNames = [
'index' => ['name' => __('Home page'), 'description' => __('Website homepage'), 'global' => true],
'index.coming-soon' => ['name' => __('Coming soon'), 'description' => __('Coming soon message page'), 'global' => true],
'index.maintenance' => ['name' => __('Under maintenance'), 'description' => __('Website under maintenance message page'), 'global' => true],
'contact' => ['name' => __('Contact us page'), 'description' => __('Contact us page')],
'blank' => ['name' => __('Blank page'), 'description' => __('Template page used for new pages')],
'product' => ['name' => __('Product page'), 'description' => __('Used to display a product'), 'editor' => ['template' => 'product'], 'global' => true],
'error404' => ['name' => __('Page not found'), 'description' => __('Shows when a page is not available'), 'global' => true],
'error500' => ['name' => __('Server error'), 'description' => __('Site error display page'), 'global' => true],
'content-index' => ['name' => __('Blog homepage'), 'description' => __('Blog page with latest posts'), 'global' => true],
'content-post' => ['name' => __('Blog post'), 'description' => __('Blog post'), 'editor' => ['template' => 'post'], 'global' => true],
'content-page' => ['name' => __('Page'), 'description' => __('Page'), 'editor' => ['template' => 'page'], 'global' => true],
'product-index' => ['name' => __('Shop page'), 'description' => __('Shop homepage'), 'global' => true],
'search-index' => ['name' => __('Search page'), 'description' => __('Search page'), 'global' => true],
'user-index' => ['name' => __('Dashboard'), 'description' => __('User dashboard'), 'global' => true],
];
$skipFolders = array_merge(['src', 'source', 'backup', 'sections', 'blocks', 'inputs', 'css', 'scss', 'screenshots', 'locale', 'node_modules'], $skip);
if (! $theme) {
$theme = \Vvveb\System\Sites::getTheme(SITE_ID) ?? 'default';
}
$pages = [];
$themeFolder = DIR_THEMES . $theme;
//$files = glob("$themeFolder/{,*/*/,*/}*.html", GLOB_BRACE);
$glob = ['', '*/*/', '*/'];
$files = globBrace($themeFolder . DS, $glob, '*.html');
foreach ($files as $file) {
$file = preg_replace('@^.*[\\\/]themes[\\\/][^\\\/]+[\\\/]@', '', $file);
$filename = basename($file);
$folder = \Vvveb\System\Functions\Str::match('@(\w+)/.*?$@', $file) ?? '/';
$path = \Vvveb\System\Functions\Str::match('@(\w+)/.*?$@', $file);
if (in_array($folder, $skipFolders)) {
continue;
}
$name = $title = str_replace('.html', '', $filename);
$description = '';
$name = (! empty($folder) && $folder != '/') ? "$folder-$name" : $name;
if (isset($friendlyNames[$name])) {
if (isset($friendlyNames[$name]['description'])) {
$description = $friendlyNames[$name]['description'];
}
$title = $friendlyNames[$name]['name'];
}
$url = PUBLIC_PATH . "themes/$theme/$file";
$pages[$name] = ['name' => $name, 'filename' => $filename, 'file' => $file, 'url' => $url, 'title' => humanReadable($title), 'folder' => $path, 'description' => $description, 'global' => $friendlyNames[$name]['global'] ?? false];
if (isset($friendlyNames[$name]['editor'])) {
$pages[$name]['editor'] = $friendlyNames[$name]['editor'];
}
}
//ksort($pages);
return $pages;
}
function sanitizeFileName($file) {
if (! $file) {
return $file;
}
//remove null bytes
$file = str_replace(chr(0), '', $file);
//sanitize, remove double dot .. and remove get parameters if any
$file = preg_replace('@\?.*$|\.{2,}|[^\/\\a-zA-Z0-9\-\._]@' , '', $file);
$file = preg_replace('@[^\/\w\s\d\.\-_~,;:\[\]\(\)\\]|[\.]{2,}@', '', $file);
//replace directory separators with OS specific separator
$file = str_replace(['\\', '/'], DS, $file);
return $file;
}
function formatBytes($bytes) {
$i = 0;
$units = ['', 'K', 'M', 'G', 'T', 'P', 'E'];
while (($remainder = ($bytes / 1024)) > 1) {
$bytes = $remainder;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i] . 'B';
}
function parseQuantity($string) {
if (function_exists('\ini_parse_quantity')) {
return \ini_parse_quantity($string);
}
$string = trim($string);
$multiplier = lcfirst($string[strlen($string) - 1]);
$number = intval($string);
switch ($multiplier) {
case 'k':
return $number * 1024;
case 'm':
return $number * 1048576;
case 'g':
return $number * 1073741824;
}
return $number;
}
function isController($name, $app = APP) {
$file = DIR_ROOT . $app . DS . 'controller' . DS . strtolower($name) . '.php';
$exists = file_exists($file);
return $exists;
}
function isModel($name, $app = APP) {
$file = DIR_ROOT . $app . DS . 'sql' . DS . DB_ENGINE . DS . $name . '.sql';
$exists = file_exists($file);
return $exists;
}
function model($model) {
$modelClass = 'Vvveb\Sql\\' . ucwords($model) . 'SQL';
return new $modelClass();
}
function controller($name) {
$controllerClass = 'Vvveb\Controller\\' . ucwords($name);
return new $controllerClass();
}
function fieldTypeClass($fieldType) {
$field = ucfirst($fieldType);
$fieldClass = "Vvveb\System\Fields\\$fieldType";
if (! class_exists($fieldClass)) {
return;
}
return $fieldClass;
}
function postTypes($type) {
$defaultTypes = [
'post' => [
'post' => [
'name' => 'Post',
'source' => 'default',
'site_id' => '0',
'type' => 'post',
'plural' => 'posts',
'icon' => 'icon-document-text-outline',
'comments'=> true,
],
'page' => [
'name' => 'Page',
'source' => 'default',
'site_id' => '0',
'type' => 'page',
'plural' => 'pages',
'icon' => 'icon-document-outline',
'comments'=> false,
],
],
'product' => [
'product' => [
'name' => 'Product',
'type' => 'product',
'site_id' => '0',
'source' => 'default',
'plural' => 'products',
'icon' => 'icon-cube-outline',
],
],
];
$default = $defaultTypes[$type] ?? [];
$typeName = ucfirst($type);
list($pluginTypes) = System\Event::trigger('Vvveb\postTypes', "custom$typeName", []);
array_walk($pluginTypes, function (&$type,$key) {
$type['source'] = 'plugin';
$type['name'] = ucfirst($key);
});
$userTypes = getSetting($type, 'types', []);
$params = ['module' => "settings/{$type}-type"];
$paramsList = ['module' => "settings/{$type}-types"];
array_walk($userTypes, function (&$type,$key) use ($params, $paramsList) {
$type['source'] = 'user';
$type['name'] = ucfirst($key);
$type['url'] = \Vvveb\url($params + ['type' => $type['type']]);
$type['delete-url'] = \Vvveb\url($paramsList + ['action' => 'delete', 'type[]' => $type['type']]);
});
$types = $default + $pluginTypes + $userTypes;
return $types;
}
function d(...$variables) {
foreach ($variables as $variable) {
echo highlight_string("<?php\n" . var_export($variable, true), true);
}
}
function dd(...$variables) {
foreach ($variables as $variable) {
echo highlight_string("<?php\n" . var_export($variable, true), true);
}
die(0);
}
function encrypt($key, $value, $cipher = 'aes256', $digest = 'sha256', $tag = null, $aad = '', $tag_length = 16) {
$key = openssl_digest($key, $digest, true);
$iv_length = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($iv_length);
return base64_encode($iv . openssl_encrypt($value, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag, $aad, $tag_length));
}
function decrypt($key, $value, $cipher = 'aes256', $digest = 'sha256', $tag = null, $aad = '') {
$result = false;
$key = openssl_digest($key, $digest, true);
$iv_length = openssl_cipher_iv_length($cipher);
$value = base64_decode($value);
$iv = substr($value, 0, $iv_length);
$value = substr($value, $iv_length);
if (strlen($iv) == $iv_length) {
$result = openssl_decrypt($value, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag, $aad);
}
return $result;
}
function camelToUnderscore($string, $us = '-') {
return strtolower(preg_replace(
'/(?<=\d)(?=[A-Za-z])|(?<=[A-Za-z])(?=\d)|(?<=[a-z])(?=[A-Z])/', $us, $string));
}
function arrayKeysToUnderscore(&$array, $us = '-') {
foreach ($array as $key => &$value) {
if (is_array($value)) {
$value = arrayKeysToUnderscore($value, $us);
}
$newKey = camelToUnderscore($key, $us);
if ($newKey != $key) {
$array[$newKey] = $value;
unset($array[$key]);
}
}
return $array;
}
function stripTags($string, $tags = ['script', 'iframe', 'applet']) {
if ($string && $tags) {
foreach ($tags as $tag) {
$string = preg_replace("@<\s*$tag.*?>.*?</$tag\s*>@im", '', $string);
}
}
return $string;
}
function stripTagsArray($array, $tags) {
if (is_array($array) && $tags) {
array_map($array, function ($key, $value) {
return stripTags($value);
});
}
return $array;
}
function sanitizeHTML($string) {
if (! is_string($string)) {
return $string;
}
//$string = stripTags($string);
// Fix &entity\n;
$string = str_replace(['&amp;', '&lt;', '&gt;'], ['&amp;amp;', '&amp;lt;', '&amp;gt;'], $string);
$string = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $string);
$string = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $string);
$string = html_entity_decode($string, ENT_COMPAT, 'UTF-8');
// Remove any attribute starting with "on" or xmlns
$string = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $string);
// Remove javascript: and vbscript: protocols
$string = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $string);
$string = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $string);
$string = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $string);
// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$string = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $string);
$string = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $string);
$string = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $string);
// Remove namespaced elements (we do not need them)
$string = preg_replace('#</*\w+:\w[^>]*+>#i', '', $string);
do {
// Remove really unwanted tags
$old_data = $string;
//$string = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $string);
$string = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $string);
} while ($string !== $string);
return $string;
}
function availableLanguages() {
static $languages = [];
if ($languages != []) {
return $languages;
}
$cache = System\Cache::getInstance();
$languages = $cache->cache(APP,'languages',function () {
$languages = new Sql\LanguageSQL();
$result = $languages->getAll(['status' => 1]);
if ($result && isset($result['language'])) {
return $result['language'];
}
return [];
}, 259200);
return $languages;
}
function availableCurrencies() {
static $currencies = [];
if ($currencies != []) {
return $currencies;
}
$cache = System\Cache::getInstance();
$currencies = $cache->cache(APP,'currency',function () {
$currency = new Sql\CurrencySQL();
$result = $currency->getAll(['status' => 1]);
if ($result && isset($result['currency'])) {
return $result['currency'];
}
return [];
}, 259200);
return $currencies;
}
function installedLanguages() {
$languages = glob(DIR_ROOT . 'locale/*', GLOB_ONLYDIR);
foreach ($languages as &$language) {
$language = basename($language);
}
return $languages;
}
function userPreferedLanguages() {
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$languages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
foreach ($languages as &$language) {
$language = \Vvveb\filter('/[-\w]+/', $language);
$language = str_replace('-', '_', $language);
}
}
return $languages ?? [];
}
function userPreferedLanguage() {
$languages = userPreferedLanguages();
$installed = installedLanguages();
foreach ($languages as $language) {
if (isset($installed[$language])) {
return $language;
}
foreach ($installed as $lang) {
if (strpos($lang, $language) === 0) {
//return $language;
return $lang;
}
}
}
return false;
}
/**
* Change locale language for gettext.
*
* @param string $langCode ['en_US']
* @param string $domain ['vvveb']
*
* @return mixed
*/
function setLanguage($langCode = 'en_US', $domain = 'vvveb') {
//global $vvvebTranslationDomains;
//setlocale(LC_TIME, "");
//\putenv('LOCPATH=' . DIR_ROOT. "locale");
//translating theme text will change theme texts and break translation
if (isEditor()) {
return;
}
if (function_exists('bindtextdomain')) {
/*
foreach ($vvvebTranslationDomains as $tdomain) {
bindtextdomain($tdomain, DIR_ROOT . 'locale');
}
*/
bindtextdomain($domain, DIR_ROOT . 'locale');
textdomain($domain);
bind_textdomain_codeset($domain, 'UTF-8');
setlocale(LC_ALL,'C.UTF-8');
if (function_exists('putenv')) {
@\putenv("LC_ALL=$langCode");
@\putenv("LC_MESSAGES=$langCode");
@\putenv("LANG=$langCode");
@\putenv('LANGUAGE=' . $langCode);
}
if (defined('LC_MESSAGES')) {
setlocale(LC_MESSAGES, "$langCode.UTF-8");
setlocale(LC_CTYPE,"$langCode.UTF-8");
} else {
setlocale(5, "$langCode.UTF-8");
setlocale(6,"$langCode.UTF-8");
setlocale(LC_ALL, "$langCode.UTF-8");
}
}
}
function clearLanguageCache($langCode = 'en_US', $domain = 'vvveb') {
if (function_exists('bindtextdomain')) {
$locale = DIR_ROOT . 'locale';
$nocache = DIR_CACHE . 'nocache';
$mo = $locale . DS . $langCode . DS . 'LC_MESSAGES' . DS . "$domain.mo";
clearstatcache(false, $mo);
if (function_exists('opcache_reset')) {
opcache_invalidate($mo, true);
opcache_reset();
}
if (function_exists('symlink') && @symlink($locale, $nocache)) {
bindtextdomain($domain, $nocache);
textdomain($domain);
bind_textdomain_codeset($domain, 'different_codeset');
bindtextdomain($domain, $locale);
}
@unlink($nocache);
@rrmdir($nocache); //for windows if it copies folder instead of link
}
}
function getLanguage() {
return session('language', 'en_US');
}
function getLanguageId() {
return session('language_id', 1);
}
function getCurrency() {
return session('currency', 'USD');
}
function siteSettings($site_id = SITE_ID, $language_id = false) {
$cache = System\Cache::getInstance();
$site = $cache->cache(APP,'site.' . $site_id, function () use ($site_id) {
$siteSql = new Sql\SiteSQL();
$site = $siteSql->get(['site_id' => $site_id]);
if ($site && isset($site['settings'])) {
$settings = json_decode($site['settings'], true);
$siteData = $siteSql->getSiteData(['site' => $settings]);
foreach (['favicon', 'logo', 'logo-sticky', 'logo-dark', 'logo-dark-sticky', 'webbanner'] as $img) {
if (isset($settings[$img])) {
$settings["$img-src"] = $settings[$img];
$settings[$img] = System\Images::image($settings[$img], '');
}
}
return $settings + $siteData;
}
return [];
}, 259200);
if ($language_id && $site) {
$site['description'] = $site['description'][$language_id] ?? $site['description'][1] ?? '';
}
return $site;
}
/**
* Check php code for syntax errors, return false on errors.
*
* @param string $source
* @return bool
*/
function checkPhpSyntax($source) {
$tokens = false;
if (function_exists('token_get_all')) {
try {
$tokens = token_get_all($source, TOKEN_PARSE);
} catch (\ParseError $e) {
}
}
return $tokens ? true : false;
}
function truncateWords($text, $limit) {
return preg_replace('/((\w+\W*){' . ($limit - 1) . '}(\w+))(.*)/m', '${1}', $text);
}
/**
* Send email using template.
*
* @param string|array $to
* @param mixed $template
* @param string $subject
* @param array $data
* @param mixed $config
* @param null|mixed $app
* @return bool
*/
function email($to, $subject, $template, $data = [], $config = [], $app = null) {
$email = System\Email::getInstance();
if (is_array($template)) {
$html = $template['html'] ?? '';
$txt = $template['txt'] ?? '';
} else {
$htmlView = new System\Core\View($app);
$htmlView->setTheme();
$htmlView->set($data);
//get email html template
$htmlView->template("email/$template.html");
$html = $htmlView->render(true, false, true);
//get email text template
$txtView = new System\Core\View($app);
$txtView->setTheme();
$txtView->set($data);
$txtView->template("email/$template.txt.html");
$txt = $txtView->render(true, false, true);
$txt = htmlToText($txt);
}
//get site contact email for sender and reply to
$site = siteSettings(SITE_ID, session('language_id') ?? 1);
$sender = $config['sender'] ?? $site['description']['title'];
$from = $config['from'] ?? $site['contact-email'];
$reply = $config['reply'] ?? $site['contact-email'];
$email->setHtml($html);
$email->setText($txt);
$email->setTo($to);
$email->setSender($sender);
$email->setFrom($from);
$email->setReplyTo($reply);
$email->setSubject($subject);
return $email->send();
}
/* Recursive rmdir */
function rrmdir($src, $skip = []) {
if (! is_dir($src)) {
return false;
}
$dir = @opendir($src);
$result = false;
if ($dir) {
while (false !== ($file = readdir($dir))) {
$full = $src . DS . $file;
if (($file != '.') &&
($file != '..')/* &&
(! in_array($full, $skip))*/) {
if (is_dir($full)) {
$result = rrmdir($full);
} else {
$result = @unlink($full);
}
if (! $result) {
break;
}
}
}
closedir($dir);
return rmdir($src);
}
return result;
}
/* Recursive copy */
function rcopy($src, $dst, $skip = [], $overwrite = true) {
if ($overwrite && file_exists($dst)) {
//rrmdir($dst);
}
$result = true;
if (is_dir($src)) {
if (! file_exists($dst)) {
$result = @mkdir($dst);
if (! $result) {
return false;
}
}
@chmod($dst, 0755);
$files = scandir($src);
foreach ($files as $file) {
$full = $src . DS . $file;
if ($file != '.' &&
$file != '..' &&
! in_array($file, $skip)) {
if (is_dir($full)) {
$result = rcopy($full, $dst . DS . $file);
} else {
$result = @copy($full, $dst . DS . $file);
if (! $result) {
if (@chmod($dst . DS . $file, 0644)) {
$result = @copy($full, $dst . DS . $file);
}
}
}
if (! $result) {
return false;
}
}
}
} else {
if (file_exists($src)) {
$result = @copy($src, $dst);
if (! $result) {
if (@chmod($dst, 0644)) {
$result = copy($src, $dst);
}
}
if (! $result) {
return false;
}
}
}
return $result;
}
/* Recursive copy */
function rrename($src, $dst, $skip = []) {
if (file_exists($dst)) {
rrmdir($dst);
}
if (is_dir($src)) {
mkdir($dst);
$files = scandir($src);
foreach ($files as $file) {
if ($file != '.' &&
$file != '..' &&
! in_array($file, $skip)) {
//rrename("$src/$file", "$dst/$file");
rename("$src/$file", "$dst/$file");
}
}
} else {
if (file_exists($src)) {
rename($src, $dst);
}
}
}
function download($url) {
$result = false;
$url = html_entity_decode($url);
if (function_exists('curl_init')) {
$ch = curl_init($url);
if ($ch) {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT'] ?? 'Vvveb ' . V_VERSION);
$result = curl_exec($ch);
if (PHP_MAJOR_VERSION < 8) {
curl_close($ch);
}
}
} else {
if (ini_get('allow_url_fopen') == '1') {
$context_options = [
'http' => [
'timeout' => 5,
'ignore_errors' => 1,
],
];
$context = stream_context_create($context_options);
$result = file_get_contents($url, 'r', $context);
}
}
return $result;
}
function getUrl($url, $cache = true, $expire = 604800, $timeout = 5, $exception = true) {
$cacheDriver = System\Cache :: getInstance();
$cacheKey = md5($url);
$result = false;
if ($cache && ($result = $cacheDriver->get('url', $cacheKey))) {
return $result;
} else {
$result = false;
$url = html_entity_decode($url);
//try with curl
if (function_exists('curl_init')) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT'] ?? 'Vvveb ' . V_VERSION);
if (DEBUG) {
curl_setopt($ch, CURLOPT_VERBOSE, true);
$streamVerboseHandle = fopen('php://temp', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $streamVerboseHandle);
}
$result = curl_exec($ch);
if ($result) {
if ($cache) {
$cacheDriver->set('url', $cacheKey, $result);
}
return $result;
} else {
if ($exception) {
$message = 'Curl error: ' . curl_errno($ch) . ' - ' . curl_error($ch);
if (DEBUG) {
$message .= "\n" . print_r(curl_getinfo($ch), 1);
rewind($streamVerboseHandle);
$message .= "\n" . stream_get_contents($streamVerboseHandle);
}
throw new \Exception($message);
}
}
if (PHP_MAJOR_VERSION < 8) {
curl_close($ch);
}
} else {
//try with file get contents
if (ini_get('allow_url_fopen') == '1') {
$context_options = [
'http' => [
'timeout' => $timeout,
'ignore_errors' => 1,
],
];
$context = stream_context_create($context_options);
if ($exception) {
$result = file_get_contents($url, false, $context);
} else {
$result = @file_get_contents($url, false, $context);
}
}
if ($result) {
if ($cache) {
$cacheDriver->set('url', $cacheKey, $result);
}
return $result;
}
}
}
return $result;
}
function unzip($file) {
// get the absolute path to $file
$path = pathinfo(realpath($file), PATHINFO_DIRNAME);
$zip = new \ZipArchive();
$res = $zip->open($file);
if ($res === true) {
$zip->extractTo($path);
$zip->close();
return true;
}
return false;
}
function htmlToText($html) {
$html = preg_replace('/\s+/', ' ', $html);
$html = str_replace('<br>', "\n", $html);
//add new line for block elements
$html = preg_replace('/<(div|p|li|hr|pre|blockquote|section|h\d+)/', "\n<$1", $html);
return trim(strip_tags($html));
}
function nl2p($string) {
$paragraphs = '';
foreach (explode("\n\n", $string) as $line) {
if (trim($line)) {
$paragraphs .= "<p>$line</p>";
}
}
return $paragraphs;
}
function orderStatusBadgeClass($order_status_id = 1) {
$classes = [
1 => 'bg-primary-subtle text-body', //pending
2 => 'bg-info-subtle text-body', //processing
3 => 'bg-primary', //processed
4 => 'bg-success', //complete
5 => 'bg-danger', //canceled
6 => 'bg-secondary', //archived
7 => 'bg-warning', //requires_action
];
return $classes[$order_status_id] ?? 'bg-warning text-dark';
}
function paymentStatusBadgeClass($payment_status_id = 1) {
$classes = [
1 => 'bg-warning-subtle text-body', //not_paid
2 => 'bg-success-subtle text-body', //awaiting
3 => 'bg-danger-subtle text-body', //captured
4 => 'bg-success', //paid
5 => 'bg-danger', //canceled
6 => 'bg-danger', //refunded
7 => 'bg-danger', //partially_refunded
8 => 'bg-danger', //chargeback
9 => 'bg-danger', //requires_action
10 => 'bg-danger', //fraud
];
return $classes[$payment_status_id] ?? 'bg-warning text-dark';
}
function shippingStatusBadgeClass($shipping_status_id = 1) {
$classes = [
1 => 'bg-warning-subtle text-body', //not_fulfilled
2 => 'bg-success-subtle text-body', //fulfilled
3 => 'bg-success-subtle text-body', //partially_fulfilled
4 => 'bg-success', //shipped
5 => 'bg-success-subtle text-body', //partially_shipped
6 => 'bg-danger-subtle text-body', //returned
7 => 'bg-danger-subtle text-body', //partially_returned
8 => 'bg-success', //delivered
9 => 'bg-danger', //canceled
10 => 'bg-warning', //requires_action
];
return $classes[$shipping_status_id] ?? 'bg-warning text-dark';
}
function commentStatusBadgeClass($status = 0) {
$classes = [
0 => 'bg-primary-subtle text-body', //pending
1 => 'bg-success-subtle text-body', //approved
2 => 'bg-warning-subtle text-body', //spam
3 => 'bg-danger-subtle text-body', //trash
];
return $classes[$status] ?? 'bg-secondary-subtle text-dark';
}
function globBrace($path, $glob, $filename = '') {
//$glob = ['*','*/*','*/*/*'];
$files = [];
if (defined('GLOB_BRACE')) {
$path .= '{' . implode(',', $glob) . '}' . $filename;
$files = glob($path, GLOB_BRACE);
} else {
foreach ($glob as $pattern) {
$files = array_merge($files, glob($path . DS . $pattern . $filename));
}
}
return $files;
}
function isSecure() {
return
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| ($_SERVER['SERVER_PORT'] ?? 80) == 443;
}
function randomDigits($length) {
$result = '';
for ($i = 0; $i < $length; $i++) {
$result .= random_int(0, 9);
}
return $result;
}
function invoiceFormat($format, $data) {
if (! $format) {
return '';
}
$data += ['date_added' => time(), 'year' => date('Y'), 'year2' => date('y'), 'month_name' => date('M'), 'month' => date('m'), 'day' => date('d')];
return preg_replace_callback('/{(.+?)}/', function ($matches) use ($data) {
$key = $matches[1];
if (isset($data[$key])) {
return $data[$key];
}
if (strpos($key, 'rand-no-') !== false) {
$length = (int) str_replace('rand-no-', '', $key);
return randomDigits($length);
}
if (strpos($key, 'rand-str-') !== false) {
$length = (int) str_replace('rand-str-', '', $key);
return strtoupper(System\Functions\Str::random($length));
}
return $matches[0];
}, $format);
}
/*
remove <?xml declaration to avoid issues with php short start tag
*/
function xmlStripVersionDeclr($xmlString) {
return preg_replace('/<\?xml\s+version[^\?]+\?>\s*/', '', $xmlString ?? '');
}
function array2xml($array, $xml = false) {
if ($xml === false) {
$xml = new \SimpleXMLElement('<root/>');
}
foreach ($array as $key => $value) {
$attributes = [];
$processAttr = function (&$key) use (&$attributes) {
$i = 0;
$start = 0;
if ($key) {
while (($start = strpos($key, '@@', $start))) {
$i++;
$start += 2;
$end = (int)strpos($key,' ', $start);
$name = substr($key, $start, $end ? $end - $start : null);
if ($end == 0) {
$start += strlen($name);
} else {
$start = (int)$end;
}
if ($name) {
$name = explode('=', $name);
$attributes[$name[0]] = trim($name[1] ?? '', '\'"');
}
}
$key = strstr($key, ' @@', true) ?: $key;
}
};
$processAttr($key);
if (is_array($value) || is_object($value)) {
$node = $xml->addChild($key);
if ($attributes) {
foreach ($attributes as $key => $val) {
$node->addAttribute($key, htmlspecialchars($val));
}
}
array2xml($value, $node);
} else {
if (substr_compare($key, '--xmlattr', -9, 9) === 0) {
$key = substr($key, 0, -9);
$xml->addAttribute($key, htmlspecialchars($value));
} else {
$processAttr($value);
if ($value && is_string($value)) {
$value = htmlspecialchars($value);
}
$node = $xml->addChild($key, $value);
if ($attributes) {
foreach ($attributes as $key => $val) {
$node->addAttribute($key, $val);
}
}
}
}
}
$xmlString = $xml->asXML();
return xmlStripVersionDeclr($xmlString);
}
function removeJsonComments($json) {
$json = preg_replace('@^\s*//.*([\r\n]|\s)*|^\s*/\*([\r\n]|.)*?\*/([\r\n]|\s)*@m', '', $json);
return $json;
}
function encodeXmlName($name) {
$len = strlen($name);
$newName = '';
for ($i = 0; $i < $len; $i++) {
$char = $name[$i];
$code = ord($char);
// = @ _ - . A-Z a-z 0-9
if (! ($code == 32 || $code == 34 || $code == 61 || $code == 64 || $code == 95 || $code == 45 || $code == 46 || ($code <= 90 && $code >= 65) || ($code <= 122 && $code >= 97) || ($code <= 57 && $code >= 48))) {
$char = '_x' . sprintf('%03d', $code) . '_';
}
$newName .= $char;
}
return $newName;
}
function decodeXmlName($name) {
return preg_replace_callback('/_x(\d+)_/',function ($matches) {
return chr(ltrim($matches[1], '0'));
}, $name);
}
function prepareJson($array) {
if (! is_array($array)) {
//return;
}
$helper = [];
foreach ($array as $key => $value) {
if (is_numeric($key)) {
$key = 'n--' . $key;
}
if ($key[0] == '@') {
if ($key[1] == '@') {
$key = substr($key, 2) . '--xmlattr';
} else {
$key = substr($key, 1) . '--attr';
}
}
if (strpos($key, '@')) {
}
//keep empty arrays as array type
if (is_object($value) && ! $value) {
$key .= '--object';
} else {
if (is_array($value) && ! $value) {
$key .= '--array';
}
}
//keep boolean type
if (is_bool($value)) {
$key .= '--boolean';
}
//keep int type
if (is_int($value)) {
$key .= '--int';
}
//keep null type
if ($value === null) {
$key .= '--null';
}
$key = encodeXmlName(trim($key));
$helper[$key] = is_array($value) ? prepareJson($value) : $value;
}
return $helper;
}
function reconstructJson(&$array, $removeAttrs = false) {
if (! is_iterable($array)) {
return;
}
$helper = [];
$array = (array)$array;
foreach ($array as $key => $value) {
if ($removeAttrs && $key == '@attributes') {
continue;
}
$key = decodeXmlName($key);
if (substr_compare($key, '--array', -7, 7) === 0) {
$key = substr($key, 0, -7);
$value = (array)$value;
} else {
if (! $value) {
$value = '';
}
}
if (substr_compare($key, '--boolean', -9, 9) === 0) {
$key = substr($key, 0, -9);
$value = (bool)$value;
}
if (substr_compare($key, '--null', -6, 6) === 0) {
$key = substr($key, 0, -6);
$value = null;
}
if (substr_compare($key, '--int', -5, 5) === 0) {
$key = substr($key, 0, -5);
$value = (int)$value;
}
if (substr_compare($key, '--object', -8, 8) === 0) {
$key = substr($key, 0, -8);
$value = (object)$value;
}
if (substr_compare($key, 'n--', 0, 3) === 0) {
$newkey = substr($key, 3);
if (is_numeric($newkey)) {
$key = intval($newkey);
}
}
if (substr_compare($key, '--xmlattr', -9, 9) === 0) {
$key = '@@' . substr($key, 0, -9);
}
if (substr_compare($key, '--attr', -6, 6) === 0) {
$key = '@' . substr($key, 0, -6);
}
$helper[$key] = (is_iterable($value)) ? reconstructJson($value, $removeAttrs) : $value;
}
return $helper;
}
function fileUploadErrMessage($errorCode) {
switch ($errorCode) {
case UPLOAD_ERR_OK:
return __('No file sent');
break;
case UPLOAD_ERR_NO_FILE:
return __('No file sent');
break;
case UPLOAD_ERR_PARTIAL:
return __('The uploaded file was only partially uploaded');
break;
case UPLOAD_ERR_NO_TMP_DIR:
return __('Missing a temporary folder');
break;
case UPLOAD_ERR_CANT_WRITE:
return __('Failed to write file to disk');
break;
case UPLOAD_ERR_EXTENSION:
return __('A PHP extension stopped the file upload');
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
return __('Exceeded filesize limit');
break;
default:
return __('Unknown errors');
}
}