shroophp/framework

HTTP应用框架。

v3.0.1 2018-12-05 23:30 UTC

This package is auto-updated.

Last update: 2024-09-08 22:42:44 UTC


README

HTTP应用框架。

安装

composer require 'shroophp/framework ^3.0'

示例用法

Hello, world!

在下面的示例中,每个请求将通过打印字符串 'Hello, world!' 进行响应。

假设请求的方法和路径分别从 $_SERVER['REQUEST_METHOD']$_SERVER['REQUEST_URI'] 读取。

<?php

use ShrooPHP\Core\Request;
use ShrooPHP\Framework\Application;
use ShrooPHP\Framework\Request\Responses\Response;
use ShrooPHP\Framework\Requests\PhpRequest;

require 'vendor/autoload.php';

$app = new Application;
$app->push(Response::string('Hello, world!'));
$app->run();

内容类型

要更改响应的格式,可以将内容类型作为响应字符串的第二个参数指定。

Response::string('Hello, world!', 'text/plain');

URLs

也可以针对特定的请求路径进行匹配。在下面的示例中,只有对路径 /hello/world 的请求会被响应。

$app->path('/hello/world', Response::string('Hello, world!'));

请求方法

请求方法也可以进行匹配。在下面的示例中,只有使用 GET 方法的请求会被响应。

$app->method('GET', Response::string('Hello, world!'));

可以通过指定为数组的方式匹配多个方法,如下面的示例(这将响应 GETPOST)。

$app->method(array('GET', 'POST'), Response::string('Hello, world!'));

动态URL

可以使用简单的花括号语法动态匹配请求路径。每个指定的键将等于一个懒惰正则表达式分组(即 (.*?))。

在下面的示例中,任何以 /hello/ 开头的路径都会被响应。

$app->path('/hello/{subject}', Response::string('Hello, subject!'));

动态响应

可以通过一系列回调动态确定对匹配请求的响应。

在下面的示例中,匹配的请求将通过打印 Hello, '<subject>'! 进行响应,其中 <subject> 是请求路径的尾部。

$app->path('/hello/{subject}', function (Application $app) {

    $app->push(function (Request $request) {

        $subject = $request->args()->get('subject');

        return Response::string("Hello, '{$subject}'!", 'text/plain');
    });
});

\ShrooPHP\Framework\Application::toModifier() 辅助方法被别名为一个下划线,以使上一个示例更加简洁,如下面的示例。

$app->path('/hello/{subject}', $app->_(function (Request $request) {

    $subject = $request->args()->get('subject');

    return Response::string("Hello, '{$subject}'!", 'text/plain');
}));

逻辑链式调用

可以使用嵌套修饰符链式调用应用程序的逻辑。

在下面的示例中,应用程序将匹配所有对路径 /chainedGET 请求。

$app->path('/chained', function (Application $app) {

    $app->method('GET', Response::string('Chained!', 'text/plain'));
});

评估

应用程序可能由多个处理程序组成。应用程序将按顺序运行每个处理程序,直到处理请求,此时将停止。

在下面的示例中,应用程序将打印 two,因为第二个处理程序是第一个响应的。

$app->path('first',  Response::string('one',   'text/plain'))
    ->path('second', Response::string('two',   'text/plain'))
    ->path('third',  Response::string('three', 'text/plain'))
    ->handle(new PhpRequest('GET', 'second')); // Prints 'two'.

应用程序通过评估处理程序的返回值来确定处理程序是否已响应。返回值 FALSENULL 告诉应用程序它应该继续迭代处理程序,而 TRUE\ShrooPHP\Core\Request\Response 将导致应用程序呈现(如果有)响应并停止。

在下面的示例中,应用程序将打印 handled,因为第一个处理程序返回 NULL

$app->path('{path}', function (Application $app) {

    $app->push(function (Request $request) {
        return null;
    });
});

$app->path('{path}', Response::string('handled', 'text/plain'));

$app->handle(new PhpRequest('GET', 'path'));

