一个小型的PHP路由库。

v4.0.1 2023-01-08 12:38 UTC

This package is auto-updated.

Last update: 2024-09-08 16:14:26 UTC


README

一个简单的PHP路由,用于处理HTTP请求。

此库符合PSR-15规范,因此可以与PSR-7消息一起使用,并利用PSR-17工厂。




实例化

use AdinanCenci\Router\Router;
$r = new Router();




添加路由

您可以通过通知HTTP方法、要匹配的路径的正则表达式模式和关联的控制器来添加路由

$r->add('get', '#home$#', 'controller');

HTTP方法

// You may inform a single http method:
$r->add('get', '#home#', 'controller')

// Or several inside an array ...
$r->add(['get', 'post'], '#home#', 'controller')

// Or in a pipe separated string
$r->add('get|post', '#home#', 'controller')

// Or use an sterisk to match all methods.
$r->add('*', '#home#', 'controller')

正则表达式模式

一个简单的正则表达式模式。捕获组将被作为属性传递给控制器。

注意:路由接受多个模式作为数组。

$r->add('*', '#products/(?<category>\d+)/(?<id>\d+)#', function($request, $handler) 
{
   $category  = $request->getAttribute('category', null);
   $productId = $request->getAttribute('id', null);
});

控制器

控制器将接收两个参数:分别是Psr\Http\Message\ServerRequestInterfacePsr\Http\Server\RequestHandlerInterface的实例。

路由接受各种参数作为控制器

$r->add('get', '#anonymous-function$#', function($request, $handler) 
{
    echo 'Anonymous function';
})

//-------------

->add('get', '#named-function$#', 'namedFunction')

//-------------

->add('get', '#static-methods$#', ['MyClass', 'staticMethod'])
// A single string also works:
->add('get', '#static-methods$#', 'MyClass::staticMethod')

//-------------

// Of course, it also accepts instances of Psr\Http\Server\MiddlewareInterfac 
// ( see the PSR-15 specification for more information )
->add('get', '#psr-15$#', $middleware)

//-------------

->add('get', '#object-and-method$#', [$object, 'methodName'])

//-------------

->add('get', '#object$#', $object)
// The ::__invoke() magic method will be called.

//-------------

->add('get', '#class-and-method$#', ['MyClass', 'methodName'])
// It will attempt to instantiate the class first.
// A single string also works:
->add('get', '#class-and-method$#', 'MyClass::methodName')

//-------------

->add('get', '#class$#', ['MyClass'])
// It will attempt to instantiate the class and call the ::__invoke() magic method.

注意:如果控制器不存在或由于某些原因无法调用,将抛出异常。

请参阅"examples"目录中的内容以获取更多详细信息。

::add() 简写

// Examples
$r->get('#home#', $call);     /* is the same as */ $r->add('get', '#home#', $call);
$r->post('#home#', $call);    /* is the same as */ $r->add('post', '#home#', $call);
$r->put('#home#', $call);     /* is the same as */ $r->add('put', '#home#', $call);
$r->delete('#home#', $call);  /* is the same as */ $r->add('delete', '#home#', $call);
$r->options('#home#', $call); /* is the same as */ $r->add('options', '#home#', $call);
$r->patch('#home#', $call);   /* is the same as */ $r->add('patch', '#home#', $call);




执行

调用::run()将执行路由并返回响应。

$r->run();




PSR合规性

此库符合PSR-15规范,因此您的控制器可以根据PSR-7中指定的详细信息定制响应。处理器提供了PSR-17工厂以供使用。

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\RequestHandlerInterface;

$r->add('get', '#home$#', function(ServerRequestInterface $request, RequestHandlerInterface $handler)
{
   // Psr\Http\Message\ResponseFactoryInterface instance.
   $responseFactory = $handler->responseFactory;

   // Returns an instance of ResponseInterface with code 200.
   return $responseFactory->createResponse(200, 'OK');
});

重要

如果您的控制器没有返回ResponseInterface的实例,路由器将基于通过echoprint输出的任何内容创建一个。

