andygrn/aquarius

为 Gemini 网罩提供应用框架

v0.2 2020-11-15 12:30 UTC

This package is auto-updated.

Last update: 2024-09-17 07:42:27 UTC


README

A PHP 应用框架,用于 Gemini 网罩,包括

  • 简单的头部/主体响应模型,具有 '中间件' 功能。
  • 正则表达式路由,可选命名或未命名的参数。
  • 自动将客户端证书链接到会话。
  • 所有内容都在一个文件中。

对于之前使用过 PHP 网络框架的人来说,应该相当熟悉。

gemini://andygrn.co.uk/apps/aquarius 上查看其功能

安装

通过 Composer:composer require andygrn/aquarius

或者下载文件并 require 'aquarius.php';

需要 PHP 7.3 或更高版本。

应用和处理程序

一个 aquarius 应用 有一个或多个 处理程序

处理程序是一个路径正则表达式和一系列函数。应用将运行第一个正则表达式与请求路径匹配的处理程序的函数栈。处理程序的函数栈必须返回一个 响应,该响应将被发送到客户端。

函数可以通过处理程序的 butFirst 方法添加到处理程序的栈中。添加到栈中的最后一个函数将首先运行。栈函数应通过 return $this->next($request, $response); 将参数传递给栈中的下一个函数,但它们可以选择直接 return $response; 以跳过其余的栈。

处理程序函数可以是任何有效的 可调用

CGI 变量

为了执行任何有用的操作,aquarius 需要CGI 主机至少定义 PATH_INFOQUERY_STRING。如果计划使用 Request::getRemoteUser(),还需要 REMOTE_USER

为了启用客户端证书会话行为,aquarius 还需要 TLS_CLIENT_HASH。我不确定它有多标准化,但 JetforceMolly BrownGLV-1.12556 似乎支持它。

API

请求

Request::getPath(): string 获取当前的 PATH_INFO,带有前导斜杠并去除尾部斜杠。

Request::getQuery(): string 获取当前的 QUERY_STRING,URL 解码(使用 rawurldecode())。

Request::getRemoteUser(): string 获取当前的 REMOTE_USER(可能是客户端证书的通用名称)。

响应

Response::setHeader(int $status, string $meta): void 设置响应的头部行。默认响应 ($status, $meta)(Response::STATUS_SUCCESS, 'text/gemini'),因此您可能不需要调用此方法。

Response::getStatus(): int 获取响应状态码。

Response::getMeta(): string 获取响应元字符串。

Response::setBody(string $body): void 设置整个响应体。

Response::appendBody(string $body): void 将内容追加到响应体。

Response::getBody(): string 获取响应体。

处理程序

Handler::next(Request $request, Response $response): Response 调用此处理程序栈中的下一个函数。

Handler::butFirst(callable $callable): self 将一个函数添加到处理程序的栈中。最后添加的将首先被调用。返回自身以便可以链式调用。

Handler::getPathParameters(): array<mixed> 获取从处理程序的 regex 模式捕获的路径参数。

应用

App::addHandler(string $path_regex, callable $callable): Handler$path_regex 上创建一个新的处理程序,其中 $callable 是其栈中的第一个函数。

App::run(): void 将当前路径解析为处理程序并运行它(如果无处理程序匹配,则提供 51 响应)。

示例应用

// A simple greeting and visit counter.

$app = new aquarius\App();

$app->addHandler('/', function ($request, $response) {
    $remote_user = $request->getRemoteUser();
    if ('' === $remote_user) {
        $remote_user = 'stranger';
    }
    $response->appendBody("Hello, $remote_user.\n\n");

    if (PHP_SESSION_ACTIVE === session_status()) {
        if (!isset($_SESSION['visit_count'])) {
            $_SESSION['visit_count'] = 0;
        }
        ++$_SESSION['visit_count'];
        $response->appendBody("You've been here {$_SESSION['visit_count']} times.");
    }

    return $response;
});

$app->run();
// Collecting input.

$app = new aquarius\App();

$app->addHandler('/add-to-list', function ($request, $response) {
    $query = $request->getQuery();
    if (0 === strlen($query)) {
        $response->setHeader($response::STATUS_INPUT, 'Enter item name');
        return $this->next($request, $response);
    }

    if (!isset($_SESSION['list'])) {
        $_SESSION['list'] = [];
    }
    $_SESSION['list'][] = $query;

    $response->setHeader($response::STATUS_REDIRECT_TEMPORARY, '/list');
    return $this->next($request, $response);
});

$app->run();
// Path parameters with regex capturing groups.

$app = new aquarius\App();

function show_path_parameters($request, $response)
{
    $parameters = $this->getPathParameters();
    $response->appendBody(var_export($parameters, true));
    return $this->next($request, $response);
}

$app->addHandler('/page/\d+', 'show_path_parameters');
// Match:      /page/1    /page/123
// Parameters: []         []

$app->addHandler('/page/([^/]+)/([^/]+)', 'show_path_parameters');
// Match:      /page/hello/world    /page/1/2:
// Parameters: ['hello','world']    ['1','2']

$app->addHandler('/page/(\d+)(?:/(\d+)(?:/(\d+))?)?', 'show_path_parameters');
// Match:      /page/1    /page/1/2    /page/1/2/3
// Parameters: ['1']      ['1','2']    ['1','2','3']

$app->addHandler('/page/(?<foo>\d+)', 'show_path_parameters');
// Match:      /page/1           /page/2
// Parameters: ['foo' => '1']    ['foo' => '2']

$app->run();
// Forcing a session (i.e. a client certificate) with middleware.

$app = new aquarius\App();

function require_session($request, $response)
{
    if (PHP_SESSION_ACTIVE !== session_status()) {
        $response->setHeader(
            $response::STATUS_CLIENT_CERTIFICATE_REQUIRED,
            'Certificate required'
        );
        return $response;
    }
    return $this->next($request, $response);
}

$app->addHandler('/private-lounge', function ($request, $response) {
    $response->setBody('Members only 😎');
    return $this->next($request, $response);
})
->butFirst('require_session');

$app->run();