Rewrite don't work in a multilanguage MVC site

Hi!Im trying to move from Apache to nginx (v1.1.6), but you know,
rewrite newbie here… In my site when a user types http://site.com he’s
redirected to http://site.com/en/, and all the other URLs are internally
handled by an index.php. This is my actual Apache htaccess:
RewriteEngine On
RewriteCond %{HTTP:Accept-Language} ^en [NC] RewriteRule ^$ /en/
[L,R=301]
RewriteCond %{HTTP:Accept-Language} ^es [NC] RewriteRule ^$ /es/
[L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond
%{REQUEST_FILENAME} !-d RewriteRule (.) index.php?ctr=$1 [QSA,L]
And this my translation to nginx:
location / { if (-f $request_filename) {
expires 30d; break; }
if ($http_accept_language ~
“^es”) {
rewrite ^/$ /es/ permanent; break; }
if ($http_accept_language ~* “^en”) {
rewrite ^/$ /en/ permanent; break; }
if (!-e $request_filename) { rewrite
(.*) /index.php?ctr=$1 last; } } location ~ .php$
{ fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name; …
With this, when I type http://site.com I’m being redirected to
http://site.com/en/, great, but I get a 404 error, and in the error.log
I have this line:
“/bla/bla/html/en/index.php” is not found
So, why is not nginx looking for the URI /index.php?ctr=/en/?

On 25 Out 2011 17h56 WEST, [email protected] wrote:

[1 <multipart/alternative (7bit)>]
[1.1 <text/plain; iso-8859-1 (quoted-printable)>]

Hi!Im trying to move from Apache to nginx (v1.1.6), but you know,
rewrite newbie here… In my site when a user types http://site.com
he’s redirected to http://site.com/en/, and all the other URLs are
internally handled by an index.php. This is my actual Apache

Try this:

At the http level.

map $http_accept_language $is_english {
default 0;
~^en 1;
}

map $http_accept_language $is_spanish {
default 0;
~^es 1;
}

location / {

expires 30d;

if ($is_english) {
return 301 /en;
}

if ($is_spanish) {
return 301 /es;
}

location /es {}

location /en {}

try_files $uri $uri/ /index.php?ctr=$uri;
}

location ~.php$ {

PHP stuff

}

— appa

Tried, and same results, redirect OK but 404 response.
Thanks!!

Show your complete config.

— appa

Here we go. Those includes are the standard locations por PHP-FPM and
static content:
map $http_accept_language $is_english { default 0; ~^en 1;}
map $http_accept_language $is_spanish { default 0; ~^es 1;}
server { listen 80; server_name localhost; root blah/blah;
location / { auth_basic “Restricted”; auth_basic_user_file
htpasswd; index index.php index.html;
expires 30d;
if ($is_english) { return 301 /en; }
if ($is_spanish) { return 301 /es; }
location /es {}
location /en {}
try_files $uri $uri/ /index.php?ctr=$uri; }
include /usr/local/nginx/conf/staticfiles.conf; include
/usr/local/nginx/conf/php.conf; include
/usr/local/nginx/conf/drop.conf;}

On 25 Out 2011 19h17 WEST, [email protected] wrote:

Tried, and same results, redirect OK but 404 response.
Thanks!!

Show your complete config.

— appa

On Tue, Oct 25, 2011 at 06:56:05PM +0200, Fernando Garca Torres wrote:

Hi there,

RewriteEngine On
RewriteCond %{HTTP:Accept-Language} ^en [NC]    RewriteRule ^$ /en/ 

[L,R=301]

RewriteCond %{HTTP:Accept-Language} ^es [NC]    RewriteRule ^$ /es/ 

[L,R=301]

RewriteCond %{REQUEST_FILENAME} !-f    RewriteCond %{REQUEST_FILENAME} !-d 

RewriteRule (.*) index.php?ctr=$1 [QSA,L]

If I read this right, it only redirects the request for “/” to “/en/” or
“/es/” if the Accept-Language header begins with one of those strings;
otherwise, if the file-or-directory exists, serve it; otherwise,
redirect
to index.php?ctr=(the original request).

Note that nginx and apache differ in the leading / of the url, so you’ll
want to make sure that you allow for that. I’m going to assume that you
want to redirect to /index.php for all otherwise-404s.

Also note that you’ll want to check whether apache writes
index.php?ctr=request or index.php?ctr=/request. The check what you
configure nginx to write, and see if it works too.

And as a final note – checking the first two characters of
Accept-Language is not the right way to process that header. But it’s
your site, and you get to do what you want on it.

And this my translation to nginx:
location / { if (-f $request_filename) {
expires 30d; break; }
if ($http_accept_language ~* “^es”) { rewrite ^/$
/es/ permanent; break; }
if ($http_accept_language ~* “^en”) { rewrite ^/$
/en/ permanent; break; }
if (!-e $request_filename) { rewrite (.*)
/index.php?ctr=$1 last; } }

I suggest writing this as two locations:

    location = / {
      if ($http_accept_language ~* "^en") {
         return 301 /en/;
      }
      if ($http_accept_language ~* "^es") {
         return 301 /es/;
      }
    }

    location / {
      try_files $uri $uri/ /index.php?ctr=$uri;
    }

location ~ .php$ { fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name; …

I would be more explicit, unless you have more php scripts:

    location = /index.php {
      fastcgi_pass unix:php.sock;
    }

with

    include fastcgi.conf;

at server level. But however you want to handle php is probably fine.

With this, when I type http://site.com I’m being redirected to
http://site.com/en/, great, but I get a 404 error, and in the error.log I have
this line:
“/bla/bla/html/en/index.php” is not found

I get a 403 Forbidden, not a 404, so I must have some other
configuration
difference from you.

So, why is not nginx looking for the URI /index.php?ctr=/en/?
Per the config, if the directory exists, it is served.

In my tests /en/ exists and returns 403, /ex/ doesn’t and returns the
same content as /index.php?ctr=/ex/ does, apart from REQUEST_URI being
different.

Good luck with it,

f

Francis D. [email protected]