yf_main class

Core main class.

Fileclasses/yf_main.class.php
Use_class('main')

Public properties

A site sets them in its config with $PROJECT_CONF['main']['NAME'] = ...;

PropertyDefaultDescription
$ADMIN_ID null
$ALLOW_DEBUG_PROFILING
bool
false
$ALLOW_FAST_INIT
bool
false Allow fast (but not complete) init
$ALLOW_PAID_OPTIONS
bool
false Paid options global switch used by lot of other code @experimental
$ALLOW_SOURCE_FROM_DB
bool
false Allow to load source code from db
$AUTO_BAN_CHECKING null
$BLOCKS_TASK_403 null
$BLOCKS_TASK_404 null
$CACHE_CONTROL_FROM_URL
bool
false Allow cache control from url modifiers
$CATCH_FATAL_ERRORS
bool
false
$CONSOLE_MODE false
$DEV_MODE
mixed
false Development mode, enable dev overrides layer, can containg string with developer name
$ENABLE_NOTIFICATIONS_ADMIN
bool
false Notify module setting
$ENABLE_NOTIFICATIONS_USER
bool
false Notify module setting
$ENFORCE_DOMAINS
bool
false Ignore HTTP_HOST not listed in conf('DOMAINS') when WEB_PATH is built (read from the PROJECT_CONF global too, as WEB_PATH is built before the main class config is applied)
$EXEC_CACHE_NAME_TPL
string
'[FUNCTION]_[CLASS]_[METHOD]_[LANG]_[DOMAIN]_[CATEGORY]_[D'... Template for exec cache name
$EXEC_CACHE_TTL
int
600 Execute method cache lifetime (in seconds), set to 0 to use cache module default value
$HIDE_TOTAL_ID
bool
false Hide total ids where possible @experimental
$HOSTNAME
string
'' Server host name
$HTTPS_ENABLED_FOR
array
[] List of patterns for https-enabled pages
$HTTPS_HEADERS_FROM_TRUSTED_ONLY
bool
any client may set them. * Read from the PROJECT_CONF global too, as WEB_PATH calls is_https() before the main class config is applied */ Property [ public $HTTPS_HEADERS_FROM_TRUSTED_ONLY = f... Honour the forwarded-scheme headers (X-Forwarded-Proto, Front-End-Https, X-Url-Scheme, Scheme) in is_https() only when REMOTE_ADDR is a trusted proxy (client_utils TRUSTED_PROXIES / conf('TRUSTED_PROXIES')); false = any client may set them. Read from the PROJECT_CONF global too, as WEB_PATH calls is_https() before the main class config is applied
$INLINE_EDIT_LOCALE
bool
false Inline edit locale vars
$INTRUSION_DETECTION
bool
false Allow to use PHPIDS (intrusion detection system) http://php-ids.org/ @experimental
$IS_403 null
$IS_404 null
$IS_503 null
$IS_BANNED null
$LANG_USE_DB
bool
false Use database for translation or language files
$LOAD_COMPOSER_AUTOLOAD
bool
false Load vendor/autoload.php of YF_PATH, APP_PATH and PROJECT_PATH (composer packages installed there) in init_files(); false opts out
$LOG_EXEC
bool
false Logging of every engine call
$MODULE_ACTION_HANDLER
string
'_module_action_handler' @conf_skip Custom module handler method name
$MODULE_CONSTRUCT
string
'_init' @conf_skip Module (not class) constructor name
$NO_CACHE_HEADERS
bool
true Send no-cache headers
$NO_DB_CONNECT
bool
false Set if no database connection needed
$NO_DB_FOR
array
['internal' => [], 'dynamic' => ['php_func']] List of objects/actions for which no db connection is required. @example: 'object' => array('action1', 'action2')
$NO_GRAPHICS
bool
false Switch standard graphics processing on/off
$NO_SIDE_AREA_TOGGLER null
$OUTPUT_CACHING
bool
false Output caching on/off
$OVERLOAD_CPU_LOAD
int
1 Overloading protection turns on (if allowed) when CPU load is higher tha this value
$OVERLOAD_PROTECTION
bool
false Allow to use overload protection methods inside user section (we will disable some heavy methods and/or queries)
$PROFILING
bool
false @conf_skip
$REDIR_URL_DENIED
string
'./?object=login_form&go_url=%%object%%;%%action%%%%add_ge'... 'Acces denied' redirect url
$REDIR_URL_NOT_FOUND
string
'./' 'Not found' redirect url, also supports internal redirect, sample: array('object' => 'help', 'action' => 'show') or array('stpl' => 'my_404_page')
$SERVER_HEALTH_CHECK
bool
false Check server health status and return 503 if not OK (great to use with nginx upstream)
$SERVER_HEALTH_FILE
string
'/tmp/isok.txt' Path to the server health check result
$SERVER_ID
int
null @conf_skip Multi-server mode option
$SERVER_INFO []
$SERVER_ROLE
string
null @conf_skip Multi-server mode option
$SESSION_CUSTOM_HANDLER
bool
false Session custom handler ('db','files','memcached' or false for 'none')
$SESSION_DESTROY_EXPIRED
string
false
$SESSION_DOMAIN
string
''
$SESSION_LIFE_TIME
int
18000 Session life time (in seconds)
$SESSION_OFF null
$SESSION_REFERER_CHECK
string
''
$SESSION_SAVE_DIR
string
'' Custom session save dir (leave ampty to skip), example: 'session_data/'
$SESSION_USE_UNIQUE_NAME
string
true Custom session name
$SITE_ID
int
null @conf_skip Multi-site mode option
$SPIDERS_DETECTION
bool
false Auto-detect spiders
$STATIC_PAGES_ROUTE_TOP
bool
false Static pages as objects routing (eq. for URL like /terms/ instead of /static_pages/show/terms/)
$STRICT_MODULES_INIT
bool
false Strict init modules check (if turned on - then module need to be installed not only found)
$TRACK_ONLINE_DETAILS
bool
false Track details (online status=true is needed too)
$TRACK_ONLINE_STATUS
bool
false Track online status
$TRACK_USER_PAGE_VIEWS
bool
false Track user last visit
$USER_GROUP
int
0 @conf_skip Current user session info
$USER_ID
int
0 @conf_skip Current user session info
$USER_INFO
array
null @conf_skip Current user session info
$USER_ROLE null
$USE_CUSTOM_ERRORS
mixed
null Set from the main config; read by yf_db when it reports a query error
$USE_GEO_IP
bool
false Allow Geo IP tracking
$USE_ONLY_HTTPS
bool
false Use only HTTPS protocol and check if not - the redirect to the HTTPS
$USE_SYSTEM_CACHE
bool
false Sytem tables caching
$USE_TASK_MANAGER
bool
false Task manager on/off
$_ARGS_DIRTY []
$_CWD null
$_IN_OUTPUT_CACHE null
$_IS_REDIRECTING null
$_ORIGINAL_VARS_GET []
$_ORIGINAL_VARS_SERVER []
$_SHUTDOWN_CODE_ARRAY []
$_composer_autoload_loaded
array
[] vendor/autoload.php files already loaded by init_files(), read by yf_services::_composer_installed()
$_current_user_info null
$_custom_class_storages []
$_data_handlers_loaded null
$_debug_header_sent
bool
false @conf_skip X-YF-Debug was sent (_debug_header())
$_extend []
$_getset_cache []
$_is_mobile null
$_paths_replace_pairs []
$_plugins null
$_plugins_classes null
$_server_self_ips null
$_time_start null
$_timing []
$_unique_widget_ids null
$_user_info null
$auth null
$cache null
$common null
$data_handlers null
$db null
$error_handler null
$events null
$graphics null
$installed_admin_modules null
$installed_user_modules null
$is_console null
$modules []
$tpl null
$type
string
'user' Type of initialization @conf_skip - user (for user section) - admin (for control panel)
$web_path_was_not_defined null

Public methods 97

public function call_class_method($class_name = '', $custom_path = '', $method_name = '', $method_params = '', $tpl_name = '', $silent = false, $use_cache = false, $cache_ttl = -1, $cache_key_override = '')

Try to return class method output.

Returns bool

    public function call_class_method($class_name = '', $custom_path = '', $method_name = '', $method_params = '', $tpl_name = '', $silent = false, $use_cache = false, $cache_ttl = -1, $cache_key_override = '')
    {
        if ( ! strlen($class_name) || ! strlen($method_name)) {
            return false;
        }
        $class_name === '@object' && $class_name = ($_GET['object'] ?? null);
        $method_name === '@action' && $method_name = ($_GET['action'] ?? null);
        if ( ! $this->USE_SYSTEM_CACHE) {
            $use_cache = false;
        }
        if ($use_cache) {
            $cache_name = $this->_get_exec_cache_name($class_name, $custom_path, $method_name, $method_params, $tpl_name);
            $cache_ttl = (int) $cache_ttl;
            if ($cache_ttl < 1) {
                // set to 0 to use cache module default value
                $cache_ttl = $this->EXEC_CACHE_TTL;
            }
            $cached = $this->modules['cache']->get($cache_name, $cache_ttl);
            if ( ! empty($cached)) {
                return $cached[0];
            }
        }
        if ($class_name == 'main') {
            $obj = $this;
        } else {
            $obj = $this->init_class($class_name, $custom_path, $method_params);
            if ( ! is_object($obj) && ! $custom_path) {
                $custom_path = 'classes/';
                $obj = $this->init_class($class_name, $custom_path, $method_params);
            }
        }
        if ( ! is_object($obj)) {
            if ( ! $silent) {
                trigger_error('MAIN: module "' . $class_name . '" init failed' . ( ! empty($tpl_name) ? ' (template "' . $tpl_name . '")' : ''), E_USER_WARNING);
            }
            return false;
        }
        if ( ! method_exists($obj, $method_name)) {
            if ( ! $silent) {
                trigger_error('MAIN: no method "' . $method_name . '" in module "' . $class_name . '"' . ( ! empty($tpl_name) ? ' (template "' . $tpl_name . '")' : ''), E_USER_WARNING);
            }
            return false;
        }
        // Try to process method params (string like attrib1=value1;attrib2=value2)
        if (is_string($method_params) && strlen($method_params)) {
            $method_params = (array) _attrs_string2array($method_params);
        }
        $result = $obj->$method_name($method_params);
        if ($use_cache) {
            $this->modules['cache']->set($cache_name, [$result]);
        }
        return $result;
    }

exec_cached

public function exec_cached($class_name = '', $method_name = '', $method_params = '', $tpl_name = '', $silent = false, $use_cache = true, $cache_ttl = -1, $cache_key_override = '')

Alias for '_execute'.

Returns bool|string

    public function exec_cached($class_name = '', $method_name = '', $method_params = '', $tpl_name = '', $silent = false, $use_cache = true, $cache_ttl = -1, $cache_key_override = '')
    {
        return $this->_execute($class_name, $method_name, $method_params, $tpl_name, $silent, $use_cache, $cache_ttl, $cache_key_override);
    }

execute

public function execute($class_name = '', $method_name = '', $method_params = '', $tpl_name = '', $silent = false, $use_cache = false, $cache_ttl = -1, $cache_key_override = '')

Alias for '_execute'.

Returns bool|string

    public function execute($class_name = '', $method_name = '', $method_params = '', $tpl_name = '', $silent = false, $use_cache = false, $cache_ttl = -1, $cache_key_override = '')
    {
        return $this->_execute($class_name, $method_name, $method_params, $tpl_name, $silent, $use_cache, $cache_ttl, $cache_key_override);
    }

extend

public function extend($module, $name, $func)
    public function extend($module, $name, $func)
    {
        $module = $this->get_class_name($module);
        $this->_extend[$module][$name] = $func;
    }

extend_call

public function extend_call($that, $name, $args, $return_obj = false)
    public function extend_call($that, $name, $args, $return_obj = false)
    {
        $module = $this->get_class_name($that);
        $func = null;
        if (isset($that->_extend[$name])) {
            $func = $that->_extend[$name];
        } elseif (isset($this->_extend[$module][$name])) {
            $func = $this->_extend[$module][$name];
        }
        if ($func) {
            $out = $func($args[0], $args[1], $args[2], $args[3], $that);
            return $return_obj ? $that : $out;
        }
        trigger_error($module . ': No method ' . $name, E_USER_WARNING);
        return $return_obj ? $that : false;
    }
public function get_class_name($name)

Return class name of the object, stripping all YF-related prefixes Needed to ensure singleton pattern and extending classes with same name.

    public function get_class_name($name)
    {
        if (is_object($name)) {
            $name = get_class($name);
        }
        if ( ! $name) {
            return $name;
        }
        if (strpos($name, YF_PREFIX) === 0) {
            $name = substr($name, strlen(YF_PREFIX));
        } elseif (strpos($name, YF_ADMIN_CLS_PREFIX) === 0) {
            $name = substr($name, strlen(YF_ADMIN_CLS_PREFIX));
        } elseif (strpos($name, YF_SITE_CLS_PREFIX) === 0) {
            $name = substr($name, strlen(YF_SITE_CLS_PREFIX));
        }
        return $name;
    }

get_data

public function get_data($name = '', $force_ttl = 0, $params = [])

Get named data array.

    public function get_data($name = '', $force_ttl = 0, $params = [])
    {
        $time_start = DEBUG_MODE ? microtime(true) : null;
        if (empty($name)) {
            return null;
        }
        $cache_name = MAIN_TYPE . ':' . $name;
        // Example: geo_regions, ["country" => "UA", "lang" => "uk"] will be saved as geo_regions:country_UA:lang_uk
        if ( ! empty($params) && is_array($params)) {
            foreach ((array) $params as $k => $v) {
                strlen($k) && strlen($v) && $cache_name .= ':' . $k . '_' . $v;
            }
        }
        if (is_object($this->db) && ! $this->db->_connected) {
        }
        $data = $this->getset('get_data:' . $cache_name, function () use ($name, $params) {
            ! $this->_data_handlers_loaded && $this->_load_data_handlers();
            if ( ! isset($this->data_handlers[$name])) {
                return [];
            }
            $handler = $this->data_handlers[$name];
            $data = null;
            if (is_string($handler)) {
                $data = include $handler;
                if (is_callable($data)) {
                    $data = $data($params);
                }
            } elseif (is_callable($handler)) {
                $data = $handler($params);
            }
            return $data ?: [];
        }, $force_ttl, $params);

        if (DEBUG_MODE) {
            debug('main_get_data[]', [
                'name' => $name,
                'cache_name' => $cache_name,
                'data' => $data,
                'params' => $params,
                'force_ttl' => $force_ttl,
                'time' => round(microtime(true) - $time_start, 5),
                'trace' => $this->trace_string(),
            ]);
        }
        return $data;
    }

getset

public function getset($name, callable $func, $ttl = 0, array $params = [])

Get named data with callback with optional caching.

  • $func callable
  • $params array
    public function getset($name, callable $func, $ttl = 0, array $params = [])
    {
        if ( ! is_string($name) || ! $name) {
            return null;
        }
        if ( ! is_array($params)) {
            $params = [];
        }
        $refresh = $params['refresh_cache'] ?? false;
        $refresh && $params['no_cache'] = true;

        $enabled = $this->USE_SYSTEM_CACHE && ! ($params['no_cache'] ?? false);
        // speed optimization with 2nd layer of caching
        $memory_enabled = (($params['no_cache'] ?? false) || $refresh || $this->is_console()) ? false : true;
        if ($memory_enabled && isset($this->_getset_cache[$name])) {
            return $this->_getset_cache[$name]['result'];
        }
        $cache = null;
        if ($enabled || $refresh) {
            $cache = cache();
        }
        $result = null;
        $enabled && $result = $cache->get($name, $ttl, $params);
        $need_result = true;
        if ($result) {
            $need_result = false;
        } elseif (is_array($result) || (is_string($result) && ($result === '' || $result === '0' || $result === 'false'))) {
            $need_result = false;
        }
        if ($need_result) {
            $result = $func($name, $ttl, $params);
            if ($enabled || $refresh) {
                $cache->set($name, $result, $ttl);
            }
        }
        if ($memory_enabled || $refresh) {
            $this->_getset_cache[$name]['result'] = $result;
        }
        return $result;
    }
public function include_module($path_to_module = '', $is_required = false)

Include module file.

    public function include_module($path_to_module = '', $is_required = false)
    {
        $_time_start = null;
        if (DEBUG_MODE) {
            $_time_start = microtime(true);
        }
        // Will throw E_FATAL_ERROR if not found
        $file_exists = file_exists($path_to_module);
        if ($is_required) {
            if ($file_exists) {
                include_once $path_to_module;
            } else {
                if (DEBUG_MODE) {
                    echo '<b>YF FATAL ERROR</b>: Required file not found: ' . $path_to_module . '<br>\n<pre>' . $this->trace_string() . '</pre>';
                }
                exit();
            }
            // Here we do not want any errors if file is missing
        } elseif ($file_exists) {
            include_once $path_to_module;
        }
        if (DEBUG_MODE) {
            debug('included_files[]', [
                'path' => $path_to_module,
                'exists' => (int) $file_exists,
                'required' => (int) $is_required,
                'size' => $file_exists ? filesize($path_to_module) : '',
                'time' => round(microtime(true) - $_time_start, 5),
                'trace' => $this->trace_string(),
            ]);
        }
    }

init_auth

public function init_auth()

Init authentication.

    public function init_auth()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->events->fire('main.before_auth');
        if (defined('SITE_DEFAULT_PAGE')) {
            conf('SITE_DEFAULT_PAGE', SITE_DEFAULT_PAGE);
        }
        if (conf('no_internal_auth')) {
            $def_page = conf('SITE_DEFAULT_PAGE');
            if ($def_page) {
                parse_str(substr($def_page, 3), $_tmp);
                foreach ((array) $_tmp as $k => $v) {
                    $_GET[$k] = $v;
                }
            }
            return false;
        }
        if ($this->SPIDERS_DETECTION && conf('IS_SPIDER')) {
            return false;
        }
        $auth_module_name = 'auth_' . (MAIN_TYPE_ADMIN ? 'admin' : 'user');
        $auth_loaded_module_name = $this->load_class_file($auth_module_name, 'classes/auth/');
        if ($auth_loaded_module_name) {
            $this->auth = new $auth_loaded_module_name();
            $this->set_module_conf($auth_module_name, $this->auth);
            $this->auth->init();
        }
        if ( ! is_object($this->auth)) {
            throw new RuntimeException('MAIN: Cannot load needed auth module');
        }
        $this->events->fire('main.after_auth');
    }

