[pmwiki-users] How can I redirect...

Joachim Durchholz jo at durchholz.org
Tue Nov 22 08:36:29 CST 2005

Robert Riebisch schrieb:
> from a, e.g., "http://www.bttr-software.de/fix8x14/" to
> "http://www.bttr-software.de/Products/FIX8X14/"? Problem is the lower
> case "fix8x14" which results in "HTTP 404 - File not found". :-(

Try making the filename lowercase :-)

In case that isn't possible, you'd need to redirect.

Here's something that I did, in an unrelated project:

In .htaccess, I made sure that every single URL was internally 
redirected to a local portal.php script, like this:

RewriteRule ^portal\.php$ - [L,PT]
RewriteRule ^(.*)$ portal.php?url=$1 [L,PT,QSA]

(The second rule is usually triggered first, the first rule is just 
there to break the infinite loop that the second rule alone would 
create. I'm pretty sure there are better ways to achieve this, but 
mod_rewrite and its interaction with Apache's internal processing aren't 
documented well enough to get something better to work without 
experimentation - I'll happily accept any improvements.)

Now portal.php inspects $_REQUEST ['url'] and Does the Right Thing (TM) 
for each URL. The general layout looks like this:

--- snip ---
# Determines results for each kind of URL.

error_reporting (E_ALL);

# Helper functions that tend to be useful.

function ok_file ($file, $mimetype) {
   # Delivers a file with a known MIME type.
   # Actually this function could determine the file type on
   # its own, by using `file --mime $file`.
   # Or it could use mime_content_type ($file).
   # However, this function is a bit more general since the
   # caller can force a given MIME type on the file contents,
   # e.g. you can say "application/octet-stream" to force
   # browsers into storing the file on disk instead of displaying
   # or executing it.
   header ('Content-type: ' . $mimetype);
   readfile ($file);

function not_found () {
   # That's our own error document handler.
   # Do anything more elaborate here if you wish :-)
   header ('Status: 404 Not Found');
   require ('error404.html');

function forbidden () {
   header ('Status: 403 Forbidden');
   require ('error403.html');

# Do the standard "no URL means index.*" convention here.
$url = $_REQUEST ['url'];
if ($url == '') $url = 'index';

# A sample URL parser.
# In this case, only letters, digits, and minus signs are allowed,
# with an optional pdf/png/gif extension.
# Files with other special characters in them will not be served,
# i.e. they are hidden from browsers' views. That's great for storing
# work files in the document tree.
if (! preg_match ('/^[a-zA-Z0-9-]+(\\.pdf|\\.png|\\.gif)?$/', $url)) {
   not_found ();

# You could do all things of processing here.
# E.g. search multiple directories for a given file; this decouples
# the URL structure from the access privilege structure. You can also
# fake a subdirectory structure (that may be useful for scripts
# running under Safe Mode).
# You could canonise URLs, by returning a Redirected Permanently
# header.
# In other words, you can do everything that mod_rewrite does,
# but in code that *you* can inspect and modify :-)

# The code here could do several things:
# Find a file to serve, and say
   if (file_exists ($file)) {
     if (is_readable ($file)) {
       ok ($datei, mime_content_type ($file));
     } else {
       forbidden ();

# Try various filename extensions.
# You can do your own form of content negotiation that way;
# e.g. if you know there was no extension in the URL,
# do something like this:
   $file = $prefix . '.html';
   if (file_exists ($file)) {
     if (is_readable ($file)) {
       ok ($datei, 'text/html');
     } else {
       forbidden ();
   # .html didn't work, try .php
   $file = $prefix . '.php';
   if (file_exists ($file)) {
     if (is_readable ($file)) {
       # A warning: any globals that were defined within
       # portal.php will remain active in the PHP file.
       # unset() them if you don't want this.
       # (I was once stumped when I found a global $url
       # variable in all of my scripts, as couldn't remember
       # that documented as PHP behavior. Turned out it was
       # my own portal script...)
       require ($file);
       die; # 'die' might not be the Right Thing here.
     } else {
       forbidden ();

# Finally, if none of the above worked:

not_found ();
--- snip ---

This framework has served me well for one project. It's just a hack, of 
course, and explicitly coded everywhere instead of picking its choices 
off tables or configuration files - but it can do more than mod_rewrite. 
E.g. Robert could uppercase the URL and try to find the file with that name.
Note that there are also subtleties with serving URLs that refer to a 
subdirectory. I haven't tested that case extensively (it's not an issue 
on my site), so there might be surprises waiting here.


More information about the pmwiki-users mailing list