~thirdplace/components

57e1109ac2491d1e4446da27477fca5b03952fd8 — Dag 11 months ago 14aadca
fix
6 files changed, 70 insertions(+), 4 deletions(-)

M composer.json
M src/Application.php
M src/Clock.php
M src/Session.php
M src/common.php
M src/http/Response.php
M composer.json => composer.json +1 -0
@@ 30,6 30,7 @@
            "./src/common.php",
            "./src/Clock.php",
            "./src/Renderer.php",
            "./src/Session.php",
            "./src/http/Response.php",
            "./src/Url.php"
        ]

M src/Application.php => src/Application.php +1 -0
@@ 69,6 69,7 @@ final class Application
            fn(Request $request) => $handler($request, $args),
        ];

        // todo: replace this with the last middeware
        $action = fn(Request $input) => $input;

        foreach (array_reverse($middlewares) as $middleware) {

M src/Clock.php => src/Clock.php +7 -2
@@ 12,9 12,14 @@ function now(): DateTimeImmutable
    return new DateTimeImmutable;
}

function tz(): DateTimeZone
function tz(string $tz = null): DateTimeZone
{
    return new DateTimeZone(date_default_timezone_get());
    return new DateTimeZone($tz ?? date_default_timezone_get());
}

function timezone_is_valid(string $tz): bool
{
    return in_array($tz, \timezone_identifiers_list());
}

interface Clock

M src/Session.php => src/Session.php +29 -1
@@ 3,6 3,34 @@ declare(strict_types=1);

namespace Thirdplace;

function flash(string $message)
{
    $messages = $_SESSION['messages'] ?? [];
    $messages[] = $message;
    $_SESSION['messages'] = $messages;
}

class SessionMiddleware
{
    private array $options;

    public function __construct(array $options = [])
    {
        $defaultOptions = [
            'name' => 'sid',
            'cookie_lifetime' => 60 * 60 * 24 * 7, // 7 days
            // Avoid unnecessary locking if desired
            //'read_and_close' => true,
        ];
        $this->options = array_merge($defaultOptions, $options);
    }

    function __invoke(Request $request, $next) {
        session_start($this->options);
        return $next($request);
    }
}

/**
 * Manipulates php's built-in $_SESSION
 */


@@ 51,4 79,4 @@ final class Session
    {
        $_SESSION = [];
    }
}
\ No newline at end of file
}

M src/common.php => src/common.php +28 -0
@@ 23,3 23,31 @@ function create_sane_stacktrace(\Throwable $e)
    }
    return array_reverse($stackTrace);
}

/**
 * Beware: the entropy cannot be deduced from the length
 */
function create_random_hex_string(int $length = 8)
{
    $bytes = (int) ceil($length / 2);
    // todo: remove annoying chars such as 0, 0, 1, l
    return substr(bin2hex(openssl_random_pseudo_bytes($bytes)), 0, $length);
}

class ExceptionMiddleware
{
    private $fn;

    public function __construct(callable $fn)
    {
        $this->fn = $fn;
    }

    function __invoke(Request $request, $next) {
        try {
            return $next($request);
        } catch (\Throwable $e) {
           return ($this->fn)($e);
        }
    }
}

M src/http/Response.php => src/http/Response.php +4 -1
@@ 19,8 19,11 @@ function json(array $body, int $code = 200): Response
    return response($json, $code)->withHeader('content-type', 'application/json');
}

function redirect(string $url): Response
function redirect(string $url, string $flash = '')
{
    if ($flash !== '') {
        flash($flash);
    }
    return response('', 302)->withHeader('location', $url);
}