Skip to page content or skip to Accesskey List.
Search evolt.org
evolt.org login: or register

Work

Main Page Content

Search Engine Friendly URLs with PHP and Apache

Rated 4.16 (Ratings: 17) (Add your rating)

Log in to add a comment
(79 comments so far)

Want more?

 
Picture of garrett

Garrett Coakley

Member info | Full bio

User since: June 27, 1999

Last login: August 26, 2006

Articles written: 4

Quick 'N' Dirty Intro

Anyone who has built template based sites that use query strings to select content will have at some point hit the problem of indexing (or lack of it) by search engines. Search engine spiders won't index dynamic sites, as they are worried about getting stuck in a maze of twisty URLs, all alike.

One way round this is to mask the fact that we're using a query string. Evolt itself uses this system (which you can see if you look at the current URL in your browsers location bar), albeit written in Cold Fusion. I'm going to show you a quick 'n' dirty way to do this in PHP. It's not the most feature complete way by any means, but it should at least provide you with a base to expand on.

Question Marks Are So 20th Century

We want to turn this

http://www.somesite.co.uk/site.php?section=books&subsection=architecture

into this

http://www.somesite.co.uk/site/books/architecture

which involves masking the file extension for the processing file and then giving the query string a shave and a haircut.

The Science Bit

Like all good things in life (Star Wars, cocktails), this little system is based on three ingredients:

  1. Setting up Apache to process a file without an extension as a PHP file.
  2. A function to process our URL and produce some variables.
  3. Something that uses those variables to provide content.

First, setting up Apache. In your .htaccess file (if you don't have one, go ahead and create it) you want these lines:

<Files site>
	ForceType application/x-httpd-php
</Files>

This tells Apache that if someone requests the file 'site' then it should be treated as a PHP file. Of course, you don't have to call it 'site'. If you were running a small online shop you might want to call it 'catalog'.

Next up, we need something that will take our new url and extract the information out of it. We do that with this function called processURI()

// processURI(): 
// Takes the query string and extracts the vars by splitting on the '/'
// Returns an array $url_array containing keys argN for each variable.
function processURI() {
 global $REQUEST_URI;   // Define our global variables
 $array = explode("/",$REQUEST_URI);	// Explode the URI using '/'.
 $num = count($array);	// How many items in the array?
 $url_array = array();	// Init our new array	
	
 for ($i = 1 ; $i < $num ; $i++) {	         
	$url_array["arg".$i] = $array[$i];  
 }
// Insert each element from the
// request URI into $url_array
// with a key of argN. We start $i
// at 1 because exploding the URI
// gives us an empty ref in $array[0] 
// It's a hacky way of getting round it
// *:)
	
return $url_array;  // return our new shiny array
}

This is a pretty simple function. First up it takes the $REQUEST_URI (everything after the server address basically) and then splits it into an array. After that it builds a new array ($url_array) containing arg1 to argN as keys, with their respective values.

The final piece in the puzzle is creating the file 'site' and doing something with all these variables that you've lovingly created. I've done just this up on http://members.evolt.org/garrett/site/books/factual

This is just a quick example of pulling in content based on the variables extracted from the query string. It's a list of books and CD's in my room. Not very interesting, but it was either that or a list of fruit and vegetables.

All the files can be downloaded from http://evolt.org/files/search_urls_php.tar.gz. This contains a .htaccess file, 'site' which has the processURI() function plus a roughly cobbled together function displayContent() to show it in action. There is also a directory 'content' which holds the files for inclusion.

That's A Wrap!

It's a very handy trick, and you only have to use evolts archive search to see how effective it can be (evolt uses Googles database to search its archives). As I said, this is a very quick approach and it could be improved in a number of ways but hopefully it's given you some ideas for your own site.

G.

Garrett has been working on the 'net since 1992 (he still gets misty eyed thinking about the first time he saw Mosaic) and now works for gencon as a developer / web standards monkey / Open Source advocate.

More of his ramblings and output can be found at his personal site

Hey!

Submitted by mccreath on August 21, 2001 - 14:26.

I understand it! Now I just gotta set something up to try it. Thanks, Garrett.

login or register to post comments

Update

Submitted by garrett on August 22, 2001 - 06:26.

No problem, glad it helped *:) BTW, I've updated the archive file on the site, it's only a minor tweak, but now it uncompresses into it's own directory instead of dumping the files into the current directory. It's a little tidier.