方法覆盖

传统上,Web上的表单只能使用 GETPOST 方法提交HTTP请求。

为了克服这个问题,可以在请求体中发送一个覆盖方法,并由应用程序检测,如下面的示例。

<?php use ShrooPHP\Framework\Application; ?>
<!-- method.php -->
<!DOCTYPE html>
<html>
    <head>
        <title>Method Overriding</title>
    </head>
    <body>
        <form action="" method="POST">
        <p>
            <label for="method">Method</label>
            <input id="method" type="text"
                name="<?= htmlentities(Application::METHOD); ?>"
                value="PUT">
        </p>
        <p>
            <input type="submit">
        </p>
        </form>
    </body>
</html>

<?php

use ShrooPHP\Core\Request;
use ShrooPHP\Framework\Application;
use ShrooPHP\Framework\Request\Responses\Response;

require 'vendor/autoload.php';

$app = new Application;

$app->web(function (Application $app) {

    $app->method('PUT', function (Application $app) {

        $app->push(function (Request $request) {

            $dump = var_export($request->data()->getArrayCopy(), true);
            return Response::string($dump, 'text/plain');
        });
    });

    ob_start();
    require 'method.php';
    $app->push(Response::string(ob_get_clean(), 'text/html'));
});

$app->run();

防止跨站请求伪造(CSRF)

防止跨站请求伪造的一种常见方法是验证请求针对目标源和与会话关联的令牌。以下是如何实现的示例。

<?php use ShrooPHP\Framework\Application; ?>
<!-- token.php -->
<!DOCTYPE html>
<html>
    <head>
        <title>Preventing Cross-Site Request Forgery (CSRF)</title>
    </head>
    <body>
        <form action="" method="POST">
            <p>
                <label for="token">Token</label>
                <input id="token" type="text"
                    name="<?= htmlentities(Application::TOKEN); ?>"
                    value="<?= htmlentities($request->token()->expected()); ?>">
            </p>
            <p>
                <input type="submit">
            </p>
        </form>
    </body>
</html>

<?php

use ShrooPHP\Core\Request;
use ShrooPHP\Framework\Application;
use ShrooPHP\Framework\Request\Responses\Response;

require 'vendor/autoload.php';

$app = new Application;

$app->token(function (Application $app) {

    $app->origin('https://example.org/', function (Application $app) {

        $app->valid(Response::string('The token is valid.', 'text/plain'));
    });

    $app->push(function (Request $request) {

        ob_start();
        require 'token.php';
        return Response::string(ob_get_clean(), 'text/html');
    });
});

$app->run();

配置

推荐的配置是将所有请求重写到一个单个PHP文件中(通常命名为index.php),通过服务器API将请求路径传递给$_SERVER['REQUEST_URI']

PHP内置Web服务器

PHP内置Web服务器非常适合开发、测试和演示目的。

不要在生产环境中使用PHP内置Web服务器.

php -S localhost:80 index.php

Apache

向您的Apache Web服务器添加一个类似于以下内容的虚拟主机。

<VirtualHost *:80>
    DocumentRoot "/path/to/directory"
    ServerName example.org
    <Directory "/path/to/directory">
        Require all granted
        <IfModule mod_rewrite.c>
            RewriteEngine on
            RewriteCond %{REQUEST_FILENAME} !index.php
            RewriteRule .* index.php [QSA,L]
        </IfModule>
    </Directory>
</VirtualHost>

nginx

确保您的nginx配置类似于以下内容(假设您正在使用FastCGI)。

worker_processes auto;
worker_cpu_affinity auto;
pcre_jit on;

events {
    worker_connections 2048;
}

http {

    include mime.types;
    default_type application/octet-stream;

    index index.php;

    server {
        listen 80;
        server_name example.org;
        root /path/to/directory;
        rewrite .* /index.php last;
        location ~ \.php$ {
            fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
            fastcgi_index index.php;
            include fastcgi.conf;
        }
    }
}