1. Home
  2. PHP
  3. Laravel
  4. Laravelで独自の動的エラーページ(404/503 etc)を手早く作成する(多言語対応も)

Laravelで独自の動的エラーページ(404/503 etc)を手早く作成する(多言語対応も)

  • 公開日
  • 更新日
  • カテゴリ:Laravel
  • タグ:PHP,Laravel,ErrorPage,Localization
Laravelで独自の動的エラーページ(404/503 etc)を手早く作成する(多言語対応も)

Laravel のエラーページは美しいと評価も高いです。例えば 404 ページはこんな感じで

「Sorry, the page you are looking for could not be found.」
「申し訳ありませんが、あなたが探しているページが見つかりませんでした。」
というテキストと共に、白背景にスタイリッシュなフォント「Raleway 」が洗練された雰囲気を演出してくれています。

しかし、エラーページをデフォルトのまま使用するというのは通常の開発案件ではなかなか難しいものがあります。

そこで今回は、Laravel のエラーページをカスタマイズし、オリジナルのものを出力するまでを行います。そしてついでに、エラーページを多言語化対応もさせてみます。

Contents

  1. 開発環境
  2. 独自エラーページの表示ロジックについて
  3. 独自エラーページの作成
  4. エラーを発生させエラーページを表示する
  5. エラーページの多言語対応
    1. 言語ファイルの作成
    2. 言語設定
    3. 多言語対応エラーページの作成

開発環境

今回の開発環境は以下の通りです。

  • Linux CentOS 7
  • Apache 2.4
  • PHP 7.2/7.1
  • Laravel

Laravel のバージョンについては、5.6/5.5/5.4/5.3 にて動作確認済みです。

Laravel のルートディレクトリを「laravel/」とします。

独自エラーページの表示ロジックについて

実は Laravel での独自エラーページの適用は非常に簡単です。

ビューを格納している laravel/resources/views 配下に errors ディレクトリを作成し、その中に HTTP ステータスコードでファイル名を作成し配置すれば、自動的に独自エラーページが表示されます。

例えば、404 ページであれば「404.blade.php 」というファイル名で作成すれば、404 発生時には自動的に独自で作成した 404 エラーページを表示してくれる。という事になります。

独自エラーページの作成

では実際にエラーページを作成します。今回は、こんな構成で作成しました。

laravel
├─ resources
│   ├─ views
│   │   ├─ errors
│   │   │   ├─ 400.blade.php
│   │   │   ├─ 401.blade.php
│   │   │   ├─ 403.blade.php
│   │   │   ├─ 404.blade.php
│   │   │   ├─ 500.blade.php
│   │   │   └─ 503.blade.php
│   │   │   └─ layouts
│   │   │         └─ base.blade.php

レイアウトとして layouts ディレクトリにエラーページのベースとなる HTML(base.blade.php)を作成し、それを各エラーページファイルに適用させていくという構成です。

laravel/resources/views/errors/layouts/base.blade.php
<!DOCTYPE html>
<html lang="ja">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
  <meta charset="UTF-8">
  <title>@yield('title')</title>
  <style>
    .error-wrap {
      margin: auto;
      padding: 5px 20px;
      width: 300px;
      display: inline-block;
      border: 1px solid #dcdcdc;
      box-shadow: 0px 0px 8px #dcdcdc;
    }
    h1 { font-size: 18px; }
    p { margin-left: 10px; font-size: 12px; }
  </style>
</head>
<body>
<div class="error-wrap">
  <section>
    <h1>@yield('title')</h1>
    <p class="error-message">@yield('message')</p>
    <p class="error-detail">@yield('detail')</p>
    @yield('link')
  </section>
</div>
</body>
</html>
400.blade.php
@extends('errors.layouts.base')

@section('title', '400 Bad Request')

@section('message', 'There is an error in the request.')
{{-- リクエストにエラーがあります。 --}}

@section('detail', 'This response indicates that the server can not understand the request because the syntax is invalid.')
{{-- このレスポンスは、構文が無効であるためサーバーがリクエストを理解できないことを示します。 --}}
401.blade.php
@extends('errors.layouts.base')

@section('title', '401 Unauthorized')

@section('message', 'certification failed.')
{{-- 認証に失敗しました。 --}}

@section('detail', 'Authentication is required to obtain the requested resource.')
{{-- リクエストされたリソースを得るために認証が必要です。 --}}
403.blade.php
@extends('errors.layouts.base')

@section('title', '403 Forbidden')

@section('message', 'You do not have access.')
{{-- あなたにはアクセス権がありません。 --}}

@section('detail', 'It indicates that the client does not have access to the content and the server is refusing to reply the appropriate response.')
{{-- クライアントがコンテンツへのアクセス権を持たず、サーバーが適切な応答への返信を拒否していることを示します。 --}}
404.blade.php
@extends('errors.layouts.base')

@section('title', '404 Not Found')

@section('message', 'The page of the corresponding address could not be found.')
{{-- 該当アドレスのページを見つける事ができませんでした。 --}}

