简体   繁体   中英

mod_rewrite: Prevent multiple rewrites using an environment variable

I'm currently returning a 404 error for *.php and internally redirecting all requests to a PHP file if one exists, using the following:

RewriteCond %{REQUEST_URI} /(?!index$)
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.+)$ /$1.php [QSA,L,E=norewrite:1]

RewriteCond %{ENV:norewrite} !1
RewriteCond %{REQUEST_URI} \.php$
RewriteRule ^(.+)$ - [R=404]

This works fine. However, I wish to have the ability to serve up PHP (or other) source (with the appropriate extension), from files eg index.php.src, while having index.php.src also return a 404 if accessed directly.

RewriteCond %{REQUEST_URI} /(?!index$)
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.+)$ /$1.php [QSA,L,E=norewrite:1]

RewriteCond %{ENV:norewrite} !1
RewriteCond %{REQUEST_FILENAME}\.src -f
RewriteRule ^(.+)$ /$1.src [L,E=norewrite:1]

RewriteCond %{ENV:norewrite} !1
RewriteCond %{REQUEST_URI} \.php$ [OR]
RewriteCond %{REQUEST_URI} \.src$
RewriteRule ^(.+)$ - [R=404]

This does not appear to work. It internally redirects to index.php, then to index.php.src, then 404s.

What's interesting is that, in the first sample, the environment variable DOES prevent the second ruleset from executing, and the page loads as expected. When I add that middle ruleset you see in the second sample, the environment variable no longer seems to have any effect. If I remove that second ruleset from the second sample, leaving the additional lines in the last ruleset, as is, it behaves just like the first sample (except that requesting eg index.php.src returns a 404, which is what I want).

For various reasons, it would be unacceptable to use a query string for this purpose, it must be an environment variable.

How can I make this work? What am I doing wrong?

Edit: In case I explained it poorly (I'm fairly sure I did)...

  • The following two files exist: 'index.php' and 'index.php.src'
  • If I request http ://domain.com/ with the first set of rules, I get my homepage (as expected). With the second set of rules, I get a 404. With the second set of rules, minus the second stanza, I get my homepage (as expected).
  • If I request http ://domain.com/index with either set of rules, I get a 404, as expected.
  • If I request http ://domain.com/index.php with either set of rules, I get a 404. This is expected with the first set, but I expect to be served the contents of 'index.php.src'.
  • If I request http ://domain.com/index.php.src with the first set of rules, I get the contents of 'index.php.src', as expected since the rule to 404 on *.src isn't in that set. I get a 404 as expected with the second set, with or without the second stanza.

The problem appears to be in the second stanza, but I can't make out what's wrong...

Here's what I did that worked:

RewriteCond %{IS_SUBREQ} false
RewriteCond %{REQUEST_URI} /(?!index$)
RewriteCond %{ENV:REDIRECT_STOP} !1
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.+)$ /$1.php [QSA,L,E=STOP:1]

RewriteCond %{IS_SUBREQ} false
RewriteCond %{ENV:REDIRECT_STOP} !1
RewriteCond %{REQUEST_FILENAME}\.src -f
RewriteRule ^(.+)$ /$1.src [L,E=STOP:1]

RewriteCond %{IS_SUBREQ} false
RewriteCond %{ENV:REDIRECT_STOP} !1
RewriteCond %{REQUEST_URI} \.php$ [OR]
RewriteCond %{REQUEST_URI} \.src$
RewriteRule ^(.+)$ - [R=404]

You'll notice I added the %{IS_SUBREQ} bits, which helped with the homepage redirerect issue that was causing it to 404. At that point, the query string method became acceptable, and I did get it working with that method, but I'm not the type to jsut let it be at that, I knew this could be done and I was gonna do it (I did!)

Aside from changing the variable name from 'norewrite' to 'STOP', which I did for clarity, I learned that environment variables set by mod_rewrite are prefixed with 'REDIRECT_' when an internal redirect occurs. That's why setting the value of 'norewrite' ('STOP'), then checking that same variable, was not working. When I appended 'REDIRECT_' to it in the check lines, it now behaves as expected.

  • Requesting '/awesome' will process 'awesome.php' and return its output
  • Requesting '/awesome.php' will return the content of 'awesome.php.src' (which is a symlink to 'awesome.php')
  • Requesting 'awesome.php.src' will return a 404

This is exactly what I wanted! Hopefully this will help someone else, as well.

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