动态地将RewriteBase设置为当前文件夹路径

Eel*_*iya 20 regex apache .htaccess mod-rewrite url-rewriting

有没有办法将RewriteBase设置为相对于主机根目录的当前文件夹(.htaccess文件所在的文件夹)?

我有一个CMS,如果我将它移动到我的主机中的目录,它将无法工作,除非我将RewriteBase设置为相对于主机根目录的路径.我希望我的CMS只能使用复制和粘贴,而无需更改htaccess中的任何代码.

更新:

例如:

webroot

 - sub_directory
 - cms
 - .htaccess
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我应该写在htaccess: RewriteBase /

如果我在sub_directory中移动htaccess,我应该将RwriteBase更改为:

RewriteBase /sub_directory/

所以我想要类似的东西

RewriteBase /%{current_folder}/

anu*_*ava 39

这是一种可以RewriteBase在环境变量中获取的方法,然后可以在其他重写规则中使用它:

RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]
Run Code Online (Sandbox Code Playgroud)

然后您可以%{ENV:BASE}在您的规则中使用来表示RewriteBase.

说明:

这条规则的工作原理是比较REQUEST_URI到URL路径RewriteRule看,这是REQUEST_URI与领先的RewriteBase剥夺.区别在于RewriteBase并且被投入%{ENV:BASE}.

  • 在一个RewriteCond中,LHS(测试字符串)可以使用反向参考变量例如$1,$2OR %1,%2等,但RHS侧即条件字符串不能使用这些$1,$2OR %1,%2变量.
  • 在RHS条件部分内部,我们可以使用的只有后向引用是内部反向引用,即我们在这种情况下捕获的组.他们用表示\1,\2等等.
  • 在第RewriteCond一个被捕获的组是(.*?/).它将由内部反向引用`\ 1表示.
  • 正如你可以指出的那样,这个规则基本上是RewriteBase通过比较%{REQUEST_URI}和动态找到的$1.%{REQUEST_URI}将是相同示例URI 的示例/directory/foobar.php和示例.是在第一个被捕获的组或.对于我们的示例,它将填充或使用稍后在设置env变量时使用的值,即.$1foobar.php^(.*?/)(.*)::\2$%1\1%1\1/directory/%{BASE}E=BASE:%1

  • 五年多后的今天,你可能拯救了我的理智。谢谢你!这开始吞噬我的灵魂! (2认同)

Dak*_*san 9

我认为,已接受的解决方案对我不起作用,但这确实有效:http : //www.zeilenwechsel.de/it/articles/8/Using-mod_rewrite-in-.htaccess-files-without-knowing-the-RewriteBase .html

长话短说:

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$
RewriteRule ^.*$ %2index.php [QSA,L]
Run Code Online (Sandbox Code Playgroud)


apl*_*lum 5

anubhava 的回答Jon Lin的回答的基础上,这是我刚刚为自己想出的(还没有在生产中使用它,也没有对此进行过广泛的测试)。

让我们使用这个示例 URL,其中 .htaccess 在 current_folder 中:

http://localhost/path_to/current_folder/misc/subdir/file.xyz

文件系统: /var/www/webroot/path_to/current_folder/.htaccess

Options +FollowSymLinks
RewriteEngine On
RewriteBase /

RewriteCond %{ENV:SUBPATH} ^$  # Check if variable is empty. If it is, process the next rule to set it.
RewriteRule ^(.*)$ - [ENV=SUBPATH:$1]
# SUBPATH is set to 'misc/subdir/file.xyz'

RewriteCond %{ENV:CWD} ^$
RewriteCond %{ENV:SUBPATH}::%{REQUEST_URI} ^(.*)::(.*?)\1$
RewriteRule ^ - [ENV=CWD:%2]
# CWD is set to '/path_to/current_folder/'

RewriteCond %{ENV:FILENAME} ^$
RewriteCond %{REQUEST_URI} ^.*/(.*)$
RewriteRule ^ - [ENV=FILENAME:%1]
# FILENAME is set to 'file.xyz'

# Check if /var/www/webroot/path_to/current_folder/misc/subdir/file.xyz exists.
# -f checks if a file exists, -d checks for a directory.
# If it exists, rewrite to /path_to/current_folder/misc/subdir/file.xyz and stop processing rules.
RewriteCond %{ENV:SUBPATH} ^.+$  # Ensure SUBPATH is not empty
RewriteCond %{DOCUMENT_ROOT}%{ENV:CWD}%{ENV:SUBPATH} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{ENV:CWD}%{ENV:SUBPATH} -d
RewriteRule ^.*$ %{ENV:CWD}%{ENV:SUBPATH} [END]

# Check if /var/www/webroot/path_to/current_folder/file.xyz exists.
# If it exists, rewrite to /path_to/current_folder/file.xyz and stop processing rules.
RewriteCond %{ENV:FILENAME} ^.+$
RewriteCond %{DOCUMENT_ROOT}%{ENV:CWD}%{ENV:FILENAME} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{ENV:CWD}%{ENV:FILENAME} -d
RewriteRule ^.*$ %{ENV:CWD}%{ENV:FILENAME} [END]

# Else, rewrite to /path_to/current_folder/index.html and stop processing rules.
RewriteRule ^.*$ %{ENV:CWD}index.html [END]
Run Code Online (Sandbox Code Playgroud)

您可以通过查看发生了什么事为自己的细节LogLevel alert rewrite:trace6httpd.confApache中,然后看着你error.log

下面是对以下两行的更多说明,我仍然觉得这有点令人困惑。

RewriteCond %{ENV:SUBPATH}::%{REQUEST_URI} ^(.*)::(.*?)\1$
RewriteRule ^ - [ENV=CWD:%2]
Run Code Online (Sandbox Code Playgroud)

首先,双冒号::不是任何类型的运算符;它只是一个任意的分隔符。在RewriteCond膨胀的TestString%{ENV:SUBPATH}::%{REQUEST_URI}以下内容:

misc/subdir/file.xyz::/path_to/current_folder/misc/subdir/file.xyz

然后我们的 CondPattern ^(.*)::(.*?)\1$

  1. ^(.*):: 火柴 misc/subdir/file.xyz::
  2. \1 是第一个捕获组, misc/subdir/file.xyz
  3. (.*?)\1$ 变成 (.*?)misc/subdir/file.xyz$
  4. 因此,我们的第二个捕获组(.*?)匹配剩余的/path_to/current_folder/

我们RewriteRule设置CWD%2,这是 CondPattern 的第二个捕获组。