Calling mod_rewrite Gurus…

Posted in: WordPress, Development, alexking.org

One of the trade-offs to going with a fully WordPress driven site for content is a little URL awkwardness for image and archive files you want to show/link to on a page.

For example, in a “standard” site it is pretty easy to have a page at this location:

http://example.com/foo/

and a related file download at this location:

http://example.com/foo/download/foo.zip

If you are using a CMS like WordPress to create the page here:

http://example.com/foo/ (or http://example.com/foo)

then there is no existing directory structure to allow you to put the ‘download/foo.zip’ into.

You can set up custom rewrite rules for each file you reference, but I prefer the “set it and forget it” approach rather than the “micro maintenance” approach. The solution I’m using is fairly simple.

I’m setting up a psuedo-mirror of the site WordPress page structure under a site/ directory. This means that in the example above, I will place the foo.zip file in a directory like this:

/site/foo/download/foo.zip

I then need to rewrite the /foo/download/foo.zip URL to point to the /site/foo/download/foo.zip file.

The WordPress rules only kick in when a file doesn’t exist, so you might think I should be able to simply put the file at /foo/download/foo.zip. Unfortunately, directory level URLs (/foo/) will get caught as “existing” too, keeping the WordPress rules from kicking in. Using the rewrite into a sub-directory solves this.

This only needs to happen for files with file extensions like .php, .html, .zip, .tar.gz, etc. so I need (what should be) a rather simple condition (RewriteCond) and rule (RewriteRule). Unfortunately, I’ve been banging my head against this for too long and I haven’t gotten it to work.

If your mod_rewrite-fu is stronger than mine (or if you have a different solution), perhaps you can help me in the comments. :)

If you are a mod_rewrite guru and are willing to be a go-to resource for me on mod_rewrite issues (paid, of course), let me know. I waste way too much time futzing with this stuff trying to get it to work.

UPDATE: I now have a very good working solution thanks to Luke Baker. His approach is a lot better than mine was: check to see if the file exists in my psuedo-site structure (DocumentRoot/site/file.gif), then rewrite the URL if it does. Here is the working rewrite code:

RewriteCond %{DOCUMENT_ROOT}site%{REQUEST_URI} -f
RewriteRule (.*) /site%{REQUEST_URI} [L]

Thanks Luke! :)

Popularity: 6% [?]

Posted October 10th, 2006 @ 10:53 AM