login or register to post comments

but

Submitted by pedrito on August 24, 2001 - 03:31.

How is this different from using apache rewrite module? I have been getting frustrated with that rewrite module for a long time... But I don't understand why you don't just get a 404 with your method?? Why does it work?

login or register to post comments

How It Works... heh.. Good Question!

Submitted by garrett on August 24, 2001 - 06:02.

Query strings are merely a way to pass variables through to a page to allow the page to act on them. Whether that page is a Perl script, a COM object, or even SSI doesn't matter, there's nothing inherently magical about query strings themselves. You just have to agree on how they will arrive, and what you're gonna do with them.

The mod_rewrite way does everything inside of Apache itself. The way I've oulined above, we pass the burden of processing over to PHP. It has to worry about whether the files are there or not.

When someone requests site (as per the example above), Apache reads the .htaccess file for that directory, sees that 'site' is to be processed as a PHP file, and calls the PHP module to do the rest of the work. The only bit Apache cares about at this point is that 'site' exists.

From this point in, PHP is doing the work, mangling and chewing on the variables we've sent it, once it's finished, it passes the content back to Apache for serving to the client.

As I have it at the minute, if no valid file is found, then it defaults to an error file that will show you the array you have produced. So content is always returned. But you could just as easily send back a 404 error and a custom error page. It's all up to you.

Has this helped you any? If you're still not sure, holler and I'll try again.

login or register to post comments

Doesn't work for me

Submitted by jobarr on August 28, 2001 - 03:38.

I am sure something is just set up wrong, but do you know why it would still display site as plain text instead of running the code? -Jobarr

login or register to post comments

Displaying as plain text

Submitted by garrett on August 28, 2001 - 04:06.

When you say displaying as plain text, do you mean that the raw code is appearing in the browser? It sounds like apache isn't paying any attention to the <Files> directive. Do you have an example URL I could have a look at?

login or register to post comments

URL

Submitted by jobarr on August 28, 2001 - 04:28.

http://www.herzeleid.com/test/site yes, it just shows the raw code and doesn't execute anything.

login or register to post comments

Displaying As Plain Text

Submitted by garrett on August 28, 2001 - 04:46.

Ok, that's definately a problem with the .htaccess file. It could be a couple of things. First off, is it in the same directory as "site" (it should be if you're using the archive from my evolt account)? Do you have permission to use .htaccess files? It could be that your host doesn't allow the use of certain .htaccess features.

login or register to post comments

working..?

Submitted by jobarr on August 28, 2001 - 05:07.

Ahh...ok, I got it working....except I get a internal server error when I try any of the 4 links =(

login or register to post comments

Server Error

Submitted by garrett on August 28, 2001 - 06:02.

Hmmm, you're getting a HTTP 500 error code. This is an internal server error. You'll need to check things like the file permission for the included content and whether the file extensions are correct (does apache know that .php is a PHP file?), What does the error log say?

login or register to post comments

Error log

Submitted by jobarr on September 11, 2001 - 01:35.

Heh...a little late responding, hopefully you'll still read this =) Ok, my error log says simply: [Tue Sep 11 00:25:08 2001] [error] [client 192.168.0.2] Premature end of script headers: c:/php/php.exe Yes, it knows that .php is a PHp file.

login or register to post comments

The problem is...

Submitted by jobarr on September 11, 2001 - 03:49.

Ok....the problem is that is doesn't like a / after a php file. If I have a php file that does a simple echo("hello"); and try to access it as http://site.com/test.php/var, it will report an error even though it is not doing anything with the text after it. http://site.com/test.html/var gives no problems though, so it is specific to php (or at least cgi). Maybe it is because I am running PHP as a CGI and not a module?

login or register to post comments

Problems

Submitted by garrett on September 11, 2001 - 05:53.

Hmmm.... ok, from the error message, you're running on a Win32 machine, I'm a unixy person and don't have a great amount of experience with serving from windows, so take all this with a pinch of salt.

A couple of things to check:

  • Premature End Of Script Headers could be down to permissions on the file. What happens if you call test.php by itself with no trailing information?
  • I notice that you've still got the file extension on test.php. Have you set up the .htaccess file as per the instructions? What happens if you call http://site.com/test/var?

As I said, I'm not a windows person, someone else might be able to jump in and help here, or we can transfer this to thelist and see if anyone else has some ideas?

login or register to post comments

Got it to work

Submitted by jobarr on September 11, 2001 - 12:20.

Ok, I got it to work. I had to use PHP as a module instead of a CGI. So, perhaps my CGI config is messed up or maybe it just won't work on a win32 box as a CGI.

login or register to post comments

good idea

Submitted by nico on September 17, 2001 - 06:05.

that's a really good trick. i'm gonna use this for sure ;)

login or register to post comments

Friendly URLS via IIS and ASP!?!

Submitted by mpgnet on November 12, 2001 - 15:44.

Does anyone know how to do this via IIS and ASP?

I could use this a bunch but I do everything in ASP's. If someone can help or direct me to help I would appreciate it.

login or register to post comments

RE: IIS and ASP

Submitted by DamianM on November 12, 2001 - 17:05.

Hi

Unfortunately IIS isn't as configuarable when it comes to toys like this. Unless you wanted to write an ISAPI filter (hint : you don't) the best way to do it....would be to write a custom 404 page.

This 404 page would have to parse out the URL, then look for the article that matches the criteria i.e. section=books, criteria=architecture

If it couldn't find anything then show a not found message, if it does find something then display that article.

It is possible, however wouldn't be very pretty, you would want to do a lot of testing to make sure weird URLs didn't crash it.

It sounds like a fun project though, if you do it, post it :)

login or register to post comments

Re: IIS and ASP

Submitted by mpgnet on November 12, 2001 - 18:51.

Well, I like the idea and started to tackle it but sadly I can't execute any ASP script in a 404 error page. I have a page (404a.asp) set as my error page and I can't execute any ASP script on that page.

That makes since to me but if someone knows how this CAN be done please let me know and I'll be glad to start working on this project.

login or register to post comments

Nevermind

Submitted by mpgnet on November 12, 2001 - 19:28.

Okay, changed the type from file to URL and get things on the roll. I'll let you know when I'm done.

login or register to post comments

Great article.

Submitted by nakedgremlin on November 27, 2001 - 11:18.

The .htaccess example alone solved so many problems I had with tweaking out a nice "non-question marked" URL.

Does any one know of spot where there is a complete list of MIME types? (ie. application/x-httpd-php, application/x-httpd-cgi, etc.)

login or register to post comments

What if I want to parse all requests?

Submitted by ezra on December 16, 2001 - 17:17.

As I see it, the example shows how to parse all requests beginning with 'site' with the script named site. I'd like to be able to parse all requests. (i.e. if someone requests http://mysite.com/ezra I will be able to parse the string 'ezra' in a PHP script.) Thanks for the help.

login or register to post comments

Follow-up to my previous comment

Submitted by ezra on December 16, 2001 - 18:40.

Well, I looked around at apache.org and constructed the following solution. It passes all urls that are constructed like http://mysite.com/ezra and mysite.com/ezra/comments/ into a script (here I called it process.php). If the url ends in a file extension (i.e. test.jpg) this url doesn't go to process.php -- it just gets called.

You can then parse the variable $query from process.php

I put this as my .htaccess in the document root directory for the server:

RewriteEngine On
# If they are looking for process.php we're done
RewriteRule ^(process.php.*) $1 [L]

# If they are looking for a file with a file extension let them get at it
RewriteRule ^(.*\..+)$ $1 [L] 

# Otherwise send their request to process.php
RewriteRule ^(.*)$ process.php?query=$1 [L]

login or register to post comments

an improvement could be

Submitted by Martin Tsachev on February 22, 2002 - 01:57.

An improvement to the suggested rewrite rules can be

RewriteRule ^(process.php.*) - [L]
RewriteRule ^([^\.]+)$ process.php?query=$1 [L]

login or register to post comments

configuration issue or module vs. CGI issue?

Submitted by ylanl on February 28, 2002 - 14:24.

I am running the CGI version of Apache on win 98. I am getting the 500 internal server error when I attempt to use this trick, just as jobarr was before he switched to the module version. Also, my error log entry is identical to his.

Unfortunately, I don't have the option of switching to the module version of Apache, so I was wondering if anyone knew whether this was indeed a module vs. CGI issue, or whether I could change something in my configuration to get it to work.

