1

My application used to do language switching using a lang.php file. A URL to redirect to English for /path/to/page.php?foo=bar would look like this:

/path/to/lang.php?lang=en-CA&uri=%2Fpath%2Fto%2Fpage.php%3Ffoo%3Dbar

Recently there has been some changes to accept a lang query parameter on all pages. So this URL is nicer:

/path/to/page.php?foo=bar&lang=en-CA

I'd like to be able to add a .htaccess file to all the locations that I have a lang.php file in order to keep the existing URL working without the lang.php file. Is this possible?

The RewriteRules must be completely relative to lang.php as the application is running on different hostnames and paths.

I took a stab at it based on the answer here but this is giving me a 404:

RewriteCond %{REQUEST_FILENAME} lang.php$
RewriteCond %{QUERY_STRING} (?:^|&)uri=([^&]+) [NC]
RewriteRule lang.php - [E=LANG_REDIR_URI:%1]

RewriteCond %{REQUEST_FILENAME} lang.php$
RewriteCond %{QUERY_STRING} (?:^|&)lang=([^&]+) [NC]
RewriteRule lang.php - [E=LANG_REDIR_LANG:%1]

RewriteCond %{REQUEST_FILENAME} lang.php$
RewriteRule . %{LANG_REDIR_URI}e [L,R=temporary]

The uri parameter may already have query parameters (as in the examble above), and the code should not make the application vulnerable to an open redirect vulnerability.

Different cases:

  • URI with query string, lang first: /foo/bar/lang.php?lang=en-CA&uri=%2Ffoo%2Fbar%2Fpage.php%3Fid%3D123 should redirect to /foo/bar/page.php?id=123&lang=en-CA
  • URI without query string, lang first: /foo/bar/lang.php?lang=en-CA&uri=%2Ffoo%2Fbar%2Fpage.php should redirect to /foo/bar/page.php?lang=en-CA
  • URI with query string, uri first: /foo/bar/lang.php?uri=%2Ffoo%2Fbar%2Fpage.php%3Fid%3D123&lang=en-CA should redirect to /foo/bar/page.php?id=123&lang=en-CA
  • URI without query string, uri first: /foo/bar/lang.php?uri=%2Ffoo%2Fbar%2Fpage.php&lang=en-CA should redirect to /foo/bar/page.php?lang=en-CA

The order of the query parameters do not matter in the redirect target.

UPDATE

After the initial answer provided at https://stackoverflow.com/a/45732670/404623, I've tried the following .htaccess rules:

# This only works for uri values without query strings

RewriteCond %{QUERY_STRING} ^(lang=[^&]+)&uri=([^&]+) [NC]
RewriteRule lang\.php$ /%2\?%1 [L,NE,R=temporary]
RewriteCond %{QUERY_STRING} ^uri=([^&]+)&(lang=[^&]+) [NC]
RewriteRule lang\.php$ /%1\?%2 [L,NE,R=temporary]

# This only works for uri values with query strings

RewriteCond %{QUERY_STRING} ^(lang=[^&]+)&uri=([^&]+) [NC]
RewriteRule lang\.php$ /%2&%1? [L,NE,R=temporary]
RewriteCond %{QUERY_STRING} ^uri=([^&]+)&(lang=[^&]+) [NC]
RewriteRule lang\.php$ /%1&%2? [L,NE,R=temporary]
rink.attendant.6
  • 44,500
  • 61
  • 101
  • 156

1 Answers1

2

You can use this rule in your site root .htaccess just below RewriteEngine On line:

RewriteEngine On

# uri with query string    
RewriteCond %{QUERY_STRING}     (?:^|&)(lang=[^&]+) [NC]
RewriteCond %1##%{QUERY_STRING} (.*)##(?:.*&)?uri=([^?]+)(?:\?|%3F)([^&]+) [NC]
RewriteRule lang\.php$ /%2?%1&%3 [L,NE,R=302]

# uri without query string    
RewriteCond %{QUERY_STRING}     (?:^|&)(lang=[^&]+) [NC]
RewriteCond %1##%{QUERY_STRING} (.*)##(?:.*&)?uri=([^?]+) [NC]
RewriteRule lang\.php$ /%2?%1 [L,NE,R=302]
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Thanks! I had to change the rule use a question mark in the middle for it to work, like this: `RewriteRule lang\.php$ /%2\?%1 [L,NE,R=temporary]`. – rink.attendant.6 Aug 17 '17 at 12:58
  • Actually upon further testing I discovered that the `?` in the middle only works for URLs without query parameters whereas the `&` in the middle only works for URLs with query parameters. Is there a way to satisfy both cases? Also the order isn't guaranteed so I duplicated it with the uri first in order to handle that. I hope I don't have to duplicate all of it to handle with and without query params – rink.attendant.6 Aug 17 '17 at 13:07
  • ok I can tweak these rules further. But you should update question with your existing .htaccess that shows these new set of rules. Also please include a sample URL for each rule so that I can test rules after modifying. – anubhava Aug 17 '17 at 14:06
  • 1
    I have modified my question to add sample URLs as well as my attempts using the rule in your solution. – rink.attendant.6 Aug 17 '17 at 14:18
  • Ok good update. So URI with query parameters can be: `/path/to/lang.php?lang=en-CA&uri=%2Fpath%2Fto%2Fpage.php%3Ffoo%3Dbar` and without can be this `/path/to/lang.php?lang=en-CA&uri=%2Fpath%2Fto%2Fpage.php` right? – anubhava Aug 17 '17 at 14:46
  • 1
    Yes, exactly. The order of the query parameters might be different (as described). – rink.attendant.6 Aug 17 '17 at 15:59