Initial commit

This commit is contained in:
Ivan Petrov
2025-12-24 19:19:01 +03:00
commit a7097c6178
19493 changed files with 94306 additions and 0 deletions

110
engine/Main/trait.admin.php Normal file
View File

@@ -0,0 +1,110 @@
<?php
defined('ROOT_DIR') || exit;
trait Admin {
public array $admin_pages = array();
public array $admin_pages_list = array();
public function admin_page_set($parent_slug, $page_slug, $page_title, $params, $function, $hide = false, $icon = false)
{
if(!isset($params)) $params = array();
$params["page"] = $page_slug;
if($parent_slug && isset($this->admin_pages_list[$parent_slug])) {
$parent = $this->admin_pages_list[$parent_slug];
$link = &$parent["link"];
$parent_level = $link["level"];
$page_info = array(
"level" => $parent_level + 1,
"title" => $page_title,
"function" => $function,
"pages" => array(),
"params" => $params,
"hide" => $hide,
"icon" => $icon,
"slug" => $page_slug
);
$link["pages"][$page_slug] = $page_info;
$page_info["link"] = &$link["pages"][$page_slug];
} else {
$page_info = array(
"level" => 0,
"title" => $page_title,
"function" => $function,
"pages" => array(),
"params" => $params,
"hide" => $hide,
"icon" => $icon,
"slug" => $page_slug
);
$this->admin_pages[$page_slug] = $page_info;
$page_info["link"] = &$this->admin_pages[$page_slug];
}
$this->admin_pages_list[$page_slug] = $page_info;
}
// Проверить есть ли у страницы дочерний элемент по с нужной подстрокой
public function admin_page_has_search($parent_slug, $search): bool
{
if(!$search) return true;
$parent_page = $this->admin_pages_list[$parent_slug];
$parent_page_link = &$parent_page["link"];
if(mb_strpos(mb_strtolower($parent_page["title"]), mb_strtolower($search)) !== false) return true;
return $this->admin_page_has_search_recurse($parent_page_link["pages"], $search);
}
// Рекурсивная функция проверки дочерних элементов для поиска подстроки
private function admin_page_has_search_recurse($pages, $search): bool
{
foreach ($pages as $key => $page) {
if(mb_strpos(mb_strtolower($page["title"]), mb_strtolower($search)) !== false) return true;
$result = $this->admin_page_has_child_recurse($page["pages"], $search);
if($result === true) return true;
}
return false;
}
// Проверить есть ли у страницы дочерний элемент
public function admin_page_has_child($parent_slug, $page_slug): bool
{
$parent_page = &$this->admin_pages_list[$parent_slug]["link"];
if($parent_slug == $page_slug) return true;
return $this->admin_page_has_child_recurse($parent_page["pages"], $page_slug);
}
// Рекурсивная функция проверки дочерних элементов
private function admin_page_has_child_recurse($pages, $page_slug): bool
{
foreach ($pages as $key => $page) {
if($key === $page_slug) return true;
$result = $this->admin_page_has_child_recurse($page["pages"], $page_slug);
if($result === true) return true;
}
return false;
}
// Отрисовка страницы в админ панели
public function admin_page_render($slug, $dive = false): bool
{
$page = $this->admin_pages_list[$slug];
if(!isset($page)) return false;
$link = &$page["link"];
if($page["level"] == 0 && $dive === true)
return $this->admin_page_render(array_shift($link["pages"])["slug"]);
if(is_callable($page["function"])) {
$page["function"]();
return true;
}
$func_name = $page["function"];
$func_body = $GLOBALS[$func_name];
$func_body();
return true;
}
}

View File

