This commit is contained in:
Flummi 2025-05-22 08:18:06 +00:00
parent f3a71e8d12
commit 497e6a0bdf
11 changed files with 320 additions and 32 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
vendor
.env
.phpdoc
public/adminer
public/docs

View File

@ -1,6 +1,8 @@
<?php
namespace Blog\Core;
use Exception;
class Container {
private array $instances = [];

View File

@ -39,10 +39,12 @@ class Router {
private function handleMiddlewares(array $middlewares, Request $req, Response $res): bool {
foreach($middlewares as $middleware) {
$middlewareInstance = is_string($middleware) ? new $middleware() : $middleware;
if($middlewareInstance instanceof MiddlewareInterface)
if(!$middlewareInstance->handle($req, $res))
if($middlewareInstance instanceof MiddlewareInterface) {
if(!$middlewareInstance->handle($req, $res)) {
return false;
}
}
}
return true;
}
}

View File

@ -4,16 +4,14 @@ namespace Blog\Template;
use Exception;
class Twig {
private $blocks = [];
private $viewsPath;
private $debugMode;
private array $blocks = [];
private string $viewsPath;
public function __construct($viewsPath, $debugMode = false) {
public function __construct($viewsPath) {
$this->viewsPath = rtrim($viewsPath, '/') . '/';
$this->debugMode = $debugMode;
}
public function render($file, $data = []) {
public function render($file, $data = []): string {
try {
$code = $this->includeFiles($file);
$code = $this->compileCode($code);
@ -23,13 +21,11 @@ class Twig {
eval('?>' . $code);
return ob_get_clean();
} catch(Exception $e) {
if($this->debugMode)
echo "Error rendering template: " . $e->getMessage();
throw $e;
throw new Expection("Error rendering template: " . $e->getMessage());
}
}
private function compileCode($code) {
private function compileCode($code): string {
$code = $this->compileBlock($code);
$code = $this->compileYield($code);
$code = $this->compileEchos($code);
@ -37,11 +33,12 @@ class Twig {
return $code;
}
private function includeFiles($file) {
private function includeFiles($file): string {
$filePath = $this->viewsPath . preg_replace("/\.twig$/", "", $file) . ".twig";
if(!file_exists($filePath))
if(!file_exists($filePath)) {
throw new Exception("View file not found: {$filePath}");
}
$code = file_get_contents($filePath);
preg_match_all('/{% ?(extends|include) ?\'?(.*?)\'? ?%}/i', $code, $matches, PREG_SET_ORDER);
@ -53,33 +50,39 @@ class Twig {
return preg_replace('/{% ?(extends|include) ?\'?(.*?)\'? ?%}/i', '', $code);
}
private function compilePHP($code) {
private function compilePHP($code): string {
return preg_replace('~\{%\s*(.+?)\s*%}~is', '<?php $1 ?>', $code);
}
private function compileEchos($code) {
private function compileEchos($code): string {
$code = preg_replace('~\{\{\s*(.+?)\s*\}\}~is', '<?=$1?>', $code);
return preg_replace('~\{\{\{\s*(.+?)\s*\}\}\}~is', '<?=htmlspecialchars($1, ENT_QUOTES, "UTF-8")?>', $code);
}
private function compileEscapedEchos($code) {
private function compileEscapedEchos($code):string {
return preg_replace('~\{{{\s*(.+?)\s*}}}~is', '<?=htmlentities($1, ENT_QUOTES, "UTF-8")?>', $code);
}
private function compileBlock($code) {
/*
*
*
*/
private function compileBlock($code): string {
preg_match_all('/{% ?block ?(.*?) ?%}(.*?){% ?endblock ?%}/is', $code, $matches, PREG_SET_ORDER);
foreach($matches as $match) {
if(!isset($this->blocks[$match[1]]))
if(!isset($this->blocks[$match[1]])) {
$this->blocks[$match[1]] = '';
}
$this->blocks[$match[1]] = str_replace('@parent', $this->blocks[$match[1]], $match[2]);
$code = str_replace($match[0], '', $code);
}
return $code;
}
private function compileYield($code) {
foreach($this->blocks as $block => $value)
private function compileYield($code): string {
foreach($this->blocks as $block => $value) {
$code = preg_replace('/{% ?yield ?' . $block . ' ?%}/', $value, $code);
}
return preg_replace('/{% ?yield ?(.*?) ?%}/i', '', $code);
}
}

View File

@ -3,5 +3,13 @@
"psr-4": {
"Blog\\": "app/"
}
},
"require": {
"phpdocumentor/shim": "^3.7"
},
"config": {
"allow-plugins": {
"phpdocumentor/shim": true
}
}
}

269
composer.lock generated Normal file
View File

@ -0,0 +1,269 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f519b099d4763add12c03dab97eaf35f",
"packages": [
{
"name": "phar-io/composer-distributor",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/phar-io/composer-distributor.git",
"reference": "dd7d936290b2a42b0c64bfe08090b5c597c280c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/composer-distributor/zipball/dd7d936290b2a42b0c64bfe08090b5c597c280c9",
"reference": "dd7d936290b2a42b0c64bfe08090b5c597c280c9",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.1 || ^2.0",
"ext-dom": "*",
"ext-libxml": "*",
"phar-io/filesystem": "^2.0",
"phar-io/gnupg": "^1.0",
"php": "^7.3 || ^8.0"
},
"require-dev": {
"composer/composer": "^2.0",
"phpunit/phpunit": "^9.4"
},
"type": "library",
"autoload": {
"psr-4": {
"PharIo\\ComposerDistributor\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Andreas Heigl",
"email": "andreas@heigl.org",
"role": "Developer"
},
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Feldmann",
"email": "sf@sebastian-feldmann.info",
"role": "Developer"
}
],
"description": "Base Code for a composer plugin that installs PHAR-files",
"homepage": "https://phar.io",
"keywords": [
"bin",
"binary",
"composer",
"distribute",
"phar",
"phive"
],
"support": {
"issues": "https://github.com/phar-io/composer-distributor/issues",
"source": "https://github.com/phar-io/composer-distributor/tree/1.0.2"
},
"funding": [
{
"url": "https://phar.io",
"type": "other"
}
],
"time": "2023-05-31T17:05:49+00:00"
},
{
"name": "phar-io/executor",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/phar-io/executor.git",
"reference": "5bfb7400224a0c1cf83343660af85c7f5a073473"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/executor/zipball/5bfb7400224a0c1cf83343660af85c7f5a073473",
"reference": "5bfb7400224a0c1cf83343660af85c7f5a073473",
"shasum": ""
},
"require": {
"phar-io/filesystem": "^2.0",
"php": "^7.2||^8.0"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"email": "sebastian@phpeople.de",
"role": "Developer"
}
],
"support": {
"issues": "https://github.com/phar-io/executor/issues",
"source": "https://github.com/phar-io/executor/tree/1.0.1"
},
"time": "2020-11-30T10:53:57+00:00"
},
{
"name": "phar-io/filesystem",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/phar-io/filesystem.git",
"reference": "222e3ea432262a05706b7066697c21257664d9d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/filesystem/zipball/222e3ea432262a05706b7066697c21257664d9d1",
"reference": "222e3ea432262a05706b7066697c21257664d9d1",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"email": "sebastian@phpeople.de",
"role": "Developer"
}
],
"support": {
"issues": "https://github.com/phar-io/filesystem/issues",
"source": "https://github.com/phar-io/filesystem/tree/2.0.1"
},
"time": "2020-11-30T10:16:22+00:00"
},
{
"name": "phar-io/gnupg",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/phar-io/gnupg.git",
"reference": "ed8ab1740ac4e9db99500e7252911f2821357093"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phar-io/gnupg/zipball/ed8ab1740ac4e9db99500e7252911f2821357093",
"reference": "ed8ab1740ac4e9db99500e7252911f2821357093",
"shasum": ""
},
"require": {
"phar-io/executor": "^1.0",
"phar-io/filesystem": "^2.0",
"php": "^7.2||^8.0"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"email": "sebastian@phpeople.de",
"role": "Developer"
}
],
"description": "Thin GnuPG wrapper class around the gnupg binary, mimicking the pecl/gnupg api",
"support": {
"issues": "https://github.com/phar-io/gnupg/issues",
"source": "https://github.com/phar-io/gnupg/tree/1.0.3"
},
"time": "2024-08-22T20:45:57+00:00"
},
{
"name": "phpdocumentor/shim",
"version": "v3.7.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/shim.git",
"reference": "0eb695503a5ad73eff5722d71a48317275dc2615"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/shim/zipball/0eb695503a5ad73eff5722d71a48317275dc2615",
"reference": "0eb695503a5ad73eff5722d71a48317275dc2615",
"shasum": ""
},
"require": {
"composer-plugin-api": "^2.0",
"phar-io/composer-distributor": "^1.0"
},
"type": "composer-plugin",
"extra": {
"class": "phpDocumentor\\Plugin"
},
"autoload": {
"psr-4": {
"phpDocumentor\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"support": {
"source": "https://github.com/phpDocumentor/shim/tree/v3.7.1"
},
"time": "2025-02-15T11:13:17+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View File

@ -24,7 +24,6 @@ $router = new Router();
$container = new Container();
$container->set('twig', fn() => new Twig(__DIR__ . "/../views"));
$container->set('postModel', fn() => new Blog\Model\postModel());
require_once __DIR__ . "/../routes/web.php";

View File

@ -4,6 +4,7 @@ use Blog\Core\container;
use Blog\Utils\authHelper;
use Blog\Http\request;
use Blog\Http\response;
use Blog\Middleware\authMiddleware;
$router->addRoute('GET', '/', function(Request $req, Response $res) use($container) {
$twig = $container->get('twig');
@ -38,7 +39,7 @@ $router->addRoute('GET', '/login', function(Request $req, Response $res) use($co
$res->getBody()->write(
$twig->render("login", [
"csrf" => Blog\Middleware\authMiddleware::generateCSRFToken()
"csrf" => authMiddleware::generateCSRFToken()
])
);
@ -53,7 +54,7 @@ $router->addRoute('POST', '/login', function(Request $req, Response $res) use($c
$password = $req->getPost('password');
$csrfToken = $req->getPost('_csrf_token');
if(!Blog\Middleware\authMiddleware::validateCSRFToken($csrfToken)) {
if(!authMiddleware::validateCSRFToken($csrfToken)) {
return $res
->setStatus(419)
->getBody()

View File

@ -10,7 +10,7 @@
<a href="/post/{{ $post->getId() }}">{{ $post->getTitle() }}</a>
<p>{{ $post->getContent(50) }}</p>
<p>Datum: 2025-03-04</p>
<p>Autor: Beispielautor</p>
<p>Autor: {{ $post->getAuthor() }}</p>
</div>
{% endforeach; %}
</div>

View File

@ -8,6 +8,8 @@
</head>
<body>
<div class="container" id="blog">
<a href="/">Home</a> - <a href="/login">Login</a>
<hr>
{% yield content %}
</div>
</body>

View File

@ -3,10 +3,10 @@
{% block title %}Login{% endblock %}
{% block content %}
<form method="POST" action="/login">
<form method="POST" action="/login">
<input type="text" name="username" placeholder="Benutzername" required>
<input type="password" name="password" placeholder="Passwort" required>
<input type="hidden" name="_csrf_token" value="{{ $csrf }}">
<button type="submit">Einloggen</button>
</form>
</form>
{% endblock %}