简体   繁体   English

将URI与当前URL匹配

[英]Match URI with current URL

I made a simple router system and I'm trying to match the current uri with an url, check: 我制作了一个简单的路由器系统,并尝试将当前的uri与网址进行匹配,请检查:

$listUri = "transaction/.+";
$uri = isset($_REQUEST['uri']) ? $_REQUEST['uri'] : '/'; // transaction/19-02-2016

if(preg_match("#^$listUri$#", $uri)) 
{
    echo "done!";
}

now I see correctly the echo "done!"; 现在我可以正确看到echo "done!"; but suppose that I put that I've this situation: 但是假设我有这种情况:

$listUri = "transaction/.+";
$uri = isset($_REQUEST['uri']) ? $_REQUEST['uri'] : '/'; // transaction/19-02-2016/SomeWrongUrlRequest?

if(preg_match("#^$listUri$#", $uri)) 
{
    echo "done!";
}

the echo "done!" echo "done!" is also printed... and this is bad. 也被打印...这很糟糕。 I've mapped the url like so: "/transaction/.+"; 我已经将网址映射为: "/transaction/.+"; where .+ is the parameter 19-02-2016 after it, if there is more content after the .+ the request must be incorrect. 其中.+是其后的参数19-02-2016 ,如果.+之后有更多内容,则请求必须不正确。

UPDATE: 更新:

In other word: 换句话说:

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

if $listUri have transaction/.+ I must have this: 如果$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)

so I have to make the match with the contents equal to the current URI 所以我必须使内容与当前URI匹配

From what I see you are making(or already made) a routing system. 从我看来,您正在制作(或已经制作)路由系统。

But I feel that the problem here won't be fixed by finding the correct regular expression but I think would be solved by finding the correct approach to create your routing system. 但是我觉得这里的问题不能通过找到正确的正则表达式来解决,但是我认为可以通过找到创建路由系统的正确方法来解决。

You need to have some sort of a policy which will determine which route should be executed when a particular URL is hit. 您需要具有某种策略,该策略将确定在命中特定URL时应执行哪个路由。 To make my self clear Say if a programmer wants the following scenario using your router: 明确说明如果程序员想要使用您的路由器的以下情况:

  1. URL -> /user/.+ 网址-> /user/.+

    result -> Hey Guest! 结果->嗨,客人!

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

    result -> Hey Username! 结果->嗨,用户名!

Now how will the routing system decide which URL to go to if the URL is like /user/free/john ? 现在,如果URL类似于/user/free/john ,路由系统将如何决定要转到哪个URL? Similar to your case, the URL #1 will still match this URL and it will keep saying Hey Guest! 与您的情况类似,URL#1仍将与此URL匹配,并且会一直说“ Hey Guest! .

So we need to define a priority with which a route should be executed, this can be the order in which they are defined(so routes are stored in a stack or a queue) or maybe some sort of a priority value assigned to each route(routes in a priority queue) . 因此,我们需要定义执行路由的优先级,这可以是定义路由的顺序(路由被存储在堆栈或队列中)或分配给每个路由的某种优先级值(优先级队列中的路由)。

Having worked with ZF1 and Laravel, I can tell about the approaches they take: 与ZF1和Laravel一起工作后,我可以介绍他们采取的方法:

ZF1 clearly mentions that ZF1明确提到

Note: Reverse Matching 注意:反向匹配

Routes are matched in reverse order so make sure your most generic routes are defined first. 路由以相反的顺序匹配,因此请确保首先定义最通用的路由。

So if you define a generic route like user/.+ in the last in ZF1, all of your other routes won't work. 因此,如果您在ZF1的最后一个中定义了类似于user/.+类的通用路由,则所有其他路由都将不起作用。

In Laravel although I wasn't able to find it in the docs, but they seem to follow the order in which the route was defined. 在Laravel中,虽然我无法在文档中找到它,但是它们似乎遵循定义路线的顺序。 I am pasting in an example just in case you would like to have a look. 我粘贴一个示例,以防万一您想看看。

// 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 网址->#/ user / abc

Output -> I am specific 输出->我具体

Url -> # /user/bbc 网址->#/ user / bbc

Output -> I am generic 输出->我很普通

Things work as expected, but now reversing the order of specific and generic routes 事情按预期工作,但现在反转了特定和通用路线的顺序

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 网址->#/ user / abc

Output -> I am generic 输出->我很普通

Url -> # /user/bbc 网址->#/ user / bbc

Output -> I am generic 输出->我很普通

Now as a generic route was at top both the URLs lead to the same output. 现在,由于通用路由位于顶部,因此两个URL都导致相同的输出。

Having said above, you may still satisfy your specific case by breaking down regular expression as well as the URL on the basis of / and then matching each non-empty part of both the strings. 上面已经说过了,您仍然可以通过基于/分解正则表达式和URL,然后匹配两个字符串的每个非空部分来满足您的特定情况。 This in psuedo-code might look like this 这在伪代码中可能看起来像这样

Matching $matcher string with the current URL 将$ matcher字符串与当前URL匹配

  1. Explode the $matcher as well as $url on the basis of / 根据/展开$ matcher和$ url

  2. Check if the number of non-empty parts of both $matcher & $url are equal. 检查$ matcher和$ url的非空部分的数量是否相等。

    if yes continue to step 3 如果是,请继续执行步骤3

    if no return false $matcher doesn't match 如果没有return false $ matcher不匹配

  3. check each part of $matcher with each part of $url using preg_match. 使用preg_match将$ matcher的每个部分与$ url的每个部分进行检查。

    if all parts match return true $matcher is correct route 如果所有零件都匹配,则return true $ matcher是正确的路线

    if any one part doesn't match return false $matcher is not the corrct route. 如果任何一部分不匹配,则return false $ matcher不是正确的路由。

I hope all this made sense :) 我希望所有这些都是有道理的:)

Update: Adding some code for the psuedocode mentioned above 更新:为上述伪代码添加一些代码

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')); 

Output: 输出:

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

Now the code written above would not be the best solution for this, some of the issues I can see right away are : 现在,上面编写的代码将不是最好的解决方案,我立即可以看到的一些问题是:

  1. You can no longer match generic routes because now you need to explicitly define the number of parts a URL will have 您无法再匹配通用路由,因为现在您需要显式定义URL将具有的部分数量

  2. array_filter checks for non-empty value so it will exclude a part such as /0 . array_filter检查非空值,因此它将排除诸如/0类的部分。 (although this can be handled by using a custom callback) (尽管可以通过使用自定义回调来处理)

Use the above if you are sure your scenarios are fullfilled by it. 如果您确定自己的方案已被满足,请使用上面的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM