使用(转义或未转义)点的htaccess内部错误

时间:2012-12-17 12:46:30

标签: php regex .htaccess infinite-loop optional-parameters

也许我做的事情很愚蠢,但我无法摆脱htaccess的问题。

我正在尝试匹配文档站点中的函数名称,并且我遇到了我无法理解的错误。我必须指出,我(我想)知道正则表达式转义,我知道点和反斜杠点是什么意思。

所以:我想允许所有这些:

example.com/foofunction
example.com/foofunction.php
example.com/function.foofunction
example.com/function.foofunction.php

这些是我尝试过的。那些导致错误的东西被误解了,所以非常感谢任何可以向我解释的人:

^function\.([A-Za-z0-9_-]+)(\.php)?$ - >有效,但function.必须

^(function\.)?([A-Za-z0-9_-]+)(\.php)?$ - >内部错误......好吧,让我们不要逃避点,最后,它会匹配任何角色并且会起作用......

^(function.)?([A-Za-z0-9_-]+)(\.php)?$ - >内部错误呢!好吧,只是为了尝试,在有条件的外面点?

^(function)?\.([A-Za-z0-9_-]+)(\.php)?$ - >工作,好吧,但它强制点。顺便说一句,更疯狂的事情:

^(function)?.([A-Za-z0-9_-]+)(\.php)?$ - >如果dot没有被转义(想象我想允许任何字符),内部错误也是如此。现在我将尝试单独制作点可选

^(function)?(\.)?([A-Za-z0-9_-]+)(\.php)?$ - >内部错误,我疯了......

这些是我到目前为止的尝试,我将尝试使用可选的lookbehind并使用结果进行更新...无论如何,我很想了解这些正则表达式导致内部错误。

如果有人知道“htaccess特殊正则表达式异常”参考或类似的东西我必须阅读,那将是非常好的。

先谢谢你们所有人。

1 个答案:

答案 0 :(得分:3)

对于除实际功能名称之外的所有内容,请使用非捕获组:

^(?:function\.)?([A-Za-z0-9_\-]+)(?:\.php)?$

让我们打破这一点:

^                   # assert start of string
  (?:function\.)?   # optionally allow the string "function."
  ([A-Za-z0-9_\-]+) # capture the function name - this could be shortened to ([-\w]+)
  (?:\.php)?        # optionally allow the string ".php"
$                   # assert end of string

所以你的.htaccess看起来(我猜)是这样的:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(?:function\.)?([A-Za-z0-9_\-]+)(?:\.php)?$ doc.php?functionname=$1 [L,QSA]

重要要点以及此案例中的实际解决方案:

必须使用RewriteCond和(通常)[L]标记的合理组合,以确保规则只匹配一次。

mod_rewrite的行为方式略有反直觉,并不总是显而易见:它一直反复运行规则,直到没有更多的匹配。所以,假设我使用上面列出的规则:

RewriteRule ^(?:function\.)?([A-Za-z0-9_\-]+)(?:\.php)?$ doc.php?functionname=$1

...我向此规则提供了输入function.myfunc.php。首先,它将被重写为:

doc.php?functionname=myfunc

但是,下次它会再次匹配。它将被重写为:

doc.php?functionname=doc

...这将一直持续发生,直到达到MaxRedirects并且Apache将抛出错误 - 您将在客户端看到它作为500响应。

解决方案取决于您的确切用例,但一个常见的解决方案(我上面使用的解决方案)是在应用重写规则之前检查所请求的文件是否存在。通过执行此操作,在第二次迭代时,将不会应用规则,并且将允许请求进行进一步处理。

[L]标志也常用(过)使用 - 这会导致重写过程的当前迭代停止,并在下一次迭代时重新开始。它实际上与continue对PHP中的循环做了同样的事情。

从Apache 2.3开始,一个更有用的标志(对于这种情况)可用 - [END]。这给出了大多数人期望[L]的行为,它导致重写过程立即停止而没有进一步的迭代,比如PHP中的break构造。使用这将意味着不再需要上述RewriteCond。但是,由于这仅适用于2.3+,因此无法安全使用,除非您确定它将在您运行的每个环境中都可用。