Mod-使用 PHP 重写在 htaccess 中不起作用
Mod-Rewrites Not Working in htaccess with PHP
我已经从我的其他站点复制了 htaccess 文件(所有这些站点都在同一台服务器上)并且只更改了需要更改的 URL(即从非 www 重定向到 www 时),但它只是不起作用。
例如,我将 /index.php
更改为 /index
失败,但 /example.html
确实在 /example
有效,这让我认为这是 [= 的问题39=] 或 htaccess 与 PHP?
我已经请我的几个朋友看了一下,他们不明白为什么会这样。
我的 .htaccess 文件是:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.example.com [NC]
RewriteRule ^(.*)$ https://example.com/ [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ .php [NC,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ .html [NC,L]
我的 VirtualHost 是:
<VirtualHost *:443>
ServerName example.com
ServerAlias localhost
DocumentRoot "/var/www/example.com/public_html"
<Directory "/var/www/example.com/public_html">
Options +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
<VirtualHost *:80>
ServerName example.com
ServerAlias localhost
DocumentRoot "/var/www/example.com/public_html"
<Directory "/var/www/example.com/public_html">
Options +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =example.com [OR]
RewriteCond %{SERVER_NAME} =localhost
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
ServerAlias localhost
DocumentRoot "/var/www/example.com/public_html"
<Directory "/var/www/example.com/public_html">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
<VirtualHost *:80>
ServerName www.example.com
ServerAlias localhost
DocumentRoot "/var/www/example.com/public_html"
<Directory "/var/www/example.com/public_html">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =www.example.com [OR]
RewriteCond %{SERVER_NAME} =localhost
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
(我已经用 example.com 替换了域——它们与 htaccess 或 vhost 中的域不同。)
.htaccess 当然没有被禁用,如果我进行重定向它就可以正常工作,例如:
Redirect 301 /test https://example.com/test
和...
root@server:~# a2enmod rewrite
Module rewrite already enabled
我的网络服务器以前从未遇到过任何类似的问题,我真的很困惑为什么会出现这个问题。
您实际上没有说明发生了什么(错误?响应代码?等),但是,关于无扩展 URLs,您的配置存在一些问题。
Options +Indexes +Includes +FollowSymLinks +MultiViews
您在服务器配置中明确启用了 MultiViews
,但是,这将与 .htaccess
中试图附加文件扩展名的 mod_rewrite 指令冲突。 MultiViews
需要 禁用 。例如。 -MultiViews
(不是 +
)。
但是,出于某种原因,您还启用了目录索引 (Indexes
) 和 server-side-includes (Includes
)?这是故意的吗?而且,令人困惑的是,您为 www 子域设置的选项与为域顶点设置的选项不同?
在 vHost 容器中,通常最好只声明所需的选项。例如:
Options FollowSymLinks
(这自然会通过不设置来禁用 MultiViews。)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ .php [NC,L]
.htaccess
中用于附加文件扩展名的这些 mod_rewrite 指令并不严格正确。虽然它们可能适用于您的“有效”URLs,但恶意用户可以构建 /index/<anything>
形式的 URL,否则会映射到 /index.php
,以触发 rewrite-loop(500 内部服务器错误)*1.
应该这样写(假设您的 .htaccess
文件在文档根目录中)以避免此漏洞:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/.php -f
RewriteRule (.*) .php [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/.html -f
RewriteRule (.*) .html [L]
文字点不需要在 TestString(RewriteCond
指令的第一个参数)中转义,因为这是一个“字符串”,而不是正则表达式.这里不需要 NC
标志。
如果您的 URL 本身不包含“文件扩展名”,那么您可以通过不测试看起来已经具有文件扩展名的 URL 来优化上述内容。例如:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}.php [L]
negated 正则表达式 !\.\w{2,4}$
只匹配 URL 不包含 - 看起来像 - 文件扩展名。此上下文中的文件扩展名是 URL-path 末尾的 2 到 4 letters/digits 序列,前面有一个点。
*1 请参阅 my answer 以了解以下 ServerFault 问题,该问题更详细地介绍了潜在的 rewrite-loop 并产生 500 错误响应:
我已经从我的其他站点复制了 htaccess 文件(所有这些站点都在同一台服务器上)并且只更改了需要更改的 URL(即从非 www 重定向到 www 时),但它只是不起作用。
例如,我将 /index.php
更改为 /index
失败,但 /example.html
确实在 /example
有效,这让我认为这是 [= 的问题39=] 或 htaccess 与 PHP?
我已经请我的几个朋友看了一下,他们不明白为什么会这样。
我的 .htaccess 文件是:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.example.com [NC]
RewriteRule ^(.*)$ https://example.com/ [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ .php [NC,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ .html [NC,L]
我的 VirtualHost 是:
<VirtualHost *:443>
ServerName example.com
ServerAlias localhost
DocumentRoot "/var/www/example.com/public_html"
<Directory "/var/www/example.com/public_html">
Options +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
<VirtualHost *:80>
ServerName example.com
ServerAlias localhost
DocumentRoot "/var/www/example.com/public_html"
<Directory "/var/www/example.com/public_html">
Options +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =example.com [OR]
RewriteCond %{SERVER_NAME} =localhost
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
ServerAlias localhost
DocumentRoot "/var/www/example.com/public_html"
<Directory "/var/www/example.com/public_html">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
<VirtualHost *:80>
ServerName www.example.com
ServerAlias localhost
DocumentRoot "/var/www/example.com/public_html"
<Directory "/var/www/example.com/public_html">
Options +Indexes +Includes +FollowSymLinks +MultiViews
AllowOverride All
Require all granted
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =www.example.com [OR]
RewriteCond %{SERVER_NAME} =localhost
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
(我已经用 example.com 替换了域——它们与 htaccess 或 vhost 中的域不同。)
.htaccess 当然没有被禁用,如果我进行重定向它就可以正常工作,例如:
Redirect 301 /test https://example.com/test
和...
root@server:~# a2enmod rewrite
Module rewrite already enabled
我的网络服务器以前从未遇到过任何类似的问题,我真的很困惑为什么会出现这个问题。
您实际上没有说明发生了什么(错误?响应代码?等),但是,关于无扩展 URLs,您的配置存在一些问题。
Options +Indexes +Includes +FollowSymLinks +MultiViews
您在服务器配置中明确启用了 MultiViews
,但是,这将与 .htaccess
中试图附加文件扩展名的 mod_rewrite 指令冲突。 MultiViews
需要 禁用 。例如。 -MultiViews
(不是 +
)。
但是,出于某种原因,您还启用了目录索引 (Indexes
) 和 server-side-includes (Includes
)?这是故意的吗?而且,令人困惑的是,您为 www 子域设置的选项与为域顶点设置的选项不同?
在 vHost 容器中,通常最好只声明所需的选项。例如:
Options FollowSymLinks
(这自然会通过不设置来禁用 MultiViews。)
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}\.php -f RewriteRule ^(.*)$ .php [NC,L]
.htaccess
中用于附加文件扩展名的这些 mod_rewrite 指令并不严格正确。虽然它们可能适用于您的“有效”URLs,但恶意用户可以构建 /index/<anything>
形式的 URL,否则会映射到 /index.php
,以触发 rewrite-loop(500 内部服务器错误)*1.
应该这样写(假设您的 .htaccess
文件在文档根目录中)以避免此漏洞:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/.php -f
RewriteRule (.*) .php [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/.html -f
RewriteRule (.*) .html [L]
文字点不需要在 TestString(RewriteCond
指令的第一个参数)中转义,因为这是一个“字符串”,而不是正则表达式.这里不需要 NC
标志。
如果您的 URL 本身不包含“文件扩展名”,那么您可以通过不测试看起来已经具有文件扩展名的 URL 来优化上述内容。例如:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}.php [L]
negated 正则表达式 !\.\w{2,4}$
只匹配 URL 不包含 - 看起来像 - 文件扩展名。此上下文中的文件扩展名是 URL-path 末尾的 2 到 4 letters/digits 序列,前面有一个点。
*1 请参阅 my answer 以了解以下 ServerFault 问题,该问题更详细地介绍了潜在的 rewrite-loop 并产生 500 错误响应: