Php 将URI与当前URL匹配

Php 将URI与当前URL匹配,php,regex,Php,Regex,我制作了一个简单的路由器系统,并尝试将当前uri与url匹配,检查: $listUri = "transaction/.+"; $uri = isset($_REQUEST['uri']) ? $_REQUEST['uri'] : '/'; // transaction/19-02-2016 if(preg_match("#^$listUri$#", $uri)) { echo "done!"; } 现在我正确地看到了echo“done!”但是假设我把我的情况: $listUri

我制作了一个简单的路由器系统,并尝试将当前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/.+"
如果
$listUri
事务/+
我必须有:

`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时应该执行哪个路由。让我自己明白 假设程序员希望使用路由器执行以下场景:

  • URL->
    /user/+

    结果->嘿,客人

  • URL->
    /user/+/{regex\u matching\u username}

    结果->嘿用户名

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

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

    通过与ZF1和Laravel的合作,我可以了解他们采取的方法:

    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', '.+');
    
    Url->#/user/abc

    输出->我是特定的

    Url->#/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.+');;
    
    Url->#/user/abc

    输出->我是通用的

    Url->#/user/bbc

    输出->我是通用的

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

    如上所述,您仍然可以通过基于
    /
    分解正则表达式和URL,然后匹配两个字符串的每个非空部分来满足特定情况。这在psuedo代码中可能是这样的

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

  • 根据
    /

  • 检查$matcher和$url的非空部分的数量是否相等

    如果是,继续执行步骤3

    如果否
    返回false
    $matcher不匹配

  • 使用preg_match检查$matcher的每个部分和$url的每个部分

    如果所有零件都匹配
    返回true
    $matcher是正确的路径

    如果任何一个零件不匹配
    返回false
    $matcher不是正确的路径

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

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

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

  • 您无法再匹配常规路由,因为现在需要显式定义URL将包含的部分数量

  • array\u filter
    检查非空值,以便排除
    /0
    等部分。(尽管这可以通过使用自定义回调来处理)


  • 如果您确信您的场景已被它填满,请使用上述选项。

    从我看到您正在制作(或已经制作)路由系统

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

    您需要有某种策略,该策略将确定在命中特定URL时应该执行哪个路由。让我自己明白 假设程序员希望使用路由器执行以下场景:

  • URL->
    /user/+

    结果->嘿,客人

  • URL->
    /user/+/{regex\u matching\u username}

    结果->嘿用户名

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

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

    通过与ZF1和Laravel的合作,我可以了解他们采取的方法:

    ZF1明确提到

    注:反向匹配

    路线是按相反顺序匹配的,所以请 确保首先定义最通用的路由

    因此,如果在ZF1的最后一个中定义了一个通用路由,如
    user/+
    ,那么所有其他路由都将无法工作

    在拉雷维尔,虽然我在文档中找不到它,但它们似乎遵循了路径定义的顺序
    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)