<?php

/* --------------------------------------------------------------------

  Chevereto
  https://chevereto.com/

  @author	Rodolfo Berrios A. <http://rodolfoberrios.com/>
            <inbox@rodolfoberrios.com>

  Copyright (C) Rodolfo Berrios A. All rights reserved.

  BY USING THIS SOFTWARE YOU DECLARE TO ACCEPT THE CHEVERETO EULA
  https://chevereto.com/license

  --------------------------------------------------------------------- */

namespace CHV;

use G;
use DirectoryIterator;
use Exception;
use LogicException;
use OutOfBoundsException;

use function G\unlinkIfExists;

if (!defined('access') or !access) {
    die('This file cannot be directly accessed.');
}

function getIdFromURLComponent($component)
{
    $explode = explode('.', $component);
    $encodedId = $explode[1] ?? $explode[0];

    return decodeID($encodedId);
}

// Inspired from http://stackoverflow.com/a/18602474
// L10n version of G\time_elapsed_string
function time_elapsed_string($datetime, $full = false)
{
    $now = new \DateTime(G\datetimegmt());
    $ago = new \DateTime($datetime);
    $diff = $now->diff($ago);

    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;

    $string = [
        'y' => _s('year'),
        'm' => _s('month'),
        'w' => _s('week'),
        'd' => _s('day'),
        'h' => _s('hour'),
        'i' => _s('minute'),
        's' => _s('second'),
    ];
    foreach ($string as $k => &$v) {
        if ($diff->$k) {
            $times = [
                'y' => _n('year', 'years', $diff->$k),
                'm' => _n('month', 'months', $diff->$k),
                'w' => _n('week', 'weeks', $diff->$k),
                'd' => _n('day', 'days', $diff->$k),
                'h' => _n('hour', 'hours', $diff->$k),
                'i' => _n('minute', 'minutes', $diff->$k),
                's' => _n('second', 'seconds', $diff->$k),
            ];

            $v = $diff->$k . ' ' . $times[$k];
        } else {
            unset($string[$k]);
        }
    }

    if (!$full) {
        $string = array_slice($string, 0, 1);
    }

    return count($string) > 0 ? _s('%s ago', implode(', ', $string)) : _s('moments ago');
}

function missing_values_to_exception($object, $exception, $values_array, $code = 100)
{
    if (!is_object($object)) {
        return;
    }
    for ($i = 0; $i < count((array) $values_array); ++$i) {
        if (!property_exists($object, $values_array[$i])) {
            throw new $exception('Missing $' . $values_array[$i], ($code + $i));
            break;
        }
    }
}

function system_notification_email($args = [])
{
    $subject = 'System notification: ' . $args['subject'] . ' [' . G\get_base_url() . ']';
    $report = $args['message'];
    send_mail(getSetting('email_incoming_email'), $subject, $report);
}

// Work-in-progress 2.0 baby!
function send_mail($to, $subject, $body)
{
    $own_name = __FUNCTION__ . '()';
    $args = ['to', 'subject', 'body'];
    foreach (func_get_args() as $k => $v) {
        if (!$v) {
            throw new Exception('Missing $' . $args[$k] . ' in ' . $own_name);
        }
    }

    // Bridge implementation
    if (is_array($to)) {
        $aux = $to;
        $to = $aux['to'];
        $from = $aux['from'];
        $reply_to = $aux['reply-to'];
    } else {
        $from = [getSettings()['email_from_email'], getSettings()['email_from_name']];
        $reply_to = null;
    }

    if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
        throw new Exception('Invalid email in ' . $own_name);
    }
    foreach (['email_from_email', 'email_from_name'] as $v) {
        if (!getSettings()[$v]) {
            throw new Exception('Invalid $' . $v . ' setting in ' . $own_name);
        }
    }
    $body = trim($body);
    $mail = new \Mailer();
    $alt_body = $mail->html2text($body);
    $mail->CharSet = 'UTF-8';
    $mail->Mailer = getSettings()['email_mode'];
    if ($mail->Mailer == 'smtp') {
        $mail->IsSMTP();
        $mail->SMTPAuth = true;
        $mail->SMTPSecure = getSettings()['email_smtp_server_security'];
        $mail->SMTPAutoTLS = in_array(getSettings()['email_smtp_server_security'], ['ssl', 'tls']);
        $mail->Port = getSettings()['email_smtp_server_port'];
        $mail->Host = getSettings()['email_smtp_server'];
        $mail->Username = getSettings()['email_smtp_server_username'];
        $mail->Password = getSettings()['email_smtp_server_password'];
    }
    $mail->Timeout = 30;
    $mail->Subject = $subject;
    if ($body != $alt_body) {
        $mail->IsHTML(true);
        $mail->Body = $mail->normalizeBreaks($body);
        $mail->AltBody = $mail->normalizeBreaks($alt_body);
    } else {
        $mail->Body = $body;
    }
    $mail->addAddress($to);
    if ($reply_to and is_array($reply_to)) {
        foreach ($reply_to as $v) {
            $mail->addReplyTo($v);
        }
    }
    $mail->setFrom($from[0], $from[1]);
    if ($mail->Send()) {
        return true;
    } else {
        throw new Exception($mail->DbgOut, 300);
    }
}

/**
 * GET AND FETCH SOME DATA
 * ----------------------------------------------------------------------------------------------------------------------------------------.
 */
function get_chevereto_version($full = true)
{
    return G\get_app_version($full);
}

// Move to render?
function getSettings($safe = false)
{
    $settings = Settings::get();

    return $safe ? G\safe_html($settings) : $settings;
}
// Move to render?
function get_chv_default_settings($safe = false)
{
    $defaults = Settings::getDefaults();

    return $safe ? G\safe_html($defaults) : $defaults;
}
// Move to render?
function getSetting($key = '', $safe = false)
{
    $return = Settings::get($key);

    return $safe ? G\safe_html($return) : $return;
}
// Move to render?
function get_chv_default_setting($value = '', $safe = false)
{
    $return = get_chv_default_settings()[$value];

    return $safe ? G\safe_html($return) : $return;
}

function getStorages()
{
    $storages = DB::get('storages', 'all');
    if ($storages) {
        foreach ($storages as $k => $v) {
            $storages[$k] = DB::formatRow($v);
        }
        $return = $storages;
    } else {
        $return = false;
    }

    return $return;
}

function get_banner_code($banner, $safe_html = true)
{
    if (strpos($banner, 'banner_') !== 0) {
        $banner = 'banner_' . $banner;
    }
    $banner_code = Settings::get($banner);
    if ($safe_html) {
        $banner_code = G\safe_html($banner_code);
    }
    if ($banner_code) {
        return $banner_code;
    }
}

function getSystemNotices()
{
    $system_notices = [];
    if (version_compare(G_APP_VERSION, getSetting('chevereto_version_installed'), '>')) {
        $system_notices[] = _s('System database is outdated. You need to run the <a href="%s">update</a> tool.', G\get_base_url('install'));
    }
    if (getSetting('maintenance')) {
        $system_notices[] = _s('Website is in maintenance mode. To revert this setting go to <a href="%s">Dashboard > Settings</a>.', G\get_base_url('dashboard/settings/system'));
    }
    if (!in_array($_SERVER['SERVER_ADDR'], ['127.0.0.1', '::1'])) {
        if (getSetting('error_reporting')) {
            $system_notices[] = _s("You should disable PHP error reporting for production enviroment. Go to <a href='%s'>System settings</a> to revert this setting.", G\get_base_url('dashboard/settings/system'));
        }
        if (preg_match('/@chevereto\.loc/', getSetting('email_from_email')) || preg_match('/@chevereto\.loc/', getSetting('email_incoming_email'))) {
            $system_notices[] = _s("You haven't changed the default email settings. Go to <a href='%s'>Email settings</a> to fix this.", G\get_base_url('dashboard/settings/email'));
        }
    }

    return $system_notices;
}