便利之处

除了符合PSR-17规范外,响应工厂还提供了一些方法以简化操作

$responseFactory = $handler->responseFactory;

// Response with code 200
$responseFactory->ok('your html here');

// Response with code 201
$responseFactory->created('your html here');

// Response with code 301
$responseFactory->movedPermanently('https://redirect.here.com');

// Response with code 302
$responseFactory->movedTemporarily('https://redirect.here.com');

// Response with code 400
$responseFactory->badRequest('your html here');

// Response with code 401
$responseFactory->unauthorized('your html here');

// Response with code 403
$responseFactory->forbidden('your html here');

// Response with code 404
$responseFactory->notFound('your html here');

// Response with code 500
$responseFactory->internalServerError('your html here');

// Response with code 501
$responseFactory->notImplemented('your html here');

// Response with code 502
$responseFactory->badGateway('your html here');

// Response with code 503
$responseFactory->serviceUnavailable('your html here');

通过::withAddedCookie()向响应对象添加cookie变得更容易

$response = $responseFactory->ok('your html here');

$expires  = null;  // optional
$path     = '';    // optional
$domain   = '';    // optional
$secure   = false; // optional
$httpOnly = false; // optional

$response = $response->withAddedCookie('cookieName', 'cookieValue', $expires, $path, $domain, $secure, $httpOnly);




中间件

中间件将在路由之前处理。中间件与路由非常相似,但与路由不同,可以执行多个中间件。

// Example
$r->before('*', '#restricted-area#', function($request, $handler) 
{
    if (! userIsLogged()) {
        return $handler->responseFactory->movedTemporarily('/login-page');
    }
});




错误

异常

默认情况下,捕获的异常将渲染在500响应对象中,您可以通过设置自己的处理程序来自定义它。

$r->setExceptionHandler(function($request, $handler, $path, $exception) 
{
    return $handler->responseFactory
      ->internalServerError('<h1>Error 500 (' . $path . ')</h1><p>' . $exception->getMessage() . '</p>');
});

未找到

默认情况下,当找不到路由时,路由器将渲染一个404响应对象,您可以通过设置自己的处理程序来自定义它。

$r->setNotFoundHandler(function($request, $handler, $path) 
{
    return $handler->notFound
      ->internalServerError('<h1>Error 404</h1><p>Nothing found related to "' . $path . '"</p>');
});




::setDefaultNamespace($namespace)

设置默认命名空间,因此在定义路由时无需编写完整的控制器类名。

// Example
$r->setDefaultNamespace('MyProject');

$r->add('get', '#home#', 'MyClass::method');
// If MyClass does not exist, the router will assume it refers to 
// MyProject\MyClass::method()




在子目录中工作

路由器将自动在子目录中工作。

考虑以下示例:您的URL:http://yourwebsite.com/foobar/about

您的文档根目录是
/var/www/html/,并且您的路由器位于
/var/www/html/foobar/.

路由器将匹配about路由,而不是foobar/about

尽管如此,如果您确实需要与foobar/about一起工作,则必须将/var/www/html/作为基本目录传递给路由器类的构造函数。

//               /var/www/html/foobar/index.php
$r = new Router('/var/www/html/');




服务器配置

为了让它工作,我们需要重写对包含我们路由器的文件的请求。下面是一些示例:

Apache

以下是为Apache的 .htaccess 示例

RewriteEngine on

# Condition: Requested resource does not exist
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d

# Rewrite to index.php
RewriteRule ^.{1,}$   index.php   [QSA]




Nginx

以下是为nginx的示例

location / {
    if ($script_filename !~ "-f") {
        rewrite "^/.{1,}$" /index.php;
    }
}




IIS

以下是为Microsoft IIS的web.config示例

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="RewriteNonExistingFiles">
                    <match url="^.{1,}$" />
                    <conditions>
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/index.php" appendQueryString="true" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>




安装

使用composer

composer require adinan-cenci/router




许可

MIT