Is there a way to have the mod_rewrite rules in my .htaccess file take effect before PHP behind fcgi sees the request?

I have an email validation link that I want to redirect from root to the login page before PHP marks it in the database as confirmed.

These are the rules I have in my .htaccess, and they work, but PHP sees the request before the rewrite rule takes effect.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{QUERY_STRING} activation_key=
    RewriteRule ^$ /login [R,L]
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]

When PHP sees a request that contains the activation_key query string, it marks the user as activated. If the user is already activated, the page will show an "Unknown validation link" error.

With these rewrite rules the request redirects to the /login page and displays the error, indicating - I assume - that PHP had already seen the request.

This is the mod_fastcgi config:

<IfModule mod_fastcgi.c>
    DirectoryIndex index.html index.shtml index.cgi index.php
    AddHandler php5-fcgi .php
    Action php5-fcgi /php5-fcgi
    Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
    FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host -pass-header Authorization
  • Rewrite rules always apply before the request is passed to PHP. What you think is happening is not what is actually happening. Explain how you are testing this in your question and we'll help devise a better test to determine what is actually happening. – Ladadadada Aug 5 '13 at 18:55
  • I added a bit more detail about the configuration. – joshperry Aug 5 '13 at 19:02

If I'm understanding this correctly:

  1. You make a request to /?activation_key=foobar and Apache sends back a response to redirect you to /login.
  2. You make a followup request to /login and that page says it has already seen the validation link. But there is no activation_key in this request, it only existed in the first request. It has probably seen the empty string before and that's why it's throwing an error now. (The exact logic in your PHP script may not match this explanation but I suspect it's something similar.)

Try changing your rewrite rules like this:

RewriteCond %{QUERY_STRING} activation_key=[^&]*
RewriteRule ^$ /login?activation_key=%1 [R,L]

That captures the activation key and passes it along on the next request to /login so that PHP will then have the key.

It might be worth while you're debugging to echo out or log to a file the query string or the whole request or even the whole $_SERVER super global.

Your last rewrite rule has an extra / in it that doesn't need to be there. This would be a better rule:

RewriteRule ^ index.php [L]

.htaccess files and the associated AllowOverride all directive carry a performance penalty with them. This becomes painfully obvious when using strace and watching all the file operations looking for all the places a .htaccess file could be hiding. If you're running your own Apache server rather than being on shared hosting, you might as well put these rules in the main config and set AllowOverride to none. Inside a <Directory> block they will work as they are. Anywhere else they will need an extra leading slash.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.