@@ -0,0 +1,50 @@
<?php
// Работа с уведомлениями
defined('ROOT_DIR') || exit;
trait Alerts {
// Получить список уведомлений
public function alerts_get_list($group = "main")
{
$session_name = $this->session_get_name();
$alerts = $this->db_query("SELECT * FROM `bive_alerts` WHERE `session` = ? AND `is_read` = 0 AND `group` = ?", array($session_name, $group), false);
if (!count($alerts)) return false;
$this->alerts_read_all($group);
return $alerts;
}
// Добавить уведомление
public function alerts_add($message, $type = "notice", $group = "main")
{
$session_name = $this->session_get_name();
$this->db_query("INSERT INTO `bive_alerts`(`session`, `message`, `type`, `group`) VALUES (?, ?, ?, ?)", array($session_name, $message, $type, $group), true);
}
// Пометить все уведомления как прочитанные
public function alerts_read_all($group = "main")
{
$session_name = $this->session_get_name();
$this->db_query("UPDATE `bive_alerts` SET `is_read` = 1 WHERE `session` = ? AND `is_read` = 0 AND `group` = ?", array($session_name, $group), true);
}
public function alerts_view($group = "main"): bool
{
$alerts = $this->alerts_get_list($group);
if(!$alerts) return false;
$alerts_dom = new DOM("div");
$alerts_dom->setAttribute("class", "b_alerts");
foreach ($alerts as $key => $alert) {
$alert_dom = new DOM("div");
$alert_dom->setAttribute("class", "b_alert " . $alert["type"]);
$alert_dom->prepend($alert["message"]);
$alerts_dom->prepend($alert_dom);
}
$alerts_dom->view();
return true;
}
}

View File

@@ -0,0 +1,133 @@
<?php
// Работа с выводом содержимого пользователям
defined('ROOT_DIR') || exit;
trait Content {
private array $meta_tags = array();
private array $link_tags = array();
private array $script_tags = array();
private string $title = "Bive Engine";
// олучить значение заголовка
public function title_get(): string
{
return $this->title;
}
// Поместить значение заголовка
public function title_set($title): bool
{
$this->title = $title;
return true;
}
// Добавить мета тег
public function meta_add($name, $content): bool
{
$this->meta_tags[$name] = $content;
return true;
}
// Удалить значение
public function meta_remove($name): bool
{
if(!isset($this->meta_tags[$name])) return false;
unlink($this->meta_tags[$name]);
return true;
}
// Рендер мета тегов
public function meta_render()
{
$meta_dom = new DOM("meta", false);
$meta_dom->setAttribute("charset", "utf-8");
echo $meta_dom->render();
foreach ($this->meta_tags as $key => $value) {
$meta_dom = new DOM("meta", false);
$meta_dom->setAttribute("name", $key);
$meta_dom->setAttribute("content", $this->get_view($value));
echo $meta_dom->render();
}
}
// Добавить тег Link
public function link_add($params): bool
{
if(gettype($params) != "array") return false;
$this->link_tags[] = $params;
return true;
}
// Отрендерить теги типа Link
public function link_render()
{
foreach ($this->link_tags as $key => $link_params) {
$link_dom = new DOM("link", false);
foreach ($link_params as $index => $value){
$link_dom->setAttribute($index, $value);
}
echo $link_dom->render();
}
}
// Подключить CSS скрипт
public function css_style_connect($path): bool
{
if(!$path) return false;
$this->link_add(array("rel" => "stylesheet", "href" => $path));
return true;
}
// Добавить тег Script
public function script_add($params): bool
{
if(gettype($params) != "array") return false;
$this->script_tags[] = $params;
return true;
}
// Отрендерить теги типа Script
public function script_render()
{
foreach ($this->script_tags as $key => $scripts_params) {
$scripts_dom = new DOM("script");
foreach ($scripts_params as $index => $value){
$scripts_dom->setAttribute($index, $value);
}
echo $scripts_dom->render();
}
}
// Безопасно выводит информацию
function view($text): bool
{
echo $this->get_view($text);
return true;
}
// Получить строку для безопасного использования
function get_view($text): string
{
return htmlspecialchars($text);
}
// Склонение слова в зависимости от числа
function pluralize($num, $words) {
$num = abs($num) % 100;
if ($num > 10 && $num < 20) {
return $words[2];
} else {
$i = $num % 10;
if ($i == 1) {
return $words[0];
} elseif (in_array($i, array(2, 3, 4))) {
return $words[1];
} else {
return $words[2];
}
}
}
}

View File

@@ -0,0 +1,34 @@
<?php
// Работа с базой данных
defined('ROOT_DIR') || exit;
require ENGINE_DIR . SLASH . "class.database.php";
trait Database {
private DB $db_class;
public function db_touch()
{
$this->db_class = new DB(DB_HOST, DB_NAME, DB_USER, DB_PASS);
$this->db_class->connect();
}
// Запрос на получение информации из базы
public function db_query($query, $params = array(), $new = false)
{
$ls_key = $query . json_encode($params);
if(!$new && $this->ls_has_key($ls_key))
return $this->ls_get_key($ls_key);
$result = $this->db_class->query($query, $params);
$this->ls_set_key($ls_key, $result);
return $result;
}
// Запрос на сохранение данных в базу
public function db_insert($query, $params)
{
return $this->db_class->insert($query, $params);
}
}

