2
\$\begingroup\$

I have a website for my car enthusiast club ("example.org") whose content can be divided into three main sections: Startseite (the "front page" of the site), Mitglieder (membership directory), and Vereinsinfos ("about us"). For each section, the content is handled by a corresponding PHP script: /home.php, /mitglieder.php, and /verein.php.

I'd like to prettify the URLs to eliminate the .php extensions, so that the URLs look like

  • http://example.org/home (maps to /home.php)
  • http://example.org/home/ (also maps to /home.php)
  • http://example.org/home/1 (maps to /home.php with a data=1 query string)

After reading all documentation, I formed my .htaccess like this (repeated for the mitglieder and verein sections):

RewriteRule ^home\/$ /home.php [L]
RewriteRule ^home$ /home/ [L]
RewriteRule ^home\/([^/]*)$ /home.php?data=$1 [L]

This works, but I can't figure out how to improve it further after reading all the documentation on the Internet. (I have difficulty understanding regular expressions.)

In addition to the content above, I also have static resources under /images/, /js/, /css/, etc. which should be left alone.

\$\endgroup\$
6
  • \$\begingroup\$ I'm a bit unsure of your intentions / skeptical of your implementation. If the request is /home, then it gets mapped to /home/ — is the content then generated by /home/index.html or some other DirectoryIndex-configured handler? Is that what you want? \$\endgroup\$ Commented Jul 14, 2015 at 5:03
  • \$\begingroup\$ What does /images/ have to do with your rules? \$\endgroup\$ Commented Jul 14, 2015 at 5:04
  • \$\begingroup\$ My intension is: rewrite /home/ to home.php So i must set links in index.php from ´./link.php´ to ´../link.php´ If someone delete the last backslash, the file would be "run" from the root-directory and File-Content + Links would not work. So i will correct the (possible) deleted backslash. \$\endgroup\$
    – C.E.
    Commented Jul 14, 2015 at 5:05
  • 1
    \$\begingroup\$ index.php? link.php? The plot thickens… those weren't mentioned anywhere in the question. Could you include a recursive directory listing? \$\endgroup\$ Commented Jul 14, 2015 at 5:07
  • 1
    \$\begingroup\$ Does Rev 4 accurately reflect what you are trying to ask? \$\endgroup\$ Commented Jul 14, 2015 at 5:52

2 Answers 2

1
\$\begingroup\$

First, I'd like to point out that when you map URLs with varying numbers of slashes to the same content, you must take care when referencing images or links in your HTML. Basically, you must use absolute URLs everywhere instead of relative URLs.

If you want to have both /home and /home/ refer to the exact same content, it would be good practice to pick one of them as the canonical URL. You should either enforce your choice by redirecting the alternate URL to the canonical URL, or just inform web crawlers of your preference putting a <link rel="canonical" href="…"> tag in the page.


If you don't want the canonicalizing redirect, then first two rules would be better combined as RewriteRule ^home/?$ /home.php [L]. (The question mark in the regex means that the trailing slash is optional; both home and home/ will match.)

If you do want a canonicalizing redirect, then you'll need the first two rules to remain separate:

RewriteRule ^home/$     /home.php    [L]
RewriteRule ^home$      /home/       [L,R]   # canonicalizing redirect

The third rule can remain as it is. However, I recommend modifying your PHP script so that it accepts the additional path elements using $_SERVER['PATH_INFO'] instead of a $_GET['data'] parameter. Then you can combine your first and third rules:

RewriteRule ^home/(.*)$  /home.php/$1 [L]
RewriteRule ^home$       /home/       [L,R]   # canonicalizing redirect

Or, without the canonicalizing redirect, it's just one rule:

RewriteRule ^home(/.*)?$ /home.php$1  [L]

You have three scripts. Instead of repeating all of the rules for each script, you should be able to combine them.

With canonicalizing redirects:

RewriteRule ^(home|mitglieder|verein)(/.*)?$ /$1.php$2   [L]
RewriteRule ^(home|mitglieder|verein)$       /$1/        [L,R]

With no canonicalizing redirects, it all collapses into one rule:

RewriteRule ^(home|mitglieder|verein)(/.*)?$ /$1.php$2
\$\endgroup\$
3
  • \$\begingroup\$ Big big thanks for your very detailled answer! But, the (last) Rule doesnt work (The non-canonical!) If i add it to the htaccess, and try it, i get an "Internal Server Error, 500".. Did you know why ? \$\endgroup\$
    – C.E.
    Commented Jul 14, 2015 at 22:21
  • \$\begingroup\$ Interesting bug! Fixed in Rev 2. The problem was that the rule would rewrite home/home.php, then to serve home.php, it would encounter the same rule again, rewriting it to /home.php — an infinite loop. The bugfix avoids the second application of the rule by ensuring that home must be followed by either a / or nothing. \$\endgroup\$ Commented Jul 14, 2015 at 22:33
  • \$\begingroup\$ Big thanks again! Works fine now! One last question: Can you explain me the canonical-redirect? I dont know, how to use it, i have planed to add Facebook-Meta-Tags. In the past, i "redirect" the crawler manually (searched for "facebookexternalhit" in theuser-agent string) to a page which only includes the meta-tags. \$\endgroup\$
    – C.E.
    Commented Jul 14, 2015 at 22:46
1
\$\begingroup\$

You can combine these:

RewriteRule ^home\/$ /home.php [L]
RewriteRule ^home$ /home/ [L]

Into:

RewriteRule ^home\/?$ /home.php [L]

In addition, you should also map /home.php to /home. So this will do all three:

RewriteRule ^home(?:\/|\.php)?$ /home.php [L]

Now your /home/1 rules. You've already got it, but you can make slight improvement:

RewriteRule ^home\/([^/]+)$ /home.php?data=$1 [L]

The + differentiates this rule from /home/.

If the data is alphanumerical you can improve this further:

RewriteRule ^home\/([\w-]+)$ /home.php?data=$1 [L]

You can replace home with other URLs as well.

\$\endgroup\$
1
  • \$\begingroup\$ No need to escape the forward slashes. ^home/$ will also work. \$\endgroup\$
    – hjpotter92
    Commented Aug 26, 2015 at 20:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.