Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Slim PHP Framework routes in a subdirectory on nginx

Tags:

php

nginx

slim

I'm trying to move a Slim application to a subdirectory, so that it can be accessed at example.com/api/, but I'm having serious problems getting the routing to work.

The main script is at /website/workbench/api/public/index.php, so a call to example.com/api/project/1 should hit the API folder. However, I also need to be able to access example.com's index.html file (which is running on Angular JS).

It does hit the PHP script when I go to example.com/api/project/1 - I can var_dump variables and see them. However, the routing is not taking effect, and the request variables seem to be empty.

/etc/nginx/sites-available/workbench

server {
    listen   80; ## listen for ipv4; this line is default and implied

    root /website/workbench;
    index index.php index.html index.htm;

    server_name example.com;

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

    location /api/ {
        try_files $uri $uri/ /api/public/index.php?$query_string;
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param PHP_VALUE "newrelic.appname=workbench";
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

(Obviously example.com is replaced with the real domain name)

Partial output of var_dump($_SERVER);

array(34) {
  ["USER"]=>
  string(8) "www-data"
  ["HOME"]=>
  string(8) "/var/www"
  ["FCGI_ROLE"]=>
  string(9) "RESPONDER"
  ["PHP_VALUE"]=>
  string(26) "newrelic.appname=workbench"
  ["QUERY_STRING"]=>
  string(0) ""
  ["REQUEST_METHOD"]=>
  string(3) "GET"
  ["CONTENT_TYPE"]=>
  string(0) ""
  ["CONTENT_LENGTH"]=>
  string(0) ""
  ["SCRIPT_FILENAME"]=>
  string(39) "/website/workbench/api/public/index.php"
  ["SCRIPT_NAME"]=>
  string(21) "/api/public/index.php"
  ["REQUEST_URI"]=>
  string(15) "/api/projects/1"
  ["DOCUMENT_URI"]=>
  string(21) "/api/public/index.php"
  ["DOCUMENT_ROOT"]=>
  string(18) "/website/workbench"
  ["SERVER_PROTOCOL"]=>
  string(8) "HTTP/1.1"
  ["GATEWAY_INTERFACE"]=>
  string(7) "CGI/1.1"
  ["SERVER_SOFTWARE"]=>
  string(11) "nginx/1.4.6"
}

var_dump($_REQUEST) gives an empty array.

Clearly there's something spectacularly wrong with my set-up, but I'm struggling to see what! Changing $query_string to $args has no effect either.

like image 998
RobL Avatar asked Sep 24 '14 10:09

RobL


2 Answers

Very late to the party here, but I was having the same issue with serving static files (an Angular application) in the root of the site, and serving a slim application in /api. As you pointed out, Slim really needs the REQUEST_URI to not have the /api in it.

server {
 server_name example.com;

    location ~ ^/api/(.*)$ {
           alias /path/to/slim-app/public/;
           try_files $1 $1/ @php;
           index index.php;
    }

    location / {
            root /path/to/your/static/files;
    }

    location @php {
           fastcgi_split_path_info ^(/api)(/.*)$;
           fastcgi_pass localhost:9000;
           fastcgi_index index.php;
           include fastcgi_params;
           fastcgi_param SCRIPT_FILENAME /path/to/slim-app/public/index.php;
           fastcgi_param REQUEST_URI $fastcgi_path_info;
           fastcgi_read_timeout 900;
    }
 }

The key for me lied in the fastcgi_split_path_info trickery. As per http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_split_path_info, what the operation does is split the $fastcgi_path_info variable into two new variables called $fastcgi_script_name and $fastcgi_path_info.

When you put in fastcgi_split_path_info ^(/api)(/.*)$; you essentially set $fastcgi_script_name to /api and set $fastcgi_path_info to /my/route. I found this was enough to get Slim (v3) working the way I wanted.

However, I also found that my default Slim app has DOCUMENT_URL and SCRIPT_NAME variables set to index.php. So you can also set them (although it doesn't seem to be required):

set $script_name "/index.php";
fastcgi_param DOCUMENT_URI $script_name;
fastcgi_param SCRIPT_NAME $script_name;
like image 186
Ben Avatar answered Nov 07 '22 02:11

Ben


I think you can remove $query_string from try_files. Add a root directive in /api location, like this:

location /api {
    root /website/workbench/api;
    try_files $uri $uri/ /public/index.php;
}

and use the fastcgi_param SCRIPT_FILENAME parameter eventually defined as:

 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

into the fastcgi_params file.

like image 37
Stefano Falsetto Avatar answered Nov 07 '22 00:11

Stefano Falsetto