Drupal 8 or 9 の 500 エラーページをカスタマイズする

Drupal 8 or 9 で致命的なエラーが発生した時に表示される 500エラーページをカスタマイズする方法を紹介します。

500エラーページとはこういうメッセージが表示されるやつです:

```
The website encountered an unexpected error. Please try again later.
```

## 選択肢

### a) Drupal だけで対応する場合

* Drupal 9.0.7 時点では、コアのエラー処理をカスタマイズする方法は用意されておらず、スマートな実現方法はない  
* エラーの発生場所、内容によってはカスタマイズが不可能な場合もある (`settings.php` でのエラーなど)

#### 選択肢

1. 実行時にエラーハンドラを独自のものに置き換える
    * この方法で実装された [error_page](https://www.drupal.org/project/error_page) モジュールが存在
    * コアのコードをコピペ & 修正してエラーハンドラをまるごと置き換える必要があり、コアのアップデートに追従できないリスクがある
2. コアのエラーハンドラを修正する
    1. 自前で修正する
        * 奥の手
    2. Drupal.org の issue ([Ability to Customize Core Error Message [#3108689] | Drupal.org](https://www.drupal.org/project/drupal/issues/3108689)) のパッチを利用する
        * **★ 次点でこれ**

### b) CDN などの上位層で対応する場合

1. CDNで対応
    * **★ 使えればこれがベスト**
    * CloudFront の場合: [特定の HTTP ステータスコードのカスタムエラーページを作成する - Amazon CloudFront](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/custom-error-pages.html)
    * 静的なHTMLページを用意する
2. Apache でがんばる
    * `mod_ext_filter` を使えばできないことはないが、色々デメリットがあるため非現実的
    * フィルタプログラムを作る手間とかパフォーマンスへの影響とか

以下では、#3108689 のパッチを利用してDrupalだけで対応する方法について考えます。

## a.2.2) [#3108689](https://www.drupal.org/project/drupal/issues/3108689) のパッチを利用する方法

CDNでの対応ができない場合は、次点でこれが一番マシだと思われます。

Drupal.orgで、500エラーページのメッセージをカスタマイズする機能を追加するissueが進行中で、
[Ability to Customize Core Error Message [#3108689] | Drupal.org](https://www.drupal.org/project/drupal/issues/3108689)

パッチの内容には大きな問題はなさそうでですが、まだマージされていないため使うには自前でパッチを当てる必要があります。
また、issueに添付されている `3108689-51.patch` のパッチは、drupal/core パッケージには存在しないファイル (`sites/default/default.settings.php`) のdiffが含まれるため、そのdiffを取り除いてから適用する必要があります。  
(`cweagans/composer-patches` プラグインを使ってパッチを当てることを想定)

### 使い方

1.  [#3108689](https://www.drupal.org/project/drupal/issues/3108689) のパッチから不要な diff を削除したファイルをリポジトリに追加する
    * `sites/default/default.settings.php` のdiffを消す
    * 修正したパッチを `[repo-root]/patches/drupal/core/3108689-51--mod.patch` などに置く
2.  `composer.json` の `extra.patches.drupal/core` にパッチのパスを追加
3.  `composer install` 実行
4.  `settings.php` で `$settings['custom_error_message']` にエラーページの内容 (HTML) を設定する

### 気をつけること

* 完全に静的な HTML 文字列を `$settings` に設定する
    * CSSファイルなどへのURLも絶対URLで直接記述する
    * 内容を動的に変えることはできない
* `settings.php` に直接HTMLを書く必要がある
    * HTMLファイルに分離すると必要ないときもファイル読み込みが発生してしまうため

### 使用例

```json:composer.json
    "extra": {
        "patches": {
            "drupal/core": {
                "3108689 Ability to Customize Core Error Message": "patches/drupal/core/3108689-51--mod.patch"
            }
        },
```

```php:settings.php
$settings['custom_error_message'] = <<<'HTML'
<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <title>エラーです</title>
  <style>
  body {
    width: 400px;
    margin: 0 auto;
  }
  h1 {
    background-color: red;
    color: white;
  }
</style>
</head>
<body>
  <h1>エラーです</h1>
  <p>何かやばいエラーが発生しました。</p>
  <p>しばらく待ってから再読み込みしてみてください。</p>
  <p><a href="/">トップページを開く</a></p>
</body>
</html>
HTML;
```

#### 上記の設定によって表示される 500 エラーページの例

![5d869b92-b6d8-75c2-fcdf-4effa061bc16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/949115/3ac39c0b-11bd-d353-48c4-e7b2e3a04265.png)