Discrepancies between Apache 1.3/2.2?

Oh, the strange things mod_rewrite does!

Discrepancies between Apache 1.3/2.2?

Postby prettyjenny » Thu Oct 02, 2008 8:51 am

I'm somewhat new to mod_rewrite, struggling with apparent discrepancies between Apache 1.3 and 2.2 (or perhaps it's Linux and Windows). Here's what I'm trying to accomplish, and in this order:

1) I want to _not_ rewrite URIs that refer to actual files or directories, such as "/css/main.css".
1a) With the exception that I want directory URIs to end with a slash.

2) I want to remove the (optional) trailing slash from all other URIs.

3) Finally, I want to decompose URIs into query parameters, to be passed to my controller script, index.php. Different URIs will be decomposed in different ways.

Pretty standard stuff, yeah? Here's my .htaccess file:

Code: Select all
Options None +FollowSymLinks
DirectoryIndex index.php
RewriteEngine On

# these preconditions satisfy my first objective
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# and 1a is handled automatically it seems (mod_dir?)

# here's number 2--and where things start to fall apart. this rule works on my
# development machine (Windows/Apache 2.2) but not on the production machine
# (Linux/Apache 1.3). by "doesn't work", i mean it triggers a 500 error
RewriteRule ^(.+)/$ $1 [R=301,L]

# so, on the production machine, i use this rule instead
RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L]

# that takes care of the first two items; now for 3

# here i have to restate the preconditions from above--is there another way?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# for URIs of the form http://www.mywebstore.com/products/123, "123" maps to the
# query parameter "item-number". this rule works locally, but hoses the
# production server (500 error). same with the next rule
RewriteRule ^products/([0-9]+)$ index.php?controller=products&item-number=$1 [QSA,L]

# dum dee dum...
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# for URIs of the form http://www.mywebstore.com/content/about, "about" maps to
# the query parameter "page"
RewriteRule ^content/([a-z]+)$ index.php?controller=content&page=$1 [QSA,L]

# and so on

# finally, i set up a catch-all for URIs that don't match any of the above
# patterns. this rule actually works in production (yay!)
RewriteRule ^(.*)$ index.php?controller=$1 [QSA,L]

The crux of the problem is I can't debug mod_rewrite on the production server. It's a shared host. I've gotten this far through trial and error. Any help would be greatly appreciated.
Posts: 2
Joined: Thu Oct 02, 2008 7:35 am

Postby richardk » Thu Oct 02, 2008 2:03 pm

Code: Select all
# You can't mix +/- and not +/- Options on the same line.
Options None
Options +FollowSymLinks
DirectoryIndex index.php

RewriteEngine On

# Only remove trailing slashes from non-directory requests.
RewriteCond %{SCRIPT_FILENAME} !-d
# You can't redirect to a relative path, so it's /$1.
RewriteRule ^(.+)/$ /$1 [R=301,L]

# Unless you have a /products or /content directory you don't
# need to make sure it's not an existing file/directory. Even
# then you only need to do that if you will be accessing it
# with a browser.
RewriteRule ^products/([0-9]+)$ /index.php?controller=products&item-number=$1 [QSA,L]
RewriteRule ^content/([a-z]+)$  /index.php?controller=content&page=$1         [QSA,L]

# You should make sure this broad rule does not match CSS, images, etc.
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?controller=$1 [QSA,L]

#here i have to restate the preconditions from above--is there another way?

You can use
Code: Select all
Options +FollowSymLinks

RewriteEngine On

# Rules here will match existing files and directories.

# If it is an existing file/directory do nothing.
RewriteCond %{SCRIPT_FILENAME} -f [OR]
RewriteCond %{SCRIPT_FILENAME} -d
RewriteRule .* - [L]

# No rules after this point will match existing files or directories.
Posts: 8800
Joined: Wed Dec 21, 2005 7:50 am

Postby metaphile » Fri Oct 03, 2008 9:04 am

(I'm the original poster. My username is metaphile, not prettyjenny. I have no idea what happened there.)

Thank you rich. Your suggestions put me on the right path. It turns out I had more problems than I realized. Here's an excerpt from my revised .htaccess file, to give you some idea of my trials over the last couple of days:

Code: Select all
# when i write regular expressions, i make a point to escape special characters,
# even when it's not strictly necessary to do so. the following regex includes a
# literal hyphen as part of a character set. the hyphen is the first character,
# and so doesn't _need_ to be escaped

# works under Apache 2.2; causes a 500 error under Apache 1.3
RewriteRule ^docs/([\-0-9a-z]+)$ /index.php?path=docs&id=$1 [QSA,L]
# works under both
RewriteRule ^docs/([-0-9a-z]+)$ /index.php?path=docs&id=$1 [QSA,L]

# the domain name of the production website is not set up (yet), so I'm
# accessing the site through a temporary alias that looks something like this:
# d999999.u32.mywebhost.com. redirecting to /$1 doesn't work, because somewhere
# along the line, /$1 becomes notsetupdomain.com/$1. to avoid this, i have to
# manually construct the target URI using %{HTTP_HOST}
RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L]

Everything is working now and I'm an ounce less intimidated by mod_rewrite. Thanks again, rich!


RewriteCond %{SCRIPT_FILENAME} -f [OR]
RewriteCond %{SCRIPT_FILENAME} -d
RewriteRule .* - [L]

Ah, I get it! Beautiful.
Posts: 1
Joined: Fri Oct 03, 2008 8:25 am

Return to Idiosyncrasies

Who is online

Users browsing this forum: No registered users and 1 guest