function hashed_token_info($public_token_format)
{
    $explode = explode(':', $public_token_format);

    return array(
        'id' => decodeID($explode[0]),
        'id_encoded' => $explode[0],
        'token' => $explode[1],
    );
}

function generate_hashed_token($id, $token = '')
{
    $token = G\random_string(rand(128, 256));
    $hash = password_hash($token, PASSWORD_BCRYPT);

    return array(
        'token' => $token,
        'hash' => $hash,
        'public_token_format' => encodeID($id) . ':' . $token,
    );
}

function check_hashed_token($hash, $public_token_format)
{
    $public_token = hashed_token_info($public_token_format);

    return password_verify($public_token['token'], $hash);
}

function recaptcha_check()
{
    // V3 aka "Invisible recaptcha"
    if (getSetting('recaptcha_version') == 3) {
        return (object) ['is_valid' => (bool) $_SESSION['isHuman']];
    }
    // V1-V2 aka "Challenge recaptcha"
    $endpoint = 'https://www.recaptcha.net/recaptcha/api/siteverify';
    $params = [
        'secret' => getSetting('recaptcha_private_key'),
        'response' => $_POST['g-recaptcha-response'],
        'remoteip' => G\get_client_ip(),
    ];
    $endpoint .= '?' . http_build_query($params);
    $re_api = json_decode(G\fetch_url($endpoint));
    // Mimic old reCaptcha API return
    return (object) ['is_valid' => (bool) $re_api->success];
}

function must_use_recaptcha($val, $max = '')
{
    if ($max == '' || !is_int($max)) {
        $db_max = getSetting('recaptcha_threshold');
        $max = $db_max ?? 5;
    }

    return $val >= $max;
}

function is_max_invalid_request($val, $max = '')
{
    if ($max == '' || !is_int($max)) {
        $max = CHV_MAX_INVALID_REQUESTS_PER_DAY;
    }

    return $val > $max;
}

// BCMath workaroud
if (!function_exists('bcdiv')) {
    function bcdiv($dividend, $divisor)
    {
        $quotient = floor($dividend / $divisor);

        return $quotient;
    }
    function bcmod($dividend, $modulo)
    {
        $remainder = $dividend % $modulo;

        return $remainder;
    }
    function bcmul($left, $right)
    {
        return $left * $right;
    }
    function bcadd($left, $right)
    {
        return $left + $right;
    }
    function bcpow($base, $power)
    {
        return pow($base, $power);
    }
}

/**
 * LANGUAGE
 * ----------------------------------------------------------------------------------------------------------------------------------------.
 */
function get_translation_table()
{
    return L10n::getTranslation();
}

function get_language_used()
{
    return get_available_languages()[L10n::getStatic('locale')];
}

function get_available_languages()
{
    return L10n::getAvailableLanguages();
}

function get_enabled_languages()
{
    if (!getSetting('language_chooser_enable')) {
        return [];
    }

    return L10n::getEnabledLanguages();
}

function get_disabled_languages()
{
    return L10n::getDisabledLanguages();
}

/**
 * CRYPT
 * ----------------------------------------------------------------------------------------------------------------------------------------.
 */

/*
 * cheveretoID
 * Encode/decode an id
 *
 * @author   Kevin van Zonneveld <kevin@vanzonneveld.net>
 * @author   Simon Franz
 * @author   Deadfish
 * @copyright 2008 Kevin van Zonneveld (http://kevin.vanzonneveld.net)
 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD Licence
 * @version   SVN: Release: $Id: alphaID.inc.php 344 2009-06-10 17:43:59Z kevin $
 * @link   http://kevin.vanzonneveld.net/
 *
 * http://kvz.io/blog/2009/06/10/create-short-ids-with-php-like-youtube-or-tinyurl/
 *
 */

