113 lines
5.0 KiB
PHP
113 lines
5.0 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Auth;
|
||
|
||
use App\Http\Controllers\Controller;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Str;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Mail;
|
||
use Illuminate\Support\Facades\Log;
|
||
use Carbon\Carbon;
|
||
|
||
class ForgotPasswordController extends Controller
|
||
{
|
||
// パスワードリセット申請画面表示
|
||
public function showLinkRequestForm()
|
||
{
|
||
return view('auth.forgot-password');
|
||
}
|
||
|
||
// リセットメール送信
|
||
public function sendResetLinkEmail(Request $request)
|
||
{
|
||
$request->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', 'パスワード再設定メールを送信しました。');
|
||
}
|
||
}
|