init_cache

public function init_cache()
    public function init_cache()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->events->fire('main.before_cache');
        $CACHE_DRIVER = conf('CACHE_DRIVER');
        if ($CACHE_DRIVER) {
            conf('cache::DRIVER', $CACHE_DRIVER);
        }
        $this->cache = $this->_class('cache');
        $this->events->fire('main.after_cache');
    }

init_class

public function init_class($class_name, $custom_path = '', $params = '')

Module(class) loader, based on singleton pattern Initialize new class object or return reference to existing one.

Returns bool|null|yf_main

    public function init_class($class_name, $custom_path = '', $params = '')
    {
        $class_name = $this->get_class_name($class_name);
        if (isset($this->modules[$class_name]) && is_object($this->modules[$class_name])) {
            return $this->modules[$class_name];
        }
        if (empty($class_name)) {
            return false;
        }
        if ($class_name == 'main') {
            return $this;
        }
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        // Strict installed modules check (currently only for user modules)
        if ($this->STRICT_MODULES_INIT && empty($custom_path)) {
            if ( ! isset($this->installed_user_modules)) {
                $this->installed_user_modules = $this->get_data('user_modules');
            }
            if (MAIN_TYPE_USER) {
                $skip_array = [
                    'rewrite',
                ];
                if ( ! in_array($class_name, $skip_array) && ! isset($this->installed_user_modules[$class_name])) {
                    return false;
                }
            } elseif (MAIN_TYPE_ADMIN) {
                if ( ! isset($this->installed_admin_modules)) {
                    $this->installed_admin_modules = $this->get_data('admin_modules');
                }
                $skip_array = [];
                if ( ! in_array($class_name, $skip_array) && ! isset($this->installed_admin_modules[$class_name]) && ! isset($this->installed_user_modules[$class_name])) {
                    return false;
                }
            }
        }
        $class_name_to_load = $this->load_class_file($class_name, $custom_path);
        if ($class_name_to_load) {
            $this->modules[$class_name] = new $class_name_to_load($params);
            $this->set_module_conf($class_name, $this->modules[$class_name], $params);
        }
        if (is_object($this->modules[$class_name] ?? null)) {
            return $this->modules[$class_name];
        }
        return null;
    }

init_common

public function init_common()
    public function init_common()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->common = $this->_class('common');
    }
public function init_composer_autoload()

Load composer autoloaders of the framework and the project, each file once, so packages added with `composer require` are found without a services/ loader.

    public function init_composer_autoload()
    {
        if ( ! $this->LOAD_COMPOSER_AUTOLOAD) {
            return false;
        }
        foreach ([YF_PATH, APP_PATH, PROJECT_PATH] as $dir) {
            $path = $dir . 'vendor/autoload.php';
            $real = is_file($path) ? realpath($path) : false;
            if ($real === false || in_array($real, $this->_composer_autoload_loaded, true)) {
                continue;
            }
            $this->_composer_autoload_loaded[] = $real;
            require_once $real;
        }
        return true;
    }
public function init_conf_functions()

conf(), module_conf() wrappers.

    public function init_conf_functions()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $path = dirname(__DIR__) . '/functions/yf_conf.php';
        if (file_exists($path)) {
            $this->include_module($path, 1);
        }
    }
public function init_constants()

