<?php

/*
 * @name        JMY CMS
 * @link        https://jmy.su/
 * @copyright   Copyright (C) 2012-2025 JMY LTD
 * @license     LICENSE.txt (see attached file)
 * @version     VERSION.txt (see attached file)
 * @author      Komarov Ivan
 * @edited      Orlov Alexsey
 */

if (!defined('ACCESS')) {
    header('Location: /');
    exit;
}

class core
{
    public $tpl;
    public $db;
    public $parse;
    public $isAdmin;
    public array $langsLang = array('ru' => 'Русский', 'en' => 'English');
    public array $deniedHTML = array('#</?(script|javascript|iframe|meta|body|form)[^>]*>#si' => '',    /*'#<img.*?src=("|\')?() #si' => '', */
        '#(javascript|onmouseover|expression)#si' => '',);
    public $module;
    public $initModule;
    public $ban = false;
    public $banReason = '';
    public $isIndex = INDEX;
    public $modArray = array();
    public $lang = '';
    public $tempModule = '';
    public $loadedLangs = array();
    public $cacheContent = array();
    var $htmlArr = array();
    public $catArray = '';
    public $aCatArray = '';
    public $html_editor = 0;
    private $urlSeparator = '/';
    private $urlEnd = '.html';

    function __construct()
    {
        $this->InitLang();
    }

    function InitLang()
    {
        global $url, $config;
        return $this->lang = $config['lang'];
        if ((isset($url[0]) && $url[0] != ADMIN) or !isset($url[0])) {
            if (empty($this->lang)) {
                if (!empty($_COOKIE['lang'])) {
                    $this->lang = filter($_COOKIE['lang'], 'a');
                } elseif (isset($config['lang'])) {
                    $this->lang = $config['lang'];
                } else {
                    $this->lang = 'ru';
                }
            }
            return $this->lang;
        } else {
            return $this->lang = $config['lang'];
        }
    }

    function initCore(): void
    {
        $this->auth = new auth();
        $this->tpl = new template();
        $this->buildUrls();
        $this->urlLang();
        global $url;
        if (isset($url[0]) && $url[0] == ADMIN) {
            global $admin_conf;
            $this->html_editor = $admin_conf['htmlEditor'];
        }
    }

    function buildUrls(): void
    {
        global $config;
        unset($GLOBALS['url']);
        $GLOBALS['url'] = array();
        if (!empty($_GET['url'])) {
            $getLink = $_GET['url'];
        } else {
            $getLink = $config['mainModule'];
            define('INDEX_NOW', true);
        }
        $tempLink = explode($this->urlSeparator, $getLink);
        for ($i = 0, $max = count($tempLink); $i < $max; $i++) {
            if ($tempLink[$i] == '') {
                continue;
            } else {
                $GLOBALS['url'][] = escape($tempLink[$i]);
            }
        }
    }

    function urlLang()
    {
        global $url, $config;
        if (isset($this->langsLang[$url[0]])) {
            $this->setLang($url[0]);
            $l = $url[0];
            unset($url[0]);
            if (count($url) == 0) $url[0] = $config['mainModule'];
            foreach ($url as $path) {
                $s[] = $path;
            }
            unset($url);
            $GLOBALS['url'] = $s;
            setcookie('lang', $l, time() + 86400, '/');
        }
    }

    function LoadLang($module = true, $system = false, $admin = false): void
    {
        global $url, $lang, $config;
        $language = $this->lang ?? $config['lang'];
        $modules = $module ? '/modules/' . ($url[2] ?? $url[0]) . '/' : '/';
        $langdir = $language . $modules . $language;
        if ($module && !$admin || $system) {
            if (file_exists(ROOT . 'langs/' . $langdir . '.site.lng')) include(ROOT . 'langs/' . $langdir . '.site.lng');
            if (file_exists(ROOT . 'langs/' . $langdir . '.tpl.lng')) include(ROOT . 'langs/' . $langdir . '.tpl.lng');
        } elseif ($admin && !$module) {
            if (file_exists(ROOT . 'langs/' . $langdir . '.admin.lng')) include(ROOT . 'langs/' . $langdir . '.admin.lng');
            if (file_exists(ROOT . 'langs/' . $langdir . '.config.lng')) include(ROOT . 'langs/' . $langdir . '.config.lng');
        } elseif ($module && $admin) {
            if (isset($url[1]) && $url[1] == 'module' && isset($url[2])) {
                if (file_exists(ROOT . 'langs/' . $langdir . '.admin.lng')) include(ROOT . 'langs/' . $langdir . '.admin.lng');
                if (file_exists(ROOT . 'langs/' . $langdir . '.config.lng')) include(ROOT . 'langs/' . $langdir . '.config.lng');
            }
        } else {
            fatal_error('Language file not found', false);
        }
    }

