Niko
Niko

Reputation: 26730

Apache does not rewrite request if file on path exists

I'm doing a rewrite with mod_rewrite on every request that does not match an existing file or directory. This is my configuration:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [NC,L]

This is used to map URLs like /abc/foo or /abc/foo/10 to my app. And it works just fine.

To improve the performance, my app now stores the results of a call to /abc/foo in a file foo in the corresponding directory /abc - so that after the first call the rewrite conditions do no longer apply (file does not exist) and apache directly serves the data without first invoking the app. Works fine as well.

The problem is: Requesting /abc/foo/10 does now no longer cause the URL to get rewritten, instead I get an error "404 File Not Found". The log entries state that the rewrite condition !-f is no longer true, but actually the file /abc/foo/10 does not exist. /abc/foo exists, but is a file, not a directory.

How can I get this to work?

(MultiViews is disabled)

Upvotes: 3

Views: 3442

Answers (3)

Jacek Kaniuk
Jacek Kaniuk

Reputation: 5229

Project design is a little bit wrong - others already pointed out that it's not scallable - how could You cache a request to /abc/foo/10 if there is already a /abc/foo file?

Answer to that and to Your problem is usage of subfolders instead of files.

So instead of cache structure of:

/abc/foo
/abc/bar
 ...?

use:

/abc/index.html
/abc/foo/index.html
/abc/bar/index.html
/abc/foo/10/index.html

and each time create new directory with index.html

This time Apache would find out that there is /abc/foo folder but no /abc/foo/10 file in it, so RewriteCond will apply.

edit

You could also try a different way - to modify url with mod_rewrite, changing urls:

/abc/foo
/abc/bar
/abc/foo/10

to something like:

/cache/abc~foo
/cache/abc~bar
/cache/abc~foo~10

htaccess rules (roughly):

# redirecting to cache folder and removing last '/'
RewriteCond %{REQUEST_URI} ^/(abc|cde)
RewriteRule ^(.*?)/?$ /cache/$1 [L]

# recursive replacing '/' with '~'
RewriteCond %{REQUEST_URI} ^/cache/.*/
RewriteRule cache/(.*)/(.*)$ /cache/$1~$2 [L]

Your standard htaccess rules should follow

Upvotes: 2

Brian P Johnson
Brian P Johnson

Reputation: 703

This is because foo exists as a file and apache serves foo with the additional /10 passed as a query string. So, your application should write some additional code to the foo file, that also checks if a request includes some additional url component and then handle creation of the directory "foo" and the file 10.

Upvotes: 4

covener
covener

Reputation: 17871

You must be in per-dir/htaccess context w/ AcceptPathInfo on.

Therefore REQUEST_FILENAME matched the part that existed, and is not the same as REQUEST_URI.

Use the REQUEST_URI var if you don't care where the request was previously mapped in your rewritecond.

In per-vh context, these vars are always the same.

Upvotes: 3

Related Questions