View File

@@ -0,0 +1,54 @@
<?php
// Работа с типами данных
defined('ROOT_DIR') || exit;
trait Datatypes {
public array $datatypes = array();
// Загрузка типов данных
public function datatype_load(): bool
{
$datatypes_dir = PLAYAREA_DIR_NAME . SLASH . "datatypes";
$datatypes = scandir($datatypes_dir, SCANDIR_SORT_DESCENDING);
if(!count($datatypes)) return false;
foreach ($datatypes as $key => $value) {
$name = $this->datatype_convert_name($value);
if(!$name) continue;
require_once $datatypes_dir . SLASH . $value;
$classes = get_declared_classes();
$class_name = end($classes);
$this->datatypes[] = $class_name;
}
return true;
}
private function datatype_convert_name($name): string
{
$parts = explode('.', $name);
if($parts[0] != "datatype" || !isset($parts[1])) return false;
return trim($parts[1]);
}
// Получить Объект по ID
public function get_item_by_id($item_id)
{
$search = new Search(array(
"limit" => 1,
"terms" => array("item_id" => $item_id)
));
$items = $search->collect();
if(!count($items)) return false;
list($item) = $items;
return $item;
}
// Получить Class объекта по ID
public function get_item_class_by_id($item_id)
{
$item = $this->get_item_by_id($item_id);
if($item === false) return false;
return $item->get_class_name();
}
}

View File

@@ -0,0 +1,90 @@
<?php
// Работа с отслеживанием данных
defined('ROOT_DIR') || exit;
trait Events {
private array $events = array();
// Добавить функцию в Событие
public function event_add($name, $function_name, $weight = 10, $lock = false): bool
{
$event_name = strtolower($name);
$this->event_create($name);
if($this->events[$event_name]["lock"]) return false;
if($lock) $this->events[$event_name]["events"] = array();
$this->events[$event_name]["events"][] = array("function_name" => $function_name, "weight" => $weight);
$this->events[$event_name]["lock"] = $lock;
return true;
}
// Запустить Событие
public function event_start($name, $args = array())
{
$event_name = strtolower($name);
$this->event_create($name);
if(!is_array($this->events[$event_name])) return false;
$events = $this->events[$event_name]["events"];
if($this->events[$event_name]["lock"]) {
$func_name = $events[0]["function_name"];
if(is_callable($func_name)) {
return $func_name(...$args);
}
if(!function_exists($func_name)) return false;
return $func_name(...$args);
}
$results = array();
foreach ($events as $key => $event) {
$func_name = $event["function_name"];
if(is_callable($func_name)) {
$results[] = $func_name(...$args);
} else {
if(!function_exists($func_name)) return false;
$results[] = $func_name(...$args);
}
}
return $results;
}
// Поймать Событие
public function event_form_capture(): bool
{
$values = array_replace_recursive($_GET, $_POST);
foreach ($_FILES as $key => $field) {
$file = $this->files_field_formate($key);
if($file === false) continue;
if(isset($values[$key])) $values[$key] = array_replace_recursive($values[$key], $file);
else $values[$key] = $file;
}
if(!isset($values["b_event"])) return false;
$this->event_start($values["b_event"], array($values));
return true;
}
// Создать Событие для формы
public function event_form($name)
{
$meta_dom = new DOM("input", false);
$meta_dom->setAttribute("type", "hidden");
$meta_dom->setAttribute("name", "b_event");
$meta_dom->setAttribute("value", $name);
echo $meta_dom->render();
}
// Создать Событие
private function event_create($name): bool
{
if(isset($this->events[$name])) return true;
$this->events[$name] = array();
$this->events[$name]["events"] = array();
return true;
}
}

View File

