【超解説】Laravelでお問い合わせフォーム作成!Gmailで連携するには?

この記事からわかること

  • Laravelお問い合わせフォームを作成する方法
  • Gmailを使うには?
  • テスト送信や作成の流れを解説

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

Laravelでお問い合わせフォームを作成する際のロジックや仕組み、注意点、そしてメールアドレスにGmailを使用する場合の方法をLaravelを学習したての初心者向けに詳しくまとめて行きたいと思います。

コピペだけでなく意味を理解してちゃんと使えるようになるのが目標です!

またLaravelのお問い合わせフォームのロジック部分及びコードは以下リンクの記事を参考にさせて頂きました。(心優しい方で引用許可をいただきました。)

参考記事:【Laravel】確認画面付きのお問い合わせフォームを作成する【メール送信対応】

Laravelでお問い合わせフォームを作ろう

まず最初にLaravelプロジェクト内の編集するファイルと新しく作成するファイルを整理しておきます。

編集するファイル

├── Laravelプロジェクト
│ ├── routes
│        └── ●web.php
│        └── ●.env

作成するファイル

├── Laravelプロジェクト
│ ├── app
│ ├── Http
│        └── Controllers
│                └── ★ContactsController.php
│        └── Mail
│                └── ★ContactsSendmail.php
│
│
│ ├── resource
│        └── view
│        └── contact
│                ├── ●index.blade.php
│                ├── ●confirm.blade.php
│                ├── ●mail.blade.php
│                └── ●thanks.blade.php

上記のファイルがお問い合わせフォームを作る上で必要になってきます。★マークがついたものはターミナルからartisan(アルチザン)コマンドを使用して作成します。それ以外はエディタなどから随時ファイルを作成すればOKです。

$ php artisan make:controller ContactsController
$ php artisan make:mail ContactsSendmail

作成するためにやるべきこと

これからやることの流れを確認しておきます。

  1. ルーティング
  2. HTMLフォームの実装
  3. コントローラーでの処理
  4. メール設定とフォーマットの作成
  5. .envファイルへのメール設定の更新
  6. Gmailを扱えるようにする

ルーティング処理

記述するファイル

│ ├── routes
│           └── ●web.php

まずはLaravelの命でもあるルーティング処理を記述します。定義するのは3つ。「入力フォームページ」「確認フォームページ」「送信完了ページ」です。

//入力フォームページ
Route::get('/contact', 'ContactsController@index')->name('contact.index');
//確認フォームページ
Route::post('/contact/confirm', 'ContactsController@confirm')->name('contact.confirm');
//送信完了ページ
Route::post('/contact/thanks', 'ContactsController@send')->name('contact.send');

ルーティングはRouteの後にHTTPメソッド(getやpost)、アクセスされるURL、アクセスされた時の処理(今回はコントローラーのアクションメソッド)、このルーティングの名前を定義することができます。

アクションメソッド(ContactsController@以降の部分)の名前はそれぞれindex、confirm、sendとしておきます。

HTTPメソッドはindexページはget、それ以外はフォームが送信されたページになるのでpostにしておきます。

それぞれのフォーム部分の実装

記述するファイル

│ ├── resource
│       └── view
│       └── contact
│             ├── ●index.blade.php   // 入力フォームページ
│             ├── ●confirm.blade.php // 入力確認ページ
│             ├── ●mail.blade.php    // メール送信時の本文部分
│             └── ●thanks.blade.php  // 送信完了ページ

「resource」>「view」内に「contact」フォルダを作成し、その中に4つのファイルを作成します。「mail.blade.php」以外は@sectionや@import、@extendsなどを使ってレイアウトや描写を作ってもらうとしてロジック部分だけに焦点を当ててみていきます

入力フォームページ(index.blade.php)

お問い合わせフォームに内容を入力してもらうページです。

重要なポイント

