Forum Moderators: phranque

Message Too Old, No Replies

Mod_Rewrite Question

         

Linda_A

12:22 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



I am currently using

RewriteCond $1 ^(Digest¦Updates).*
RewriteRule ^(.*) index.php/$1

to rewrite www.domain.com/Digest/<anything> to www.domain.com/index.php/Digest/<anything> and www.domain.com/Updates/<anything> to www.domain.com/index.php/Updates/<anything>.

So far, so good. However, I need to do the same kind of rewriting in several subdirectories. For example, www.domain.com/Dir/News/<anything> to www.domain.com/Dir/index.php/News/<anything>.

I am able to solve this by placing an additional .htaccess file in said subdirectory and using the same code as above with Digest and Updates replaced with News. However, I would prefer it if I could just use a single .htaccess by adding a separate rewrite condition and rule pair for each subdirectory that needs it.

So, my question is: is this possible, and how would I configure the rewrite if so? How could I change

RewriteCond $1 ^(News).*
RewriteRule ^(.*) index.php/$1

to get it to turn www.domain.com/Dir/News/<anything> to www.domain.com/Dir/index.php/News/<anything> while the rule is found in the .htaccess stored under root, not under /Dir/?

jdMorgan

2:49 pm on Sep 7, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Your original rule is non-intuitive and somewhat over-complicated, which makes it hard to see the answer.

You could rewrite that to either


RewriteRule ^((Digest¦Updates)/.*)$ /index.php/$1 [L]

or

RewriteCond %{REQUEST_URI} ^Digest [OR]
RewriteCond %{REQUEST_URI} ^Updates
RewriteRule (.*) /index.php/$1 [L]

or even

RewriteCond %{REQUEST_URI} ^(Digest¦Updates)
RewriteRule (.*) /index.php/$1 [L]

So applying those techniques to your problem, you might use

RewriteCond %{REQUEST_URI} ^Dir/News [OR]
RewriteCond %{REQUEST_URI} ^Dir/Digest [OR]
RewriteCond %{REQUEST_URI} ^OtherDir/Updates
RewriteRule ^([^/]+)/([^/]+.*)$ /$1/index.php/$2 [L]

to turn www.domain.com/Dir/News/<anything> to www.domain.com/Dir/index.php/News/<anything>

Note that the last RewriteCond in an [OR]ed list *must not* have an [OR] appended. Note also that you must edit the broken pipe characters and replace them with solid pipes before use - posting on this board modifies them.

Hopefully this answers your question, as there are many "dimensions" to these problems. If you have many, many subdirectories and subcategories you may want to use multiple RewriteRules to first rewrite the subdirectories, and then rewrite the categories. Doing it in two steps can simplify things by eliminating redundant subdirectory tests. But this may not apply to your case; Sometimes the directory architecture of a site heavliy influences the most efficient way to do rewrites in it.

There are some references cited at the end of our forum [url=RewriteCond $1 ^(Digest¦Updates).*
RewriteRule ^(.*) index.php/$1]charter[/url] that might come in handy, too.

Jim

Linda_A

4:08 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



I didn't actually write the original rule, as I don't know much at all about mod_rewrite, but let me see if I follow what you wrote. I appreciate the help a lot. :)

First, I should perhaps clarify my situation further. The 'directories' being rewritten are actually virtual rather than physical directories, part of the URL structure of the software I use for dynamic content on my site. But since I also use static content, I needed to be able to only rewrite the virtual directories. Hence the need for very specific rules.

So ... lets say I have:

