PHP FastCGI の例

この例は、内蔵されたPHP FPM (FastCGI プロセスマネージャー)を使った新しいPHP (>= 5.3.3) のためのものです。

このガイドは、PHP FPMが既にインストールされていて、tcpポート (127.0.0.1:9000) あるいはunixソケット (/var/run/php-fpm.sock) のどちらかを使うように設定されていることを仮定します。

PHP FPMを使ったNGINXの設定についての多くのガイドがありますが、それらの多くは不完全(PATH_INFO を適切に処理しない) あるいはセキュリティの問題(スクリプトが実際にphpファイルかどうかをチェックしない)を含んでいます。

FastCGI パラメータ

まず、全ての代表的なFCGI設定を1つのファイルにまとめ、それらをimportすることをお勧めします。

例えば、debian および ubuntu 上でデフォルトでは、/etc/nginx/fastcgi_params ファイルは以下のようになります:

fastcgi_param   QUERY_STRING            $query_string;
fastcgi_param   REQUEST_METHOD          $request_method;
fastcgi_param   CONTENT_TYPE            $content_type;
fastcgi_param   CONTENT_LENGTH          $content_length;

fastcgi_param   SCRIPT_FILENAME         $document_root$fastcgi_script_name;
fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
fastcgi_param   PATH_INFO               $fastcgi_path_info;
fastcgi_param   PATH_TRANSLATED         $document_root$fastcgi_path_info;
fastcgi_param   REQUEST_URI             $request_uri;
fastcgi_param   DOCUMENT_URI            $document_uri;
fastcgi_param   DOCUMENT_ROOT           $document_root;
fastcgi_param   SERVER_PROTOCOL         $server_protocol;

fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
fastcgi_param   SERVER_SOFTWARE         nginx/$nginx_version;

fastcgi_param   REMOTE_ADDR             $remote_addr;
fastcgi_param   REMOTE_PORT             $remote_port;
fastcgi_param   SERVER_ADDR             $server_addr;
fastcgi_param   SERVER_PORT             $server_port;
fastcgi_param   SERVER_NAME             $server_name;

fastcgi_param   HTTPS                   $https;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param   REDIRECT_STATUS         200;

Ubuntu Precise (12.04) を使っている場合、SCRIPT_FILENAME を変更し、PATH_INFOパラメータを追加することに注意してください。

NGINXをPHP FPMに接続

ここで、NGINXがFCGIプロトコルを使ってリクエストをPHP FPMにproxyするように指示しなければなりません:

location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
        return 404;
    }

    # Mitigate https://httpoxy.org/ vulnerabilities
    fastcgi_param HTTP_PROXY "";

    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;

    # include the fastcgi_param setting
    include fastcgi_params;

    # SCRIPT_FILENAME parameter is used for PHP FPM determining
    #  the script name. If it is not set in fastcgi_params file,
    # i.e. /etc/nginx/fastcgi_params or in the parent contexts,
    # please comment off following line:
    # fastcgi_param  SCRIPT_FILENAME   $document_root$fastcgi_script_name;
}

unixソケットを使っている場合は、fastcgi_pass を以下に変更してください:

fastcgi_pass unix:/var/run/php-fpm.sock;

NGINXを再起動します。

テスト

ちょうど以下のものを含むtest.phpをNGINXドキュメントルート上に作成します:

 var_export($_SERVER)?>

ブラウザ内で以下をリクエストしてみてください: # /test.php # /test.php/ # /test.php/foo # /test.php/foo/bar.php # /test.php/foo/bar.php?v=1

REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME, PATH_INFO および PHP_SELF の値に注意してください。

以下はhttp://lemp.test/test.php/foo/bar.php?v=1の正しい出力です

array (
  'USER' => 'www-data',
  'HOME' => '/var/www',
  'FCGI_ROLE' => 'RESPONDER',
  'QUERY_STRING' => 'v=1',
  'REQUEST_METHOD' => 'GET',
  'CONTENT_TYPE' => '',
  'CONTENT_LENGTH' => '',
  'SCRIPT_FILENAME' => '/var/www/test.php',
  'SCRIPT_NAME' => '/test.php',
  'PATH_INFO' => '/foo/bar.php',
  'REQUEST_URI' => '/test.php/foo/bar.php?v=1',
  'DOCUMENT_URI' => '/test.php/foo/bar.php',
  'DOCUMENT_ROOT' => '/var/www',
  'SERVER_PROTOCOL' => 'HTTP/1.1',
  'GATEWAY_INTERFACE' => 'CGI/1.1',
  'SERVER_SOFTWARE' => 'nginx/1.4.0',
  'REMOTE_ADDR' => '192.168.56.1',
  'REMOTE_PORT' => '44644',
  'SERVER_ADDR' => '192.168.56.3',
  'SERVER_PORT' => '80',
  'SERVER_NAME' => '',
  'HTTPS' => '',
  'REDIRECT_STATUS' => '200',
  'HTTP_HOST' => 'lemp.test',
  'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0',
  'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.5',
  'HTTP_ACCEPT_ENCODING' => 'gzip, deflate',
  'HTTP_CONNECTION' => 'keep-alive',
  'PHP_SELF' => '/test.php/foo/bar.php',
  'REQUEST_TIME' => 1367829847,
)

注意

  1. PATH_INFO を処理し、PATH_INFO があるかどうかに関わらず、拡張子が実際に .php (.phps ではありません) であることを適切にチェックできる location の正規表現。

  2. fastcgi_split_path_info regex は/test.php/foo/blah.php あるいは /test.php/のようなリクエストを正しく処理することができます。

  3. if により、NGINXがPHP FPMに(アップロードされたイメージのような)非phpスクリプトファイルを入力することを防ぐために*.php が実際に存在するかどうかをチェックさせます。

    幾つかのガイドはifの代わりにtry_filesを使うように勧めます。そうする場合は、NGINX のbug #321に注意してください。個人的には、if の方が適切だと思います。If は location のコンテキストで使う場合に邪悪です これが if で使う100%安全なものの1つであることに同意します。

  4. SCRIPT_FILENAME パラメータは、スクリプト名を決定するために PHP FPM に渡されるために必要です。

    In the builds of NGINX for a lot of Linux distributions, this parameter has been added in fastcgi_params file, i.e. /etc/nginx/fastcgi_params``so the users could import all the CGI params via the ``include directive, i.e. include fastcgi_params . しかし、CentOSのような一部のディストリビューションでは、このパラメータはfastcgi_params ファイルの中に存在しません。

    このパラメータが設定されていない場合、PHP FPMは空の内容の200 OKを応答し、エラーあるいは警告はありません。CGIパラメータの詳細については、nginx初心者ガイド, PHPでの$_SERVER および RFC3875を参照してください。

  5. ブラウザに空白のページが表示される場合は、SCRIPT_FILENAMEパラメータが設定されているか調べてください。

  6. このガイドは、php.ini で cgi.fix_pathinfo = 1 (デフォルト) で良く動作します。

    幾つかのガイドではそれをcgi.fix_pathinfo = 0に変更するように言い張りますが、そうすると PHP_SELF 変数を破壊します (DOCUMENT_URIと同じではありません)。

inserted by FC2 system