Thanks.

login or register to post comments

This is all cool, but...

Submitted by jesteruk on March 9, 2002 - 16:16.

Everything worked fine on my m.e.o account, until i went to use a txt file to show some source code and the server forces it to be parsed as a PHP file, annoying.

login or register to post comments

Re: This is all cool, but...

Submitted by mwarden on March 9, 2002 - 16:58.

Yeah, the forcetype declaration makes it that way for that folder. You'll have to store it in a different folder.

Or, you could create a php script that reads the source of another php script and spits it out. That way, you can even color code it, if you want. Many sites do it this way, including php.net

login or register to post comments

why, oh why?

Submitted by fraggle on March 9, 2002 - 18:18.

this method's sloppy cuz it requires you to strip the extension off all your scripts it'd be better to have a file like local.php (WITH EXTENSION) map to www.dotcom.com/local/ without needing an accompanying rewrite directive for every script. this way urls like /local.php?var=22&var=112 and the new /any_other_script/var/var would still work. this way I wouldn't have to rename all my *.php files to just *, and I wouldn't have to hunt down every site that linked to me with the old urls.

secondly, when u do this some references to files may become more difficult to maintain such as CSS and JS file includes -- if your structure is complicated. for my whole site, i use a "COMMON" folder which is above the site root. so i need to use ../common/file.js etc.

lastly, and most importantly, pls correct me if i am wrong, but google now saves all kinds of URLs so all this stuff is not needed. AV and lycos have saved URIs for a while now.

good effort at explaining the techniquue, but completely unnecessary!

login or register to post comments

nah

Submitted by jesteruk on March 9, 2002 - 21:55.

I kinda like it, the URL looks tidier

And as for storing it in another folder, i did, plus i tried renaming the file to filename.phps and it worked fine, showed the source all colour-coded and stuff, but for some reason it only read a certain number if lines in, and then cut off halfway through the script, i thought this was my browser or somethin' so i had other people check it and they had the same problem, when i shortened the script, took some comments out, and it displayed it fine *shrug* weird.

login or register to post comments

php output buffering

Submitted by Martin Tsachev on March 10, 2002 - 00:27.

Jester you have problems with PHP's output buffering, I have reported the bug to PHP and I hope it could be solved soon.

login or register to post comments

ah i see

Submitted by jesteruk on March 10, 2002 - 10:27.

This was on my m.e.o account shaggy. My site worked fine on my computer, win 98, apache, php4, but when i uploaded it alot of things broke. I think i fixed most of it now though, i hope!

-J

login or register to post comments

I know what you're talking about

Submitted by Martin Tsachev on March 16, 2002 - 00:08.

The hosting at members.evolt.org uses the recommended value of PHP's output buffering 4096. While this as the documentation states should improve performance it surely cuts the PHP colored sources.

If you want all your sources shown you will have to disable output buffering.

login or register to post comments

thanks shaggy

Submitted by jesteruk on March 16, 2002 - 08:56.

But i just showed the source on an HTML page, too much bother showing the colour source thingy.bollocks to it.

-J

login or register to post comments

Help

Submitted by rzconcepts on April 13, 2002 - 18:11.

Hello Garrett,

Could you contact me, I am interested in Paying you to show me how to do this. I've tried and am not that great at coding. My E-Mail Is Info@ItalyVillaRentals.Com. Also, can this work with asp also?

Regards, Randy

login or register to post comments

re:help

Submitted by Martin Tsachev on April 13, 2002 - 18:20.

I think you can do this in ASP by setting a custom 404 page and then sending a Status: 200 to the webserver to pass to the browser.

IIS doesn't have a rewrite module as far as I know.

login or register to post comments

re: help

Submitted by Martin Tsachev on April 13, 2002 - 18:25.

I mean to send a header Status: 200.

I'm sorry if it looked like it should work with plain text.

login or register to post comments

Re: Help

Submitted by garrett on April 14, 2002 - 04:24.

Randy,

I'm flattered that you want to pay me, but there is really no need. If you have any problems with implementing the article then feel free to ask me, or, even better, sign up for the evolt.org discussion list at http://lists.evolt.org/index.cfm/a/listinfo. You'll find lots of talented developers there who will be able to help.