function cheveretoID($in, $action = 'encode')
{
    global $cheveretoID;
    $index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $salt = getSetting('crypt_salt');
    $id_padding = intval(getSetting('id_padding'));

    // Use a stock version of the hashed values (faster execution)
    if (isset($cheveretoID)) {
        $passhash = $cheveretoID['passhash'];
        $p = $cheveretoID['p'];
        $i = $cheveretoID['i'];
    } else {
        for ($n = 0; $n < strlen($index); ++$n) {
            $i[] = substr($index, $n, 1);
        }

        $passhash = hash('sha256', $salt);
        $passhash = (strlen($passhash) < strlen($index)) ? hash('sha512', $salt) : $passhash;

        for ($n = 0; $n < strlen($index); ++$n) {
            $p[] = substr($passhash, $n, 1);
        }

        // Stock the crypting thing to don't do it every time
        $cheveretoID = [
            'passhash' => $passhash,
            'p' => $p,
            'i' => $i,
        ];
    }

    array_multisort($p, SORT_DESC, $i);
    $index = implode($i);

    $base = strlen($index);

    if ($action == 'decode') {
        // Digital number  <<--  alphabet letter code
        $out = 0;
        $len = strlen($in) - 1;
        for ($t = 0; $t <= $len; ++$t) {
            $bcpow = bcpow($base, $len - $t);
            $out = $out + strpos($index, substr($in, $t, 1)) * $bcpow;
        }
        if ($id_padding > 0) {
            $out = $out / $id_padding;
        }
        $out = sprintf('%s', $out);
    } else {
        // Digital number  -->>  alphabet letter code
        if ($id_padding > 0) {
            $in = $in * $id_padding;
        }
        $out = '';
        for ($t = floor(log((float) $in, $base)); $t >= 0; --$t) {
            $bcp = bcpow($base, $t);
            $a = floor($in / $bcp) % $base;
            $out = $out . substr($index, $a, 1);
            $in = $in - ($a * $bcp);
        }
    }

    return $out;
}

// Shorthand for cheveretoID encode
function encodeID($var)
{
    return cheveretoID($var, 'encode');
}

// Shorthand for cheveretoID decode
function decodeID($var)
{
    return cheveretoID($var, 'decode');
}

// Linkify stuff to the internal redirector
function linkify_redirector($text)
{
    return G\linkify_safe($text, ['callback' => function ($url, $caption, $options) {
        return '<a href="' . get_redirect_url($url) . '" ' . $options['attr'] . '>' . $caption . '</a>';
    }]);
}

function get_redirect_url($url)
{
    return G\get_base_url('redirect/?to=' . urlencode(encryptString($url)) . '&auth_token=' . G\Handler::getAuthToken());
}

// This is used for encrypt strings
function sessionCrypt($string, $encrypt = true)
{
    if (($_SESSION['crypt'] ?? null) == false) {
        $cipher = 'AES-128-CBC';
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $_SESSION['crypt'] = [
            'cipher' => $cipher,
            'ivlen' => $ivlen,
            'iv' => $iv,
        ];
    }
    extract($_SESSION['crypt'] ?? []);
    $fn = 'openssl_' . ($encrypt ? 'encrypt' : 'decrypt');
    $secret = md5(getSetting('crypt_salt'));

    return $fn($string, $cipher, $secret, 0, $iv);
}

function encryptString($string)
{
    return sessionCrypt($string, true);
}

function decryptString($string)
{
    return sessionCrypt($string, false);
}

/**
 * Get some URLs.
 */
function get_content_url($sub)
{
    $dirname = dirname($sub);
    $local = CHV_ROOT_URL_STATIC;
    $url = AssetStorage::getStorage()['url'] ?? $local;
    if(basename($dirname) == 'default') {
        $url = $local;
    }
    return G\absolute_to_url(CHV_PATH_CONTENT . $sub, $url);
}