@section('content')
<form method="POST" action="{{ route('contact.confirm') }}">
    @csrf

    <label>メールアドレス</label>
    <input
        name="email"
        value="{{ old('email') }}"
        type="text">
    @if ($errors->has('email'))
        <p class="error-message">{{ $errors->first('email') }}</p>
    @endif

    <label>タイトル</label>
    <input
        name="title"
        value="{{ old('title') }}"
        type="text">
    @if ($errors->has('title'))
        <p class="error-message">{{ $errors->first('title') }}</p>
    @endif

    <label>お問い合わせ内容</label>
    <textarea name="body">{{ old('body') }}</textarea>
    @if ($errors->has('body'))
        <p class="error-message">{{ $errors->first('body') }}</p>
    @endif

    <button type="submit">入力内容確認</button>
</form>
@endsection

アクション先にルーティングの名前

<form method="POST" action="{{ route('contact.confirm') }}">

action先にはURLを指定しますが、Laravelではルーティング処理でつけた名前でも指定可能です。ここではルーティング名「contact.confirm」(入力値確認ページ)へ送信します。

@csrfディレクティブ

@csrfディレクティブはLaravelに標準装備されているセキュリティ対策用の構文です。Laravelでフォームを実装する時は基本必須になります。詳しくはこちらの記事をご覧ください。

oldヘルパ関数

value="{{ old('email') }}"

input要素のvalue属性には{{ old('title') }}のようにoldヘルパ関数を使用します。oldヘルパ関数は直前のinput要素に入力された値を表示することができる関数です。引数には表示したいinput要素name属性を指定します。これでバリデーションで弾かれた時や確認ページからこのページに戻った時でも値を保持することができます。

$errors変数

@if ($errors->has('name'))
  <li>{{$errors->first('name')}}</li>
@endif

$errors変数Illuminate\Support\MessageBagのインスタンスで何もしなくてもどこでも使えるように設定されています。バリデーションに弾かれた際にエラーを感知し$errors変数の中に自動でエラーメッセージが格納されます。

テンプレート側で表示する際は、hasメソッド中身の有無を確認し、firstメソッド1番目に格納されているエラーメッセージを取り出すのが基本です。firstメソッドではなくgetメソッドにすると指定項目の全メッセージを、引数なしのallメソッドにすると全項目の全エラーメッセージカードを取得できます。

oldヘルパ関数と$errors変数はフォーム実装にあたってよく使う手法なので覚えておくと便利です。

入力確認ページ(confirm.blade.php)

入力された値で送信して良いかをユーザーに表示するページです。POSTされた値を受け取り表示させています。

重要なポイント

@section('content')
<form method="POST" action="{{ route('contact.send') }}">
  @csrf

  <label>メールアドレス</label>
  {{ $inputs['email'] }}
  <input name="email" value="{{ $inputs['email'] }}" type="hidden">

  <label>タイトル</label>
  {{ $inputs['title'] }}
  <input name="title" value="{{ $inputs['title'] }}" type="hidden">


  <label>お問い合わせ内容</label>
  {!! nl2br(e($inputs['body'])) !!}
  <input name="body" value="{{ $inputs['body'] }}" type="hidden">

  <button type="submit" name="action" value="back">入力内容修正</button>
  <button type="submit" name="action" value="submit">送信する</button>
</form>
@endsection

コントローラ側から変数を受け取る

{{ $inputs['email'] }}

ここで定義されている$inputs変数コントローラ側から受け取る予定の変数です。(変数名はなんでも可)後ほどコントローラ側で$inputsの中にPOSTされた入力値を入れ込むことでindexページで入力された値を表示させています。

その下にtype=hidden(非表示)にさせたinput要素を作成します。valueには同じく$inputsに格納されている入力値を渡します。問題がなければこのフォーム(indexではなくconfirm)の値を送信するためです。

改行を制御するnl2br関数とe関数と!!構文

{!! nl2br(e($inputs['body'])) !!}

入力値の本文部分を扱うためには改行コード(\n)を意識しないといけません。POST送信された値では改行部分は\nで表されているので改行コードを変換してくれるnl2br関数を使ってHTMLでの改行(<br>)に変換します。

しかしLaravelではHTML特殊文字を自動エスケープ(内部的にhtmlspecialchars関数が実行)されてしまうので<>部分がうまく表示されません。これを防ぐには自動エスケープを施さない{!! !!}文を使います。

さらにこのままでは入力値に悪意あるコードを埋め込まれるリスクがあるので入力値のみに対してエスケープ処理を行います。Laravelでは長く冗長なhtmlspecialchars関数を簡単に扱えるようにe関数が用意されているのでこちらを使ってエスケープしておきます。

