views:

24

answers:

1

I'm trying to force a trailing slash to my URLs, but I can't make it work the way I want. This is my .htaccess file:

RewriteEngine on

#Force trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !index.php
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ /$1/ [L,R=301] 

#Subdomains
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteCond %{HTTP_HOST} ^([^/.]+)\.example\.com$
RewriteCond $1/%1 !^([^/]+)/\1$
RewriteRule ^/([^/]+)? /%1%{REQUEST_URI} [L]

#Point everything to page.php
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteCond $1 !^(.*).(php|css|js|png|jpg|gif|htm|html)$
RewriteRule ^(.*)$ page.php?q=$1 [L,NC]

If I go to "en.example.com/about" I'm redirected to "en.example.com/en/about/", which is an invalid page.

How can I make this work?

A: 

The problem here is that the L flag causes a restart of the rewriting process with the rewritten URL (I’ve already told you that, didn’t I?):

Remember, however, that if the RewriteRule generates an internal redirect (which frequently occurs when rewriting in a per-directory context), this will reinject the request and will cause processing to be repeated starting from the first RewriteRule.

Now when /about is requested, the first rule get’s applied and redirects to /about/. The subsequent request of /about/ is then processed, at first the third rule is applied and the URL path is rewritten to /page.php. So far, so good.

But now the internal redirect takes place and the rewriting process is restarted with the new URL path /page.php. This is then fetched by the first rule again and redirected externally to /page.php/.

The second rule shouldn’t be applied at all as the pattern ^/ should never match as the per-directory path prefix is removed before testing the pattern when using mod_rewrite in an .htaccess file:

When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is automatically removed for the pattern matching and automatically added after the substitution has been done.

But these rules should work:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .*[^/]$ /$0/ [L,R=301]

RewriteCond %{HTTP_HOST} ^([^/.]+)\.example\.com$ [NC]
RewriteCond %1 !=www [NC]
RewriteCond $0/%1 !^([^/]+)/\1$
RewriteRule ^[^/]* /%1%{REQUEST_URI} [L]

RewriteCond %{HTTP_HOST} !=www.example.com [NC]
RewriteCond $1 !.*\.(php|css|js|png|jpg|gif|htm|html)$
RewriteRule .* page.php?q=$0 [L]
Gumbo
I'm not yet very professional concerning mod_rewrite, so I'm really thankful for your time I'm learning. My browser tells me that the page was directed wrong - is that zero on line 6 really ment to be a zero?
Ivarska
@Ivarska: Yes, `$0` refers to the matched string of the whole pattern. But since this does not seem to work, you should do some debugging on your own using [mod_rewrite’s logging feature](http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriteloglevel).
Gumbo
@Gumbo: Hm, okay - why I asked is because you wrote $1 when you helped me in the topic about subdomains. Ironically, RewriteLogLevel 9 gives me an error code 500 - as well do RewriteLogLevel 0. I've putted this at the first row, so it's kinda weird.
Ivarska
@Ivarska: [`RewriteLogLevel`](http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriteloglevel) and [`RewriteLog`](http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewritelog) can only be used in the [server configuration and virtual host context](http://httpd.apache.org/docs/2.2/mod/directive-dict.html#Context).
Gumbo
@Gumbo: Too bad that I haven't got access to any configuration files since the site is located on a web hosting.
Ivarska