简体   繁体   中英

mod_rewrite exception for a specific file

My page is not redirecting as it should due to my .htaccess file which is set as:

RewriteEngine on  
RewriteCond $1 !^(index\.php|resources|robots\.txt)  
RewriteCond %{REQUEST_FILENAME} !-f  
RewriteCond %{REQUEST_FILENAME} !-d  
RewriteRule ^(.*)$ index.php/$1 [L,QSA]   

I use this setup for my MVC Framework so i get urls like /controller/method/argument however when I redirect to /forum/login.php it cuts to /forum/.

How can I add this as an exception so that i will be able to redirect to /forum/login.php

I found another .htaccess in my /forum/ directory could this be causing the problem as well?

# BEGIN PunBB

<IfModule mod_rewrite.c>
    # MultiViews interfers with proper rewriting
    Options -MultiViews

    RewriteEngine On

    # Uncomment and properly set the RewriteBase if the rewrite rules are not working properly
    #RewriteBase /

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . rewrite.php [L]
</IfModule>

First I'll tell you how to read your RewriteRule:

You start with the first (or next) RewriteRule entry:

RewriteRule ^(.*)$ index.php/$1 [L,QSA]

The first parameter is a regular expression that can match your requested URL. ^(.*)$ matches everything, and stores this "everything" inside a variable that can be used later.

Only if there are preceding RewriteCond entries, they are evaluated next:

RewriteCond $1 !^(index\\.php|resources|robots\\.txt)

$1 is a reference to the content matched inside the first parentheses of RewriteRule. This is compared to the second parameter, which is a regular expression stating several explicit names, and the ! negates the expression, eg this rule allows execution of the RewriteRule only if the regex does not match. If this condition returns true, the next condition will be looked at.

RewriteCond %{REQUEST_FILENAME} !-f

If the requested filename is no real file on the harddisk, this condition is true.

RewriteCond %{REQUEST_FILENAME} !-d

If the requested filename is no real directory, this condition is true.

Only if all these conditions are true (they are chained together with AND), we come back to the rewrite rule:

RewriteRule ^(.*)$ index.php/$1 [L,QSA]

The result of this rewrite step is defined as the second and third parameter. $1 is used again as with the content of the match, and the parameters define that this rule, if initially matched, will be the last rule (L), and that any query string defined in the rewrite target will be appended to any query string in the original URL (QSA).

Critique:

The usual rewriting for MVC frameworks try to be as performant as possible. Your rewrite conditions all have to be evaluated for a successful rewrite. The will stop only if any of the RewriteCond return false. Every request that gets rewritten is subject to plenty of cpu intensive tests. First the RewriteRule regex, then the regex in the first RewriteCond, followed by two harddisk tests on the filesystem for file existance.

On the other hand, the first RewriteCond seems to be unnecessary. It tests for certain names, and if found, aborts the rewriting. "index.php" should be detected by the second RewriteCond, because it is an existing file (how would the rewriting work if not). Anything starting with "resources" will also be matched, but probably shouldn't for the same reasons: Existing resources will be found by the second RewriteCond. Last the "robots.txt" file. It is always a good idea to have one, possibly emtpy if you want to avoid 404 when robots fetch your site.

As you are not changing anything in the query string, the [QSA] directive is not needed.

Improvements:

RewriteEngine on  
RewriteCond %{REQUEST_FILENAME} -f [OR] 
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [L]  
RewriteRule ^.*$ index.php [L]

The first RewriteRule will match the whole requested path. The two RewriteCond are connected with [OR], so the first RewriteCond that returns true will cancel further evaluation. The first RewriteCond tests if the requested file exists. If it exists, it returns true, and the processing returns to the first RewriteRule. The target expression is "-", which means "do not rewrite". The [L] stops further processing of rewrite rules. So in the end, for an existing file we only have one regex and one filesystem test, and after that, this existing file will be sent to the browser.

If no file was found, the first RewriteRule and RewriteCond will not trigger, so the [L] there will not stop the process. So the second RewriteRule is executed. This one is unconditional, and the regex is the same as before, matching everything, and rewriting it to "index.php".

This rewriting will not call your index.php if any file exists, including /forum/login.php.

You can change the second to RewriteRule ^.*$ index.php/$0 [L] if you do want to continue parsing $_SERVER['PATH_INFO'] instead of $_SERVER['REQUEST_URI'] .

Try with this:

RewriteEngine on  
RewriteCond $1 !^(index\.php|forum|resources|robots\.txt)  
RewriteCond %{REQUEST_FILENAME} !-f  
RewriteCond %{REQUEST_FILENAME} !-d  
RewriteRule ^(.*)$ index.php/$1 [L,QSA]   

And this:

# BEGIN PunBB

# ----------------------------------------------------------------------
# Start rewrite engine
# ----------------------------------------------------------------------

<IfModule mod_rewrite.c>
    # MultiViews interfers with proper rewriting
    Options -MultiViews

    RewriteEngine On

    # Uncomment and properly set the RewriteBase if the rewrite rules are not working properly
    RewriteBase /forum/

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . rewrite.php [L]
</IfModule>


# ----------------------------------------------------------------------
# Better website experience for IE users
# ----------------------------------------------------------------------

# Force the latest IE version, in various cases when it may fall back to IE7 mode
# github.com/rails/rails/commit/123eb25#commitcomment-118920
# Use ChromeFrame if it's installed for a better experience for the poor IE folk

<IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
        BrowserMatch MSIE ie
        Header set X-UA-Compatible "IE=Edge,chrome=1" env=ie
    </IfModule>
</IfModule>

<IfModule mod_headers.c>
    # Because X-UA-Compatible isn't sent to non-IE (to save header bytes),
    # We need to inform proxies that content changes based on UA
    Header append Vary User-Agent
    # Cache control is set only if mod_headers is enabled, so that's unncessary to declare
</IfModule>


# ----------------------------------------------------------------------
# UTF-8 encoding
# ----------------------------------------------------------------------

# Use UTF-8 encoding for anything served text/plain or text/html
AddDefaultCharset utf-8

# Force UTF-8 for a number of file formats
AddCharset utf-8 .html .css .js .xml .json .rss


# ----------------------------------------------------------------------
# A little more security
# ----------------------------------------------------------------------

# Do we want to advertise the exact version number of Apache we're running?
# Probably not.
## This can only be enabled if used in httpd.conf - It will not work in .htaccess
# ServerTokens Prod


# "-Indexes" will have Apache block users from browsing folders without a default document
# Usually you should leave this activated, because you shouldn't allow everybody to surf through
# every folder on your server (which includes rather private places like CMS system folders).
<IfModule mod_autoindex.c>
    Options -Indexes
</IfModule>

# END PunBB

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