zofe/burp

简单的PHP路由器,与查询字符串和uri-segments一起工作,laravel过滤器系统

3.1.4 2022-07-19 08:33 UTC

README

简单的php 路由器,可以与 "URI","查询字符串" 或两者同时工作。
它还包含简单的 事件 监听器实现(用于触发或队列应用程序事件)。

您可以在您首选的框架中使用Burp(包括laravel),它并不假装是唯一的路由器,它只是检查您的URL,然后触发或队列您的事件。

原因

想法是有一个 "一站式" 路由器、过滤器、事件监听器。
这是一种构建事件驱动小部件并定义应用程序URL的灵活 "语义" 的方法。

Burp可以为通过 uri-segments查询字符串 或两者同时驱动的部件提供动力,而无需拥有经典控制器。

安装

通过composer安装,添加 "zofe/burp": "3.0.*"

如果您使用laravel,请在config/app.php中添加服务提供者

'providers' => array(
    ...
    'Zofe\Burp\BurpServiceProvider',
)

使用

Burp与任何其他PHP路由器类似,但它也可以作为过滤器使用。
您需要知道两个主要区别

  • 路由规则可以是 严格非严格(这意味着:“精确匹配”或“部分匹配”,即非严格规则可以匹配一些uri-segment或一些查询字符串参数)

  • 规则是非阻塞的,这意味着单个HTTP请求可以触发多个路由

示例

<?php


//catch /user/2 (GET)
Burp::get('^/user/(\d+)$', null, array('as'=>'user.show', function($id) {
    //show user $id
}));

//catch /user (POST)
Burp::post('^/user$', null, array('as'=>'user.create', function() {
    //create new user
}));

//catch /user/2 (PATCH)
Burp::patch('^/user/(\d+)$', null, array('as'=>'user.update', function($id) {
    //save changes for user $id
}));

//catch /welcome (on any http method: GET, POST, ...)
Burp::any('^/welcome/(\w+)$', null, function($username) {
    //say welcome $username!
}));

//catch /something?apikey=xxxx
Burp::get(null, 'apikey=(\w+)', array('as'=>'key', function($key) {
    //check api key in query string..
}));

//will return: /currenturi?apikey=asda
Burp::linkRoute('key','asda')

Burp::dispatch();

重要

  • 要定义 "严格规则",您必须使用正则表达式分隔符 ^$
  • 要定义 "参数",您必须使用括号,如正则表达式原子

绑定控制器

您可以使用 'uses' 键将路由绑定到某个 class@method

<?php

//catch /user/2 (GET)  and bind it to UserController class on show method  
Burp::get('^/user/(\d+)$', null, array('as'=>'user.show', 'uses'=>'UsersController@show'));

使用 - 前端控制器完整示例

如果您需要在 "独立" 环境中使用Burp,则需要前端控制器。
您可以从这个 .htaccess(大多数应用程序框架已经类似)开始

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

然后您需要包含burp,这是将Burp作为独立路由器的方式

<?php
#index.php

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

use Zofe\Burp\Burp;


//widget routing - fired when url is for example:  /something/pg/2
Burp::get('pg/(\d+)', null, array('as'=>'page', function($page) {
    echo "current page is page: $page<br>";
}));

//widget routing - fired when url is for example: /something?ord=-title
Burp::get(null, 'ord=(-?)(\w+)', array('as'=>'orderby', function($direction, $field) {
    $direction = ($direction == '-') ? "descending" : "ascending";
    echo "current sorting is on : $field ($direction)<br>";
}))->remove('page');



//strict route  - fired when uri is "/"  or "/pg/2", but not when is "/something/pag/2" ...
Burp::get('^/{page?}$', null, array('as'=>'home', function() {

  echo '<hr>';
  echo '<a href="'.Burp::linkRoute('page',1).'">page 1</a><br>';
  echo '<a href="'.Burp::linkRoute('page',2).'">page 2</a><br>';

  echo '<a href="'.Burp::linkRoute('orderby',array('','title')).'">sort title up</a><br>';
  echo '<a href="'.Burp::linkRoute('orderby',array('-','label')).'">sort label down</a><br>';

  echo '<hr>';
}));

//404 route  - fired only if there are defined strict routes (i.e.: ^/$ or ^.*$)  
//but all uncatched
Burp::missing(function() {
    header("HTTP/1.0 404 Not Found");
    echo '404 - Resource Not Found';
    die;
});

//where all began
Burp::dispatch();

模式

您也可以声明和使用模式

Burp::pattern('number', '(\d+)');
Burp::pattern('page', 'pg/(\d+)');
Burp::pattern('slug', '([a-z0-9-]+)');

Burp::get('articles/{page?}',...
Burp::get('article/{slug}',...

重要:您必须使用括号来定义原子/s

使用 - 在laravel中

此片段应使您了解您可以使用Burp
"定义laravel路由的一些行为"。

此URL:/article/list?ord=-title将触发 "sort" 事件。
此URL:/article/list/pg/2?ord=title将触发 "sort" 和 "page" 事件。

此外,如您所知,laravel分页默认情况下只与类似此的URL一起工作
/articles/list?page=1,但在这个示例中,对于这个控制器,它将通过段来工作
/articles/list/pg/x(无需创建自定义分页类)。

<?php

#in your laravel routes.php add

Route::pattern('pg', 'pg/(\d+)');
Route::get('/articles/list/{pg?}', array('as'=>'art','uses'=>'ArticleController@getList'));

//define some general purpose events on uri-segments
Burp::pattern('pg', 'pg/(\d+)');
Burp::get('{pg}', null, array('as'=>'page', function($page) {
     \Event::queue('page', array($page));
}));
//define some general purpose events on query-string
Burp::get(null, 'ord=(-?)(\w+)', array('as'=>'orderby', function($direction, $field) {
    $direction = ($direction == '-') ? "DESC" : "ASC";
    \Event::queue('sort', array($direction, $field));
}))->remove('page');

Burp::dispatch();


#in your controller 
class ArticleController extends BaseController {

public function __construct()
{
    //starting from a clean query builder
    $this->articles = new Article;
    
    //listen for burp defined events
    \Event::listen('sort', array($this, 'sort'));
    \Event::listen('page', array($this, 'page'));
    
    //flush queued events
    \Event::flush('sort');
    \Event::flush('page');
}

public function sort($direction, $field)
{
    $this->articles = $this->articles->orderBy($field, $direction);
}
public function page($page)
{
    \Paginator::setCurrentPage($page);
}

public function getList()
{
    //paginate
    $articles = $this->articles->paginate(20);
    
    //fix links to use custom defined pagination-uri (instead classic 'page=?')
    $links = $articles->links();
    $links = preg_replace('@href="(.*\?page=(\d+))"@U', 
                          'href="'.Burp::linkRoute('page', '$2').'"', $links);

    return view('articles.list', compact('articles','links'));
}

}

现在您也可以自由更改您的路由器中的URL-语义,例如从查询字符串切换到uri-segments或相反。
您还可以将事件和常见行为移动到基控制器中,然后扩展该控制器