eru123/router

使用父子模型的PHP库,用于处理路由

v1.0.2 2023-11-20 03:46 UTC

This package is auto-updated.

Last update: 2024-09-20 05:48:23 UTC


README

Build Status Latest Stable Version Total Downloads License

PHP库,用于处理HTTP请求。

有关最新文档,请访问 文档

支持的功能

  • URL参数 - 允许在URL路径中允许动态参数(例如:/user/$id
  • 静态路由 - 从目录中提供静态文件(即使是禁止的目录)并具有目录遍历保护
  • 回退路由 - 处理不匹配任何其他路由但匹配前缀URL的请求的路由
  • 调试 - 调试模式,用于调试路由和路由状态
  • 路由状态 - 路由状态传递给所有路由处理程序和响应处理程序
  • 路由引导程序 - 允许您运行预处理程序,并允许您在路由器开始运行处理程序之前操作路由状态
  • 路由处理程序 - 当路由匹配请求时调用路由处理程序
  • 响应处理程序 - 在最后一个路由处理程序调用后调用响应处理程序
  • 错误处理程序 - 当路由处理程序创建可抛出对象时调用错误处理程序
  • 父子路由 - 您可以创建父子路由以分组路由

基本用法

安装

composer require eru123/router

创建基本路由

<?php

require_once __DIR__ . '/vendor/autoload.php';

use eru123\router\Router;
use eru123\router\Builtin;

// Create Router instance
$r = new Router;

// Enable Debug Mode.
// When debug mode is on, we add is_debug and debug() methods to the route state
// $state->is_debug - true if debug mode is on
// $state->debug - array of debugging information (ex: routes, route, errors, etc.)
$r->debug();

// Base Path
// This is used as the prefix for all routes
$r->base('/api');

// Set a response handler using a callable function
// Response handlers are called after the last route
// handler is called, it uses the return value of the 
// last route handler as the first argument and then
// the route state as the second argument
$r->response(function($result, $state) {
    if (is_array($res) || is_object($res)) {

        header('Content-Type: application/json');
        if ($state->is_debug && is_array($res)) {
            $result['debug'] = $state->debug;
        }
        
        print json_encode($result);
        exit;
    }

    if (is_string($result) && strpos($result, '<?xml') === 0) {
        header('Content-Type: application/xml');
        print $result;
        exit;
    }

    print $result;
    exit;
});

// Set an error handler using a callable function
// Error handlers are called when a route handler creates a Throwable
$r->error(function($error, $state) {
    $result = [
        'error' => $error->getMessage(),
        'code' => $error->getCode(),
    ];

    if ($state->is_debug) {
        $result['debug'] = $state->debug;
    }

    header('Content-Type: application/json');
    print json_encode($result);
    exit;
});

// Default response and error handlers
$r->response([Builtin::class, 'response']);
$r->error([Builtin::class, 'error']);

// Create Route Request
// The first argument is the HTTP method
// The second argument is the path
// The third and so on arguments are route handlers
$r->request('GET', '/', function($state) {
    return 'Hello World!';
});

// Request Aliases
// We implement most used and common HTTP methods as aliases
$r->get($path, $handler);
$r->post($path, $handler);
$r->put($path, $handler);

// URL Parameters
// You can use URL parameters in the path with $<name> syntax.
// Parameter name must start with alpha and the following 
// characters can be alpanumeric or underscore.
$r->get('/user/$id', function($state) {
    return 'User ID: ' . $state->params['id'];
});

// Fallback Route
// This route is called when no other route matches
// all requests with /pages as the base path will 
// be handled by this route if no other route matches
$r->fallback('/pages', function($state) {
    return 'Page not found';
});

// OR Global Fallback Route
// This route is called when no other route matches
// all requests will be handled by this route if no other route matches.
// It uses a prefix url, and process the fallback route only if the URL
// matches the prefix url.
// Example:
//      $r->fallback('/pages', $handler)
//      Process all requests starting with /pages (ex: /pages/1, /pages/user/1, etc.) 
$r->fallback('/', function($state) {
    return 'Page not found';
});

// Static Routes
// Static routes are routes that are intended to be used for static files.
// It can serve files from a forbidden directory that can't be accessed by
// the client. You can inject a middleware to it for checking authentication
// or etc.
// It uses a prefix url, and process the static route only if the URL
// matches the prefix url.
// For the second argument, you need to pass a directory path where the 
// request file needs to be looked up.
// Example:
//      $r->static('/css', __DIR__ . '/../src/assets/css', $handler)
//      Process all requests starting with /css (ex: /css/style.css, /css/style.min.css, etc.) 
$r->static('/static', __DIR__ . '/static', function($state) {
    // Check if user is authenticated
    if (!$state->user) {
        throw new \Exception('Not authenticated', 401); // this will be handled by the error handler

        // You can also return a response here if you dont want to use the error handler
        header('Content-Type: application/json');
        print json_encode([
            'error' => 'Not authenticated',
            'code' => 401,
        ]);

        exit;
    }

    // If the handler doesn't return anything, the file will be served accordingly
});

高级用法

在本节中,我们将介绍一些高级用法以及有关库使用的深入细节。

路由器路径匹配顺序

对于高级用法,您需要了解路由器如何将请求路径匹配到路由路径。路由器按照以下顺序将请求路径匹配到路由路径:

  • Router::static('/', $directory[, ...$handlers]) - 使用静态方法定义的路由首先匹配。
  • Router::request($method, $path, ...$handlers)Router::get($path, ...$handlers)Router::post($path, ...$handlers) - 使用请求方法及其别名定义的路由接下来匹配。
  • Router::fallback($path, ...$handlers) - 使用回退方法定义的路由最后匹配。

关于这些组内的匹配顺序,路由器按先来先服务的顺序将请求路径匹配到路由路径。

例如,如果您有以下路由

// First come first serve order

// this will be matched first, this will also match /user/me
$r->get('/user/$x', $handler1); 

// this will be matched second, but it's handlers will not be 
// called unless the $handler1's state called skip() method
// Example: $state->skip();
$r->get('/user/me', $handler2); 

// NOTE: These kind of URL path designs are NOT RECOMMENDED.

路由状态

RouteState 是传递给所有处理程序以在处理程序和路由之间共享信息的类实例。

以下是您可以使用的 RouteState 方法

  • skip() - 将状态设置为允许跳过以跳过当前路由的所有剩余处理程序,以转到下一个路由。
  • unskip() - 将状态设置为不允许跳过以取消跳过状态。
  • is_allowed_skip() - 检查状态是否允许跳过。值可以是 truefalsenullnull 表示状态未设置或未调用 skip()unskip()
  • next() - 必须为每个路由处理程序调用此方法(除了最后一个处理程序),以转到下一个处理程序。
  • stop() - 如果您想停止当前路由的下一个处理程序的执行,则应调用此方法。
  • is_allowed_next() - 检查状态是否允许转到下一个处理程序。值可以是 truefalsenullnull 表示状态未设置或未调用 next()stop()
  • extract_info(Route $route) - 从 $route->info() 的结果中提取信息,并将其设置为 RouteState 属性。以下是定义要提取的路由信息属性
    • method - 路由中定义的 HTTP 方法。这还包括此库的魔法方法,如 ANY、FALLBACK 和 STATIC。
    • path - 路由中定义的 URL 路径。如果您在路由器中设置了基本路径,它将包含在路径中。
    • params - 路由中定义的 URL 参数数组。
    • matched - 一个布尔值,表示路由是否与请求路径匹配。
    • regex - 用于将请求路径与路由路径匹配的正则表达式模式。

或者,您可以通过直接设置来覆盖 RouteState 属性,就像使用魔法一样。例如

// Override existing properties
$state->method = 'GET';
$state->path = '/user/1';

// Add new properties
$state->user_id = 1;

但是,有一些受保护的属性您无法覆盖,它们是

  • allow_next
  • allow_skip
  • route

静态处理器 Router::static($path, $directory[, ...$handlers])

  • $path - 静态路由的 URL 路径前缀。
  • $directory - 请求文件需要查找的目录路径。
  • $handlers - 可选的路由处理器。这些可以是任何可调用的函数、类静态方法或对象方法调用,它接受一个参数为 RouterState $state 对象。

从禁止的目录中提供文件服务

静态处理器可以提供由网络服务器配置(例如 Apache 的 deny from all 指令)禁止访问的目录中的文件。只要网络服务器应用程序的系统用户可以访问该目录,静态处理器就可以提供文件。

$r->static('/', '/');