Htaccess /用户名重写与现有映射文件冲突

Htaccess /username rewrite conflict with existing mapped files

我制作了一个 .htaccess 文件来将 /username 重写为 /profile.php?=username

这是我的 htaccess 文件

Options All -Indexes

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9_-]+)$ /profile.php?username= [QSA,L]

问题是同一级别的其他文件被跳过,除非我添加了它们的 .php 扩展名,这很糟糕。 如果该文件存在,我可以阻止 /username 重写,并且还可以进行另一次重写以使 URL 没有文件扩展名吗?

您可以按给定顺序保留这 2 个规则:

Options All -Indexes -MultiViews
RewriteEngine On

## To internally rewrite /dir/file to /dir/file.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ .php [L]

## for user profile
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([\w-]+)/?$ profile.php?username= [QSA,L]

为此关闭 Apache 的 -MultiViews(内容协商服务)很重要。

@MrWhite nothing for now, i just want to stop rewrite when file exist

这些规则可以协同工作。如果你检查目标 .php 文件是否存在 before 重写请求(在你的无扩展名 URLs 上) - 你应该 - 那么你不需要对将请求重写为 profile.php.

的现有规则应用相同的文件系统检查

例如:

# Append ".php" if request file without extension and target file exists
RewriteCond %{DOCUMENT_ROOT}/.php -f
RewriteRule ^([^.]+[^/])$ .php [L]

# Rewrite user profiles (directory check is optional)
#RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9_-]+)$ profile.php?username= [QSA,L]

我假设您的 URL 不包含点(这自然避免了必须对以文件扩展名结尾的请求进行例外处理)。正则表达式 ^([^.]+[^/])$ 匹配不包含点且不以斜杠结尾的 URL(即目录以斜杠结尾)。

文件系统检查相对昂贵,因此最好保持在最低限度(或尽可能完全避免)。在附加“.php”扩展名的规则中,在检查请求之前不需要检查请求没有映射到目录]does 在附加 .php 时映射到文件,这些检查是相互包含的。 (但如果目录确实存在,那么该文件将无法访问 - 捕获 22。)

同样,没有必要检查 user-profile URL 没有映射到一个文件,除非你也有没有文件扩展名的文件(不太可能但最好如果你这样做,无论如何都会避免)。

甚至 user-profile URL 上的目录检查也值得商榷。仅当您需要能够直接访问根目录之外的子目录时才需要这样做。

有了这组有限的规则,是否启用 MutliViews 并不重要。 (尽管最佳实践会规定应在此处禁用 MultiViews,以避免将来发生冲突。)启用 MultiViews 的效果仅意味着附加 .php 文件扩展名的第一条规则被绕过(不是必需的)。但是启用 MultiViews 本质上可以在 everything.

上启用无扩展 URLs

考虑重组您的 user-profile URLs

但是,您的 user-profile URL 结构存在一个根本性的“问题”——即它们确实与实际文件请求“冲突”。实际的文件请求自然会优先,但这意味着您不能让 usernames 恰好与根目录中的文件匹配 - 因为用户配置文件将无法访问。当 creating/updating 个用户帐户时需要执行此检查。

最好通过创建一个“唯一”URL 来避免这种歧义并允许所有用户名(也可以匹配根文件)。例如。 /user/<username>。这也完全避免了必须执行目录检查。例如:

# Rewrite user profiles (directory check is not required)
RewriteRule ^user/([a-zA-Z0-9_-]+)$ profile.php?username= [QSA,L]