As for the ASP side of things, someone else will have to explain that. I don't have any experience of the Microsoft side of web development.

login or register to post comments

How Would One Do This in ColdFusion?

Submitted by mwallick on April 22, 2002 - 09:24.

Hello Garrett. Great article by the way.

At the beginning of your article, you mention that evolt.org uses this technique, but using ColdFusion instead of PHP. How would one set up apache to to this? Does it require recompiling the apache module to not check for file extensions or what? Or is it a trade secret you're not allowed to divulge to the masses?

Again, great article, works like a champ in PHP, but here at work, we're a ColdFusion shop.

Mike Wallick
mike@wallick.net

login or register to post comments

Garrett: Passing Form Values?

Submitted by mobileserver on May 11, 2002 - 06:20.

Garrett- I have set up a test environment using the "site" script to direct page requests. All seems to be working well except I can't seem to get forms to pass values correctly from one included page to another .

i.e.- I have a signup form at http://www.domain.com/site/signup/form1

and I do a "POST" to http://www.domain.com/site/signup/form2

The values from form1 do not pass from to form 2. All I get are blank entries.

On the other hand, if I do the following all works beautifully:

I have a signup form at http://www.domain.com/site/signup/form1

and I do a "POST" to http://www.domain.com/content/signup_form2.php

Can you offer a newish programmer some advice?

login or register to post comments

Multiple File Like site(.php)

Submitted by wahyu on May 29, 2002 - 05:51.

How to create htacces to request multiple files like site, district, product, .... until maybe more that 200 files, im tryed but there was doesnt work.

login or register to post comments

Questions & answers

Submitted by garrett on May 31, 2002 - 05:48.

Sorry I haven't got back to your questions sooner... I'm slack, I know.