@section('detail', 'The server indicates that it could not find the requested resource. A typo in the URL, or the page may have been moved or deleted. Please go back to the top page or search again.')
{{-- サーバーは要求されたリソースを見つけることができなかったことを示します。 URL のタイプミス、もしくはページが移動または削除された可能性があります。 トップページに戻るか、もう一度検索してください。 --}}

@section('link')
  <p><a href="{{env('APP_URL')}}">to TOP&gt;&gt;</a></p>
@endsection
500.blade.php
@extends('errors.layouts.base')

@section('title', '500 Internal Server Error')
{{-- サーバ内部エラー --}}

@section('message', 'An error occurred inside the server.')
{{-- サーバー内部でエラーが発生しました。 --}}

@section('detail', 'It will be returned when there is a syntax error in the program, or there is an error in the setting. Please contact the administrator.')
{{-- プログラムに文法エラーがあったり、設定に誤りがあった場合などに返されます。管理者へ連絡してください。 --}}
503.blade.php
@extends('errors.layouts.base')

@section('title', '503 Service Unavailable')
{{-- サービス利用不可 --}}

@section('message', 'You can not access this page due to circumstances.')
{{-- このページへは事情によりアクセスできません。 --}}

@section('detail', 'Service is temporarily unusable due to overload or maintenance.')
{{-- サービスが一時的に過負荷やメンテナンスで使用不可能な状態です。 --}}

エラーを発生させエラーページを表示する

エラーページの作成が完了したので作業的にはこれで終わりですが、実際にエラーを発生させ、実際に独自エラーページが表示されるかを確認します。

具体的な方法としては、ルーティングでエラーを発生させ、エラーページを表示させます。

laravel/routes/web.php
// HTTP ステータスコードを引数に、該当するエラーページを表示させる
Route::get('error/{code}', function ($code) {
    abort($code);
});

上記は、HTTP ステータスコードを引数に、該当するエラーページを表示させるルーティングです。

URL に HTTP ステータスコード({code}の部分)を含め、それを引き数に abort() メソッドでエラーを発生させている。という流れになっています。

こうする事で、例えば
http://YOUR-DOMAIN/error/404
という URL でブラウザからアクセスすれば、404 ページが表示される。というわけです。

エラーページの多言語対応

先ほど作成したエラーページは全て英語での表記でした。これを、英語と日本語の2言語に対応させてみます。

言語ファイルの作成

英語と日本語にて多言語対応させる場合には、それぞれの言語ファイルが必要になるので作成します。

laravel/resources/lang/ 配下の en ディレクトリと ja ディレクトリ内にそれぞれ http_status_code.php という PHP ファイルを作成します。(ja ディレクトリが無い場合は作成してください)

laravel
├─ resources
│   ├─ lang
│   │   ├─ en
│   │   │   ├─ auth.php
│   │   │   ├─ http_status_code.php
│   │   │   ├─ pagination.php
│   │   │   ├─ passwords.php
│   │   │   └─ validation.php
│   │   └─ ja
│   │       ├─ auth.php
│   │       ├─ http_status_code.php
│   │       ├─ pagination.php
│   │       ├─ passwords.php
│   │       └─ validation.php

ベースとなるその他日本語言語ファイルは以下から入手できます。
[Github]Laravel 日本語言語ファイル

ファイルが作成できたら、それぞれを以下のように記述します。

laravel/resources/lang/en/http_status_code.php
<?php

return [
  '400' => [
    'title'   => '400 Bad Request',
    'message' => 'There is an error in the request.',
    'detail'  => 'This response indicates that the server can not understand the request because the syntax is invalid.',
  ],
  '401' => [
    'title'   => '401 Unauthorized',
    'message' => 'certification failed.',
    'detail'  => 'Authentication is required to obtain the requested resource.',
  ],
  '403' => [
    'title'   => '403 Forbidden',
    'message' => 'You do not have access.',
    'detail'  => 'It indicates that the client does not have access to the content and the server is refusing to reply the appropriate response.',
  ],
  '404' => [
    'title'   => '404 Not Found',
    'message' => 'The page of the corresponding address could not be found.',
    'detail'  => 'The server indicates that it could not find the requested resource. A typo in the URL, or the page may have been moved or deleted. Please go back to the top page or search again.',
  ],
  '500' => [
    'title'   => '500 Internal Server Error',
    'message' => 'An error occurred inside the server.',
    'detail'  => 'It will be returned when there is a syntax error in the program, or there is an error in the setting. Please contact the administrator.',
  ],
  '503' => [
    'title'   => '503 Service Unavailable',
    'message' => 'You can not access this page due to circumstances.',
    'detail'  => 'Service is temporarily unusable due to overload or maintenance.',
  ],
];
laravel/resources/lang/ja/http_status_code.php
<?php

