%PDF- %PDF-
| Direktori : /www/varak.net/dmarc.varak.net/classes/ |
| Current File : //www/varak.net/dmarc.varak.net/classes/Core.php |
<?php
/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2020-2025 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* =========================
*
* This file contains the Core class
*
* @category API
* @package DmarcSrg
* @author Aleksey Andreev (liuch)
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
*/
namespace Liuch\DmarcSrg;
use Liuch\DmarcSrg\Users\User;
use Liuch\DmarcSrg\Users\DbUser;
use Liuch\DmarcSrg\Users\UserList;
use Liuch\DmarcSrg\Users\AdminUser;
use Liuch\DmarcSrg\Exception\SoftException;
use Liuch\DmarcSrg\Exception\LogicException;
use Liuch\DmarcSrg\Exception\ForbiddenException;
/**
* It's class for accessing to most methods for working with http, json data,
* getting instances of some classes
*/
class Core
{
private $user = null;
private $modules = [];
private $template = null;
/** @var self|null */
private static $instance = null;
/**
* The constructor
*
* @param array $params Array with modules to be bind to
*/
public function __construct($params)
{
foreach ([ 'admin', 'auth', 'config', 'database', 'ehandler', 'session', 'status' ] as $key) {
if (isset($params[$key])) {
$this->modules[$key] = $params[$key];
}
}
if (isset($params['template'])) {
$this->template = $params['template'];
}
if (!self::$instance) {
self::$instance = $this;
}
}
/**
* Returns the method of the current http request.
*
* @return string http method
*/
public static function requestMethod(): string
{
return $_SERVER['REQUEST_METHOD'];
}
/**
* Determines whether the current invocation is being run via a web server
*
* @return bool
*/
public static function isWEB(): bool
{
return isset($_SERVER['REQUEST_METHOD']);
}
/**
* Returns an instance of the current user
*
* @return User|null
*/
public function getCurrentUser()
{
$session = $this->session();
if (!$this->auth()->isEnabled()) {
return $this->user = new AdminUser($this);
}
if (!$this->user) {
$data = $session->getData();
if (isset($data['user']) && gettype($data['user']) == 'array') {
if ($data['user']['name'] === 'admin') {
if (($data['user']['id'] ?? -1) !== 0 || ($data['user']['level'] ?? -1) !== User::LEVEL_ADMIN) {
throw new ForbiddenException('The user session has been broken!');
}
$this->user = new AdminUser($this);
$session->commit();
} elseif ($this->config('users/user_management', false)) {
try {
$this->user = new DbUser($data['user'], $this->database());
$cts = (new DateTime())->getTimestamp();
if (($data['s_time'] ?? 0) + 5 <= $cts) {
if (isset($data['s_id']) &&
$this->user->session() === $data['s_id'] &&
$this->user->isEnabled()
) {
$data['s_time'] = $cts;
$data['user']['level'] = $this->user->level();
$session->setData($data);
$session->commit();
} else {
$this->user = null;
$session->destroy();
}
} else {
$session->commit();
}
} catch (SoftException $e) {
if (!$this->user->exists()) {
$this->user = null;
$session->destroy();
}
throw $e;
}
} else {
$session->destroy();
}
}
}
return $this->user;
}
/**
* Sets the passed user as the current user
*
* @param User|string|null $user User (instance, name or none) to set
*
* @return void
*/
public function setCurrentUser($user): void
{
if (gettype($user) == 'string') {
$user = UserList::getUserByName($user, $this);
} elseif (!is_null($user) && !($user instanceof User)) {
throw new LogicException('Wrong user object was passed');
}
$this->user = $user;
if (self::isWEB()) {
$session = $this->session();
$session->destroy();
if ($user) {
$session->setData([
'user' => [
'id' => $user->id(),
'name' => $user->name(),
'level' => $user->level()
],
's_id' => $user->session(),
's_time' => (new DateTime())->getTimestamp()
]);
$session->commit();
}
}
}
/**
* Returns true if the http request asks for json data.
*
* @return bool
*/
public static function isJson(): bool
{
return ($_SERVER['HTTP_ACCEPT'] ?? '') === 'application/json';
}
/**
* Sends the html file to the client and inserts a link with a custom CSS file if necessary
*
* @return void
*/
public function sendHtml(): void
{
if (is_readable($this->template)) {
$ccf = $this->config('custom_css', '');
if (substr_compare($ccf, '.css', -4) === 0) { // replacement for str_ends_with
$ccf = '<link rel="stylesheet" href="' . htmlspecialchars($ccf) . '" type="text/css" />';
} else {
$ccf = '';
}
$fd = fopen($this->template, 'r');
if ($fd) {
while (($buffer = fgets($fd)) !== false) {
if (substr_compare($buffer, "<!-- Custom CSS -->\n", -20) === 0) {
if (!empty($ccf)) {
$buffer = str_replace('<!-- Custom CSS -->', $ccf, $buffer);
echo $buffer;
}
} else {
echo $buffer;
}
}
fclose($fd);
}
}
}
/**
* Sends data from an array as json string to the client.
*
* @param array $data - Data to send.
*
* @return void
*/
public static function sendJson(array $data): void
{
$res_str = json_encode($data);
if ($res_str === false) {
$res_str = '[]';
}
header('content-type: application/json; charset=UTF-8');
echo $res_str;
}
/**
* Sends a Bad Request response to the client.
*
* @return void
*/
public static function sendBad(): void
{
http_response_code(400);
echo 'Bad request';
}
/**
* Retrieves json data from the request and return it as an array.
*
* Returns an array with data or null if there is an error.
*
* @return array|null Data from the request
*/
public static function getJsonData()
{
$res = null;
if (($_SERVER['CONTENT_TYPE'] ?? $_SERVER['HTTP_CONTENT_TYPE'] ?? '') === 'application/json') {
$str = file_get_contents('php://input');
if ($str) {
$res = json_decode($str, true);
}
}
return $res;
}
/**
* Checks if the dependencies passed in the parameter are installed
*
* @param string $deps Comma-separated string of dependency names to be checked
*
* @return void
*/
public function checkDependencies(string $deps): void
{
$adeps = explode(',', $deps);
$no_deps = [];
foreach ($adeps as $ext) {
$no_dep = null;
switch ($ext) {
case 'flyfs':
if (!class_exists('League\Flysystem\Filesystem')) {
$no_dep = 'Flysystem';
}
break;
default:
if (!extension_loaded($ext)) {
$no_dep = 'ext-' . $ext;
}
break;
}
if ($no_dep) {
$no_deps[] = $no_dep;
$no_dep = null;
}
}
if (count($no_deps)) {
if (count($no_deps) === 1) {
$s1 = 'y';
$s2 = 'is';
} else {
$s1 = 'ies';
$s2 = 'are';
}
$msg = "Required dependenc$s1 $s2 missing";
$usr = $this->getCurrentUser();
if ($usr && $usr->level() === User::LEVEL_ADMIN) {
$msg .= ': ' . implode(', ', $no_deps) . '.';
} else {
$msg .= '. Contact the administrator.';
}
throw new SoftException($msg);
}
}
/**
* Returns an instance of the class Auth.
*
* @return Auth
*/
public function auth()
{
return $this->getModule('auth', true);
}
/**
* Returns an instance of the class Status.
*
* @return Status instance of Status
*/
public function status()
{
return $this->getModule('status', true);
}
/**
* Returns an instance of the Session class
*
* @return Session
*/
public function session()
{
return $this->getModule('session', false);
}
/**
* Returns an instance of the class Admin.
*
* @return Admin instance of Admin
*/
public function admin()
{
return $this->getModule('admin', true);
}
/**
* Returns an instance of the class Database.
*
* @return Database\DatabaseController
*/
public function database()
{
return $this->getModule('database', true);
}
/**
* Returns an instance of the class ErrorHandler
*
* @return ErrorHandler
*/
public function errorHandler()
{
return $this->getModule('ehandler', true);
}
/**
* Returns the current logger.
* Just a proxy method to return the logger from ErrorHandler
*
* @return Log\LoggerInterface
*/
public function logger()
{
return $this->errorHandler()->logger();
}
/**
* Returns instance of the object
*
* @return self
*/
public static function instance()
{
return self::$instance;
}
/**
* Returns the config value by its name
*
* @param string $name Config item name. Hierarchy supported via '/'
* @param mixed $default Value to be returned if the required config item is missing or null
*
* @return mixed
*/
public function config(string $name, $default = null)
{
return $this->getModule('config', false)->get($name, $default);
}
/**
* Returns a module instance by its name. Lazy initialization is used.
*
* @param string $name Module name
* @param bool $core Whether to pass $this to the constructor
*
* @return object
*/
private function getModule(string $name, bool $core)
{
$module = $this->modules[$name] ?? null;
switch (gettype($module)) {
case 'array':
if ($core) {
$module = new $module[0]($this, ...($module[1] ?? []));
} else {
$module = new $module[0](...($module[1] ?? []));
}
$this->modules[$name] = $module;
break;
case 'NULL':
throw new LogicException('Attempt to initiate an unloaded module ' . $name);
}
return $module;
}
}