Check and try to fix required constants.

    public function init_constants()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        // Save current working directory (to restore it later when execute shutdown functions)
        $this->_CWD = getcwd();

        $this->_ORIGINAL_VARS_GET = $_GET;
        $this->_ORIGINAL_VARS_SERVER = $_SERVER;

        ! defined('DEBUG_MODE') && define('DEBUG_MODE', false);
        if (DEBUG_MODE) {
            ini_set('display_errors', 'stdout');
        }
        if (($_SERVER['SERVER_ADDR'] ?? null) !== null) {
            $_SERVER['SERVER_ADDR'] = preg_replace('#[^0-9\.]+#', '', trim(($_SERVER['SERVER_ADDR'] ?? '')));
        }
        if (($_SERVER['SERVER_PORT'] ?? null) !== null) {
            $_SERVER['SERVER_PORT'] = (int) ($_SERVER['SERVER_PORT'] ?? null);
        }
        if (($_SERVER['HTTP_HOST'] ?? null) !== null) {
            if (false !== ($pos = strpos(($_SERVER['HTTP_HOST'] ?? ''), ':'))) {
                $_SERVER['HTTP_HOST'] = substr(($_SERVER['HTTP_HOST'] ?? ''), 0, $pos);
            }
            $_SERVER['HTTP_HOST'] = strtolower(str_replace('..', '.', preg_replace('#[^0-9a-z\-\.]+#', '', trim(($_SERVER['HTTP_HOST'] ?? '')))));
        }
        if (($_SERVER['REQUEST_URI'] ?? null) !== null) {
            // Some servers pass an absolute-form request target ("GET http://test.dev/ HTTP/1.1") as REQUEST_URI: keep path and query
            $p = parse_url(($_SERVER['REQUEST_URI'] ?? ''));
            if (isset($p['scheme']) || isset($p['host'])) {
                $_SERVER['REQUEST_URI'] = (($p['path'] ?? null) ?: '/') . ($p['query'] ? '?' . $p['query'] : '');
                if (($_SERVER['QUERY_STRING'] ?? null) != $p['query']) {
                    $_SERVER['QUERY_STRING'] = $p['query'];
                    parse_str($p['query'], $_get);
                    foreach ((array) $_get as $k => $v) {
                        $_GET[$k] = $v;
                    }
                }
            }
        }
        defined('DEV_MODE') && conf('DEV_MODE', constant('DEV_MODE'));
        $this->DEV_MODE = conf('DEV_MODE');

        define('OS_WINDOWS', strpos(PHP_OS, 'WIN') === 0);

        $this->HOSTNAME = php_uname('n');

        if ( ! defined('INCLUDE_PATH')) {
            if ($this->is_console()) {
                $_trace = debug_backtrace();
                $_trace = $_trace[1];
                $_path = dirname($_trace['file']);
                define('INCLUDE_PATH', (MAIN_TYPE_ADMIN ? dirname($_path) : $_path) . '/');
            } else {
                $cur_script_path = dirname(realpath(getenv('SCRIPT_FILENAME')));
                define('INCLUDE_PATH', str_replace(['\\', '//'], ['/', '/'], (MAIN_TYPE_ADMIN ? dirname($cur_script_path) : $cur_script_path) . '/'));
            }
        }
        // Alias (an entry script may define it first, e.g. .dev/sample_app/router.php)
        ! defined('PROJECT_PATH') && define('PROJECT_PATH', INCLUDE_PATH);
        // Framework root filesystem path
        ! defined('YF_PATH') && define('YF_PATH', dirname(PROJECT_PATH) . '/yf/');
        // Project-level application path, where will be other important subfolders like: APP_PATH.'www/', APP_PATH.'docs/', APP_PATH.'tests/',
        ! defined('APP_PATH') && define('APP_PATH', dirname(PROJECT_PATH) . '/');
        // Filesystem path for configuration files, including db_setup.php and so on
        ! defined('CONFIG_PATH') && define('CONFIG_PATH', APP_PATH . 'config/');
        // Filesystem path for various storage needs: logs, sessions, other files that should not be accessible from WEB
        ! defined('STORAGE_PATH') && define('STORAGE_PATH', APP_PATH . 'storage/');
        // Filesystem path to logs, usually should be at least one level up from WEB_PATH to be not accessible from web server
        ! defined('LOGS_PATH') && define('LOGS_PATH', STORAGE_PATH . 'logs/');
        // Uploads path should be used for various uploaded content accessible from WEB_PATH
        ! defined('UPLOADS_PATH') && define('UPLOADS_PATH', PROJECT_PATH . 'uploads/');
        // Website inside project FS base path. Recommended to use from now instead of REAL_PATH
        if ( ! defined('SITE_PATH')) {
            $_site_tmp = $this->_find_site();
            $found_site = $_site_tmp[0] ?? '';
            $found_dir = $_site_tmp[1] ?? '';
            define('SITE_PATH', $found_site ? $found_dir . $found_site . '/' : APP_PATH);
        }
        // Alias of SITE_PATH. Compatibility with old code. DEPRECATED
        ! defined('REAL_PATH') && define('REAL_PATH', SITE_PATH);
        // Set WEB_PATH (if not done yet)
        if ( ! defined('WEB_PATH')) {
            $request_uri = (string) ($_SERVER['REQUEST_URI'] ?? '/');
            $cur_web_path = '';
            if ($request_uri === '' || $request_uri[strlen($request_uri) - 1] == '/') {
                $cur_web_path = substr($request_uri, 0, -1);
            } else {
                $cur_web_path = dirname((string) $request_uri);
            }
            $host = '';
            $conf_domains = conf('DOMAINS');
            $enforce = $this->ENFORCE_DOMAINS || ! empty($GLOBALS['PROJECT_CONF']['main']['ENFORCE_DOMAINS']);
            if ( ! empty($_SERVER['HTTP_HOST'])) {
                $host = $_SERVER['HTTP_HOST'];
                if ($enforce && is_array($conf_domains) && $conf_domains && ! $this->_host_is_allowed($host, $conf_domains)) {
                    // bare host: the port is appended below from SERVER_PORT
                    $host = preg_replace('/:\d+$/', '', (string) current($conf_domains));
                }
            } elseif (is_array($conf_domains)) {
                $host = (string) current($conf_domains);
            } else {
                $host = '127.0.0.1';
            }
            $this->web_path_was_not_defined = true;
            define(
                'WEB_PATH',
                ($this->is_https() ? 'https://' : 'http://')
                    . $host . ( ! empty($_SERVER['SERVER_PORT']) && ! in_array($_SERVER['SERVER_PORT'], ['80', '443']) ? ':' . $_SERVER['SERVER_PORT'] : '')
                    . str_replace(['\\', '//'], '/', (MAIN_TYPE_ADMIN ? dirname($cur_web_path) : $cur_web_path) . '/')
            );
        }
        if ( ! defined('WEB_DOMAIN') && defined('WEB_PATH') && strlen(WEB_PATH)) {
            define('WEB_DOMAIN', parse_url(WEB_PATH, PHP_URL_HOST));
        }
        // Should be different that WEB_PATH to distribute static content from other subdomain
        ! defined('MEDIA_PATH') && define('MEDIA_PATH', WEB_PATH);
        ! defined('ADMIN_SITE_PATH') && define('ADMIN_SITE_PATH', SITE_PATH . 'admin/');
        ! defined('ADMIN_WEB_PATH') && define('ADMIN_WEB_PATH', WEB_PATH . 'admin/');
        // Check if current page is called via AJAX call from javascript
        conf('IS_AJAX', (strtolower($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') == 'xmlhttprequest' || ! empty($_GET['ajax_mode'] ?? '')) ? 1 : 0);

        define('USER_MODULES_DIR', 'modules/');
        define('ADMIN_MODULES_DIR', 'admin_modules/');
        // Set console-specific options
        if ($this->is_console()) {
            ini_set('memory_limit', -1);
            set_time_limit(0);
            // Send PHP warnings and errors to stderr instead of stdout. This aids in diagnosing problems, while keeping messages out of redirected output.
            if (ini_get('display_errors')) {
                ini_set('display_errors', 'stderr');
            }
            // Parse console options into $_GET array
            foreach ((array) ($_SERVER['argv'] ?? null) as $v) {
                if (strpos($v, '--') !== 0) {
                    continue;
                }
                $v = substr($v, 2);
                list($_name, $_val) = array_pad(explode('=', $v, 2), 2, '');
                $_name = trim($_name);
                if (strlen($_name)) {
                    $_GET[$_name] = trim((string) $_val);
                }
            }
        }
        $this->_filter_object_action();
        ! conf('css_framework') && conf('css_framework', 'bs3');
    }

init_content

public function init_content()
    public function init_content()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->events->fire('main.before_content');

        $this->tpl->init_graphics();

        $this->is_post() && $this->events->fire('main.on_post');
        $this->is_ajax() && $this->events->fire('main.on_ajax');
        $this->is_console() && $this->events->fire('main.on_console');
        $this->is_redirect() && $this->events->fire('main.on_redirect');

        $this->events->fire('main.after_content');
    }

init_db

public function init_db()
    public function init_db()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->events->fire('main.before_db');
        // Check if current object/action not required db connection
        $get_object = ($_GET['object'] ?? null);
        $get_action = ($_GET['action'] ?? null);
        if ($this->NO_DB_FOR && $get_object && isset($this->NO_DB_FOR[$get_object])) {
            if (empty($this->NO_DB_FOR[$get_object]) || ($get_action && in_array($get_action, $this->NO_DB_FOR[$get_object]))) {
                $this->NO_DB_CONNECT = true;
            }
        }
        if ($this->NO_DB_CONNECT) {
            return false;
        }
        if ( ! isset($GLOBALS['db'])) {
            $this->_class('db');
            $GLOBALS['db'] = &$this->modules['db'];
        } else {
            $this->set_module_conf('db', $this->modules['db']);
        }
        $this->db = &$this->modules['db'];
        $this->events->fire('main.after_db');
    }

init_events

public function init_events()
    public function init_events()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->events = $this->_class('core_events');
        // Load event listeners from supported locations
        $ext = '.listener.php';
        $patterns = [
            'framework' => [
                YF_PATH . 'events/*' . $ext,
                YF_PATH . 'plugins/*/events/*' . $ext,
                YF_PATH . 'share/events/*' . $ext,
                YF_PATH . 'plugins/*/share/events/*' . $ext,
            ],
            'app' => [
                APP_PATH . 'events/*' . $ext,
                APP_PATH . 'plugins/*/events/*' . $ext,
                APP_PATH . 'share/events/*' . $ext,
                APP_PATH . 'plugins/*/share/events/*' . $ext,
            ],
        ];
        $ext_len = strlen($ext);
        $names = [];
        foreach ($patterns as $gname => $paths) {
            foreach ($paths as $path) {
                foreach (glob($path) as $matchedPath) {
                    $name = substr(basename($matchedPath), 0, -$ext_len);
                    $names[$name] = $matchedPath;
                    $locations[$name][$gname] = $matchedPath;
                }
            }
        }
        // This double iterating code allows to inherit/replace listeners with same name in project
        foreach ($names as $name => $path) {
            require_once $path;
        }
    }

init_files

public function init_files()

