Riyyi
4 years ago
commit
a8056b66cc
67 changed files with 7759 additions and 0 deletions
@ -0,0 +1,31 @@
|
||||
# Non-project |
||||
.idea/ |
||||
.directory |
||||
|
||||
# Files |
||||
*.mwb.bak |
||||
config.php |
||||
composer.lock |
||||
syncconfig.sh |
||||
|
||||
# Directories |
||||
/public/* |
||||
!/public/css/ |
||||
/public/css/* |
||||
!/public/fonts/ |
||||
!/public/img/ |
||||
/public/img/* |
||||
!/public/js/ |
||||
/public/js/* |
||||
!/public/media/ |
||||
/public/media/* |
||||
/vendor/* |
||||
|
||||
# Unignore |
||||
!/public/.htaccess |
||||
!/public/css/style.css |
||||
!/public/img/favicon.png |
||||
!/public/index.php |
||||
!/public/js/app.js |
||||
!/public/js/site.js |
||||
!/public/media/.gitinclude |
@ -0,0 +1,29 @@
|
||||
<?php |
||||
|
||||
namespace App\Classes; |
||||
|
||||
class Config { |
||||
|
||||
protected static $config; |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public static function load(): void |
||||
{ |
||||
if (file_exists('../config.php')) { |
||||
self::$config = require_once '../config.php'; |
||||
} |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public static function c(string $index = ''): string |
||||
{ |
||||
if (_exists(self::$config, $index)) { |
||||
return self::$config[$index]; |
||||
} |
||||
|
||||
return ''; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,106 @@
|
||||
<?php |
||||
|
||||
namespace App\Classes; |
||||
|
||||
class Db { |
||||
|
||||
protected static $db; |
||||
|
||||
protected static $columns = []; |
||||
protected static $sections = []; |
||||
protected static $pages = []; |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public static function load(): void { |
||||
try { |
||||
$host = Config::c('DB_HOST'); |
||||
$name = Config::c('DB_NAME'); |
||||
self::$db = new \PDO( |
||||
"mysql:host=$host;dbname=$name;charset=utf8mb4", |
||||
Config::c('DB_USERNAME'), |
||||
Config::c('DB_PASSWORD') |
||||
); |
||||
} catch (\PDOException $e) { |
||||
throw new \PDOException($e->getMessage(), (int)$e->getCode()); |
||||
} |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
/** |
||||
* Get the PDO connection object |
||||
* |
||||
* @return PDO |
||||
*/ |
||||
public static function get(): \PDO { |
||||
return self::$db; |
||||
} |
||||
|
||||
/** |
||||
* Get all columns |
||||
* |
||||
* @return array |
||||
*/ |
||||
public static function getColumns(): array |
||||
{ |
||||
return self::$columns; |
||||
} |
||||
|
||||
/** |
||||
* Get all sections |
||||
* |
||||
* @return array |
||||
*/ |
||||
public static function getSections(): array |
||||
{ |
||||
return self::$sections; |
||||
} |
||||
|
||||
/** |
||||
* Get all pages |
||||
* |
||||
* @return array |
||||
*/ |
||||
public static function getPages(): array |
||||
{ |
||||
return self::$pages; |
||||
} |
||||
|
||||
/** |
||||
* Store columns |
||||
* |
||||
* @param array $columns |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function setColumns(array $columns): void |
||||
{ |
||||
self::$columns = $columns; |
||||
} |
||||
|
||||
/** |
||||
* Store sections |
||||
* |
||||
* @param array $sections |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function setSections(array $sections): void |
||||
{ |
||||
self::$sections = $sections; |
||||
} |
||||
|
||||
/** |
||||
* Store pages |
||||
* |
||||
* @param array $pages |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function setPages(array $pages): void |
||||
{ |
||||
self::$pages = $pages; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,188 @@
|
||||
<?php |
||||
|
||||
namespace App\Classes; |
||||
|
||||
use \Klein\Klein; |
||||
|
||||
class Form { |
||||
|
||||
private $router; |
||||
|
||||
private $data = []; |
||||
private $resetLabel = ''; |
||||
private $submitLabel = 'Submit'; |
||||
private $errorKey = ''; |
||||
|
||||
public function __construct(Klein $router) |
||||
{ |
||||
$this->router = $router; |
||||
$this->router->service()->csrfToken = Session::token(); |
||||
$this->router->service()->form = $this; |
||||
$this->router->service()->injectView = '../app/views/form.php'; |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public function addField(string $name, array $field): void |
||||
{ |
||||
// "name" => [ |
||||
// "label", |
||||
// "type", text, email, tel, password, radio, textarea, checkbox(?), comment |
||||
// "data", (for radio fields) [ 'value' => 'Label', 'value' => 'Label'] |
||||
// "rules", (server side rules) |
||||
// "message", (server side error message) |
||||
// "pattern", (client sided rule) |
||||
// "title", |
||||
// ], |
||||
|
||||
$this->data[$name] = [ |
||||
$field[0] ?? '', |
||||
$field[1] ?? '', |
||||
$field[2] ?? '', |
||||
$field[3] ?? '', |
||||
$field[4] ?? '', |
||||
$field[5] ?? '', |
||||
$field[6] ?? '', |
||||
]; |
||||
} |
||||
|
||||
public function validated(array $submit = []): bool |
||||
{ |
||||
$result = false; |
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') { |
||||
|
||||
$result = true; |
||||
|
||||
if (empty($submit)) { |
||||
$submit = $_POST; |
||||
} |
||||
|
||||
if (!Session::validateToken($submit)) { |
||||
$result = false; |
||||
} |
||||
|
||||
// Only check fields if CSRF token is valid |
||||
if ($result) { |
||||
// Check field rules |
||||
foreach ($this->data as $ruleName => $ruleValue) { |
||||
|
||||
$found = false; |
||||
$value = ''; |
||||
foreach ($submit as $submitName => $submitValue) { |
||||
|
||||
if ($ruleName == $submitName) { |
||||
$found = true; |
||||
$value = $submitValue; |
||||
break; |
||||
} |
||||
|
||||
if ($ruleValue[1] == 'comment') { |
||||
$found = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!$found || !$this->matchRule($ruleName, $value)) { |
||||
$this->errorKey = $ruleName; |
||||
$result = false; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// If unsuccessful, remember the form fields |
||||
if (!$result) { |
||||
foreach (array_keys($this->data) as $name) { |
||||
if ($name == 'captcha') { |
||||
continue; |
||||
} |
||||
|
||||
$this->router->service()->{$name} = $submit[$name] ?? ''; |
||||
} |
||||
} |
||||
} |
||||
|
||||
Session::delete('captcha'); |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
public function matchRule(string $key, string $value): bool |
||||
{ |
||||
// Get the rule(s) |
||||
$rule = $this->data[$key]; |
||||
$rules = explode('|', $rule[3]); |
||||
|
||||
if (array_search('required', $rules) !== false) { |
||||
if (empty($value)) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if (array_search('email', $rules) !== false) { |
||||
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if (array_search('tel', $rules) !== false) { |
||||
if (!filter_var($value, FILTER_VALIDATE_REGEXP, [ |
||||
'options' => [ |
||||
'regexp' => '/^([0-9]{2}-?[0-9]{8})|([0-9]{3}-?[0-9]{7})$/', |
||||
] |
||||
])) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if (array_search('captcha', $rules) !== false) { |
||||
if (!Session::exists('captcha')) { |
||||
return false; |
||||
} |
||||
else if ($value != Session::get('captcha')) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public function errorMessage(): string |
||||
{ |
||||
return $this->errorKey != '' ? $this->data[$this->errorKey][4] : ''; |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public function getFields(): array |
||||
{ |
||||
return $this->data; |
||||
} |
||||
|
||||
public function getReset(): string |
||||
{ |
||||
return $this->resetLabel; |
||||
} |
||||
|
||||
public function getSubmit(): string |
||||
{ |
||||
return $this->submitLabel; |
||||
} |
||||
|
||||
public function setData(array $data): void |
||||
{ |
||||
$this->data = $data; |
||||
} |
||||
|
||||
public function setReset(string $resetLabel): void |
||||
{ |
||||
$this->resetLabel = $resetLabel; |
||||
} |
||||
|
||||
public function setSubmit(string $submitLabel): void |
||||
{ |
||||
$this->submitLabel = $submitLabel; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,72 @@
|
||||
<?php |
||||
|
||||
namespace App\Classes; |
||||
|
||||
use Tx\Mailer; |
||||
|
||||
class Mail { |
||||
|
||||
protected static $host; |
||||
protected static $port; |
||||
protected static $name; |
||||
protected static $username; |
||||
protected static $password; |
||||
protected static $to; |
||||
|
||||
public static function _init(): void { |
||||
self::$host = Config::c('MAIL_HOST'); |
||||
self::$port = Config::c('MAIL_PORT'); |
||||
self::$name = Config::c('MAIL_NAME'); |
||||
self::$username = Config::c('MAIL_USERNAME'); |
||||
self::$password = Config::c('MAIL_PASSWORD'); |
||||
self::$to = Config::c('MAIL_TO'); |
||||
} |
||||
|
||||
public static function send( |
||||
string $subject, string $message, string $to = '', string $from = ''): bool |
||||
{ |
||||
if ($to == '') { |
||||
$to = self::$to; |
||||
} |
||||
if ($from == '') { |
||||
$from = 'Website <'. self::$username . '>'; |
||||
} |
||||
|
||||
$headers = |
||||
'MIME-Version: 1.0' . "\r\n" . |
||||
'Content-type: text/html; charset=utf-8' . "\r\n" . |
||||
'From: ' . $from . "\r\n" . |
||||
'Reply-To: ' . $from . "\r\n" . |
||||
'X-Mailer: PHP/' . phpversion(); |
||||
|
||||
return mail($to, $subject, $message, $headers); |
||||
} |
||||
|
||||
public static function sendMail(string $subject, string $message, string $from = '', string $to = ''): bool |
||||
{ |
||||
if ($to == '') { |
||||
$to = self::$to; |
||||
} |
||||
if ($from == '') { |
||||
$from = self::$name; |
||||
} |
||||
if (empty(self::$host) || empty(self::$port) || |
||||
empty(self::$username) || empty(self::$password) || empty($to)) { |
||||
return false; |
||||
} |
||||
|
||||
$result = (new Mailer()) |
||||
->setServer(self::$host, self::$port, "tlsv1.2") |
||||
->setAuth(self::$username, self::$password) |
||||
->setFrom($from, self::$username) |
||||
->addTo('', $to) |
||||
->setSubject($subject) |
||||
->setBody($message) |
||||
->send(); |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
} |
||||
|
||||
Mail::_init(); |
@ -0,0 +1,282 @@
|
||||
<?php |
||||
|
||||
namespace App\Classes; |
||||
|
||||
use App\Model\MediaModel; |
||||
|
||||
class Media { |
||||
|
||||
public static $pagination = 20; |
||||
public static $directory = 'media'; |
||||
|
||||
public static function errorMessage(int $errorCode): string |
||||
{ |
||||
// https://www.php.net/manual/en/features.file-upload.errors.php |
||||
$errorMessages = [ |
||||
0 => 'Uploaded with success.', |
||||
1 => 'Uploaded file exceeds the maximum upload size. (1)', // php.ini |
||||
2 => 'Uploaded file exceeds the maximum upload size. (2)', // HTML Form |
||||
3 => 'Uploaded file was only partially uploaded.', |
||||
4 => 'No file was uploaded.', |
||||
6 => 'Missing a temporary folder.', |
||||
7 => 'Failed to write file to disk.', |
||||
8 => 'A PHP extension stopped the file upload.', |
||||
9 => 'User was not logged in.', |
||||
10 => 'Missing media folder.', |
||||
11 => 'Uploaded file has invalid MIME type.', |
||||
12 => 'Uploaded file exceeds the maximum upload size. (3)', // Media.php |
||||
13 => 'Uploaded file already exists.', |
||||
14 => 'DB entry creation failed.', |
||||
15 => 'Moving file from temporary location failed.', |
||||
]; |
||||
|
||||
return $errorMessages[$errorCode]; |
||||
} |
||||
|
||||
public static function deleteMedia(int $id): bool |
||||
{ |
||||
if (!User::check()) { |
||||
return false; |
||||
} |
||||
|
||||
$media = MediaModel::find($id); |
||||
|
||||
if (!$media->exists()) { |
||||
return false; |
||||
} |
||||
|
||||
// Delete file |
||||
$file = self::$directory . '/' . $media->filename . '.' . $media->extension; |
||||
if (file_exists($file)) { |
||||
unlink($file); |
||||
} |
||||
|
||||
return $media->delete(); |
||||
} |
||||
|
||||
public static function uploadMedia(bool $overwrite = false): int |
||||
{ |
||||
// Check if User is logged in |
||||
if (!User::check()) { |
||||
return 9; |
||||
} |
||||
|
||||
// Check if "media" directory exists |
||||
if (!is_dir(self::$directory) && !mkdir(self::$directory, 0755)) { |
||||
return 10; |
||||
} |
||||
|
||||
$files = $_FILES['file']; |
||||
|
||||
// Check for file errors |
||||
foreach ($files['error'] as $error) { |
||||
if ($error != 0) { |
||||
return $error; |
||||
} |
||||
} |
||||
|
||||
if (!Media::checkMimeType($files['type'], $files['tmp_name'])) { |
||||
return 11; |
||||
} |
||||
|
||||
if (!Media::checkSize($files['size'])) { |
||||
return 12; |
||||
} |
||||
|
||||
// Append random string to filename that already exists |
||||
$nameExt = Media::duplicateName($files['name'], $overwrite); |
||||
|
||||
// Check if the file already exists |
||||
$hash = Media::hashExists($files['tmp_name']); |
||||
if (!$hash[0]) { |
||||
return 13; |
||||
} |
||||
|
||||
$count = count($files['name']); |
||||
for ($i = 0; $i < $count; $i++) { |
||||
$filename = $nameExt[0][$i]; |
||||
$extension = $nameExt[1][$i]; |
||||
$md5 = $hash[1][$i]; |
||||
$tmpName = $files['tmp_name'][$i]; |
||||
|
||||
// Store record |
||||
$media = MediaModel::create([ |
||||
'filename' => $filename, |
||||
'extension' => $extension, |
||||
'md5' => $md5, |
||||
]); |
||||
|
||||
if (!$media->exists()) { |
||||
return 14; |
||||
} |
||||
|
||||
// Store image |
||||
$name = self::$directory . '/'. $filename . '.' . $extension; |
||||
if (!move_uploaded_file($tmpName, $name)) { |
||||
return 15; |
||||
} |
||||
|
||||
// After storing successfully, remove old entries with duplicate names |
||||
if ($overwrite) { |
||||
Media::destroyDuplicates($filename, $extension); |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
private static function checkMimeType(array $fileTypes, array $fileTmpNames): bool |
||||
{ |
||||
$allowedMimeType = [ |
||||
// .tar.gz |
||||
'application/gzip', |
||||
'application/json', |
||||
'application/octet-stream', |
||||
'application/pdf', |
||||
'application/sql', |
||||
// .tar.xz |
||||
'application/x-xz', |
||||
'application/xml', |
||||
'application/zip', |
||||
'audio/mp3', |
||||
'audio/mpeg', |
||||
'audio/ogg', |
||||
'audio/wav', |
||||
'audio/webm', |
||||
'image/jpg', |
||||
'image/jpeg', |
||||
'image/png', |
||||
'image/gif', |
||||
'text/plain', |
||||
'text/csv', |
||||
'text/xml', |
||||
'video/mp4', |
||||
'video/webm', |
||||
// .doc |
||||
'application/msword', |
||||
// .xls |
||||
'application/vnd.ms-excel', |
||||
// .ppt |
||||
'application/vnd.ms-powerpoint', |
||||
// .docx |
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document', |
||||
// .xlsx |
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
||||
// .pptx |
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation', |
||||
]; |
||||
|
||||
// Files type check |
||||
$count = count($fileTypes); |
||||
for ($i = 0; $i < $count; $i++) { |
||||
if ($fileTypes[$i] != mime_content_type($fileTmpNames[$i]) || |
||||
!in_array($fileTypes[$i], $allowedMimeType)) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
private static function checkSize(array $fileSizes): bool |
||||
{ |
||||
// Files should not exceed 10MiB |
||||
foreach ($fileSizes as $fileSize) { |
||||
if ($fileSize > 10485760) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
private static function duplicateName(array $filenames, bool $overwrite): array |
||||
{ |
||||
// Split name from extension |
||||
$names = []; |
||||
$extensions = []; |
||||
foreach ($filenames as $name) { |
||||
$dotPos = strrpos($name, '.'); |
||||
$names[] = substr($name, 0, $dotPos); |
||||
$extensions[] = substr($name, $dotPos + 1); |
||||
} |
||||
|
||||
// Early return if names are specified to be overwritten |
||||
if ($overwrite) { |
||||
return [$names, $extensions]; |
||||
} |
||||
|
||||
// Get duplicate filenames |
||||
$in1 = str_repeat('?, ', count($names) - 1) . '?'; |
||||
$in2 = str_repeat('?, ', count($extensions) - 1) . '?'; |
||||
$data = array_merge($names, $extensions); |
||||
$duplicates = MediaModel::selectAll( |
||||
'*', "WHERE filename IN ($in1) AND extension IN ($in2)", $data, '?' |
||||
); |
||||
|
||||
foreach ($filenames as $key => $filename) { |
||||
$hasDuplicate = false; |
||||
foreach ($duplicates as $duplicate) { |
||||
if ($filename == $duplicate['filename'] . '.' . $duplicate['extension']) { |
||||
$hasDuplicate = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// Append to filename if there are duplicates |
||||
if ($hasDuplicate) { |
||||
$names[$key] = $names[$key] . '-' . _randomStr(5); |
||||
} |
||||
} |
||||
|
||||
return [$names, $extensions]; |
||||
} |
||||
|
||||
private static function hashExists(array $fileTmpNames): array |
||||
{ |
||||
$md5 = []; |
||||
foreach ($fileTmpNames as $tmpName) { |
||||
$md5[] = md5_file($tmpName); |
||||
} |
||||
|
||||
// If exact file already exists |
||||
$in = str_repeat('?, ', count($md5) - 1) . '?'; |
||||
$exists = MediaModel::selectAll( |
||||
'*', "WHERE md5 IN ($in)", $md5, '?' |
||||
); |
||||
|
||||
if (!empty($exists)) { |
||||
return [false]; |
||||
} |
||||
|
||||
return [true, $md5]; |
||||
} |
||||
|
||||
private static function destroyDuplicates(string $filename, string $extension): void |
||||
{ |
||||
$media = MediaModel::selectAll( |
||||
'*', 'WHERE filename = ? AND extension = ? ORDER BY id ASC', |
||||
[$filename, $extension], '?' |
||||
); |
||||
|
||||
if (!_exists($media)) { |
||||
return; |
||||
} |
||||
|
||||
foreach ($media as $key => $value) { |
||||
|
||||
// Dont delete the new entry |
||||
if ($key === array_key_last($media)) { |
||||
return; |
||||
} |
||||
|
||||
MediaModel::destroy($value['id']); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
// @Todo |
||||
// - If a file fails to store in the loop, destruct all files of that request, by tracking all IDs |
@ -0,0 +1,352 @@
|
||||
<?php |
||||
|
||||
namespace App\Classes; |
||||
|
||||
use Klein\Klein; |
||||
|
||||
use App\Classes\Db; |
||||
|
||||
use App\Model\SectionModel; |
||||
use App\Model\PageModel; |
||||
|
||||
class Router { |
||||
|
||||
protected static $router; |
||||
protected static $routes = []; |
||||
|
||||
public static function _init(): void { |
||||
self::$router = new Klein(); |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
/** |
||||
* Load all routes into the Klein object |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function fire(): void |
||||
{ |
||||
$path = parse_url($_SERVER['REQUEST_URI'])['path']; |
||||
$check = str_replace('.', '', $path); |
||||
|
||||
// If it's a dynamic file or the file doesn't exist, go through the router. |
||||
if ($path == $check || !file_exists(getcwd() . $path)) { |
||||
|
||||
Db::load(); |
||||
self::setDefaultLayout(); |
||||
self::loadConfigRoutes(); |
||||
self::loadDbRoutes(); |
||||
|
||||
// Process basic routes |
||||
foreach (self::$routes as $route) { |
||||
// If route does not match the base url |
||||
if ($route[0] != $path) { |
||||
continue; |
||||
} |
||||
|
||||
// ["/example/my-page", "ExampleController", "action", "" : ["view", "title", "description"]], |
||||
self::addBasicRoute(['GET', 'POST'], $route); |
||||
|
||||
break; |
||||
} |
||||
|
||||
self::createNavigation(); |
||||
self::setHttpError(); |
||||
|
||||
self::$router->dispatch(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add CRUD routes |
||||
* Example usage: Router::resource('/example', 'CrudController'); |
||||
* |
||||
* @param string $route The URL location |
||||
* @param string $controller Controller to handle this route |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function resource(string $route, string $controller): void |
||||
{ |
||||
/* |
||||
* HTTP Verb Part (URL) Action (Method) |
||||
* |
||||
* GET /route indexAction |
||||
* GET /route/create createAction |
||||
* POST /route storeAction |
||||
* GET /route/{id} showAction |
||||
* GET /route/{id}/edit editAction |
||||
* PUT/PATCH /route/{id} updateAction |
||||
* DELETE /route/{id} destroyAction |
||||
*/ |
||||
|
||||
self::addRoute(['GET'], [$route, $controller, 'indexAction']); |
||||
self::addRoute(['GET'], [$route . '/create', $controller, 'createAction']); |
||||
self::addRoute(['POST'], [$route, $controller, 'storeAction']); |
||||
self::addRoute(['GET'], [$route . '/[i:id]', $controller, 'showAction', ['id']]); |
||||
self::addRoute(['GET'], [$route . '/[i:id]/edit', $controller, 'editAction', ['id']]); |
||||
self::addRoute(['PUT', 'PATCH'], [$route . '/[i:id]', $controller, 'updateAction', ['id']]); |
||||
self::addRoute(['DELETE'], [$route . '/[i:id]', $controller, 'destroyAction', ['id']]); |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
protected static function setDefaultLayout(): void |
||||
{ |
||||
self::$router->respond(function ($request, $response, $service) { |
||||
$service->layout('../app/views/layouts/default.php'); |
||||
}); |
||||
} |
||||
|
||||
protected static function loadConfigRoutes(): void |
||||
{ |
||||
if (file_exists('../route.php')) { |
||||
self::$routes = require_once '../route.php'; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add all pages in the Db to self::$routes |
||||
* |
||||
* @return void |
||||
*/ |
||||
protected static function loadDbRoutes(): void |
||||
{ |
||||
// Load all sections from Db |
||||
$sections = SectionModel::selectAll('*', 'WHERE `active` = 1 ORDER BY `order` ASC'); |
||||
|
||||
// Return if no sections |
||||
if (!_exists($sections)) { |
||||
return; |
||||
} |
||||
|
||||
// Load all pages from Db |
||||
$pages = PageModel::selectAll('DISTINCT page.*', ' |
||||
LEFT JOIN page_has_content ON page_has_content.page_id = page.id |
||||
LEFT JOIN content ON content.id = page_has_content.content_id |
||||
WHERE page.active = 1 AND content.active = 1 |
||||
ORDER BY page.order ASC; |
||||
'); |
||||
|
||||
// Return if no pages |
||||
if (!_exists($pages)) { |
||||
return; |
||||
} |
||||
|
||||
// Select id column |
||||
$section = array_column($sections, 'section', 'id'); |
||||
|
||||
// Loop through all pages |
||||
foreach ($pages as $pageKey => $page) { |
||||
// Skip if section isn't created / active |
||||
if (!_exists($section, $page['section_id'])) { continue; } |
||||
|
||||
// url = /section/page |
||||
$url = '/' . $section[$page['section_id']] . '/' . $page['page']; |
||||
|
||||
// Add route |
||||
self::$routes[] = [$url, 'PageController', 'route', $page['id']]; |
||||
} |
||||
|
||||
// Cache sections and pages |
||||
Db::setSections($sections); |
||||
Db::setPages($pages); |
||||
} |
||||
|
||||
protected static function addRoute(array $method = [], array $data = []): void |
||||
{ |
||||
if (!_exists($method) || !_exists($data)) { |
||||
return; |
||||
} |
||||
|
||||
$route = $data[0] ?? ''; |
||||
$controller = $data[1] ?? ''; |
||||
$action = $data[2] ?? ''; |
||||
$param = $data[3] ?? []; |
||||
if ($route == '' || $controller == '' || $action == '') { |
||||
return; |
||||
} |
||||
|
||||
// Create Klein route |
||||
self::$router->respond($method, $route, function($request, $response, $service) |
||||
use($controller, $action, $param) { |
||||
|
||||
// Create new Controller object |
||||
$controller = '\App\Controllers\\' . $controller; |
||||
$controller = new $controller(self::$router); |
||||
|
||||
$stillValid = true; |
||||
|
||||
// If method does not exist in object |
||||
if (!method_exists($controller, $action)) { |
||||
$stillValid = false; |
||||
} |
||||
|
||||
// If no valid permissions |
||||
if ($controller->getAdminSection() && |
||||
$controller->getLoggedIn() == false) { |
||||
$stillValid = false; |
||||
} |
||||
|
||||
// Call Controller action |
||||
if ($stillValid) { |
||||
|
||||
// Loop through params |
||||
$params = []; |
||||
foreach ($param as $name) { |
||||
$params[] = $request->param($name); |
||||
} |
||||
|
||||
return $controller->{$action}(...$params); |
||||
} |
||||
else { |
||||
$controller->throw404(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
protected static function addBasicRoute(array $method = [], array $route = []): void |
||||
{ |
||||
if (!_exists($method) || !_exists($route)) { |
||||
return; |
||||
} |
||||
|
||||
// Create Klein route |
||||
self::$router->respond($method, $route[0], function() use($route) { |
||||
|
||||
// Create new Controller object |
||||
$controller = '\App\Controllers\\' . $route[1]; |
||||
$controller = new $controller(self::$router); |
||||
|
||||
// Complete action variable |
||||
if ($route[2] == '') { |
||||
$route[2] = 'indexAction'; |
||||
} |
||||
else { |
||||
$route[2] .= 'Action'; |
||||
} |
||||
|
||||
$stillValid = true; |
||||
|
||||
// If method does not exist in object |
||||
if (!method_exists($controller, $route[2])) { |
||||
$stillValid = false; |
||||
} |
||||
|
||||
// If no valid permissions |
||||
if ($controller->getAdminSection() && |
||||
$controller->getLoggedIn() == false) { |
||||
$stillValid = false; |
||||
} |
||||
|
||||
// Call Controller action |
||||
if ($stillValid) { |
||||
if (is_array($route[3])) { |
||||
return $controller->{$route[2]}( |
||||
$route[3][0] ?? '', |
||||
$route[3][1] ?? '', |
||||
$route[3][2] ?? '' |
||||
); |
||||
} |
||||
else if ($route[3] != '') { |
||||
return $controller->{$route[2]}($route[3]); |
||||
} |
||||
else { |
||||
return $controller->{$route[2]}(); |
||||
} |
||||
} |
||||
else { |
||||
$controller->throw404(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public static function createNavigation(): void |
||||
{ |
||||
// Pull from cache |
||||
$sections = Db::getSections(); |
||||
$pages = Db::getPages(); |
||||
|
||||
// [ |
||||
// [ |
||||
// 'section url', |
||||
// 'title', |
||||
// ['page url', 'title'], |
||||
// ['page url', 'titleOfPage2'], |
||||
// ], |
||||
// [], |
||||
// [], |
||||
// ] |
||||
|
||||
$navigation = []; |
||||
|
||||
// Generate sections |
||||
foreach ($sections as $section) { |
||||
// Skip hidden sections |
||||
if ($section['hide_navigation'] == '1') { |
||||
continue; |
||||
} |
||||
|
||||
// Add URL, title to ID |
||||
$navigation[$section['id']] = [ |
||||
$section['section'], $section['title'] |
||||
]; |
||||
} |
||||
|
||||
// Generate pages |
||||
foreach ($pages as $page) { |
||||
// Skip hidden sections |
||||
if (!_exists($navigation, $page['section_id'])) { |
||||
continue; |
||||
} |
||||
|
||||
// Skip hidden pages |
||||
if ($page['hide_navigation'] == '1') { |
||||
continue; |
||||
} |
||||
|
||||
// Add [URL, title] to ID |
||||
$navigation[$page['section_id']][] = [ |
||||
$page['page'], $page['title'] |
||||
]; |
||||
} |
||||
|
||||
self::$router->service()->navigation = $navigation; |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
protected static function setHttpError(): void |
||||
{ |
||||
self::$router->onHttpError(function($code) { |
||||
$service = self::$router->service(); |
||||
|
||||
switch ($code) { |
||||
case 404: |
||||
|
||||
$service->escape = function (?string $string) { |
||||
return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8'); |
||||
}; |
||||
|
||||
self::$router->response()->sendHeaders(true, true); |
||||
$service->pageTitle = 'Error 404 (Not Found)'; |
||||
$service->render('../app/views/errors/404.php'); |
||||
break; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public static function getRoutes(): array |
||||
{ |
||||
return self::$routes; |
||||
} |
||||
|
||||
} |
||||
|
||||
Router::_init(); |
||||
|
||||
// @Todo |
||||
// - combine addRoute and addBasicroute functionality |
@ -0,0 +1,300 @@
|
||||
<?php |
||||
|
||||
namespace App\Classes; |
||||
|
||||
use stdClass; |
||||
|
||||
class Session { |
||||
|
||||
/** |
||||
* The session attributes. |
||||
* |
||||
* @var array |
||||
*/ |
||||
private static $attributes; |
||||
|
||||
/** |
||||
* Session store started status. |
||||
* |
||||
* @var bool |
||||
*/ |
||||
protected static $started = false; |
||||
|
||||
//-------------------------------------// |
||||
|
||||
/** |
||||
* Start the PHP session |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function start(): void |
||||
{ |
||||
if (self::$started) { |
||||
return; |
||||
} |
||||
|
||||
session_set_cookie_params(['secure' => true, 'httponly' => true, 'samesite' => 'Strict']); |
||||
session_start(); |
||||
|
||||
self::$attributes = &$_SESSION; |
||||
|
||||
if (!self::exists('_token')) { |
||||
self::regenerateToken(); |
||||
} |
||||
|
||||
self::$started = true; |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
/** |
||||
* Get all of the session data. |
||||
* |
||||
* @return array |
||||
*/ |
||||
public static function all(): array |
||||
{ |
||||
return self::$attributes; |
||||
} |
||||
|
||||
/** |
||||
* Checks if a key exists. |
||||
* |
||||
* @param string|array $key |
||||
* |
||||
* @return bool |
||||
*/ |
||||
public static function isset($key): bool |
||||
{ |
||||
$placeholder = new stdClass; |
||||
return self::get($key, $placeholder) !== $placeholder; |
||||
} |
||||
|
||||
/** |
||||
* Check if a key is present and not null. |
||||
* |
||||
* @param string|array $key |
||||
* |
||||
* @return bool |
||||
*/ |
||||
public static function exists($key): bool |
||||
{ |
||||
return !is_null(self::get($key)); |
||||
} |
||||
|
||||
/** |
||||
* Get an item from the session. |
||||
* |
||||
* @param string $key |
||||
* @param mixed $default |
||||
* |
||||
* @return mixed |
||||
*/ |
||||
public static function get(string $key, $default = null) |
||||
{ |
||||
if (array_key_exists($key, self::$attributes)) { |
||||
return self::$attributes[$key]; |
||||
} |
||||
|
||||
if (strpos($key, '.') === false) { |
||||
return $default; |
||||
} |
||||
|
||||
// Get item using the "dot" notation |
||||
$array = self::$attributes; |
||||
foreach (explode('.', $key) as $segment) { |
||||
if (is_array($array) && array_key_exists($segment, $array)) { |
||||
$array = $array[$segment]; |
||||
} |
||||
else { |
||||
return $default; |
||||
} |
||||
} |
||||
|
||||
return $array; |
||||
} |
||||
|
||||
/** |
||||
* Put a key / value pair or array of key / value pairs in the session. |
||||
* |
||||
* @param string|array $key |
||||
* @param mixed $value |
||||
* @return void |
||||
*/ |
||||
public static function put($key, $value = null) |
||||
{ |
||||
if (!is_array($key)) { |
||||
$key = [$key => $value]; |
||||
} |
||||
|
||||
foreach ($key as $arrayKey => $arrayValue) { |
||||
|
||||
// Set array item to a given value using the "dot" notation |
||||
|
||||
$keys = explode('.', $arrayKey); |
||||
|
||||
$array = &self::$attributes; |
||||
foreach ($keys as $i => $key) { |
||||
if (count($keys) === 1) { |
||||
break; |
||||
} |
||||
|
||||
unset($keys[$i]); |
||||
|
||||
// If key doesnt exist at this depth, create empty array holder |
||||
if (!isset($array[$key]) || !is_array($array[$key])) { |
||||
$array[$key] = []; |
||||
} |
||||
|
||||
$array = &$array[$key]; |
||||
} |
||||
|
||||
$array[array_shift($keys)] = $arrayValue; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Get an item from the session, or store the default value. |
||||
* |
||||
* @param string $key |
||||
* |
||||
* @return mixed |
||||
*/ |
||||
public static function emplace(string $key) |
||||
{ |
||||
$value = self::get($key); |
||||
if (!is_null($value)) { |
||||
return $value; |
||||
} |
||||
|
||||
self::put($key, $value); |
||||
return $value; |
||||
} |
||||
|
||||
/** |
||||
* Push a value onto a session array. |
||||
* |
||||
* @param string $key |
||||
* @param mixed $value |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function push(string $key, $value): void |
||||
{ |
||||
$array = self::get($key, []); |
||||
$array[] = $value; |
||||
self::put($key, $array); |
||||
} |
||||
|
||||
/** |
||||
* Get the value of a given key and then remove it. |
||||
* |
||||
* @param string $keys |
||||
* |
||||
* @return mixed |
||||
*/ |
||||
public static function pull(string $key, $default = null) |
||||
{ |
||||
$result = self::get($key, $default); |
||||
self::delete($key); |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
/** |
||||
* Delete one or many items from the session. |
||||
* |
||||
* @param string|array $keys |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function delete($keys): void |
||||
{ |
||||
$start = &self::$attributes; |
||||
|
||||
$keys = (array)$keys; |
||||
|
||||
if (count($keys) === 0) { |
||||
return; |
||||
} |
||||
|
||||
foreach ($keys as $key) { |
||||
// Delete top-level if non-"dot" notation key |
||||
if (self::exists($key)) { |
||||
unset(self::$attributes[$key]); |
||||
|
||||
continue; |
||||
} |
||||
|
||||
// Delete using "dot" notation key |
||||
|
||||
$parts = explode('.', $key); |
||||
|
||||
// Move to the start of the array each pass |
||||
$array = &$start; |
||||
|
||||
// Traverse into the associative array |
||||
while (count($parts) > 1) { |
||||
$part = array_shift($parts); |
||||
|
||||
if (isset($array[$part]) && is_array($array[$part])) { |
||||
$array = &$array[$part]; |
||||
} |
||||
else { |
||||
continue 2; |
||||
} |
||||
} |
||||
|
||||
unset($array[array_shift($parts)]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Remove all of the items from the session. |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function flush(): void |
||||
{ |
||||
self::$attributes = []; |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
/** |
||||
* Get the CSRF token value. |
||||
* |
||||
* @return string |
||||
*/ |
||||
public static function token() |
||||
{ |
||||
return self::get('_token'); |
||||
} |
||||
|
||||
/** |
||||
* Regenerate the CSRF token value. |
||||
* |
||||
* @return void |
||||
*/ |
||||
public static function regenerateToken() |
||||
{ |
||||
self::put('_token', _randomStr(40)); |
||||
} |
||||
|
||||
/** |
||||
* Validate the CSRF token value to the given value. |
||||
* |
||||
* @param array $array |
||||
* |
||||
* @return bool |
||||
*/ |
||||
public static function validateToken(array $array = null): bool |
||||
{ |
||||
if (is_array($array) && array_key_exists('_token', $array) && $array['_token'] == self::token()) { |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,174 @@
|
||||
<?php |
||||
|
||||
namespace App\Classes; |
||||
|
||||
use App\Model\UserModel; |
||||
|
||||
class User { |
||||
|
||||
public static function check(): bool |
||||
{ |
||||
$success = false; |
||||
|
||||
// Session |
||||
if (Session::exists('user')) { |
||||
$success = true; |
||||
} |
||||
|
||||
// If cookie is set, try to login |
||||
if (!$success && |
||||
_exists($_COOKIE, 'id') && |
||||
_exists($_COOKIE, 'username') && |
||||
_exists($_COOKIE, 'salt') && |
||||
_exists($_COOKIE, 'toggle')) { |
||||
|
||||
$user = UserModel::find($_COOKIE['id']); |
||||
|
||||
if ($user->exists() && |
||||
$_COOKIE['username'] == $user->username && |
||||
$_COOKIE['salt'] == $user->salt) { |
||||
$success = true; |
||||
|
||||
self::setSession($_COOKIE['id'], $_COOKIE['username'], |
||||
$_COOKIE['salt'], $_COOKIE['toggle']); |
||||
} |
||||
} |
||||
|
||||
return $success; |
||||
} |
||||
|
||||
public static function login(string $username, string $password, string $rememberMe): bool |
||||
{ |
||||
$user = UserModel::search(['username' => $username]); |
||||
|
||||
$success = false; |
||||
if ($user->exists() && $user->failed_login_attempt <= 2) { |
||||
$saltPassword = $user->salt . $password; |
||||
if (password_verify($saltPassword, $user->password)) { |
||||
$success = true; |
||||
|
||||
// On successful login, set failed_login_attempt to 0 |
||||
if ($user->failed_login_attempt > 0) { |
||||
$user->failed_login_attempt = 0; |
||||
$user->save(); |
||||
} |
||||
} |
||||
else { |
||||
$user->failed_login_attempt++; |
||||
$user->save(); |
||||
} |
||||
} |
||||
|
||||
if (!$success) { |
||||
self::logout(); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
// Set session |
||||
self::setSession($user->id, $user->username, $user->salt, 1); |
||||
|
||||
// Set cookie |
||||
if ($rememberMe == '1') { |
||||
$time = time() + (3600 * 24 * 7); |
||||
self::setCookie($time, $user->id, $user->username, $user->salt, 1); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public static function logout(): void |
||||
{ |
||||
Session::delete('user'); |
||||
|
||||
// Destroy user login cookie |
||||
$time = time() - 3600; |
||||
self::setCookie($time, 0, '', '', 0); |
||||
} |
||||
|
||||
public static function getUser(string $id = '', string $username = '', string $email = ''): UserModel |
||||
{ |
||||
if ($id == '' && $username == '' && $email == '' && self::check()) { |
||||
$id = Session::get('user.id'); |
||||
$username = Session::get('user.username'); |
||||
} |
||||
|
||||
return UserModel::search([ |
||||
'id' => $id, |
||||
'username' => $username, |
||||
'email' => $email, |
||||
], 'OR'); |
||||
} |
||||
|
||||
public static function toggle(): void |
||||
{ |
||||
if (self::check()) { |
||||
// Toggle session |
||||
Session::put('user.toggle', !Session::get('user.toggle')); |
||||
// Toggle cookie |
||||
self::setCookieToggle(Session::get('user.toggle')); |
||||
} |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
protected static function setSession( |
||||
int $id, string $username, string $salt, int $toggle): void |
||||
{ |
||||
Session::put('user', [ |
||||
'id' => $id, |
||||
'username' => $username, |
||||
'salt' => $salt, |
||||
'toggle' => $toggle, |
||||
]); |
||||
} |
||||
|
||||
protected static function setCookie( |
||||
int $time, int $id, string $username, string $salt, int $toggle): void |
||||
{ |
||||
if (_exists($_SERVER, 'HTTPS') && $_SERVER['HTTPS'] == 'on') { |
||||
$domain = Config::c('APP_NAME'); |
||||
$options = [ |
||||
'expires' => $time, |
||||
'path' => '/', |
||||
'domain' => $domain, |
||||
'secure' => true, |
||||
'httponly' => true, |
||||
'samesite' => 'Strict' |
||||
]; |
||||
setcookie('id', $id, $options); |
||||
setcookie('username', $username, $options); |
||||
setcookie('salt', $salt, $options); |
||||
setcookie('toggle', $toggle, $options); |
||||
} |
||||
} |
||||
|
||||
protected static function setCookieToggle(int $toggle): void |
||||
{ |
||||
if (_exists($_SERVER, 'HTTPS') && $_SERVER['HTTPS'] == 'on') { |
||||
$domain = Config::c('APP_NAME'); |
||||
$options = [ |
||||
'expires' => time() + (3600 * 24 * 7), |
||||
'path' => '/', |
||||
'domain' => $domain, |
||||
'secure' => true, |
||||
'httponly' => true, |
||||
'samesite' => 'Strict' |
||||
]; |
||||
setcookie('toggle', $toggle, $options); |
||||
} |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public static function getToggle(): int |
||||
{ |
||||
return self::check() ? Session::get('user.toggle') : 0; |
||||
} |
||||
|
||||
public static function getSession(): array |
||||
{ |
||||
return self::check() ? Session::get('user') : []; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,24 @@
|
||||
<?php |
||||
|
||||
namespace App\Controllers; |
||||
|
||||
use App\Classes\User; |
||||
|
||||
class AdminController extends PageController { |
||||
|
||||
public function indexAction(): void { |
||||
$this->router->service()->user = User::getUser(); |
||||
|
||||
parent::view('', 'Admin'); |
||||
} |
||||
|
||||
public function toggleAction(): void { |
||||
User::toggle(); |
||||
echo User::getToggle() ? '1' : '0'; |
||||
} |
||||
|
||||
public function syntaxAction(): void { |
||||
parent::view(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,133 @@
|
||||
<?php |
||||
|
||||
namespace App\Controllers; |
||||
|
||||
use App\Classes\Config; |
||||
use App\Classes\Db; |
||||
use App\Classes\Session; |
||||
use App\Classes\User; |
||||
|
||||
class BaseController { |
||||
|
||||
protected $router; |
||||
protected $section; |
||||
protected $page; |
||||
protected $loggedIn; |
||||
protected $url; |
||||
protected $adminSection; |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public function __construct(\Klein\Klein $router = null) |
||||
{ |
||||
$this->router = $router; |
||||
|
||||
$request = $this->router->request()->uri(); |
||||
$request = parse_url($request)['path']; |
||||
$request = explode("/", $request); |
||||
|
||||
if (array_key_exists(1, $request)) { |
||||
$this->section = $request[1]; |
||||
} |
||||
if (array_key_exists(2, $request)) { |
||||
$this->page = $request[2]; |
||||
} |
||||
|
||||
// Set login status |
||||
$this->loggedIn = User::check(); |
||||
$this->router->service()->loggedIn = $this->loggedIn; |
||||
|
||||
// Set url https://site.com/section/page |
||||
$this->url = Config::c('APP_URL'); |
||||
$this->url .= _exists([$this->section]) ? '/' . $this->section : ''; |
||||
$this->url .= _exists([$this->page]) ? '/' . $this->page : ''; |
||||
$this->router->service()->url = $this->url; |
||||
|
||||
// If Admin section |
||||
$this->adminSection = $this->section == 'admin'; |
||||
$this->router->service()->adminSection = $this->adminSection; |
||||
|
||||
// Clear alert |
||||
$this->setAlert('', ''); |
||||
// Load alert set on the previous page |
||||
$this->loadAlert(); |
||||
|
||||
// View helper method |
||||
$this->router->service()->escape = function (?string $string) { |
||||
return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8'); |
||||
}; |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public function throw404(): void |
||||
{ |
||||
$this->router->response()->sendHeaders(true, true); |
||||
$service = $this->router->service(); |
||||
$service->pageTitle = 'Error 404 (Not Found)'; |
||||
$service->render('../app/views/errors/404.php'); |
||||
exit(); |
||||
} |
||||
|
||||
/** |
||||
* Set alert for the current page |
||||
* |
||||
* @param string $type Color of the message (success/danger/warning/info) |
||||
* @param string $message The message to display |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function setAlert(string $type, string $message): void |
||||
{ |
||||
$this->router->service()->type = $type; |
||||
$this->router->service()->message = $message; |
||||
} |
||||
|
||||
/** |
||||
* Set alert for the next page |
||||
* |
||||
* @param string $type Color of the message (success/danger/warning/info) |
||||
* @param string $message The message to display |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function setAlertNext(string $type, string $message): void |
||||
{ |
||||
Session::put('type', $type); |
||||
Session::put('message', $message); |
||||
} |
||||
|
||||
/** |
||||
* Load alert set on the previous page |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function loadAlert(): void |
||||
{ |
||||
if (Session::exists('type') && Session::exists('message')) { |
||||
$this->setAlert(Session::get('type'), Session::get('message')); |
||||
Session::delete(['type', 'message']); |
||||
} |
||||
} |
||||
|
||||
//-------------------------------------// |
||||
|
||||
public function getSection(): string |
||||
{ |
||||
return $this->section; |
||||
} |
||||