Init
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.idea/
|
||||
/vendor
|
||||
composer.lock
|
||||
22
composer.json
Normal file
22
composer.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "rmphp/kernel",
|
||||
"license": "proprietary",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Yuri Zuev",
|
||||
"email": "y_zuev@mail.ru"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"psr/log": "^3.0.0",
|
||||
"psr/container": "^1.0",
|
||||
"rmphp/foundation": "1.0.x-dev"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Rmphp\\Kernel\\": "src/"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
207
src/App.php
Normal file
207
src/App.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Rmphp\Kernel;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Rmphp\Foundation\Exceptions\AppError;
|
||||
use Rmphp\Foundation\Exceptions\AppException;
|
||||
use Rmphp\Foundation\RouterInterface;
|
||||
use Rmphp\Foundation\TemplateInterface;
|
||||
use Rmphp\Foundation\MatchObject;
|
||||
|
||||
|
||||
class App extends Main {
|
||||
|
||||
private string $baseDir;
|
||||
private array $appRoutes = [];
|
||||
private RouterInterface $router;
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$this->baseDir = dirname(__DIR__, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function handler(ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface {
|
||||
try{
|
||||
$this->init($request, $response);
|
||||
$this->syslogger()->log("routes", "", $this->appRoutes);
|
||||
|
||||
foreach ($this->appRoutes as $appRouteKey => $appHandler){
|
||||
|
||||
if(!$appHandler instanceof MatchObject) continue;
|
||||
$response = null;
|
||||
|
||||
if(!empty($appHandler->className)){
|
||||
if(!class_exists($appHandler->className)) {
|
||||
$this->syslogger()->log("handlers", "Err - Class ".$appHandler->className." is not exists");
|
||||
continue;
|
||||
}
|
||||
$controllers[$appRouteKey] = new $appHandler->className;
|
||||
$log = "OK - Class ".$appHandler->className;
|
||||
|
||||
if(!empty($appHandler->methodName)){
|
||||
if(!method_exists($appHandler->className, $appHandler->methodName)) {
|
||||
$this->syslogger()->log("handlers", "Err - Method ".$appHandler->className."/".$appHandler->methodName." is not exists");
|
||||
continue;
|
||||
}
|
||||
$response = (!empty($appHandler->params)) ? $controllers[$appRouteKey]->{$appHandler->methodName}(...$appHandler->params) : $controllers[$appRouteKey]->{$appHandler->methodName}();
|
||||
$log = "OK - Method ".$appHandler->className."/".$appHandler->methodName;
|
||||
}
|
||||
$this->syslogger()->log("handlers", $log);
|
||||
/**
|
||||
* 1. Если на этапе итерации уже получен ответ ResponseInterface - досрочно отдаем результат в эмиттер
|
||||
*/
|
||||
if($response instanceof ResponseInterface) {
|
||||
return $response;
|
||||
}
|
||||
elseif($response === false) break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 2. Если итерации закончились и задан обьект Content им создаем результат для эмиттера
|
||||
*/
|
||||
if($this->template() && !empty($this->template()->getResponse())){
|
||||
$body = $this->globals()->response()->getBody();
|
||||
$body->write($this->template()->getResponse());
|
||||
$body->rewind();
|
||||
return $this->globals()->response()->withBody($body);
|
||||
}
|
||||
/**
|
||||
* 3. Отдаем пустой результат если не определен шаблонизатор
|
||||
*/
|
||||
return $this->defaultPage(404);
|
||||
}
|
||||
catch (AppException $appException){
|
||||
if($this->logger()) $this->logger()->warning($appException->getMessage()." on ".$appException->getFile().":".$appException->getLine());
|
||||
$this->syslogger()->warning("AppException: ".$appException->getMessage());
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
if($this->logger()) $this->logger()->warning($exception->getMessage()." on ".$exception->getFile().":".$exception->getLine());
|
||||
$this->syslogger()->warning("Exception: ".$exception->getMessage()." : ".$exception->getFile()." : ".$exception->getLine());
|
||||
}
|
||||
catch (AppError $appError){
|
||||
if($this->logger()) $this->logger()->warning($appError->getMessage()." on ".$appError->getFile().":".$appError->getLine());
|
||||
$this->syslogger()->error("Error: ".$appError->getMessage()." : ".$appError->getFile()." : ".$appError->getLine());
|
||||
}
|
||||
catch (\Error $error) {
|
||||
if($this->logger()) $this->logger()->error($error->getMessage()." on ".$error->getFile().":".$error->getLine());
|
||||
$this->syslogger()->error("Error: ".$error->getMessage()." : ".$error->getFile()." : ".$error->getLine());
|
||||
}
|
||||
/**
|
||||
* 4. Отдаем ошибку без шаблона
|
||||
*/
|
||||
return $this->defaultPage(501);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $code
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
private function defaultPage(int $code) : ResponseInterface{
|
||||
if(is_file($this->baseDir.'/'.getenv("PAGE".$code))){
|
||||
$body = $this->globals()->response()->getBody();
|
||||
$body->write(file_get_contents($this->baseDir.'/'.getenv("PAGE".$code)));
|
||||
$body->rewind();
|
||||
return $this->globals()->response()->withBody($body)->withStatus($code);
|
||||
}
|
||||
return $this->globals()->response()->withStatus($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return void
|
||||
* @throws AppException
|
||||
*/
|
||||
private function init(ServerRequestInterface $request, ResponseInterface $response) : void {
|
||||
|
||||
$this->setGlobals($request, $response);
|
||||
|
||||
// init factories
|
||||
if(is_file($this->baseDir."/".getenv("APP_COMPONENTS_FILE"))){
|
||||
$components = include_once $this->baseDir."/".getenv("APP_COMPONENTS_FILE");
|
||||
if(!empty($components) && is_array($components)){
|
||||
foreach ($components as $componentName => $componentValue){
|
||||
if(empty($componentValue)) {
|
||||
continue;
|
||||
}
|
||||
elseif(is_object($componentValue)){
|
||||
$componentObject = $componentValue;
|
||||
}
|
||||
elseif(!file_exists($this->baseDir.'/'.$componentValue) || !is_object($componentObject = require $this->baseDir.'/'.$componentValue)){
|
||||
throw AppException::invalidObject($componentValue);
|
||||
}
|
||||
switch (true){
|
||||
case ($componentObject instanceof ContainerInterface): $this->setContainer($componentObject); break;
|
||||
case ($componentObject instanceof TemplateInterface): $this->setTemplate($componentObject); break;
|
||||
case ($componentObject instanceof LoggerInterface): $this->setLogger($componentObject); break;
|
||||
case ($componentObject instanceof RouterInterface): $this->router = $componentObject; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// app nodes
|
||||
if(is_file($this->baseDir."/".getenv("APP_NODES_FILE"))){
|
||||
$nodes = include_once $this->baseDir."/".getenv("APP_NODES_FILE");
|
||||
}
|
||||
for ($appNodeNum = 1; getenv("APP_NODE".$appNodeNum); $appNodeNum++){
|
||||
$nodesCollection[] = json_decode(getenv("APP_NODE".$appNodeNum), true);
|
||||
}
|
||||
if(isset($nodesCollection)) $nodes = $nodesCollection;
|
||||
|
||||
if(empty($nodes) || !is_array($nodes)) throw AppException::emptyAppNodes();
|
||||
$this->getActions($nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $appNodes
|
||||
*/
|
||||
private function getActions(array $appNodes) : void {
|
||||
foreach ($appNodes as $appNode){
|
||||
|
||||
// по умолчанию точка монтирования ровна корню
|
||||
$mountKey = (!empty($appNode['key'])) ? $appNode['key'] : '/';
|
||||
|
||||
// если url начинается не с точки монтирования смотрим далее
|
||||
if (0 !== (strpos($this->globals()->request()->getUri()->getPath(), $mountKey))) continue;
|
||||
|
||||
if(!empty($appNode['action'])){
|
||||
$className = $appNode['action'];
|
||||
$methodName = $appNode['method'];
|
||||
$params = (!empty($appNode['params']) && is_string($appNode['params'])) ? explode(",",str_replace(" ", "", $appNode['params'])) : [];
|
||||
$this->appRoutes[] = new MatchObject($className, $methodName, $params);
|
||||
}
|
||||
elseif(!empty($appNode['router']) && file_exists($this->baseDir."/".$appNode['router'])){
|
||||
|
||||
if(empty($this->router)) throw AppError::invalidRequiredObject("Application config without router");
|
||||
$this->router->setStartPoint($mountKey);
|
||||
|
||||
if(pathinfo($this->baseDir."/".$appNode['router'])['extension'] == "php") {
|
||||
$this->router->withRules(include_once $this->baseDir."/".$appNode['router']);
|
||||
}
|
||||
elseif(pathinfo($this->baseDir."/".$appNode['router'])['extension'] == "json") {
|
||||
$this->router->withRules(json_decode(file_get_contents($this->baseDir."/".$appNode['router']), true));
|
||||
}
|
||||
elseif(pathinfo($this->baseDir."/".$appNode['router'])['extension'] == "yaml") {
|
||||
$this->router->withRules(yaml_parse_file($this->baseDir."/".$appNode['router']));
|
||||
}
|
||||
|
||||
$routes = $this->router->match($this->globals()->request()) ?? [];
|
||||
foreach ($routes as $route){
|
||||
$this->appRoutes[] = $route;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
261
src/Globals.php
Normal file
261
src/Globals.php
Normal file
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
|
||||
namespace Rmphp\Kernel;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class Globals {
|
||||
|
||||
private ServerRequestInterface $request;
|
||||
private ResponseInterface $response;
|
||||
private Session $session;
|
||||
|
||||
const INT = "INT";
|
||||
const STRING = "STRING";
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
public function __construct(ServerRequestInterface $request, ResponseInterface $response) {
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return ServerRequestInterface
|
||||
*/
|
||||
public function request() : ServerRequestInterface {
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function response() : ResponseInterface {
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @return ServerRequestInterface
|
||||
*/
|
||||
public function setReqest(ServerRequestInterface $request) : ServerRequestInterface {
|
||||
$this->request = $request;
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function setResponse(ResponseInterface $response) : ResponseInterface {
|
||||
$this->response = $response;
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function isGet(string $name = "") : bool {
|
||||
return (!empty($name)) ? isset($this->request->getQueryParams()[$name]) : !empty($this->request->getQueryParams());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function isPost(string $name = "") : bool {
|
||||
return (!empty($name)) ? isset($this->request->getParsedBody()[$name]) : !empty($this->request->getParsedBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function isCookie(string $name = "") : bool {
|
||||
return (!empty($name)) ? isset($this->request->getCookieParams()[$name]) : !empty($this->request->getCookieParams());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function isSession(string $name = "") : bool {
|
||||
if(!class_exists(Session::class)) return false;
|
||||
if(!isset($this->session)) $this->session = new Session();
|
||||
return (!empty($name)) ? isset($this->session->getSession()[$name]) : !empty($this->session->getSession());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function isFile(string $name = "") : bool {
|
||||
return (!empty($name)) ? isset($this->request->getUploadedFiles()[$name]) : !empty($this->request->getUploadedFiles());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isStream() : bool {
|
||||
return !empty($this->request->getBody()->getContents());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @return array|int|string
|
||||
*/
|
||||
public function get(string $name = "", string $type = "") {
|
||||
return $this->onGlobal($this->request->getQueryParams(), $name, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @return array|int|string
|
||||
*/
|
||||
public function post(string $name = "", string $type = "") {
|
||||
return $this->onGlobal($this->request->getParsedBody(), $name, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @return array|int|string
|
||||
*/
|
||||
public function cookie(string $name = "", string $type = "") {
|
||||
return $this->onGlobal($this->request->getCookieParams(), $name, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @return array|int|string
|
||||
*/
|
||||
public function session(string $name = "", string $type = "") {
|
||||
if(!class_exists(Session::class)) return null;
|
||||
if(!isset($this->session)) $this->session = new Session();
|
||||
return $this->onGlobal($this->session->getSession(), $name, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return array|int|string
|
||||
*/
|
||||
public function files(string $name = "") {
|
||||
return $this->onGlobal($this->request->getUploadedFiles(), $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function stream() {
|
||||
return !empty($this->request->getBody()->getContents()) ? $this->request->getBody()->getContents(): null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function addHeader(string $name, string $value) : void {
|
||||
$this->setResponse($this->response->withAddedHeader($name, $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param $value
|
||||
* @return void
|
||||
*/
|
||||
public function setSession(string $name, $value = null) : void {
|
||||
if(class_exists(Session::class)) {
|
||||
if(!isset($this->session)) $this->session = new Session();
|
||||
$this->session->setSession($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @param int $expires
|
||||
* @param string $path
|
||||
* @param string $domain
|
||||
* @param bool $secure
|
||||
* @param bool $httponly
|
||||
* @return void
|
||||
*/
|
||||
public function setCookie(string $name, string $value="", int $expires = 0, string $path = "", string $domain = "", bool $secure = false, bool $httponly = false) : void {
|
||||
$cookie = [];
|
||||
$cookie[] = $name."=".((!empty($value)) ? $value : "deleted");
|
||||
if($expires != 0) {
|
||||
$cookie[] = ($expires>time()) ? "expires=".date("D, d-M-Y H:i:s", $expires)." GMT; Max-Age=".($expires-time()) : "expires=".date("D, d-M-Y H:i:s", 0)." GMT; Max-Age=0";
|
||||
}
|
||||
if(!empty($path)) $cookie[] = "path=".$path;
|
||||
if(!empty($domain)) $cookie[] = "domain=".$domain;
|
||||
if($secure) $cookie[] = "Secure";
|
||||
if($httponly) $cookie[] = "HttpOnly";
|
||||
$this->addHeader("Set-Cookie", implode("; ", $cookie));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $name
|
||||
* @return void
|
||||
*/
|
||||
public function clearSession(string $name = null) : void{
|
||||
if(class_exists(Session::class)) {
|
||||
if(!isset($this->session)) $this->session = new Session();
|
||||
$this->session->clearSession($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function clearCookie(string $name, string $path = "") : void {
|
||||
$cookie = $name."=deleted; expires=".date("D, d-M-Y H:i:s", 0)." GMT; Max-Age=0";
|
||||
if(!empty($path)) $cookie.="; path=".$path;
|
||||
$this->addHeader("Set-Cookie", $cookie);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param array $var
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @return array|int|string
|
||||
*/
|
||||
private function onGlobal(array $var, string $name, string $type = "") {
|
||||
$name = strtolower($name);
|
||||
if (!empty($name))
|
||||
{
|
||||
if (!isset($var[$name])) return null;
|
||||
|
||||
if (empty($type)) {
|
||||
return $var[$name];
|
||||
}
|
||||
elseif ($type == self::STRING) {
|
||||
return (!empty($var[$name])) ? (string)$var[$name] : null;
|
||||
}
|
||||
elseif ($type == self::INT) {
|
||||
return (!empty((int)$var[$name]) || $var[$name]==0) ? (int)$var[$name] : null;
|
||||
}
|
||||
}
|
||||
return $var;
|
||||
}
|
||||
|
||||
}
|
||||
144
src/Logger.php
Normal file
144
src/Logger.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Rmphp\Kernel;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Logger implements LoggerInterface {
|
||||
|
||||
public const DEBUG = 'DEBUG';
|
||||
public const INFO = 'INFO';
|
||||
public const NOTICE = 'NOTICE';
|
||||
public const WARNING = 'WARNING';
|
||||
public const ERROR = 'ERROR';
|
||||
public const CRITICAL = 'CRITICAL';
|
||||
public const ALERT = 'ALERT';
|
||||
public const EMERGENCY = 'EMERGENCY';
|
||||
|
||||
private static array $logs = [];
|
||||
|
||||
/**
|
||||
* Levels numbers defined in RFC 5424
|
||||
*/
|
||||
private const RFC_5424_LEVELS = [
|
||||
7 => self::DEBUG,
|
||||
6 => self::INFO,
|
||||
5 => self::NOTICE,
|
||||
4 => self::WARNING,
|
||||
3 => self::ERROR,
|
||||
2 => self::CRITICAL,
|
||||
1 => self::ALERT,
|
||||
0 => self::EMERGENCY,
|
||||
];
|
||||
|
||||
/**
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function emergency(\Stringable|string $message, array $context=[]): void {
|
||||
$this->log(self::EMERGENCY, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function alert(\Stringable|string $message, array $context=[]): void {
|
||||
$this->log(self::ALERT, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function critical(\Stringable|string $message, array $context=[]): void {
|
||||
$this->log(self::CRITICAL, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function error(\Stringable|string $message, array $context=[]): void {
|
||||
$this->log(self::ERROR, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function warning(\Stringable|string $message, array $context=[]): void {
|
||||
$this->log(self::WARNING, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function notice(\Stringable|string $message, array $context=[]): void {
|
||||
$this->log(self::NOTICE, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function info(\Stringable|string $message, array $context=[]): void {
|
||||
$this->log(self::INFO, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function debug(\Stringable|string $message, array $context=[]): void {
|
||||
$this->log(self::DEBUG, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $level
|
||||
* @param \Stringable|string $message
|
||||
* @param array $context
|
||||
* @return void
|
||||
*/
|
||||
public function log($level, \Stringable|string $message, array $context=[]): void {
|
||||
if(is_numeric($level) && isset(self::RFC_5424_LEVELS[$level])){
|
||||
$level = self::RFC_5424_LEVELS[$level];
|
||||
}
|
||||
if(!empty((string)$message))$in[] = $message;
|
||||
if(!empty($context))$in[] = $context;
|
||||
self::$logs[$level][] = (count($in)==1) ? $in[0] : $in;;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $level
|
||||
* @param mixed $context
|
||||
* @return void
|
||||
*/
|
||||
public function dump($level, mixed $context) : void {
|
||||
self::$logs[$level][] = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array
|
||||
*/
|
||||
public function getLogs($level = null) : array {
|
||||
if(is_numeric($level) && isset(self::RFC_5424_LEVELS[$level])){
|
||||
$level = self::RFC_5424_LEVELS[$level];
|
||||
}
|
||||
$out = [];
|
||||
foreach (self::$logs as $key => $logField){
|
||||
$out[$key] = (count($logField)==1) ? $logField[0] : $logField;
|
||||
}
|
||||
return isset($level) ? $out[$level] : $out;
|
||||
}
|
||||
}
|
||||
97
src/Main.php
Normal file
97
src/Main.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Rmphp\Kernel;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Rmphp\Foundation\TemplateInterface;
|
||||
|
||||
class Main {
|
||||
|
||||
private static ?Logger $syslogger = null;
|
||||
private static ?Globals $globals = null;
|
||||
private static ?ContainerInterface $container = null;
|
||||
private static ?TemplateInterface $template = null;
|
||||
private static ?LoggerInterface $logger = null;
|
||||
|
||||
/**
|
||||
* @return Logger
|
||||
*/
|
||||
final public function syslogger() : Logger {
|
||||
if(!isset(self::$syslogger) && class_exists(Logger::class)) {
|
||||
self::$syslogger = new Logger();
|
||||
}
|
||||
return self::$syslogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return void
|
||||
*/
|
||||
protected function setGlobals(ServerRequestInterface $request, ResponseInterface $response) : void {
|
||||
if(!isset(self::$globals) && class_exists(Globals::class)) {
|
||||
self::$globals = new Globals($request, $response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
* @return void
|
||||
*/
|
||||
protected function setContainer(ContainerInterface $container) : void {
|
||||
self::$container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TemplateInterface $template
|
||||
* @return void
|
||||
*/
|
||||
protected function setTemplate(TemplateInterface $template) : void {
|
||||
self::$template = $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LoggerInterface $logger
|
||||
* @return void
|
||||
*/
|
||||
protected function setLogger(LoggerInterface $logger) : void {
|
||||
self::$logger = $logger;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Globals|null
|
||||
*/
|
||||
final public function globals() : ?Globals {
|
||||
return self::$globals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContainerInterface|null
|
||||
*/
|
||||
final public function container() : ?ContainerInterface {
|
||||
if(empty(self::$container)) $this->syslogger()->warning("Application config without countainer");
|
||||
return self::$container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TemplateInterface|null
|
||||
*/
|
||||
final public function template() : ?TemplateInterface {
|
||||
if(empty(self::$template)) $this->syslogger()->warning("Application config without template");
|
||||
return self::$template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LoggerInterface|null
|
||||
*/
|
||||
final public function logger() : ?LoggerInterface {
|
||||
if(empty(self::$logger)){
|
||||
$this->syslogger()->warning("Application config without logger");
|
||||
}
|
||||
return self::$logger;
|
||||
}
|
||||
}
|
||||
117
src/ResponseEmitter.php
Normal file
117
src/ResponseEmitter.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Rmphp\Kernel;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class ResponseEmitter {
|
||||
|
||||
private int $responseChunkSize;
|
||||
|
||||
/**
|
||||
* ResponseEmitter constructor.
|
||||
* @param int $responseChunkSize
|
||||
*/
|
||||
public function __construct(int $responseChunkSize = 4096)
|
||||
{
|
||||
$this->responseChunkSize = $responseChunkSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
public function emit(ResponseInterface $response): void
|
||||
{
|
||||
$isEmpty = $this->isResponseEmpty($response);
|
||||
if (headers_sent() === false) {
|
||||
$this->emitStatusLine($response);
|
||||
$this->emitHeaders($response);
|
||||
}
|
||||
|
||||
if (!$isEmpty) {
|
||||
$this->emitBody($response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
private function emitHeaders(ResponseInterface $response): void
|
||||
{
|
||||
foreach ($response->getHeaders() as $name => $values) {
|
||||
$first = strtolower($name) !== 'set-cookie';
|
||||
foreach ($values as $value) {
|
||||
$header = sprintf('%s: %s', $name, $value);
|
||||
header($header, $first);
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
private function emitStatusLine(ResponseInterface $response): void
|
||||
{
|
||||
$statusLine = sprintf(
|
||||
'HTTP/%s %s %s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
header($statusLine, true, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
private function emitBody(ResponseInterface $response): void
|
||||
{
|
||||
$body = $response->getBody();
|
||||
if ($body->isSeekable()) {
|
||||
$body->rewind();
|
||||
}
|
||||
|
||||
$amountToRead = (int) $response->getHeaderLine('Content-Length');
|
||||
if (!$amountToRead) {
|
||||
$amountToRead = $body->getSize();
|
||||
}
|
||||
|
||||
if ($amountToRead) {
|
||||
while ($amountToRead > 0 && !$body->eof()) {
|
||||
$length = min($this->responseChunkSize, $amountToRead);
|
||||
$data = $body->read($length);
|
||||
echo $data;
|
||||
|
||||
$amountToRead -= strlen($data);
|
||||
|
||||
if (connection_status() !== CONNECTION_NORMAL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (!$body->eof()) {
|
||||
echo $body->read($this->responseChunkSize);
|
||||
if (connection_status() !== CONNECTION_NORMAL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
* @return bool
|
||||
*/
|
||||
public function isResponseEmpty(ResponseInterface $response): bool
|
||||
{
|
||||
if (in_array($response->getStatusCode(), [204, 205, 304], true)) {
|
||||
return true;
|
||||
}
|
||||
$stream = $response->getBody();
|
||||
$seekable = $stream->isSeekable();
|
||||
if ($seekable) {
|
||||
$stream->rewind();
|
||||
}
|
||||
return $seekable ? $stream->read(1) === '' : $stream->eof();
|
||||
}
|
||||
}
|
||||
39
src/Session.php
Normal file
39
src/Session.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Rmphp\Kernel;
|
||||
|
||||
|
||||
class Session {
|
||||
|
||||
public function __construct(string $name = "usi") {
|
||||
if(session_status() == PHP_SESSION_NONE) {
|
||||
session_name($name);
|
||||
session_start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSession() : array {
|
||||
return $_SESSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param $value
|
||||
*/
|
||||
public function setSession(string $name, $value = null) : void {
|
||||
$_SESSION[$name] = $value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $name
|
||||
* @return void
|
||||
*/
|
||||
public function clearSession(string $name = null) : void {
|
||||
if (isset($name)) unset($_SESSION[$name]);
|
||||
else $_SESSION = [];
|
||||
}
|
||||
}
|
||||
140
src/Utils.php
Normal file
140
src/Utils.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Rmphp\Kernel;
|
||||
|
||||
|
||||
class Utils {
|
||||
|
||||
private static int $idcount = 0;
|
||||
private static string $objid;
|
||||
private static int $deep = 0;
|
||||
|
||||
private static function generateCSSBlock() : void {
|
||||
?>
|
||||
<style>
|
||||
.hide-<?=self::$objid?>{display: none}
|
||||
.s-<?=self::$objid?>-h{padding: 5px 0; box-sizing: border-box; background: #0F0F0A; font: 11px Tahoma; color:#868746; font-weight: bold; border-bottom: 1px solid #323334;}
|
||||
.s-<?=self::$objid?>-h span{cursor: pointer;}
|
||||
.s-<?=self::$objid?>-b{border-left: 1px solid #606060; border-bottom: 0; padding: 0 0 0 20px; margin: 3px 0 0 0; position: relative}
|
||||
.s-<?=self::$objid?>-t{display: table; border-collapse: collapse;}
|
||||
.s-<?=self::$objid?>-tr{background: #000000; display: table-row; border-bottom: 1px solid #323334;}
|
||||
.s-<?=self::$objid?>-tс{display:table-cell; padding: 5px 25px 5px 0; font: 11px Tahoma; color:#a2a399; font-weight: bold}
|
||||
.s-<?=self::$objid?>-tс:nth-child(1){min-width:10%;}
|
||||
.s-<?=self::$objid?>-tс:nth-child(2){min-width:10%;}
|
||||
.s-<?=self::$objid?>-tс:nth-child(3){width:100%;}
|
||||
.s-<?=self::$objid?>-trs{background: #000000; display: table-row;}
|
||||
.s-<?=self::$objid?>-tсs:nth-child(1){display:table-cell; padding: 0; font: 11px Tahoma; color:#a2a399; font-weight: bold}
|
||||
.s-<?=self::$objid?>-sc{font: 11px Tahoma; color:#a2a399; font-weight: bold}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function generateJSBlock() : void{
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
document.querySelectorAll('.s-<?=self::$objid?>-h>span').forEach(i => {
|
||||
if(document.getElementById('b-'+i.id)) {
|
||||
i.querySelector('span').innerHTML = (document.getElementById('b-'+i.id).classList.contains("hide-<?=self::$objid?>")) ? ' ►' : ' ▼'
|
||||
i.addEventListener('click', ()=>{
|
||||
document.getElementById('b-'+i.id).classList.toggle("hide-<?=self::$objid?>");
|
||||
i.querySelector('span').innerHTML = (document.getElementById('b-'+i.id).classList.contains("hide-<?=self::$objid?>")) ? ' ►' : ' ▼'
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function generateStartLine(): void {
|
||||
?>
|
||||
<div style="position:relative; box-sizing: border-box; width:100%; padding:10px; background: #000000; z-index: 10000; overflow: auto;">
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function fromatValue(mixed $val) : mixed {
|
||||
if(is_bool($val)) return (!empty($val)) ? 'true' : 'false';
|
||||
if(is_int($val)) return htmlspecialchars($val);
|
||||
if(is_float($val)) return htmlspecialchars($val);
|
||||
if(is_string($val)) return htmlspecialchars($val);
|
||||
if(!isset($val)) return '-';
|
||||
return $val;
|
||||
}
|
||||
|
||||
private static function generateHTMLBlock ($data, $title = "array"){
|
||||
if(is_array($data) || is_object($data)){
|
||||
self::$deep++;
|
||||
$id = 'id'.self::$objid.self::$idcount++;
|
||||
$display = true;
|
||||
if(is_array((array)$data) && count((array)$data) > 10) $display = false;
|
||||
if (in_array(self::$deep,[3,5])) $display = false;
|
||||
?>
|
||||
<div class="s-<?=self::$objid?>-h">
|
||||
<span id="<?=$id?>"><?=str_replace(mb_chr(0), "-", $title)?> (<?=count((array)$data)?>) <span> </span></span>
|
||||
</div>
|
||||
<?php if(count((array)$data)): ?>
|
||||
<div id="b-<?=$id?>" class="s-<?=self::$objid?>-b <?=((!$display)?'hide-'.self::$objid:'')?>">
|
||||
<table class="s-<?=self::$objid?>-t">
|
||||
<?php foreach ((array)$data as $key => $val) : ?>
|
||||
<?php if(is_array($val) || is_object($val)):?>
|
||||
<tr class="s-<?=self::$objid?>-trs">
|
||||
<td class="s-<?=self::$objid?>-tсs" colspan="3"><?php self::generateHTMLBlock($val, "[".$key."]");?></td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<tr class="s-<?=self::$objid?>-tr">
|
||||
<td class="s-<?=self::$objid?>-tс">[<?=htmlspecialchars($key)?>]</td>
|
||||
<td class="s-<?=self::$objid?>-tс"><?=gettype($val)?></td>
|
||||
<td class="s-<?=self::$objid?>-tс"><?=self::fromatValue($val)?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php endforeach;?>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif;
|
||||
self::$deep--;
|
||||
} else {
|
||||
?>
|
||||
<div class="s-<?=self::$objid?>-sc">
|
||||
<div>(<?=gettype($data)?>) <?=self::fromatValue($data)?></div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
public static function addShutdownInfo(array $exData = []) : void {
|
||||
register_shutdown_function(function() use ($exData) {
|
||||
$finish = array_sum(explode(' ', microtime()));
|
||||
$info[] = error_get_last();
|
||||
$info[] = "Время генерации: ".substr((string)($finish-$_SERVER['REQUEST_TIME_FLOAT']), 0, 10)." сек.";
|
||||
$info[] = "Объем памяти: ".round((memory_get_usage()),2)." байт.";
|
||||
$info[] = "Выделено памяти в пике: ".round((memory_get_peak_usage()),2)." байт.";
|
||||
$exData['info'] = array_diff($info, array(null));
|
||||
|
||||
if(in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)){
|
||||
var_dump($exData);
|
||||
} else {
|
||||
self::$objid = substr(md5(time()),0,5);
|
||||
self::generateCSSBlock();
|
||||
self::generateStartLine();
|
||||
self::generateHTMLBlock($exData, "dump info");
|
||||
echo '</div>';
|
||||
self::generateJSBlock();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static function dd(mixed $exData) : void {
|
||||
register_shutdown_function(function() use ($exData) {
|
||||
if(in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)){
|
||||
var_dump($exData);
|
||||
} else {
|
||||
self::$objid = substr(md5(time()),0,5);
|
||||
self::generateCSSBlock();
|
||||
self::generateStartLine();
|
||||
self::generateHTMLBlock($exData);
|
||||
echo '</div>';
|
||||
self::generateJSBlock();
|
||||
}
|
||||
});
|
||||
exit;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user