Initialization of required files.

    public function init_files()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $include_files = [];
        $required_files = [];
        $this->events && $this->events->fire('main.before_files');
        $this->init_composer_autoload();
        if ($this->NO_DB_CONNECT == 0) {
            $include_files[] = CONFIG_PATH . 'db_setup.php';
        }
        foreach ((array) conf('include_files::' . MAIN_TYPE) as $path) {
            $include_files[] = $path;
        }
        foreach ((array) conf('required_files::' . MAIN_TYPE) as $path) {
            $required_files[] = $path;
        }
        $funcs_paths = [
            'app' => APP_PATH . 'functions/common_funcs.php',
            'app_old' => APP_PATH . 'share/functions/common_funcs.php',
            'yf' => YF_PATH . 'functions/' . YF_PREFIX . 'common_funcs.php',
        ];
        foreach ($funcs_paths as $path) {
            if (file_exists($path)) {
                $required_files[] = $path;
            }
        }
        foreach ((array) $include_files as $path) {
            $this->include_module($this->_replace_core_paths($path), $_requried = false);
        }
        foreach ((array) $required_files as $path) {
            $this->include_module($this->_replace_core_paths($path), $_requried = true);
        }
    }

init_locale

public function init_locale()

Starting localization engine.

    public function init_locale()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if (($_GET['no_lang'] ?? false) || conf('no_locale')) {
            return false;
        }
        _class('i18n')->init_locale();
    }
public function init_main_functions()

main(), _class(), module(), db(), tpl(), common() wrappers and more.

    public function init_main_functions()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $path = dirname(__DIR__) . '/functions/yf_aliases.php';
        if (file_exists($path)) {
            $this->include_module($path, 1);
        }
    }
public function init_modules_base()
    public function init_modules_base()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->modules = [];
    }
public function init_server_health()
    public function init_server_health()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        // Server health result (needed to correctly self turn off faulty box from frontend requests)
        if ( ! $this->is_console() && $this->SERVER_HEALTH_CHECK && $this->SERVER_HEALTH_FILE && file_exists($this->SERVER_HEALTH_FILE)) {
            $health_result = file_get_contents($this->SERVER_HEALTH_FILE);
            if ($health_result != 'OK') {
                header($this->_server('SERVER_PROTOCOL') . ' 503 Service Unavailable');
                exit();
            }
        }
        // Get current server load value (only for user section)
        if ($this->OVERLOAD_PROTECTION && MAIN_TYPE_USER && ! OS_WINDOWS) {
            $load = sys_getloadavg();
            conf('HIGH_CPU_LOAD', $load[0] > $this->OVERLOAD_CPU_LOAD ? 1 : 0);
        } else {
            conf('HIGH_CPU_LOAD', 0);
        }
    }
public function init_server_id()

Try to find current server if not done yet.

    public function init_server_id()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $servers = $this->get_data('servers');
        $this->SERVER_ID = 0;
        if ( ! conf('SERVER_ID') && ($servers || DEBUG_MODE)) {
            $self_ips = explode(' ', exec('hostname --all-ip-addresses'));
            if ($self_ips) {
                $self_ips = array_combine($self_ips, $self_ips);
                $this->_server_self_ips = $self_ips;
            }
            foreach ((array) $servers as $server) {
                if ($server['hostname'] == $this->HOSTNAME) {
                    $this->SERVER_ID = (int) $server['id'];
                    break;
                }
                $server_ips = [];
                if ($self_ips) {
                    foreach (explode(',', str_replace([',', ';', PHP_EOL, "\t", ' '], ',', trim($server['ip']))) as $v) {
                        $v = trim($v);
                        $v && $server_ips[$v] = $v;
                    }
                    if ($server_ips && array_intersect($self_ips, $server_ips)) {
                        $this->SERVER_ID = (int) $server['id'];
                        break;
                    }
                }
            }
        }
        conf('SERVER_ID', (int) $this->SERVER_ID);
        if ($this->SERVER_ID) {
            $this->SERVER_INFO = $servers[$this->SERVER_ID];
        }
        return $this->SERVER_ID;
    }
public function init_server_role()

Try to find current server role if not done yet.

    public function init_server_role()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->SERVER_ROLE = 'default';
        if ( ! conf('SERVER_ROLE') && ($this->SERVER_INFO['role'] ?? false)) {
            $this->SERVER_ROLE = $this->SERVER_INFO['role'];
            conf('SERVER_ROLE', $this->SERVER_ROLE);
        }
        return $this->SERVER_ROLE;
    }

init_session

public function init_session()
    public function init_session()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->events->fire('main.before_session');
        $skip = false;
        if (isset($this->_session_init_complete) || $this->is_console() || conf('SESSION_OFF') || $this->SESSION_OFF) {
            $skip = true;
        } elseif ($this->SPIDERS_DETECTION && conf('IS_SPIDER')) {
            $skip = true;
        }
        if ( ! $skip) {
            _class('session')->start();
        }
        $this->events->fire('main.after_session');
    }

init_settings

public function init_settings()

Initialization settings stored in the database.

    public function init_settings()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $output_caching = conf('output_caching');
        if (isset($output_caching)) {
            $this->OUTPUT_CACHING = $output_caching;
        }
        $this->events->fire('main.settings');
    }

init_site_id

public function init_site_id()

Try to find current site if not done yet.

    public function init_site_id()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if ( ! conf('SITE_ID')) {
            $site_id = 1;
            foreach ((array) $this->get_data('sites') as $site) {
                if ($site['name'] == ($_SERVER['HTTP_HOST'] ?? null)) {
                    $site_id = $site['id'];
                    break;
                }
            }
            conf('SITE_ID', (int) $site_id);
            $this->SITE_ID = (int) $site_id;
        }
        return $this->SITE_ID;
    }

init_tpl

public function init_tpl()
    public function init_tpl()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->events->fire('main.before_tpl');
        $this->tpl = $this->_class('tpl');
        $this->events->fire('main.after_tpl');
    }

is_403

public function is_403()
    public function is_403()
    {
        return (bool) ($this->IS_403 || $this->BLOCKS_TASK_403);
    }

is_404

public function is_404()
    public function is_404()
    {
        return (bool) ($this->IS_404 || $this->BLOCKS_TASK_404);
    }

is_503

public function is_503()
    public function is_503()
    {
        return (bool) $this->IS_503;
    }

is_ajax

public function is_ajax()

Checks whether current page was requested with AJAX.

    public function is_ajax()
    {
        return (bool) conf('IS_AJAX');
    }

is_banned

public function is_banned()
    public function is_banned()
    {
        return (bool) $this->IS_BANNED;
    }
public function is_blocks_task_403()
    public function is_blocks_task_403()
    {
        return (bool) $this->BLOCKS_TASK_403;
    }
public function is_blocks_task_404()
    public function is_blocks_task_404()
    {
        return (bool) $this->BLOCKS_TASK_404;
    }

is_cache_on

public function is_cache_on()
    public function is_cache_on()
    {
        return (bool) (($this->USE_SYSTEM_CACHE || conf('USE_CACHE')) && ! cache()->NO_CACHE);
    }
public function is_common_page()

Checks whether current page is not a special page (no ajax, no redirects, no console, no post, etc).

    public function is_common_page()
    {
        return ! ($this->is_post() || $this->is_ajax() || $this->is_redirect() || $this->is_console());
    }

is_console

public function is_console()

Checks whether current page was requested from console.

    public function is_console()
    {
        return (bool) $this->CONSOLE_MODE;
    }

is_db

public function is_db()
    public function is_db()
    {
        return is_object($this->db) ? true : false;
    }

is_debug

public function is_debug()
    public function is_debug()
    {
        return defined('DEBUG_MODE') && DEBUG_MODE;
    }

is_dev

public function is_dev()
    public function is_dev()
    {
        return (defined('DEVELOP') && DEVELOP) || (defined('TEST_MODE') && TEST_MODE);
    }

is_https

public function is_https()
    public function is_https()
    {
        $direct = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] ?? null) && strtolower(($_SERVER['HTTPS'] ?? '')) != 'off')
            || (isset($_SERVER['SSL_PROTOCOL']) && ($_SERVER['SSL_PROTOCOL'] ?? null));
        if ($direct) {
            return true;
        }
        $trusted_only = $this->HTTPS_HEADERS_FROM_TRUSTED_ONLY || ! empty($GLOBALS['PROJECT_CONF']['main']['HTTPS_HEADERS_FROM_TRUSTED_ONLY']);
        if ($trusted_only && ! $this->_from_trusted_proxy()) {
            return false;
        }
        return false
            // Non-standard header used by Microsoft applications and load-balancers:
            || (isset($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower(($_SERVER['HTTP_FRONT_END_HTTPS'] ?? '')) == 'on')
            // http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/x-forwarded-headers.html
            || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower(($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '')) == 'https')
            // http://stackoverflow.com/questions/16042647/whats-the-de-facto-standard-for-a-reverse-proxy-to-tell-the-backend-ssl-is-used
            || (isset($_SERVER['HTTP_X_URL_SCHEME']) && strtolower(($_SERVER['HTTP_X_URL_SCHEME'] ?? '')) == 'https')
            // http://serverfault.com/questions/302282/how-can-i-use-haproxy-with-ssl-and-get-x-forwarded-for-headers-and-tell-php-that
            || (isset($_SERVER['HTTP_SCHEME']) && strtolower(($_SERVER['HTTP_SCHEME'] ?? '')) == 'https');
    }

is_logged_in

public function is_logged_in()
    public function is_logged_in()
    {
        return MAIN_TYPE_ADMIN ? $this->ADMIN_ID : $this->USER_ID;
    }

is_mobile

public function is_mobile()
    public function is_mobile()
    {
        if (isset($this->_is_mobile)) {
            return $this->_is_mobile;
        }
        $this->_is_mobile = false;
        if ( ! $this->is_console()) {
            try {
                require_php_lib('mobile_detect');
                $detect = new Mobile_Detect([], strtolower(($_SERVER['HTTP_USER_AGENT'] ?? '')));
                $this->_is_mobile = (bool) $detect->isMobile();
            } catch (Exception $e) {
            }
        }
        return $this->_is_mobile;
    }
public function is_output_cache_on()
    public function is_output_cache_on()
    {
        return (bool) $this->OUTPUT_CACHING;
    }

is_post

public function is_post()

Checks whether current page was requested with POST method.

    public function is_post()
    {
        return strtoupper($_SERVER['REQUEST_METHOD'] ?? '') == 'POST';
    }

is_redirect

public function is_redirect()

Checks whether current page is a redirect.

    public function is_redirect()
    {
        return (bool) $this->_IS_REDIRECTING;
    }

is_site_path

public function is_site_path()
    public function is_site_path()
    {
        return defined('SITE_PATH') && SITE_PATH != '' && SITE_PATH != PROJECT_PATH;
    }

is_spider

public function is_spider()
    public function is_spider()
    {
        return (bool) conf('IS_SPIDER');
    }

is_unit_test

public function is_unit_test()

Checks whether current page is in unit testing mode.

    public function is_unit_test()
    {
        return (bool) defined('YF_IN_UNIT_TESTS');
    }
public function load_class_file($class_name = '', $custom_path = '', $force_storage = '')

