codem - blog

Archive for September, 2010

Zeus and crazy URL rewriting

Recently I had a SilverStripe project go live on a host running the “Zeus” web server. I’ve never worked with this beasty before and I can see why – a pretty bog standard URL rewrite using mod_rewrite in Apache turned into multi-line horror.

Here’s the Apache rewrite, pretty standard stuff that ships with SilverStripe:

<IfModule  mod_rewrite.c>
	RewriteEngine On
	RewriteBase /
	RewriteCond %{REQUEST_URI} ^(.*)$
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteRule .* sapphire/main.php?url=%1&%{QUERY_STRING} [L]
<IfModule>

Here’s the Zeus equivalent:

insensitive match URL into $ with ^/.*\.(gif|jpg|jpeg|png|css|js|swf|php|html|htm|pdf)$
if not matched
	insensitive match URL into $ with ^/(.*)$
	if matched
		look for file at $1
		if not exists
			# Set the default page to be displayed if the URL is not a file or resource
			set URL = /sapphire/main.php?url=$1
			goto END
		endif
	endif
endif

Notice the case insensitivity matching, the Leaning Tower of Ifs and the file extension matching. It works, but not very nicely – for instance I missed the “swf” extension and no Flash files loaded, so it seems to automatically shove anything that doesn’t match down the pipe with a 404 header (even though the file exists on the server)

Edit – I’ve found a better way to do this.. which started by reading some Zeus/Apache rewrite translations at this Drupal page.

RULE_0_START:
# get the document root
map path into SCRATCH:DOCROOT from /
# initialize our variables
set SCRATCH:ORIG_URL = %{URL}
set SCRATCH:REQUEST_URI = %{URL}

# see if theres any queries in our URL
match URL into $ with ^(.*)\?(.*)$
if matched then
  set SCRATCH:REQUEST_URI = $1
  set SCRATCH:QUERY_STRING = $2
endif
RULE_0_END:

RULE_1_START:
# prepare to search for file, rewrite if its not found
set SCRATCH:REQUEST_FILENAME = %{SCRATCH:DOCROOT}
set SCRATCH:REQUEST_FILENAME . %{SCRATCH:REQUEST_URI}

# check to see if the file requested is an actual file or
# a directory with possibly an index.  don't rewrite if so
look for file at %{SCRATCH:REQUEST_FILENAME}
if not exists then
  look for dir at %{SCRATCH:REQUEST_FILENAME}
  if not exists then
    set URL = /sapphire/main.php?url=%{SCRATCH:REQUEST_URI}
    goto QSA_RULE_START
  endif
endif

# if we made it here then its a file or dir and no rewrite
goto END
RULE_1_END:

QSA_RULE_START:
# append the query string if there was one originally
# the same as [QSA,L] for apache
match SCRATCH:ORIG_URL into % with \?(.*)$
if matched then
  set URL = %{URL}&%{SCRATCH:QUERY_STRING}
endif
goto END
QSA_RULE_END:

That’s half the problem – after changing this I noticed that the base path in SilverStripe was set to “/index.php” resulting in all the links to various CSS and JS files to be broken. To get around this, in your _config.php file, make this change to force the base path

//force base URL for zeus
Director::setBaseURL('/');

And you should end up with a functioning site mimicking the (simpler) Apache setup.

In any case, even if it does work, my advice: anything that makes mod_rewrite even harder to implement by turning a 4 line rewrite into a 44 line monster should be avoided.

Cufón and the flash of unstyled text

A quickie but a goodie. Cufón’s great for embedding fonts into web pages without having to resort to images or Flash. In some cases there is a Flash Of Unstyled Text (FOUT) when the page is loading, with the default pre-replaced text rendered in a web font shining through for a split second.

I tried all the recommended options including Cufon.now() and a visibility CSS trick but neither seemed to work. Eventually I came up with this solution, which only involves removing a class added to Cufón targets. All your offscreen rules happen in a CSS file and not in Javascript.

In your  stylesheet add this class rule (which is applied to every HTML element you wish to have Cufón-ised) e.g <h2 class=”cufonised”>

 .cufonised { text-indent : -9000px; }

After your Cufon.replace javascript (which I place in a document.ready event handler), add this JS:

jQuery('.cufonised').removeClass('cufonised');

…which resets the text-indent style and shows the Cufón-ised text (i.e the “Cufon.replace()” happens off-screen to the left). visibility : hidden/visible doesn’t seem to work in IE here, so we resort to text-indent.

For non JS enabled browsers and devices, use a noscript tag to reset the style and show the un-Cufón-ised text

<noscript><style type="text/css"> .cufonised { text-indent : 0px; } </style></noscript>

After all that you should have a well behaved Cufón replacement happening cross browser.