1) www.domain.com/Updates/* which needs to become www.domain.com/index.php/Updates/*

2) www.domain.com/Dir1/News/* which needs to become www.domain.com/Dir1/index.php/News/*

3) www.domain.com/Dir2/Announcements/* which needs to become www.domain.com/Dir2/index.php/Announcements/*

And so on. There are, perhaps, 10 or so virtual directories that need this kind of rewriting, a few located right under root and the rest located in two different subdirectories.

Would this then be the best approach, using a specific condition for each virtual directory?

RewriteCond %{REQUEST_URI} ^Updates [OR]
RewriteCond %{REQUEST_URI} ^Dir1/News [OR]
RewriteCond %{REQUEST_URI} ^Dir2/Announcements [OR]
RewriteRule ^([^/]+)/([^/]+.*)$ /$1/index.php/$2 [L]

jdMorgan

4:25 pm on Sep 7, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> Would this then be the best approach [...]?

I can't say "best," but it would probably be the simplest. Simple is good.

Please note my warning about not appending an [OR] to the final RewriteCond in msg#2. This will cause unexpected problems.

Also, you may need to add another RewriteCond to prevent a rewrite loop:


RewriteCond %{REQUEST_URI} !index\.php

Add it at the top of your RewriteCond list, with no [OR] after it.

Please review the references cited in our charter. Using mod_rewrite without a good understanding of it can be quite dangerous to the health of your site. There are two parts, mod_rewrite itself, and the regular expressions used in mod_rewrite patterns. While both may seem daunting at first, having your own rules and test results at hand as examples will make them progressively clearer.

With the provisos above, I think what you have will work, but there's no substitute for testing.

Jim

Linda_A

7:04 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



Thank you. I'll read over that information and do some testing. :)

Linda_A

7:18 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



Well, the first test wasn't too successful, since it resulted in an internal server error. The setup I used was this:

RewriteCond %{REQUEST_URI} ^Digest [OR]
RewriteCond %{REQUEST_URI} ^Updates [OR]
RewriteCond %{REQUEST_URI} ^BoD/Announcements [OR]
RewriteCond %{REQUEST_URI} ^BoD/Events [OR]
RewriteCond %{REQUEST_URI} ^BoD/Logs [OR]
RewriteCond %{REQUEST_URI} ^RR/News [OR]
RewriteRule ^([^/]+)/([^/]+.*)$ /$1/index.php/$2 [L]

If I add the RewriteCond %{REQUEST_URI}!index\.php line at the top, then it results in a 404.

I noticed that the documents you suggested that I read talk about Apache 1.3. My host runs Apache 2.0.40, could this be causing the problem?

[edited by: Linda_A at 7:27 pm (utc) on Sep. 7, 2004]

jdMorgan

7:23 pm on Sep 7, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Please note the following, mentioned twice in this thread:

Note that the last RewriteCond in an [OR]ed list *must not* have an [OR] appended.

In order to work, every single detail of mod_rewrite code must be correct. There's no wiggle room.

Jim

Linda_A

7:35 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



Oh, sorry about that. I kept reading it as must have an [OR] appended.

However, even with that corrected, I still get 404 errors, both with and without RewriteCond %{REQUEST_URI}!index\.php.

jdMorgan

7:53 pm on Sep 7, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



OK, here's the detail I messed up... The pattern for the REQUEST_URI Conds must start with a slash, e.g.

RewriteCond %{REQUEST_URI} [b]^/D[/b]igest [OR]

Jim

Linda_A

8:16 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



Like this, then?

RewriteCond %{REQUEST_URI} ^/Digest [OR]
RewriteCond %{REQUEST_URI} ^/Updates [OR]
RewriteCond %{REQUEST_URI} ^/BoD/Announcements [OR]
RewriteCond %{REQUEST_URI} ^/BoD/Events [OR]
RewriteCond %{REQUEST_URI} ^/BoD/Logs [OR]
RewriteCond %{REQUEST_URI} ^/RR/News
RewriteRule ^([^/]+)/([^/]+.*)$ /$1/index.php/$2 [L]

Doesn't seem to do the trick either, unless I am making another mistake somewhere. If I include RewriteCond %{REQUEST_URI}!index\.php (not sure if that one has to start with a / too, but I tried both with and without it, with no difference) I get 404s, without it I get internal server errors.

Maybe it is my other rewrite rules (the standard setup for protecting graphics from hotlinking) that are conflicting? However, from what I had understood, once you reach a RewriteRule, it stops there, and you should be able to add another?

Linda_A

8:23 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



Okay, addition to the previous: http://www.example.org/BoD/Announcements/* and http://www.example.org/RR/News/* works, but not http://www.example.org/Updates/*

So the subdirectories are solved, but not those located right under root.

[edited by: jdMorgan at 10:30 pm (utc) on Oct. 5, 2005]
[edit reason] Examplified. [/edit]

jdMorgan

8:53 pm on Sep 7, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Ah, you'll need a separate rule, then:

# Rewrite subdirectory requests
RewriteCond %{REQUEST_URI} ^/BoD/Announcements [OR]
RewriteCond %{REQUEST_URI} ^/BoD/Events [OR]
RewriteCond %{REQUEST_URI} ^/BoD/Logs [OR]
RewriteCond %{REQUEST_URI} ^/RR/News
RewriteRule ^([^/]+)/([^/]+.*)$ /$1/index.php/$2 [L]
#
# Rewrite root directory requests
RewriteCond %{REQUEST_URI} !index\.php
RewriteCond %{REQUEST_URI} ^/Digest [OR]
RewriteCond %{REQUEST_URI} ^/Updates
RewriteRule ^([^/]+)$ /index.php/$1 [L]

Jim

Linda_A

9:21 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



Looks reasonable ... but I am still getting 404s for the ones straight under root.

I really appreciate the help with this, btw. :) I keep trying figure out just what those regexps do, but so far it is mostly greek to me.

Linda_A

9:25 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



Ah-ha, I think I've got it. I switched RewriteRule ^([^/]+)$ /index.php/$1 [L] for RewriteRule ^([^/]+.*)$ /index.php/$1 [L], and that seems to have done the trick. :)

Should, btw, it be RewriteCond %{REQUEST_URI}!index\.php or RewriteCond %{REQUEST_URI}!/index\.php? And is it correct to use that only for the rewrite for the root directories?

Again, thank you. :)

jdMorgan

9:32 pm on Sep 7, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> Should, btw, it be RewriteCond %{REQUEST_URI} !index\.php or RewriteCond %{REQUEST_URI}!/index\.php? And is it correct to use that only for the rewrite for the root directories?

Yes and yes. There are a couple of ways to do it, but the point is to identify index.php no matter what subdirectory it may be requested in, and to avoid rewriting index.php to index.php, creating an "infinite loop."

For this reason, I omitted the start anchor "^" on the index.php pattern as well.

Jim

Linda_A

9:42 pm on Sep 7, 2004 (gmt 0)

10+ Year Member



Okay, I do think I've got a good idea of what this does, now. I'll pass this on to the person who put together my original code, as an example of a better solution. :)