2371 lines
59 KiB
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;'], $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');
|
|
}
|
|
}
|