Load module file.

    public function load_class_file($class_name = '', $custom_path = '', $force_storage = '')
    {
        if (empty($class_name) || $class_name == 'main') {
            return false;
        }
        $cur_hook_prefix = MAIN_TYPE_ADMIN ? YF_ADMIN_CLS_PREFIX : YF_SITE_CLS_PREFIX;
        $loaded_class_name = false;
        // Site loaded class have top priority
        $site_class_name = $cur_hook_prefix . $class_name;
        if (class_exists($site_class_name)) {
            return $site_class_name;
        }
        if (class_exists($class_name)) {
            return $class_name;
        }
        if (class_exists($cur_hook_prefix . $class_name)) {
            return $cur_hook_prefix . $class_name;
        }
        if (class_exists(YF_PREFIX . $class_name)) {
            return YF_PREFIX . $class_name;
        }
        if (strpos($class_name, YF_PREFIX) === 0) {
            $class_name = substr($class_name, strlen(YF_PREFIX));
        }
        $_time_start = null;
        if (DEBUG_MODE) {
            $_time_start = microtime(true);
        }
        $class_file = $class_name . YF_CLS_EXT;
        // Developer part of path is related to hostname to be able to make different code overrides for each
        $dev_path = '.dev/' . $this->HOSTNAME . '/';
        // additional path variables
        $project_path2 = null;
        $site_path = null;
        $site_path_dev = null;
        $project_path = null;
        $project_path_dev = null;
        $fwork_path = null;
        $SITE_PATH = MAIN_TYPE_USER ? SITE_PATH : ADMIN_SITE_PATH;
        if (MAIN_TYPE_USER) {
            if (empty($custom_path)) {
                $site_path = USER_MODULES_DIR;
                $site_path_dev = $dev_path . USER_MODULES_DIR;
                $project_path = USER_MODULES_DIR;
                $project_path_dev = $dev_path . USER_MODULES_DIR;
                $fwork_path = USER_MODULES_DIR;
            } else {
                if (false === strpos($custom_path, SITE_PATH) && false === strpos($custom_path, PROJECT_PATH)) {
                    $site_path = $custom_path;
                    $site_path_dev = $dev_path . $custom_path;
                    $project_path = $custom_path;
                    $project_path_dev = $dev_path . $custom_path;
                    $fwork_path = $custom_path;
                } else {
                    $site_path = $custom_path;
                }
            }
        } elseif (MAIN_TYPE_ADMIN) {
            if (empty($custom_path)) {
                $site_path = ADMIN_MODULES_DIR;
                $site_path_dev = $dev_path . ADMIN_MODULES_DIR;
                $project_path = ADMIN_MODULES_DIR;
                $project_path_dev = $dev_path . ADMIN_MODULES_DIR;
                $fwork_path = ADMIN_MODULES_DIR;
                $project_path2 = USER_MODULES_DIR;
            } else {
                if (false === strpos($custom_path, SITE_PATH) && false === strpos($custom_path, PROJECT_PATH) && false === strpos($custom_path, ADMIN_SITE_PATH)) {
                    $site_path = $custom_path;
                    $site_path_dev = $dev_path . $custom_path;
                    $project_path = $custom_path;
                    $project_path_dev = $dev_path . $custom_path;
                    $fwork_path = $custom_path;
                } else {
                    $site_path = $custom_path;
                }
            }
        }
        if ( ! isset($this->_plugins)) {
            $this->_preload_plugins_list();
        }
        $yf_plugins = &$this->_plugins;
        $yf_plugins_classes = &$this->_plugins_classes;

        // Order of storages matters a lot!
        $storages = [];
        if (conf('DEV_MODE')) {
            if ($site_path_dev && $site_path_dev != $project_path_dev) {
                $storages['dev_site'] = [$SITE_PATH . $site_path_dev];
            }
            $storages['dev_app'] = [APP_PATH . $project_path_dev];
            $storages['dev_project'] = [PROJECT_PATH . $project_path_dev];
        }
        if (strlen($site_path)) {
            $def_path = 'classes/';
            if (strpos($site_path, $def_path) !== 0) {
                if (strlen(YF_PATH) > 3 && strpos($site_path, YF_PATH) === 0) {
                    $storages['site'] = [$site_path];
                } elseif (strlen(APP_PATH) > 3 && strpos($site_path, APP_PATH) === 0) {
                    $storages['site'] = [$site_path];
                } elseif (strlen(PROJECT_PATH) > 3 && strpos($site_path, PROJECT_PATH) === 0) {
                    $storages['site'] = [$site_path];
                }
            }
            if ( ! isset($storages['site']) && strlen($SITE_PATH . $site_path) && ($SITE_PATH . $site_path) != (PROJECT_PATH . $project_path)) {
                $storages['site'] = [$SITE_PATH . $site_path];
            }
        }
        $storages['app_site_hook'] = [APP_PATH . $site_path, $cur_hook_prefix];
        $storages['app'] = [APP_PATH . $project_path];
        $storages['project_site_hook'] = [$SITE_PATH . $site_path, $cur_hook_prefix];
        $storages['project'] = [PROJECT_PATH . $project_path];
        $plugin_name = '';
        if (isset($yf_plugins[$class_name]) || isset($yf_plugins_classes[$class_name])) {
            if (isset($yf_plugins_classes[$class_name])) {
                $plugin_name = $yf_plugins_classes[$class_name];
            } elseif (isset($yf_plugins[$class_name])) {
                $plugin_name = $class_name;
            }
        }
        if ($plugin_name) {
            $plugin_info = $yf_plugins[$plugin_name];
            $plugin_subdir = 'plugins/' . $plugin_name . '/';

            if ($site_path && $site_path != $project_path) {
                $storages['plugins_site'] = [$SITE_PATH . $plugin_subdir . $site_path];
            }
            if (isset($plugin_info['app'])) {
                $storages['plugins_app'] = [APP_PATH . $plugin_subdir . $project_path];
                if (MAIN_TYPE_ADMIN) {
                    $storages['plugins_admin_user_app'] = [APP_PATH . $plugin_subdir . $project_path2];
                }
            } elseif (isset($plugin_info['project'])) {
                $storages['plugins_project'] = [PROJECT_PATH . $plugin_subdir . $project_path];
                if (MAIN_TYPE_ADMIN) {
                    $storages['plugins_admin_user_project'] = [PROJECT_PATH . $plugin_subdir . $project_path2];
                }
            }
        }
        $storages['framework'] = [YF_PATH . $fwork_path, YF_PREFIX];
        if ($plugin_name) {
            if (isset($plugin_info['framework'])) {
                $storages['plugins_framework'] = [YF_PATH . $plugin_subdir . $fwork_path, YF_PREFIX];
                if (MAIN_TYPE_ADMIN) {
                    $storages['plugins_admin_user_framework'] = [YF_PATH . $plugin_subdir . USER_MODULES_DIR, YF_PREFIX];
                }
            }
        }
        if (MAIN_TYPE_ADMIN) {
            $storages['admin_user_app'] = [APP_PATH . $project_path2];
            $storages['admin_user_project'] = [PROJECT_PATH . $project_path2];
            $storages['admin_user_framework'] = [YF_PATH . USER_MODULES_DIR, YF_PREFIX];
        }
        // Extending storages on-the-fly. Examples:
        // main()->_custom_class_storages = array(
        //     'film_model' => array('unit_tests' => array(__DIR__.'/model/other_fixtures/')),
        //     '*_model' => array('unit_tests' => array(__DIR__.'/model/fixtures/')),
        // );
        // $film_model = _class('film_model');
        foreach ((array) $this->_custom_class_storages as $_class_name => $_storages) {
            // Have support for wildcards: * ? [abc]
            if ( ! fnmatch($_class_name, $class_name)) {
                continue;
            }
            foreach ((array) $_storages as $sname => $sinfo) {
                $storages[$sname] = $sinfo;
            }
        }
        $storage = '';
        $loaded_path = '';
        foreach ((array) $storages as $_storage => $v) {
            $_path = (string) $v[0];
            $_prefix = (string) ($v[1] ?? '');
            if (empty($_path)) {
                continue;
            }
            if ($force_storage && $force_storage != $_storage) {
                continue;
            }
            $this->include_module($_path . $_prefix . $class_file);
            if (class_exists($_prefix . $class_name)) {
                $loaded_class_name = $_prefix . $class_name;
                $storage = $_storage;
                $loaded_path = $_path . $_prefix . $class_file;
                break;
            }
        }
        // Try to load classes from db
        if (empty($loaded_class_name) && $this->ALLOW_SOURCE_FROM_DB && is_object($this->db)) {
            $result_from_db = $this->db->query_fetch('SELECT * FROM ' . db('code_source') . ' WHERE keyword="' . _es($class_name) . '"');
            if ( ! empty($result_from_db)) {
                eval($result_from_db['source']);
            }
            if (class_exists($class_name)) {
                $loaded_class_name = $class_name;
                $storage = 'db';
            }
        }
        if (DEBUG_MODE) {
            debug('main_load_class[]', [
                'class_name' => $class_name,
                'loaded_class_name' => $loaded_class_name,
                'loaded_path' => $loaded_path,
                'storage' => $storage,
                'storages' => $storages,
                'time' => microtime(true) - $_time_start,
                'trace' => $this->trace_string(),
            ]);
        }
        return $loaded_class_name;
    }

no_graphics

public function no_graphics($val = null)
    public function no_graphics($val = null)
    {
        if ($val !== null) {
            $this->NO_GRAPHICS = $val;
        }
        return $this->NO_GRAPHICS;
    }

put_data

public function put_data($name = '', $data = [])

Put named data array.

Returns bool

    public function put_data($name = '', $data = [])
    {
        if (empty($this->USE_SYSTEM_CACHE)) {
            return false;
        }
        if ( ! is_object($this->modules['cache'])) {
            return false;
        }
        return $this->modules['cache']->set($name, $data);
    }
public function require_php_lib($name, $params = [])
    public function require_php_lib($name, $params = [])
    {
        return $this->_class('services')->require_php_lib($name, $params);
    }
public function set_module_conf($module_name = '', &$MODULE_OBJ = null, $params = '')

Set module properties from project conf array.

Returns bool

    public function set_module_conf($module_name = '', &$MODULE_OBJ = null, $params = '')
    {
        // Stop here if project config not set or some other things missing
        if (empty($module_name) || ! is_object($MODULE_OBJ)) {
            return false;
        }
        global $PROJECT_CONF, $CONF;
        $module_conf_name = $module_name;
        // Allow to have separate conf entries for admin or user only modules
        if (isset($PROJECT_CONF[MAIN_TYPE . ':' . $module_name])) {
            $module_conf_name = MAIN_TYPE . ':' . $module_name;
        }
        if (isset($PROJECT_CONF[$module_conf_name])) {
            foreach ((array) $PROJECT_CONF[$module_conf_name] as $k => $v) {
                $MODULE_OBJ->$k = $v;
            }
        }
        // Override PROJECT_CONF with specially set CONF (from web admin panel, as example)
        if (isset($CONF[$module_conf_name]) && is_array($CONF[$module_conf_name])) {
            foreach ((array) $CONF[$module_conf_name] as $k => $v) {
                $MODULE_OBJ->$k = $v;
            }
        }
        // Implementation of hook 'init'
        if (method_exists($MODULE_OBJ, $this->MODULE_CONSTRUCT)) {
            $MODULE_OBJ->{$this->MODULE_CONSTRUCT}($params);
        }
        return true;
    }