    function loadLangFile($str): void
    {
        global $lang;
        $url = str_replace('{lang}', $this->lang, $str);
        if (file_exists(ROOT . $url)) {
            require_once(ROOT . $url);
        } else {
            if (file_exists(ROOT . str_replace('{lang}', 'ru', $str))) require_once(ROOT . str_replace('{lang}', 'ru', $str));
        }
    }

    function loadModLang($mod): void
    {
        global $lang;
        if (!isset($this->loadedLangs[$mod]) && file_exists(ROOT . 'langs/' . $this->lang . '/modules/' . $mod . '/' . $this->lang . '.site.lng')) {
            $this->loadedLangs[$mod] = true;
            require_once(ROOT . 'langs/' . $this->lang . '/modules/' . $mod . '/' . $this->lang . '.site.lng');
        } else {
            fatal_error('Language file not found', false);
        }
    }

    function loadModLangADM($mod): void
    {
        global $lang;
        if (!isset($this->loadedLangs[$mod]) && file_exists(ROOT . 'langs/' . $this->lang . '/modules/' . $mod . '/' . $this->lang . '.admin.lng')) {
            $this->loadedLangs[$mod] = true;
            require_once(ROOT . 'langs/' . $this->lang . '/modules/' . $mod . '/' . $this->lang . '.admin.lng');
        } else {
            fatal_error('Language file not found', false);
        }
    }

    function loadblockLang($block): void
    {
        global $lang;
        if (file_exists(ROOT . 'langs/' . $this->lang . '/blocks/' . $this->lang . '.' . $block . '.lng')) {
            $this->loadedLangs[$block] = true;
            require_once(ROOT . 'langs/' . $this->lang . '/blocks/' . $this->lang . '.' . $block . '.lng');
        } else {
            fatal_error('Language file not found', false);
        }
    }

    function getLang($const)
    {
        return constant($const);
    }

    function setLang($lang): void
    {
        $this->lang = $lang;
    }

    function getLangList($force = false): array
    {
        if (!$force) {
            foreach (scandir(ROOT . 'usr/langs') as $k => $v) {
                if (eregStrt('' . $this->lang . '.site.lng', $v)) {
                    $l = str_replace($this->lang . '.site.lng', '', $v);
                    $lang[] = array($l, $this->langsLang[$l]);
                }
            }
        } else {
            foreach ($this->langsLang as $key => $val) {
                $lang[] = array($key, $val);
            }
        }
        return $lang;
    }

    function getModList()
    {
        if (empty($this->modArray)) {
            foreach (glob(ROOT . 'usr/modules/*/index.php') as $dir) {
                $dir_arr = explode('/', $dir);
                $this->modArray[] = $dir_arr[count($dir_arr) - 2];
            }
        }
        return $this->modArray;
    }

    function fullURL(): string
    {
        global $url, $config;
        return $config['url'] . (!empty($url[0]) ? '/' . $url[0] : '') . (!empty($url[1]) ? '/' . $url[1] : '') . (!empty($url[2]) ? '/' . $url[2] : '') . (!empty($url[3]) ? '/' . $url[3] : '') . (!empty($url[4]) ? '/' . $url[4] : '') . (!empty($url[5]) ? '/' . $url[5] : '') . (!empty($url[6]) ? '/' . $url[6] : '') . (!empty($url[7]) ? '/' . $url[7] : '') . (!empty($url[8]) ? '/' . $url[8] : '') . (!empty($url[9]) ? '/' . $url[9] : '') . (!empty($url[10]) ? '/' . $url[10] : '');
    }

    function checkModule($name = '')
    {
        global $core;
        $module = $core->row_data('plugins', 'title = "' . $name . '"');
        return isset($module) ? $module['active'] : false;
    }

    function row_data($module = '', $where = false, $order_stat = false, $select = false, $as = false)
    {
        global $db;
        $module = $db->safesql($module);
        $where = str_replace(array('WHERE'), array(''), $where);
        $where = $where ? ' WHERE ' . $where : '';
        $where = str_replace(array('AND'), array(' AND'), $where);
        $ord_stat = str_replace(array('ORDER BY'), array(''), $order_stat);
        $order = $order_stat ? 'ORDER BY ' . $ord_stat : '';
        $order = str_replace(array('ORDER BY'), array(' ORDER BY'), $order);
        $select = $select ?: '*';
        $as = $as ? ' ' . $as : '';
        $query = $db->query("SELECT " . $select . " FROM " . DB_PREFIX . "_" . $module . $as . $where . $order);
        if ($db->numRows($query) > 0) return $db->getRow($query);
    }

    function isOnline($uid = ''): bool
    {
        global $core, $db;
        $query = $core->select_data('online', 'uid = "' . $uid . '"');
        return $db->numRows($query) > 0;
    }

    function select_data($module = '', $where = false, $order_stat = false, $select = false, $as = false, $order_group = false)
    {
        global $db;
        $module = $db->safesql($module);
        if (isset($where)) $where = str_replace(array('WHERE'), array(''), $where);
        $where = $where ? ' WHERE ' . $where : '';
        $where = str_replace(array('AND'), array(' AND'), $where);
        $ord_stat = str_replace(array('ORDER BY'), array(''), $order_stat);
        $order = $order_stat ? ' ORDER BY ' . $ord_stat : '';
        $order = str_replace(array(' ORDER BY '), array(' ORDER BY '), $order);
        $order = $order_group ?: $order;
        $select = $select ?: '*';
        $as = $as ? ' ' . $as : '';
        return $db->query("SELECT " . $select . " FROM " . DB_PREFIX . "_" . $module . $as . $where . $order);
    }

    function isOffline($uid = ''): bool
    {
        global $core, $db;
        $query = $core->select_data('online', 'uid = "' . $uid . '"');
        return $db->numRows($query) == 0;
    }

    function con_check($method, $post = false, $dop = false, $Url = false)
    {
        global $url, $lang;
        $method = $method == 'i' ? 'intval' : ($method == 'f' ? 'filter' : $lang['error']);
        $dop = $dop ? ',' . $dop : '';
        return $post ? $method($_POST[$post] . $dop) : $method($url[$Url]);
    }

    function fetch_data($module = '', $where = false, $select = false, $as = false)
    {
        global $db;
        $module = $db->safesql($module);
        if (isset($where)) $where = str_replace(array('WHERE'), array(''), $where);
        $where = $where ? ' WHERE ' . $where : '';
        $where = str_replace(array('AND'), array(' AND'), $where);
        $select = $select ?: 'id';
        $as = $as ? ' ' . $as : '';
        return $db->fetchRow($db->query("SELECT " . $select . " FROM " . DB_PREFIX . "_" . $module . $as . $where));
    }

    function ins_data($module = '', $column = '', $values = '', $dop = false)
    {
        global $db;
        $module = $db->safesql($module);
        $column = $column ? implode(',', array_map(function ($str) {
            return "`$str`";
        }, explode(',', $column))) : '';
        $dop = $dop ?: '';
        $column = $column ? "(" . $column . ")" : '';
        return $db->query("INSERT " . $dop . " INTO " . DB_PREFIX . "_" . $module . $column . " VALUES (" . $values . ")");
    }

    function upd_data($module = '', $set = '', $where = false, $limit = 'LIMIT 1;')
    {
        global $db;
        $module = $db->safesql($module);
        if (isset($where)) $where = str_replace(array('WHERE'), array(''), $where);
        $set = $set ? ' SET ' . $set : '';
        $limit = $limit ?: '';
        $limit = $limit <> 'LIMIT 1;' ? ' LIMIT ' . $limit . ';' : ' LIMIT 1;';
        $where = $where ? ' WHERE ' . $where : '';
        $where = str_replace(array('AND'), array(' AND'), $where);
        return $db->query("UPDATE " . DB_PREFIX . "_" . $module . $set . $where . $limit);
    }

