{"id":1045,"date":"2009-07-27T13:12:57","date_gmt":"2009-07-27T19:12:57","guid":{"rendered":"http:\/\/bililite.nfshost.com\/blog\/?p=1045"},"modified":"2009-07-27T15:56:25","modified_gmt":"2009-07-27T21:56:25","slug":"things-i-learned-about-htaccess","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2009\/07\/27\/things-i-learned-about-htaccess\/","title":{"rendered":"Things I Learned About .htaccess"},"content":{"rendered":"<p>All I wanted was to get a better 404 page for the <a href=\"\/\">bililite.com site<\/a> and to use <a href=\"http:\/\/httpd.apache.org\/docs\/2.0\/mod\/mod_rewrite.html\">mod_rewrite<\/a> to <a href=\"http:\/\/www.workingwith.me.uk\/blog\/software\/open_source\/apache\/mod_rewriting_an_entire_site\">standardize my pages<\/a>. Of course, nothing is ever simple and <a href=\"http:\/\/httpd.apache.org\/docs\/2.0\/rewrite\/#preamble\">mod_rewrite is voodoo<\/a>. So it took a week of experimenting, pulling my hair and staring at a lot of <a href=\"http:\/\/www.checkupdown.com\/status\/E500.html\">500 errors<\/a>, but I think I got things where I wanted them (still don't have a very elegant 404 page, though!). To make sure I didn't have to go through this again, and to help anyone else out there, here are the things I wish I had known:<\/p><!--more-->\r\n<h3><a href=\"http:\/\/www.askapache.com\/\">askApache<\/a> is my new best friend<\/h3>\r\n<p>There are <a href=\"http:\/\/www.google.com\/search?q=mod_rewrite+tutorial\">lots of mod_rewrite tutorials out there<\/a> on the web, but once you get past the simple stuff, nothing is obvious. <a href=\"http:\/\/www.askapache.com\/\">askApache<\/a> digs deeper and explains more of the hack-y stuff that you need to know in order to actually <em>use<\/em> your <code>.htaccess<\/code> file, especially his <a href=\"http:\/\/www.askapache.com\/htaccess\/crazy-advanced-mod_rewrite-tutorial.html\">Crazy Advanced Mod_Rewrite Tutorial<\/a>, Highly recommended.<\/p>\r\n<h3>Know the difference between <code>Redirect<\/code> and <code>Rewrite<\/code><\/h3>\r\n<p>Both of these involve changing a URL to a different one. Redirecting, however, tells the browser that it changed (generally by sending a <a href=\"http:\/\/www.w3.org\/Protocols\/rfc2616\/rfc2616-sec10.html#sec10.3.2\">301 status code<\/a>) while rewriting (or \"internally redirecting\") keeps it a secret. Thus if I internally use URL's like <code>\/\/example.com\/index.php?main=foo&part=bar<\/code> but publicly I want them to look like <code>\/\/example.com\/foo\/bar<\/code> I'll rewrite:<\/p>\r\n<pre><code>RewriteRule ^([^\/\\.]+)\/([^\/\\.]+)$ index.php?main=$1&part=$2 [QSA,L]<\/code><\/pre>\r\n<p>But to publicly change a URL, say from <code>\/\/example.com\/oldname.html<\/code> to <code>\/\/example.com\/newname.html<\/code> I'll redirect:<\/p>\r\n<pre><code>Redirect Permanent \/oldname.html \/newname.html\r\n# or\r\nRewriteRule ^oldname.html$ newname.html [R]<\/code><\/pre>\r\n<p>Note that it's usually easier to use <a href=\"http:\/\/httpd.apache.org\/docs\/2.0\/mod\/mod_alias.html#redirect\"><code>Redirect<\/code><\/a> or <a href=\"http:\/\/httpd.apache.org\/docs\/2.0\/mod\/mod_alias.html#redirectmatch\"><code>RedirectMatch<\/code><\/a> rather than <a href=\"http:\/\/httpd.apache.org\/docs\/2.0\/mod\/mod_rewrite.html#rewriterule\"><code>RewriteRule<\/code><\/a> with the [R] flag. Note also that the <code>Redirect<\/code> pattern starts with the <code>\/<\/code> (or whatever the per-directory prefix is) while <code>RewriteRule<\/code> patterns strip the <code>\/<\/code> out. I've been burned by this! (this is true for <code>.htaccess<\/code> only; the per-server configuration file <code>httpd.conf<\/code> uses the entire URL. But I'm on a cheap shared server; I can't touch <code>httpd.conf<\/code>).<\/p>\r\n<h3>Use <code>Redirect<\/code> to append a slash to directories<\/h3>\r\n<p>Generally, if you use a URL like <code>\/\/example.com\/foo<\/code> you really want <code>\/\/example.com\/foo\/<\/code>. Apache does this <a href=\"http:\/\/httpd.apache.org\/docs\/2.2\/mod\/mod_dir.html#directoryslash\">automatically<\/a> for real directories. But if you're doing the <code>\/foo\/bar<\/code> to <code>\/index.php?main=foo&part=bar<\/code> and <code>\/foo<\/code> to <code>\/index.php?main=foo<\/code>, you really want <code>\/foo<\/code> to be <em>redirected<\/em> to <code>\/foo\/<\/code>, then \/foo\/ <em>rewritten<\/em> to <code>\/index.php?main=foo<\/code>. If you don't, then relative URL's won't work. If the file returned by <code>\/foo<\/code> contains a link <code>&lt;a href=\"bar\"&gt;<\/code> you want the browser to interpret that href as <code>\/foo\/bar<\/code>. But it won't. It thinks the file has the URL <code>\/foo<\/code>, so its directory is <code>\/<\/code> and the relative URL bar refers to <code>\/bar<\/code>. Redirecting <code>\/foo<\/code> to <code>\/foo\/<\/code> lets the browser know that <code>foo<\/code> is to be treated as a directory, so <code>bar<\/code> refers to <code>\/foo\/bar<\/code>. Example:\r\n<pre><code>RedirectMatch Permanent ^\/([^\/\\.]+)$ \/$1\/\r\nRewriteRule ^([^\/\\.]+)\/$ index.php?main=$1 [QSA,L]\r\nRewriteRule ^([^\/\\.]+)\/([^\/\\.]+)$ index.php?main=$1&part=$2 [QSA,L]<\/code><\/pre>\r\n<h3><code>ErrorDocument<\/code> should rewrite, not redirect<\/h3>\r\n<p>It's incredibly annoying to type in <code>\/\/example.com\/long\/complicated\/urk.html<\/code> (note the typo!) and have the address bar turn into \/\/example.com\/404.html. I want the address bar to stay the same so I can edit what I wrote! The <a href=\"http:\/\/httpd.apache.org\/docs\/2.0\/mod\/core.html#errordocument\">ErrorDocument<\/a> directive uses redirection if a complete URL is specified. This is bad. Just start the URL with a slash and it will use internal redirection (what I'm calling rewriting) and the browser's address bar will remain untouched.\r\n<pre><code>ErrorDocument 404 \/404.php\r\n#NOT ErrorDocument 404 http:\/\/example.com\/404.php\r\n<\/code><\/pre>\r\n<h3>1&1 gets it wrong<\/h3>\r\n<p>I use the cheapest shared-server plan from <a href=\"http:\/\/1and1.com\">1&1<\/a> and I've been pretty happy with it: no frills, straight classic <a href=\"http:\/\/en.wikipedia.org\/wiki\/LAMP_(software_bundle)\">LAMP stack<\/a>, reliable enough for me. But they \"hijack\" the <code>ErrorDocument<\/code> for active pages (.php, .cgi, .pl and I assume others) to their own advertising-laden page. That I can understand (again, it's a cheap plan) but they redirect so you can't correct the URL. So I need to do an end run around them by catching nonexistent files first:\r\n<pre><code>RewriteCond %{REQUEST_FILENAME} \\.php$\r\nRewriteCond %{REQUEST_FILENAME} !-f\r\nRewriteRule . \/404.php [L]\r\n<\/code><\/pre>\r\n<h3><code>RewriteCond -f<\/code> is case sensitive<\/h3>\r\n<p>This burned me badly before I figured it out. The <code>-f<\/code> test for <a href=\"http:\/\/httpd.apache.org\/docs\/2.0\/mod\/mod_rewrite.html#rewritecond\"><code>RewriteCond<\/code><\/a> uses the underlying operating system to find the file, which means that on a Linux system, it's case-sensitive. No way around it; the <code>[NC]<\/code> flag doesn't help. So when I create gif's on my Windows machine in Paint and save it, it automatically names the file <code>whatever.GIF<\/code> and remains that way when I copy it to the Linux server. Now Apache will do fine finding the file if I request it with <code>&lt;img src=\"whatever.gif\"\/&gt;<\/code>, but if my <code>.htaccess<\/code> has a line <code>RewriteCond %{REQUEST_FILENAME} !-f<\/code> it will return true since <code>whatever.gif<\/code> doesn't exist; <code>whatever.GIF<\/code> does.<\/p>\r\n<p>Hope this saves someone some time (and hair).<\/p>","protected":false},"excerpt":{"rendered":"All I wanted was to get a better 404 page for the bililite.com site and to use mod_rewrite to standardize my pages. Of course, nothing is ever simple and mod_rewrite is voodoo. So it took a week of experimenting, pulling my hair and staring at a lot of 500 errors, but I think I got [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1045"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=1045"}],"version-history":[{"count":23,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1045\/revisions"}],"predecessor-version":[{"id":1068,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/1045\/revisions\/1068"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=1045"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=1045"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=1045"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}