return [
  '400' => [
    'title'   => '400 Bad Request',
    'message' => 'リクエストにエラーがあります',
    'detail'  => 'このレスポンスは、構文が無効であるためサーバーがリクエストを理解できないことを示します。',
  ],
  '401' => [
    'title'   => '401 Unauthorized',
    'message' => '認証に失敗しました',
    'detail'  => 'リクエストされたリソースを得るために認証が必要です。',
  ],
  '403' => [
    'title'   => '403 Forbidden',
    'message' => 'あなたにはアクセス権がありません',
    'detail'  => 'クライアントがコンテンツへのアクセス権を持たず、サーバーが適切な応答への返信を拒否していることを示します。',
  ],
  '404' => [
    'title'   => '404 Not Found',
    'message' => '該当アドレスのページを見つける事ができませんでした',
    'detail'  => 'サーバーは要求されたリソースを見つけることができなかったことを示します。 URLのタイプミス、もしくはページが移動または削除された可能性があります。 トップページに戻るか、もう一度検索してください。',
  ],
  '500' => [
    'title'   => '500 Internal Server Error',
    'message' => 'サーバー内部でエラーが発生しました',
    'detail'  => 'プログラムに文法エラーがあったり、設定に誤りがあった場合などに返されます。管理者へ連絡してください。',
  ],
  '503' => [
    'title'   => '503 Service Unavailable',
    'message' => 'このページへは事情によりアクセスできません',
    'detail'  => 'サービスが一時的に過負荷やメンテナンスで使用不可能な状態です。',
  ],
];

これで、エラーページ用の言語ファイルは完成です。

言語設定

続いては、エラーページの言語設定を行います。

基本的に言語の切り替えというのは

  • 設定情報に基づき言語設定を固定する
  • 閲覧者の言語設定などから動的に設定する

の2パターンありますが、今回は前者の固定設定で進めていきます。

また、その際にベースの言語設定を用いても良いのですが、エラーページのみの言語切り替えが行えるように設定していきます。(その理由は後ほど)

それではエラーページ用の言語設定を行っていきます。言語に関する設定ファイルを開いて、以下を追記します。

laravel/config/app.php
// 基本言語設定
'locale' => 'ja',
// エラーページ用の言語設定
'http_status_code_locale' => 'ja',

前者はもともとある言語の設定ですが、その下に新たに「http_status_code_locale 」という項目を追記しています。

上記の設定では、エラーページは「ja 」つまり日本語に設定しました。

多言語対応エラーページの作成

最後に、エラーページを多言語化に対応した形で作成します。
多言語化前の形で作成したエラーページがある場合には、そこを更新する形でも OK です。

400.blade.php
<?php App::setLocale(config('app.http_status_code_locale')); ?>

@extends('errors.layouts.base')

@section('title', __("http_status_code.400.title"))

@section('message', __("http_status_code.400.message"))

@section('detail', __("http_status_code.400.detail"))
401.blade.php
<?php App::setLocale(config('app.http_status_code_locale')); ?>

@extends('errors.layouts.base')

@section('title', __("http_status_code.401.title"))

@section('message', __("http_status_code.401.message"))

@section('detail', __("http_status_code.401.detail"))
403.blade.php
<?php App::setLocale(config('app.http_status_code_locale')); ?>

@extends('errors.layouts.base')

@section('title', __("http_status_code.403.title"))

@section('message', __("http_status_code.403.message"))

@section('detail', __("http_status_code.403.detail"))
404.blade.php
<?php App::setLocale(config('app.http_status_code_locale')); ?>

@extends('errors.layouts.base')

@section('title', __("http_status_code.404.title"))

@section('message', __("http_status_code.404.message"))

@section('detail', __("http_status_code.404.detail"))

@section('link')
  <p><a href="{{env('APP_URL')}}">to TOP&gt;&gt;</a></p>
@endsection
500.blade.php
<?php App::setLocale(config('app.http_status_code_locale')); ?>

@extends('errors.layouts.base')

@section('title', __("http_status_code.500.title"))

@section('message', __("http_status_code.500.message"))

@section('detail', __("http_status_code.500.detail"))
503.blade.php
<?php App::setLocale(config('app.http_status_code_locale')); ?>

@extends('errors.layouts.base')

@section('title', __("http_status_code.503.title"))

@section('message', __("http_status_code.503.message"))

@section('detail', __("http_status_code.503.detail"))

主要部分を解説します。

<?php App::setLocale(config('app.http_status_code_locale')); ?>

ここで、HTTP ステータスコード用の言語設定を読み込み、用いる言語を指定しています。

laravel/config/app.php では、日本語を指定しましたので、日本語での表示を指定したという事になります。

@section('title', __("http_status_code.400.title"))

ここでどの言語ファイルの、どの文面を使うかを指定しています。上記では、「http_status_code 」ファイルの、 $配列['400']['title']を指定しています。

他の message や detail に関しても、この方式で文面を割り当てています。

まとめ

以上で作業は完了となります。確認が終わったら、エラーページ確認用のルーティングは削除しておきましょう。

構築する WEB アプリケーションによってはここまで作りこむ必要もやはり出てくると思いますが、エラーページというのはエラーが起きない限りは現れないものでもあるので、できるだけ最少工数で実現したいですよね。

Laravel では独自エラーページの作成も簡単に行えるので是非試してみてください。

尚、今回のサンプルソースは以下よりダウンロードできます。

Author

rito

  • Backend Engineer
  • Tokyo, Japan
  • PHP 5 技術者認定上級試験 認定者
  • 統計検定 3 級