nginx $document_root$fastcgi_script_name と $request_filename の違い


## 前書き

ファイルが存在するかどうかの記述でよく、 `if (-f $request_filename) { ... }` と `if (-f $document_root$fastcgi_script_name) { ... }` の2通りがあるが、これって何か違うの？って思った時がありました。

その頃、調べた内容を下記に記します。

## 変数の意味

### `$request_filename`

[Module ngx_http_core_module #variables](http://nginx.org/en/docs/http/ngx_http_core_module.html#variables)

現在のリクエストのファイルパスは、 `root` または `alias` ディレクティブとリクエストの URI に基づきます。

### `$document_root`

[Module ngx_http_core_module #variables](http://nginx.org/en/docs/http/ngx_http_core_module.html#variables)

現在のリクエストの `root` または `alias` ディレクティブの値です。

### `$fastcgi_script_name`

[Module ngx_http_fastcgi_module #variables](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#variables)

URI がスラッシュで終わっている場合、URI をリクエストするか、 URI に `fastcgi_index` ディレクティブによって設定されたインデックスファイル名をつけてリクエストしてください。この変数は、 PHPのスクリプト名を決定する `SCRIPT_FILENAME` と `PATH_TRANSLATED` パラメータを設定するために使用することができます。例えば、次のディレクティブを持つ `/info/` リクエストについて

```nginx
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/www/scripts/php$fastcgi_script_name;
```

`SCRIPT_FILENAME` パラメータは `/home/www/scripts/php/info/index.php` と等しい。
`fastcgi_split_path_info` ディレイクティブを使っている場合、 `$fastcgi_script_name` はそのディレイクティブにより設定された一つ目のキャプチャの値と等しい。

※ 正規表現では、特定のパターンにマッチした文字列を後で参照できるように保存しておくことをキャプチャと呼びます。

## 上記の変数を扱う上で押さえておくべき重要なディレイクティブ

### `fastcgi_split_path_info` ディレイクティブ

[Module ngx_http_fastcgi_module #fastcgi_split_path_info](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_split_path_info)

```
Syntax:   fastcgi_split_path_info regex;
Default:  —
Context:  location
```

`$fastcgi_path_info` の値をキャプチャする正規表現を定義します。正規表現は、2つのキャプチャを持つ必要があります。一つ目は `$fastcgi_script_name` の値になり、二つ目は `$fastcgi_path_info` の値になります。例えば、以下のようなの設定の場合

```nginx
location ~ ^(.+\.php)(.*)$ {
    fastcgi_split_path_info       ^(.+\.php)(.*)$;
    fastcgi_param SCRIPT_FILENAME /path/to/php$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;
```

そして、 `/show.php/article/0001` リクエストは、SCRIPT_FILENAME パラメータは `/path/to/php/show.php` と等しく、 `PATH_INFO` パラメータは `/article/0001` と等しい。

### `fastcgi_index` ディレイクティブ

[Module ngx_http_fastcgi_module #fastcgi_index](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_index)

```
Syntax:   fastcgi_index name;
Default:  —
Context:  http, server, location
```

`$fastcgi_script_name` の値で、スラッシュで終わる URI の後に追加されるファイル名を設定します。例えば、以下のような設定の場合

```nginx
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/www/scripts/php$fastcgi_script_name;
```

そして、 `/page.php` リクエストは、SCRIPT_FILENAME パラメータは `/home/www/scripts/php/page.php` と等しく、 `/` とリクエストされた場合は `/home/www/scripts/php/index.php` と等しい。

## 本題

### 結局違いは？

下記の記事を見つけました。

[web server - Nginx $document_root$fastcgi_script_name vs $request_filename - Server Fault](http://serverfault.com/questions/465607/nginx-document-rootfastcgi-script-name-vs-request-filename "web server - Nginx $document_root$fastcgi_script_name vs $request_filename - Server Fault")

> You get the request "/info/" and have the following configuration:
> ```
> fastcgi_index  index.php;
> fastcgi_param  SCRIPT_FILENAME  /home/www/scripts/php$fastcgi_script_name;
> ```
> SCRIPT_FILENAME would equal "/home/www/scripts/php/info/index.php", but using $request_filename it would just be "/home/www/scripts/php/info/".

`/info/` とリクエストされ、 `SCRIPT_FILENAME` パラメータに `/home/www/scripts/php$fastcgi_script_name` を使用した場合 `/home/www/scripts/php/info/index.php` と等しいが、 `$request_filename` を使用した場合は `/home/www/scripts/php/info/` と等しい。

とのことでした。上記の記述が正しいかどうか実証してみます。

### 実証

#### 前提

下記の記事内容を最低限把握している程で実証をするため、インストール手順や公開ディレクトリの作成、設定後の再起動等は省略します。

[nginx と php-fpm の仕組みをちゃんと理解しながら PHP の実行環境を構築する - Qiita](http://qiita.com/kotarella1110/items/634f6fafeb33ae0f51dc)

#### 環境

```vim:/etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.1 LTS"
```

#### 設定

`add_header` ディレイクティブを使って変数の確認を行います。詳しく知りたい方は下記をご覧ください。

[nginx 変数の値を確認したい時は add_header ディレイクティブを使うと超絶簡単 - Qiita](http://qiita.com/kotarella1110/items/33d6cfbe6cb897c2af4d)

```nginx:/etc/nginx/nginx.conf
server {
    listen 80 default_server;

    root /home/www/scripts/php;
    index index.php index.html index.htm;

    server_name localhost;

    location /info/ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;

        add_header $request_filename $request_filename;
        add_header $document_root$fastcgi_script_name $document_root$fastcgi_script_name;
    }
}
```

#### 変数の値を確認

##### `/info/` でリクエスト

```console
$ curl -I localhost/info/
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Mon, 28 Mar 2016 11:30:28 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
$request_filename: /var/www/info/
$document_root$fastcgi_script_name: /var/www/info/index.php
```

##### `/info/index.php` でリクエスト

```console
$ curl -I localhost/info/index.php
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Mon, 28 Mar 2016 11:30:13 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
$request_filename: /var/www/info/index.php
$document_root$fastcgi_script_name: /var/www/info/index.php
```

## 参考文献

* [nginx documentation](http://nginx.org/en/docs/)
* [web server - Nginx $document_root$fastcgi_script_name vs $request_filename - Server Fault](http://serverfault.com/questions/465607/nginx-document-rootfastcgi-script-name-vs-request-filename "web server - Nginx $document_root$fastcgi_script_name vs $request_filename - Server Fault")