• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 331
  • Last Modified:

Mod_Rewrite Search Multiple Folders

I'm having trouble with mod_rewrite.

I have a virtual host with a directory structure like this:
    ./
    ./one/
    ./two/

Open in new window


I want apache to search the ./ (default folder, including aliases inherited from the httpd.conf). If no file is found then check the ./one/ folder then if it's still not found search the ./two/ folder otherwise return a 404.

The url should never contain /one/ or /two/ (unless explicitly added by the user).

Here's the vhost.conf:

<VirtualHost *:80>
        RewriteEngine On
        RewriteOptions Inherit

        #..irrelevant stuff here..

<Directory /var/www/html/site.com>
            Order allow,deny
            Allow from all
            AllowOverride none
</Directory>
</VirtualHost>

Open in new window

0
huntedcow
Asked:
huntedcow
  • 7
  • 5
2 Solutions
 
xtermCommented:
Well, firstly you need to set AllowOverride to FileInfo if your rewrite rules are in .htaccess files, or are you hardcoding these into the VirtualHost itself?  (you have a "# irrelevant stuff" comment in the place where it seems the most relevant stuff would go is why I ask)
0
 
huntedcowAuthor Commented:
They are hardcoded into the virtual host itself.


DirectoryIndex index.html index.htm index.php

RewriteLog /var/log/httpd/site.rewrite
RewriteLogLevel 9

ServerName site.com
ServerAlias *.site.com
ServerAdmin webmaster@site.com
ErrorLog /var/log/httpd/site.error
CustomLog /var/log/httpd/site.log combined
DocumentRoot /var/www/html/site.com

Open in new window


That's all that's in the #..irrelevant stuff here.. section. Sorry for leaving it out.
0
 
xtermCommented:
Okay, so help me understand what you're wanting to do here.

If somebody goes to site.com/foo.htm, you want to:

a) Check if foo.htm is in the root folder, and if so load it
b) Check if foo.htm is in the root/one folder, and if so load it
c) Check if foo.htm is in the root/two folder, and if so load it
d) If not found anywhere, send a 404 not found.

Yes?
0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

 
huntedcowAuthor Commented:
Yes, exactly.
0
 
xtermCommented:
Okay, my "real" job sidetracked me but I'll put together some rules for you later if another expert doesn't beat me to it...
0
 
huntedcowAuthor Commented:
Thank you it's very much appreciated, I've tried for 3 days to get this to work :\
0
 
xtermCommented:
Here you go, this should do what you need using .htaccess files (this is much more portable than trying to put them into httpd.conf.  You will need to turn AllowOverride = FileInfo though for Directory /var/www/html/site.com, and restart httpd)  I gave you two options for the .htaccess file in /two, explained below

The logic is:
1)  /.htaccess doesn't find the file, redirects user to /one/<filename>
2)  If file is not found in /one/<filename>, redirect user to /two/<filename>
3)  If file is not found in /two/<filename> do either
  a)  Redirect user to custom 404 page
  b)  Tell user that /two/<filename> wasn't found and present actual code 404

# /.htaccess
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/$0 !-f
RewriteRule ^(.*)$      /one/$1 [L,R]

# /one/.htaccess
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/$0 !-f
RewriteRule ^(.*)$      /two/$1 [L,R]

# /two/.htaccess to go to your custom 404 page
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/$0 !-f
RewriteRule ^(.*)$      /404page.htm [L,R]

# /two/.htaccess to create 404 code rather than the 404 page
RewriteEngine Off

Open in new window

0
 
huntedcowAuthor Commented:
This is almost exactly what I was looking for however, once it rewrites the URL it adds /one/index.html or /two.index.html

The url should never contain /one/ or /two/ (unless explicitly added by the user).

It works great apart from that. Any ideas of how to fix this too?
0
 
xtermCommented:
This wouldn't be a fix - the definition of "rewrite" is to do exactly that - change the URL - this behavior cannot be changed while still using mod_rewrite.

However, there is an alternate approach (should really be a separate question, but what the heck, I'll tell you how I'd do it if I had to for some reason) and very easily achievable with PHP.

You pipe EVERY hit through a filter page - so /* gets ultimately rewritten to /index.php?q=<original desired pathname>

Your main index.php does nothing else but include() the page they asked for.  You can even make it do a jscript POST to itself with the necessary arguments to make the query string disappear.

It will make your logs look ugly, because ultimately every hit will generate 3 hits, and it may slow things down.  I guess its all how much you want to make the URL bar in the client browser look how you like.  From personal experience, I'd tell you that most of the web browsing public barely notices that such a thing exists and you'd do best keeping it as simple as possible.

At any rate, I (and most of the experts here) are most happy to help you achieve the objective no matter how unusual - we are happy to explore!  All I'd say is that you should probably open a new question that does not use the phrase "rewrite" if you want to mask URLs.  Best of luck!
0
 
David S.Commented:
> This wouldn't be a fix - the definition of "rewrite" is to do exactly that - change the URL - this behavior cannot be
> changed while still using mod_rewrite.

Yes, but it doesn't have to show the new URL to the user, which is being done because you used the "R" flag which triggers an (external) redirect.


> You can even make it do a jscript POST to itself with the necessary arguments to make the query string disappear.

So you break bookmarking? There's no need for that.


huntedcow, something like this in the .htaccess file in the web root should do it:
RewriteEngine On

# if the file is in the web root, don't rewrite and stop looking
RewriteCond %{DOCUMENT_ROOT}/$0 -f
RewriteRule ^\/?(.*)$      - [L]

# if the file is in "one/", rewrite and stop looking
RewriteCond %{DOCUMENT_ROOT}/one/$0 -f
RewriteRule ^\/?(.*)$      /one/$1 [L]

# if the file is in "two/", rewrite and stop looking
RewriteCond %{DOCUMENT_ROOT}/two/$0 -f
RewriteRule ^\/?(.*)$      /two/$1 [L]

Open in new window

0
 
xtermCommented:
Kravimir, thanks for the correction on the URL changing - I will test that today.  

Your logic however is reversed - the rewrite needs to occur if the file does NOT exist in each directory.

@huntedcow:
I will test the removal of the "R" flag and post back shortly.
0
 
xtermCommented:
I have modified the original with Kravimir's suggested flag change, and this does work without changing the URL.  Note that the last rewrite to /404page.htm still does the "hard" external redirect.
# /.htaccess
RewriteCond %{DOCUMENT_ROOT}/$0 !-f
RewriteRule ^(.*)$      /one/$1 [L]

# one/.htaccess 
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/one/$0 !-f
RewriteRule ^(.*)$      /two/$1 [L]

# two/.htaccess 
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/two/$0 !-f
RewriteRule ^(.*)$      /404page.htm [L,R]

Open in new window

0
 
huntedcowAuthor Commented:
# /.htaccess
RewriteEngine On

# if the file or folder is in the web root, don't rewrite and stop looking
RewriteCond %{DOCUMENT_ROOT}/$0 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/$0 -d
RewriteRule ^\/?(.*)$       - [L]

## if the file or folder is in "one/", rewrite and stop looking
RewriteCond %{DOCUMENT_ROOT}/one/$0 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/one/$0 -d
RewriteRule ^\/?(.*)$       /one/$1 [L]

## if the file or folder is in "two/", rewrite and stop looking
RewriteCond %{DOCUMENT_ROOT}/two/$0 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/two/$0 -d
RewriteRule ^\/?(.*)$       /two/$1 [L]

Open in new window


I used code from both answers so applied the points 50/50.

- Thanks Hunted Cow
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

  • 7
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now