@@ -0,0 +1,48 @@
<?php
// Работа с полями для данных
defined('ROOT_DIR') || exit;
trait Fields {
public array $fields = array();
public function field_register($key, $field): bool
{
$this->fields[$key] = $field;
return true;
}
public function field_render_edit($key, $name, $content = "")
{
$field = $this->field_get($key);
if(!$field) return "";
$field->set_name($name);
$field->set_content($content);
$field->render_edit();
}
public function field_render_value($key, $name, $content = "")
{
$field = $this->field_get($key);
if(!$field) return "";
$field->set_name($name);
$field->set_content($content);
return $field->render_value();
}
public function field_render_db_value($key, $name, $value = "", $old_value = "")
{
$field = $this->field_get($key);
if(!$field) return "";
$field->set_name($name);
$field->set_content($value);
return $field->render_db_value($old_value);
}
public function field_get($name)
{
if(!isset($this->fields[$name])) return false;
return $this->fields[$name];
}
}

121
engine/Main/trait.files.php Normal file
View File

@@ -0,0 +1,121 @@
<?php
// Работа с файлами
defined('ROOT_DIR') || exit;
trait Files {
// Получить файл по ID
public function file_get($file_id)
{
$keys = $this->db_query("SELECT * FROM `bive_files` WHERE `id` = ?", array($file_id), true);
if(!count($keys)) return false;
return $keys[0];
}
// Удалить файл по его ID
public function file_delete($file_id): bool
{
$db_file = $this->file_get($file_id);
if(!$db_file) return false;
$file_path = ROOT_DIR . SLASH . STORAGE_DIR_NAME . "/files/" . $db_file["file_name"];
unlink($file_path);
$this->db_query("DELETE FROM `bive_files` WHERE `id` = ?", array($file_id), true);
return true;
}
// Проверить есть ли файл по его ID
public function file_has($file_id): bool
{
$db_file = $this->file_get($file_id);
if($db_file === false) return false;
$file_path = ROOT_DIR . SLASH . STORAGE_DIR_NAME . "/files/" . $db_file["file_name"];
return file_exists($file_path);
}
// Получить ссылку на файл по ID
public function file_get_link($file_id)
{
$db_file = $this->file_get($file_id);
if($db_file === false) return false;
return $this->router_get_root_uri() . "/" . STORAGE_DIR_NAME . "/files/" . $db_file["file_name"];
}
// Сохранить файл и вернуть его ID в базе
public function files_save($file, $max_size = 5242880, $file_types = array("jpeg", "jpg", "png", "svg", "webp"))
{
if(!isset($file) || $file["error"] != 0) return false;
$storage = $this->get_storage_dir();
$file_name = $file["name"];
$file_size = $file["size"];
$file_type = strtolower(pathinfo(SLASH . $file_name, PATHINFO_EXTENSION));
if ($file_size > $max_size) {
$this->alerts_add("Размер файла превышает минимально допустимый.", "error", "file");
return false;
}
$db_name = $this->files_create_name() . "." . $file_type;
$targetDir = $storage . SLASH . "files" . SLASH; // Директория для сохранения загруженных файлов
$targetFile = $targetDir . basename($db_name); // Полный путь до файла
if(!in_array($file_type, $file_types)) {
$this->alerts_add("Недопустимое расширение файла.", "error", "file");
return false;
}
if (move_uploaded_file($file["tmp_name"], $targetFile)) {
return $this->files_db_add($db_name, $file_size, $file_type, $targetFile);
} else {
$this->alerts_add("Произошла ошибка при загрузке файла.", "error", "file");
return false;
}
}
// Сохранить файлы по имени поля
public function files_save_by_name($name, $max_size = 5242880, $file_types = array("jpeg", "jpg", "png", "svg", "webp"))
{
if(!isset($_FILES[$name]) || $_FILES[$name]["error"] != 0) return false;
return $this->files_save($_FILES[$name], $max_size, $file_types);
}
// Добавление файла в базу данных
public function files_db_add($file_name, $weight, $mime_type, $path)
{
global $b;
return $b->db_insert("INSERT INTO `bive_files`(`path`, `mime_type`, `weight`, `file_name`) VALUES (?, ?, ?, ?)", array($path, $mime_type, $weight, $file_name));
}
// Форматирование файлов под поле
public function files_field_formate($name)
{
$file = $_FILES[$name];
if(!isset($file)) return false;
if(is_string($file["name"])) return $file;
$fields = array();
$this->files_field_formate_recurse($file, $fields);
return $fields;
}
// Рекурсивная функция форматирования файлов
private function files_field_formate_recurse($files_array, &$fields, $prop = null)
{
foreach ($files_array as $prop_key => $prop_value) {
if(is_array($prop_value)){
if($prop) $this->files_field_formate_recurse($prop_value,$fields[$prop_key], $prop);
else $this->files_field_formate_recurse($prop_value,$fields, $prop_key);
} else {
$fields[$prop_key][$prop] = $prop_value;
}
}
}
// Рандомное название для файла
public function files_create_name()
{
return bin2hex(random_bytes(16));
}
}