戻るボタンと送信ボタン

<button type="submit" name="action" value="back">入力内容修正</button>
<button type="submit" name="action" value="submit">送信する</button>

続いて確認ページから、修正のために入力ページへ戻るボタンお問い合わせを送る送信ボタンを設置します。ページの分岐はコントローラ側に託し、フォーム側では分岐できるようにPOST送信の値を別にしておきます(back/submit)。これでname=actioninput要素にはボタンが押された方の値が入るのでコントローラ側でチェックし分岐させることができるようになります。

メール送信時の本文部分(mail.blade.php)

問い合わせをしてくれたユーザーに対して受付完了したことを通知するメールの本文部分です。

お問い合わせ内容を受け付けました。<br>
<br>
■メールアドレス<br>
{!! $email !!}<br>
<br>
■タイトル<br>
{!! $title !!}<br>
<br>
■お問い合わせ内容<br>
{!! nl2br($body) !!}<br>

ここに記述した内容のメールがユーザーと自分が設定したメールアドレスに届くようにします。mail.blade.phpファイル内に記述するのは上記のみでOKです。HTMLで出力されるので改行は<br>で実装します。

コントローラ側から変数の値は渡すのでひとまずフォーマットを作成して次に進みます。

送信完了ページ(thanks.blade.php)

送信完了したことをWebページで表示します。

@section('content')

{{ __('送信完了') }}

@endsection

ここまでで作り上げたのは処理のフレーム部分だけです。実際のデータの受け渡しや操作はコントローラ側で行います。

コントローラ側の処理

コントローラ処理を記述するために新しくコントローラを作成します。まだ作っていなければartisanコマンドで生成しておきます。

php artisan make:controller ContactsController

コントローラ側で実装することは以下の5つです。

  1. ルーティング時のview設定
  2. POSTされたデータのバリデーション
  3. POSTされたデータのページ間受け渡し
  4. 修正ボタンと送信ボタンの実装
  5. 実際にメールを送る処理

ルーティング時に指定したアクションメソッド(index、confirm、send)をコントローラ内に記述していきます。

indexメソッド

まずは最初のお問い合わせ入力画面を表示できるようにindexメソッドを登録します。ここは単純にアクセスされたらページを表示するだけですので「contactフォルダ」の中のindex.blade.phpがreturnする様にしておきます

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ContactsController extends Controller
{
    public function index()
    {
        // 入力ページを表示
        return view('contact.index');
    }
}

confirmメソッド

indexページ→確認ページに変異する際のアクションメソッドを定義します。

重要なポイント

public function confirm(Request $request)
{
    // バリデーションルールを定義
    // 引っかかるとエラーを起こしてくれる
    $request->validate([
    'email' => 'required|email',
    'title' => 'required',
    'body' => 'required',
    ]);

    // フォームからの入力値を全て取得
    $inputs = $request->all();

    // 確認ページに表示
    // 入力値を引数に渡す
    return view('contact.confirm', [
    'inputs' => $inputs,
    ]);
}

入力値のバリデーション

$request->validate([
  'email' => 'required|email',
  'title' => 'required',
  'body' => 'required',
]);

バリデーションとは「値が適切なものであるかチェックすること」です。LaravelではValidation機能も常設されています。使用するにはアクションメソッドの引数にrequestオブジェクトを受け取ります。

// コントローラの上部に以下の文があることを確認
use Illuminate\Http\Request;
// アクションメソッドの引数にリクエストオブジェクトを渡す
public function confirm(Request $request) {
}

requestオブジェクトはHTTPリクエスト情報(POSTされた入力値やURL、リクエストヘッダ情報など)を取得できる機能です。その中にValidationメソッドが用意されており、その引数にバリデーションしたい入力値の項目名(name属性)とバリデーションルール(requiredemailmax:255など)を指定することができます。

バリデーションルールに違反する入力値が与えられた場合Validationメソッドはエラーレスポンスを返し、直前のURL(ここでいうindexページ)へ自動でリダイレクトしてくれます。

その際にエラー内容が$errors変数に格納されるのでindexページで作成した以下の部分でエラーを表示できるようになります。

