2

我正在使用 CodeIgniter 编写一个应用程序,允许用户注册一个帐户并分配一个他们选择的 URL(URL slug)(例如 domain.com/user-name)。CodeIgniter 具有允许使用正则表达式(链接)的 URL 路由功能。

用户只能注册包含字母数字字符、破折号 (-) 和下划线 (_) 的 URL。这是我用来验证 URL slug 有效性的正则表达式:^[A-Za-z0-9][A-Za-z0-9_-]{2,254}$

我正在使用 url 路由功能将一些 url 路由到我网站上的功能(例如/home -> /pages/index, /activity -> /user/activity),因此用户显然无法注册这些特定的 URL。

我在很大程度上缺乏正则表达式的经验,但我试图编写一个表达式来匹配任何带有字母数字/破折号/下划线的 URL slug,除非它们是以下任何一种:

  1. default_controller
  2. 404_覆盖
  3. 活动

这是我用来尝试将单词与特定条件匹配的代码:

$route['(?!default_controller|404_override|home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254}'] = 'view/slug/$1';

但它没有正确路由。有人可以帮忙吗?(附带问题:在尝试与 URL 匹配时是否有必要在正则表达式中包含^或在正则表达式中?)$

4

3 回答 3

8

好吧,让我们把这个分开。

忽略 CodeIgniter 的保留路由。

您的路线的default_controller404_override部分是不必要的。将路由与请求的 URI 进行比较以查看是否匹配。这两项不太可能出现在您的 URI 中,因为它们是 CodeIgniter 的特殊保留路由。所以让我们忘记他们吧。

$route['(?!home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254}'] = 'view/slug/$1';

捕捉一切!

使用正则表达式,使用圆括号创建一个组()。然后可以使用反向引用检索该组 - 在我们的例子中,$1, $2, etc.位于路线的第二部分。您在尝试排除的第一组项目周围只有一个组,因此它无法正确捕获整个通配符。您自己已经发现了这一点,并在整个项目周围添加了一个组(好!)。

$route['((?!home|activity)[A-Za-z0-9][A-Za-z0-9_-]{2,254})'] = 'view/slug/$1';

展望?!

关于那个主题,第一组周围home|activity实际上并不是一个传统的组,因为?!一开始就使用了。这称为负前瞻,它是一个复杂的正则表达式功能。它被错误地使用:

如果你想匹配一些没有被其他东西跟随的东西,负前瞻是必不可少的。

我可以做的还有很多,但基本上我们一开始并不真正想要或不需要它,所以如果你愿意,我会让你探索。

为了让你的生活更轻松,我建议在路由中分离 home、activity 和其他现有控制器。CodeIgniter 将从上到下查看路由列表,一旦匹配,它就会停止检查。因此,如果您在通配符之前指定您现有的控制器,它们将匹配,并且您的通配符正则表达式可以大大简化。

$route['home'] = 'pages';
$route['activity'] = 'user/activity';
$route['([A-Za-z0-9][A-Za-z0-9_-]{2,254})'] = 'view/slug/$1';

请记住按从最具体到最少的顺序列出您的路线。通配符匹配不如完全匹配(如家庭和活动)那么具体,因此它们应该紧随其后(如下)。

现在,这就是所有复杂的东西。多一点仅供参考。

请记住,括号中的破折号-具有特殊含义。[]如果您想匹配文字破折号,您应该转义它们。

$route['([A-Za-z0-9][A-Za-z0-9_\-]{2,254})'] = 'view/slug/$1';

请注意,您的字符重复最小值/最大值{2,254}仅适用于第二组字符,因此您的用户名必须至少为 3 个字符,最多为 255 个字符。仅供参考,如果您还没有意识到的话。

我看到了你自己对这个问题的回答,这很丑陋。对不起。^和符号在$整个前瞻过程中使用不当(一开始就不应该存在)。它可能对您正在测试它的一些用例“有效”,但它只会在未来给您带来问题和头痛。

希望现在您对正则表达式以及它们在路由过程中的匹配方式有更多的了解。

为了回答你的问题,不,你不应该在你的正则表达式的开头和结尾使用^$——CodeIgniter 会为你添加它。


使用 404,卢克...

此时,您的路线已得到改进,应该可以正常工作。不过,我会把它扔在那里,你可能想考虑使用定义为的控制器/方法404_override来处理你的通配符。这样做的主要好处是您不需要任何路由来引导通配符,或者防止通配符弄乱现有的控制器。你只需要:

$route['404_override'] = 'view/slug';

然后,您的 View::slug() 方法将检查 URI,并查看它是否是有效模式,然后检查它是否作为用户存在(毫无疑问,与您的 slug 方法现在所做的相同)。如果是这样,那么你很高兴。如果没有,那么您将抛出 404 错误。

它可能看起来不那么优雅,但效果很好。如果听起来更适合您,请试一试。

于 2013-04-02T20:26:57.140 回答
0

我对 codeIgniter 并不特别熟悉,但大多数框架路由都基于优先级进行操作。也就是说,应该先定义默认控制器、404等路由。然后您可以简化您的正则表达式以仅匹配 slug。

于 2013-04-02T18:39:12.567 回答
0

好的回答我自己的问题

我似乎想出了一个不同的表达方式:

$route['(^(?!default_controller$|404_override$|home$|activity$)[A-Za-z0-9][A-Za-z0-9_-]{2,254}$)'] = 'view/slug/$1';

我在整个表达式周围添加了括号(我认为这是 CodeIgniter$1在右侧匹配的内容)并添加了行首标识符:^和一堆行尾标识符:$

希望这对以后可能遇到此问题的人有所帮助。

于 2013-04-02T18:49:37.800 回答