    function truncate_data($module = '')
    {
        global $db;
        $module = $db->safesql($module);
        return $db->query("TRUNCATE TABLE " . DB_PREFIX . "_" . $module);
    }

    function ereg_Strt($module = ''): bool
    {
        global $db;
        $module = $db->safesql($module);
        return (bool)eregStrt(DB_PREFIX, DB_PREFIX . "_" . $module);
    }

    function header_title($set_title): string
    {
        global $config;
        $set_title = $set_title ? implode($config['divider'], array_map(function ($str) {
            return "$str";
        }, explode(',', $set_title))) : '';
        set_title(array($set_title));
        return $set_title;
    }

    function del_data($module = '', $where = false)
    {
        global $db;
        $module = $db->safesql($module);
        if (isset($where)) $where = str_replace(array('WHERE'), array(''), $where);
        $where = $where ? ' WHERE ' . $where : '';
        $where = str_replace(array('AND'), array(' AND'), $where);
        return $db->query("DELETE FROM " . DB_PREFIX . "_" . $module . $where);
    }

    function ins_log($title = '', $text = '', $status = '1', $replace = false, $name = false, $tname = false, $choice = false)
    {
        global $db, $core;
        $sname = $name ? '[' . $name . ']' : '[name]';
        $tname = $tname ?: $tname;
        $snick = $choice ? '[' . $choice . ']' : '[nick]';
        $tnick = $title ?: $core->auth->user_info['nick'];
        return $replace ? $db->query("REPLACE INTO " . DB_PREFIX . "_logs VALUES (NULL,'" . time() . "', '" . filter($_SERVER['REMOTE_ADDR']) . "', '" . $core->auth->user_id . "', '" . sess_count() . "','" . str_replace(array($snick, $sname), array($tnick, $tname), $text) . "', $status)") : $db->query("INSERT INTO " . DB_PREFIX . "_logs VALUES (NULL,'" . time() . "', '" . filter($_SERVER['REMOTE_ADDR']) . "', '" . $core->auth->user_id . "', '" . sess_count() . "','" . str_replace(array($snick, $sname), array($tnick, $tname), $text) . "', $status)");
    }

    /*
      * Вывод лимит страниц
  */
    function site_limit_page($mod_conf, $mod_num = false, $pages = true): false|string
    {
        global $mod_conf, $page;
        $page = init_page();
        $cut = $pages ? (($page - 1) * $mod_num) . ', ' : false;
        return $mod_num ? $cut . $mod_num : false;
    }

    /*
    * Вывод навигации страниц
*/
    function site_page_list($module, $dbaze, $where = false, $numb = false): void
    {
        global $core;
        $page = init_page();
        $where = $where ? ' WHERE ' . $where : '';
        $where = str_replace(array('AND'), array(' AND'), $where);
        $core->tpl->pages($page, $numb, $core->sum_data($dbaze, $where), $module . '/{page}');
    }

    /*
    * Вывод
    * $admin - папка с размещением админки модуля (root либо urs)
    * $module - название модуль, усли нужно вевести на главной странице админки подставить $admin_conf['num']
    * $dbaze - название таблицы базы данных
    * $where - то что запишем в кэш
    * $order - Какой порядковый номер order относительно /administration(0)/module(1)/news(2)/order(3)/, если вместо order в адресной строке /administration/module/news/(order)tags/ то выводиться будет tags
    */
    function sum_data($module = '', $where = false, $order_stat = false, $select = false, $as = false)
    {
        global $db;
        $module = $db->safesql($module);
        if (isset($where)) $where = str_replace(array('WHERE'), array(''), $where);
        $where = $where ? ' WHERE ' . $where : '';
        $where = str_replace(array('AND'), array(' AND'), $where);
        $ord_stat = str_replace(array('ORDER BY'), array(''), $order_stat);
        $order = $order_stat ? 'ORDER BY ' . $ord_stat : '';
        $order = str_replace(array('ORDER BY'), array(' ORDER BY'), $order);
        $select = $select ?: '*';
        $as = $as ? ' ' . $as : '';
        $query = $db->query("SELECT " . $select . " FROM " . DB_PREFIX . "_" . $module . $as . $where . $order);
        return $db->numRows($query);
    }