function get_system_image_url($filename)
{
    return get_content_url('images/system/' . $filename);
}

function get_users_image_url($filename)
{
    return get_content_url('images/users/' . $filename);
}

function get_image_fileinfo($file)
{
    $extension = G\get_file_extension($file);
    $return = [
        'filename' => basename($file), // image.jpg
        'name' => basename($file, '.' . $extension), // image
        'mime' => G\extension_to_mime($extension),
        'extension' => $extension,
        'url' => G\is_url($file) ? $file : G\absolute_to_url($file),
    ];
    if (!G\is_url($file) && defined('CHV_ROOT_URL_STATIC')) {
        $return['url'] = preg_replace('#' . G_ROOT_URL . '#', CHV_ROOT_URL_STATIC, $return['url'], 1);
    }

    return $return;
}

function upload_to_content_images($source, $what)
{
    $remove_old = true;
    $localPath = CHV_PATH_CONTENT_IMAGES_SYSTEM;
    $storagePath = ltrim(G\absolute_to_relative($localPath), '/');
    $typeArr = [
        'favicon_image' => [
            'name' => 'favicon',
            'type' => 'image',
        ],
        'logo_vector' => [
            'name' => 'logo',
            'type' => 'file',
        ],
        'logo_image' => [
            'name' => 'logo',
            'type' => 'image',
        ],
        'watermark_image' => [
            'name' => 'watermark',
            'type' => 'image',
        ],
        'consent_screen_cover_image' => [
            'name' => 'consent-screen_cover',
            'type' => 'image',
        ],
        'homepage_cover_image' => [
            'name' => 'home_cover',
            'type' => 'image',
        ],
    ];
    if(!isset($typeArr[$what]) && !G\starts_with('homepage_cover_image_', $what)) {
        throw new OutOfBoundsException(sprintf('Invalid key %s', $what));
    }
    if (G\starts_with('homepage_cover_image_', $what)) {
        $cover_handle = str_replace('homepage_cover_image_', '', $what);
        if ($cover_handle == 'add') {
            $remove_old = false;
        } else {
            $db_filename = getSetting('homepage_cover_images')[$cover_handle]['basename'];
        }
        $typeArr[$what] = $typeArr['homepage_cover_image'];
    }
    foreach (['logo_vector', 'logo_image'] as $k) {
        $typeArr[$k . '_homepage'] = array_merge($typeArr[$k], ['name' => 'logo_homepage']);
    }
    foreach ($typeArr as $k => &$v) {
        $v['name'] .= '_' . number_format(round(microtime(true) * 1000), 0, '', '') . '_' . G\random_string(6);
    }
    $name = $typeArr[$what]['name'];
    if ($typeArr[$what]['type'] == 'image') {
        $fileinfo = @G\get_image_fileinfo($source['tmp_name']);
        switch ($what) {
            case 'favicon_image':
                if (!$fileinfo['ratio']) {
                    throw new Exception('Invalid favicon image.', 200);
                }
                if ($fileinfo['ratio'] != 1) {
                    throw new Exception('You need to use a square image for the favicon.', 210);
                }
                break;
            case 'watermark_image':
                if ($fileinfo['extension'] !== 'png') {
                    throw new Exception('Invalid watermark image.', 200);
                }
                break;
        }
        $upload = new Upload();
        $upload->setSource($source);
        $upload->setDestination($localPath);
        $upload->setFilename($name);
        if (in_array($what, ['homepage_cover_image_add', 'homepage_cover_image', 'consent_screen_cover_image'])) {
            $upload->setOption('max_size', Settings::get('true_upload_max_filesize'));
        }
        if($what !== 'watermark_image') {
            $upload->setStorageId(0);
        }
        $upload->exec();
        $uploaded = $upload->uploaded;
    } else {
        switch ($source['error']) {
            case UPLOAD_ERR_OK:
                break;
            case UPLOAD_ERR_NO_FILE:
                throw new Exception('No file sent.', 500);
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                throw new Exception('Exceeded filesize limit.', 501);
            default:
                throw new Exception('Unknown errors.', 502);
        }
        $file_contents = @file_get_contents($source['tmp_name']);
        if (!$file_contents) {
            throw new Exception("Can't read uploaded file content.", 500);
        }
        if (strpos($file_contents, '<!DOCTYPE svg PUBLIC') === false and strpos($file_contents, '<svg') === false) {
            throw new Exception("Uploaded file isn't an SVG.", 300);
        }
        $filename = $name . G\random_string(8) . '.svg';
        $uploaded = [
            'file' => $source['tmp_name'],
            'filename' => $filename,
            'fileinfo' => [
                'extension' => 'svg',
                'filename' => $filename,
                'mime' => 'image/svg+xml',
            ],
        ];
    }
    $filename = $name . '.' . $uploaded['fileinfo']['extension'];
    $toStorage = [
        [
            'file' => $uploaded['file'],
            'filename' => $filename,
            'mime' => $uploaded['fileinfo']['mime'],
        ]
    ];
    Storage::uploadFiles($toStorage, AssetStorage::getStorage(), [
        'keyprefix' => $storagePath
    ]);
    if (!isset($db_filename) || empty($db_filename)) {
        $db_filename = getSetting($what);
    }
    if ($remove_old) {
        if($what === 'watermark_image') {
            unlinkIfExists(CHV_PATH_CONTENT_IMAGES_SYSTEM . $db_filename);
        } else {
            Storage::deleteFiles($storagePath . $db_filename, AssetStorage::getStorage());
        }
    }
    if (isset($cover_handle)) {
        $what = 'homepage_cover_image';
        $homepage_cover_image = getSetting($what);
        if ($cover_handle == 'add') {
            $filename = (isset($homepage_cover_image) ? $homepage_cover_image : getSetting('homepage_cover_images')[0]['basename']) . ',' . $filename;
        } else {
            $filename = isset($homepage_cover_image) ? str_replace($db_filename, $filename, getSetting('homepage_cover_image')) : $filename;
        }
        $filename = trim($filename, ',');
        $homecovers = [];
        foreach (explode(',', $filename) as $v) {
            $homecovers[] = [
                'basename' => $v,
                'url' => get_system_image_url($v),
            ];
        }
    }
    Settings::update([$what => $filename]);
    if (isset($cover_handle)) {
        Settings::setValue('homepage_cover_images', $homecovers);
    }
    if($what === 'watermark_image') {
        $fp = fopen($uploaded['file'], 'rb');
        $assetsDb = DB::get('assets', ['key' => $what]);
        $dbArray = [
            'md5' => md5_file($uploaded['file']),
            'filename' => $filename,
            'file_path' => $storagePath,
            'blob' => $fp,
        ];
        if(empty($assetsDb)) {
            $dbArray['key'] = $what;
            DB::insert('assets', $dbArray);
        } else {
            DB::update('assets', $dbArray, ['key' => $what]);
        }
    }
    if(!AssetStorage::isLocalLegacy()) {
        unlinkIfExists($uploaded['file']);
    }

}