Mike, as far as I can remember (and I don't use CF, so I could be totally wrong) the evolt.org CMS makes use of a custom 404 page to produce the URL's. No recompiling of Apache needed. .jeff's the guy you want to talk to though. He's the talented monkey that built it.

Chris, I'm not entirely sure what the problem you're having is, I have a few suspicions, but if you want to email me over your code then I'll see what I can do for you.

Wahyu, you have to remember that this is an entry level article, and isn't really designed to scale up to the kind of level you're talking about. You could probably hack it with mod_rewrite but it wouldn't be pretty. A better bet is ask over on our mailing list. Lot's of talented brains just itching to get their cerebellums around a problem like that.

login or register to post comments

Why isnt it working plz?

Submitted by lee123 on June 18, 2002 - 07:42.

Hi.. im trying to make the SEARCH ENGINE FRIENDLY script work. But am failing thus far... This is a sample page which i am trying to call.. Previously : http://www.imsingle.com/preview.profile.php?mode=fsearch&id=AtlasXL&ty=r Now : http://www.imsingle.com/site/preview.profile/fsearch/AtlasXL/r Sometimes it displays the page, but everything is messed up. As though the INCLUDE "header.inc.php" file is not be called (top of page) Any help would be much appreciated. Thanks

login or register to post comments

This is great...but it doesn't work

Submitted by BlueGus on July 4, 2002 - 15:51.

At least not yet.

The page is:
www.FoggyNoggin.com/test/site

Apache is set up to be able to use my .htaccess file, but when I access 'site' I get an Internal Server Error. When the .htaccess file is removed, the error goes away, but then 'site' doesn't get processed.

In my error log, I get "FoggyNoggin/test/.htaccess: Missing </Files> directive at end-of-file" even though the </Files> tag is clearly in the .htaccess file.

I'm using a virtual server directive, but I don't think that's the problem. Any ideas? Thanks!

August

login or register to post comments

Probs on Windows (Apache Mod_php)

Submitted by Till_Dawn on August 12, 2002 - 08:19.

Thank's for this article, that's exactly what I was looking for a long time. Even if it doesn't work on my mashine. I'm running Apache2 with mod_php 4.2.2 on a Win2000 Computer.

Can you explain what kind of "hard coded links" you used in your example, are they relative to the DOCUMENT_ROOT

[DOCUMENT_ROOT]/garrett/site/books/factual

or to the Unix root

/garrett/site/books/factual

However, what should I use on Widows?

  • "E:/htdocs/development/site/books/factual" ///or even with backslash

or a http:// link

  • "http://192.168.0.1/development/site/books/factual"

I think thats the main reason, why it doesn't realy work on windows. I better try that thing with rewrite.

login or register to post comments

Please ignore the last one

Submitted by Till_Dawn on August 12, 2002 - 14:58.

Im stupid, please ignore my last message. I fixed my prob.

login or register to post comments

Great article! - but problems with paths

Submitted by hughprior on August 21, 2002 - 01:58.

I think the article is really fantastic!! (I tried and later abandoned trying to do this sort of stuff via .htaccess rewrite rules, but keeping it all in the PHP family makes life soooo much easier).

Anyhows...I've got things mostly working except I have a problem with paths (and I don't like the solution of the article "Search Engine Friendly URLs (Part II)", as it seems I have to change ALL my files - yuk.

The problem is this:

I am trying to create static pages for the site LocalPin regional search engine aka the Link To Us section on this site which is currently generated statically. I have created a 'site' file as described in the article, and created a .htaccess file which does the ForceType change. Works like a dream (though I must say for testing and keeping Dreamweaver happy I keep the file named site.php, rather than just site). However, when I include a file from a different directory, it does not get the paths right.

What I want to do is:

$my_other_file = "main/search_result.php";<br>
include($my_other_file)

but my other file begins with the lines:
require_once("../config.php");

and when I include it, I get the error:

Fatal error: Failed opening required '../config.php' (include_path='.;./class;../class;./template;../template;../class/form;./class/menu;../class/menu;') in c:\program files\apache group\apache\htdocs\localpindev\main\search_result.php on line 2

Any ideas how to do the include AND have the paths working OK? As I said, I would like to try and keep the included file(s) unchanged, and do it from the file doing the include.

login or register to post comments

How to change type from file to URL?

Submitted by chetlet on November 13, 2002 - 23:41.

How do I change the type from file to URL ? Is this done in the .htaccess file? thanks

login or register to post comments

IIS rewrite module

Submitted by shotgun on November 20, 2002 - 07:32.

In response to: shaggy

IIS doesn't have a rewrite module as far as I know.

Yes, it does. Look here IIS Rewrite or here ISAPI Rewrite

P.D.: these are NOT the only ones that expand IIS functionality, there are other products. Just SEARCH!!!

login or register to post comments

Apache2

Submitted by chx on November 30, 2002 - 02:22.

With Apache2 (Apache 2.0.30 and above) you need to use AcceptPathInfo On besides the ForceType directive.

login or register to post comments

Apache look back not working, Coldfusion, plus...

Submitted by pete.francomb on February 10, 2003 - 04:26.

I'm looking to do something similar to that suggested in your article, but with Coldfusion. I noticed you mention that evolt uses Coldfusion. I have a standard Fusebox template for converting user-friendly URLs to attributes scope variables, so apart from perhaps using the ForceType directive to lose the ".cfm" extension, all I should need is for the Apache look back feature to work.

Unfortunately, both on my Windows development server and my Linux production server, the Apache look back feature doesn't seem to be working. It simply throws a 404 error if there's any forward slash after the file I'm interested in. I'm running Apache 1.3.2 on both machines. I've tried using mod rewrite to replace the forward slash after my index.cfm file with a question mark, but Apache returns an internal server error 500. My mod rewrite routine works with "index.htm" instead of "index.cfm". Here's the rule:

RewriteRule ^/spingyro/index.cfm/(.*) /spingyro/index.cfm?$1

I expect I'm barking up the wrong tree here anyway - I just need the look back feature to work as I've been led to believe it should.

Also, how do I use the ForceType directive with Coldfusion MX? What type is it?

Any help gratefully received.

login or register to post comments

mod_rewrite

Submitted by minivip on February 10, 2003 - 10:49.

Have made some experiences wirh mod_rewrite long time ago, but only with php, not cfm. I really don't know whether it makes any differences, but perhaps a $ behind ^/spingyro/index.cfm/(.*) could help. only a silly guess. Beyond the apache original documentation at http://httpd.apache.org/docs/mod/mod_rewrite.html a lot of helpful information concerning mod_rewrite can be found at www.engelschall.com/pw/apache/rewriteguide/ or www.webmasterbase.com/article/910.

login or register to post comments

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.orgEvolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.