@if ($errors->has('name'))
  <li>{{$errors->first('name')}}</li>
@endif

各エラーメッセージのカスタマイズはresources/lang/en/validation.phpの中を変更すればOKです。

入力値を変数に入れて確認ページに渡す

バリデーションを通ったら次は入力値を変数に格納し、確認ページへ渡します。indexからPOST送信された値はrequestオブジェクトallメソッド項目名(name属性)がキー値、入力値が値の連想配列形式で取得できます。

 // 連想配列形式で取得
$inputs = $request->all();

あとは一度変数に格納し、確認ページをviewする際に引数として渡せばOKです。渡す際のキー値をinputsとしているので確認ページ内では$inputs['項目名'] でアクセスできます。

最後のsendメソッドを記述する前に実際にメールを送信する機能を実装するため前準備をしておきます。

メール送信機能:Mailableクラス

Laravelではメール送信機能も簡単に実装できるMailableクラスが用意されています。使用方法は簡単でまずはプロジェクト内で以下のartisanコマンドを叩きます。

$ php artisan make:mail ContactsSendmail

これでapp/Mail/ContactsSendmail.php が作成されます。

├── Laravelプロジェクト
│ ├── app
│ ├── Http
│ └── Mail
│       └── ★ContactsSendmail.php

作成された中身を以下のように変更します。

class ContactsSendmail extends Mailable
{
use Queueable, SerializesModels;

// プロパティを定義
private $email;
private $title;
private $body;

  /**
  * Create a new message instance.
  *
  * @return void
  */
  public function __construct( $inputs )
  {
    // コンストラクタでプロパティに値を格納
    $this->email = $inputs['email'];
    $this->title = $inputs['title'];
    $this->body = $inputs['body'];
  }

  /**
  * Build the message.
  *
  * @return $this
  */
  public function build()
  {
    // メールの設定
    return $this
            ->from('example@gmail.com')
            ->subject('自動送信メール')
            ->view('contact.mail')
            ->with([
            'email' => $this->email,
            'title' => $this->title,
            'body' => $this->body,
            ]);
  }

重要なポイント

クラス内にプロパティを定義

まずは作成したMailableクラスの中にプロパティを定義します。メール作成に必要な以下の3つをprivateで定義します。

private $email;
private $title;
private $body;

コンストラクタでプロパティに値を格納

