validate([ 'email' => 'required|email', 'email_confirmation' => 'required|email|same:email', ], [ 'email.required' => 'メールアドレスを入力してください。', 'email.email' => '正しいメールアドレス形式で入力してください。', 'email_confirmation.required' => '確認用メールアドレスを入力してください。', 'email_confirmation.email' => '正しいメールアドレス形式で入力してください。', 'email_confirmation.same' => 'メールアドレスが一致しません。', ]); // ope_mailでユーザーを検索 $user = \App\Models\Ope::where('ope_mail', $request->input('email'))->first(); if (!$user) { return back()->withErrors(['email' => '該当するユーザーが見つかりません。']); } // 5分間隔のメール送信制限チェック(最新のトークンを対象) $lastToken = DB::table('password_reset_tokens') ->where('ope_mail', $user->ope_mail) ->orderByDesc('created_at') ->first(); if ($lastToken) { // タイムゾーンを明示的に指定(デフォルトはUTCで解析される可能性がある) $lastCreatedAt = Carbon::parse($lastToken->created_at, config('app.timezone')); $now = now(); // 経過秒数で判定 $diffSeconds = $lastCreatedAt->diffInSeconds(now(), false); $limitSeconds = 5 * 60; // 5分 if ($diffSeconds < $limitSeconds) { $remainSeconds = $limitSeconds - $diffSeconds; // 残り秒を「分」に変換:端数は切り上げ(例:1秒残りでも1分と表示) $waitMinutes = (int) ceil($remainSeconds / 60); return back()->withErrors([ 'email' => "パスワード再設定メールは5分以上の間隔を置いて送信してください。{$waitMinutes}分後に再度お試しください。" ]); } } // トークン生成 $token = Str::random(60); // SHA256ハッシュで保存(セキュリティ向上) $tokenHash = hash('sha256', $token); // トークン保存(既存レコードがあれば更新) DB::table('password_reset_tokens')->updateOrInsert( ['ope_mail' => $user->ope_mail], [ 'token' => $tokenHash, 'created_at' => now(), ] ); // メール送信 try { $resetUrl = url('/reset-password?token=' . $token . '&email=' . urlencode($user->ope_mail)); $body = $user->ope_name . " 様\n\n" . "So-Managerをご利用いただき、ありがとうございます。\n\n" . "本メールは、パスワード再設定のご依頼を受けてお送りしております。\n\n" . "以下のURLをクリックし、新しいパスワードを設定してください。\n\n" . $resetUrl . "\n\n" . "※このURLの有効期限は、24時間です。\n" . "※有効期限を過ぎた場合は、再度パスワード再設定手続きを行ってください。\n" . "※本メールにお心当たりがない場合は、本メールを破棄してください。\n\n" . "_________________________________\n" . "So-Manager サポートセンター\n" . "E-mail : support@so-manager.com\n" . "URL : https://www.so-manager.com/\n" . "_________________________________"; Mail::raw($body, function ($message) use ($user) { $message->to($user->ope_mail) ->from(config('mail.from.address'), config('mail.from.name')) ->subject('【【So-Manager】パスワード再設定のご案内】'); }); } catch (\Throwable $e) { Log::error('ForgotPassword mail send failed', [ 'to' => $user->ope_mail, 'error' => $e->getMessage(), ]); return back()->withErrors(['email' => 'メール送信に失敗しました。サーバログを確認してください。']); } return back()->with('status', 'パスワード再設定メールを送信しました。'); } }