public function spider_detection()
    public function spider_detection()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if ( ! $this->SPIDERS_DETECTION) {
            return false;
        }
        $_spider_name = conf('SPIDER_NAME');
        if (isset($_spider_name)) {
            return $_spider_name;
        }
        $SPIDER_NAME = $this->modules['common']->_is_spider(($_SERVER['REMOTE_ADDR'] ?? null), ($_SERVER['HTTP_USER_AGENT'] ?? null));
        if (empty($SPIDER_NAME)) {
            if (preg_match('/(bot|spider|crawler|curl|wget)/ims', $SPIDER_NAME)) {
                $SPIDER_NAME = 'Unknown spider';
            }
        }
        if ( ! empty($SPIDER_NAME)) {
            conf('IS_SPIDER', true);
            conf('SPIDER_NAME', $SPIDER_NAME);
        }
        return $SPIDER_NAME;
    }

tasks

public function tasks($allowed_check = false)

Main $_GET tasks handler.

    public function tasks($allowed_check = false)
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        return $this->_class('core_blocks')->tasks($allowed_check);
    }

trace

public function trace()

Simple trace without dumping whole objects.

    public function trace()
    {
        $trace = [];
        foreach (debug_backtrace() as $k => $v) {
            if ( ! $k) {
                continue;
            }
            $v['object'] = isset($v['object']) && is_object($v['object']) ? get_class($v['object']) : null;
            $trace[$k - 1] = $v;
        }
        return $trace;
    }

trace_string

public function trace_string()

Print nice.

    public function trace_string()
    {
        $e = new Exception();
        return implode("\n", array_slice(explode("\n", $e->getTraceAsString()), 1, -1));
    }

try_fast_init

public function try_fast_init()

Micro-framework 'fast_init' inside big YF framework. We use it when some actions need to be done at top speed.

    public function try_fast_init()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if ( ! $this->ALLOW_FAST_INIT) {
            return false;
        }
        global $CONF; // Do not remove this, it is needed for extending fast init

        $paths = [
            'app' => APP_PATH . 'share/fast_init.php',
            'yf' => YF_PATH . 'plugins/fast_init/share/fast_init.php',
        ];
        foreach ($paths as $path) {
            if (file_exists($path)) {
                include_once $path;
                return true;
            }
        }
        return false;
    }

Methods starting with _ hooks and helpers; not routable as page actions

__call

public function __call($name, $args)

Catch missing method call.

    public function __call($name, $args)
    {
        return $this->extend_call($this, $name, $args);
    }

__construct

public function __construct($type = 'user', $no_db_connect = false, $auto_init_all = false, $_conf = [])

Engine constructor Depends on type that is given to it initialize user section or administrative backend.

    public function __construct($type = 'user', $no_db_connect = false, $auto_init_all = false, $_conf = [])
    {
        if ( ! isset($this->_time_start)) {
            $this->_time_start = microtime(true);
        }
        global $CONF;
        // Inject configuration directly, usually inside unit tests
        if ($CONF === null && ! empty($_conf)) {
            $CONF = $_conf;
        }
        if (defined('DEBUG_MODE') && DEBUG_MODE && ($this->ALLOW_DEBUG_PROFILING || ($CONF['main']['ALLOW_DEBUG_PROFILING'] ?? false))) {
            $this->PROFILING = true;
        }
        if (($_SERVER['argc'] ?? null) && ! isset($_SERVER['REQUEST_METHOD'])) {
            $this->CONSOLE_MODE = true;
        }

        define('YF_CLS_EXT', '.class.php');
        define('YF_PREFIX', 'yf_'); // Prefix to the all framework classes
        define('YF_ADMIN_CLS_PREFIX', 'adm__'); // Prefix for the admin files (optional, to inherit user class with the same name)
        define('YF_SITE_CLS_PREFIX', 'site__'); // Prefix for the site files (optional, to inherit project level user class with the same name)

        $this->type = $type; // Initialization type (user or admin)
        define('MAIN_TYPE', $this->type); // Alias
        define('MAIN_TYPE_USER', $this->type == 'user'); // Alias
        define('MAIN_TYPE_ADMIN', $this->type == 'admin'); // Alias
        $this->NO_DB_CONNECT = (bool) $no_db_connect;
        $GLOBALS['main'] = &$this; // To allow links to the incomplete initialized class
        try {
            $this->init_conf_functions();
            $this->_before_init_hook();
            $this->init_constants();
            $this->set_module_conf('main', $this); // // Load project config for self
            $conf_tz = conf('timezone'); // 'Europe/Kiev'
            $conf_tz && date_default_timezone_set($conf_tz);
            $this->init_main_functions();
            $this->error_handler = $this->_class('core_errors');
            $this->init_server_health();
            $this->try_fast_init();
            $this->init_modules_base();
            $this->init_events();
            $this->init_cache();
            $this->init_files();
            $this->init_db();
            $this->init_common();
            $this->_class('graphics');
            $this->load_class_file('module', 'classes/');
            $this->init_site_id();
            $this->init_server_id();
            $this->init_server_role();
            $this->init_settings();
            $this->spider_detection();
            $this->init_session();
            $this->init_locale();
            $this->init_tpl();
            $this->_after_init_hook();
            if ($auto_init_all) {
                $this->init_auth();
                $this->init_content();
            }
            register_shutdown_function([$this, '_framework_destruct']);
        } catch (Exception $e) {
            $msg = 'MAIN: Caught exception: ' . print_r($e->getMessage(), 1) . PHP_EOL . $e->getTraceAsString();
            trigger_error($msg, E_USER_WARNING);
        }
    }
public function _add_shutdown_code($code = '')

Adds code to execute on shutdown.

    public function _add_shutdown_code($code = '')
    {
        if ( ! empty($code)) {
            $this->_SHUTDOWN_CODE_ARRAY[] = $code;
        }
    }
public function _after_init_hook()

Allows to call code here before we begin with graphics.

    public function _after_init_hook()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->events->fire('main.after_init_begin');
        $this->_check_site_maintenance();

        $this->_do_rewrite();

        $this->_init_cur_user_info($this);
        if ($this->TRACK_ONLINE_STATUS) {
            $this->_class('online_users')->process();
        }
        if ($this->type == 'admin' && $this->ENABLE_NOTIFICATIONS_ADMIN) {
            $this->_module('notifications')->_prepare();
        } elseif ($this->type == 'user' && $this->ENABLE_NOTIFICATIONS_USER) {
            $this->_module('notifications')->_prepare();
        }

        if ($this->TRACK_USER_PAGE_VIEWS && $this->USER_ID) {
            $this->_add_shutdown_code(function () {
                if ( ! main()->NO_GRAPHICS) {
                    db()->update_safe('user', ['last_view' => time(), 'num_views' => ++$this->_user_info['num_views']], $this->USER_ID);
                }
            });
        }
        conf('filter_hidden', ($_COOKIE['filter_hidden'] ?? false) ? 1 : 0);
        conf('qm_hidden', ($_COOKIE['qm_hidden'] ?? false) ? 1 : 0);

        $https_needed = $this->USE_ONLY_HTTPS;
        if ( ! $https_needed) {
            $query_string = $this->_server('QUERY_STRING');
            foreach ((array) $this->HTTPS_ENABLED_FOR as $item) {
                if (is_callable($item)) {
                    if ($item($query_string)) {
                        $https_needed = true;
                        break;
                    }
                } elseif (preg_match('@' . $item . '@ims', $query_string)) {
                    $https_needed = true;
                    break;
                }
            }
        }
        if ($https_needed && ! $this->is_console() && ! ($this->_server('HTTPS') || $this->_server('SSL_PROTOCOL'))) {
            $redirect_url = str_replace('http://', 'https://', WEB_PATH) . $this->_server('QUERY_STRING');
            return js_redirect(process_url($redirect_url));
        }
        if ($this->INTRUSION_DETECTION) {
            $this->modules['common']->intrusion_detection();
        }
        $this->events->fire('main.after_init');
    }
public function _before_init_hook()

Allows to call code here before we begin initializing engine parts.

    public function _before_init_hook()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        $this->NO_GRAPHICS = ($GLOBALS['no_graphics'] ?? null);
        $GLOBALS['no_graphics'] = &$this->NO_GRAPHICS;
        if (defined('DEBUG_MODE') && DEBUG_MODE) {
            ini_set('display_errors', 'on');
        }
    }
public function _check_site_maintenance()
    public function _check_site_maintenance()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if (MAIN_TYPE_USER && ! $this->is_console() && ! DEBUG_MODE && conf('site_maintenance')) {
            $this->NO_GRAPHICS = true;
            header('HTTP/1.1 503 Service Temporarily Unavailable');
            header('Status: 503 Service Temporarily Unavailable');
            header('Retry-After: 300');
            echo common()->show_empty_page(tpl()->parse('site_maintenance'));
            exit();
        }
    }

_class

public function _class($name, $path = 'classes/', $params = '')

Alias.

Returns bool|null|yf_main

    public function _class($name, $path = 'classes/', $params = '')
    {
        if ( ! $path) {
            $path = 'classes/';
        }
        return $this->init_class($name, $path, $params);
    }

_class_exists

public function _class_exists($class_name = '', $custom_path = '', $force_storage = '')

Returns bool

    public function _class_exists($class_name = '', $custom_path = '', $force_storage = '')
    {
        $loaded = $this->load_class_file($class_name, $custom_path, $force_storage);
        return (bool) $loaded;
    }

_debug_header

public function _debug_header()

An ajax / htmx answer carries no debug console: under DEBUG_MODE its figures go into an X-YF-Debug header, which the console's htmx tab shows. Called where an answer is sent (yf_tpl::init_graphics(), yf_htmx::_result() / _finish(), yf_api::_send_http_content()); an answer that a module echoes and exits on its own gets none. Once per request, never after the headers went out. Returns the header line sent, or ''.

    public function _debug_header()
    {
        if ( ! defined('DEBUG_MODE') || ! DEBUG_MODE || $this->_debug_header_sent || headers_sent()
            || ( ! conf('IS_AJAX') && ! isset($_SERVER['HTTP_HX_REQUEST']))) {
            return '';
        }
        $this->_debug_header_sent = true;
        $line = $this->_debug_header_line();
        header($line);
        return $line;
    }
public function _debug_header_line()

X-YF-Debug: time so far, db queries, peak memory, PHP messages.

    public function _debug_header_line()
    {
        $db = $GLOBALS['db'] ?? null;
        return 'X-YF-Debug: time=' . round((microtime(true) - $this->_time_start) * 1000, 1) . 'ms; db=' . (is_object($db) ? (int) ($db->NUM_QUERIES ?? 0) : 0)
            . '; mem=' . round(memory_get_peak_usage() / 1048576, 1) . 'MB; php_errors=' . count((array) debug('php_errors'));
    }

_do_rewrite

public function _do_rewrite()