    function getMod($allowTemp = false)
    {
        global $url;
        return !$allowTemp ? $url[0] : (empty($this->tempModule) ? $url[0] : $this->tempModule);
    }

    public function bbDecode($text, $pubId = 0, $html = false): array|string|null
    {
        $new_bb = new bb;
        return $new_bb->bbSite($text, $pubId);
    }

    function getCatList($parent, $module, $columns): void
    {
        global $core;
        if (empty($this->catArray)) $this->catArray = getcache('categories');
        if (isset($this->catArray[$module])) {
            $cat_get = $this->catArray[$module];
            $count = 0;
            $cols = 1;
            $content = '<table style="width=:100%; border: 0; border-spacing: 1px; border-collapse: separate; text-align:center;">
   <tr>';
            foreach ($cat_get as $cid => $info) {
                if ($info['parent'] != 0 and $info['parent'] != $parent or $info['parent'] == 0 and $parent) continue;
                $catLink = $module . '/' . $this->getCat($module, $cid, 'development') . '/';
                $content .= '<td>
         <table style="border:0;" class="_catInfos">
            <tr>
               <td class="_catIcon"><a href="' . $catLink . '" title="' . $info['title'] . '"><img style="border:0;" src="' . (!empty($info['icon']) ? 'media/cats/' . $info['icon'] : 'media/noicon.png') . '" title="' . $info['title'] . '" alt=""></a></td>
               <td>
                  <div class="_catTitle"><a href="' . $catLink . '" title="' . $info['title'] . '"><b>' . $info['title'] . '</b></a></div>
                  <div class="_catDesc"><i>' . $info['description'] . '</i></div>
               </td>
            </tr>
         </table>
      </td>' . ($cols % $columns == 0 ? ' </tr> <tr>' : '');
                $cols++;
                $count++;
            }
            $content .= '</tr>
</table>';
            if ($count > 0) {
                $core->tpl->open();
                echo $content;
                $core->tpl->close();
            }
        }
    }