View File

@@ -0,0 +1,41 @@
<?php
defined('ROOT_DIR') || exit;
// Локальное хранилище
// Служит для хранения информации в рамках одного запроса
trait LocalStorage {
private array $key_value = array();
// Получить значение по ключу
public function ls_get_key($key)
{
return $this->key_value[md5($key)];
}
// Записать значение по ключу
public function ls_set_key($key, $value)
{
return $this->key_value[md5($key)] = $value;
}
// Есть ли ключ
public function ls_has_key($key): bool
{
return isset($this->key_value[md5($key)]);
}
// Получить длину локального хранилища
public function ls_get_size(): int
{
return count($this->key_value);
}
// Удалить ключ
public function ls_remove_key($key): bool
{
unlink($this->key_value[md5($key)]);
return true;
}
}

View File

@@ -0,0 +1,39 @@
<?php
// Работа с путями
defined('ROOT_DIR') || exit;
trait Path
{
// Получить директорию движка
public function get_engine_path(): string
{
$r = $this->get_root_dir();
return $r . "/" .ENGINE_DIR_NAME;
}
// Получить корневую директорию
function get_root_dir(): string
{
return ROOT_DIR;
}
// Получить директорию хранилища
function get_storage_dir(): string
{
return ROOT_DIR . SLASH . STORAGE_DIR_NAME;
}
// Получить директорию пользовательского контента
function get_playarea_dir(): string
{
return ROOT_DIR . SLASH . PLAYAREA_DIR_NAME;
}
// Получить директорию со скриптами
function get_scripts_dir(): string
{
return $this->get_playarea_dir() . SLASH . "scripts";
}
}

View File

@@ -0,0 +1,17 @@
<?php
// Работа с песочницей
defined('ROOT_DIR') || exit;
trait PlayArea {
public function pa_connect_main(){
require_once $this->get_playarea_dir() . SLASH . "main.php";
}
// Получить папку с ассетами
public function pa_get_assets_dir(){
$root = $this->router_get_root_uri();
return $root . SLASH . PLAYAREA_DIR_NAME . SLASH . 'assets' . SLASH;
}
}

View File

@@ -0,0 +1,90 @@
<?php
// Работа с плагинами
defined('ROOT_DIR') || exit;
trait Plugins {
public array $plugins = array();
// Загрузка всех плагинов системы
public function plugins_load(): bool
{
$plugins_dir = $this->plugins_get_dir();
$plugins = scandir($plugins_dir, SCANDIR_SORT_DESCENDING);
if(!count($plugins)) return false;
foreach ($plugins as $key => $plugin_dir)
$this->plugin_load($plugin_dir);
return true;
}
// Загрузка плагина
public function plugin_load($plugin_dir){
global $b;
if($this->plugins[$plugin_dir]) return;
$plugins_dir = $this->plugins_get_dir();
$plugin_path = $plugins_dir . SLASH . $plugin_dir . SLASH;
$plugin_manifest_path = $plugin_path . "manifest.yaml";
// Проверка наличия manifest.yaml
if(!file_exists($plugin_manifest_path)) return;
$manifest = $this->yaml_read($plugin_manifest_path);
$plugin_script_path = $plugin_path . $manifest["plugin_script"];
// Подгрузка зависимостей
if(isset($manifest["plugin_dependencies"])) {
foreach ($manifest["plugin_dependencies"] as $key => $plugin_dependence) {
$this->plugin_load($plugin_dependence);
}
}
// Проверка наличия исполняемого скрипта
if(!file_exists($plugin_script_path)) return;
$plugin_class = $this->plugin_register($manifest, $plugin_dir);
$this->ls_set_key("plugin", $plugin_class);
require_once $plugin_script_path;
}
// Получить текущий плагин
public function plugin_get()
{
return $this->ls_get_key("plugin");
}
// Регистрация плагина
public function plugin_register($manifest, $plugin_dir)
{
$plugin_class = $this->plugin_create_class($manifest, $plugin_dir);
$this->plugins[$plugin_dir] = array(
"plugin_name" => $manifest["plugin_name"],
"plugin_description" => $manifest["plugin_description"],
"plugin_author" => $manifest["plugin_author"],
"plugin_version" => $manifest["plugin_version"],
"class" => $plugin_class
);
return $plugin_class;
}
// Функция создания класса плагина
public function plugin_create_class($manifest, $plugin_dir)
{
$plugin_class_name = $manifest["plugin_class"] ?? "Plugin";
return new $plugin_class_name($plugin_dir);
}
// Получить папку где хранятся плагины
public function plugins_get_dir(): string
{
return ROOT_DIR . SLASH . PLAYAREA_DIR_NAME . SLASH . "plugins";
}
// Прочитать конфигурацию YAML
public function yaml_read($filePath)
{
if (!extension_loaded('yaml'))
die('Расширение YAML не установлено.');
$ymlContent = file_get_contents($filePath);
return yaml_parse($ymlContent);
}
}