16 Replies

  1. Ajay D'Souza adds this Comment:

    Hi Alex,

    I’m no expert, but what rules have you used so far?

    I take it you have already implemented it but it doesn’t work?

    October 10th, 2006 at 11:39 am

  2. Luke Baker adds this Comment:

    The following seemed to work for me from a .htaccess file. You’d want the wordpress rules to be below these two.
    RewriteEngine On
    RewriteCond %{DOCUMENT_ROOT}/site%{REQUEST_URI} -f
    RewriteRule (.*) /site%{REQUEST_URI} [L]

    October 10th, 2006 at 11:45 am

  3. Alex adds this Comment:

    I’ve been trying a bunch of stuff. My last attempt looked something like this:

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} \.(gif|jpg|png|php|html|txt|tar|gz|zip)$ [NC]
    RewriteRule ^(.*)?$ /site/$1 [QSA,L]

    If this is totally ridiculous, feel free to laugh. ;)

    October 10th, 2006 at 11:46 am

  4. Alex adds this Comment:

    Luke - looks like a good approach, but doesn’t seem to work for me.

    October 10th, 2006 at 11:49 am

  5. Luke Baker adds this Comment:

    Alex, I’ll assume that by not working means the RewriteCond never evaluates to true, which means it isn’t generating the proper path with the %{DOCUMENT_ROOT}/site${REQUEST_URI} part. Try seeing what that would evaluate to by handcrafting a RewriteRule that uses that. For example, if I were doing it on a non-production server:
    RewriteRule .* http://0.0.0.0/%{DOCUMENT_ROOT}/site%{REQUEST_URI} [R,L]

    Then I’d try to hit a URL like http://example.com/f[...]load/foo.zip and see where you get redirected to.

    October 10th, 2006 at 12:17 pm

  6. matthijs adds this Comment:

    The reason the RewriteCond never evaluates to true is that there is no REQUEST_FILENAME - it doesn’t exist in the requested location.

    You need to have some sort of marker in your URLs to tell you’re looking for a file, something like

    http://example.com/f[...]omething.zip

    and your rule would simply be

    RewriteRule ^(.+)\/download\/(.+) /site/$1/download/$2

    or somesuch

    That’s what I’d do, anyways. Just make sure you can tell if something is a filedownload that needs to be redirected.

    October 10th, 2006 at 12:28 pm

  7. Alex adds this Comment:

    I think that this URL does indicate a file:

    http://example.com/f[...]load/foo.zip

    And I want to be able to support any file, not just a download URL:

    http://example.com/foo/bar.txt
    http://example.com/foo/bar.gif
    http://example.com/foo/bar/file.php

    October 10th, 2006 at 12:36 pm

  8. Abazza adds this Comment:

    Isn“t there anywhere a Mod_Rewrite ganerator available?
    Would be best selution I think.

    October 11th, 2006 at 12:02 am

  9. Florian adds this Comment:

    I’ve done it like this some time ago.

    RewriteCond %{REQUESTURI} ^\/(.*)/download\/(.*)
    RewriteRule . /download/%1/%2 [R,L]

    It’s only a memory yet, so I’m not sure if I did forget something.

    October 11th, 2006 at 3:45 am

  10. Alex adds this Comment:

    That would probably help for files in a “download” directory, but that isn’t the solution I’m looking for. Luke Baker came up with a great solution, it is there in the post body now.

    October 11th, 2006 at 6:33 am

  11. Erik adds this Comment:

    If i get you right… then: In order to get the “marker” into URLs without actually marking them, you could simply let a preformatting plugin (eg: Jerome’s Preformatted) parse all links right when you save a post to the db. you could for example search all links and images for URIs starting with a “/” then replace it with that needed string/folder… (for feed validity you would of course do it absolute)
    Just an idea - i know this doesn’t solve the mod_rewrite problem - but in the end could make the pretty simple satisfying

    October 12th, 2006 at 12:24 am

  12. Alex adds this Comment:

    No, the goal is to *not* have the marker in the URL.

    October 12th, 2006 at 7:44 am

  13. Sudar adds this Comment:

    Hi Alex,

    I think you missed out a slash between the document_root and the site folder in the first line.

    It should be

    RewriteCond %{DOCUMENT_ROOT}/site%{REQUEST_URI} -f

    instead of

    RewriteCond %{DOCUMENT_ROOT}site%{REQUEST_URI} -f

    since document_root does not include a slash at the end.

    Cheers,
    Sudar

    November 27th, 2006 at 2:24 am

  14. Alex adds this Comment:

    Interestingly, the slash was required on a Linux box and was required to be absent on a Mac OS X box. My guess is that this comes from the https.conf setting, which can define the directory location with or without the slash.

    November 27th, 2006 at 8:47 am

  15. Ron adds this Comment:

    Very nice!

    This is exactly what I was looking for. After hours of fiddling and searching I stumbled across your blog, Alex.

    Thanks Luke for posting your solution, you’ve helped more than just one person. :)

    Ron

    May 16th, 2007 at 7:44 pm

  16. Abazza adds this Comment:

    Thanx Luke, with your solution you finished my endless work.
    Thanx to Alex for this helpful blog.

    May 27th, 2007 at 12:24 pm

Add a Comment

Please note: Use of a non-personal web site or blog in the field below and/or comments that are off-topic, personal attacks, or support requests will likely be removed at my discretion.

Note: This post is over a year and a half old. You may want to check later in this blog to see if there is new information relevant to your comment.

PHP Tag Engine “How To” » « Tasks Pro 1.7rc2 and Tasks 2.7rc2

About This Site

This is the personal web site of Alex King, an independent developer based in Denver, Colorado USA. More...


Crowd Favorite

Crowd Favorite is my software and web development business.

We build web applications, design and develop custom WordPress themes and plugins, and build custom sites using WordPress as a CMS.


I also have a tumblog that aggregates my online content from other services (Twitter, Flickr, del.icio.us. etc.).

Ads