Skip to content

Avian Bone Syndrome

An exercise in futility by Daniele Nicolucci

Menu
  • About ABS
Menu

Prettifying URLs with fake subdirectories using mod_rewrite

Posted on 2010-09-16 by Daniele Nicolucci

Lately, I have been trying to define a common basis for most of my web projects, since I often end up reinventing the wheel every time. I have tried a few PHP frameworks, but none of them tickled my fancy, but I have complicated tastes. I am known for reimplementing something from scratch rather than wasting time adapting other people’s code to my needs, and it’s often much faster too.

Therefore I have been working on JBFW, my very own PHP/Javascript framework. One of the key components of it is pretty URLS and a centralized index.php to handle most of the things.

If you access http://mysite.com/news?lang=en, the server will transparently route that to http://mysite.com/index.php?pagename=news&lang=en. At that point, index.php runs the news module if it’s present, and then loads the news template (possibly showing the result of what was done in the module, if it was called at all.) I find that it’s a very slick and modular way of handling things, as static pages only need new templates and boom, they are live, with the rest of the framework readily accessible.

The mod_rewrite configuration for such a behavior is as follows:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?pagename=$1&%{QUERY_STRING}

This means: if the requested filename is not a directory and is not a file, route the request as described (knowing something about regular expressions, or being proficient in creative swearing — which goes hand in hand with regexp — comes in very handy at this point.)

I used a similar, but coarser, approach on my own main website, http://www.nicolucci.eu. There, I even used fake subdirectories, so that http://www.nicolucci.eu/photography/book/glimpses will have it show the photography-book-glimpses template. Neat, but doesn’t work with real subdirectories. It’s not a big problem on that site, but when you need to have a separate administration section, you need real subdirectories. The problem is that, using the approach I described above, http://mysite.com/admin/login into http://mysite.com/index.php?pagename=admin/login, and while the correct function could be run in PHP by mangling the request as it’s done for the “top level” modules, it could quickly turn into a nightmare.

The solution is to add another set of mod_rewrite rules, as follows:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^((.*)/)+(.*)$ /$2/index.php?pagename=$3&%{QUERY_STRING} [L]

Yes, that’s incredibly messy, and I’m pretty sure that there is a better way to do it. However it works, and for now I’m going to concentrate on finishing the website and go back to it later. What this does is: if the request has one or more blocks ending wish a slash (the directory), followed by something else (the file name), it is routed to index.php inside that directory, using the file name as a parameter to pagename, plus the original query string as usual. The [L] at the end tells mod_rewrite: please refrain from doing any other change, this is flaky enough. This ensures that http://mysite.com/admin/login effectively calls http://mysite.com/admin/index.php?pagename=login.

Note that this is another block of RewriteCond and RewriteRule, and goes before the original one. I tried to put them together, since the conditions are the same, but after fifteen minutes of trying all combinations I gave up. I’m sure I was one attempt away from getting it right.

A very clever thing (ok I’m kidding, it’s a side effect I hadn’t fully realized but I’m glad it’s there) is that addresses such as img/logo.png are not rewritten because those files do exist. It would probably make sense to exclude common file extensions, such as image files and javascript, from this kind of mangling; or even better, make it only work when the “file name” part does not have a dot in it. I’ll find a way to do it, at some point.

To finish up, an extra little trick that can come in very handy when you want to make sure that certain files are not downloadable by anybody:

<Files ~ "\.sqlite3$">
Order Allow,Deny
Deny From All
</Files>

Make sure that there are no spaces on either side of the comma in the first line. I was quite frustrated because I kept getting the infamous error 500, and there it was.

I hope this spares someone from wasting as much time as I did with this kind of thing!

Post navigation

← 20 tips to run a business without committing suicide
TV shows I’ll be watching →

Written by a human

All text in this blog was written the old-fashioned way, without going through an AI / LLM. Any typos, mistakes and inconsistencies are proudly mine.

If you like this…

Did you enjoy reading this post without ads? If so, you may consider supporting this blog via Ko-fi!

Where was that?

Time travel

  • June 2026 (1)
  • May 2026 (1)
  • April 2026 (1)
  • November 2022 (1)
  • March 2022 (1)
  • December 2021 (1)
  • October 2020 (1)
  • August 2020 (1)
  • May 2020 (1)
  • March 2020 (3)
  • February 2020 (1)
  • April 2019 (1)
  • March 2016 (1)
  • July 2015 (1)
  • May 2015 (3)
  • April 2015 (2)
  • November 2014 (1)
  • August 2014 (2)
  • September 2013 (2)
  • April 2013 (1)
  • March 2013 (1)
  • October 2012 (1)
  • June 2012 (1)
  • March 2012 (1)
  • December 2011 (1)
  • November 2011 (3)
  • October 2011 (2)
  • July 2011 (1)
  • April 2011 (1)
  • January 2011 (1)
  • December 2010 (2)
  • November 2010 (1)
  • October 2010 (3)
  • September 2010 (16)
  • August 2010 (12)
  • July 2010 (10)
  • June 2010 (1)
  • May 2010 (7)
  • April 2010 (3)

Categories

  • Business (2)
  • Culture (13)
  • Electronics (4)
  • Huh? (1)
  • iOS (4)
  • Linguistics (11)
  • Music (8)
  • Personal (5)
  • Photography (10)
  • Podcast (5)
  • Science (7)
  • Society (28)
  • Technology (50)
  • Travel (2)
  • Tutorials (13)
  • TV (7)
  • Video games (6)

Tags

1984 (3) absp (3) apple (11) bluray (3) camera (4) communication (3) coronavirus (5) covid19 (5) culture (4) death (3) dream theater (4) ebooks (5) english (4) facebook (3) ios (8) ipad (4) iphone (10) iphone os (4) italian (3) italy (6) james labrie (3) jordan rudess (3) language (6) languages (3) linguistics (6) lockdown (5) mac (6) memories (3) mike portnoy (3) opus (4) orwell (3) os x (6) personal (4) photography (10) podcast (6) projects (3) rant (4) reading (4) spanish (3) the big bang theory (3) tutorial (12) tv (5) twitter (3) video games (6) work (3)
© 2026 Avian Bone Syndrome | Powered by Minimalist Blog WordPress Theme
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept”, you consent to the use of ALL the cookies.
Do not sell my personal information.
SettingsAccept
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Non-necessary
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
SAVE & ACCEPT