  public function __construct( $inputs )
  {
    // コンストラクタでプロパティに値を格納
    $this->email = $inputs['email'];
    $this->title = $inputs['title'];
    $this->body = $inputs['body'];
  }

続いてクラス内のコンストラクタ(インスタンス時に実行されるメソッド)で変数$inputsの中の値を各プロパティにセットします。変数$inputsはインスタンス時の引数として渡す(コントローラ側から)のでここでは受取る前提で記述しておきます。

buildメソッド内でメール設定と作成

public function build()
  {
    // メールの設定
    return $this
            ->from('example@gmail.com')
            ->subject('自動送信メール')
            ->view('contact.mail')
            ->with([
            'email' => $this->email,
            'title' => $this->title,
            'body' => $this->body,
            ]);
  }

Mailableクラスの中に元から定義されているbuildメソッドメール送信設定を司っている部分です。buildメソッドの中で重要になってくるのがfromメソッドviewメソッドです。

fromメソッドは引数にメールの差出人部分のメールアドレスを設定するメソッドです。自分のメールアドレスをここに設定します。viewメソッドはメールの本文部分を設定するメソッドです。引数には表示させたいbladeファイルを指定することでそのファイルの内容のメールを作成することができます。

subjectメソッドメールタイトルを設定するメソッドです。これでMailableクラスの準備は整いました。次はコントローラ側(sendメソッド)を実装していきます。

メールを送信する処理

コントローラのsendメソッドに実装したいのは以下のポイントです。

重要なポイント

// 上部に追加
use App\Mail\ContactsSendmail;

public function send(Request $request)
{
    // バリデーション
    $request->validate([
    'email' => 'required|email',
    'title' => 'required',
    'body' => 'required'
  ]);

    // actionの値を取得
    $action = $request->input('action');

    // action以外のinputの値を取得
    $inputs = $request->except('action');

    //actionの値で分岐
    if($action !== 'submit'){

        // 戻るボタンの場合リダイレクト処理
        return redirect()
        ->route('contact.index')
        ->withInput($inputs);
        
    } else {
        // 送信ボタンの場合、送信処理

        // ユーザにメールを送信
        \Mail::to($inputs['email'])->send(new ContactsSendmail($inputs));
        // 自分にメールを送信
        \Mail::to('自分のメールアドレス')->send(new ContactsSendmail($inputs));

        // 二重送信対策のためトークンを再発行
        $request->session()->regenerateToken();

        // 送信完了ページのviewを表示
        return view('contact.thanks');

    }
}

入力値のバリデーション

まずはconfirmの時と同様にバリデーションしておきます。

戻るボタンと送信ボタンの分岐

// actionの値を取得
$action = $request->input('action');

続いて「戻るボタン」か「送信ボタン」どちらが押されたかを識別するためのactionに格納されている値を取り出しておきます。メール作成用の変数として$inputsも定義しておき、exceptメソッドを使ってactionだけ除外した入力値を格納します。

// action以外のinputの値を取得
$inputs = $request->except('action');

実際にメールを送信する

あとは$actionに格納された値によって処理分岐します。backであればviewにindexページを渡し画面をリダイレクトさせます。

submit(送信)であればメールの送信処理、トークンのリセット、送信完了ページへの表示を行います。

メール送信機能をコントローラ内で使えるようにContactscontrollerの上部に以下の文を追記します。

use App\Mail\ContactsSendmail;
// ユーザにメールを送信
\Mail::to($inputs['email'])->send(new ContactsSendmail($inputs));
// 自分にメールを送信
\Mail::to('自分のメールアドレス')->send(new ContactsSendmail($inputs));

実際の送信処理はMailファザードsendメソッドで行います。まずMailファザードのtoメソッドの引数に送信先のメールアドレス(入力されたメールアドレス)を指定します。さらにsendメソッドを繋げてその引数にuse文で読み込んだMailableクラスのインスタンス化したものを渡します。Mailableクラスの引数には$inputs(フォーム入力データの連想配列)を渡しておきます。

これでユーザー様へのお問い合わせ完了メールが送信できたので自分にもお問い合わせ内容メールを送るために->bcc(メールアドレス)メソッド、もしくは上記のように再度をメール送信処理を記述すればOKです。

二重送信対策

フォーム送信する場合上記が行われた時に同じPOST送信が複数回、送られてしまうことがあります。なので二重送信対策を施しておきます。

LaravelではCSRF対策としてワンタイムトークンを使用しています。簡単に言うと重複しないパスワードをPOST送信の際に乗せて送信側と受取側で照らし合わせマッチした場合のみ受け入れる方法です。先ほどの@csrfディレクティブがまさしくそうです。

この仕組みを利用して二重送信対策を行います。具体的にはPOST送信を一度受け入れたら、パスワードを採番しなおすことで同じPOSTデータ(古くなったパスワードを持ったPOST送信)を受け入れないようにする方法です。受け入れ側のパスワードはsessionの中に保持されていますのでパスワードを採番し直すには$requestオブジェクト内のsessionに対してregenerateTokenメソッドを実行するだけです。

$request->session()->regenerateToken();

これで送信処理と二重送信対策を終えたので最後に送信完了ページを表示させればOKです。

return view('contact.thanks');

.envファイルの変更

ここまででお問い合わせ機能のロジック部分が完成しました。最後にLaravelプロジェクト本体のメール設定を変更して終了です。メールの設定は隠しファイルである「Laravelプロジェクト」>「.env」の中に記述します。Macであれば「Shift + command + . 」の同時押しで表示/非表示を切り替えることができます。以下はGmailの場合の設定です。

MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=自分のメールアドレス
MAIL_PASSWORD=アプリパスワード
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=自分のアドレス
MAIL_FROM_NAME="${APP_NAME}"

GmailをLaravelなどの外部のアプリで扱う場合はGmail側でも設定をしないといけません。Googleアカウントに管理者権限が付与されていれば「安全性の低いアプリを許可する」の設定をONにすればOKですが管理者権限がない場合はアプリパスワードを発行して使うのがオススメです。

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index