Jump to most recent update (0617.2000)..

The PHP Snurk - v0.02

When you run a database-driven website, it makes sense to generate pages on the fly. PHP, MySQL, and Apache let you do just that... But they don't make it pretty. How many times have you had to create a URL that looks like this:

http://www.schmoop.com/snurk.php3?snurk=23497

... when what you wanted was a URL like this:

http://www.schmoop.com/snurk/23497

...?

A while back, Tim Perdue wrote a PHP Builder Article that walked you through modifying Apache's access.conf file to create user- and search-engine friendly URLs.. Which is all well and good, but what if you don't have access to access.conf?

Snurk makes it possible!

With Snurk, all you need is the ability to run custom CGI scripts, an .htaccess file, and a little bit of time and effort.

Right now, the Snurk method has only been tested with unix-based web hosting services that run PHP3 through CGI. If you get it working on other systems, please email snurk@sabren.com for the next version.

If there's enough interest in this, future versions of Snurk will automate some of the setup for you, but right now, Snurk consists of four very simple files, which are listed below, and must be modified by hand.

How to Snurk your script

explore.php3

First, create a new PHP3 script, explore.php3 with the following lines:

<?
   print "PATH_TO_SH is: ";
   system ("which sh");
   print "<HR>\n";

   phpinfo();
?>

When you run this script, PHP will give you all kinds of information about your environment variables and server paths. Write down the following values:

snurk

This is your database driven PHP3 file. You can call it whatever you want, but most likely, you'll want to make it look like a directory. In this case, our directory is called snurk. The goal is that whether a browser requests snurk, or snurk/apple, or snurk/234, or snurk/whatever.php3?X=34, only one file will ever actually be run, and that's snurk.

If that's the case, snurk needs to know what page the browser thinks it's getting. You can figure it out by putting this chunk of code at the top of your page:

## SNURK STUFF ##########################

  $url_array=explode("/",$REQUEST_URI);
  $product = $url_array[count($url_array)-1];

  # strip off extra stuff in the URL:
  if  (strpos($product, '?')) {
     $snurk = substr($product, 0, strpos($product, '?'));
  }

## END OF SNURK STUFF ##################

// the rest of your script goes here...
// $snurk contains everything after "snurk" in the URL

// here's a highly useful example script!
print "hello, world! snurk is $snurk\n";

Actually type in the "hello, world!" stuff, or something like it - you'll use it for testing in a minute.

When you pull up snurk in your browser, you should actually see the above source code. That's because Apache doesn't yet know you want to run it as PHP. So, to fix that...

phpsnurk.cgi

This file is the heart of PHP Snurk. It gives you a chance to trick PHP into running a specific script, instead of whichever script the browser happened to ask for.

We want to tell PHP to run snurk. Given the PATH_TRANSLATED you wrote down, you should be able to figure out what snurk's PATH_TRANSLATED would be. Stick that and the other variables you wrote down into the file below, and save it as phpsnurk.cgi. (You'll have to chmod 777 it and put it in a directory that allows CGI, just like any other CGI script.)

#!PATH_TO_SH
export PATH_TRANSLATED=PATH_TRANSLATED_FOR_SNURK
SCRIPT_FILENAME

Pull this page up in your browser. If everything's working, it should say "hello, world!" and tell you that snurk is "phpsnurk.cgi". If not, something's wrong and you're on your own. :)

Future versions will allow you to have multiple PHP files all using the Snurk method, but for now, you'll have to do this once for each file. (If you know the [probably very simple!] shell scripting to make a "case" statement - send it to me... otherwise, the rest of you can wait until I look it up)..

.htaccess

Finally, you need to tell Apache to run phpsnurk.cgi every time a browser requests snurk. Go to the directory that contains snurk and put the following text in your .htaccess file. (the path to phpsnurk.cgi should be the relative path as the browser would see it.)

Action phpsnurk /cgi-bin/phpsnurk.cgi

<Files snurk>
ForceType phpsnurk
</Files>

That's it! Pull up snurk/whatever in your browser, and snurk will run!

Questions

Why in the bloody blue blazes of hell did you call this thing "PHP Snurk"?
Well, I was going to call it "sneaky-php", but I figured that might raise some eyebrows with nervous web hosting sysadmins, when it's really all pretty innocent. So instead of a sneak, it's just a snurk. Now you know.

Future Plans?
It would be nice if Snurk could handle more than one file like this on a site.. I'm imagining a "snurk control panel" that sets up all the files and variables for you, and lets you configure which URLs map to which scripts. I probably won't bother, though, unless enough people ask. (snurk@sabren.com)

Update

0719.1999

Marinos J. Yannikos (mjy at pobox.com) offered a much simpler solution if your Apache has mod_rewrite installed:

> I'm using mod_rewrite to achieve the same effect:
>
> RewriteEngine On
> RewriteBase /foo/blah
> RewriteRule index.php3.* - [L]
> RewriteRule ^(.*) index.php3/$1
>
> If this is put in the .htaccess in a directory with local URL
> /foo/blah, then all accesses like /foo/blah/1/2/3 go through 
> the script index.php3 (which gets the usual PATH_INFO etc.). 
> Works fine with php3 as a module, and probably with all other
> types of scripts as well.

I got this method working with php3.cgi as well, but you have to change the last line a bit:

 RewriteEngine On
 RewriteBase /foo/blah
 RewriteRule index.php3.* - [L]
 RewriteRule ^(.*) index.php3?fakepath=$1

Otherwise php3.cgi gives an "unable to find script" error. Thanks, Marinos!

0617.2000

A year later, and I finally find out that you can do this with a simple 404 page after all. (That's what I tried to begin with!) To change the error code on just about any cgi/php page, you just send a "status" header.. For example:

<?php header("status: 200"); ?>

Thanks to Phil _______ (knoebi at gmx dot net) for getting the 404 concept working. He reported that he got the following line to work, though it gave me an internal server error with apache:

<?php header("http/1.0 200 Ok"); ?>