Initial commit
Couldnt keep the history unfortunately.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
public function getLoggedIn(): bool
|
||||
{
|
||||
return $this->loggedIn;
|
||||
}
|
||||
|
||||
public function getAdminSection(): bool
|
||||
{
|
||||
return $this->adminSection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @Todo
|
||||
// - Image lazy loading
|
||||
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Classes\Session;
|
||||
|
||||
class CrudController extends PageController {
|
||||
|
||||
public static $pagination = 10;
|
||||
|
||||
//-------------------------------------//
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction(): void
|
||||
{
|
||||
$modelName = $this->getModelName();
|
||||
$model = "\App\Model\\{$modelName}Model";
|
||||
$model = new $model;
|
||||
|
||||
// ?page=x
|
||||
$page = 1;
|
||||
if (_exists($_GET, 'page') && is_numeric($_GET['page'])) {
|
||||
$page = $_GET['page'];
|
||||
}
|
||||
|
||||
$rows = $model->all($page, self::$pagination);
|
||||
|
||||
// Set empty value
|
||||
if (!_exists($rows)) {
|
||||
$rows = [];
|
||||
}
|
||||
|
||||
$this->router->service()->attributes = $model->getAttributesRules();
|
||||
$this->router->service()->csrfToken = Session::token();
|
||||
$this->router->service()->rows = $rows;
|
||||
$this->router->service()->title = $modelName;
|
||||
|
||||
// Set page variables
|
||||
$this->router->service()->page = $page;
|
||||
$pages = ceil($model->count() / self::$pagination);
|
||||
$pages > 1
|
||||
? $this->router->service()->pages = $pages
|
||||
: $this->router->service()->pages = 1;
|
||||
|
||||
parent::view("{$this->section}/crud/index");
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createAction(): void
|
||||
{
|
||||
$model = "\App\Model\\{$this->getModelName()}Model";
|
||||
$model = new $model;
|
||||
|
||||
$attributes = $model->getAttributesRules();
|
||||
|
||||
// Get dropdown data
|
||||
$dropdownData = [];
|
||||
foreach ($attributes as $key => $attribute) {
|
||||
if ($attribute[1] == 'dropdown') {
|
||||
$dropdownData[$key] = $model->getDropdownData($attribute[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->router->service()->attributes = $attributes;
|
||||
$this->router->service()->csrfToken = Session::token();
|
||||
$this->router->service()->dropdownData = $dropdownData;
|
||||
parent::view("{$this->section}/crud/create");
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function storeAction(): void
|
||||
{
|
||||
$modelName = $this->getModelName();
|
||||
$model = "\App\Model\\{$modelName}Model";
|
||||
$model = new $model;
|
||||
|
||||
$token = Session::validateToken($_POST);
|
||||
|
||||
$token && $model->fill($_POST) && $model->save()
|
||||
? $this->setAlertNext('success', "$modelName successfully created.")
|
||||
: $this->setAlertNext('danger', "$modelName could not be created!");
|
||||
|
||||
$this->router->response()->redirect($this->url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function showAction(int $id): void
|
||||
{
|
||||
$model = "\App\Model\\{$this->getModelName()}Model";
|
||||
$model = $model::find($id);
|
||||
|
||||
if (!$model->exists()) {
|
||||
parent::throw404();
|
||||
}
|
||||
|
||||
$this->router->service()->model = $model;
|
||||
$this->router->service()->attributes = $model->getAttributesRules();
|
||||
parent::view("{$this->section}/crud/show");
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function editAction(int $id): void
|
||||
{
|
||||
$model = "\App\Model\\{$this->getModelName()}Model";
|
||||
$model = $model::find($id);
|
||||
|
||||
if (!$model->exists()) {
|
||||
parent::throw404();
|
||||
}
|
||||
|
||||
$attributes = $model->getAttributesRules();
|
||||
|
||||
// Get dropdown data
|
||||
$dropdownData = [];
|
||||
foreach ($attributes as $key => $attribute) {
|
||||
if ($attribute[1] == 'dropdown') {
|
||||
$dropdownData[$key] = $model->getDropdownData($attribute[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->router->service()->attributes = $attributes;
|
||||
$this->router->service()->csrfToken = Session::token();
|
||||
$this->router->service()->dropdownData = $dropdownData;
|
||||
$this->router->service()->model = $model;
|
||||
parent::view("{$this->section}/crud/edit");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateAction(int $id): void
|
||||
{
|
||||
$modelName = $this->getModelName();
|
||||
$model = "\App\Model\\{$modelName}Model";
|
||||
$model = $model::find($id);
|
||||
|
||||
if (!$model->exists()) {
|
||||
$this->setAlertNext('danger', "$modelName does not exist!");
|
||||
}
|
||||
else {
|
||||
// Read PUT request
|
||||
$this->parsePhpInput($_PUT);
|
||||
|
||||
$token = Session::validateToken($_PUT);
|
||||
|
||||
$token && $model->fill($_PUT) && $model->save()
|
||||
? $this->setAlertNext('success', "$modelName successfully updated.")
|
||||
: $this->setAlertNext('danger', "$modelName could not be updated!");
|
||||
}
|
||||
|
||||
echo $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function destroyAction(int $id): void
|
||||
{
|
||||
// Read DELETE request
|
||||
$this->parsePhpInput($_DELETE);
|
||||
|
||||
$token = Session::validateToken($_DELETE);
|
||||
|
||||
$modelName = $this->getModelName();
|
||||
$model = "\App\Model\\{$modelName}Model";
|
||||
|
||||
$token && $model::destroy($id)
|
||||
? $this->setAlertNext('success', "$modelName successfully deleted.")
|
||||
: $this->setAlertNext('danger', "$modelName could not be deleted!");
|
||||
}
|
||||
|
||||
//-------------------------------------//
|
||||
|
||||
/**
|
||||
* Generate the model name from the /section/page url
|
||||
*
|
||||
* @return string The model name
|
||||
*/
|
||||
private function getModelName(): string
|
||||
{
|
||||
$model = $this->page;
|
||||
$model = str_replace('-', ' ', $model);
|
||||
$model = str_replace('_', ' ', $model);
|
||||
$model = ucwords($model);
|
||||
$model = str_replace(' ', '', $model);
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT/DELETE requests aren't handled by PHP automatically yet.
|
||||
* Parse them from php://input instead.
|
||||
*
|
||||
* @param ?array &$result Array filled with input data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function parsePhpInput(?array &$result): void
|
||||
{
|
||||
// Parse json or form-encoded formatted data
|
||||
if (strpos($_SERVER['CONTENT_TYPE'], "application/json") !== false) {
|
||||
$result = json_decode(file_get_contents("php://input"), true);
|
||||
}
|
||||
else if (strpos($_SERVER['CONTENT_TYPE'], "application/x-www-form-urlencoded") !== false) {
|
||||
parse_str(file_get_contents("php://input"), $result);
|
||||
|
||||
// Cleanup & HTML entities
|
||||
foreach ($result as $key => $value) {
|
||||
unset($result[$key]);
|
||||
$result[str_replace('amp;', '', $key)] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$_REQUEST = array_merge($_REQUEST, $result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Classes\Config;
|
||||
use App\Classes\Db;
|
||||
use App\Classes\Router;
|
||||
use App\Classes\Session;
|
||||
|
||||
class IndexController extends PageController {
|
||||
|
||||
public function indexAction(): void
|
||||
{
|
||||
// Pull pages from cache
|
||||
$pages = Db::getPages();
|
||||
|
||||
parent::routeAction(
|
||||
array_search('home', array_column($pages, 'page', 'id')));
|
||||
}
|
||||
|
||||
public function captchaAction(): void
|
||||
{
|
||||
header('Content-type: image/jpeg');
|
||||
|
||||
if (!Session::exists('captcha')) {
|
||||
Session::put('captcha', _randomStr(4, '0123456789'));
|
||||
}
|
||||
|
||||
$imageWidth = 151;
|
||||
$imageHeight = 51;
|
||||
|
||||
// Text
|
||||
$textSize = 30;
|
||||
$textFont = 'fonts/captcha.otf';
|
||||
$text = Session::get('captcha');
|
||||
|
||||
// Generate position
|
||||
$randPosX = rand(0, 40);
|
||||
$randPosY = rand(35, 45);
|
||||
|
||||
// Calculate rotation from the position
|
||||
$rotationFactorUp = 1.0 - (($randPosY - 40.0) / 5.0);
|
||||
$rotationFactorDown = 1.0 - ((40.0 - $randPosY) / 5.0);
|
||||
// Clamp between 0.0-1.0
|
||||
$rotationFactorUp = max(0.0, min(1.0, $rotationFactorUp));
|
||||
$rotationFactorDown = max(0.0, min(1.0, $rotationFactorDown));
|
||||
$rotation = rand(-8 * $rotationFactorUp, 8 * $rotationFactorDown);
|
||||
|
||||
// Create image
|
||||
$image = imagecreate($imageWidth, $imageHeight);
|
||||
imagecolorallocate($image, 255, 255, 255);
|
||||
|
||||
// Render number
|
||||
$textColor = imagecolorallocate($image, 0, 0, 0);
|
||||
imagettftext($image, $textSize, $rotation, $randPosX, $randPosY,
|
||||
$textColor, $textFont, $text);
|
||||
|
||||
// Render grid pattern
|
||||
$lineColor = imagecolorallocate($image, 73, 106, 164);
|
||||
$cord = 0;
|
||||
for ($i = 1; $i <= 31; $i++) {
|
||||
imageline($image, $cord, 0, $cord, 50, $lineColor);
|
||||
imageline($image, 0, $cord, 150, $cord, $lineColor);
|
||||
$cord = $cord + 5;
|
||||
}
|
||||
|
||||
imagejpeg($image);
|
||||
exit();
|
||||
}
|
||||
|
||||
public function sitemapAction(): void
|
||||
{
|
||||
$xml = new \SimpleXMLElement('<urlset/>');
|
||||
|
||||
// Config routes
|
||||
$routes = array_column(Router::getRoutes(), '0');
|
||||
|
||||
// Remove /admin and /test pages
|
||||
foreach ($routes as $key => $route) {
|
||||
if (strpos($route, '/admin') !== false ||
|
||||
strpos($route, '/test') !== false) {
|
||||
|
||||
unset($routes[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($routes as $route) {
|
||||
$url = $xml->addChild('url');
|
||||
$loc = Config::c('APP_URL') . $route;
|
||||
|
||||
$url->addChild('loc', $loc);
|
||||
}
|
||||
|
||||
Header('Content-type: text/xml');
|
||||
print($xml->asXML());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Classes\Config;
|
||||
use App\Classes\Db;
|
||||
use App\Classes\Form;
|
||||
use App\Classes\User;
|
||||
use App\Classes\Mail;
|
||||
|
||||
class LoginController extends PageController {
|
||||
|
||||
public function loginAction(string $view, string $title): void {
|
||||
$form = new Form($this->router);
|
||||
$form->addField('username', [
|
||||
'Username*',
|
||||
'text',
|
||||
'',
|
||||
'required',
|
||||
'Username is required.',
|
||||
]);
|
||||
$form->addField('password', [
|
||||
'Password*',
|
||||
'password',
|
||||
'',
|
||||
'required',
|
||||
'Password is required.',
|
||||
]);
|
||||
$form->addField('rememberMe', [
|
||||
'',
|
||||
'checkbox',
|
||||
['1' => 'Remember me'],
|
||||
]);
|
||||
|
||||
$form->setSubmit('Sign in');
|
||||
|
||||
if ($form->validated()) {
|
||||
if (User::login($_POST['username'], $_POST['password'], $_POST['rememberMe'])) {
|
||||
$this->setAlert('success', 'Successfully signed in, redirecting...');
|
||||
|
||||
// Set delayed redirect URL
|
||||
$this->router->service()->redirectURL = Config::c('APP_URL') . '/admin';
|
||||
}
|
||||
else {
|
||||
$user = User::getUser('', $_POST['username']);
|
||||
if ($user->exists() && $user->failed_login_attempt >= 5) {
|
||||
$this->setAlert('danger', 'User has been blocked.');
|
||||
}
|
||||
else {
|
||||
$this->setAlert('danger', 'Invalid username and password combination.');
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if(!_exists($_POST, 'username') || !_exists($_POST, 'password')) {
|
||||
$this->setAlert('danger', 'Please fill out both fields.');
|
||||
}
|
||||
else {
|
||||
$this->setAlert('danger', 'Could not sign in.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->router->service()->password = "";
|
||||
parent::view($view, $title);
|
||||
}
|
||||
|
||||
public function resetAction(string $view, string $title): void {
|
||||
|
||||
// Send request
|
||||
if (!_exists($_GET, 'uid') || !_exists($_GET, 'reset-key')) {
|
||||
$this->requestResetForm();
|
||||
}
|
||||
// Reset password
|
||||
else {
|
||||
$this->resetPasswordForm();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
|
||||
$this->router->service()->newPassword = true;
|
||||
$user = User::getUser($_GET['uid']);
|
||||
if (!$user->exists() || $_GET['reset-key'] != $user->reset_key) {
|
||||
$this->setAlert('danger', 'Link expired.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::view($view, $title);
|
||||
}
|
||||
|
||||
public function logoutAction(): void {
|
||||
User::logout();
|
||||
|
||||
$this->router->response()->redirect('/');
|
||||
}
|
||||
|
||||
//-------------------------------------//
|
||||
|
||||
private function requestResetForm(): void {
|
||||
// Only have required on 1 field
|
||||
$usernameRule = !_exists($_POST, 'reset-password-email') ? 'required' : '';
|
||||
$emailRule = !_exists($_POST, 'reset-password-username') ? 'required|email' : '';
|
||||
|
||||
$form = new Form($this->router);
|
||||
$form->addField('reset-password-username', [
|
||||
'Username',
|
||||
'text',
|
||||
'',
|
||||
"$usernameRule",
|
||||
'Username is required.',
|
||||
]);
|
||||
$form->addField('reset-password-email', [
|
||||
'Email',
|
||||
'email',
|
||||
'',
|
||||
"$emailRule",
|
||||
'Please enter a valid email address.',
|
||||
'[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$',
|
||||
'Valid email address'
|
||||
]);
|
||||
|
||||
$form->setSubmit('Send request');
|
||||
|
||||
if ($form->validated()) {
|
||||
$this->requestResetSend();
|
||||
}
|
||||
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if (!_exists($_POST, 'reset-password-username') &&
|
||||
!_exists($_POST, 'reset-password-email')) {
|
||||
$this->setAlert('danger', 'Please fill out one of the fields.');
|
||||
}
|
||||
else {
|
||||
$error = $form->errorMessage();
|
||||
$this->setAlert('danger', $error ? $error : 'Could not send request.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function requestResetSend(): void {
|
||||
$user = User::getUser('', $_POST['reset-password-username'], $_POST['reset-password-email']);
|
||||
if ($user->exists()) {
|
||||
|
||||
// Generate new reset key
|
||||
$user->reset_key = _randomStr(25);
|
||||
$user->save();
|
||||
|
||||
// Send reset mail
|
||||
$subject = 'Password reset request - ' . Config::c('APP_NAME');
|
||||
|
||||
$resetUrl = Config::c('APP_URL') . "/reset-password?uid={$user->id}&reset-key={$user->reset_key}";
|
||||
$message = "
|
||||
Click the link below to reset your password:<br>
|
||||
<a href='$resetUrl'>$resetUrl</a>
|
||||
";
|
||||
|
||||
if (Mail::send($subject, $message, $user->email)) {
|
||||
$this->setAlert('success', 'Successfully requested password reset.');
|
||||
}
|
||||
else {
|
||||
$this->setAlert('danger', 'Password reset failed.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->setAlert('danger', 'User was not found.');
|
||||
}
|
||||
}
|
||||
|
||||
private function resetPasswordForm(): void {
|
||||
// Add _GETs to form post url
|
||||
$uid = $_GET['uid'];
|
||||
$resetKey = $_GET['reset-key'];
|
||||
$this->router->service()->url .= "?uid=$uid&reset-key=$resetKey";
|
||||
|
||||
$form = new Form($this->router);
|
||||
$form->addField('password', [
|
||||
'New password*',
|
||||
'password',
|
||||
'',
|
||||
'required',
|
||||
'New password is required.',
|
||||
]);
|
||||
$form->addField('password-again', [
|
||||
'New password again*',
|
||||
'password',
|
||||
'',
|
||||
'required',
|
||||
'New password again is required.',
|
||||
]);
|
||||
|
||||
$form->setSubmit('Reset password');
|
||||
|
||||
if ($form->validated()) {
|
||||
$this->resetPasswordSend();
|
||||
}
|
||||
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if (!_exists($_POST, 'password') ||
|
||||
!_exists($_POST, 'password-again')) {
|
||||
$this->setAlert('danger', 'Please fill out all fields.');
|
||||
}
|
||||
else {
|
||||
$error = $form->errorMessage();
|
||||
$this->setAlert('danger', $error ? $error : 'Could not reset password.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function resetPasswordSend(): void
|
||||
{
|
||||
$user = User::getUser($_GET['uid']);
|
||||
if ($user->exists()) {
|
||||
(bool)$notEmptyKey = $user->reset_key != '';
|
||||
(bool)$correctKey = $user->reset_key == $_GET['reset-key'];
|
||||
(bool)$identicalPass = $_POST['password'] == $_POST['password-again'];
|
||||
}
|
||||
if ($notEmptyKey && $correctKey && $identicalPass) {
|
||||
|
||||
$user->salt = _randomStr(15);
|
||||
$user->password = password_hash($user->salt . $_POST['password'], PASSWORD_BCRYPT, ['cost', 12]);
|
||||
$user->reset_key = '';
|
||||
$user->save();
|
||||
|
||||
$this->setAlert('success', 'Successfully changed password.');
|
||||
}
|
||||
|
||||
// Display error message
|
||||
if (!$user || !$notEmptyKey || !$correctKey) {
|
||||
$this->setAlert('danger', 'Invalid password reset link.');
|
||||
}
|
||||
else if (!$identicalPass) {
|
||||
$this->setAlert('danger', 'Fields did not match.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Classes\Config;
|
||||
use App\Classes\Media;
|
||||
|
||||
use App\Model\LogModel;
|
||||
use App\Model\MediaModel;
|
||||
use App\Model\UserModel;
|
||||
|
||||
class MediaController extends PageController {
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function indexAction(): void
|
||||
{
|
||||
$this->mediaPage();
|
||||
parent::view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function storeAction(): void
|
||||
{
|
||||
$name = ucfirst($this->page);
|
||||
|
||||
$overwrite = _exists($_POST, 'overwrite');
|
||||
|
||||
$error = Media::uploadMedia($overwrite);
|
||||
if (!$error) {
|
||||
$this->setAlert('success', "$name successfully created.");
|
||||
}
|
||||
else {
|
||||
$this->setAlert('danger', Media::errorMessage($error));
|
||||
}
|
||||
|
||||
$this->mediaPage();
|
||||
parent::view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function destroyAction(int $id): void
|
||||
{
|
||||
$name = ucfirst($this->page);
|
||||
|
||||
if (Media::deleteMedia($id)) {
|
||||
$this->setAlertNext('success', "$name successfully deleted.");
|
||||
}
|
||||
else {
|
||||
$this->setAlertNext('danger', "$name could not be deleted!");
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------//
|
||||
|
||||
protected function mediaPage(): void {
|
||||
// ?page=x
|
||||
$page = 1;
|
||||
if (_exists($_GET, 'page') && is_numeric($_GET['page'])) {
|
||||
$page = $_GET['page'];
|
||||
}
|
||||
|
||||
$mediaModel = new MediaModel;
|
||||
|
||||
// Get all Media of the page
|
||||
$media = $mediaModel->all($page, Media::$pagination);
|
||||
|
||||
// Get all the connected Logs
|
||||
$log = null;
|
||||
if (_exists($media)) {
|
||||
$logId = array_column($media, 'log_id');
|
||||
$log = LogModel::findAll($logId);
|
||||
}
|
||||
|
||||
// Get all the connected Users
|
||||
$user = null;
|
||||
if (_exists($log)) {
|
||||
$uploaderId = array_column($log, 'user_id');
|
||||
$user = UserModel::findAll($uploaderId);
|
||||
}
|
||||
|
||||
// Set empty values
|
||||
if (!_exists($media) || !_exists($log) || !_exists($user)) {
|
||||
$media = [];
|
||||
$log = [["user_id" => "0"]];
|
||||
$user = [["username" => "Could not load users.."]];
|
||||
}
|
||||
|
||||
// Set view Media variables
|
||||
$this->router->service()->media = $media;
|
||||
$this->router->service()->log = $log;
|
||||
$this->router->service()->user = $user;
|
||||
|
||||
// Set view Page variables
|
||||
$this->router->service()->page = $page;
|
||||
$pages = ceil($mediaModel->count() / Media::$pagination);
|
||||
$pages > 1
|
||||
? $this->router->service()->pages = $pages
|
||||
: $this->router->service()->pages = 1;
|
||||
|
||||
$this->router->service()->fileUrl = Config::c('APP_URL') . '/' . Media::$directory . '/';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Classes\Db;
|
||||
use App\Model\Model;
|
||||
use App\Model\ContentModel;
|
||||
use App\Model\PageHasContentModel;
|
||||
use App\Model\SectionHasContentModel;
|
||||
|
||||
class PageController extends BaseController {
|
||||
|
||||
/**
|
||||
* Path of the page view files.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $views = '../app/views/';
|
||||
|
||||
//-------------------------------------//
|
||||
|
||||
/**
|
||||
* Create a new page controller instance.
|
||||
*
|
||||
* @param Klein $router
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(\Klein\Klein $router = null)
|
||||
{
|
||||
parent::__construct($router);
|
||||
}
|
||||
|
||||
//-------------------------------------//
|
||||
|
||||
/**
|
||||
* Handle page request with Db stored content.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function routeAction(int $id): void
|
||||
{
|
||||
// Pull pages from cache
|
||||
$pages = Db::getPages();
|
||||
$page = array_search($id, array_column($pages, 'id'));
|
||||
$page = $pages[$page];
|
||||
|
||||
$title = $page['title'] ?? '';
|
||||
$metaDescription = $page['meta_description'] ?? '';
|
||||
|
||||
// Load linked content
|
||||
$pageHasContent = new PageHasContentModel;
|
||||
$sectionHasContent = new SectionHasContentModel;
|
||||
$contents = array_merge(
|
||||
(array)$this->loadLinkedContent($pageHasContent, 'page', $id),
|
||||
(array)$this->loadLinkedContent($sectionHasContent, 'section', $page['section_id']));
|
||||
|
||||
// Exit if nothing was found
|
||||
if (!_exists($contents)) {
|
||||
parent::throw404();
|
||||
}
|
||||
|
||||
$sideContent = in_array('2', array_column($contents, 'type'));
|
||||
|
||||
$this->router->service()->contents = $contents;
|
||||
$this->router->service()->sideContent = $sideContent;
|
||||
$this->view('content', $title, $metaDescription);
|
||||
}
|
||||
|
||||
//-------------------------------------//
|
||||
|
||||
/**
|
||||
* Load all content blocks linked to the provided Model.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param string $column
|
||||
* @param int $id
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
protected function loadLinkedContent(Model $model, string $column, int $id): ?array
|
||||
{
|
||||
// Load all the Model <-> Content link data
|
||||
$hasContent = $model::selectAll('*', "
|
||||
WHERE {$column}_id = :id
|
||||
ORDER BY {$model->getSort()} ASC", [
|
||||
[':id', $id, \PDO::PARAM_INT],
|
||||
]
|
||||
);
|
||||
|
||||
// Exit if nothing was found
|
||||
if (!_exists($hasContent)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get all the content
|
||||
$contentIds = array_column($hasContent, 'content_id');
|
||||
$contents = ContentModel::findAll($contentIds);
|
||||
|
||||
// Exit if nothing was found
|
||||
if (!_exists($contents)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remove inactive content
|
||||
foreach ($contents as $key => $content) {
|
||||
if ($content['active'] == "0") {
|
||||
unset($contents[$key]);
|
||||
}
|
||||
}
|
||||
$contents = array_values($contents);
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render page view with title and meta description.
|
||||
*
|
||||
* @param string $view
|
||||
* @param string $pageTitle
|
||||
* @param string $metaDescription
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function view(
|
||||
string $view = '', string $pageTitle = '', string $metaDescription = ''): void
|
||||
{
|
||||
if ($view != '') {
|
||||
$view = $this->fileExists($this->views . $view . '.php');
|
||||
}
|
||||
|
||||
if ($this->page == null) {
|
||||
if ($view == '' && $this->section == '') {
|
||||
// /
|
||||
$view = $this->fileExists($this->views . 'home.php');
|
||||
}
|
||||
|
||||
if ($view == '') {
|
||||
// /example.php
|
||||
$view = $this->fileExists($this->views . $this->section . '.php');
|
||||
}
|
||||
|
||||
if ($view == '') {
|
||||
// /example/index.php
|
||||
$view = $this->fileExists($this->views . $this->section . '/index.php');
|
||||
}
|
||||
}
|
||||
else if ($view == '') {
|
||||
// /example/my-page.php
|
||||
$view = $this->fileExists($this->views . $this->section . '/' . $this->page . '.php');
|
||||
}
|
||||
|
||||
if ($view != '') {
|
||||
$pageTitle != ''
|
||||
? $this->router->service()->pageTitle = $pageTitle
|
||||
: $this->router->service()->pageTitle = ucfirst(str_replace('-', ' ', $this->page));
|
||||
$this->router->service()->metaDescription = $metaDescription;
|
||||
$this->router->service()->render($view);
|
||||
}
|
||||
else {
|
||||
parent::throw404();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------//
|
||||
|
||||
/**
|
||||
* Loop back filename if it exists, empty string otherwise.
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function fileExists(string $file): string
|
||||
{
|
||||
return file_exists($file) ? $file : '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @Todo
|
||||
// - Fix line 32, breaks if no DB content!
|
||||
// - Implement page.description (meta)
|
||||
// - Use page.title instead of content.title (?)
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Classes\Config;
|
||||
use App\Classes\Db;
|
||||
use App\Classes\User;
|
||||
use App\Classes\Mail;
|
||||
use App\Classes\Media;
|
||||
use App\Classes\Session;
|
||||
|
||||
use App\Model\MediaModel;
|
||||
use App\Model\Model;
|
||||
use App\Model\SectionModel;
|
||||
use App\Model\PageModel;
|
||||
use App\Model\UserModel;
|
||||
use App\Model\LogModel;
|
||||
|
||||
class TestController extends PageController {
|
||||
|
||||
public function indexAction(): void {
|
||||
parent::throw404();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user