简体   繁体   中英

Mod-Rewrites Not Working in htaccess with PHP

I have copied the htaccess file from my other sites (that all work, and are on the same server) and have only changed URLs that need changing (ie when redirecting from non-www to www), but it simply does not work.

My changing of, for example, /index.php to /index fails, but /example.html does work at /example , which makes me think it's an issue with PHP or htaccess acting with PHP?

I've asked several friends of mine to have a look at it and they cannot understand why it's happening.

My .htaccess file is:

RewriteEngine On

RewriteCond %{HTTP_HOST} ^www.example.com [NC]
RewriteRule ^(.*)$ https://example.com/$1 [L,R=301]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [NC,L] 

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html [NC,L] 

And my VirtualHost is:

<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>

(I've replaced the domain with example.com -- they're not like that in htaccess or the vhost.)

.htaccess is certainly not disabled, if I make a redirect it works just fine, for example:

Redirect 301 /test https://example.com/test

and...

root@server:~# a2enmod rewrite
Module rewrite already enabled

I've never experience any similar issues with my web-server before, and I'm really puzzled as to why the issue is occurring.

You don't actually state what is happening (errors? response codes? etc.), however, there are a few issues with your config with respect to extensionless URLs.

 Options +Indexes +Includes +FollowSymLinks +MultiViews

You are explicitly enabling MultiViews in your server config, however, this is going to conflict with the mod_rewrite directives in .htaccess that attempt to append the file extension. MultiViews needs to be disabled . eg. -MultiViews (not + ).

However, you are also enabling directory indexes ( Indexes ) and server-side-includes ( Includes ) for some reason? Is this intentional? And, rather confusingly, you are setting different options for your www subdomain than for the domain apex?

In the vHost container it is often preferable to state just the options needed. For example:

Options FollowSymLinks

(This naturally disables MultiViews by not setting it.)

 RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}\\.php -f RewriteRule ^(.*)$ $1.php [NC,L]

These mod_rewrite directives in .htaccess to append the file extension are not strictly correct. Whilst they may work for your "valid" URLs, a malicious user could construct a URL of the form /index/<anything> that would otherwise map to /index.php , to trigger a rewrite-loop (500 Internal Server Error) . .

These should be written like this instead (assuming your .htaccess file is in the document root) to avoid this vulnerability:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule (.*) $1.html [L]

The literal dot does not need to be escaped in the TestString (first argument to the RewriteCond directive) since this is a "string", not a regex. The NC flag is not required here.

If your URLs themselves don't contain "file extensions" then you can optimise the above by not testing URLs that already look like they have a file extension. For example:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}.php [L]

The negated regex !\\.\\w{2,4}$ only matches URLs that don't contain - what looks like - file extensions. A file extension in this context is a sequence of 2 to 4 letters/digits at the end of the URL-path, preceded by a dot.


See my answer to the following ServerFault question that goes into more detail regarding the potential rewrite-loop and resulting 500 error response: 请参阅对以下 ServerFault 问题的回答,其中详细介绍了潜在的重写循环和导致的 500 错误响应:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM