如何为.htaccess编写RewriteRules?

时间:2019-05-01 08:10:37

标签: regex apache .htaccess mod-rewrite url-rewriting

我有一个名为otp.php的PHP文件。

URL栏中的URL为

http://localhost/college/otp/MTA=/teacher

应将其视为

http://localhost/college/otp.php?user=MTA=&role=teacher

为此,我在 http://localhost/college/ 中创建了.htaccess文件:

RewriteEngine On    # Turn on the rewriting engine
RewriteRule    ^otp/?$    otp.php    [NC,L]
RewriteRule    ^otp/[A-Za-z-]+/([A-Za-z0-9-]+)/?$    otp.php?user=$1&role=$2    [NC,L]

但是,otp.php文件说:

  

注意:未定义的索引:在C:\ wamp \ www \ college \ otp.php中的角色   11

     

注意:未定义索引:在线的C:\ wamp \ www \ college \ otp.php中的用户   11

更新

URL栏中的URL为

http://localhost/college/otp/MTA/teacher

应视为

http://localhost/college/otp.php?user=MTA&role=teacher

如何解决此问题?

2 个答案:

答案 0 :(得分:2)

  

URL: /college/otp/MTA=/teacher
  Target: /college/otp.php?user=MTA=&role=teacher
  .htaccess: /college/.htaccess

RewriteRule    ^otp/[A-Za-z-]+/([A-Za-z0-9-]+)/?$    otp.php?user=$1&role=$2    [NC,L]

您的RewriteRule 模式需要稍作修改以匹配示例URL,因为它目前在=中的MTA=上失败。 (尽管我刚刚注意到,对您问题的“更新”没有在URL中显示=?)还需要 capture 捕获此模式,以使{{1 }}捡起来。

因此,以上指令应显示为:

$1

这假定 RewriteRule ^otp/([A-Za-z-]+=)/([A-Za-z0-9-]+)/?$ otp.php?user=$1&role=$2 [NC,L] 总是出现在路径段的末尾,如您最初的示例所示(如果可以出现在任何地方,请将其包括在字符类中,尽管这可能是一个有点混乱)。可能不需要=标志,除非您还需要允许使用NC的混合大小写版本(不可取)。您已经在正则表达式中允许混合大小写。

UPDATE#1::似乎第二个路径段是base64编码的字符串/整数。为此,您将需要在正则表达式中包含数字,并且可能有0、1或2个尾随otp字符。也不需要匹配连字符。例如:

=

但是,您似乎正在遇到的另一个问题(实际上是您正在“看到”的问题)是与MultiViews(mod_negotiation的一部分)发生冲突。为了使上面的mod_rewrite指令起作用(实际上,可以执行任何操作),需要禁用此功能。如果您没有在 RewriteRule ^otp/([A-Za-z0-9]+={0,2})/([A-Za-z0-9-]+)/?$ otp.php?user=$1&role=$2 [NC,L] 中启用此功能,请通过在.htaccess文件顶部添加以下内容来禁用它:

.htaccess

如果启用了MultiViews,则当您请求Options -MultiViews (存在具有相同 basename 的文件时,该文件也将返回适当的mime类型)mod_negotiation发出{{ 1}}。这里的问题是发生在之前 mod_rewrite,因此otp最终在没有任何URL参数的情况下被调用。


旁边:

您的代码不应生成这些“未定义索引”通知。由于这实际上是“用户提供的数据”,因此您应该在脚本中进行检查。例如:

otp.php
otp.php

请注意,Apache不支持行尾注释,因此您应该从第一行中删除$role = isset($_GET['role']) ? $_GET['role'] : null; 文本。 (但是,行尾注释似乎“有效”,这与Apache指令的一般工作方式只是巧合,否则它们将导致500个内部服务器错误。)


UPDATE#2:

  

如果URL栏上有RewriteEngine On # Turn on the rewriting engine ,可以将其更改为# Turn on the rewriting engine吗?

是的,可以这样做。尽管我假设http://localhost/college/otp.php?user=MTA=&role=teacher应该出现在两个地方? (您在源中有http://localhost/college/otp/MTA/teacher,在目标中有MTA=,这大概会破坏base64编码吗?)我假设您已经在内部链接到正确的URL,这仅是为了避免流浪请求(搜索引擎,反向链接等?)

您可以在上述重写之前实施外部重定向,请注意不要重定向已重写的URL并触发重定向循环。例如:

MTA=

这基本上是与内部重写(在MTA文件中稍后出现)相反的。根据{{​​1}}环境变量进行检查的条件确保了它仅触发直接请求,而不触发重写请求。

请注意,由于这是外部重定向,因此您需要在 substitution 参数中包含相对于根的URL路径。即。包括RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteCond %{QUERY_STRING} ^user=([A-Za-z0-9]+={0,2})&role=([A-Za-z0-9-]+) RewriteRule ^(otp)\.php$ /college/$1/%1/%2 [QSD,R=302,L] 子目录。 (或者,您可以使用相对的替代并设置.htaccess-尽管只有在具有多个这些指令的情况下才这样做。)

REDIRECT_STATUS是对/college 模式的反向引用(即始终为RewriteBase),而$1RewriteRule是反向引用到之前的 CondPattern ,即分别是otp%1 URL参数的值。

%2标志(Apache 2.4+)从请求中丢弃原始查询字符串。

答案 1 :(得分:0)

This tool可以帮助您为RewriteRules编写正确的表达式。也许,这种表达会给您一个想法,问题可能出在哪里:

(.*otp)\/([A-Za-z0-9-]+=)\/([A-Za-z0-9-]+)

enter image description here

RegEx描述图

link帮助您可视化RewriteRule的表达式:

enter image description here

然后,您可以编写一个RewriteRule,也许类似于:

<IfModule mod_rewrite.c>
    RewriteEngine On    # Turn on the rewriting engine
    RewriteCond %{HTTP_HOST} localhost  [NC]
    RewriteRule    (.*otp)\/([A-Za-z0-9-]+=)\/([A-Za-z0-9-]+)  $1.php?user=$2&role=$3  [NC,L]
</IfModule>

每次修改.htaccess文件时,您可能希望清除浏览器历史记录。