function isSafeToExecute($max_execution_time = null, $options = [])
{
    if (is_null($max_execution_time)) {
        $max_execution_time = ini_get('max_execution_time');
    }
    if ($max_execution_time == 0) {
        return true;
    }
    $executed_time = microtime(true) - G_APP_TIME_EXECUTION_START;
    $options = array_merge(['safe_time' => 5], $options);
    if (($max_execution_time - $executed_time) > $options['safe_time']) {
        return true;
    }

    return false;
}

/* Update ping */
function checkUpdates()
{
    $CHEVERETO = Settings::getChevereto();
    $update = G\fetch_url($CHEVERETO['api']['get']['info']);
    if (isSafeToExecute() && $update) {
        $json = json_decode($update);
        $release_notes = $json->software->release_notes;
        $pos = strpos($release_notes, 'Affected files and folders');
        $release_notes = trim(substr($release_notes, 0, $pos));
        $latest_release = $json->software->current_version;
        // Notify only if not notified OR if latest release is newer and not being notified AND is not installed (files)
        if (is_null(getSetting('update_check_notified_release')) || (version_compare($latest_release, G_APP_VERSION, '>') && version_compare($latest_release, getSetting('update_check_notified_release'), '>'))) {
            // Email notify
            $message = _s('There is an update available for your Chevereto based website.') . ' ' . _s('The release notes for this update are:');
            $message .= "\n\n";
            $firstBreak = strpos($release_notes, "\n");
            $release_notes = '<b>' . rtrim(substr($release_notes, 0, $firstBreak)) . '</b>' . substr($release_notes, $firstBreak);
            $message .= $release_notes . "\n\n";
            $message .= _s('You can apply this update directly from your %a or download it from %s and then manually install it.', ['%a' => '<a href="' . G\get_base_url('dashboard?checkUpdates') . '" target="_blank">' . _s('admin dashboard') . '</a>', '%s' => '<a href="' . $CHEVERETO['source']['url'] . '" target="_blank">' . $CHEVERETO['source']['label'] . '</a>']) . "\n\n";
            $message .= '--' . "\n" . 'Chevereto' . "\n" . G\get_base_url();
            $message = nl2br($message);
            system_notification_email(['subject' => sprintf('Chevereto update available (v%s)', $latest_release), $latest_release, 'message' => $message]);
            $settings_update = [
                'update_check_notified_release' => $latest_release,
                'update_check_datetimegmt' => G\datetimegmt(),
                'update_check_latest_release' => $latest_release,
            ];
        } else {
            $settings_update = ['update_check_datetimegmt' => G\datetimegmt()];
        }
        Settings::update($settings_update);
    }
}

function getJsModLangL10n()
{
    foreach (new DirectoryIterator(CHV_APP_PATH_CONTENT_LANGUAGES . 'cache/') as $fileInfo) {
        if ($fileInfo->isDot() || $fileInfo->isDir()) {
            continue;
        }
        $lang_code = str_replace('.po.cache.php', null, $fileInfo->getFilename());
        include $fileInfo->getPathname();
        if (!$translation_table['Upload images']) {
            continue;
        }
        $l10n[$lang_code] = $translation_table['Upload images'][0];
    }
    unset($translation_table);

    return json_encode($l10n);
}

function obfuscate($string)
{
    $len = strlen($string);
    $return = '';
    for ($i = 0; $i < $len; ++$i) {
        $return .= '&#' . ord($string[$i]) . ';';
    }

    return $return;
}

function get_base_url_wildcard($path = '', $subdomain = null)
{
    if ($subdomain == null && defined('CHV_HOST_WILDCARD')) {
        $subdomain = CHV_HOST_WILDCARD;
    }
    if ($subdomain) {
        return G\str_replace_first(CHV_HTTP_HOST, $subdomain . '.' . CHV_HTTP_HOST, G\get_base_url($path));
    }

    return G\get_base_url($path);
}

function get_current_url_wildcard($subdomain, $qsremove = [])
{
    return G\str_replace_first(CHV_HTTP_HOST, $subdomain . '.' . CHV_HTTP_HOST, G\get_current_url(true, $qsremove));
}
/**
 * Sub-domain aware version.
 */
function get_current_url($safe = true, $removeQs = [])
{
    $url = G\get_current_url($safe, $removeQs);

    return G\str_replace_first(G\get_base_url(), get_base_url_wildcard(), $url);
}

function isShowEmbedContent()
{
    switch (getSetting('theme_show_embed_content_for')) {
        case 'none':
            $showEmbed = false;
        break;
        case 'users':
            $showEmbed = Login::isLoggedUser();
        break;
        default:
            $showEmbed = true;
        break;
    }

    return $showEmbed;
}
