50

I have following command in my .htaccess

    RewriteCond %{HTTP_HOST} ^(www\.)?([a-z0-9-]+)\.example\.com [NC]
    RewriteRule ^(.*?)-([a-z]+) %2/$1.$2 [L]
    RewriteRule ^(.*?)-([0-9]+)([a-z]) %2/$1$3.$2 [L]

%2 is not working in second and later lines. Can I define any variable for %2 and use it in all RewriteRule commands? Following command works

     RewriteCond %{HTTP_HOST} ^(www\.)?([a-z0-9-]+)\.example\.com [NC]
     RewriteRule ^(.*?)-([a-z]+) %2/$1.$2 [L]
     RewriteCond %{HTTP_HOST} ^(www\.)?([a-z0-9-]+)\.example\.com [NC]
     RewriteRule ^(.*?)-([0-9]+)([a-z]) %2/$1$3.$2 [L]

But I want use %2 for multiple rule line without duplicating condition.

Book Of Zeus
  • 48,229
  • 18
  • 169
  • 166
Huseyin
  • 1,407
  • 2
  • 24
  • 38

4 Answers4

68

You can use the RewriteRule flag S|skip to tie multiples RewriteRules to a single RewriteCond (or to a set of RewriteConds). Here is an example that applies one Cond to three Rules:

RewriteCond  %{HTTP_HOST}  !^www.mydomain.com$
# skip rules if NOT within domain - only way to tie multiple rules to one cond
RewriteRule  .?  -  [S=3]
RewriteRule  ^path1(/.*)$  /otherpath1$1
RewriteRule  ^path2(/.*)$  /otherpath2$1
RewriteRule  ^path3(/.*)$  /otherpath3$1

To change an existing Cond to work for multiple Rules you have to:

  • Negate the condition (prepend it with !)
  • If you have multiple RewriteConds:
    Change logical ANDs in the Conds to ORs and vice versa.
  • Add a skipping rewrite rule in front of all rules that you want to tie to the condition(s). Set the S parameter to the number of Rule lines to be skipped.

Please be aware that it is not possible to use any backreferences that point back to the RewriteCond (like %1) in the skipped Rules. These are only accessible in the skipping RewriteRule.

Jpsy
  • 17,245
  • 6
  • 99
  • 99
  • This solves only the logic part, not the backreferences part, as the `RewriteCond` technically still applies only to the first `RewriteRule`. The original question does need backreferences. – rustyx May 21 '14 at 09:33
  • 1
    I have mentioned this in the last sentence of my anwser, @rustyx. Still I think that many users who do not need back reference will read this posting and will enjoy the skip based solution. – Jpsy May 22 '14 at 09:11
  • @Jpsy Can any of the possibly skipped Rules have their own Conds? If so, does this affect what to set in the `S` parameter? – JAAulde May 03 '16 at 19:30
  • 1
    @JAAulde I guess not. I have never tried it, but the docs only talk about skipping RewriteRules, not Conds. But you should have a look at the new directives , , . They are available since Apache 2.4 and might solve your problem. See http://httpd.apache.org/docs/2.4/expr.html#examples – Jpsy May 04 '16 at 13:13
  • @Jpsy, thanks! Yeah, I want to use `` but am on Apache 2.2 at the moment. – JAAulde May 04 '16 at 13:42
32

The variable must be saved as an Apache var, then that can be used without repeated conditions.

Saving in Apache variables are shown in second line. Usage of saved vars in 3th and 4th lines.

RewriteCond %{HTTP_HOST} ^(www\.)?([a-z0-9-]+)\.example\.com [NC]
RewriteRule .? - [E=Wa:%1,E=Wb:%2]
RewriteRule ^(.*?)-([a-z]+) %{ENV:Wb}/$1.%{ENV:Wb} [L]
RewriteRule ^(.*?)-([0-9]+)([a-z]) %{ENV:Wb}/$1$3.$2 [L]
Ben
  • 47,286
  • 44
  • 159
  • 208
Huseyin
  • 1,407
  • 2
  • 24
  • 38
7

Clearly, this isn’t much fun, especially as things grow and become more complex. However, there is a less well known option of the RewriteRule statement, that tells apache to skip the next N number of RewriteRule statement. [S=N]. So instead of checking each time if the request is NOT a file AND is NOT a directory, we could do this: Code block

#
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [S=3]
RewriteRule ^([^./]+)/$ http://www.santweb.co.uk/$1 [L]
RewriteRule ^([^./]+)/([^./]+)/$ http://www.santweb.co.uk/$1/$2 [L]
RewriteRule ^([^./]+)/([^./]+)/([^./]+)/$ http://www.santweb.co.uk/$1/$2/$3 [L]

#

I found this, from: http://www.sant-media.co.uk/2010/03/applying-rewritecond-to-multiple-rewriterule-in-htaccess/

I think it helpfull

Hoàng Vũ Tgtt
  • 1,318
  • 18
  • 6
  • 3
    Yes not fun. Somebody should tell the folks at Apache about if/else blocks. Thanks. – Rolf Feb 22 '16 at 06:57
4

From Apache 2.4 you can use the <If> directive:

RewriteEngine On
<If "%{HTTP:Upgrade} == 'websocket'">
    RewriteRule /nidoran/(.*)           ws://localhost:8080/nidoran/$1 [P,L]
    RewriteRule /kakuna/(.*)           ws://localhost:8081/kakuna/$1 [P,L]
    RewriteRule /porygon/(.*)           ws://localhost:8082/porygon/$1 [P,L]
</If>

http://httpd.apache.org/docs/2.4/expr.html#examples

Juan Calero
  • 3,638
  • 5
  • 25
  • 42