Redirect folder contents

Hello again,

I’m trying this again, but after months away from htaccess, I’m having issues…

I currently use this:


Options +FollowSymLinks -MultiViews -Indexes
RewriteEngine On

# disable magic quotes
php_flag magic_quotes_gpc Off

# disable register globals
php_flag register_globals 0

# redirect everything to the dispatcher, everything!
RewriteRule ^(.*)$ dispatcher.php [QSA,L,NC]

Everything is routed to dispatcher.php, where various things happen.

There are images residing in resources/images and webroot/images. Each folder has subfolders with images in them as well. The router currently checks for the files and passes them through to the browser. Other files in the webroot and resources folder (css, js, etc.) are parsed and must go through the dispatcher.

The url for a file named 1.jpg in resources/images would be http://domain.com/1.jpg. The url for a file named 1.jpg in webroot/images would also be http://domain.com/1.jpg. If the file exists in both folders, then the one in resources is served. Any number of arbitrary subfolders can exist in either folder.

Publicly accessible Images that are uploaded to the system through the backend are stored in resources/images/SOMETHING/filename.jpeg###x###. The numbers represent the maximum height and width of the image. Each image is resized multiple times, and would have multiple names with different numbers. If ### is invalid or out of range, then the application takes the largest image and sends that through. These images have urls of http::/domain.com/images/SOMETHING/filename.jpeg?w=###&h=###

I am trying to do two things:

  1. Stop parsing files in webroot/images and resources/images and let apache send them through (but NOT any other files in resources/ or webroot/)
  2. Pass images from resources/images/SOMETHING through apache as well, but first converting the w & h querystrings into the filename
  3. If the size specified in step 2 (w & h) does not exist (resources/images/SOMETHING/filename.jpeg###x####), but filename.jpeg is correct,
    then pass through to the dispatcher and let it give out the largest size, otherwise return a 404.

I don’t know why this seems so difficult, but nothing seems to be working…

Hi Jon!

Welcome to SitePoint’s Apache forum!

Good explanation … with the exception of

The url for a file named 1.jpg in resources/images would be http://domain.com/1.jpg. The url for a file named 1.jpg in webroot/images would also be http://domain.com/1.jpg. If the file exists in both folders, then the one in resources is served. Any number of arbitrary subfolders can exist in either folder.
which implies that either the subdirectories (resources and webroot) do not exist or … okay, that’s the confusion, I just don’t know what!

Because mod_rewrite handles redirects in an order-critical manner, let me address your questions in reverse:

  1. If the size specified in step 2 (w & h) does not exist (resources/images/SOMETHING/filename.jpeg###x####), but filename.jpeg is correct, then pass through to the dispatcher and let it give out the largest size, otherwise return a 404.

The mod_rewrite coding for this would be absolutely horrendous - if it were possible (I’m not sure that it is). That said, it would be possible to use a RewriteMap (IF - and ONLY if) you have access to the httpd.conf to create a “program” to parse your #'s, check for file exist status and make decisions based on that. In other words, mod_rewrite is a simple “language” based on using the server’s regex engine - it does NOT have the “smarts” of PHP or other true languages! Therefore, my recommendation is to handle the # problems in a script (like your dispatcher.php).

  1. Pass images from resources/images/SOMETHING through apache as well, but first converting the w & h querystrings into the filename

That’s easy enough:

# capture JPEG image width and height values
RewriteCond %{QUERY_STRING} w=([0-9]+)&h=([0-9]+)
# add width and height values to resources/{something}/{filename}.jpeg
# where {something} is lowercase letters ONLY and
# where {filename} is lowercase letters ONLY
RewriteRule ^resources/([a-z]+)/([a-z]+)\\.jpeg$ resources/$1/$2.jpeg%1x%2? [L]
# the ? kills the existing query string to prevent looping
  1. Stop parsing files in webroot/images and resources/images and let apache send them through (but NOT any other files in resources/ or webroot/)
    Easy, too, once the other “problems” are handled:
RewriteRule ^(webroot|resources)/images/([a-z]+)\\.jpeg - [L]

For these to work, they MUST be before the :kaioken: EVERYTHING :kaioken: atom redirecting to dispatcher.php THEN that mod_rewrite block MUST include a RewriteCond exclusion like RewriteCond ^(webroot|resources)/.+\.jpeg which is intentionally vague but insists on the webroot or resources subdirectory and a jpeg extension (but allows your #'s appended to the extension :nono: ).

Your problems are non-trivial but, IMHO, of your own making with the use of the jpeg filenames you’ve chosen and the use of dispatcher.php to handle EVERYTHING but your images.

Regards,

DK

Jon,

# pass resources/images/* through, though first convert ?w=x&h=x
# if the file doesn't exist with the proper dimensions, then just skip
# and let the dispatcher deal with it
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} w=([0-9]+)&h=([0-9]+)
RewriteCond %{DOCUMENT_ROOT}/resources/images/$1/$2.$3%1%2 -f
RewriteRule ^images/([-a-z_]+)/([-a-z_]+)\\.([a-z]+)$ resources/images/$1/$2.$3%1x%2? [L,R]

Question: Is the query string w=###&h=### (order)?

:blush: I don’t know whether %{DOCUMENT_ROOT} contains the trailing / so that COULD be the problem (the / between %{DOCUMENT_ROOT} and resources/).

For testing, I prefer to use the R=301 flag to SEE the redirection.

Regards,

DK

Hi David,

Thanks for the reply, I appreciate it.

The resources/images and webroot/images folders do exist, but each folder is accessible to the world without the resources or webroot in the URL. Each of these folders also contains subfolders like css, js, etc. If a file is found in the resources folder then it is served. If not, then webroot is checked.

Why would I have to use a rewrite map for the images? The dimensions passed through the url will be set by me most of the time. If the numbers don’t exist in the filename, then I’ll just let the software handle it.

Anyway, here’s what I’ve got now:

Options +FollowSymLinks -MultiViews -Indexes
RewriteEngine On

# disable magic quotes
php_flag magic_quotes_gpc Off

# disable register globals
php_flag register_globals 0

# pass resources/images/* through, though first convert ?w=x&h=x
# if the file doesn't exist with the proper dimensions, then just skip
# and let the dispatcher deal with it
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} w=([0-9]+)&h=([0-9]+)
RewriteCond resources/$1/$2.$3%1%2 -f
RewriteRule ^resources/([a-z\\-\\_]+)/([a-z\\-\\_]+)\\.(a-z)$ resources/$1/$2.$3%1x%2? [L]

# publicly accessible resources/images folder
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $0 ^(images/(.+))$
RewriteRule ^images/(.+)$ resources/images/$1

# publicly accessible webroot/images folder
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $0 ^(images/(.+))$
RewriteRule ^images/(.+)$ webroot/images/$1

# redirect everything to the dispatcher, everything!
#RewriteCond %{ENV:REDIRECT_STATUS} ^$
#RewriteRule ^(.*)$ dispatcher.php [QSA,L,NC]

I commented out the last two lines for testing. Images in resources are coming through just fine, but the first and third blocks of rules don’t seem to be functioning. I can’t for the life of me figure out what is different between the 2nd and 3rd that would cause it to not work… The first block of stuff, isn’t this close? Am I missing something big here?

Thanks!

grrrr, I know we’re close!

Okay, just working on the first block (the variable size images):


Options +FollowSymLinks -MultiViews -Indexes
RewriteEngine On

# disable magic quotes
php_flag magic_quotes_gpc Off

# disable register globals
php_flag register_globals 0

# pass resources/images/* through, though first convert ?w=x&h=x
# if the file doesn't exist with the proper dimensions, then just skip
# and let the dispatcher deal with it
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} w=([0-9]+)&h=([0-9]+)
RewriteCond %{DOCUMENT_ROOT}/resources/images/$1/$2.$3%1%2 -f
RewriteRule ^images/([-a-z_]+)/([-a-z_]+)\\.([a-z]+)$ resources/images/$1/$2.$3%1x%2? [L,R]

# publicly accessible resources/images folder
#RewriteCond %{ENV:REDIRECT_STATUS} ^$
#RewriteCond $0 ^(images/(.+))$
#RewriteRule ^images/(.+)$ resources/images/$1