Url rewriting engine init and apply if rewrite is enabled.

    public function _do_rewrite()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if ($this->is_console() || MAIN_TYPE_ADMIN || ! module_conf('tpl', 'REWRITE_MODE')) {
            return false;
        }
        $this->events->fire('main.before_rewrite');
        $host = ($_SERVER['HTTP_HOST'] ?? null);
        $request_uri = ($_SERVER['REQUEST_URI'] ?? null);
        // Override by WEB_PATH
        if (defined('WEB_PATH') && ! $this->web_path_was_not_defined) {
            $w = parse_url(WEB_PATH);
            $w_host = $w['host'];
            $w_port = $w['port'];
            $w_path = $w['path'];
            $host = $w_host . (strlen($w_port ?? '') > 1 ? ':' . $w_port : '') . (strlen($w_path ?? '') > 1 ? $w_path : '');
            if ($w_path != '/' && strpos($request_uri, $w_path) === 0) {
                $request_uri = substr($request_uri, strlen($w_path));
                $request_uri = '/' . ltrim($request_uri, '/');
            }
        }
        if (isset($_GET['host']) && ! empty($_GET['host'])) {
            $host = ($_GET['host'] ?? null);
        }
        list($u) = explode('?', trim($request_uri, '/'));
        $u_arr = explode('/', preg_replace('/\.htm.*/', '', $u));

        $orig_object = ($_GET['object'] ?? null);
        $orig_action = ($_GET['action'] ?? null);

        unset($_GET['object'], $_GET['action']);

        $class_rewrite = $this->_class('rewrite');
        $u_arr = $class_rewrite->_query_route($u_arr, $orig_object, $orig_action);
        $arr = $class_rewrite->REWRITE_PATTERNS['yf']->_parse($host, $u_arr, $_GET, '', $class_rewrite);

        foreach ((array) $arr as $k => $v) {
            if ($k != '%redirect_url%') {
                $_GET[$k] = $v;
            }
        }
        foreach ((array) $_GET as $k => $v) {
            if ($v == '') {
                unset($_GET[$k]);
            }
        }
        if ( ! isset($_GET['action'])) {
            $_GET['action'] = 'show';
        }
        if ( ! $this->is_console() && ! isset($_SESSION['utm_source'])) {
            $utm_source = $_GET['utm_source'] ?? null;
            $utm_source = $utm_source ?? $_POST['utm_source'] ?? null;
            $utm_source = $utm_source ?? $_COOKIE['utm_source'] ?? null;
            if ( ! $utm_source && ($_SERVER['HTTP_REFERER'] ?? false)) {
                $cur_domain = trim(($_SERVER['HTTP_HOST'] ?? ''));
                $ref_domain = trim(parse_url(($_SERVER['HTTP_REFERER'] ?? ''), PHP_URL_HOST));
                if ($ref_domain && $ref_domain != $cur_domain) {
                    $utm_source = $ref_domain;
                }
            }
            if ($utm_source) {
                $_SESSION['utm_source'] = trim(preg_replace('~[^a-z0-9\.\/_@-]~ims', '', strtolower(substr($utm_source, 0, 255))));
            }
        }
        $_SERVER['QUERY_STRING'] = http_build_query((array) $_GET);
        $this->events->fire('main.after_rewrite');
    }

_env

public function _env($key = null, $val = null)
    public function _env($key = null, $val = null)
    {
        return $this->_class('input')->env($key, $val);
    }

_eval_code

public function _eval_code($code_text = '', $as_string = 1)

Evaluate given code as PHP code.

    public function _eval_code($code_text = '', $as_string = 1)
    {
        return eval('return ' . ($as_string ? '"' . $code_text . '"' : $code_text) . ' ;');
    }

_execute

public function _execute($class_name = '', $method_name = '', $method_params = '', $tpl_name = '', $silent = false, $use_cache = false, $cache_ttl = -1, $cache_key_override = '')

Try to return class method output (usually from templates).

Returns bool|string

    public function _execute($class_name = '', $method_name = '', $method_params = '', $tpl_name = '', $silent = false, $use_cache = false, $cache_ttl = -1, $cache_key_override = '')
    {
        $_time_start = null;
        if (DEBUG_MODE) {
            $_time_start = microtime(true);
        }
        $body = $this->call_class_method($class_name, '', $method_name, $method_params, $tpl_name, $silent, $use_cache, $cache_ttl, $cache_key_override);
        if ( ! $body) {
            $body = '';
        }
        $this->events->fire('main.execute', [
            'body' => &$body,
            'args' => func_get_args(),
        ]);
        if (DEBUG_MODE) {
            debug('main_execute_block_time[]', [
                'class' => $class_name,
                'method' => $method_name,
                'params' => $method_params,
                'tpl_name' => $tpl_name,
                'silent' => (int) $silent,
                'size' => strlen(is_array($body) ? implode($body) : $body),
                'time' => round(microtime(true) - $_time_start, 5),
                'trace' => $this->trace_string(),
            ]);
        }
        return $body;
    }
public function _fatal_error_info($error)

Shutdown log line for a fatal error_get_last() array, empty string for anything else.

Returns string

    public function _fatal_error_info($error)
    {
        $fatal = [E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, E_USER_ERROR, E_RECOVERABLE_ERROR];
        if ( ! is_array($error) || ! in_array($error['type'] ?? null, $fatal, true)) {
            return '';
        }
        return '[' . gmdate('Y-m-d H:i:s') . '] [SHUTDOWN] file:' . ($error['file'] ?? '') . ' | ln:' . ($error['line'] ?? '') . ' | msg:' . ($error['message'] ?? '') . PHP_EOL;
    }
public function _filter_object_action()

Filter object and action of $_GET down to module / method names.

    public function _filter_object_action()
    {
        // `?object[]=x` is no name: trim() of an array was an uncaught TypeError
        foreach (['object', 'action'] as $k) {
            isset($_GET[$k]) && ! is_string($_GET[$k]) && $_GET[$k] = '';
        }
        if (($_GET['action'] ?? '') == ($_GET['object'] ?? '')) {
            $_GET['action'] = '';
        }
        $_GET['object'] = str_replace(['yf_', '-'], ['', '_'], preg_replace('/[^a-z_\-0-9]*/', '', strtolower(trim($_GET['object'] ?? ''))));
        $_GET['action'] = str_replace('-', '_', preg_replace('/[^a-z_\-0-9]*/', '', strtolower(trim($_GET['action'] ?? ''))));
        if ( ! ($_GET['action'] ?? null)) {
            $_GET['action'] = defined('DEFAULT_ACTION') ? constant('DEFAULT_ACTION') : 'show';
        }
    }

_find_site

public function _find_site($sites_dir = '')

Search for sites configuration overrides (in subfolder ./sites/).

Returns array

    public function _find_site($sites_dir = '')
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if ( ! $sites_dir) {
            $try_paths = [
                APP_PATH . 'sites/',
                PROJECT_PATH . 'sites/',
            ];
            $sites_dir = '';
            foreach ($try_paths as $try_path) {
                if (file_exists($try_path)) {
                    $sites_dir = $try_path;
                    break;
                }
            }
        }
        if ( ! $sites_dir) {
            return [];
        }
        // Array of sites passed here
        if (is_array($sites_dir)) {
            $dirs = $sites_dir;
        } else {
            if ( ! file_exists($sites_dir)) {
                return [];
            }
            $dirs = array_merge(
                glob($sites_dir . '*', GLOB_ONLYDIR),
                glob($sites_dir . '.*', GLOB_ONLYDIR)
            );
        }
        $sites = $sites1 = $sites2 = [];
        foreach ((array) $dirs as $v) {
            $v = strtolower(basename($v));
            if ($v == '.' || $v == '..') {
                continue;
            }
            if (preg_match('#^([0-9]+\.|:[0-9]+)#', $v)) {
                $sites1[$v] = $v;
            } else {
                $sites2[$v] = $v;
            }
        }
        $sort_by_length = function ($a, $b) {
            return (strlen($a) < strlen($b)) ? +1 : -1;
        };
        uksort($sites1, $sort_by_length);
        uksort($sites2, $sort_by_length);
        $sites = $sites1 + $sites2;
        $found_site = $this->_find_site_path_best_match(
            $sites,
            $_SERVER['SERVER_ADDR'] ?? '',
            $_SERVER['SERVER_PORT'] ?? '',
            $_SERVER['HTTP_HOST'] ?? ''
        );
        return [$found_site, $sites_dir];
    }
public function _find_site_path_best_match($sites, $server_ip, $server_port, $server_host)

Trying to find site matching current environment Examples: 127.0.0.1 192.168. 192.168.1.5 :443 :81 example.com .example.com .dev .example.dev .example.dev:443 .example.dev:81 subdomain. subdomain.:443 sub1.sub2. sub1.sub2.:443.

Returns string

    public function _find_site_path_best_match($sites, $server_ip, $server_port, $server_host)
    {
        $sip = $server_ip ? explode('.', $server_ip) : ['', '', ''];
        $sh = $server_host ? array_reverse(explode('.', $server_host)) : ['', ''];
        $sh2 = $server_host ? explode('.', $server_host) : ['', ''];
        $variants = [
            $server_ip . ':' . $server_port,
            $server_ip,
            $sip[0] . '.' . $sip[1] . '.' . $sip[2] . '.:' . $server_port,
            $sip[0] . '.' . $sip[1] . '.' . $sip[2] . '.',
            $sip[0] . '.' . $sip[1] . '.:' . $server_port,
            $sip[0] . '.' . $sip[1] . '.',
            $sip[0] . '.:' . $server_port,
            $sip[0] . '.',
            $server_host . ':' . $server_port,
            $server_host,
            '.' . $sh[0] . ':' . $server_port,
            '.' . $sh[0],
            '.' . ($sh[1] ?? '') . '.' . $sh[0] . ':' . $server_port,
            '.' . ($sh[1] ?? '') . '.' . $sh[0],
            $sh2[0] . '.' . ($sh2[1] ?? '') . '.:' . $server_port,
            $sh2[0] . '.' . ($sh2[1] ?? '') . '.',
            $sh2[0] . '.:' . $server_port,
            $sh2[0] . '.',
            ':' . $server_port,
        ];
        foreach (array_intersect($sites, $variants) as $sname) {
            return $sname;
        }
        return ''; // Found nothing
    }
public function _framework_destruct()

Framework destructor handler.

    public function _framework_destruct()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        // Restore startup working directory
        chdir($this->_CWD);

        $this->events->fire('main.shutdown');

        if ($this->CATCH_FATAL_ERRORS) {
            $this->_handle_fatal(error_get_last());
        }
        if (isset($this->_SHUTDOWN_CODE_ARRAY)) {
            foreach ((array) $this->_SHUTDOWN_CODE_ARRAY as $_cur_code) {
                $_cur_code();
            }
        }
    }
public function _from_trusted_proxy()

