将 URI 与当前 URL 匹配


Match URI with current URL

我做了一个简单的路由器系统,我正在尝试将当前 uri 与 url 匹配,请检查:

$listUri = "transaction/.+";
$uri = isset($_REQUEST['uri']) ? $_REQUEST['uri'] : '/'; // transaction/19-02-2016
if(preg_match("#^$listUri$#", $uri)) 
{
    echo "done!";
}

现在我正确地看到了echo "done!";,但假设我说我有这种情况:

$listUri = "transaction/.+";
$uri = isset($_REQUEST['uri']) ? $_REQUEST['uri'] : '/'; // transaction/19-02-2016/SomeWrongUrlRequest?
if(preg_match("#^$listUri$#", $uri)) 
{
    echo "done!";
}

echo "done!"也被打印出来...这很糟糕。我已经像这样映射了 url:"/transaction/.+";其中 .+ 是参数19-02-2016它之后,如果.+后有更多内容,则请求一定不正确。

更新:

换句话说:

$uri     =>  "transaction/19-02-2016/SomeWrongUrlRequest"
$listUri =>  "transaction/.+"

如果$listUritransaction/.+我必须有这个:

`transaction/19-02-2016/` (correct with or without final slash)
`transaction/19-02-2016/SomeWrongUrlRequest` (incorrect - there is only a .+ it would have been correct if $listUri had been: transaction/.+/SomeWrongUrlRequest)

所以我必须与等于当前 URI 的内容匹配

据我所知,您正在(或已经制作)路由系统。

我觉得这里的问题不会通过找到正确的正则表达式来解决,但我认为可以通过找到正确的方法来创建路由系统来解决。

您需要有某种策略来确定在命中特定 URL 时应执行哪个路由。让我的自我清晰假设程序员是否希望使用您的路由器进行以下场景:

  1. 网址 -> /user/.+

    结果 -> 嘿,客人!

  2. 网址 -> /user/.+/{regex_matching_username}

    结果 -> 嘿用户名!

现在,如果 URL 像 /user/free/john,路由系统将如何决定转到哪个 URL?与您的情况类似,URL #1 仍将与此 URL 匹配,并且它会一直说Hey Guest! .

因此

,我们需要定义执行路由的优先级,这可以是定义它们的顺序(因此路由存储在堆栈或队列中),或者可能是分配给每个路由的某种优先级值(优先级队列中的路由)。

在与ZF1和Laravel合作过之后,我可以谈谈他们采取的方法:

ZF1 明确提到

注意:反向匹配

路线以相反的顺序匹配,因此使 确保首先定义最通用的路由。

因此,如果您在 ZF1 中

定义一个通用路由(如 ZF1 中最后一个中的 user/.+),则所有其他路由都将不起作用。

在 Laravel 中,虽然我无法在文档中找到它,但它们似乎遵循定义路线的顺序。我正在粘贴一个例子,以防您想看看。

// matches a url that has username starting with a
Route::get('user/{name}', ['as' => 'profile', function()
{
    //
    echo ' I am specific';
}])->where('name', 'a.+');;
Route::get('user/{ame}', ['as' => 'profile', function()
{
    //
    echo ' I am  generic';
}])->where('ame', '.+');

网址 -> #/user/abc

输出 -> 我是特定的

网址 -> #/user/bbc

输出 ->我是通用的

事情按预期工作,但现在颠倒了特定和通用路由的顺序

Route::get('user/{ame}', ['as' => 'profile', function()
{
    //
    echo ' I am  generic';
}])->where('ame', '.+');
// matches a url that has username starting with a
Route::get('user/{name}', ['as' => 'profile', function()
{
    //
    echo ' I am specific';
}])->where('name', 'a.+');;

网址 -> #/user/abc

输出 ->我是通用的

网址 -> #/user/bbc

输出 ->我是通用的

现在,由于通用路由位于顶部,因此两个 URL 都指向相同的输出。

话虽如此,您仍然可以通过在/的基础上分解正则表达式和 URL 来满足具体情况,然后匹配两个字符串的每个非空部分。这在伪代码中可能看起来像这样

将$matcher字符串与当前 URL 匹配

  1. /的基础上爆炸$matcher和$url

  2. 检查两个$matcher和$url的非空部分数量是否相等。

    如果是,请继续执行步骤 3

    如果没有return false $matcher则不匹配

  3. 使用preg_match检查$matcher的每个部分以及$url的每个部分。

    如果所有零件都匹配return true $matcher则路线正确

    如果任何一个部分不匹配return false $matcher则不是Corrct路线。

我希望这一切都有意义:)

更新:为上面提到的伪代码添加一些代码

function matchRoute($url, $pattern) {
        // get parts of the url
        $urlParts = array_filter(explode('/', $url));
        $patternParts = array_filter(explode('/', $pattern)); 
        // match if number of parts are equal
        if (count($urlParts) != count($patternParts)) {
            return false;
        }
        // preg match in a loop
        for ($i = 0 ; $i < count($urlParts); $i++) {
            if(!preg_match('/' . $patternParts[$i] .'/', $urlParts[$i])) {
                return false;
            }
        }
        return true;
}
$testUri = 'transaction/19-02-2016/SomeWrongUrlRequest';
$matchUri = 'transaction/.+';
echo "expected false 'n";
var_dump(matchRoute($testUri, $matchUri));  
echo "expected true 'n";
var_dump(matchRoute('transaction/19-02-2016', $matchUri)); 
echo "expected true 'n";
var_dump(matchRoute('transaction/19-02-2016/', $matchUri));
echo "expected true 'n";
var_dump(matchRoute($testUri, 'transaction/.+/SomeWrongUrlRequest')); 
echo "expected false 'n";
var_dump(matchRoute($testUri, 'transaction/.+/SomeOtherUrlRequest')); 

输出:

expected false 
bool(false)
expected true 
bool(true)
expected true 
bool(true)
expected true 
bool(true)
expected false 
bool(false)

现在上面编写的代码不是最好的解决方案,我可以立即看到的一些问题是:

  1. 您无法再匹配通用路由,因为现在您需要显式定义 URL 将具有的段数

  2. array_filter检查非空值,因此它将排除诸如 /0 之类的部分。(尽管这可以通过使用自定义回调来处理)

如果您确定您的方案已由它填充,请使用上述内容。