cssyphus
cssyphus

Reputation: 40038

.htaccess do something else if file not exist

We are using an .htaccess in combination with anchor tags to serve files and conceal the server directory structure.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /_docu/clients/$1/$2/$3.pdf [NC,L]

For example, all files are stored under /public_html/_docu/clients/ and inside that folder are listed all the clients, and then under each client their projects. However, an anchor tag for a file would read only:

http://mydomain.com/client-name/proj-name/docname.pdf

(the /_docu/clients/ being omitted - there is a good reason for this). The above .htaccess grabs the client-name, proj-name and docname and serves it from the correct folder:

http://mydomain.com/_docu/clients/client-name/proj-name/docname.pdf

whilst preserving in the address bar the incorrect (concealed) directory structure.

I wish to handle the error condition of a document not existing. This should never happen, but it could. Can anyone suggest a way of dealing with this? Can something functionally akin to "if fileexist($1/$2/%3.pdf)" be somehow constructed in an .htaccess file?


EDIT:

Delayed response as JL's answer below required research and experimentation. Thanks, Jon, for the gentle push in the right direction but I haven't got it to work just yet. Here's what I tried:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# check if the requested file exists in the "_docu/clients" directory
RewriteCond %{DOCUMENT_ROOT}/_docu/clients/$1/$2/$3.pdf -f
RewriteRule ^([a-z0-9])/([a-z0-9])/([a-z0-9]*).pdf$ /_docu/clients/$1/$2/$3.pdf [NC,L]
RewriteRule ^(.*)$ /errors/404.php [L]

I thought that what that should do is:

  1. If http://mydomain.com/_docu/clients/$1/$2/$3.pdf does not exist,
  2. GoTo page http://mydomain.com/errors/404.php

Actual outcome is an "internal server error" message.


EDIT TWO:

Latest changes:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/([a-z0-9])/([a-z0-9])/([a-z0-9]*).pdf$
RewriteCond %{DOCUMENT_ROOT}/_data/cli/%1/%2/%3.pdf -f
RewriteRule ^([a-z0-9])/([a-z0-9])/([a-z0-9]*).pdf$ /_data/cli/$1/$2/$3.pdf [NC,L]
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteRule ^(.*)$ /metshare/404.php [L]

The problem with this one is that legitimate pages also are directed to 404.php

MESSAGE TO FUTURE READERS:

All of the above concerns were addressed in Jon Lin's final answer. As issues were detected, he modified his answer until it was a perfect, working solution. I am leaving the above as it is because there are some good ULOs within (unscheduled learning opportunities) for those who want to compare versions.

Upvotes: 0

Views: 896

Answers (1)

Jon Lin
Jon Lin

Reputation: 143866

You need to use a condition like this:

RewriteCond %{DOCUMENT_ROOT}/_docu/clients%{REQUEST_URI} -f

So that your rules looks ssomething like:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# check if the requested file exists in the "_docu/clients" directory
RewriteCond %{DOCUMENT_ROOT}/_docu/clients%{REQUEST_URI} -f
RewriteRule ^ /_docu/clients%{REQUEST_URI} [L]

EDIT: Response to edit in question

You can't do this:

RewriteCond %{DOCUMENT_ROOT}/_docu/clients/$1/$2/$3.pdf -f

Because the backreferences for $1/$2/$3 don't exist yet, they are matched in the groupings in your RewriteRule, which hasn't happened yet at this point. But you can try something like this:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# check if the requested file exists in the "_docu/clients" directory
RewriteCond %{REQUEST_URI} ^/([a-z0-9])/([a-z0-9])/([a-z0-9]*).pdf$
RewriteCond %{DOCUMENT_ROOT}/_docu/clients/%1/%2/%3.pdf -f
RewriteRule ^([a-z0-9])/([a-z0-9])/([a-z0-9]*).pdf$ /_docu/clients/$1/$2/$3.pdf [NC,L]

RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /errors/404.php [L]

Essentially creating a match against %{REQUEST_URI} in a previous RewriteCond then using the %N backreferences in the following RewriteCond.

Upvotes: 1

Related Questions