refresh after 3-4 years
0
.gitignore
vendored
Normal file → Executable file
47
composer.json
Normal file → Executable file
@@ -1,25 +1,26 @@
|
|||||||
{
|
{
|
||||||
"name": "mirzaev/surikovlib",
|
"name": "kodorvan/surikov",
|
||||||
"description": "Онлайн библеотека музея имени Сурикова",
|
"description": "Online library of the Surikov Museum",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "WTFPL",
|
||||||
"homepage": "https://git.hood.su/mirzaev/surikovlib",
|
"homepage": "https://git.svoboda.works/kodorvan/surikov",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Arsen Mirzaev Tatyano-Muradovich",
|
"name": "Arsen Mirzaev Tatyano-Muradovich",
|
||||||
"email": "arsen@mirzaev.sexy",
|
"email": "arsen@mirzaev.sexy",
|
||||||
"homepage": "https://mirzaev.sexy",
|
"homepage": "https://mirzaev.sexy",
|
||||||
"role": "Developer"
|
"role": "Developer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.0.0",
|
"php": "^8.4.0",
|
||||||
"mirzaev/minimal": "^2.0.x-dev",
|
"mirzaev/minimal": "^3.6.2",
|
||||||
"twig/twig": "^3.3"
|
"twig/twig": "^3.3",
|
||||||
},
|
"mirzaev/languages": "^1.0"
|
||||||
"autoload": {
|
},
|
||||||
"psr-4": {
|
"autoload": {
|
||||||
"mirzaev\\surikovlib\\": "mirzaev/surikovlib/system"
|
"psr-4": {
|
||||||
}
|
"kodorvan\\surikov\\": "kodorvan/surikov/system"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
230
composer.lock
generated
Normal file → Executable file
@@ -4,21 +4,59 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "1c826a114d11e8301a0f17171d987459",
|
"content-hash": "97cd0861246168b4da62751f2317bc62",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "mirzaev/minimal",
|
"name": "mirzaev/languages",
|
||||||
"version": "2.0.x-dev",
|
"version": "1.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.hood.su/mirzaev/minimal",
|
"url": "https://git.svoboda.works/mirzaev/languages",
|
||||||
"reference": "7777d7af1733d661a36551a0fdcf27a972e4ef81"
|
"reference": "eceff49204c718243f24e3da42294c5ea5b29e01"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "~8.0"
|
"php": "^8.4"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"type": "library",
|
||||||
"ext-PDO": "Для работы с базами данных на SQL (MySQL, PostreSQL...)"
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"mirzaev\\languages\\": "mirzaev/languages/system"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"WTFPL"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Arsen Mirzaev Tatyano-Muradovich",
|
||||||
|
"email": "arsen@mirzaev.sexy",
|
||||||
|
"homepage": "https://mirzaev.sexy",
|
||||||
|
"role": "Creator"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Library for easy languages support",
|
||||||
|
"homepage": "https://git.svoboda.works/mirzaev/languages",
|
||||||
|
"keywords": [
|
||||||
|
"enumeration",
|
||||||
|
"languages"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://git.svoboda.works/mirzaev/languages/issues",
|
||||||
|
"wiki": "https://git.svoboda.works/mirzaev/languages/wiki"
|
||||||
|
},
|
||||||
|
"time": "2025-08-21T14:50:06+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mirzaev/minimal",
|
||||||
|
"version": "3.6.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.svoboda.works/mirzaev/minimal",
|
||||||
|
"reference": "d9e4e0af6cffc169831eec798d00e53187839b8e"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "~8.4"
|
||||||
},
|
},
|
||||||
"type": "framework",
|
"type": "framework",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -35,37 +73,105 @@
|
|||||||
"name": "Arsen Mirzaev Tatyano-Muradovich",
|
"name": "Arsen Mirzaev Tatyano-Muradovich",
|
||||||
"email": "arsen@mirzaev.sexy",
|
"email": "arsen@mirzaev.sexy",
|
||||||
"homepage": "https://mirzaev.sexy",
|
"homepage": "https://mirzaev.sexy",
|
||||||
"role": "Developer"
|
"role": "Programmer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Легковесный MVC фреймворк который следует твоим правилам, а не диктует свои",
|
"description": "My vision of a good framework",
|
||||||
"homepage": "https://git.hood.su/mirzaev/minimal",
|
"homepage": "https://git.mirzaev.sexy/mirzaev/minimal",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"framework",
|
"framework",
|
||||||
|
"lightweight",
|
||||||
"mvc"
|
"mvc"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"docs": "https://git.hood.su/mirzaev/minimal/manual",
|
"docs": "https://git.mirzaev.sexy/mirzaev/minimal/wiki",
|
||||||
"issues": "https://git.hood.su/mirzaev/minimal/issues"
|
"issues": "https://git.mirzaev.sexy/mirzaev/minimal/issues"
|
||||||
},
|
},
|
||||||
"time": "2022-03-03T21:15:52+00:00"
|
"time": "2025-07-16T01:09:25+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v1.25.0",
|
"version": "v3.6.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
"reference": "30885182c981ab175d4d034db0f6f469898070ab"
|
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
|
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||||
"reference": "30885182c981ab175d4d034db0f6f469898070ab",
|
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1"
|
"php": ">=8.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/contracts",
|
||||||
|
"name": "symfony/contracts"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.6-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"function.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-09-25T14:21:43+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-ctype",
|
||||||
|
"version": "v1.33.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||||
|
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||||
|
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
"ext-ctype": "*"
|
"ext-ctype": "*"
|
||||||
@@ -75,12 +181,9 @@
|
|||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "1.23-dev"
|
|
||||||
},
|
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/polyfill",
|
"url": "https://github.com/symfony/polyfill",
|
||||||
"url": "https://github.com/symfony/polyfill"
|
"name": "symfony/polyfill"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -114,7 +217,7 @@
|
|||||||
"portable"
|
"portable"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
|
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -125,29 +228,34 @@
|
|||||||
"url": "https://github.com/fabpot",
|
"url": "https://github.com/fabpot",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-10-20T20:35:02+00:00"
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-mbstring",
|
"name": "symfony/polyfill-mbstring",
|
||||||
"version": "v1.25.0",
|
"version": "v1.33.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825"
|
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825",
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||||
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825",
|
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1"
|
"ext-iconv": "*",
|
||||||
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
"ext-mbstring": "*"
|
"ext-mbstring": "*"
|
||||||
@@ -157,12 +265,9 @@
|
|||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "1.23-dev"
|
|
||||||
},
|
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/polyfill",
|
"url": "https://github.com/symfony/polyfill",
|
||||||
"url": "https://github.com/symfony/polyfill"
|
"name": "symfony/polyfill"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -197,7 +302,7 @@
|
|||||||
"shim"
|
"shim"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
|
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -208,43 +313,50 @@
|
|||||||
"url": "https://github.com/fabpot",
|
"url": "https://github.com/fabpot",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-11-30T18:21:41+00:00"
|
"time": "2024-12-23T08:48:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
"version": "v3.3.8",
|
"version": "v3.21.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/twigphp/Twig.git",
|
"url": "https://github.com/twigphp/Twig.git",
|
||||||
"reference": "972d8604a92b7054828b539f2febb0211dd5945c"
|
"reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/972d8604a92b7054828b539f2febb0211dd5945c",
|
"url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d",
|
||||||
"reference": "972d8604a92b7054828b539f2febb0211dd5945c",
|
"reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.2.5",
|
"php": ">=8.1.0",
|
||||||
|
"symfony/deprecation-contracts": "^2.5|^3",
|
||||||
"symfony/polyfill-ctype": "^1.8",
|
"symfony/polyfill-ctype": "^1.8",
|
||||||
"symfony/polyfill-mbstring": "^1.3"
|
"symfony/polyfill-mbstring": "^1.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"psr/container": "^1.0",
|
"phpstan/phpstan": "^2.0",
|
||||||
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
|
"psr/container": "^1.0|^2.0",
|
||||||
|
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "3.3-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/Resources/core.php",
|
||||||
|
"src/Resources/debug.php",
|
||||||
|
"src/Resources/escaper.php",
|
||||||
|
"src/Resources/string_loader.php"
|
||||||
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Twig\\": "src/"
|
"Twig\\": "src/"
|
||||||
}
|
}
|
||||||
@@ -277,7 +389,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/twigphp/Twig/issues",
|
"issues": "https://github.com/twigphp/Twig/issues",
|
||||||
"source": "https://github.com/twigphp/Twig/tree/v3.3.8"
|
"source": "https://github.com/twigphp/Twig/tree/v3.21.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -289,20 +401,18 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-02-04T06:59:48+00:00"
|
"time": "2025-05-03T07:21:55+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [],
|
"packages-dev": [],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": {
|
"stability-flags": {},
|
||||||
"mirzaev/minimal": 20
|
|
||||||
},
|
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "^8.0.0"
|
"php": "^8.4.0"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.2.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
283
kodorvan/surikov/system/controllers/accounts.php
Executable file
@@ -0,0 +1,283 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\controllers;
|
||||||
|
|
||||||
|
// The project
|
||||||
|
use kodorvan\surikov\controllers\core,
|
||||||
|
kodorvan\surikov\models\account;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
mirzaev\minimal\http\enumerations\protocol,
|
||||||
|
mirzaev\minimal\http\enumerations\status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accounts controller
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\controllers
|
||||||
|
*
|
||||||
|
* @param array $errors Registry of errors
|
||||||
|
*
|
||||||
|
* @method null index() Account page
|
||||||
|
* @method string|null registration() Registration
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class accounts extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Errors
|
||||||
|
*
|
||||||
|
* @var array $errors Registry of errors
|
||||||
|
*/
|
||||||
|
protected array $errors = [
|
||||||
|
'system' => [],
|
||||||
|
'account' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account page
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function index(): null
|
||||||
|
{
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
|
||||||
|
// Request for any response
|
||||||
|
|
||||||
|
// Render page
|
||||||
|
$page = $this->view->render('pages/account/index.html');
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->status(status::ok)
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->write($page)
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Deinitializing rendered page
|
||||||
|
unset($page);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registration
|
||||||
|
*
|
||||||
|
* @param string|null $mail Mail
|
||||||
|
* @param string|null $password Password
|
||||||
|
* @param int|string|bool|null $remember Remember
|
||||||
|
* @param string|null $redirect Redirect @deprecated
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function registration(
|
||||||
|
?string $mail = null,
|
||||||
|
?string $password = null,
|
||||||
|
int|string|bool|null $remember = null,
|
||||||
|
?string $redirect = null
|
||||||
|
): null {
|
||||||
|
if ($this->view->account = account::registrate(mail: $mail, password: $password, errors: $this->errors['account'])) {
|
||||||
|
// Registered
|
||||||
|
|
||||||
|
// Filtering the remember argument
|
||||||
|
$remember = (bool) $remember;
|
||||||
|
|
||||||
|
if ($this->view->account = account::authenticate(mail: $mail, password: $password, remember: $remember, errors: $this->errors['account'])) {
|
||||||
|
// Authenticated
|
||||||
|
} else {
|
||||||
|
// Not authenticated
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->status(status::forbidden)
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not registered
|
||||||
|
var_dump($this->errors); die;
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->status(status::unauthorized)
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializing path to redirecting @deprecated
|
||||||
|
$redirect ??= $_SERVER['HTTP_REFERER'] ?? '/';
|
||||||
|
|
||||||
|
// Redirecting
|
||||||
|
header("Location: $redirect", response_code: status::see_other->value);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication
|
||||||
|
*
|
||||||
|
* @param string|null $mail Mail
|
||||||
|
* @param string|null $password Password
|
||||||
|
* @param int|string|bool|null $remember Remember
|
||||||
|
* @param string|null $redirect Redirect @deprecated
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function authentication(
|
||||||
|
?string $mail = null,
|
||||||
|
?string $password = null,
|
||||||
|
int|string|bool|null $remember = null,
|
||||||
|
?string $redirect = null
|
||||||
|
): ?string {
|
||||||
|
// Filtering the remember argument
|
||||||
|
$remember = (bool) $remember;
|
||||||
|
|
||||||
|
if ($this->view->account = account::authenticate(mail: $mail, password: $password, remember: $remember, errors: $this->errors['account'])) {
|
||||||
|
// Authenticated
|
||||||
|
} else {
|
||||||
|
// Not authenticated
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->status(status::forbidden)
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializing path to redirecting @deprecated
|
||||||
|
$redirect ??= $_SERVER['HTTP_REFERER'] ?? '/';
|
||||||
|
|
||||||
|
// Redirecting
|
||||||
|
header("Location: $redirect", response_code: status::see_other->value);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deauthentication
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function deauthentication(): null
|
||||||
|
{
|
||||||
|
if (account::deauthenticate(errors: $this->errors['account'])) {
|
||||||
|
// Deauthenticated
|
||||||
|
} else {
|
||||||
|
// Not deauthenticated
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->status(status::internal_server_error)
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Перенаправление
|
||||||
|
header('Location: /', response_code: status::see_other->value);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data
|
||||||
|
*
|
||||||
|
* If the information requested is not by an administrator,
|
||||||
|
* only publicly permitted information will be returned.
|
||||||
|
*
|
||||||
|
* @param int|null $identifier Identifier
|
||||||
|
*
|
||||||
|
* @return string JSON-документ
|
||||||
|
*/
|
||||||
|
public function data(?int $identifier = null): ?string
|
||||||
|
{
|
||||||
|
if ($account = account::read(expressions: ['identifier' => $identifier], errors: $this->errors['account'])) {
|
||||||
|
// Found the account
|
||||||
|
|
||||||
|
// Initializing the account
|
||||||
|
$this->view->account = account::initialize(errors: $this->errors['account']);
|
||||||
|
|
||||||
|
if ($this->view->account) {
|
||||||
|
// Initialized the account
|
||||||
|
|
||||||
|
if ($this->view->account->permissions['accounts'] ?? 0 === 1) {
|
||||||
|
// Authorized to accounts
|
||||||
|
} else {
|
||||||
|
// Not authorized to accounts
|
||||||
|
|
||||||
|
// Deinitializing the account private properties
|
||||||
|
unset($account->password, $account->hash, $account->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
|
||||||
|
// Request for any response
|
||||||
|
|
||||||
|
// Render page
|
||||||
|
$page = $this->view->render('pages/account/index.html');
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->status(status::ok)
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->json($account)
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Deinitializing rendered page
|
||||||
|
unset($page);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not found the account
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->status(status::not_found)
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
313
kodorvan/surikov/system/controllers/books.php
Executable file
@@ -0,0 +1,313 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\controllers;
|
||||||
|
|
||||||
|
// The project
|
||||||
|
use kodorvan\surikov\controllers\core,
|
||||||
|
kodorvan\surikov\models\account,
|
||||||
|
kodorvan\surikov\models\book;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
mirzaev\minimal\http\enumerations\status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Books controller
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\controllers
|
||||||
|
*
|
||||||
|
* @param array $errors Registry of errors
|
||||||
|
*
|
||||||
|
* @method null index() Books page
|
||||||
|
* @method null write() Write
|
||||||
|
* @method null read(int|string|null $identifier, int|string|null $page) Read
|
||||||
|
* @method null delete(int|string|null $identifier) Delete
|
||||||
|
* @method null rotate(int|string|null $identifier, int|string|null $page) Rotate
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class books extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Errors
|
||||||
|
*
|
||||||
|
* @var array $errors Registry of errors
|
||||||
|
*/
|
||||||
|
protected array $errors = [
|
||||||
|
'system' => [],
|
||||||
|
'account' => [],
|
||||||
|
'books' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Books page (or the book page)
|
||||||
|
*
|
||||||
|
* @param int|string|null $identifier Identifier of the book
|
||||||
|
* @param int|string $page Page if the book
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function index(
|
||||||
|
int|string|null $identifier = null,
|
||||||
|
int|string $page = 1
|
||||||
|
): null {
|
||||||
|
// Normalizing the page argument
|
||||||
|
$page = (int) $page;
|
||||||
|
if ($page < 1) $page = 1;
|
||||||
|
|
||||||
|
if (isset($identifier)) {
|
||||||
|
// Received the book identifier (the book)
|
||||||
|
|
||||||
|
// Initializing the book
|
||||||
|
$this->view->book = book::read(expressions: ['identifier' => (int) $identifier])[0] ?? null;
|
||||||
|
|
||||||
|
if (empty($page)) {
|
||||||
|
// Received the book page
|
||||||
|
|
||||||
|
// Initializing the book page
|
||||||
|
$this->view->page = $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
|
||||||
|
// Request for any response
|
||||||
|
|
||||||
|
// Render page
|
||||||
|
$page = $this->view->render('books/book.html');
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->write($page)
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Deinitializing rendered page
|
||||||
|
unset($page);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not received the book identifier (all books)
|
||||||
|
|
||||||
|
// Reading books
|
||||||
|
$this->view->books = book::read(limit: 30, page: $page);
|
||||||
|
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
|
||||||
|
// Request for any response
|
||||||
|
|
||||||
|
// Render page
|
||||||
|
$page = $this->view->render('books/index.html');
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->write($page)
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Deinitializing rendered page
|
||||||
|
unset($page);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write
|
||||||
|
*
|
||||||
|
* Import books into the storage and the database
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function write(): null
|
||||||
|
{
|
||||||
|
if (account::initialize(errors: $this->errors['account'])->access('books')) {
|
||||||
|
// Initialized account and authorized to books
|
||||||
|
|
||||||
|
if (count($books = book::import(files: $this->request->files['books'] ?? [], errors: $this->errors['books'])) > 0) {
|
||||||
|
// Imported books
|
||||||
|
} else {
|
||||||
|
// Not imported books
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirecting
|
||||||
|
header(header: 'Location: /books', response_code: status::see_other->value);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read
|
||||||
|
*
|
||||||
|
* Read the book page file (expected jpeg image)
|
||||||
|
*
|
||||||
|
* @param int|string|null $identifier Identifier of the book
|
||||||
|
* @param int|string|null $page Page of the book
|
||||||
|
*
|
||||||
|
* @return string|null The book page file
|
||||||
|
*/
|
||||||
|
public function read(
|
||||||
|
int|string|null $identifier = null,
|
||||||
|
int|string|null $page = 1
|
||||||
|
): ?string {
|
||||||
|
// Normalizing the identifier argument
|
||||||
|
$identifier = (int) $identifier;
|
||||||
|
|
||||||
|
// Normalizing the page argument
|
||||||
|
$page = (int) $page;
|
||||||
|
if ($page < 1) $page = 1;
|
||||||
|
|
||||||
|
// Initializing the book file path
|
||||||
|
$file = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $identifier . DIRECTORY_SEPARATOR . $page . '.jpg';
|
||||||
|
|
||||||
|
if (file_exists($file)) {
|
||||||
|
// Found the book page file
|
||||||
|
|
||||||
|
// Initializing headers
|
||||||
|
header('Content-Description: File Transfer');
|
||||||
|
header('Content-Type: image/jpeg');
|
||||||
|
header('Content-Disposition: attachment; filename=' . basename($file));
|
||||||
|
header('Content-Transfer-Encoding: binary');
|
||||||
|
header('Content-Length: ' . filesize($file));
|
||||||
|
|
||||||
|
// Cleaning the output buffer
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return file_get_contents($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete
|
||||||
|
*
|
||||||
|
* Delete the book from the storage and the database
|
||||||
|
*
|
||||||
|
* @param int|string|null $identifier Identifier of the book
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function delete(int|string|null $identifier = null): null
|
||||||
|
{
|
||||||
|
if (account::initialize(errors: $this->errors['account'])->access('books')) {
|
||||||
|
// Initialized account and authorized to books
|
||||||
|
|
||||||
|
// Initializing the processing status
|
||||||
|
$status = false;
|
||||||
|
|
||||||
|
// Normalizing the identifier argument
|
||||||
|
$identifier = (int) $identifier;
|
||||||
|
|
||||||
|
if (book::delete(identifier: $identifier, errors: $this->errors['books'])) {
|
||||||
|
// Deleted the book from the database
|
||||||
|
|
||||||
|
// Initializing the book directory path
|
||||||
|
$directory = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $identifier;
|
||||||
|
|
||||||
|
if (file_exists($directory)) {
|
||||||
|
// Found the book directory
|
||||||
|
|
||||||
|
// Deletimg the book from the storage
|
||||||
|
exec('rm -rf ' . escapeshellarg($directory));
|
||||||
|
|
||||||
|
// Writing the processing status
|
||||||
|
$status = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::json->value)) {
|
||||||
|
// Request for JSON response
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->json([
|
||||||
|
'status' => $status,
|
||||||
|
'errors' => $this->errors
|
||||||
|
])
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate
|
||||||
|
*
|
||||||
|
* Rotate the book image in the storage
|
||||||
|
*
|
||||||
|
* @param int|string|null $identifier Identifier of the book
|
||||||
|
* @param int|string|null $page Page of the book
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function rotate(
|
||||||
|
int|string|null $identifier = null,
|
||||||
|
int|string|null $page = 1
|
||||||
|
): null {
|
||||||
|
if (account::initialize(errors: $this->errors['account'])->access('books')) {
|
||||||
|
// Initialized account and authorized to books
|
||||||
|
|
||||||
|
// Normalizing the identifier argument
|
||||||
|
$identifier = (int) $identifier;
|
||||||
|
|
||||||
|
// Normalizing the page argument
|
||||||
|
$page = (int) $page;
|
||||||
|
|
||||||
|
// Rotating the book page file
|
||||||
|
$status = book::rotate(identifier: $identifier, page: $page, errors: $this->errors['books']);
|
||||||
|
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::json->value)) {
|
||||||
|
// Request for JSON response
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->json([
|
||||||
|
'status' => $status,
|
||||||
|
'errors' => $this->errors
|
||||||
|
])
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
72
kodorvan/surikov/system/controllers/contacts.php
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\controllers;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use kodorvan\surikov\controllers\core,
|
||||||
|
kodorvan\surikov\models\account;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
mirzaev\minimal\http\enumerations\status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contacts controller
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\controllers
|
||||||
|
*
|
||||||
|
* @param array $errors Registry of errors
|
||||||
|
*
|
||||||
|
* @method null index() Contacts page
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class contacts extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Errors
|
||||||
|
*
|
||||||
|
* @var array $errors Registry of errors
|
||||||
|
*/
|
||||||
|
protected array $errors = [
|
||||||
|
'system' => [],
|
||||||
|
'account' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contacts page
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function index(): null
|
||||||
|
{
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
|
||||||
|
// Request for any response
|
||||||
|
|
||||||
|
// Render page
|
||||||
|
$page = $this->view->render('pages/contacts/index.html');
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->write($page)
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Deinitializing rendered page
|
||||||
|
unset($page);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
88
kodorvan/surikov/system/controllers/core.php
Executable file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\controllers;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use kodorvan\surikov\views\templater,
|
||||||
|
kodorvan\surikov\models\core as models,
|
||||||
|
kodorvan\surikov\models\account;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\core as minimal,
|
||||||
|
mirzaev\minimal\controller,
|
||||||
|
mirzaev\minimal\http\response,
|
||||||
|
mirzaev\minimal\http\enumerations\status;
|
||||||
|
|
||||||
|
// Library for languages support
|
||||||
|
use mirzaev\languages\language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core controller
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\controllers
|
||||||
|
*
|
||||||
|
* @param language $language Language
|
||||||
|
* @param response $response Response
|
||||||
|
* @param array $errors Registry of errors
|
||||||
|
*
|
||||||
|
* @method void __construct(minimal $minimal) Constructor
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
class core extends controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Language
|
||||||
|
*
|
||||||
|
* @var language $language Language
|
||||||
|
*/
|
||||||
|
protected language $language = language::ru;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response
|
||||||
|
*
|
||||||
|
* @see https://wiki.php.net/rfc/property-hooks (find a table about backed and virtual hooks)
|
||||||
|
*
|
||||||
|
* @var response $response Response
|
||||||
|
*/
|
||||||
|
protected response $response {
|
||||||
|
// Read
|
||||||
|
get => $this->response ??= $this->request->response();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Errors
|
||||||
|
*
|
||||||
|
* @var array $errors Registry of errors
|
||||||
|
*/
|
||||||
|
protected array $errors = [
|
||||||
|
'system' => [],
|
||||||
|
'account' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param minimal $core Instance of the MINIMAL
|
||||||
|
* @param bool $initialize Initialize a controller?
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(minimal $core)
|
||||||
|
{
|
||||||
|
// Blocking requests from CloudFlare (better to write this blocking into nginx config file)
|
||||||
|
if (isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] === 'nginx-ssl early hints') return status::bruh->label;
|
||||||
|
|
||||||
|
// Initializing the models core
|
||||||
|
new models();
|
||||||
|
|
||||||
|
// Initializing the view template engine instance
|
||||||
|
$this->view = new templater(account::initialize(errors: $this->errors['account']));
|
||||||
|
|
||||||
|
// For the extends system
|
||||||
|
parent::__construct(core: $core);
|
||||||
|
}
|
||||||
|
}
|
45
kodorvan/surikov/system/controllers/errors.php
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\controllers;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use kodorvan\surikov\controllers\core;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
mirzaev\minimal\http\enumerations\status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Errors controller
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\controllers
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class errors_controller extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Errors
|
||||||
|
*
|
||||||
|
* @var array $errors Registry of errors
|
||||||
|
*/
|
||||||
|
protected array $errors = [
|
||||||
|
'system' => [],
|
||||||
|
'account' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
public function error404(): ?string
|
||||||
|
{
|
||||||
|
// Генерация представления
|
||||||
|
return 'Ошибка 404 (не найдено)';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function error500(): ?string
|
||||||
|
{
|
||||||
|
// Генерация представления
|
||||||
|
return 'Ошибка 500 (на стороне сервера)';
|
||||||
|
}
|
||||||
|
}
|
72
kodorvan/surikov/system/controllers/index.php
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\controllers;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use kodorvan\surikov\controllers\core,
|
||||||
|
kodorvan\surikov\models\account;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
mirzaev\minimal\http\enumerations\status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index controller
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\controllers
|
||||||
|
*
|
||||||
|
* @param array $errors Registry of errors
|
||||||
|
*
|
||||||
|
* @method null index() Main page
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class index extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Errors
|
||||||
|
*
|
||||||
|
* @var array $errors Registry of errors
|
||||||
|
*/
|
||||||
|
protected array $errors = [
|
||||||
|
'system' => [],
|
||||||
|
'account' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main page
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function index(): null
|
||||||
|
{
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
|
||||||
|
// Request for any response
|
||||||
|
|
||||||
|
// Render page
|
||||||
|
$page = $this->view->render('main/index.html');
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->write($page)
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Deinitializing rendered page
|
||||||
|
unset($page);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
74
kodorvan/surikov/system/controllers/kemenov.php
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\controllers;
|
||||||
|
|
||||||
|
// The project
|
||||||
|
use kodorvan\surikov\controllers\core,
|
||||||
|
kodorvan\surikov\models\account;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
mirzaev\minimal\http\enumerations\status;
|
||||||
|
|
||||||
|
use Twig\Environment as view;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kemenov constroller
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\controllers
|
||||||
|
*
|
||||||
|
* @param array $errors Registry of errors
|
||||||
|
*
|
||||||
|
* @method null index() Kemenov page
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class kemenov extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Errors
|
||||||
|
*
|
||||||
|
* @var array $errors Registry of errors
|
||||||
|
*/
|
||||||
|
protected array $errors = [
|
||||||
|
'system' => [],
|
||||||
|
'account' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kemenov page
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function index(): null
|
||||||
|
{
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
|
||||||
|
// Request for any response
|
||||||
|
|
||||||
|
// Render page
|
||||||
|
$page = $this->view->render('pages/kemenov/index.html');
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->write($page)
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Deinitializing rendered page
|
||||||
|
unset($page);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
72
kodorvan/surikov/system/controllers/surikov.php
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\controllers;
|
||||||
|
|
||||||
|
// The project
|
||||||
|
use kodorvan\surikov\controllers\core,
|
||||||
|
kodorvan\surikov\models\account;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\http\enumerations\content,
|
||||||
|
mirzaev\minimal\http\enumerations\status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Surikov controller
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\controllers
|
||||||
|
*
|
||||||
|
* @param array $errors Registry of errors
|
||||||
|
*
|
||||||
|
* @method null index() Surikov page
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class surikov extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Errors
|
||||||
|
*
|
||||||
|
* @var array $errors Registry of errors
|
||||||
|
*/
|
||||||
|
protected array $errors = [
|
||||||
|
'system' => [],
|
||||||
|
'account' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Surikov page
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function index(): null
|
||||||
|
{
|
||||||
|
if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
|
||||||
|
// Request for any response
|
||||||
|
|
||||||
|
// Render page
|
||||||
|
$page = $this->view->render('pages/surikov/index.html');
|
||||||
|
|
||||||
|
// Sending response
|
||||||
|
$this->response
|
||||||
|
->start()
|
||||||
|
->clean()
|
||||||
|
->sse()
|
||||||
|
->write($page)
|
||||||
|
->validate($this->request)
|
||||||
|
?->body()
|
||||||
|
->end();
|
||||||
|
|
||||||
|
// Deinitializing rendered page
|
||||||
|
unset($page);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
711
kodorvan/surikov/system/models/account.php
Executable file
@@ -0,0 +1,711 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\models;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use kodorvan\surikov\models\core;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use pdo,
|
||||||
|
exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\models
|
||||||
|
*
|
||||||
|
* @param int $identifier Identifier
|
||||||
|
* @param string $password Password
|
||||||
|
* @param string|null $hash Hash
|
||||||
|
* @param int $time Time
|
||||||
|
* @param array $permissions Permissions
|
||||||
|
*
|
||||||
|
* @method void __construct(array $parameters) Constructor
|
||||||
|
* @method static static|null registrate(string $mail, string $password, bool $authenticate, array &$errors) Registrate
|
||||||
|
* @method static static|null authenticate(string $mail, string $password, bool $remember, array &$errors) Authenticate
|
||||||
|
* @method static bool deauthenticate(array &$errors) Deauthenticate
|
||||||
|
* @method static static|null initialize(?int $identifier, array &$errors) Initialize
|
||||||
|
* @method static array permissions(int $identifier, array &$errors) Permissions
|
||||||
|
* @method static bool|null access(string $permission, array &$errors) Access
|
||||||
|
* @method static static|null write(string $mail, string $password, array &$errors) Write
|
||||||
|
* @method static static|null read(array $expressions, array &$errors) Read
|
||||||
|
* @method static array|bool hash(int $identifier, string|null $hash, int|null $time, array &$errors) Hash
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class account extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Identifier
|
||||||
|
*
|
||||||
|
* @var int $identifier
|
||||||
|
*/
|
||||||
|
public int $identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mail
|
||||||
|
*
|
||||||
|
* @var string $mail
|
||||||
|
*/
|
||||||
|
public string $mail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Password
|
||||||
|
*
|
||||||
|
* @var string $password
|
||||||
|
*/
|
||||||
|
public string $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash
|
||||||
|
*
|
||||||
|
* Hash of the session
|
||||||
|
*
|
||||||
|
* @var string|null $hash
|
||||||
|
*/
|
||||||
|
public ?string $hash = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time
|
||||||
|
*
|
||||||
|
* Time of the session
|
||||||
|
*
|
||||||
|
* @var int|null $time
|
||||||
|
*/
|
||||||
|
public ?int $time = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permissions
|
||||||
|
*
|
||||||
|
* @var array $permissions
|
||||||
|
*/
|
||||||
|
public array $permissions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param array $parameters Parameters
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(array $parameters)
|
||||||
|
{
|
||||||
|
foreach ($parameters as $key => $value) {
|
||||||
|
// Iterating over parameters
|
||||||
|
|
||||||
|
// Writing the property
|
||||||
|
if (property_exists($this, $key)) $this->$key = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registrate
|
||||||
|
*
|
||||||
|
* @param string $mail Mail
|
||||||
|
* @param string $password Password
|
||||||
|
* @param bool $authenticate Authenticate the account after registration?
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return static|null Account
|
||||||
|
*/
|
||||||
|
public static function registrate(string $mail, string $password, bool $authenticate = true, array &$errors = []): ?static
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (static::initialize(errors: $errors)) {
|
||||||
|
// Authenticated the account
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Уже аутентифицирован');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($account = static::read(expressions: ['mail' => $mail]))) {
|
||||||
|
// Not found the account
|
||||||
|
|
||||||
|
if (static::write(mail: $mail, password: $password, errors: $errors)) {
|
||||||
|
// Registrated the account
|
||||||
|
|
||||||
|
if ($authenticate) {
|
||||||
|
// Requested authentication after registration
|
||||||
|
|
||||||
|
// Authentication
|
||||||
|
$account = static::authenticate(mail: $mail, password: $password, remember: true, errors: $errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Found the account
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate
|
||||||
|
*
|
||||||
|
* @param string $mail Mail
|
||||||
|
* @param string $password Password
|
||||||
|
* @param bool $remember Increase time of the session?
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return static|null Account
|
||||||
|
*/
|
||||||
|
public static function authenticate(string $mail, string $password, bool $remember = false, array &$errors = []): ?static
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (static::initialize(errors: $errors)) {
|
||||||
|
// Authenticated the account
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Уже аутентифицирован');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($account = static::read(expressions: ['mail' => $mail]))) {
|
||||||
|
// Not found the account
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Не удалось найти аккаунт');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password_verify($password, $account->password)) {
|
||||||
|
// Matches hashes
|
||||||
|
|
||||||
|
// Initializing the session identifier
|
||||||
|
session_id((string) $account->identifier);
|
||||||
|
|
||||||
|
// Initializing the session name
|
||||||
|
session_name('identifier');
|
||||||
|
|
||||||
|
// Initializing the session
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
// Calculating the session time
|
||||||
|
$time = time() + ($remember ? 604800 : 86400);
|
||||||
|
|
||||||
|
// Generating the session hash
|
||||||
|
$hash = static::hash(identifier: (int) $account->identifier, hash: crypt($account->password, time() . $account->identifier), time: $time, errors: $errors)['hash'];
|
||||||
|
|
||||||
|
// Initializing cookies
|
||||||
|
setcookie(name: 'hash', value: $hash, expires_or_options: $time, path: '/', secure: true);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $account;
|
||||||
|
} else {
|
||||||
|
// Not matches hashes
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Wrong password');
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deauthenticate
|
||||||
|
*
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return bool The session is deauthenticated?
|
||||||
|
*/
|
||||||
|
public static function deauthenticate(array &$errors = []): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if ($account = static::initialize(errors: $errors)) {
|
||||||
|
// Authenticated the account
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("UPDATE `accounts` SET `hash` = null, `time` = 0 WHERE `identifier` = :identifier");
|
||||||
|
|
||||||
|
// Initializing parameters of the request
|
||||||
|
$parameters = [
|
||||||
|
":identifier" => $account->identifier,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Generating the answer
|
||||||
|
$request->fetch(pdo::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Deinitializing cookies
|
||||||
|
setcookie('identifier', '', 0, path: '/', secure: true);
|
||||||
|
setcookie('hash', '', 0, path: '/', secure: true);
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Not authenticated the account
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Not authenticated');
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the registry of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializing
|
||||||
|
*
|
||||||
|
* Initializing of the account
|
||||||
|
*
|
||||||
|
* @param int|null $identifier Identifier of the account
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return static|null Account
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
public static function init(?int $identifier = null, array &$errors = []): ?static
|
||||||
|
{
|
||||||
|
// Exit (success/fail)
|
||||||
|
return static::initialize(identifier: $identifier, errors: $errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize
|
||||||
|
*
|
||||||
|
* Initializing of the account
|
||||||
|
*
|
||||||
|
* @param int|null $identifier Identifier of the account
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return static|null Account
|
||||||
|
*/
|
||||||
|
public static function initialize(?int $identifier = null, array &$errors = []): ?static
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (isset($identifier)) {
|
||||||
|
// Recaifer identifier of the account
|
||||||
|
|
||||||
|
if (empty($account = static::read(['identifier' => $identifier]))) {
|
||||||
|
// Found the account
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Не найден пользователь');
|
||||||
|
}
|
||||||
|
} else if (!empty($_COOKIE['identifier']) && !empty($_COOKIE['hash'])) {
|
||||||
|
// Found cookie with the account data (expected that is already authenticated)
|
||||||
|
|
||||||
|
if ($_COOKIE['hash'] === static::hash(identifier: (int) $_COOKIE['identifier'], errors: $errors)['hash']) {
|
||||||
|
// Matches hashes from the cookie and the database
|
||||||
|
} else {
|
||||||
|
// Not matches hashes from the cookie and the database
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Вы аутентифицированы с другого устройства (не совпадают хеши аутентификации)');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($account = static::read([
|
||||||
|
'identifier' => $_COOKIE['identifier'],
|
||||||
|
'hash' => $_COOKIE['hash']
|
||||||
|
]))) {
|
||||||
|
// Not found the account or a connection with it
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Не найден пользователь или время аутентификации истекло');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not found parameters for authentication
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializing permissions
|
||||||
|
$account->permissions = static::permissions(identifier: (int) $account->identifier, errors: $errors);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $account;
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permissions
|
||||||
|
*
|
||||||
|
* Read permissions of the account from the database
|
||||||
|
*
|
||||||
|
* @param int $identifier Identifier of the account
|
||||||
|
* @param array &$errors Registy of errors
|
||||||
|
*
|
||||||
|
* @return array Permissions of the account
|
||||||
|
*/
|
||||||
|
public static function permissions(int $identifier, array &$errors = []): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("SELECT * FROM `permissions` WHERE `account` = :identifier");
|
||||||
|
|
||||||
|
// Initializing parametes of the request
|
||||||
|
$parameters = [
|
||||||
|
":identifier" => $identifier
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Generating the answer
|
||||||
|
if (empty($response = $request->fetch(pdo::FETCH_ASSOC))) {
|
||||||
|
// Not found permissions
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Not found permissions');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deleting deprecated parameters
|
||||||
|
unset($response['identifier']);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $response;
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access
|
||||||
|
*
|
||||||
|
* Check for the account authorizing by the permission
|
||||||
|
*
|
||||||
|
* @param string $permission Permission
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return bool|null Authorized?
|
||||||
|
*/
|
||||||
|
public function access(string $permission, array &$errors = []): ?bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Exit (success)
|
||||||
|
return isset($this->permissions[$permission]) ? (bool) $this->permissions[$permission] : null;
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors['account'][] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write
|
||||||
|
*
|
||||||
|
* Write the account into the database
|
||||||
|
*
|
||||||
|
* @param string $mail Mail
|
||||||
|
* @param string $password Password
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return static|null Account
|
||||||
|
*/
|
||||||
|
public static function write(string $mail, string $password, array &$errors = []): ?static
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing parameters of the request
|
||||||
|
$parameters = [];
|
||||||
|
|
||||||
|
// Filtering the parameter
|
||||||
|
if (filter_var($mail, FILTER_VALIDATE_EMAIL) === false) throw new exception('Не удалось распознать почту');
|
||||||
|
if (iconv_strlen($mail) < 3) throw new exception('Длина почты должна быть не менее 3 символов');
|
||||||
|
if (iconv_strlen($mail) > 60) throw new exception('Длина почты должна быть не более 80 символов');
|
||||||
|
|
||||||
|
// Writing the parameter
|
||||||
|
$parameters[':mail'] = $mail;
|
||||||
|
|
||||||
|
// Filtering the parameter
|
||||||
|
if (iconv_strlen($password) < 3) throw new exception('Длина пароля должна быть не менее 3 символов');
|
||||||
|
if (iconv_strlen($password) > 60) throw new exception('Длина пароля должна быть не более 120 символов');
|
||||||
|
|
||||||
|
// Writing the parameter
|
||||||
|
$parameters[':password'] = password_hash($password, PASSWORD_BCRYPT);
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("INSERT INTO `accounts` (" . (isset($name) ? '`name`' : '') . (isset($name) && isset($mail) ? ', ' : '') . (isset($mail) ? '`mail`' : '') . ((isset($name) || isset($mail)) && isset($password) ? ', ' : '') . (isset($password) ? '`password`' : '') . ") VALUES (" . (isset($name) ? ':name' : '') . (isset($name) && isset($mail) ? ', ' : '') . (isset($mail) ? ':mail' : '') . ((isset($name) || isset($mail)) && isset($password) ? ', ' : '') . (isset($password) ? ':password' : '') . ")");
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Generating the answer
|
||||||
|
$request->fetch(pdo::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Reading the account
|
||||||
|
$account = static::read(expressions: ['mail' => $mail]);
|
||||||
|
|
||||||
|
if ($account instanceof static) {
|
||||||
|
// Registered the account
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("INSERT INTO `permissions` (`account`) VALUES (:identifier)");
|
||||||
|
|
||||||
|
// Initializing parameters of the request
|
||||||
|
$parameters = [
|
||||||
|
':identifier' => $account->identifier
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Generating the answer
|
||||||
|
$request->fetch(pdo::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read
|
||||||
|
*
|
||||||
|
* Read the account from the database
|
||||||
|
*
|
||||||
|
* @param array $expressions Request expressions [name => value]
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return static|null Account
|
||||||
|
*/
|
||||||
|
public static function read(array $expressions, array &$errors = []): ?static
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing the request row
|
||||||
|
$row = 'WHERE ';
|
||||||
|
|
||||||
|
// Declaring the request parameters
|
||||||
|
$parameters = [];
|
||||||
|
|
||||||
|
foreach ($expressions as $name => $value) {
|
||||||
|
// Iterating over request expressions
|
||||||
|
|
||||||
|
// Generating the request row
|
||||||
|
$row .= "`$name` = :$name &&";
|
||||||
|
|
||||||
|
// Generating the request parameters
|
||||||
|
$parameters[":$name"] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleaning the request row
|
||||||
|
$row = empty($expressions) ? '' : trim(trim($row, '&&'));
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("SELECT * FROM `accounts` $row LIMIT 1");
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Generating the response
|
||||||
|
$response = $request->fetch(pdo::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!empty($response) && $account = new static($response ?? [])) {
|
||||||
|
// Found the account
|
||||||
|
|
||||||
|
if ($permissions = static::permissions(identifier: (int) $account->identifier, errors: $errors)) {
|
||||||
|
// Found the account permissions
|
||||||
|
|
||||||
|
// Writing permissions into the account implementator
|
||||||
|
$account->permissions = $permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $account;
|
||||||
|
} else {
|
||||||
|
// Not found the account
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Not found the account');
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash
|
||||||
|
*
|
||||||
|
* Write or read the account hash from the database
|
||||||
|
*
|
||||||
|
* @param int $identifier Identifier
|
||||||
|
* @param int|null $hash Hash
|
||||||
|
* @param string|null $time Time
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return array|bool Read: ['hash' => $hash, 'time' => $time]; Write: true; Error: false
|
||||||
|
*/
|
||||||
|
public static function hash(int $identifier, string|null $hash = null, int|null $time = null, array &$errors = []): array|bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (isset($hash, $time)) {
|
||||||
|
// Write (received hash and time)
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("UPDATE `accounts` SET `hash` = :hash, `time` = :time WHERE `identifier` = :identifier");
|
||||||
|
|
||||||
|
// Initializing the request parameters
|
||||||
|
$parameters = [
|
||||||
|
":identifier" => $identifier,
|
||||||
|
":hash" => $hash,
|
||||||
|
":time" => $time,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Generating the answer
|
||||||
|
$response = $request->fetch(pdo::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return ['hash' => $hash, 'time' => $time];
|
||||||
|
} else {
|
||||||
|
// Read (not received hash and time)
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("SELECT `hash`, `time` FROM `accounts` WHERE `identifier` = :identifier");
|
||||||
|
|
||||||
|
// Initializing the request parameters
|
||||||
|
$parameters = [
|
||||||
|
":identifier" => $identifier
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Generating the answer
|
||||||
|
extract((array) $request->fetch(pdo::FETCH_ASSOC));
|
||||||
|
|
||||||
|
if (!empty($response['time']) && $response['time'] <= time()) {
|
||||||
|
// Expired the hash
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("UPDATE `accounts` SET `hash` = :hash, `time` = :time WHERE `identifier` = :identifier");
|
||||||
|
|
||||||
|
// Initializing the request parameters
|
||||||
|
$parameters = [
|
||||||
|
":identifier" => $identifier,
|
||||||
|
":hash" => null,
|
||||||
|
":time" => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Generating the answer
|
||||||
|
$response = $request->fetch(pdo::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Expired the hash');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return ['hash' => $hash, 'time' => $time];
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors['account'][] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
412
kodorvan/surikov/system/models/book.php
Executable file
@@ -0,0 +1,412 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\models;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use kodorvan\surikov\models\account;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use pdo,
|
||||||
|
exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Book model
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\models
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
*
|
||||||
|
* @method static int|null write(string $title, ?string $description, ?int $account, array &$errors) Write
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class book extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Write
|
||||||
|
*
|
||||||
|
* Write into the database
|
||||||
|
*
|
||||||
|
* @param string $title Title
|
||||||
|
* @param string|null $description Description
|
||||||
|
* @param int|null $account Identifier of the account
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return int|null The book identifier
|
||||||
|
*/
|
||||||
|
public static function write(string $title, ?string $description = null, ?int $account = null, array &$errors = []): ?int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing the account
|
||||||
|
$account = account::initialize($account, $errors);
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("INSERT INTO `books` (`account`, `title`, `description`) VALUES (:account, :title, :description)");
|
||||||
|
|
||||||
|
// Initializing the request parameters
|
||||||
|
$parameters = [
|
||||||
|
':account' => $account->identifier,
|
||||||
|
':title' => $title,
|
||||||
|
':description' => $description
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
if ($id = static::$database->lastInsertId()) {
|
||||||
|
// Received the created book identifier
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return (int) $id;
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read
|
||||||
|
*
|
||||||
|
* Read books from the database
|
||||||
|
*
|
||||||
|
* @param array $expressions Request expressions
|
||||||
|
* @param int $limit Amount
|
||||||
|
* @param int $page Page (offset by $limit)
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return array|false Books
|
||||||
|
*/
|
||||||
|
public static function read(array $expressions = [], int $limit = 1, int $page = 1, array &$errors = []): array|false
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing the request row
|
||||||
|
$row = 'WHERE ';
|
||||||
|
|
||||||
|
// Initializing the request parameters
|
||||||
|
$parameters = [];
|
||||||
|
|
||||||
|
foreach ($expressions as $name => $value) {
|
||||||
|
// Iterating over the request expressions
|
||||||
|
|
||||||
|
// Generating the request row
|
||||||
|
$row .= "`$name` = :$name &&";
|
||||||
|
|
||||||
|
// Generating the request parameters
|
||||||
|
$parameters[":$name"] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleaning the request row
|
||||||
|
$row = empty($expressions) ? '' : trim(trim($row, '&&'));
|
||||||
|
|
||||||
|
// Initializing the page
|
||||||
|
$page = $limit * --$page;
|
||||||
|
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("SELECT * FROM `books` $row LIMIT $page, $limit");
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute($parameters);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return (array) $request->fetchAll(pdo::FETCH_ASSOC);
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete
|
||||||
|
*
|
||||||
|
* Delete the book from the database
|
||||||
|
*
|
||||||
|
* @param int $identifier Identifier
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return bool Is the book was deleted?
|
||||||
|
*/
|
||||||
|
public static function delete(int $identifier, array &$errors = []): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("DELETE FROM `books` WHERE `identifier` = :identifier LIMIT 1");
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute([':identifier' => $identifier]);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return true;
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import
|
||||||
|
*
|
||||||
|
* Import books into the storage and database
|
||||||
|
*
|
||||||
|
* @param array $files Books
|
||||||
|
* @param int|null $account Identifier of the account
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return array|false Imported books
|
||||||
|
*/
|
||||||
|
public static function import(array $files, ?int $account = null, array &$errors = []): array|false
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (empty($files)) {
|
||||||
|
// Not received books
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Не найдены книги для записи');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializing the account
|
||||||
|
$account = account::initialize($account, $errors);
|
||||||
|
|
||||||
|
// Declaring the buffer of saved books
|
||||||
|
$saved = [];
|
||||||
|
|
||||||
|
for ($i = -1; count($files['name']) > ++$i;) {
|
||||||
|
// Iterating over books
|
||||||
|
|
||||||
|
// Generating the book file hash
|
||||||
|
$hash = hash_file('md5', $files['tmp_name'][$i]) ?? 0;
|
||||||
|
|
||||||
|
if (move_uploaded_file($files['tmp_name'][$i], \STORAGE . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $hash . '_' . $files['name'][$i])) {
|
||||||
|
// Saved the book file
|
||||||
|
|
||||||
|
// Writing into the buffer of saved books
|
||||||
|
$saved[] = [
|
||||||
|
'name' => preg_replace('/\.pdf/', '', $files['name'])[0],
|
||||||
|
'file' => $hash . '_' . $files['name'][$i]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declaring buffer of writed books
|
||||||
|
$writed = [];
|
||||||
|
|
||||||
|
foreach ($saved as $book) {
|
||||||
|
// Iterating over saved books
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($identifier = static::write(title: $book['name'], description: 'Без описания', account: $account->identifier ?? null, errors: $errors)) {
|
||||||
|
// Writed book into the database
|
||||||
|
|
||||||
|
// Initializing the book directory path
|
||||||
|
$directory = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $identifier . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
|
if (!file_exists($directory)) {
|
||||||
|
// Not found the book directory
|
||||||
|
|
||||||
|
if (!mkdir($directory, 0755, true)) {
|
||||||
|
// Failed to create the book directory
|
||||||
|
|
||||||
|
// Skipping (fail)
|
||||||
|
throw new exception('Не удалось записать директорию для книги');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializing the book file path
|
||||||
|
$file = \STORAGE . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $book['file'];
|
||||||
|
|
||||||
|
// Extracting images from the PDF document
|
||||||
|
exec("pdfimages -j '$file' '$directory'");
|
||||||
|
|
||||||
|
// Renaming files
|
||||||
|
exec("echo 'export j=-1; for i in $directory*.jpg; do let j+=1; mv \$i $directory\$j.jpg; done' | bash");
|
||||||
|
|
||||||
|
// Writing into the buffer of writed books
|
||||||
|
$writed[] = $identifier;
|
||||||
|
} else {
|
||||||
|
// Not writed into the database
|
||||||
|
|
||||||
|
// Skipping (fail)
|
||||||
|
throw new exception('Не удалось записать книгу в базу данных', 500);
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $writed;
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate
|
||||||
|
*
|
||||||
|
* Rotate the book page image
|
||||||
|
*
|
||||||
|
* @param int $identifier Identifier
|
||||||
|
* @param int $page Page (offset)
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return bool Is the book page was rotated?
|
||||||
|
*/
|
||||||
|
public static function rotate(int $identifier, int $page = 1, array &$errors = []): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing the request
|
||||||
|
$request = static::$database->prepare("SELECT EXISTS (SELECT * FROM `books` WHERE `identifier` = :identifier LIMIT 1)");
|
||||||
|
|
||||||
|
// Sending the request
|
||||||
|
$request->execute([':identifier' => $identifier]);
|
||||||
|
|
||||||
|
if ($request->fetch(pdo::FETCH_NUM)[0] === 1) {
|
||||||
|
// Found the book
|
||||||
|
|
||||||
|
// Initializing the book directory path
|
||||||
|
$directory = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $identifier;
|
||||||
|
|
||||||
|
// Initializing the book file path
|
||||||
|
$file = $directory . DIRECTORY_SEPARATOR . "$page.jpg";
|
||||||
|
|
||||||
|
// Initializing the book file new location path
|
||||||
|
$old = $directory . DIRECTORY_SEPARATOR . 'old' . DIRECTORY_SEPARATOR . "$page.jpg";
|
||||||
|
|
||||||
|
if (!file_exists($directory)) {
|
||||||
|
// Not found the book directory
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Не удалось найти директорию книги');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Инициализация директории оригинальных изображений
|
||||||
|
if (!file_exists($directory . DIRECTORY_SEPARATOR . 'old')) {
|
||||||
|
// Not found the directory for deprecated files
|
||||||
|
|
||||||
|
if (!mkdir($directory . DIRECTORY_SEPARATOR . 'old', 0755, true)) {
|
||||||
|
// Failed to create the directory for deprecated files
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
throw new exception('Failed to create the directory for deprecated files');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moving the deprecated file
|
||||||
|
exec("mv $file $old");
|
||||||
|
|
||||||
|
// Rotating the deprecated file and moving back
|
||||||
|
exec("jpegtran -rotate 90 $old > $file");
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount
|
||||||
|
*
|
||||||
|
* Calculate amount of pages in the book storage
|
||||||
|
*
|
||||||
|
* @param int $identifier Identifier
|
||||||
|
* @param array &$errors Registry of errors
|
||||||
|
*
|
||||||
|
* @return int|false Amount of pages
|
||||||
|
*/
|
||||||
|
public static function amount(int $id, array &$errors = []): int|false
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing the iterator
|
||||||
|
$page = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Iterating over the book pages files in ascending order (from 0.jpg to 999.jpg and more) (!!! recursion !!!)
|
||||||
|
|
||||||
|
if (!file_exists(\STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $id . DIRECTORY_SEPARATOR . $page++ . '.jpg')) {
|
||||||
|
// Not found the book page by the iterator
|
||||||
|
|
||||||
|
// Exit (success) (!!! exit from the recursion !!!)
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Exception
|
||||||
|
|
||||||
|
// Writing into the errors registry
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit (fail)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
54
kodorvan/surikov/system/models/core.php
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\models;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\model;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use pdo,
|
||||||
|
pdoexception,
|
||||||
|
exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core model
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\models
|
||||||
|
*
|
||||||
|
* @param pdo $database Database
|
||||||
|
*
|
||||||
|
* @method void __construct(?pdo $database) Constructor
|
||||||
|
* @method void __set(string $name, mixed $value) Write
|
||||||
|
* @method mixed __get(string $name) Read
|
||||||
|
* @method bool __isset(string $name) Isset
|
||||||
|
* @method void __unset(string $name) Deinitialize
|
||||||
|
* @method mixed __callStatic(string $name, mixed $arguments) Call static
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
class core extends model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Database
|
||||||
|
*
|
||||||
|
* @see https://www.php.net/manual/en/book.pdo.php PDO
|
||||||
|
*
|
||||||
|
* @var pdo $database Database
|
||||||
|
*/
|
||||||
|
protected static pdo $database;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Initializing the database connetion
|
||||||
|
self::$database = new pdo(DATABASE['type'] . ':dbname=' . DATABASE['name'] . ';host=' . DATABASE['host'], DATABASE['login'], DATABASE['password']);
|
||||||
|
}
|
||||||
|
}
|
0
mirzaev/surikovlib/system/public/css/auth.css → kodorvan/surikov/system/public/css/auth.css
Normal file → Executable file
0
mirzaev/surikovlib/system/public/css/books.css → kodorvan/surikov/system/public/css/books.css
Normal file → Executable file
0
mirzaev/surikovlib/system/public/css/main.css → kodorvan/surikov/system/public/css/main.css
Normal file → Executable file
0
mirzaev/surikovlib/system/public/css/pages.css → kodorvan/surikov/system/public/css/pages.css
Normal file → Executable file
0
mirzaev/surikovlib/system/public/css/upload.css → kodorvan/surikov/system/public/css/upload.css
Normal file → Executable file
0
mirzaev/surikovlib/system/public/img/background_1.png → kodorvan/surikov/system/public/img/background_1.png
Normal file → Executable file
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 172 KiB |
0
mirzaev/surikovlib/system/public/img/background_1.svg → kodorvan/surikov/system/public/img/background_1.svg
Normal file → Executable file
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
0
mirzaev/surikovlib/system/public/img/background_2.png → kodorvan/surikov/system/public/img/background_2.png
Normal file → Executable file
Before Width: | Height: | Size: 853 KiB After Width: | Height: | Size: 853 KiB |
0
mirzaev/surikovlib/system/public/img/surikovlib_logo_1.svg → kodorvan/surikov/system/public/img/surikovlib_logo_1.svg
Normal file → Executable file
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
0
mirzaev/surikovlib/system/public/img/ФЖ-28.png → kodorvan/surikov/system/public/img/ФЖ-28.png
Normal file → Executable file
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
0
mirzaev/surikovlib/system/public/img/школьникам.png → kodorvan/surikov/system/public/img/школьникам.png
Normal file → Executable file
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
58
kodorvan/surikov/system/public/index.php
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\core,
|
||||||
|
mirzaev\minimal\route;
|
||||||
|
|
||||||
|
// Initializing path to the public directory
|
||||||
|
define('INDEX', __DIR__);
|
||||||
|
|
||||||
|
// Initializing path to the project root directory
|
||||||
|
define('ROOT', INDEX . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
|
// Initializing path to the directory of views
|
||||||
|
define('VIEWS', INDEX . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'views');
|
||||||
|
|
||||||
|
// Initializing path to the directory of the storage
|
||||||
|
define('STORAGE', INDEX . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'storage');
|
||||||
|
|
||||||
|
// Initializing path to the directory of settings
|
||||||
|
define('SETTINGS', INDEX . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'settings');
|
||||||
|
|
||||||
|
// Initializing the database connection parameters
|
||||||
|
define('DATABASE', require(SETTINGS . DIRECTORY_SEPARATOR . 'database.php'));
|
||||||
|
|
||||||
|
ini_set('error_reporting', E_ALL);
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
|
||||||
|
// Initializing dependencies
|
||||||
|
require ROOT . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||||
|
|
||||||
|
// Initializing the core
|
||||||
|
$core = new core(namespace: __NAMESPACE__);
|
||||||
|
|
||||||
|
// Initializing routes
|
||||||
|
$core->router
|
||||||
|
->write('/', new route('index', 'index'), 'GET')
|
||||||
|
->write('/account/registration', new route('accounts', 'registration'), 'POST')
|
||||||
|
->write('/account/authentication', new route('accounts', 'authentication'), 'POST')
|
||||||
|
->write('/account/deauthentication', new route('accounts', 'deauthentication'), 'POST')
|
||||||
|
->write('/account/deauthentication', new route('accounts', 'deauthentication'), 'GET')
|
||||||
|
->write('/books', new route('books', 'index'), 'GET')
|
||||||
|
->write('/books/$id', new route('books', 'index'), 'GET')
|
||||||
|
->write('/books/$id/$page', new route('books', 'index'), 'GET')
|
||||||
|
->write('/books/$id/$page/rotate', new route('books', 'rotate'), 'POST')
|
||||||
|
->write('/books/$id/delete', new route('books', 'delete'), 'POST')
|
||||||
|
->write('/storage/books/$id/$file', new route('books', 'read'), 'GET')
|
||||||
|
->write('/storage/books/write', new route('books', 'write'), 'POST')
|
||||||
|
->write('/kemenov', new route('kemenov', 'index'), 'GET')
|
||||||
|
->write('/surikov', new route('surikov', 'index'), 'GET')
|
||||||
|
->write('/contacts', new route('contacts', 'index'), 'GET');
|
||||||
|
|
||||||
|
// Handling the request
|
||||||
|
$core->start();
|
0
mirzaev/surikovlib/system/public/js/auth.js → kodorvan/surikov/system/public/js/auth.js
Normal file → Executable file
0
mirzaev/surikovlib/system/public/js/delete.js → kodorvan/surikov/system/public/js/delete.js
Normal file → Executable file
0
mirzaev/surikovlib/system/public/js/rotate.js → kodorvan/surikov/system/public/js/rotate.js
Normal file → Executable file
1
kodorvan/surikov/system/settings/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.sample.php
|
10
kodorvan/surikov/system/settings/database.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return [
|
||||||
|
'type' => 'mysql',
|
||||||
|
'host' => '127.0.0.1',
|
||||||
|
'name' => 'casino_2',
|
||||||
|
'login' => 'brawl_stars',
|
||||||
|
'password' => 'knopka_bablo_228'
|
||||||
|
];
|
0
mirzaev/surikovlib/system/storage/.gitignore → kodorvan/surikov/system/storage/.gitignore
vendored
Normal file → Executable file
0
mirzaev/surikovlib/system/storage/books/.gitkeep → kodorvan/surikov/system/storage/books/.gitkeep
Normal file → Executable file
0
mirzaev/surikovlib/system/storage/temp/.gitkeep → kodorvan/surikov/system/storage/temp/.gitkeep
Normal file → Executable file
213
kodorvan/surikov/system/views/templater.php
Executable file
@@ -0,0 +1,213 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace kodorvan\surikov\views;
|
||||||
|
|
||||||
|
// Files of the project
|
||||||
|
use kodorvan\surikov\models\account;
|
||||||
|
|
||||||
|
// Framework for PHP
|
||||||
|
use mirzaev\minimal\controller;
|
||||||
|
|
||||||
|
// Library for languages support
|
||||||
|
use mirzaev\languages\language;
|
||||||
|
|
||||||
|
// Templater of views
|
||||||
|
use Twig\Loader\FilesystemLoader,
|
||||||
|
Twig\Environment as twig,
|
||||||
|
Twig\Extra\Intl\IntlExtension as intl,
|
||||||
|
Twig\TwigFilter,
|
||||||
|
Twig\TwigFunction;
|
||||||
|
|
||||||
|
// Built-in libraries
|
||||||
|
use ArrayAccess as array_access,
|
||||||
|
Error as error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Templater
|
||||||
|
*
|
||||||
|
* @package kodorvan\surikov\views
|
||||||
|
*
|
||||||
|
* @param twig $twig Instance of the twig templater
|
||||||
|
* @param array $variables Registry of view global variables
|
||||||
|
*
|
||||||
|
* @method void __construct() Constructor
|
||||||
|
* @method string|null render(string $file, ?array $variables) Render the HTML-document
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
final class templater extends controller implements array_access
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Twig
|
||||||
|
*
|
||||||
|
* @var twig $twig Instance of the twig templater
|
||||||
|
*/
|
||||||
|
readonly public twig $twig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variables
|
||||||
|
*
|
||||||
|
* @var array $variables Registry of view global variables
|
||||||
|
*/
|
||||||
|
public array $variables = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of an instance
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(?account $account = null)
|
||||||
|
{
|
||||||
|
// Initializing the Twig instance
|
||||||
|
$this->twig = new twig(new FilesystemLoader(VIEWS));
|
||||||
|
|
||||||
|
// Initializing global variables
|
||||||
|
$this->twig->addGlobal('theme', 'default');
|
||||||
|
$this->twig->addGlobal('server', $_SERVER);
|
||||||
|
$this->twig->addGlobal('cookies', $_COOKIE);
|
||||||
|
if ($account instanceof account) $this->twig->addGlobal('account', $account);
|
||||||
|
$this->twig->addGlobal('language', $language = $session?->buffer['language'] ?? language::en);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render
|
||||||
|
*
|
||||||
|
* Render the HTML-document
|
||||||
|
*
|
||||||
|
* @param string $file Related path to a HTML-document
|
||||||
|
* @param array $variables Registry of variables to push into registry of global variables
|
||||||
|
*
|
||||||
|
* @return ?string HTML-document
|
||||||
|
*/
|
||||||
|
public function render(string $file, array $variables = []): ?string
|
||||||
|
{
|
||||||
|
// Generation and exit (success)
|
||||||
|
return $this->twig->render('themes' . DIRECTORY_SEPARATOR . $this->twig->getGlobals()['theme'] . DIRECTORY_SEPARATOR . $file, $variables + $this->variables);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write
|
||||||
|
*
|
||||||
|
* Write the variable into the registry of the view global variables
|
||||||
|
*
|
||||||
|
* @param string $name Name of the variable
|
||||||
|
* @param mixed $value Value of the variable
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __set(string $name, mixed $value = null): void
|
||||||
|
{
|
||||||
|
// Write the variable and exit (success)
|
||||||
|
$this->variables[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read
|
||||||
|
*
|
||||||
|
* Read the variable from the registry of the view global variables
|
||||||
|
*
|
||||||
|
* @param string $name Name of the variable
|
||||||
|
*
|
||||||
|
* @return mixed Content of the variable, if they are found
|
||||||
|
*/
|
||||||
|
public function __get(string $name): mixed
|
||||||
|
{
|
||||||
|
// Read the variable and exit (success)
|
||||||
|
return $this->variables[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete
|
||||||
|
*
|
||||||
|
* Delete the variable from the registry of the view global variables
|
||||||
|
*
|
||||||
|
* @param string $name Name of the variable
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __unset(string $name): void
|
||||||
|
{
|
||||||
|
// Delete the variable and exit (success)
|
||||||
|
unset($this->variables[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check of initialization
|
||||||
|
*
|
||||||
|
* Check of initialization in the registry of the view global variables
|
||||||
|
*
|
||||||
|
* @param string $name Name of the variable
|
||||||
|
*
|
||||||
|
* @return bool The variable is initialized?
|
||||||
|
*/
|
||||||
|
public function __isset(string $name): bool
|
||||||
|
{
|
||||||
|
// Check of initialization of the variable and exit (success)
|
||||||
|
return isset($this->variables[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write
|
||||||
|
*
|
||||||
|
* Write the variable into the registry of the view global variables
|
||||||
|
*
|
||||||
|
* @param mixed $name Name of an offset of the variable
|
||||||
|
* @param mixed $value Value of the variable
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function offsetSet(mixed $name, mixed $value): void
|
||||||
|
{
|
||||||
|
// Write the variable and exit (success)
|
||||||
|
$this->variables[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read
|
||||||
|
*
|
||||||
|
* Read the variable from the registry of the view global variables
|
||||||
|
*
|
||||||
|
* @param mixed $name Name of the variable
|
||||||
|
*
|
||||||
|
* @return mixed Content of the variable, if they are found
|
||||||
|
*/
|
||||||
|
public function offsetGet(mixed $name): mixed
|
||||||
|
{
|
||||||
|
// Read the variable and exit (success)
|
||||||
|
return $this->variables[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete
|
||||||
|
*
|
||||||
|
* Delete the variable from the registry of the view global variables
|
||||||
|
*
|
||||||
|
* @param mixed $name Name of the variable
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function offsetUnset(mixed $name): void
|
||||||
|
{
|
||||||
|
// Delete the variable and exit (success)
|
||||||
|
unset($this->variables[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check of initialization
|
||||||
|
*
|
||||||
|
* Check of initialization in the registry of the view global variables
|
||||||
|
*
|
||||||
|
* @param mixed $name Name of the variable
|
||||||
|
*
|
||||||
|
* @return bool The variable is initialized?
|
||||||
|
*/
|
||||||
|
public function offsetExists(mixed $name): bool
|
||||||
|
{
|
||||||
|
// Check of initialization of the variable and exit (success)
|
||||||
|
return isset($this->variables[$name]);
|
||||||
|
}
|
||||||
|
}
|
0
mirzaev/surikovlib/system/views/auth.html → kodorvan/surikov/system/views/themes/default/authentication.html
Normal file → Executable file
2
mirzaev/surikovlib/system/views/books/book.html → kodorvan/surikov/system/views/themes/default/books/book.html
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
{% extends "core.html" %}
|
{% extends "/themes/default/core.html" %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="/css/books.css" rel="stylesheet">
|
<link href="/css/books.css" rel="stylesheet">
|
2
mirzaev/surikovlib/system/views/books/index.html → kodorvan/surikov/system/views/themes/default/books/index.html
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
{% extends "core.html" %}
|
{% extends "/themes/default/core.html" %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="/css/books.css" rel="stylesheet">
|
<link href="/css/books.css" rel="stylesheet">
|
12
mirzaev/surikovlib/system/views/core.html → kodorvan/surikov/system/views/themes/default/core.html
Normal file → Executable file
@@ -3,7 +3,7 @@
|
|||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
{% include 'head.html' %}
|
{% include '/themes/default/head.html' %}
|
||||||
|
|
||||||
<link href="/css/main.css" rel="stylesheet">
|
<link href="/css/main.css" rel="stylesheet">
|
||||||
|
|
||||||
@@ -15,20 +15,20 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{% include 'header.html' %}
|
{% include '/themes/default/header.html' %}
|
||||||
|
|
||||||
<aside>
|
<aside>
|
||||||
{% include 'sidebar.html' %}
|
{% include '/themes/default/sidebar.html' %}
|
||||||
</aside><!----><main>
|
</aside><!----><main>
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% include 'calculators/index.html' %}
|
{% include '/themes/default/calculators/index.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
{% include 'footer.html' %}
|
{% include '/themes/default/footer.html' %}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
{% include 'js.html' %}
|
{% include '/themes/default/js.html' %}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
0
mirzaev/surikovlib/system/views/footer.html → kodorvan/surikov/system/views/themes/default/footer.html
Normal file → Executable file
0
mirzaev/surikovlib/system/views/head.html → kodorvan/surikov/system/views/themes/default/head.html
Normal file → Executable file
0
mirzaev/surikovlib/system/views/header.html → kodorvan/surikov/system/views/themes/default/header.html
Normal file → Executable file
0
mirzaev/surikovlib/system/views/js.html → kodorvan/surikov/system/views/themes/default/js.html
Normal file → Executable file
2
mirzaev/surikovlib/system/views/main/index.html → kodorvan/surikov/system/views/themes/default/main/index.html
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
{% extends "core.html" %}
|
{% extends "/themes/default/core.html" %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<img class="banner unselectable" src="/img/школьникам.png" alt="Предложение для школьников">
|
<img class="banner unselectable" src="/img/школьникам.png" alt="Предложение для школьников">
|
@@ -1,4 +1,4 @@
|
|||||||
{% extends "core.html" %}
|
{% extends "/themes/default/core.html" %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="/css/pages.css" rel="stylesheet">
|
<link href="/css/pages.css" rel="stylesheet">
|
2
mirzaev/surikovlib/system/views/pages/kemenov/index.html → kodorvan/surikov/system/views/themes/default/pages/kemenov/index.html
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
{% extends "core.html" %}
|
{% extends "/themes/default/core.html" %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="/css/pages.css" rel="stylesheet">
|
<link href="/css/pages.css" rel="stylesheet">
|
2
mirzaev/surikovlib/system/views/pages/surikov/index.html → kodorvan/surikov/system/views/themes/default/pages/surikov/index.html
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
{% extends "core.html" %}
|
{% extends "/themes/default/core.html" %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<link href="/css/pages.css" rel="stylesheet">
|
<link href="/css/pages.css" rel="stylesheet">
|
4
mirzaev/surikovlib/system/views/sidebar.html → kodorvan/surikov/system/views/themes/default/sidebar.html
Normal file → Executable file
@@ -1,6 +1,6 @@
|
|||||||
<link href="/css/banners.css" rel="stylesheet">
|
<link href="/css/banners.css" rel="stylesheet">
|
||||||
|
|
||||||
{% include 'auth.html' %}
|
{% include '/themes/default/authentication.html' %}
|
||||||
{% include 'vk.html' %}
|
{% include '/themes/default/vk.html' %}
|
||||||
<!-- <section class="banners">
|
<!-- <section class="banners">
|
||||||
</section> -->
|
</section> -->
|
0
mirzaev/surikovlib/system/views/vk.html → kodorvan/surikov/system/views/themes/default/vk.html
Normal file → Executable file
@@ -1,168 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\controllers;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\controllers\core;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\models\accounts_model as accounts;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контроллер пользователей
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class accounts_controller extends core
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Страница профиля
|
|
||||||
*
|
|
||||||
* @param array $vars
|
|
||||||
*/
|
|
||||||
public function index(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Регистрация
|
|
||||||
*
|
|
||||||
* @param array $vars Параметры запроса
|
|
||||||
*
|
|
||||||
* @return string|null HTML-документ
|
|
||||||
*/
|
|
||||||
public function registration(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
if ($vars['account'] = accounts::registration(mail: $vars['mail'] ?? null, password: $vars['password'] ?? null, errors: $vars['errors'])) {
|
|
||||||
// Удалось зарегистрироваться
|
|
||||||
|
|
||||||
if ($vars['account'] = accounts::authentication($vars['mail'] ?? null, $vars['password'] ?? null, (bool) ($vars['remember'] ?? false), $vars)) {
|
|
||||||
// Удалось аутентифицироваться
|
|
||||||
} else {
|
|
||||||
// Не удалось аутентифицироваться
|
|
||||||
|
|
||||||
// Запись кода ответа
|
|
||||||
http_response_code(401);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Не удалось зарегистрироваться
|
|
||||||
|
|
||||||
// Запись кода ответа
|
|
||||||
http_response_code(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Инициализаци пути для перенаправления
|
|
||||||
$redirect = isset($vars['redirect']) ? $vars['redirect'] : $_SERVER['HTTP_REFERER'] ?? '/';
|
|
||||||
|
|
||||||
// Перенаправление
|
|
||||||
header("Location: $redirect", response_code: 303);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Аутентификация
|
|
||||||
*
|
|
||||||
* @param array $vars Параметры запроса
|
|
||||||
*
|
|
||||||
* @return string|null HTML-документ
|
|
||||||
*/
|
|
||||||
public function authentication(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
if ($vars['account'] = accounts::authentication($vars['mail'] ?? null, $vars['password'] ?? null, (bool) ($vars['remember'] ?? false), errors: $vars['errors'])) {
|
|
||||||
// Удалось аутентифицироваться
|
|
||||||
} else {
|
|
||||||
// Не удалось аутентифицироваться
|
|
||||||
|
|
||||||
// Запись кода ответа
|
|
||||||
http_response_code(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Инициализаци пути для перенаправления
|
|
||||||
$redirect = isset($vars['redirect']) ? $vars['redirect'] : $_SERVER['HTTP_REFERER'] ?? '/';
|
|
||||||
|
|
||||||
// Перенаправление
|
|
||||||
header("Location: $redirect", response_code: 303);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Деаутентификация
|
|
||||||
*
|
|
||||||
* @param array $vars Параметры запроса
|
|
||||||
*
|
|
||||||
* @return string|null HTML-документ
|
|
||||||
*/
|
|
||||||
public function deauthentication(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
if (accounts::deauthentication(errors: $vars['errors'])) {
|
|
||||||
// Удалось деаутентифицироваться
|
|
||||||
|
|
||||||
// Деинициализация аккаунта
|
|
||||||
$vars['account'] = null;
|
|
||||||
} else {
|
|
||||||
// Не удалось деаутентифицироваться
|
|
||||||
|
|
||||||
// Запись кода ответа
|
|
||||||
http_response_code(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Перенаправление
|
|
||||||
header('Location: /', response_code: 303);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Данные аккаунта
|
|
||||||
*
|
|
||||||
* Если информацию запрашивает администратор, то вернётся вся, иначе только разрешённая публично
|
|
||||||
*
|
|
||||||
* @param array $vars Параметры запроса
|
|
||||||
*
|
|
||||||
* @return string JSON-документ
|
|
||||||
*/
|
|
||||||
public function data(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
if ($account = accounts::read(['id' => $vars['id']], $vars['errors'])) {
|
|
||||||
// Найдены данные запрашиваемого аккаунта
|
|
||||||
|
|
||||||
// Инициализация аккаунта
|
|
||||||
$vars['account'] = accounts::init(errors: $vars['errors']);
|
|
||||||
|
|
||||||
if ($vars['account'] && $vars['account']->permissions['accounts'] ?? 0 === 1) {
|
|
||||||
// Удалось аутентифицироваться и пройдена проверка авторизации
|
|
||||||
} else {
|
|
||||||
// Не удалось аутентифицироваться
|
|
||||||
|
|
||||||
// Удаление запрещённых к публикации полей
|
|
||||||
$account->password = $account->hash = $account->time = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
return json_encode($account ?? '');
|
|
||||||
} else {
|
|
||||||
// Не найдены данные запрашиваемого аккаунта
|
|
||||||
|
|
||||||
// Запись кода ответа
|
|
||||||
http_response_code(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,191 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\controllers;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\controllers\core;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\models\accounts_model as accounts;
|
|
||||||
use mirzaev\surikovlib\models\books_model as books;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контроллер пользователей
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class books_controller extends core
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Страница с книгами (или книгой)
|
|
||||||
*
|
|
||||||
* @param array $vars
|
|
||||||
*/
|
|
||||||
public function index(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
// Проверка аутентифицированности
|
|
||||||
$vars['account'] = accounts::init(errors: $vars['errors']);
|
|
||||||
|
|
||||||
if (isset($vars['id'])) {
|
|
||||||
// Определённая книга
|
|
||||||
|
|
||||||
// Чтение метаданных книги
|
|
||||||
$vars['book'] = books::read(['id' => $vars['id']])[0] ?? null;
|
|
||||||
|
|
||||||
// Инициализация страницы
|
|
||||||
if (empty($vars['page']) || $vars['page'] < 0) $vars['page'] = 0;
|
|
||||||
|
|
||||||
// Генерация представления
|
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . 'book.html', $vars);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Все книги
|
|
||||||
|
|
||||||
// Чтение книг
|
|
||||||
$vars['books'] = books::read(limit: 30, page: isset($vars['page']) && $vars['page'] > 0 ? $vars['page'] : 1);
|
|
||||||
|
|
||||||
// Генерация представления
|
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Запись
|
|
||||||
*
|
|
||||||
* @param array $vars Параметры
|
|
||||||
* @param array $files Файлы
|
|
||||||
*
|
|
||||||
* @return string|null HTML-документ
|
|
||||||
*/
|
|
||||||
public function write(array $vars = [], array $files = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
if (accounts::init(errors: $vars['errors'])->access('books')) {
|
|
||||||
// Найден и авторизован аккаунт
|
|
||||||
|
|
||||||
if (count($books = books::import($files['books'] ?? [], errors: $vars['errors'])) > 0) {
|
|
||||||
// Загружены книги
|
|
||||||
} else {
|
|
||||||
// Не загружены книги
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Перенаправление
|
|
||||||
header('Location: /books', response_code: 303);
|
|
||||||
|
|
||||||
return 'wtf';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Чтение
|
|
||||||
*
|
|
||||||
* @param array $vars
|
|
||||||
*
|
|
||||||
* @return string|null Файл, если найден
|
|
||||||
*/
|
|
||||||
public function read(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
if (isset($vars['id'], $vars['file'])) {
|
|
||||||
// Найдены обязательные входные параметры
|
|
||||||
|
|
||||||
// Инициализация пути до файла
|
|
||||||
$file = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $vars['id'] . DIRECTORY_SEPARATOR . $vars['file'] . '.jpg';
|
|
||||||
|
|
||||||
if (file_exists($file)) {
|
|
||||||
// Найден файл
|
|
||||||
|
|
||||||
// Настройка заголовков
|
|
||||||
header('Content-Description: File Transfer');
|
|
||||||
header('Content-Type: image/jpeg');
|
|
||||||
header('Content-Disposition: attachment; filename=' . basename($file));
|
|
||||||
header('Content-Transfer-Encoding: binary');
|
|
||||||
header('Content-Length: ' . filesize($file));
|
|
||||||
|
|
||||||
// Очистить буфер вывода
|
|
||||||
ob_end_clean();
|
|
||||||
|
|
||||||
return file_get_contents($file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Удаление
|
|
||||||
*
|
|
||||||
* @param array $vars Параметры запроса
|
|
||||||
*
|
|
||||||
* @return string|null HTML-документ
|
|
||||||
*/
|
|
||||||
public function delete(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
if (accounts::init(errors: $vars['errors'])->access('books')) {
|
|
||||||
// Найден и авторизован аккаунт
|
|
||||||
|
|
||||||
if (isset($vars['id'])) {
|
|
||||||
// Найдены обязательные входные параметры
|
|
||||||
|
|
||||||
if (books::delete((int) $vars['id'], $vars['errors'])) {
|
|
||||||
// Удалена книга из базы данных
|
|
||||||
|
|
||||||
// Инициализация пути до книги
|
|
||||||
$book = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $vars['id'];
|
|
||||||
|
|
||||||
if (file_exists($book)) {
|
|
||||||
// Найдена книга
|
|
||||||
|
|
||||||
// Удаление книги
|
|
||||||
exec('rm -rf ' . escapeshellarg($book));
|
|
||||||
|
|
||||||
// Запись статуса выполнения в буфер вывода
|
|
||||||
$status = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return json_encode([
|
|
||||||
'status' => $status ?? false,
|
|
||||||
'errors' => $vars['errors']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поворот
|
|
||||||
*
|
|
||||||
* @param array $vars
|
|
||||||
*
|
|
||||||
* @return string|null JSON
|
|
||||||
*/
|
|
||||||
public function rotate(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
if (accounts::init(errors: $vars['errors'])->access('books')) {
|
|
||||||
// Найден и авторизован аккаунт
|
|
||||||
|
|
||||||
if (isset($vars['id'], $vars['page'])) {
|
|
||||||
// Найдены обязательные входные параметры
|
|
||||||
|
|
||||||
// Поворот страницы
|
|
||||||
$status = books::rotate((int) $vars['id'], (int) $vars['page'], $vars['errors']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return json_encode([
|
|
||||||
'status' => $status ?? false,
|
|
||||||
'errors' => $vars['errors']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\controllers;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\controllers\core;
|
|
||||||
use mirzaev\surikovlib\models\accounts_model as accounts;
|
|
||||||
|
|
||||||
use Twig\Environment as view;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контроллер страницы "контакты"
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class contacts_controller extends core
|
|
||||||
{
|
|
||||||
public function index(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
// Генерация представления
|
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . 'contacts' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\controllers;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\views\manager;
|
|
||||||
use mirzaev\surikovlib\models\core as models;
|
|
||||||
|
|
||||||
use mirzaev\minimal\controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ядро контроллеров
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
class core extends controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Конструктор
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
|
|
||||||
// Инициализация ядра моделей (соединение с базой данных...)
|
|
||||||
new models();
|
|
||||||
|
|
||||||
$this->view = new manager;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\controllers;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\controllers\core;
|
|
||||||
|
|
||||||
use Twig\Loader\FilesystemLoader;
|
|
||||||
use Twig\Environment as view;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контроллер основной страницы
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class errors_controller extends core
|
|
||||||
{
|
|
||||||
public function error404(): ?string
|
|
||||||
{
|
|
||||||
// Генерация представления
|
|
||||||
return 'Ошибка 404 (не найдено)';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function error500(): ?string
|
|
||||||
{
|
|
||||||
// Генерация представления
|
|
||||||
return 'Ошибка 500 (на стороне сервера)';
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\controllers;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\controllers\core;
|
|
||||||
use mirzaev\surikovlib\models\accounts_model as accounts;
|
|
||||||
|
|
||||||
use Twig\Environment as view;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контроллер страницы "кеменов"
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class kemenov_controller extends core
|
|
||||||
{
|
|
||||||
public function index(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
// Генерация представления
|
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . 'kemenov' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\controllers;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\controllers\core;
|
|
||||||
use mirzaev\surikovlib\models\accounts_model as accounts;
|
|
||||||
|
|
||||||
use Twig\Loader\FilesystemLoader;
|
|
||||||
use Twig\Environment as view;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контроллер основной страницы
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class main_controller extends core
|
|
||||||
{
|
|
||||||
public function index(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
// Проверка аутентифицированности
|
|
||||||
$vars['account'] = accounts::init(errors: $vars['errors']);
|
|
||||||
|
|
||||||
// Генерация представления
|
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'main' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\controllers;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\controllers\core;
|
|
||||||
use mirzaev\surikovlib\models\accounts_model as accounts;
|
|
||||||
|
|
||||||
use Twig\Environment as view;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контроллер страницы "суриков"
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class surikov_controller extends core
|
|
||||||
{
|
|
||||||
public function index(array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$vars['errors'] = [];
|
|
||||||
|
|
||||||
// Генерация представления
|
|
||||||
return $this->view->render(DIRECTORY_SEPARATOR . 'pages' . DIRECTORY_SEPARATOR . 'surikov' . DIRECTORY_SEPARATOR . 'index.html', $vars);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,638 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\models;
|
|
||||||
|
|
||||||
use pdo;
|
|
||||||
use exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Модель регистрации, аутентификации и авторизации
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\models
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class accounts_model extends core
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Идентификатор
|
|
||||||
*/
|
|
||||||
public int $id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Почта
|
|
||||||
*/
|
|
||||||
public string $mail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Пароль
|
|
||||||
*/
|
|
||||||
public string $password;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Хеш
|
|
||||||
*/
|
|
||||||
public ?string $hash;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Время активности хеша
|
|
||||||
*/
|
|
||||||
public int $time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Время активности хеша
|
|
||||||
*/
|
|
||||||
public array $permissions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Конструктор
|
|
||||||
*
|
|
||||||
* @param array $vars Параметры
|
|
||||||
*/
|
|
||||||
public function __construct(array $vars = []) {
|
|
||||||
foreach ($vars as $key => $value) {
|
|
||||||
// Перебор параметров
|
|
||||||
|
|
||||||
// Запись свойства
|
|
||||||
if (property_exists($this, $key)) $this->$key = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Регистрация
|
|
||||||
*
|
|
||||||
* @param string $mail Почта
|
|
||||||
* @param string $password Пароль
|
|
||||||
* @param bool $authenticate Автоматическая аутентификация в случае успешной регистрации
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return static|null Аккаунт
|
|
||||||
*/
|
|
||||||
public static function registration(string $mail, string $password, bool $authenticate = true, array &$errors = []): ?static
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (static::init(errors: $errors)) {
|
|
||||||
// Аутентифицирован пользователь
|
|
||||||
|
|
||||||
// Запись ошибки
|
|
||||||
throw new exception('Уже аутентифицирован');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($account = static::read(['mail' => $mail]))) {
|
|
||||||
// Не удалось найти аккаунт
|
|
||||||
|
|
||||||
if (static::write($mail, $password, $errors)) {
|
|
||||||
// Удалось зарегистрироваться
|
|
||||||
|
|
||||||
if ($authenticate) {
|
|
||||||
// Запрошена аутентификация
|
|
||||||
|
|
||||||
// Аутентификация
|
|
||||||
$account = static::authentication($mail, $password, true, $errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $account;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Удалось найти аккаунт
|
|
||||||
|
|
||||||
return $account;
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Аутентификация
|
|
||||||
*
|
|
||||||
* @param string $mail Почта
|
|
||||||
* @param string $password Пароль
|
|
||||||
* @param bool $remember Функция "Запомнить меня" - увеличенное время хранения cookies
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return static|null Аккаунт
|
|
||||||
*/
|
|
||||||
public static function authentication(string $mail, string $password, bool $remember = false, array &$errors = []): ?static
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (static::init(errors: $errors)) {
|
|
||||||
// Аутентифицирован пользователь
|
|
||||||
|
|
||||||
// Запись ошибки
|
|
||||||
throw new exception('Уже аутентифицирован');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($account = static::read(['mail' => $mail]))) {
|
|
||||||
// Не удалось найти аккаунт
|
|
||||||
|
|
||||||
throw new exception('Не удалось найти аккаунт');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (password_verify($password, $account->password)) {
|
|
||||||
// Совпадают хеши паролей
|
|
||||||
|
|
||||||
// Инициализация идентификатора сессии
|
|
||||||
session_id((string) $account->id);
|
|
||||||
|
|
||||||
// Инициализация названия сессии
|
|
||||||
session_name('id');
|
|
||||||
|
|
||||||
// Инициализация сессии
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
// Инициализация времени хранения хеша
|
|
||||||
$time = time() + ($remember ? 604800 : 86400);
|
|
||||||
|
|
||||||
// Инициализация хеша
|
|
||||||
$hash = static::hash((int) $account->id, crypt($account->password, time() . $account->id), $time, $errors)['hash'];
|
|
||||||
|
|
||||||
// Инициализация cookies
|
|
||||||
setcookie('hash', $hash, $time, path: '/', secure: true);
|
|
||||||
|
|
||||||
return $account;
|
|
||||||
} else {
|
|
||||||
// Не совпадают хеши паролей
|
|
||||||
|
|
||||||
throw new exception('Неправильный пароль');
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Аутентификация
|
|
||||||
*
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return bool Удалось ли деаутентифицироваться
|
|
||||||
*/
|
|
||||||
public static function deauthentication(array &$errors = []): bool
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
if ($account = static::init(errors: $errors)) {
|
|
||||||
// Аутентифицирован пользователь
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("UPDATE `accounts` SET `hash` = null, `time` = 0 WHERE `id` = :id");
|
|
||||||
|
|
||||||
// Параметры запроса
|
|
||||||
$params = [
|
|
||||||
":id" => $account->id,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
$request->fetch(pdo::FETCH_ASSOC);
|
|
||||||
|
|
||||||
// Деинициализация cookies
|
|
||||||
setcookie('id', '', 0, path: '/', secure: true);
|
|
||||||
setcookie('hash', '', 0, path: '/', secure: true);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// Не аутентифицирован пользователь
|
|
||||||
|
|
||||||
// Запись ошибки
|
|
||||||
throw new exception('Не аутентифицирован');
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Инициализация
|
|
||||||
*
|
|
||||||
* @param int|null $account Аккаунт (идентификатор)
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return static|null Аккаунт
|
|
||||||
*/
|
|
||||||
public static function init(?int $account = null, array &$errors = []): ?static
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (isset($account)) {
|
|
||||||
// Получен идентификатор аккаунта
|
|
||||||
|
|
||||||
if (empty($account = static::read(['id' => $account]))) {
|
|
||||||
// Не найден аккаунт
|
|
||||||
|
|
||||||
// Генерация ошибки
|
|
||||||
throw new exception('Не найден пользователь');
|
|
||||||
}
|
|
||||||
} else if (!empty($_COOKIE['id']) && !empty($_COOKIE['hash'])) {
|
|
||||||
// Найдены cookie с данными аккаунта (подразумевается, что он аутентифицирован)
|
|
||||||
|
|
||||||
if ($_COOKIE['hash'] === static::hash((int) $_COOKIE['id'], errors: $errors)['hash']) {
|
|
||||||
// Совпадает переданный хеш с тем, что хранится в базе данных
|
|
||||||
} else {
|
|
||||||
// Не совпадает переданный хеш с тем, что хранится в базе данных
|
|
||||||
|
|
||||||
// Генерация ошибки
|
|
||||||
throw new exception('Вы аутентифицированы с другого устройства (не совпадают хеши аутентификации)');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($account = static::read([
|
|
||||||
'id' => $_COOKIE['id'],
|
|
||||||
'hash' => $_COOKIE['hash']
|
|
||||||
]))) {
|
|
||||||
// Не найден аккаунт или связка аккаунта с хешем
|
|
||||||
|
|
||||||
// Генерация ошибки
|
|
||||||
throw new exception('Не найден пользователь или время аутентификации истекло');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Не найдены параметры для поиска аккаунта
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Чтение разрешений
|
|
||||||
$account->permissions = static::permissions((int) $account->id, $errors);
|
|
||||||
|
|
||||||
return $account;
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][]= [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Прочитать разрешения из базы данных
|
|
||||||
*
|
|
||||||
* @param int $id Идентификатор аккаунта
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return array Разрешения аккаунта, если найдены
|
|
||||||
*/
|
|
||||||
public static function permissions(int $id, array &$errors = []): array
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("SELECT * FROM `permissions` WHERE `id` = :id");
|
|
||||||
|
|
||||||
// Параметры запроса
|
|
||||||
$params = [
|
|
||||||
":id" => $id
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
if (empty($response = $request->fetch(pdo::FETCH_ASSOC))) {
|
|
||||||
// Не найдены разрешения
|
|
||||||
|
|
||||||
// Генерация ошибки
|
|
||||||
throw new exception('Не найдены разрешения');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Удаление ненужных данных
|
|
||||||
unset($response['id']);
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверить разрешение
|
|
||||||
*
|
|
||||||
* @param string $permission Разрешение
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return bool|null Статус разрешения, если оно записано
|
|
||||||
*/
|
|
||||||
public function access(string $permission, array &$errors = []): ?bool
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
return isset($this->permissions[$permission]) ? (bool) $this->permissions[$permission] : null;
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][]= [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Запись в базу данных
|
|
||||||
*
|
|
||||||
* @param string $mail Почта
|
|
||||||
* @param string $password Пароль
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return static|null Аккаунт
|
|
||||||
*/
|
|
||||||
public static function write(string $mail, string $password, array &$errors = []): ?static
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Инициализация параметров запроса
|
|
||||||
$params = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Проверка параметра
|
|
||||||
if (filter_var($mail, FILTER_VALIDATE_mail) === false) throw new exception('Не удалось распознать почту');
|
|
||||||
if (iconv_strlen($mail) < 3) throw new exception('Длина почты должна быть не менее 3 символов');
|
|
||||||
if (iconv_strlen($mail) > 60) throw new exception('Длина почты должна быть не более 80 символов');
|
|
||||||
|
|
||||||
// Запись в буфер параметров запроса
|
|
||||||
$params[':mail'] = $mail;
|
|
||||||
|
|
||||||
// Проверка параметра
|
|
||||||
if (iconv_strlen($password) < 3) throw new exception('Длина пароля должна быть не менее 3 символов');
|
|
||||||
if (iconv_strlen($password) > 60) throw new exception('Длина пароля должна быть не более 120 символов');
|
|
||||||
|
|
||||||
// Запись в буфер параметров запроса
|
|
||||||
$params[':password'] = password_hash($password, PASSWORD_BCRYPT);
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("INSERT INTO `accounts` (" . (isset($name) ? '`name`' : '') . (isset($name) && isset($mail) ? ', ' : '') . (isset($mail) ? '`mail`' : '') . ((isset($name) || isset($mail)) && isset($password) ? ', ' : '') . (isset($password) ? '`password`' : '') . ") VALUES (" . (isset($name) ? ':name' : '') . (isset($name) && isset($mail) ? ', ' : '') . (isset($mail) ? ':mail' : '') . ((isset($name) || isset($mail)) && isset($password) ? ', ' : '') . (isset($password) ? ':password' : '') . ")");
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
$request->fetch(pdo::FETCH_ASSOC);
|
|
||||||
|
|
||||||
// Чтение аккаунта
|
|
||||||
$account = static::read(['mail' => $mail]);
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("INSERT INTO `permissions` (`id`) VALUES (:id)");
|
|
||||||
|
|
||||||
// Инициализация параметров
|
|
||||||
$params = [
|
|
||||||
':id' => $account->id
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
$request->fetch(pdo::FETCH_ASSOC);
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Конец выполнения
|
|
||||||
end:
|
|
||||||
|
|
||||||
return $account ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Чтение из базы данных
|
|
||||||
*
|
|
||||||
* @param array $expression Выражение поиска ('поле' => 'значение')
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return static|null Аккаунт
|
|
||||||
*/
|
|
||||||
public static function read(array $expression, array &$errors = []): ?static
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Инициализация выражения поиска
|
|
||||||
$where = 'WHERE ';
|
|
||||||
|
|
||||||
// Инициализация параметров запроса
|
|
||||||
$params = [];
|
|
||||||
|
|
||||||
foreach ($expression as $parameter => $value) {
|
|
||||||
// Перебор выражения поиска
|
|
||||||
|
|
||||||
// Запись в строку запроса
|
|
||||||
$where .= "`$parameter` = :$parameter &&";
|
|
||||||
|
|
||||||
// Запись параметров запроса
|
|
||||||
$params[":$parameter"] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Очистка или реинициализация выражения поиска
|
|
||||||
$where = empty($expression) ? '' : trim(trim($where, '&&'));
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("SELECT * FROM `accounts` $where LIMIT 1");
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
if ($account = new static($request->fetch(pdo::FETCH_ASSOC))) {
|
|
||||||
// Найден аккаунт
|
|
||||||
|
|
||||||
try {
|
|
||||||
if ($permissions = static::permissions((int) $account->id, $errors)) {
|
|
||||||
// Найдены разрешения
|
|
||||||
|
|
||||||
// Запись в буфер данных аккаунта
|
|
||||||
$account->permissions = $permissions;
|
|
||||||
} else {
|
|
||||||
// Не найдены разрешения
|
|
||||||
|
|
||||||
throw new exception('Не удалось найти и прочитать разрешения');
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Не найден аккаунт
|
|
||||||
|
|
||||||
throw new exception('Не удалось найти аккаунт');
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][]= [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $account ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Запись или чтение хеша из базы данных
|
|
||||||
*
|
|
||||||
* @param int $id Идентификатор аккаунта
|
|
||||||
* @param int|null $hash Хеш аутентифиакции
|
|
||||||
* @param string|null $time Время хранения хеша
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return array ['hash' => $hash, 'time' => $time]
|
|
||||||
*/
|
|
||||||
public static function hash(int $id, string|null $hash = null, int|null $time = null, array &$errors = []): array
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['account'] ?? $errors['account'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (isset($hash, $time)) {
|
|
||||||
// Переданы хеш и его время хранения
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("UPDATE `accounts` SET `hash` = :hash, `time` = :time WHERE `id` = :id");
|
|
||||||
|
|
||||||
// Параметры запроса
|
|
||||||
$params = [
|
|
||||||
":id" => $id,
|
|
||||||
":hash" => $hash,
|
|
||||||
":time" => $time,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
$request->fetch(pdo::FETCH_ASSOC);
|
|
||||||
} else {
|
|
||||||
// Не переданы хеш и его время хранения
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("SELECT `hash`, `time` FROM `accounts` WHERE `id` = :id");
|
|
||||||
|
|
||||||
// Параметры запроса
|
|
||||||
$params = [
|
|
||||||
":id" => $id,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
extract((array) $request->fetch(pdo::FETCH_ASSOC));
|
|
||||||
|
|
||||||
if (!empty($response['time']) && $response['time'] <= time()) {
|
|
||||||
// Истекло время жизни хеша
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("UPDATE `accounts` SET `hash` = :hash, `time` = :time WHERE `id` = :id");
|
|
||||||
|
|
||||||
// Параметры запроса
|
|
||||||
$params = [
|
|
||||||
":id" => $id,
|
|
||||||
":hash" => null,
|
|
||||||
":time" => null,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
// Генерация ответа
|
|
||||||
$response = $request->fetch(pdo::FETCH_ASSOC);
|
|
||||||
|
|
||||||
// Генерация ошибки
|
|
||||||
throw new exception('Время аутентификации истекло');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['account'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['hash' => $hash, 'time' => $time];
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,358 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\models;
|
|
||||||
|
|
||||||
use mirzaev\surikovlib\models\accounts_model as accounts;
|
|
||||||
|
|
||||||
use pdo;
|
|
||||||
use exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Модель книг
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\models
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class books_model extends core
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Запись в базу данных
|
|
||||||
*
|
|
||||||
* @param string $title Название
|
|
||||||
* @param string|null $description Описание
|
|
||||||
* @param int|null $account Аккаунт (идентификатор)
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return int|null Идентификатор записанной книги
|
|
||||||
*/
|
|
||||||
public static function write(string $title, ?string $description = null, ?int $account = null, array &$errors = []): ?int
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['books'] ?? $errors['books'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Инициализация аккаунта
|
|
||||||
$account = accounts::init($account, $errors);
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("INSERT INTO `books` (`account`, `title`, `description`) VALUES (:account, :title, :description)");
|
|
||||||
|
|
||||||
// Инициализация параметров
|
|
||||||
$params = [
|
|
||||||
':account' => $account->id,
|
|
||||||
':title' => $title,
|
|
||||||
':description' => $description
|
|
||||||
];
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
if ($id = static::$db->lastInsertId()) {
|
|
||||||
// Получен идентификатор загруженной книги (подразумевается)
|
|
||||||
|
|
||||||
return (int) $id;
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['books'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Чтение
|
|
||||||
*
|
|
||||||
* @param array $expression Выражение поиска
|
|
||||||
* @param int $limit Ограничение по количеству
|
|
||||||
* @param int $page Страница (для списка книг)
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return array Книги
|
|
||||||
*/
|
|
||||||
public static function read(array $expression = [], int $limit = 1, int $page = 1, array &$errors = []): array
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['books'] ?? $errors['books'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Инициализация выражения поиска
|
|
||||||
$where = 'WHERE ';
|
|
||||||
|
|
||||||
// Инициализация параметров запроса
|
|
||||||
$params = [];
|
|
||||||
|
|
||||||
foreach ($expression as $parameter => $value) {
|
|
||||||
// Перебор выражения поиска
|
|
||||||
|
|
||||||
// Запись в строку запроса
|
|
||||||
$where .= "`$parameter` = :$parameter &&";
|
|
||||||
|
|
||||||
// Запись параметров запроса
|
|
||||||
$params[":$parameter"] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Очистка или реинициализация выражения поиска
|
|
||||||
$where = empty($expression) ? '' : trim(trim($where, '&&'));
|
|
||||||
|
|
||||||
// Инициализация страницы
|
|
||||||
$page = $limit * --$page;
|
|
||||||
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("SELECT * FROM `books` $where LIMIT $page, $limit");
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute($params);
|
|
||||||
|
|
||||||
return (array) $request->fetchAll(pdo::FETCH_ASSOC);
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['books'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Удаление из базы данных
|
|
||||||
*
|
|
||||||
* @param int $id Идентификатор
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return bool Статус выполнения
|
|
||||||
*/
|
|
||||||
public static function delete(int $id, array &$errors = []): bool
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['books'] ?? $errors['books'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("DELETE FROM `books` WHERE `id` = :id LIMIT 1");
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute([':id' => $id]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['books'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Импорт
|
|
||||||
*
|
|
||||||
* @param array $books Книги (файлы)
|
|
||||||
* @param int|null $account Аккаунт (идентификатор)
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return array Записанные книги
|
|
||||||
*/
|
|
||||||
public static function import(array $books, ?int $account = null, array &$errors = []): array
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['books'] ?? $errors['books'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (empty($books)) {
|
|
||||||
// Не найдены книги
|
|
||||||
|
|
||||||
throw new exception('Не найдены книги для записи');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Инициализация аккаунта
|
|
||||||
$account = accounts::init($account, $errors);
|
|
||||||
|
|
||||||
// Инициализация буфера инициализированных книг
|
|
||||||
$initialized = [];
|
|
||||||
|
|
||||||
for ($i = -1; count($books['name']) > ++$i;) {
|
|
||||||
// Перебор загруженных книг
|
|
||||||
|
|
||||||
// Генерация хеша файла
|
|
||||||
$hash = hash_file('md5', $books['tmp_name'][$i]) ?? 0;
|
|
||||||
|
|
||||||
if (move_uploaded_file($books['tmp_name'][$i], \STORAGE . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $hash . '_' . $books['name'][$i])) {
|
|
||||||
// Загружен и перемещён из временной папки файл с книгой
|
|
||||||
|
|
||||||
// Извлечение имени файла
|
|
||||||
|
|
||||||
// Запись в буфер инициализированных книг
|
|
||||||
$initialized[] = [
|
|
||||||
'name' => preg_replace('/\.pdf/', '', $books['name'])[0],
|
|
||||||
'file' => $hash . '_' . $books['name'][$i]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Инициализация буфера записанных книг
|
|
||||||
$writed = [];
|
|
||||||
|
|
||||||
foreach ($initialized as $book) {
|
|
||||||
// Перебор инициализированных книг
|
|
||||||
|
|
||||||
try {
|
|
||||||
if ($id = static::write($book['name'], 'Без описания', $account->id ?? null, $errors)) {
|
|
||||||
// Записана в базу данных книга
|
|
||||||
|
|
||||||
// Инициализация пути до хранилища
|
|
||||||
$directory = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $id . DIRECTORY_SEPARATOR;
|
|
||||||
|
|
||||||
// Инициализация директории
|
|
||||||
if (!file_exists($directory)) if (!mkdir($directory, 0755, true)) throw new exception('Не удалось записать директорию для книги');
|
|
||||||
|
|
||||||
// Инициализация пути до временного файла
|
|
||||||
$file = \STORAGE . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . $book['file'];
|
|
||||||
|
|
||||||
// Извлечение изображений из PDF-документа
|
|
||||||
exec("pdfimages -j '$file' '$directory'");
|
|
||||||
|
|
||||||
// Переименование файлов в необходимый формат
|
|
||||||
exec("echo 'export j=-1; for i in $directory*.jpg; do let j+=1; mv \$i $directory\$j.jpg; done' | bash");
|
|
||||||
|
|
||||||
// Запись в буфер записанных книг
|
|
||||||
$writed[] = $id;
|
|
||||||
} else {
|
|
||||||
// Не записана в базу данных книга
|
|
||||||
|
|
||||||
throw new exception('Не удалось записать книгу в базу данных', 500);
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['books'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['books'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $writed ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Чтение
|
|
||||||
*
|
|
||||||
* @param int $id Идентификатор
|
|
||||||
* @param int $page Страница (сдвиг)
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return bool Статус выполнения
|
|
||||||
*/
|
|
||||||
public static function rotate(int $id, int $page = 1, array &$errors = []): bool
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['books'] ?? $errors['books'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Инициализация запроса
|
|
||||||
$request = static::$db->prepare("SELECT EXISTS (SELECT * FROM `books` WHERE `id` = :id LIMIT 1)");
|
|
||||||
|
|
||||||
// Отправка запроса
|
|
||||||
$request->execute([':id' => $id]);
|
|
||||||
|
|
||||||
if ($request->fetch(pdo::FETCH_NUM)[0] === 1) {
|
|
||||||
// Найдена книга
|
|
||||||
|
|
||||||
// Инициализация пути книги
|
|
||||||
$book = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $id;
|
|
||||||
|
|
||||||
// Инициализация пути до файла
|
|
||||||
$file = $book . DIRECTORY_SEPARATOR . "$page.jpg";
|
|
||||||
|
|
||||||
// Инициализация пути до нового местоположения файла
|
|
||||||
$old = $book . DIRECTORY_SEPARATOR . 'old' . DIRECTORY_SEPARATOR . "$page.jpg";
|
|
||||||
|
|
||||||
// Инициализация директории
|
|
||||||
if (!file_exists($book)) throw new exception('Не удалось найти директорию книги');
|
|
||||||
|
|
||||||
// Инициализация директории оригинальных изображений
|
|
||||||
if (!file_exists($book . DIRECTORY_SEPARATOR . 'old')) if (!mkdir($book . DIRECTORY_SEPARATOR . 'old', 0755, true)) throw new exception('Не удалось записать директорию для оригинальных страниц книги');
|
|
||||||
|
|
||||||
// Перемещение страницы в директорию оригинальных страниц
|
|
||||||
exec("mv $file $old");
|
|
||||||
|
|
||||||
// Переворачивание файла и возвращение на нужное местоположение
|
|
||||||
exec("jpegtran -rotate 90 $old > $file");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['books'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Подсчёт количества страниц
|
|
||||||
*
|
|
||||||
* @param int $id Идентификатор
|
|
||||||
* @param array &$errors Журнал ошибок
|
|
||||||
*
|
|
||||||
* @return int|null Количество страниц
|
|
||||||
*/
|
|
||||||
public static function amount(int $id, array &$errors = []): ?int
|
|
||||||
{
|
|
||||||
// Инициализация журнала ошибок
|
|
||||||
$errors['books'] ?? $errors['books'] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Инициализация счётчика
|
|
||||||
$amount = -1;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Перебор директорий (!!! Рекурсия !!!)
|
|
||||||
|
|
||||||
// Перебор изображений по возрастанию (от 0.jpg до 999.jpg и т.д.)
|
|
||||||
if (!file_exists(\STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $id . DIRECTORY_SEPARATOR . ++$amount . '.jpg')) return $amount;
|
|
||||||
}
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Запись в журнал ошибок
|
|
||||||
$errors['books'][] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,139 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\models;
|
|
||||||
|
|
||||||
use mirzaev\minimal\model;
|
|
||||||
|
|
||||||
use pdo;
|
|
||||||
use pdoexception;
|
|
||||||
|
|
||||||
use exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ядро моделей
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\models
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
class core extends model
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Соединение с базой данных
|
|
||||||
*/
|
|
||||||
protected static PDO $db ;
|
|
||||||
|
|
||||||
public function __construct(pdo $db = null)
|
|
||||||
{
|
|
||||||
if (isset($db)) {
|
|
||||||
// Получена инстанция соединения с базой данных
|
|
||||||
|
|
||||||
// Запись и инициализация соединения с базой данных
|
|
||||||
$this->__set('db', $db);
|
|
||||||
} else {
|
|
||||||
// Не получена инстанция соединения с базой данных
|
|
||||||
|
|
||||||
// Инициализация соединения с базой данных по умолчанию
|
|
||||||
$this->__get('db');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Записать свойство
|
|
||||||
*
|
|
||||||
* @param string $name Название
|
|
||||||
* @param mixed $value Значение
|
|
||||||
*/
|
|
||||||
public function __set(string $name, mixed $value = null): void
|
|
||||||
{
|
|
||||||
match ($name) {
|
|
||||||
'db' => (function () use ($value) {
|
|
||||||
if ($this->__isset('db')) {
|
|
||||||
// Свойство уже было инициализировано
|
|
||||||
|
|
||||||
// Выброс исключения (неудача)
|
|
||||||
throw new exception('Запрещено реинициализировать соединение с базой данных ($this->db)', 500);
|
|
||||||
} else {
|
|
||||||
// Свойство ещё не было инициализировано
|
|
||||||
|
|
||||||
if ($value instanceof pdo) {
|
|
||||||
// Передано подходящее значение
|
|
||||||
|
|
||||||
// Запись свойства (успех)
|
|
||||||
self::$db = $value;
|
|
||||||
} else {
|
|
||||||
// Передано неподходящее значение
|
|
||||||
|
|
||||||
// Выброс исключения (неудача)
|
|
||||||
throw new exception('Соединение с базой данных ($this->db) должен быть инстанцией PDO', 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
default => parent::__set($name, $value)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Прочитать свойство
|
|
||||||
*
|
|
||||||
* @param string $name Название
|
|
||||||
*
|
|
||||||
* @return mixed Содержимое
|
|
||||||
*/
|
|
||||||
public function __get(string $name): mixed
|
|
||||||
{
|
|
||||||
return match ($name) {
|
|
||||||
'db' => (function () {
|
|
||||||
if (!$this->__isset('db')) {
|
|
||||||
// Свойство не инициализировано
|
|
||||||
|
|
||||||
// Инициализация значения по умолчанию исходя из настроек
|
|
||||||
$this->__set('db', new pdo(\TYPE . ':dbname=' . \BASE . ';host=' . \HOST, LOGIN, PASSWORD));
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$db;
|
|
||||||
})(),
|
|
||||||
default => parent::__get($name)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверить свойство на инициализированность
|
|
||||||
*
|
|
||||||
* @param string $name Название
|
|
||||||
*/
|
|
||||||
public function __isset(string $name): bool
|
|
||||||
{
|
|
||||||
return match ($name) {
|
|
||||||
default => parent::__isset($name)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Удалить свойство
|
|
||||||
*
|
|
||||||
* @param string $name Название
|
|
||||||
*/
|
|
||||||
public function __unset(string $name): void
|
|
||||||
{
|
|
||||||
match ($name) {
|
|
||||||
default => parent::__isset($name)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Статический вызов
|
|
||||||
*
|
|
||||||
* @param string $name Название
|
|
||||||
* @param array $arguments Параметры
|
|
||||||
*/
|
|
||||||
public static function __callStatic(string $name, array $arguments): mixed
|
|
||||||
{
|
|
||||||
match ($name) {
|
|
||||||
'db' => (new static)->__get('db'),
|
|
||||||
default => throw new exception("Не найдено свойство или функция: $name", 500)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,105 +0,0 @@
|
|||||||
# ----------------------------
|
|
||||||
# Host config
|
|
||||||
# ----------------------------
|
|
||||||
|
|
||||||
server {
|
|
||||||
|
|
||||||
listen %ip%:%httpport%;
|
|
||||||
listen %ip%:%httpsport% ssl http2;
|
|
||||||
|
|
||||||
server_name surikovlib.loc %aliases%;
|
|
||||||
root '%hostdir%';
|
|
||||||
limit_conn addr 64;
|
|
||||||
autoindex off;
|
|
||||||
index index.php index.html index.htm;
|
|
||||||
|
|
||||||
ssl_certificate '%sprogdir%/userdata/config/cert_files/server.crt';
|
|
||||||
ssl_certificate_key '%sprogdir%/userdata/config/cert_files/server.key';
|
|
||||||
# ssl_trusted_certificate '';
|
|
||||||
|
|
||||||
# Force HTTPS
|
|
||||||
# add_header Strict-Transport-Security 'max-age=2592000' always;
|
|
||||||
# if ($scheme ~* ^(?!https).*$) {
|
|
||||||
# return 301 https://$host$request_uri;
|
|
||||||
# }
|
|
||||||
|
|
||||||
# Force www.site.com => site.com
|
|
||||||
# if ($host ~* ^www\.(.+)$) {
|
|
||||||
# return 301 $scheme://$1$request_uri;
|
|
||||||
# }
|
|
||||||
# Disable access to backup/config/command/log files
|
|
||||||
# if ($uri ~* ^.+\.(?:bak|co?nf|in[ci]|log|orig|sh|sql|tar|sql|t?gz|cmd|bat)$) {
|
|
||||||
# return 404;
|
|
||||||
# }
|
|
||||||
# Disable access to hidden files/folders
|
|
||||||
if ($uri ~* /\.(?!well-known)) {
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Disable MIME sniffing
|
|
||||||
add_header X-Content-Type-Options 'nosniff' always;
|
|
||||||
|
|
||||||
location ~* ^.+\.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv|svgz?|ttf|ttc|otf|eot|woff2?)$ {
|
|
||||||
expires 1d;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
# Force index.php routing (if not found)
|
|
||||||
try_files $uri $uri/ /index.php$is_args$args;
|
|
||||||
|
|
||||||
# Force index.php routing (all requests)
|
|
||||||
# rewrite ^/(.*)$ /index.php?/$1 last;
|
|
||||||
|
|
||||||
location ~ \.php$ {
|
|
||||||
try_files $fastcgi_script_name =404;
|
|
||||||
|
|
||||||
# limit_conn addr 16;
|
|
||||||
# limit_req zone=flood burst=32 nodelay;
|
|
||||||
|
|
||||||
# add_header X-Frame-Options 'SAMEORIGIN' always;
|
|
||||||
# add_header Referrer-Policy 'no-referrer-when-downgrade' always;
|
|
||||||
# CSP syntax: <host-source> <scheme-source>(http: https: data: mediastream: blob: filesystem:) 'self' 'unsafe-inline' 'unsafe-eval' 'none'
|
|
||||||
# Content-Security-Policy-Report-Only (report-uri https://site.com/csp/)
|
|
||||||
# add_header Content-Security-Policy "default-src 'self'; connect-src 'self'; font-src 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; media-src 'self'; object-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'self'; frame-ancestors 'self'; upgrade-insecure-requests" always;
|
|
||||||
fastcgi_pass backend;
|
|
||||||
include '%sprogdir%/userdata/config/nginx_fastcgi_params.txt';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Service configuration (do not edit!)
|
|
||||||
# ----------------------------
|
|
||||||
location /openserver/ {
|
|
||||||
root '%sprogdir%/modules/system/html';
|
|
||||||
autoindex off;
|
|
||||||
index index.php index.html index.htm;
|
|
||||||
|
|
||||||
%allow%allow all;
|
|
||||||
allow 127.0.0.0/8;
|
|
||||||
allow ::1/128;
|
|
||||||
allow %ips%;
|
|
||||||
deny all;
|
|
||||||
|
|
||||||
location ~* ^/openserver/.+\.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv|svgz?|ttf|ttc|otf|eot|woff2?)$ {
|
|
||||||
expires 1d;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /openserver/server-status {
|
|
||||||
stub_status on;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ ^/openserver/.*\.php$ {
|
|
||||||
try_files $fastcgi_script_name =404;
|
|
||||||
fastcgi_index index.php;
|
|
||||||
fastcgi_pass backend;
|
|
||||||
include '%sprogdir%/userdata/config/nginx_fastcgi_params.txt';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# End service configuration
|
|
||||||
# ----------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
# ----------------------------
|
|
||||||
# End host config
|
|
||||||
# ----------------------------
|
|
@@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib;
|
|
||||||
|
|
||||||
use mirzaev\minimal\core;
|
|
||||||
use mirzaev\minimal\router;
|
|
||||||
|
|
||||||
define('VIEWS', realpath('..' . DIRECTORY_SEPARATOR . 'views'));
|
|
||||||
define('STORAGE', realpath('..' . DIRECTORY_SEPARATOR . 'storage'));
|
|
||||||
define('TYPE', 'mysql');
|
|
||||||
define('BASE', 'surikovlib');
|
|
||||||
define('HOST', '127.0.0.1');
|
|
||||||
define('LOGIN', 'root');
|
|
||||||
define('PASSWORD', 'sUrikov_topchik_228!');
|
|
||||||
|
|
||||||
ini_set('error_reporting', E_ALL);
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
ini_set('display_startup_errors', 1);
|
|
||||||
|
|
||||||
// Автозагрузка
|
|
||||||
require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
|
||||||
|
|
||||||
// Инициализация маршрутазитора
|
|
||||||
$router = new router;
|
|
||||||
|
|
||||||
// Запись маршрутов
|
|
||||||
$router->write('/', 'main', 'index');
|
|
||||||
$router->write('/account/registration', 'accounts', 'registration', 'POST');
|
|
||||||
$router->write('/account/authentication', 'accounts', 'authentication', 'POST');
|
|
||||||
$router->write('/account/deauthentication', 'accounts', 'deauthentication', 'POST');
|
|
||||||
$router->write('/account/deauthentication', 'accounts', 'deauthentication', 'GET');
|
|
||||||
$router->write('/books', 'books', 'index', 'GET');
|
|
||||||
$router->write('/books/$id', 'books', 'index', 'GET');
|
|
||||||
$router->write('/books/$id/$page', 'books', 'index', 'GET');
|
|
||||||
$router->write('/books/$id/$page/rotate', 'books', 'rotate', 'POST');
|
|
||||||
$router->write('/books/$id/delete', 'books', 'delete', 'POST');
|
|
||||||
$router->write('/storage/books/$id/$file', 'books', 'read', 'GET');
|
|
||||||
$router->write('/storage/books/write', 'books', 'write', 'POST');
|
|
||||||
$router->write('/kemenov', 'kemenov', 'index', 'GET');
|
|
||||||
$router->write('/surikov', 'surikov', 'index', 'GET');
|
|
||||||
$router->write('/contacts', 'contacts', 'index', 'GET');
|
|
||||||
|
|
||||||
// Инициализация ядра
|
|
||||||
$core = new core(namespace: __NAMESPACE__, router: $router);
|
|
||||||
|
|
||||||
// Обработка запроса
|
|
||||||
echo $core->start();
|
|
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace mirzaev\surikovlib\views;
|
|
||||||
|
|
||||||
use mirzaev\minimal\controller;
|
|
||||||
|
|
||||||
use Twig\Loader\FilesystemLoader;
|
|
||||||
use Twig\Environment as view;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Менеджер представлений
|
|
||||||
*
|
|
||||||
* @package mirzaev\surikovlib\controllers
|
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
|
||||||
*/
|
|
||||||
final class manager extends controller
|
|
||||||
{
|
|
||||||
public function render(string $file, array $vars = []): ?string
|
|
||||||
{
|
|
||||||
// Генерация представления
|
|
||||||
return (new view(new FilesystemLoader(VIEWS)))->render($file, $vars);
|
|
||||||
}
|
|
||||||
}
|
|