View File

@@ -0,0 +1,194 @@
<?php
// Работа с адресной строкой
defined('ROOT_DIR') || exit;
trait Router {
private array $routerList = array();
private $fun_not_found;
// Получить адрес
public function router_get_uri()
{
return parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
}
// Регистрация роутера
public function router_add($page, $func, $methods = array("GET", "POST"))
{
$type = 'function';
if(gettype($func) == 'string') {
if(substr($func, strlen($func) - strlen(".php")) == ".php") $type = 'template';
else $type = 'function_name';
}
$this->routerList[] = array(
"page" => $page,
"func" => &$func,
"type" => $type,
"methods" => $methods
);
}
// Получение списка роутов
private function router_get_list(): array
{
return $this->routerList;
}
// Получить сегменты адреса
public function router_get_segments()
{
$uri = $this->router_get_uri();
return explode('/', trim($uri, '/'));
}
// Получить сегмент адреса
public function router_get_segment($segment_num)
{
$segments = $this->router_get_segments();
return $segments[$segment_num];
}
// Определить функцию не найденной страницы
public function router_set_not_found($fun)
{
$this->fun_not_found = &$fun;
}
// Когда страница не найдена
private function router_not_found()
{
http_response_code(404);
if(empty($this->fun_not_found))
echo "not found";
$fun = $this->fun_not_found;
$fun();
}
// Запускаем сканирование
public function router_init()
{
$uri = $this->router_get_uri();
$list = $this->router_get_list();
$method = $this->router_get_method();
foreach ($list as $key => $item) {
if(!in_array($method, $item["methods"], true)) continue;
if(substr($item["page"], -1) == "%"){
$clear_uri = substr($item["page"], 0, -1);
if(strpos($uri, $clear_uri) === 0) {
$this->event_start(base64_encode($item["page"]));
if($item["type"] == "template")
return $this->template_load($item["func"], array(), true);
return $item["func"]();
}
} else if ($uri == $item["page"]) {
$this->event_start(base64_encode($item["page"]));
if($item["type"] == "template")
return $this->template_load($item["func"], array(), true);
return $item["func"]();
}
}
$this->router_not_found();
return true;
}
// Получить метод запроса
public function router_get_method(): string
{
return strtolower($_SERVER['REQUEST_METHOD']);
}
// Получить текущий протокол
public function router_get_protocol(): string
{
if (
isset($_SERVER['REQUEST_SCHEME']) &&
($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' ||
isset($_SERVER['REQUEST_SCHEME']) &&
$_SERVER['REQUEST_SCHEME'] == "https"
) return "https";
return "http";
}
// Получить корневой адрес сайта
public function router_get_root_uri(): string
{
$protocol = $this->router_get_protocol();
return $protocol . "://" . $_SERVER['HTTP_HOST'];
}
// Получить канонический адрес
public function router_get_canonical_uri(): string
{
$canonical_link = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
return $this->router_get_root_uri() . $canonical_link;
}
// Получить полный адрес
public function router_get_full_uri(): string
{
return ((!empty($_SERVER['HTTPS'])) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
// Выполнить редирект на другой адрес
public function router_redirect($path)
{
$root = $this->router_get_root_uri();
header("Location: $root$path");
}
// Выполнить редирект на эту же страницу чтобы очистить POST
public function router_refresh()
{
$current_path = $_SERVER['REQUEST_URI'];
$this->router_redirect($current_path);
}
// Получить ссылку с измененными GET параметрами
public function router_format_get_params($params, $split = false, $exclude = array()): string
{
$string = "?";
$params_list = array();
$params = $this->router_edit_get_params($params, $split, $exclude);
foreach ($params as $key => $value)
$params_list[] = $key . "=" . $value;
return $string . implode("&", $params_list);
}
// Соединить GET параметры со значениями массива
public function router_edit_get_params($params, $split = false, $exclude = array())
{
$current_params = $_GET;
if($split) $params = array_merge($current_params, $params);
foreach ($exclude as $key => $value) unset($params[$value]);
return $params;
}
// Заполнить форму невидимыми полями по переданному массиву
public function router_params_to_form($params, $exclude = array(), $prefix = "", $nested = false)
{
foreach ($params as $key => $value) {
if(in_array($key, $exclude)) continue;
if(is_array($value)) {
if($nested) $this->router_params_to_form($value, $exclude = array(), $prefix . "[". $key . "]", true);
else $this->router_params_to_form($value, $exclude = array(), $prefix . $key, true);
continue;
}
if($nested) $this->router_get_hidden_input($prefix . "[" . $key . "]", $value, $prefix);
else $this->router_get_hidden_input($prefix . $key, $value, $prefix);
}
}
// Добавить невидимое поле на страницу
private function router_get_hidden_input($name, $value, $prefix = "")
{
$meta_dom = new DOM("input", false);
$meta_dom->setAttribute("type", "hidden");
$meta_dom->setAttribute("name", $prefix . $this->get_view($name));
$meta_dom->setAttribute("value", $this->get_view($value));
$meta_dom->view();
}
}

View File

@@ -0,0 +1,43 @@
<?php
// Работа с сессиями
defined('ROOT_DIR') || exit;
trait Sessions {
// Создать сессию для посетителя
public function session_create()
{
if(isset($_COOKIE["b_session"])) return true;
$session_id = bin2hex(random_bytes(16));
setcookie('b_session', $session_id, time() + (30 * 24 * 60 * 60), '/', '', SESSION_SECURE, true);
$_COOKIE["b_session"] = $session_id;
return $session_id;
}
// Получить значение сессии
public function session_get_name()
{
$session_name = $_COOKIE["b_session"];
if(!isset($session_name)) return $this->session_create();
return $session_name;
}
// Получить значение сессии
public function session_get($key)
{
$session_name = $this->session_get_name();
$keys = $this->db_query("SELECT * FROM `bive_session` WHERE `session` = ? AND `key` = ?", array($session_name, $key), true);
if(!isset($keys[0])) return false;
return $keys[0]["value"];
}
// Сохранить значение сессии
public function session_set($key, $value)
{
$session_name = $this->session_get_name();
$old_value = $this->session_get($key);
if($old_value === false) return $this->db_query("INSERT INTO `bive_session`(`session`, `key`, `value`) VALUES (?, ?, ?)", array($session_name, $key, $value), true);
return $this->db_query("UPDATE `bive_session` SET `value` = ? WHERE `session` = ? AND `key` = ?", array($value, $session_name, $key), true);
}
}

View File

@@ -0,0 +1,63 @@
<?php
// Работа с настройками BiveEngine
defined('ROOT_DIR') || exit;
trait Settings {
public array $setting_list = array();
public function setting_register($setting_key, $title, $field_key): string
{
$this->setting_list[$setting_key] = array("title" => $title, "field_key" => $field_key);
return $setting_key;
}
public function setting_get($setting_key)
{
$keys = $this->db_query("SELECT `value` FROM `bive_settings` WHERE `setting_key` = ?", array($setting_key), true);
if(!isset($keys[0])) return false;
return $keys[0]["value"];
}
public function setting_get_value($setting_key)
{
$value = $this->setting_get($setting_key);
if($value === false) return false;
$field_key = $this->setting_get_field($setting_key);
if($field_key === false) return false;
return $this->field_render_value($field_key, $setting_key, $value);
}
public function setting_get_field($setting_key)
{
if(!isset($this->setting_list[$setting_key])) return false;
return $this->setting_list[$setting_key]["field_key"];
}
public function setting_get_title($setting_key)
{
if(!isset($this->setting_list[$setting_key])) return false;
return $this->setting_list[$setting_key]["title"];
}
public function setting_set($setting_key, $value): bool
{
$field_key = $this->setting_get_field($setting_key);
if(!$field_key) return false;
$old_value = $this->setting_get($setting_key);
$value = $this->field_render_db_value($field_key, $setting_key, $value, $old_value);
if($old_value === false) return $this->setting_add($setting_key, $value);
$this->db_query("UPDATE `bive_settings` SET `value` = ? WHERE `setting_key` = ?", array($value, $setting_key), true);
return true;
}
public function setting_add($setting_key, $value)
{
return $this->db_insert("INSERT INTO `bive_settings`(`setting_key`, `value`) VALUES (?, ?)", array($setting_key, $value), true);
}
}

View File

@@ -0,0 +1,119 @@
<?php
// Работа с шаблонами
defined('ROOT_DIR') || exit;
trait Templates {
// Загрузка шаблона
public function template_load($name, $variables = array(), $new = true)
{
$template_path = $this->template_touch_name($name);
return $this->template_load_by_path($template_path, $variables, $new);
}
private function template_touch_name($name): string
{
$template_path = ROOT_DIR . SLASH . PLAYAREA_DIR_NAME . SLASH . "templates" . SLASH . $name;
if(file_exists($template_path)) return $template_path;
$plugin_template_path = ROOT_DIR . SLASH . PLAYAREA_DIR_NAME . SLASH . "plugins" . SLASH . $name;
if(file_exists($plugin_template_path)) return $plugin_template_path;
return $template_path;
}
// Загрузка шаблона по его адресу
public function template_load_by_path($path, $variables = array(), $new = true)
{
// Загрузка шаблона из буффера
$cache = $this->template_cache_load($path, $variables, $new);
if($cache) return $cache;
// Начало буффера
ob_start();
global $b;
require $path;
$buffer = ob_get_contents();
ob_end_clean();
// Конец буффера
// Сохранение буффера в кеш
$rendered = $this->template_variables_apply($buffer, $variables);
if($new === false) $this->template_cache_save($path, $variables, $rendered);
// Вывод буффера пользователю
echo $rendered;
return $buffer;
}
// Применить значения переменных
private function template_variables_apply($content, $variables)
{
return preg_replace_callback('/{{\s*(\w+)\s*}}/', function($match) use ($variables) {
$key = $match[1];
return $variables[$key] ?? $match[0];
}, $content);
}
// Сохранить шаблон
private function template_cache_save($name, $variables, $content): bool
{
if(!TEMPLATE_CACHE) return false;
$path = $this->template_cache_get_full_path($name, $variables);
file_put_contents($path, $content);
return true;
}
// Есть ли шаблон с таким именем
private function template_cache_has($name, $variables): bool
{
$path = $this->template_cache_get_full_path($name, $variables);
return file_exists($path);
}
// Загрузка кешированного шаблона
private function template_cache_load($name, $variables, $new = false)
{
if(!TEMPLATE_CACHE) return false;
if(!$new && $this->template_cache_has($name, $variables)) {
$cache = $this->template_cache_get($name, $variables);
echo $cache;
return $cache;
}
return false;
}
// Получить кеш шаблона
private function template_cache_get($name, $variables): string
{
$path = $this->template_cache_get_full_path($name, $variables);
return file_get_contents($path);
}
// Получить полный путь до кеша шаблона
private function template_cache_get_full_path($name, $variables): string
{
$path = $this->get_storage_dir() . SLASH . "temp" . SLASH . "templates" . SLASH;
return $path . md5($name . json_encode($variables)) . ".php";
}
// Количество кешированных шаблонов
public function template_cache_count(): int
{
$path = $this->get_storage_dir() . SLASH . "temp" . SLASH . "templates" . SLASH;
$files = glob($path."/*");
return count($files);
}
// Удалить весь кеш шаблонов
public function template_cache_remove(){
$path = $this->get_storage_dir() . SLASH . "temp" . SLASH . "templates" . SLASH;
$files = glob($path."/*");
if (count($files) > 0) {
foreach ($files as $file) {
if (file_exists($file)) {
unlink($file);
}
}
}
}
}