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]

文字点不需要在 TestStringRewriteCond 指令的第一个参数)中转义,因为这是一个“字符串”,而不是正则表达式.这里不需要 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 错误响应: