views:

35

answers:

1

Hey, I've been reading StackOverflow.com for a long time but decided to sign up to ask a question. I'm writing my own lightweight MVC framework that routes page requests in index.php.

Page requests look like /controller/action/arg1/arg2/arg3, and they should be rewritten to index.php?route=[request]. So, a [request] like site.com/user/profile/123 should be rewritten to index.php?route=user/profile/123

However, files aren't meant to rewrite to index.php. Assets such as images and stylesheets are in the /app/webroot/ folder, and don't need PHP to be executed. So, the mod_rewrite engine should rewrite any filerequests to /app/webroot/, and serve the configured 404 ErrorDocument when the file doesn't exist.

Directory structure

  • ./index.php
  • ./app/webroot/scripts/helpers/hamster.js
  • ./app/webroot/images/logo.png
  • ./app/webroot/style/main.css

Since you can tell the difference between a file request (/squirrel.png) and a page request (/user/profile/123) just by the existence of the file extension / dot, I was expecting that this would be really easy. But... I'm having a really hard time with it and I was hoping someone could help me out.

Something I've tried was...

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ app/webroot/$1 [L]

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

... but it doesn't really work except for redirecting correctly to existing files. Pagerequests or nonexisting files result in HTTP 500 errors.

Any help is greatly appreciated! =)

A: 

See if this works out a little more like you expected:

RewriteEngine On

# These two lines are very specific to your current setup, to prevent
# mod_dir from doing what it does, but in a more controlled way
RewriteCond %{THE_REQUEST} ^[A-Z]+\s/iceberg[^/]
RewriteRule .* http://localhost/iceberg/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI}      !^/app/webroot
RewriteCond %{REQUEST_URI}       \.[a-z]+$ [NC]
RewriteRule ^.*$ app/webroot/$0 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI}      !^/app/webroot
RewriteRule ^.*$ index.php?route=$0 [QSA,L]

Also, to explain, the reason why you are getting the 500 error is likely because of your rule:

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

Since it's unconditional, and the regular expression pattern will always match, your rewrite will be performed over and over (the L flag doesn't prevent this, because after you rewrite to index.php, an internal redirection is made inside of Apache, and the process loses its current state).

Tim Stone
Thanks alot Tim, this works pretty well! However the following requests behave 'odd': - http://localhost/iceberg : When there is no trailing slash, this appears in the address bar of the browser: http://localhost/iceberg/?route=/Users/nilsw/Web/iceberg. I'd like to rewrite it to index.php?route=[empty string or '/'] instead - http://localhost/iceberg/images/notexist.png, it throws a HTTP 500 error code. (rather than a 404Document)
Nils W
Is the `iceberg` directory where your site (and `.htaccess`) lives? That scenario is being caused by `mod_dir`'s `DirectorySlash` option, which causes some pretty messed up behaviour in this context. "In production", the site's root should always have an initial slash, which prevents this problem (note this will only happen when you're pointing to a real directory without the trailing slash). I'll update the answer with a potential fix though.
Tim Stone
Also, I'm not sure what the issue is in the second case (it doesn't happen on my test server), but I'm adding something else that hopefully will cause the expected 404 response.
Tim Stone
Again, thanks for your help Tim. I've moved Iceberg to my root public_html folder and the problem has disappeared. For situations where it isn't in the root folder, there is this temporarily workaround at line1 of index.php: if($_GET['route'][0] == '/') $_GET['route'] = '/'; It now all works as expected (except for 404 response for files that don't exist)
Nils W
No problem, glad to help. If you can check your server logs to see what sort of error is popping up in regards to the lack of 404 response, we should be able to resolve that issue as well I hope.
Tim Stone
Alright, thanks! The only thing missing now is the 404 document so if you have an idea for that too, I'd love to hear it. Question marked as answered btw, again, thanks alot!
Nils W