.htaccess to beautify a url

Viewed 67

There are several articles about this but I cannot make it work.
I have the following urls:

 1. /index.php
 2. /index.php?lg=el
 3. /index.php?lg=en
 4. /index.php?lg=el#anchor
 5. /index.php?lg=en#anchor
 6. /index.php?ct=1&lg=el
 7. /index.php?ct=1&lg=el#anchor
 8. /index.php?ct=1&lg=en
 9. /index.php?ct=1&lg=en#anchor
10. /index.php?ct=2&lg=el
11. /index.php?ct=2&lg=el#anchor
12. /index.php?ct=3&lg=el
13. /index.php?ct=3&lg=el#anchor
14. /index.php?ct=4&lg=el
15. /index.php?ct=4&lg=el#anchor
16. /index.php?ct=5&lg=el
17. /index.php?ct=5&lg=el#anchor
18. /index.php?ct=2&lg=en
19. /index.php?ct=2&lg=en#anchor
20. /index.php?ct=3&lg=en
21. /index.php?ct=3&lg=en#anchor
22. /index.php?ct=4&lg=en
23. /index.php?ct=4&lg=en#anchor
24. /index.php?ct=5&lg=en
25. /index.php?ct=5&lg=en#anchor

and similar ones without the "index.php". The "ct" variable should be converted based on the following array (index from 1):

[company,history,news,measurements,contact]

I want to convert them to:

 1. /
 2. /el
 3. /en
 4. /el#anchor
 5. /en#anchor
 6. /el/company
 7. /el/company#anchor
 8. /en/company
 9. /en/company#anchor
10. /el/history
11. /el/history#anchor
12. /el/news
13. /el/news#anchor
14. /el/measurements
15. /el/measurements#anchor
16. /el/contact
17. /el/contact#anchor
18. /en/history
19. /en/history#anchor
20. /en/news
21. /en/news#anchor
22. /en/measurements
23. /en/measurements#anchor
24. /en/contact
25. /en/contact#anchor

I have tried the following syntax in .htaccess:

RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(\/)?([a-z]{2})?(\/)?((?:company|history|news|measurements|contact))?(#[\w\-]+)?$ $1index.php?ct=$4&lg=$2$5 [L,QSA]

but I cannot get the expected result.
Any ideas?

1 Answers
6. /el/company
7. /el/company#anchor

The #anchor (aka. the fragment identifier) is not passed to the server, so it's not part of the URL rewriting process. #anchor is used by the client-side code and it is present on the client-side URL, so there is nothing to do in this respect. So, #6 and #7 (and other similar URLs) are in fact "the same" as regards the server request.

The trick is converting the 2nd path segment into a number 1..5, which you don't appear to be doing in your attempt.

If you are OK with the ct URL parameter always being present (except on requests for the root), but empty when not required (ie. ct=), rather than being totally absent, then you could do it like the following in a single rule:

DirectoryIndex index.php

RewriteEngine On

# HTTP to HTTPS redirect
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Rewrite "pretty" URL
RewriteCond 1$2 ^(\d)company [OR]
RewriteCond 2$2 ^(\d)history [OR]
RewriteCond 3$2 ^(\d)news [OR]
RewriteCond 4$2 ^(\d)measurements [OR]
RewriteCond 5$2 ^(\d)contact [OR]
RewriteCond $2 ^$
RewriteRule ^(el|en)(?:/(company|history|news|measurements|contact))?$ index.php?ct=%1&lg=$1 [L]

Since you only appear to have two languages I've used simple alternation to match just these two. ie. (el|en). If you do have many language codes then consider changing this to [a-z]{2} instead. However, it is preferable to be specific and list the languages to avoid potential conflicts.

There's no need for the filesystem check (to check that the request does not map to a file) since you don't have files of the form /en/contact. If you did then the rewrite would not be possible with the filesystem check anyway.

The RewriteBase directive is not required here.

The "number" (array index) that the 2nd path segment corresponds to is captured from the preceding RewriteCond directives and this is available later in the substitution string using the %1 backreference.

The above rule(s) will rewrite the request as follows (very close to your examples):

  • / -> index.php (by mod_dir, no URL parameters)
  • /el -> index.php?ct=&lg=el (ct parameter is empty)
  • /el/ (with a trailing slash) - no rewrite
  • /el/company -> index.php?ct=1&lg=el
  • /en/contact -> index.php?ct=5&lg=en
  • /ab - no rewrite (unrecognised language code)
  • /en/contacts - no rewrite (2nd path segment not recognised)

and similar ones without the "index.php".

Although, going forward, the rewritten URL should always contain index.php.

I want to convert them to:

To clarify, this rule rewrites the "pretty" URL back to the underlying URL that your application understands. It doesn't physically change the URLs used in your application - you must manually change the URLs in your HTML source to be the new "pretty" URLs.

If, however, you are changing an existing URL structure that has already been indexed by search engines and possibly linked to by third parties then you should consider also implementing an external redirect from the old URL to the new "pretty" URL in order to preserve SEO. But this is not necessary for your application to work with the new "pretty" URLs.

Related