    function getCat($module, $pid = null, $type = 'short', $limit = 99)
    {
        global $lang;
        $cats = array();
        if ($pid) {
            if (empty($this->catArray)) $this->catArray = getcache('categories');
            if (isset($this->catArray[$module])) {
                $cat_get = $this->catArray[$module];
                $stop = $type == 'short';
                $carr = explode(',', $pid);
                foreach ($cat_get as $cid => $parseArr) {
                    if (in_array($cid, $carr)) {
                        $catsNewArr[$cid] = array('title' => $parseArr['title'], 'altname' => $parseArr['altname']);
                        $sub = $parseArr['parent'];
                        if ($stop) {
                            while ($sub) {
                                $adress[] = $cat_get[$sub]['altname'];
                                $sub = $cat_get[$sub]['parent'];
                                $catsNewArr[$cid] = array('title' => $parseArr['title'], 'altname' => $parseArr['altname'], 'adress' => array_reverse($adress));
                            }
                        } else {
                            while ($sub) {
                                $adress[] = $cat_get[$sub]['altname'];
                                $breadCrumb[] = array($cat_get[$sub]['title'], $cat_get[$sub]['altname']);
                                $catsNewArr[$cid] = $cat_get[$sub]['title'] . " » " . $catsNewArr[$cid]['title'];
                                $sub = $cat_get[$sub]['parent'];
                                $catsNewArr[$cid] = array('title' => $catsNewArr[$cid], 'altname' => $parseArr['altname'], 'adress' => array_reverse($adress));
                            }
                        }
                        unset($adress);
                    }
                }
                $catNum = 0;
                if (!empty($catsNewArr)) {
                    foreach ($catsNewArr as $catInfo) {
                        $catNum++;
                        switch ($type) {
                            case 'short':
                                if ($catNum <= $limit) {
                                    $subAdress = false;
                                    if (isset($catInfo['adress'])) {
                                        foreach ($catInfo['adress'] as $url) {
                                            $subAdress .= $url . '/';
                                        }
                                    }
                                    $cats[] = '<a href="' . $module . '/' . $subAdress . $catInfo['altname'] . '" target="_blank" data-toggle="tooltip" data-original-title="' . $catInfo['title'] . '">' . trimtitle($catInfo['title']) . '</a>';
                                    $implodeBy = ', ';
//unset($subAdress);
                                }
                                break;
                            case 'altname':
                                return $catInfo['altname'];
                            case 'url':
                                if ($catNum <= $limit) {
                                    $subAdress = false;
                                    if (isset($catInfo['adress'])) {
                                        foreach ($catInfo['adress'] as $url) {
                                            $subAdress .= $url . '/';
                                        }
                                    }
                                    $cats[] = '<a href="' . $module . '/' . $subAdress . $catInfo['altname'] . '" target="_blank" data-toggle="tooltip" data-original-title="' . $catInfo['title'] . '">' . trimtitle($catInfo['title']) . '</a>';
                                    $implodeBy = ', ';
//unset($subAdress);
                                }
                                return $module . '/' . $subAdress . $catInfo['altname'];
                            case 'development':
                                if ($catNum < 2) {
                                    $adress = false;
                                    if (isset($catInfo['adress'])) {
                                        foreach ($catInfo['adress'] as $url) {
                                            $adress .= $url . '/';
                                        }
                                    }
                                    return $adress . $catInfo['altname'];
                                    unset($adress);
                                }
                                break;
                            case 'breadcrumb':
                                if (isset($breadCrumb)) $breadCrumb = array_reverse($breadCrumb);
                                $breadCrumb[] = array($cat_get[$pid]['title'], $cat_get[$pid]['altname']);
                                $subAdress = '';
                                $cats[] = '<a href="' . $module . '" title="' . $lang['main_page'] . '">' . $lang['main_page'] . '</a>';
                                foreach ($breadCrumb as $step) {
                                    $subAdress = $subAdress . $step[1] . '/';
                                    $cats[] = '<a href="' . $module . '/' . $subAdress . '" title="' . $step[0] . '">' . $step[0] . '</a>';
                                }
//$showOpen = true;
                                $implodeBy = ' » ';
                                break;
                        }
                    }
                }
                if (isset($showOpen)) {
                    global $core;
                    $core->tpl->open();
                    echo implode($implodeBy, $cats);
                    $core->tpl->close();
                } else {
                    if (isset($implodeBy)) return implode($implodeBy, $cats);
                    return implode($cats);
                }
                unset($cats, $implodeBy);
            }
        }
    }

    function getCatImg($link, $img, $ctitle)
    {
        if (!empty($img)) return '<a href="' . $link . '" title="' . $ctitle . '"><img src="media/cats/' . $img . '"  alt="' . $ctitle . '" title="' . $ctitle . '" style="border:0; text-align:right;"/></a>';
    }

    function catInfo($module, $cid)
    {
        if (empty($this->catArray)) $this->catArray = getcache('categories');
        $cat_get = $this->catArray[$module];
        if (isset($this->catArray[$module])) {
            $cArr = explode(',', $cid);
            $cat = $cat_get[$cArr[1]] ?? '';
        } else {
            $cat = '';
        }
        return $cat;
    }

    function aCatList($module = ''): array
    {
        global $core, $db;
        if (empty($this->aCatArray)) {
            $where = '';
            if (!empty($module)) $where = "WHERE module='" . $db->safesql($module) . "'";
            $query = $core->select_data('categories', $where, false, 'id, name, parent_id as pid');
            while ($rows = $db->getRow($query)) {
                $cat_get[$rows['id']] = array($rows['name'], $rows['pid']);
            }
            if (isset($cat_get)) {
                foreach ($cat_get as $cid => $sub_arr) {
                    $cats_arr[$cid] = $sub_arr[0];
                    $flag = $sub_arr[1];
                    while ($flag != "0") {
                        $cats_arr[$cid] = $cat_get[$flag][0] . "/" . $cats_arr[$cid];
                        $flag = $cat_get[$flag][1];
                    }
                }
                asort($cats_arr);
                $this->aCatArray = $cats_arr;
            }
        }
        if (empty($this->aCatArray)) $this->aCatArray = array();
        return $this->aCatArray;
    }
}

$core = new core();