# publicly accessible webroot/images folder
#RewriteCond %{ENV:REDIRECT_STATUS} ^$
#RewriteCond $0 ^(images/(.+))$
#RewriteRule ^images/(.+)$ webroot/images/$1

# redirect everything to the dispatcher, everything!
#RewriteCond %{ENV:REDIRECT_STATUS} ^$
#RewriteRule ^(.*)$ dispatcher.php [QSA,L,NC]

It still isn’t working, and the log isn’t helping much either… I don’t think the file check is happening.

Hi Jon!

You’re welcome. That (helping others LEARN) is what I’m here for!

If “something” is checking the resources folder and, when not finding a file there, checks the webroot folder, you’ve got a lot of smarts going on “somewhere” (not in .htaccess). This can make things more complicated but let me get on to your questions and code.

It appeared that the dimensions you passed were highly variable (not fixed sets) so a “program” seems to be necessary to do the checking of the size variables before redirecting to the largest size available. My RewriteMap suggestion was the only way to force mod_rewrite to gain the “smarts” to do for images what your dispatcher script is doing for all non-image files. In other words, you’ll need to program this one way or another (unless there are only one or two sets of dimensions to be checked). An additional problem with your image naming scheme, though, would seem to be the type handler used to serve the image file with .jpeg###x### as a file extension (although mod_rewrite can be used to instruct Apache to use an image type handler on this “type” of file - personally, I’d move the size to the filename and leave the extension alone!).

Options +FollowSymLinks -MultiViews -Indexes
RewriteEngine On

# disable magic quotes
php_flag magic_quotes_gpc Off

# disable register globals
php_flag register_globals 0

# pass resources/images/* through, though first convert ?w=x&h=x
# if the file doesn't exist with the proper dimensions, then just skip
# and let the dispatcher deal with it
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} w=([0-9]+)&h=([0-9]+)
RewriteCond resources/$1/$2.$3%1%2 -f
[indent]The file exists check is made against the {REQUEST_FILENAME} string which is the PHYSICAL path/file whereas you are using the webspace path. I believe (without checking) that you can get the equivalent of the {REQUEST_FILENAME} by preceding resources with %{DOCUMENT_ROOT}.

Then, I believe that the $ variables do not exist at this point (but I've recently seen an apache.org code snippet that indicates I'm wrong - I have more checking to do on this one, too.[/indent]
RewriteRule ^resources/([a-z\\-\\_]+)/([a-z\\-\\_]+)\\.(a-z)$ resources/$1/$2.$3%1x%2? [L]
[indent]The range definition is wrong BECAUSE the hyphen MUST be either first (preferred) or last to NOT be interpreted as part of a range definition, i.e., a-z.  Escaping it does NOTHING - as it's irrelevant to the underscore character.  Change these two [a-z\\-\\_] snippets to [-a-z_] and you should have better success (when the preceding RewriteCond "problems" are addressed).[/indent]

# publicly accessible resources/images folder
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $0 ^(images/(.+))$
RewriteRule ^images/(.+)$ resources/images/$1

# publicly accessible webroot/images folder
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond $0 ^(images/(.+))$
[indent]You've GOT me on this one!  Beside the forward "backreference," you're using an Apache variable that I know exists but I've not found a reference for how it's created (what it is).  $1-$9 are the ordered atoms but $0 is WHAT?  If you know where that's defined, please let me know (for my own piece of mind).[/indent]
RewriteRule ^images/(.+)$ webroot/images/$1
[indent]NO Last flag directs mod_rewrite to place an AND here so, with the conflicting regex, the third block can NEVER match/redirect.  It's a simple error (along the lines of a typo) but, OH SO CRITICAL![/indent]
# redirect everything to the dispatcher, everything!
#RewriteCond %{ENV:REDIRECT_STATUS} ^$
#RewriteRule ^(.*)$ dispatcher.php [QSA,L,NC]

I REALLY like the use of the environment variable to prevent looping - especially when using the :kaioken: EVERYTHING :kaioken: atom as it’s just as effective as a list of RewriteCond statements looking at the {REQUEST_URI} or {QUERY_STRING} for redirections and so much simpler!

Regards,

DK