views:

103

answers:

3

I notice that there are a few common ways to setup RewriteRules for MVC based PHP applications. Most of which contain:

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-d

Followed by a RewriteRule:

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

or

RewriteRule .* /index.php/$0 [PT,L]

I realize that L = LAST, QSA = query string appended, PT = pass through but as I don't have the real world experience of using these yet, could anyone inform me which flags and URI they would go with and why?

The latter rule contains a slash before the $0, I'm assuming because this forces it so the PATH CGI variable is populated, as often times I don't see it populated. Does the PT actually serve somewhat of the same purpose as the QSA, indirectly? Or how else would one use query strings? Basically, what are the pros and cons of these?

And just to confirm, if I wanted to add say an ErrorDocument directive would the L flag matter? Let's say a request to '/non-existing-link/' is made, my application cannot pick it up from the defined routes I have, nor is there an existing directory as such, would the L have any effect if I placed the ErrorDocument below the RewriteRule? Should I place it before the entire snippet? Same with 301s, 302s. And if I were to actually manually invoke 3xx/4xx codes, I would be using the header() function within my application, right? I kind of have a feeling this is quite dirty but is probably the most practical and only way of doing it hence it probably isn't dirty.

A: 

I have used zend framework suggestion for MVC application.

http://framework.zend.com/manual/en/zend.controller.html

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Ismael
-1 because I'm asking for an explanation, not a random snippet paste.
meder
+1  A: 

The ErrorDocument setting will have no effect. If files are not found by Apache, the request is handled by PHP (as defined by these rewrite rules). Once inside PHP, you have to stay inside. Setting the response code to an error value with header() will not invoke Apache's error handling. You have to make your own code to present a decent error page.

Bart van Heukelom
+1  A: 

When the htaccess is read by the server, it goes line-by-line, trying to find a match. Without the L flag it will check every rule in the htaccess (though I'm not sure what happens if it finds multiple matches here).

If you include the L flag, when it gets to that rule, it will stop processing rules and serve the request. However, the gotcha here is that when it serves the request it will process the htaccess file from the beginning again with the new, rewritten URL. This page explains it well, with an example.

The ErrorDocument rule will be independent from the rewrite rules, so it doesn't matter where it comes (I usually put it at the top so it's obvious and not buried under a bunch of rewrites).

However, note that if a rewrite rule matches a valid file or script, the error document won't fire, even if the data/querystring is bogus. For example if a URL gets written to /index.php?page=NON_EXISTENT_PAGE then the server believes it has found the document. You will need to handle the parameter in the PHP script. Setting 404 headers in the PHP script won't automatically serve up the 404 document (but you can include it from the PHP script).

DisgruntledGoat
So would you go with the first or second rule that I have?
meder
DisgruntledGoat
In your case, maybe `RewriteRule ^(.*)$ /index.php/$1 [L]` would be more appropriate. I don't think you need `PT`. You might want `QSA` if any URLs will have a query string.
DisgruntledGoat