Whether the request came from a trusted proxy: REMOTE_ADDR is in client_utils TRUSTED_PROXIES / conf('TRUSTED_PROXIES'). An empty list trusts nobody.

    public function _from_trusted_proxy()
    {
        if (function_exists('_class') && function_exists('conf')) {
            $utils = _class('client_utils', 'classes/common/');
            if ( ! is_object($utils) || ! method_exists($utils, '_trusted_proxies') || ! method_exists($utils, '_ip_in_list')) {
                return false;
            }
            $trusted = $utils->_trusted_proxies();
        } else {
            // WEB_PATH asks before the helpers and plugins are loaded: read the same settings from the config globals
            $file = YF_PATH . 'plugins/common/classes/common/yf_client_utils.class.php';
            if ( ! class_exists('yf_client_utils', false) && ! is_file($file)) {
                return false;
            }
            class_exists('yf_client_utils', false) || require_once $file;
            $utils = new yf_client_utils();
            $list = ($GLOBALS['PROJECT_CONF']['client_utils']['TRUSTED_PROXIES'] ?? null) ?: ($GLOBALS['CONF']['TRUSTED_PROXIES'] ?? []);
            is_string($list) && $list = explode(',', $list);
            $trusted = [];
            foreach ((array) $list as $item) {
                is_string($item) && trim($item) !== '' && $trusted[] = trim($item);
            }
        }
        return $trusted && $utils->_ip_in_list((string) ($_SERVER['REMOTE_ADDR'] ?? ''), $trusted);
    }

_get

public function _get($key = null, $val = null)
    public function _get($key = null, $val = null)
    {
        return $this->_class('input')->get($key, $val);
    }
public function _get_exec_cache_name($class_name = '', $custom_path = '', $method_name = '', $method_params = '', $tpl_name = '')

Prepare name for call_class_method cache.

    public function _get_exec_cache_name($class_name = '', $custom_path = '', $method_name = '', $method_params = '', $tpl_name = '')
    {
        $params = [
            '[FUNCTION]' => 'call_class_method',
            '[CLASS]' => $class_name,
            '[METHOD]' => $method_name,
            '[LANG]' => defined('DEFAULT_LANG') ? DEFAULT_LANG : conf('language'),
            '[DOMAIN]' => defined('CUR_DOMAIN_LONG') ? constant('CUR_DOMAIN_LONG') : ($_SERVER['HTTP_HOST'] ?? null),
            '[CATEGORY]' => conf('current_category'),
            '[DEBUG]' => (int) DEBUG_MODE,
        ];
        return str_replace(array_keys($params), array_values($params), $this->EXEC_CACHE_NAME_TPL);
    }

_handle_fatal

public function _handle_fatal($error)

The CATCH_FATAL_ERRORS part of the shutdown: log, and answer with the 500 page when ERROR_PAGES is on.

  • $error mixed error_get_last() array
    public function _handle_fatal($error)
    {
        $info = $this->_fatal_error_info($error);
        if ($info === '') {
            return false;
        }
        @file_put_contents(LOGS_PATH . 'fatal_log.txt', $info, FILE_APPEND);
        $ce = $this->error_handler ?? null;
        $error_id = (is_object($ce) && ! empty($ce->ERROR_PAGES)) ? $ce->_error_id() : '';
        if ($error_id) {
            error_log($error_id . ' ' . rtrim($info));
        }
        if (is_object($ce)) {
            $ce->_to_logger('critical', rtrim($info), $error_id ? ['error_id' => $error_id] : []);
        }
        if ($error_id && ! $ce->_is_cli()) {
            $ce->_clean_output_buffers();
            echo $ce->_error_500_page($error_id, $ce->_show_details() ? rtrim($info) : '');
        } else {
            // the message carries file paths: only for developers
            DEBUG_MODE && print $info;
        }
        return true;
    }
public function _host_is_allowed($host, $domains)

Check that host (port, case and trailing dot ignored) is one of the domains.

    public function _host_is_allowed($host, $domains)
    {
        $norm = function ($h) {
            return rtrim(strtolower(preg_replace('/:\d+$/', '', trim((string) $h))), '.');
        };
        $host = $norm($host);
        foreach ((array) $domains as $domain) {
            if ($host !== '' && $host === $norm($domain)) {
                return true;
            }
        }
        return false;
    }
public function _init_cur_user_info(&$obj)
    public function _init_cur_user_info(&$obj)
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), []];
        if (MAIN_TYPE_ADMIN) {
            $obj->USER_ID = (int) ($_GET['user_id'] ?? 0);
            $obj->ADMIN_ID = (int) ($_SESSION['admin_id'] ?? 0);
            $obj->ADMIN_GROUP = (int) ($_SESSION['admin_group'] ?? 0);
        } elseif (MAIN_TYPE_USER) {
            $obj->USER_ID = (int) ($_SESSION['user_id'] ?? 0);
            $obj->USER_GROUP = (int) ($_SESSION['user_group'] ?? 0);
        }
        if (isset($obj->USER_ID) && ! empty($obj->USER_ID)) {
            if ( ! isset($this->_current_user_info)) {
                $this->_current_user_info = user($obj->USER_ID);
            }
            $obj->_user_info = &$this->_current_user_info;
            if ( ! $obj->USER_GROUP) {
                $obj->USER_GROUP = $this->_current_user_info['group'];
            }
        }
        $this->events->fire('main.user_info');
    }
public function _load_data_handlers()

Load common data handlers array from file.

    public function _load_data_handlers()
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if ($this->_data_handlers_loaded) {
            return false;
        }
        $this->data_handlers = [];
        $handlers = [];
        $this->events && $this->events->fire('main.load_data_handlers');

        $suffix = '.php';
        $patterns = [
            'framework' => [
                YF_PATH . 'data_handlers/*' . $suffix,
                YF_PATH . 'plugins/*/data_handlers/*' . $suffix,
                YF_PATH . 'share/data_handlers/*' . $suffix,
                YF_PATH . 'plugins/*/share/data_handlers/*' . $suffix,
            ],
            'app' => [
                APP_PATH . 'data_handlers/*' . $suffix,
                APP_PATH . 'plugins/*/data_handlers/*' . $suffix,
                APP_PATH . 'share/data_handlers/*' . $suffix,
                APP_PATH . 'plugins/*/share/data_handlers/*' . $suffix,
            ],
        ];
        $strlen_suffix = strlen($suffix);
        $handlers = [];
        foreach ($patterns as $gname => $paths) {
            foreach ($paths as $path) {
                foreach (glob($path) as $matchedPath) {
                    $name = substr(basename($matchedPath), 0, -$strlen_suffix);
                    $handlers[$name] = $matchedPath;
                }
            }
        }
        $aliases = [
            'category_sets' => 'cats_blocks',
            'sys_sites' => 'sites',
            'sys_servers' => 'servers',
        ];
        foreach ((array) $aliases as $from => $to) {
            $handlers[$from] = $handlers[$to];
        }
        $this->data_handlers = $handlers;

        $this->_data_handlers_loaded = true;
        return $this->data_handlers;
    }

_module

public function _module($name, $params = '')

Alias.

Returns bool|null|yf_main

    public function _module($name, $params = '')
    {
        return $this->init_class($name, '', $params);
    }

_post

public function _post($key = null, $val = null)
    public function _post($key = null, $val = null)
    {
        return $this->_class('input')->post($key, $val);
    }
public function _preload_plugins_list($force = false)

Returns array

    public function _preload_plugins_list($force = false)
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        if (isset($this->_plugins) && ! $force) {
            return $this->_plugins;
        }
        $white_list = $this->_plugins_white_list ?? [];
        $black_list = $this->_plugins_black_list ?? [];
        // Order matters for plugins_classes !!
        $sets = [
            'framework' => YF_PATH . 'plugins/*/',
            'app' => APP_PATH . 'plugins/*/',
        ];
        $_plen = strlen(YF_PREFIX);
        $plugins = [];
        $plugins_classes = [];
        $ext = YF_CLS_EXT; // default is .class.php
        foreach ((array) $sets as $set => $pattern) {
            foreach ((array) glob($pattern, GLOB_ONLYDIR | GLOB_NOSORT) as $d) {
                $pname = basename($d);
                if ($white_list && wildcard_compare($white_list, $pname)) {
                    // result is good, do not check black list if name found here, inside white list
                } elseif ($black_list && wildcard_compare($black_list, $pname)) {
                    // Do not load files from this plugin
                    break;
                }
                $dlen = strlen($d);
                $classes = [];
                $patterns = [
                    $d . '*' . $ext,
                    $d . '*/' . '*' . $ext,
                    $d . '*/*/' . '*' . $ext,
                ];
                $classes = [];
                foreach ($patterns as $pattern) {
                    foreach (glob($pattern) as $f) {
                        $cname = str_replace($ext, '', basename($f));
                        $cdir = dirname(substr($f, $dlen)) . '/';
                        if (strpos($cname, YF_PREFIX) === 0) {
                            $cname = substr($cname, $_plen);
                        }
                        $classes[$cname][$cdir] = $f;
                        $plugins_classes[$cname] = $pname;
                    }
                }
                $plugins[$pname][$set] = $classes;
            }
        }
        ksort($plugins);
        $this->_plugins = $plugins;
        ksort($plugins_classes);
        $this->_plugins_classes = $plugins_classes;
        return $this->_plugins;
    }
public function _replace_core_paths($str)

Unified method to replace core paths inside configuration directives. Examples: YF_PATH, {YF_PATH}, %YF_PATH%.

    public function _replace_core_paths($str)
    {
        if (strpos($str, '_PATH') === false) {
            return $str;
        }
        if (empty($this->_paths_replace_pairs)) {
            $pairs = [];
            // Note: order matters
            $path_names = [
                'ADMIN_WEB_PATH',
                'ADMIN_SITE_PATH',
                'UPLOADS_PATH',
                'WEB_PATH',
                'MEDIA_PATH',
                'YF_PATH',
                'APP_PATH',
                'PROJECT_PATH',
                'SITE_PATH',
                'CONFIG_PATH',
                'STORAGE_PATH',
                'LOGS_PATH',
            ];
            foreach ($path_names as $name) {
                $val = constant($name);
                $pairs[$name] = $val; // Example: YF_PATH
                $pairs['{' . $name . '}'] = $val; // Example: {YF_PATH}
                $pairs['%' . $name . '%'] = $val; // Example: %YF_PATH%
            }
            $this->_paths_replace_pairs = $pairs;
            unset($pairs);
        }
        return str_replace(array_keys($this->_paths_replace_pairs), $this->_paths_replace_pairs, $str);
    }
public function _send_main_headers($content_length = 0)

Send main headers.

    public function _send_main_headers($content_length = 0)
    {
        $this->PROFILING && $this->_timing[] = [microtime(true), __CLASS__, __FUNCTION__, $this->trace_string(), func_get_args()];
        return $this->_class('graphics')->_send_main_headers($content_length);
        $this->events->fire('main.http_headers');
    }

_server

public function _server($key = null, $val = null)
    public function _server($key = null, $val = null)
    {
        return $this->_class('input')->server($key, $val);
    }

_session

public function _session($key = null, $val = null)
    public function _session($key = null, $val = null)
    {
        return $this->_class('input')->session($key, $val);
    }
public function _strip_quotes_recursive($mixed)

Recursive method for stripping quotes from given data (string or array).

Returns array|string

    public function _strip_quotes_recursive($mixed)
    {
        if (is_array($mixed)) {
            return array_map([$this, __FUNCTION__], $mixed);
        }
        return stripslashes($mixed);
    }