This repository has been archived on 2024-10-16. You can view files and clone it, but cannot push or open issues or pull requests.
ebala/mirzaev/ebala/system/controllers/session.php

626 lines
24 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace mirzaev\ebala\controllers;
// Файлы проекта
use mirzaev\ebala\controllers\core,
mirzaev\ebala\controllers\traits\errors,
mirzaev\ebala\models\account,
mirzaev\ebala\models\market;
// Библиотека для ArangoDB
use ArangoDBClient\Document as _document;
// Встроенные библиотеки
use exception;
/**
* Контроллер сессии
*
* @package mirzaev\ebala\controllers
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class session extends core
{
use errors;
/**
* Записать номер сотрудника во все буферы сессии
*
* Проверяет существование аккаунта сотрудника с этим номером
* и запоминает для использования в процессе аутентификации
*
* @param array $parameters Параметры запроса
*
* @return void В буфер вывода JSON-документ с запрашиваемыми параметрами
*/
public function worker(array $parameters = []): void
{
// Инициализация буфера ответа
$buffer = [];
// Инициализация реестра возвращаемых параметров
$return = explode(',', $parameters['return'], 50);
try {
// Проверка наличия обязательных параметров
if (empty($parameters['worker'])) throw new exception('Необходимо передать номер');
// Очистка всего кроме цифр, а потом поиск 10 первых чисел (без восьмёрки)
preg_match('/^\d(\d{10})/', preg_replace("/[^\d]/", "", $parameters['worker']), $matches);
// Инициализация номера
$parameters['worker'] = isset($matches[1]) ? 7 . $matches[1] : $parameters['worker'];
// Вычисление длины
$length = mb_strlen($parameters['worker']);
// Проверка параметров на соответствование требованиям
if ($length === 0) throw new exception('Номер не может быть пустым');
if ($length !== 11) throw new exception('Номер должен иметь 11 цифр');
if (preg_match_all('/[^\d\(\)\-\s\r\n\t\0]+/u', $parameters['worker'], $matches) > 0) throw new exception('Нельзя использовать символы: ' . implode(', ', ...$matches));
if ($remember = isset($parameters['remember']) && $parameters['remember'] === '1') {
// Запрошено запоминание
// Запись в cookie
setcookie('entry_number', $parameters['worker'], [
'expires' => strtotime('+1 day'),
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'strict'
]);
}
// Поиск аккаунта
$account = account::read('d.number == "' . $parameters['worker'] . '"', amount: 1);
// Генерация ответа по запрашиваемым параметрам
foreach ($return as $parameter) match ($parameter) {
'exist' => $buffer['exist'] = isset($account),
'account' => (function () use ($parameters, $remember, &$buffer) {
// Запись в буфер сессии
if ($remember) $this->session->write(['entry' => ['number' => $parameters['worker']]], $this->errors);
// Поиск аккаунта и запись в буфер вывода
$buffer['account'] = (new account($this->session, 'worker', $this->errors))?->instance() instanceof _document;
})(),
'verify' => $buffer['verify'] = true,
'errors' => null,
default => throw new exception("Параметр не найден: $parameter")
};
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors['session'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Запись реестра ошибок в буфер ответа
if (in_array('errors', $return, true)) $buffer['errors'] = self::parse_only_text($this->errors);
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Генерация ответа
echo json_encode($buffer);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
// Запись в буфер сессии
if (!in_array('account', $return, true) && ($remember ?? false))
$this->session->write(['entry' => ['number' => $parameters['worker']]]);
}
/**
* Записать идентификатор администратора во все буферы сессии
*
* Проверяет существование аккаунта администратора с этим идентификатором
* и запоминает для использования в процессе аутентификации
*
* @param array $parameters Параметры запроса
*
* @return void В буфер вывода JSON-документ с запрашиваемыми параметрами
*/
public function administrator(array $parameters = []): void
{
// Инициализация буфера ответа
$buffer = [];
// Инициализация реестра возвращаемых параметров
$return = explode(',', $parameters['return'], 50);
try {
// Проверка наличия обязательных параметров
if (empty($parameters['administrator'])) throw new exception('Необходимо передать идентификатор');
// Очистка всего кроме цифр, а потом поиск 10 первых чисел (без восьмёрки)
preg_match('/^\d{3,12}/', preg_replace("/[^\d]/", "", $parameters['administrator']), $matches);
// Инициализация номера
$parameters['administrator'] = $matches[0];
// Вычисление длины
$length = mb_strlen($parameters['administrator']);
// Проверка параметров на соответствование требованиям
if ($length === 0) throw new exception('Идентификатор аккаунта не может быть пустым');
if ($length > 12) throw new exception('Идентификатор аккаунта должен иметь не более 12 цифр');
if (preg_match_all('/[^\d\(\)\-\s\r\n\t\0]+/u', $parameters['administrator'], $matches) > 0) throw new exception('Нельзя использовать символы: ' . implode(', ', ...$matches));
if ($remember = isset($parameters['remember']) && $parameters['remember'] === '1') {
// Запрошено запоминание
// Запись в cookie
setcookie(
'entry__key',
$parameters['administrator'],
[
'expires' => strtotime('+1 day'),
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'strict'
]
);
}
// Поиск аккаунта
$account = account::read('d._key == "' . $parameters['administrator'] . '"', amount: 1);
// Генерация ответа по запрашиваемым параметрам
foreach ($return as $parameter) match ($parameter) {
'exist' => $buffer['exist'] = isset($account),
'account' => (function () use ($parameters, $remember, &$buffer) {
// Запись в буфер сессии
if ($remember) $this->session->write(['entry' => ['_key' => $parameters['administrator']]], $this->errors);
// Поиск аккаунта и запись в буфер вывода
$buffer['account'] = (new account($this->session, 'administrator', $this->errors))?->instance() instanceof _document;
})(),
'verify' => $buffer['verify'] = true,
'errors' => null,
default => throw new exception("Параметр не найден: $parameter")
};
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors['session'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Запись реестра ошибок в буфер ответа
if (in_array('errors', $return, true)) $buffer['errors'] = self::parse_only_text($this->errors);
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Генерация ответа
echo json_encode($buffer);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
// Запись в буфер сессии
if (!in_array('account', $return, true) && ($remember ?? false))
$this->session->write(['entry' => ['_key' => $parameters['administrator']]]);
}
/**
* Записать идентификатор оператора во все буферы сессии
*
* Проверяет существование аккаунта оператора с этим идентификатором
* и запоминает для использования в процессе аутентификации
*
* @param array $parameters Параметры запроса
*
* @return void В буфер вывода JSON-документ с запрашиваемыми параметрами
*/
public function operator(array $parameters = []): void
{
// Инициализация буфера ответа
$buffer = [];
// Инициализация реестра возвращаемых параметров
$return = explode(',', $parameters['return'], 50);
try {
// Проверка наличия обязательных параметров
if (empty($parameters['operator'])) throw new exception('Необходимо передать идентификатор');
// Очистка всего кроме цифр, а потом поиск 10 первых чисел (без восьмёрки)
preg_match('/^\d{3,12}/', preg_replace("/[^\d]/", "", $parameters['operator']), $matches);
// Инициализация номера
$parameters['operator'] = $matches[0];
// Вычисление длины
$length = mb_strlen($parameters['operator']);
// Проверка параметров на соответствование требованиям
if ($length === 0) throw new exception('Идентификатор аккаунта не может быть пустым');
if ($length > 12) throw new exception('Идентификатор аккаунта должен иметь не более 12 цифр');
if (preg_match_all('/[^\d\(\)\-\s\r\n\t\0]+/u', $parameters['operator'], $matches) > 0) throw new exception('Нельзя использовать символы: ' . implode(', ', ...$matches));
if ($remember = isset($parameters['remember']) && $parameters['remember'] === '1') {
// Запрошено запоминание
// Запись в cookie
setcookie('entry__key', $parameters['operator'], [
'expires' => strtotime('+1 day'),
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'strict'
]);
}
// Поиск аккаунта
$account = account::read('d._key == "' . $parameters['operator'] . '"', amount: 1);
// Генерация ответа по запрашиваемым параметрам
foreach ($return as $parameter) match ($parameter) {
'exist' => $buffer['exist'] = isset($account),
'account' => (function () use ($parameters, $remember, &$buffer) {
// Запись в буфер сессии
if ($remember) $this->session->write(['entry' => ['_key' => $parameters['operator']]], $this->errors);
// Поиск аккаунта и запись в буфер вывода
$buffer['account'] = (new account($this->session, 'operator', $this->errors))?->instance() instanceof _document;
})(),
'verify' => $buffer['verify'] = true,
'errors' => null,
default => throw new exception("Параметр не найден: $parameter")
};
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors['session'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Запись реестра ошибок в буфер ответа
if (in_array('errors', $return, true)) $buffer['errors'] = self::parse_only_text($this->errors);
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Генерация ответа
echo json_encode($buffer);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
// Запись в буфер сессии
if (!in_array('account', $return, true) && ($remember ?? false))
$this->session->write(['entry' => ['_key' => $parameters['operator']]]);
}
/**
* Записать идентификатор магазина во все буферы сессии
*
* Проверяет существование аккаунта магазина с этим идентификатором
* и запоминает для использования в процессе аутентификации
*
* @param array $parameters Параметры запроса
*
* @return void В буфер вывода JSON-документ с запрашиваемыми параметрами
*/
public function market(array $parameters = []): void
{
// Инициализация буфера ответа
$buffer = [];
// Инициализация реестра возвращаемых параметров
$return = explode(',', $parameters['return'], 50);
try {
// Проверка наличия обязательных параметров
if (empty($parameters['market'])) throw new exception('Необходимо передать идентификатор');
// Вычисление длины
$length = mb_strlen($parameters['market']);
// Проверка параметров на соответствование требованиям
if ($length === 0) throw new exception('Идентификатор аккаунта аккаунта не может быть пустым');
if ($length > 40) throw new exception('Идентификатор аккаунта аккаунта должен иметь не более 40 символов');
if (preg_match_all('/[^\d\(\)\-\s\r\n\t\0]+/u', $parameters['market'], $matches) > 0) throw new exception('Нельзя использовать символы: ' . implode(', ', ...$matches));
if ($remember = isset($parameters['remember']) && $parameters['remember'] === '1') {
// Запрошено запоминание
// Запись в cookie
setcookie('entry__key', $parameters['market'], [
'expires' => strtotime('+1 day'),
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'strict'
]);
}
// Поиск аккаунта
$account = account::read('d._key == "' . $parameters['market'] . '"', amount: 1);
// Генерация ответа по запрашиваемым параметрам
foreach ($return as $parameter) match ($parameter) {
'exist' => $buffer['exist'] = isset($account),
'account' => (function () use ($parameters, $remember, &$buffer) {
// Запись в буфер сессии
if ($remember) $this->session->write(['entry' => ['_key' => $parameters['market']]], $this->errors);
// Поиск аккаунта и запись в буфер вывода
$buffer['account'] = (new account($this->session, 'market', $this->errors))?->instance() instanceof _document;
})(),
'verify' => $buffer['verify'] = true,
'errors' => null,
default => throw new exception("Параметр не найден: $parameter")
};
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors['session'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Запись реестра ошибок в буфер ответа
if (in_array('errors', $return, true)) $buffer['errors'] = self::parse_only_text($this->errors);
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Генерация ответа
echo json_encode($buffer);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
// Запись в буфер сессии
if (!in_array('account', $return, true) && ($remember ?? false))
$this->session->write(['entry' => ['_key' => $parameters['market']]]);
}
/**
* Записать пароль любого типа аккаунта во все буферы сессии
*
* Проверяет на соответствие требованиям
* и запоминает для использования в процессе аутентификации
*
* @param array $parameters Параметры запроса
*
* @return void В буфер вывода JSON-документ с запрашиваемыми параметрами
*/
public function password(array $parameters = []): void
{
// Инициализация буфера ответа
$buffer = [];
// Инициализация реестра возвращаемых параметров
$return = explode(',', $parameters['return'], 50);
try {
// Вычисление длины
$length = strlen($parameters['password']);
// Проверка параметров на соответствование требованиям
if ($length > 300) throw new exception('Пароль не может быть длиннее 300 символов');
if (preg_match_all('/[^\w\s\r\n\t\0]+/u', $parameters['password'], $matches) > 0) throw new exception('Нельзя использовать символы: ' . implode(', ', ...$matches));
// Инициализация значения по умолчанию для типа аккаунта
$parameters['type'] ??= 'worker';
// Генерация ответа по запрашиваемым параметрам
foreach ($return as $parameter) match ($parameter) {
'account' => (function () use ($parameters, &$buffer) {
// Запись в буфер сессии
if (isset($parameters['remember']) && $parameters['remember'] === '1')
$this->session->write(['entry' => ['password' => $parameters['password']]], $this->errors);
// Поиск аккаунта и запись в буфер вывода
$buffer['account'] = (new account($this->session, $parameters['type'], $this->errors))?->instance() instanceof _document;
})(),
'verify' => $buffer['verify'] = true,
'errors' => null,
default => throw new exception("Параметр не найден: $parameter")
};
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors['session'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Запись реестра ошибок в буфер ответа
if (in_array('errors', $return, true)) $buffer['errors'] = self::parse_only_text($this->errors);
// Запись заголовков ответа
header('Content-Type: application/json');
header('Content-Encoding: none');
header('X-Accel-Buffering: no');
// Инициализация буфера вывода
ob_start();
// Генерация ответа
echo json_encode($buffer);
// Запись заголовков ответа
header('Content-Length: ' . ob_get_length());
// Отправка и деинициализация буфера вывода
ob_end_flush();
flush();
// Запись в буфер сессии
if (!in_array('account', $return, true) && isset($parameters['remember']) && $parameters['remember'] === '1')
$this->session->write(['entry' => ['password' => $parameters['password']]]);
}
/**
* Записать в буфер сессии
*
* @param array $parameters Параметры запроса
*
* @return void
*/
public function write(array $parameters = []): void
{
try {
if ($this->account->status()) {
// Авторизован аккаунт
// Инициализация директорий для генерации
$directories = explode('_', $parameters['name'], 100);
// Инициализированы директории?
if (count($directories) === 0) return;
// Конвертация: filter -> filters
if ($directories[1] === 'filter') $directories[1] .= 's';
// Инициализация буфера вывода
$response = [];
// Инициализация буфера выполнения
$buffer = &$response;
foreach ($directories as $directory) {
// Перебор директорий
// Инициализация структуры
$buffer[$directory] = ($next = next($directories) === false) ? $parameters['value'] : [];
// Реинициализация цели для инициализации структуры (углубление в массив)
if ($next) unset($buffer);
else $buffer = &$buffer[$directory];
}
// Запись в буфер сессии
$this->session->write($response);
}
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors['session'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
}
/**
* Прочитать из буфера сессии
*
* @param array $parameters Параметры запроса
*
* @return ?string Данные из буфера сессии, если найдены
*/
public function read(array $parameters = []): ?string
{
try {
if ($this->account->status()) {
// Авторизован аккаунт
// Инициализация директорий для генерации
$directories = explode('_', $parameters['name'], 100);
// Инициализированы директории?
if (count($directories) === 0) return null;
// Конвертация: filter -> filters
if ($directories[1] === 'filter') $directories[1] .= 's';
// Инициализация буфера хранилища
$storage = $this->session->buffer[$_SERVER['INTERFACE']];
// Инициализация буфера выполнения
$buffer = &$storage[reset($directories)] ?? null;
// Найдена первая директория в базе данных?
if (isset($buffer) === 0) return null;
foreach ($directories as &$directory) {
// Перебор директорий
// Инициализация новой целевой директории
if (isset($buffer[$directory])) $buffer = &$buffer[$directory];
else continue;
// Реинициализация цели для инициализации структуры (углубление в массив)
if (next($directories) === false) $buffer = $buffer[$directory];
}
// Возврат (успех)
return is_array($buffer) ? null : $buffer;
}
} catch (exception $e) {
// Запись в реестр ошибок
$this->errors['session'][] = [
'text' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'stack' => $e->getTrace()
];
}
// Возврат (провал)
return null;
}
}