【市場価値がわかる】エンジニア転職におすすめなサイト

Laravelでパスワードとパスワード確認用が一致するかバリデーション

MENTAでエラー解決

パスワードが一致するかバリデーションするにはどうすればいいんだろう….

こんな疑問を解決します。

本記事のゴールは以下のように登録画面でパスワードとパスワード確認用が一致するかのバリデーションを実装。

また、編集画面で現在のパスワード(DBでハッシュ化されたパスワードの値)と入力したパスワードが一致するかも解説していきます。

本記事で動作確認した環境は、PHP7.4,Laravel8系です。bootstrapを導入しているので、フォームはbootstrapを参考にしてます。

Contents

登録画面でパスワードとパスワード確認用が一致するか

パスワードとパスワード確認用が一致するかは、結論sameを使えば実装できます。

登録画面

@extends('layouts.app')

@section('content')
<div class="container small">
  <h1>ユーザーの登録画面</h1>
  <form action="{{ route('user.store') }}" method="POST">
  @csrf
    <fieldset>
      <div class="form-group">
        <label for="user_name">{{ __('ユーザー名') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="text" class="form-control {{ $errors->has('user_name') ? 'is-invalid' : '' }}" name="user_name" id="user_name">
        @if ($errors->has('user_name'))
          <span class="invalid-feedback" role="alert">
            {{ $errors->first('user_name') }}
          </span>
        @endif
      </div>
      <div class="form-group">
        <label for="email">{{ __('Eメール') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="email" class="form-control {{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" id="email" value="{{ old('email') }}">
        @if ($errors->has('email'))
          <span class="invalid-feedback" role="alert">
            {{ $errors->first('email') }}
          </span>
        @endif
      </div>
      <div class="form-group">
        <label for="user_password">{{ __('パスワード') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="password" class="form-control {{ $errors->has('user_password') ? ' is-invalid' : '' }}" name="user_password" id="user_password" value="{{ old('user_password') }}">
        @if ($errors->has('user_password'))
          <span class="invalid-feedback" role="alert">
            {{ $errors->first('user_password') }}
          </span>
        @endif
      </div>
      <div class="form-group">
        <label for="confirm_password">{{ __('パスワード確認用') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="password" class="form-control {{ $errors->has('confirm_password') ? ' is-invalid' : '' }}" name="confirm_password" id="confirm_password" value="{{ old('confirm_password') }}">
        @if ($errors->has('confirm_password'))
          <span class="invalid-feedback" role="alert">
            {{ $errors->first('confirm_password') }}
          </span>
        @endif
      </div>
        <button type="submit" class="btn btn-success">
            {{ __('登録') }}
        </button>
      </div>
    </fieldset>
  </form>
</div>
@endsection

以下のような画面が作成できます。

フォームリクエストのバリーデーションはこんな感じ。

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            // ユーザー名
            'user_name' => 'required', // 必須
            // メールアドレス
            'email'     => 'required', // 必須
            // パスワード
            'user_password'  => [
                'required', // 必須
                'min:8', // 最低8文字以上
                'max:16', // 最高16文字まで
                'regex:/^(?=.*?[a-zA-Z])(?=.*?\d)[a-zA-Z\d]/' // 正規表現を使って、半角英数字混在
            ],
            // パスワード確認用
            'confirm_password' => [
                'required', // 必須
                'same:user_password', // user_passwordと値が同じか
            ],
        ];
    }

    public function messages()
    {
        return [
          'user_name.required' => 'ユーザー名は必須です。',
          'email.required'     => 'メールアドレスは必須です。',
          'user_password.required'    => 'パスワードは必須です。',
          'user_password.min'         => 'パスワードは :min桁以上で入力してください。',
          'user_password.max'         => 'パスワードは :max桁以下で入力してください。',
          'user_password.regex'       => 'パスワードは半角英数字混在で入力してください。',
          'confirm_password.required' => 'パスワード確認用は必須です。',
          'confirm_password.same'     => 'パスワードとパスワード確認用が一致しません。',
        ];
    }
}

注目すべきはsame:passwordの部分。

same:〇〇と書けば、〇〇と同じ値であるかバリデーションします。

これで目的のバリデーションである、パスワードとパスワード確認用の値が一致するか検証できます。

ついでに、編集画面で現在のパスワードと入力したパスワードが一致するかも解説します。

現在のパスワードと入力したパスワードが一致するか

ここからは、編集画面で現在のパスワードと入力したパスワードが一致するか解説していきます。

まずは、画面レイアウト

@extends('layouts.app')

@section('content')
<div class="container small">
  <h1>ユーザー編集</h1>
  <form action="{{ route('user.update') }}" method="POST">
  @csrf
  <input type="hidden" name="user_id" value="{{ $user->user_id }}">
    <fieldset>
      <div class="form-group">
        <label for="user_name">{{ __('ユーザー名') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="text" class="form-control" name="user_name" id="user_name" value="{{ old('email', $user->user_name) }}">
      </div>
      @if ($errors->has('user_name'))
        <span class="invalid-feedback" role="alert">
          {{ $errors->first('user_name') }}
        </span>
      @endif
      <div class="form-group">
        <label for="email">{{ __('メールアドレス') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="text" class="form-control {{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" id="email" value="{{ old('email', $user->email) }}">
        @if ($errors->has('email'))
          <span class="invalid-feedback" role="alert">
            {{ $errors->first('email') }}
          </span>
        @endif
      </div>
      <div class="form-group">
        <label for="current_password">{{ __('現在のパスワード') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="password" class="form-control {{ $errors->has('current_password') ? ' is-invalid' : '' }}" name="current_password" id="current_password">
        @if ($errors->has('current_password'))
          <span class="invalid-feedback" role="alert">
            {{ $errors->first('current_password') }}
          </span>
        @endif
      </div>
      <div class="form-group">
        <label for="user_password">{{ __('新しいパスワード') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="password" class="form-control {{ $errors->has('user_password') ? ' is-invalid' : '' }}" name="user_password" id="user_password">
        @if ($errors->has('user_password'))
          <span class="invalid-feedback" role="alert">
            {{ $errors->first('user_password') }}
          </span>
        @endif
      </div>
      <div class="form-group">
        <label for="confirm_password">{{ __('新しいパスワード確認用') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
        <input type="password" class="form-control {{ $errors->has('confirm_password') ? ' is-invalid' : '' }}" name="confirm_password" id="confirm_password">
        @if ($errors->has('confirm_password'))
          <span class="invalid-feedback" role="alert">
            {{ $errors->first('confirm_password') }}
          </span>
        @endif
      </div>
      <div class="d-flex justify-content-between pt-3">
        <button type="submit" class="btn btn-success">
            {{ __('更新') }}
        </button>
      </div>
    </fieldset>
  </form>
</div>
@endsection

以下のような画面になります。

  • 現在のパスワードにパスワードを入力して、一致しなかったらエラーメッセージ
  • 新しいパスワードと新しいパスワード確認用には、登録画面で実装したバリデーションを使う

このような仕様になります。

上記を考慮したパスワードのバリデーションは以下のようになります。

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request; // 追加
use Illuminate\Support\Facades\Hash; // 追加
use App\Models\User; //追加

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules(Request $request)
    {
        if (isset($request->user_id)) {
            // 編集画面のバリデーション(編集画面ではinputのtype="hidden"でuser_idの値が送られてくるので値があるかで登録画面か編集画面か判別できる)

            // 現在のパスワードフォームに入力したパスワード
            $pass = $request->current_password;

            // user_idをもとに、usersテーブルから一意にレコードを絞り込む
            $user = User::find($request->user_id);
            // 現在のパスワードを取得
            $currentPass = $user->password;
            
            return [
                // ユーザー名
                'user_name' => 'required', // 必須
                // メールアドレス
                'email'     => 'required', // 必須
                // 現在のパスワード
                'current_password' => [ // 無名関数を使ってできる。
                    function ($attribute, $value, $fail) use ($pass, $currentPass) { // use(変数)でfunctionn内で使用する変数を宣言する。
                        if (!Hash::check($pass, $currentPass)) {
                            // $passはフォームに入力した値で、$currentPassはusersのDBにあるハッシュ化されたパスワードで、
                            // Hash::check('入力パスワード', 'ハッシュ化されたパスワード')で比較できる。
                            return $fail('現在のパスワードと入力したパスワードが一致しません。');
                        }
                    }
                ],
                // 新しいパスワード
                'user_password'  => [
                    'required', // 必須
                    'min:8', // 最低8文字以上
                    'max:16', // 最高16文字まで
                    'regex:/^(?=.*?[a-zA-Z])(?=.*?\d)[a-zA-Z\d]/' // 正規表現を使って、半角英数字混在
                ],
                // 新しいパスワード確認用
                'confirm_password' => [
                    'required', // 必須
                    'same:user_password', // user_passwordと値が同じか
                ],
            ];
        } else {
            // 登録画面のバリデーション
            return [
                // ユーザー名
                'user_name' => 'required', // 必須
                // メールアドレス
                'email'     => 'required', // 必須
                // パスワード
                'user_password'  => [
                    'required', // 必須
                    'min:8', // 最低8文字以上
                    'max:16', // 最高16文字まで
                    'regex:/^(?=.*?[a-zA-Z])(?=.*?\d)[a-zA-Z\d]/' // 正規表現を使って、半角英数字混在
                ],
                // パスワード確認用
                'confirm_password' => [
                    'required', // 必須
                    'same:user_password', // user_passwordと値が同じか
                ],
            ];
        }
    }

    public function messages()
    {
        return [
          'user_name.required' => 'ユーザー名は必須です。',
          'email.required'     => 'メールアドレスは必須です。',
          'user_password.required'    => 'パスワードは必須です。',
          'user_password.min'         => 'パスワードは :min桁以上で入力してください。',
          'user_password.max'         => 'パスワードは :max桁以下で入力してください。',
          'user_password.regex'       => 'パスワードは半角英数字混在で入力してください。',
          'confirm_password.required' => 'パスワード確認用は必須です。',
          'confirm_password.same'     => 'パスワードとパスワード確認用が一致しません。',
        ];
    }
}

コメントアウトでほぼ解説していますが、注意点として冒頭にRequest,Hash,Userの追加を忘れないようにしましょう。

また、編集画面と登録画面でバリデーションが異なるので、そこも注意です。

現役エンジニアに相談するならMENTA(おすすめ)

スキルを売り買いするならココナラ

動画教材ならUdemy

コメント

コメントする

CAPTCHA


Contents
閉じる