2

So I'm no .htaccess expert, by no means, but I have managed to put this code together for a webiste I'm making:

Options -Indexes +Includes
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]
RewriteRule ^\.htaccess$ - [F]
RewriteRule ^$ /%{ENV:BASE}/index.php?id=home
RewriteCond %{REQUEST_URI} !\.php$ [NC]
RewriteCond %{REQUEST_FILENAME} !-s
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ $1 [R=301,L]
RewriteRule ^([a-zA-Z0-9]*)$ /%{ENV:BASE}/index.php?id=$1 [QSA,L]
</IfModule>

It basically changes www.example.com/some/dir/index.php?id=home to www.example.com/some/dir/home while the first few rules are creating some kind of relative path value so I don't have to change the RewriteBase everytime I change the base folder (this is important for this project!).

It works perfectly fine, but now I have encountered a problem where there have to be spaces in the URL like www.example.com/some dir/sub folder/home and this messes everything up.

If you click a link on the page (e.g. "href="home"") it redirects to www.example.com/home instead of www.example.com/some dir/sub folder/home with a 404 error, obviously (even though it works if there are no spaces!). I found out if right click > "copy link to clipboard" it becomes the encoded version www.example.com/some%20dir/sub%20folder/home even if it shows the decoded version in the address bar. BUT if you manually type the decoded version www.example.com/some dir/sub folder/home it still works fine.

There seems to be a problem with spaces and encoding. How do I get my hyperlinks working properly?

-- EDIT -- Thanks to the tutorial posted by elcodedocle, I simply added backslash space: ^([a-zA-Z0-9/ ]*)$ to the regex in the last rule, even if it's not the best method. Then I noticed the [L] flag in the second last rule. I removed it because this shouldn't be the last rule (don't know why it was there in the first place...) and now it works! Well, kind of...

Now, If there is a trailing slash at the end of the URL it sill doesn't work anymore. Probabply because of the removal of the [L] flag in the rule but I don't know how to fix this...

anubhava
  • 761,203
  • 64
  • 569
  • 643
Marc Eickhoff
  • 102
  • 12
  • `href="/home"` is absolute, it means `www.example.com/home`. `href="home"` would be the relative variant that means `www.example.com/some dir/sub folder/home`. Special characters in the URI should not affect this. – DaveRandom Jun 19 '14 at 14:22
  • See http://stackoverflow.com/questions/5442658/spaces-in-urls. Also, in regards to your `/home` link issue: by having `/` as the first character in the `href`, you are telling the server that you want the URL relative to your root directory `example.com`. If you want `home` relative to your current location in the directory tree, then just use `home` with no leading `/`. Alternatively, if you want the link to always point to `/some dir/sub folder/home` regardless of where you are, use that as your `href`. – Benjam Jun 19 '14 at 14:22
  • Oh damn, sorry, actually there isn't any `/` before `home` in the code, just a typo. But still, how do I tell mod_rewrite how to handle these encoded spaces? Sorry if this is a dumb question but I just don't seem to understand *why* it won't work with spaces in the URL. – Marc Eickhoff Jun 19 '14 at 14:27
  • Where is this .htaccess file located? – anubhava Jun 19 '14 at 14:46
  • It's always the same location as the index.php-file here. Sorry, forgot to mention. – Marc Eickhoff Jun 19 '14 at 14:56
  • But `index.php` can be in any sub directory also. Is it in `DocumentRoot` or in some sub directory? – anubhava Jun 19 '14 at 15:03
  • In this example `www.example.com/some dir/sub folder/home` is equivalent to `www.example.com/some dir/sub folder/index.php?id=home`, so index.php and .htaccess are both in `www.example.com/some dir/sub folder/` – Marc Eickhoff Jun 19 '14 at 15:26

2 Answers2

2

Have your .htaccess like this:

Options -Indexes +Includes -MultiViews

<IfModule mod_rewrite.c>
RewriteEngine on

RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]

RewriteCond %{REQUEST_URI} !\.php$ [NC]
RewriteCond %{REQUEST_FILENAME} !-s
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ %{ENV:BASE}$1 [R=302,L,NE]

RewriteRule ^\.htaccess$ - [F]

RewriteRule ^$ /%{ENV:BASE}/index.php?id=home [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+?)/?$ %{ENV:BASE}index.php?id=$1 [QSA,L]
</IfModule>

This is working fine under all the test cases you have described in your question like handling spaces, trailing slashes etc.

anubhava
  • 761,203
  • 64
  • 569
  • 643
1

Try changing:

RewriteRule ^([a-zA-Z0-9]*)$ /%{ENV:BASE}/index.php?id=$1 [QSA,L]

to

RewriteRule ^([a-zA-Z0-9%]*)$ /%{ENV:BASE}/index.php?id=$1 [QSA,L]

(It's a wild guess but it's the only one of your rules that has problems with %)

[EDIT] Unencoded spaces are not allowed in URIs. The ban on spaces is enforced by all browsers as they will convert every space to %20 before sending the request via the http protocol. A workaround to handle them in mod_rewrite is described on this tutorial:

Since URLs can't have spaces (except as %20), use underlines or hyphens to replace them. If you ABSOLUTELY have to use spaces (%20) in your URIs, you can include them in your regex within a range definition as {space}, i.e., ([a-zA-Z\ ]+). However, this is NOT advised.

[EDIT2] If that doesn't work, you may have to translate %20 into spaces, then apply the other rules. Here is a hack based on this answer you may try:

sedspace.sh:

#!/bin/sh
sed -u 's/%20/ /g'

.htaccess:

...
RewriteMap sed-space prg:sedspace.sh
RewriteRule ^(.*)$ ${sed-space:$1}
...

(Make sure that sedspace.sh is executable)

Community
  • 1
  • 1
NotGaeL
  • 8,344
  • 5
  • 40
  • 70
  • I tried this before and tried it again but unfortunately, nothing changes. This was my first guess, too. – Marc Eickhoff Jun 19 '14 at 14:41
  • found a tutorial addressing the issue, and edited my answer with its recommendation. – NotGaeL Jun 19 '14 at 14:47
  • based on the tutorial advice, it seems you'll get %20 instead of spaces and you'll have to replace it with spaces before applying other rules. I have updated my answer again accordingly. – NotGaeL Jun 19 '14 at 15:02
  • It seems to me you are using the wrong slash, I think you want backslash `\ ` not regular slash `/ `. Try: `^([a-zA-Z0-9\ ]*)$` instead. – NotGaeL Jun 21 '14 at 13:15