質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.96%

PHP-FPM使用時のPHPファイルへのErrorDocument設定について・検証追記

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,788

snic518

score 37

前回、こちらの質問をさせていただきまして、その結果下記の構成で構築を進めていました。
また少し躓いてしまったので、質問を書かせていただいております。

  • VPS(さくらVPS)
  • CentOS7
  • Apache 2.4.6
  • PHP 7.0.3(PHP-FPM)

PHP-FPMを利用するため、Apacheには下記の設定をしています。

# php-fpm用の設定
ProxyPassMatch ^(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1
DirectoryIndex /index.php index.php

これで、PHPファイルがFPM/FastCGIで動いていることを確認できました。
ここまでは良かったのですが、この後ちょっと困ったことになりました。

バーチャルホスト設定のところで、独自のエラー画面を出すために、ErrorDocumentを設定しました。

<Directory "/var/www/html">
    :
    :
  ErrorDocument 503 /error/503.html
  ErrorDocument 404 /error/404.html
</Directory>

これで、存在しないアドレスにブラウザアクセスすると、HTMLファイルや画像ファイル等は、思った通りのエラー画面(/error/404.html)が表示されるのですが、PHPファイルだけは、おそらくPHP-FPMの標準のエラー表示がされるようなのです。
その時の表示は、「File not found.」とのテキスト表示のみで、ステータスコードは404です。

PHPファイルはFCGIの実行パスに飛ばしているから、そこのディレクトリにErrorDocumentを設定しないといけないのかと思いますが、PHP-FPMの実行ディレクトリがどこなのか、そもそもそれで良いのか等が、なかなか調べても出てこなかったので、質問させていただきました。

こうした場合にPHPファイルにもErrorDocumentを適用するには、どのようにすればよいのでしょうか。

ご意見賜れますと幸いです。
よろしくお願いいたします。


【20160225追記】

回答いただいた通りに、

この解決方法は、下記のサイトにもありました。

Apache 2.4 + PHP-FPM, catching error pages

結果、VirtualHostディレクティブの設定は以下のようになりました。

※今回の問題に関係ない記述もあると思いますが、念のためすべて掲載しました。

<VirtualHost *:80>
  ServerName hoge.jp
  DocumentRoot /var/www/html

  ProxyErrorOverride On
  ErrorDocument 503 /error/503.html
  ErrorDocument 404 /error/404.html
  ProxyPassMatch ^(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1
  <Directory "/var/www/html">
    Require all granted
    Options FollowSymLinks

    # Expires settings
    ExpiresActive On
    ExpiresByType text/css "access plus 7 day"
    ExpiresByType text/javascript "access plus 7 day"
    ExpiresByType application/x-javascript "access plus 7 day"

    # gzip transrate
    RewriteEngine On
    RewriteCond %{HTTP:Accept-Encoding} gzip
    RewriteCond %{REQUEST_FILENAME} \.js$ [OR]
    RewriteCond %{REQUEST_FILENAME} \.css$
    RewriteCond %{REQUEST_FILENAME} !\.gz$
    RewriteCond %{REQUEST_FILENAME}\.gz -s
    RewriteRule .+ %{REQUEST_URI}.gz

    <FilesMatch "\.js\.gz$">
      ForceType application/x-javascript
      AddEncoding x-gzip .gz
    </FilesMatch>

    <FilesMatch "\.css\.gz$">
      ForceType text/css
      AddEncoding x-gzip .gz
    </FilesMatch>
  </Directory>
</VirtualHost>

その結果、下記のような状態になりました。

・PHP以外のファイル … 変化無し。期待通りのエラーページ表示
・PHPファイル … 「File not found.」ではなく、ブラウザのエラーが発生。

ブラウザのエラーは、chromeの場合下記画像のような表示になります。

エラー表示

また、アドバイスいただいた通り、コンソールからcurlでアクセスしてみた場合は、期待通りのページのソースが返ってきました。

$ curl http://127.0.0.1/nofile.php
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="robots" content="noindex,nofollow">
<title>404</title>
</head>
:
:
</html>

これは外部の別のサーバーからIPを指定して実行しても同じで、なおかつ外部サーバーから、例えばPHPの下記のようなスクリプトを叩いてみても、期待する404ページHTMLが出力される状態です。

<?php
$context = stream_context_create(array(
      'http' => array('ignore_errors' => true)
 ));

$url = "http://hoge.jp/nofile.php";
echo file_get_contents($url, false, $context);


この時のレスポンスヘッダは以下でした。

HTTP/1.1 404 Not Found
Date: Thu, 25 Feb 2016 08:35:23 GMT
Server: Apache
Last-Modified: Thu, 25 Feb 2016 08:31:54 GMT
Accept-Ranges: bytes
Content-Length: 1823
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Connection: close
Content-Type: text/html; charset=UTF-8

つまり、データの通信上は正しく設定されたものがやり取りされているものの、ブラウザが受信した場合はそれをHTMLページとして表示できていない、という状態なのかなと思います。

なお、iPhone Safariでアクセスすると、エラーページの表示は「RAWデータをデコードできません」というものになりました。

Content-Typeはちゃんとtext/htmlになっているみたいなのですが、どうしてこのような状態になっているのか、色々調べてもわかりませんでした。

何か問題点があるか、どなたかおわかりになりませんでしょうか。
よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

php-fpm 側にエラードキュメントを設定する方法についてはわかりませんが、
RewriteCond で .php ファイルが存在する場合のみ php-fpm に渡す方法はどうでしょうか。 

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/(.*\.php)(/.*)?$
RewriteCond /var/www/html/%1 -f
RewriteRule ^(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1 [P,L]

(追記)
ProxyErrorOverride On とする方法もありました。
ただし、<Directory "/var/www/html"> のスコープから外れるようですので、
別途、ErrorDocument を設定する必要があります。

ProxyErrorOverride On
ErrorDocument 503 /error/503.html
ErrorDocument 404 /error/404.html
ProxyPassMatch ^(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/23 17:27

    コメントありがとうございます。大変助かります。
    早速ProxyErrorOverrideの方を試してみました。
    -------------------------------------------------------------------
    #Directoryの外に追記
    ProxyErrorOverride On
    ErrorDocument 503 /error/503.html
    ErrorDocument 404 /error/404.html
    ProxyPassMatch ^(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1
    <Directory "/var/www/html">
    :
    :
    #ErrorDocument 503 /error/503.html
    #ErrorDocument 404 /error/404.html
    </Directory>
    -------------------------------------------------------------------

    すると、今度は存在しないPHPファイルにアクセスした時にブラウザのエラーが返るようになりました。
    ※Chromeだと「このウェブページにアクセスできません ERR_CONTENT_DECODING_FAILED」と出ます。
    エラーログは下記のようになっていて、これは変更前と同じです。

    AH01071: Got error 'Primary script unknown\n'

    PHP以外のファイルについては、変更前後も同じように意図したページ表示になりました。
    これは、エラーのHTMLをPHP-FPMが参照できる場所に追加で置かないといけないということでしょうか。
    たびたびすみません。

    キャンセル

  • 2016/02/23 18:32

    設定は問題ないと思います。ブラウザ側の問題でしょうか?
    サーバーで「curl http://127.0.0.1/nofile.php」などで 404.html が返りませんでしょうか。

    キャンセル

  • 2016/02/23 18:46

    コメントありがとうございます。

    >curl http://127.0.0.1/nofile.php

    こちら、試したところ、コンソール上には指定したページのソースが返ってきました。

    -------------------------------------------------------------------
    $ curl http://127.0.0.1/nofile.php
    <!doctype html>
    <html lang="ja">
    <head>
    <meta charset="utf-8">
    <meta name="robots" content="noindex,nofollow">
    <title>404</title>
    </head>
    :
    :
    </html>
    -------------------------------------------------------------------

    また、こことは別のサーバーから同じようにcurlを叩いた場合も
    同様に404エラー用のHTMLソースが返ってきました。

    しかし、依然ブラウザからのアクセスでは見えない状態です。
    ドメインではなくIP直アクセスにしてみてもダメでした。
    通信環境の問題も考え、スマートフォンからアクセスしてみても、同様にページが見つからないエラーとなりました。
    何か他に原因になりそうなことはありますでしょうか。

    キャンセル

0

追記をした後、エラーメッセージを再度検索していろいろ調べたところ、解決しました。

参考ページ:
Fixing ERR_CONTENT_DECODING_FAILED in Apache+PHP

php.iniの設定で、zlib.output_compressionを有効にしていました。

zlib.output_compression=On

これが原因だったようで、Offにした後PHP-FPMを再起動したところ、エラーページが表示されるようになりました。
お騒がせいたしました。

zlib.output_compression=On の設定は、存在するスクリプトだけで機能するよう、スクリプト内のini_setで指定するようにします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.96%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる