PHPMailer HTML邮件添加跳转按钮及token验证失败问题求助
问题分析与修复方案
核心问题:邮件模板变量未正确解析
你用单引号定义了$email_template,PHP不会解析单引号字符串内的变量,导致邮件链接里的$verify_token始终是字面量,而非实际生成的验证token值,所以跳转后verify.php找不到对应token,触发“token不存在”提示。
修复步骤
1. 修正邮件模板的变量解析逻辑
将模板定义的单引号改为双引号,确保PHP能正确替换变量;同时修复样式和HTML结构的小问题:
$email_template = " <html> <head> <link href='https://fonts.googleapis.com/css2?family=Montserrat:wght@200;300;500;700;800&family=Source+Sans+Pro:wght@700&display=swap' rel='stylesheet' /> <style> body { width: 100%; min-height: 100vh; align-items: center; display: block; justify-content: center; user-select: none; position: absolute; top: 80px; } table { border-spacing: 0; } td { padding: 0; background-color: rgba(247, 189, 22, 0.8); width: 655px; height: 300px; border-radius: 10px; margin-top: 7%; align-items: center; } .webkit { max-width: 600px; background-color: #ffffff; } .main { font-family: 'Montserrat', sans-serif; } .main p { text-align: center; margin-left: 20px; margin-right: 20px; font-weight: 700; font-size: 14px; } .main h1 { font-size: 25px; text-align: center; } .reset-btn { background-color: rgba(45, 45, 45, 0.9); font-size: 14.5px; color: #fff; font-family: 'Montserrat', sans-serif; font-weight: 400; width: 100px; padding: 8px 60px; margin: 0 auto; cursor: pointer; justify-content: center; align-items: center; border: none; border-radius: 50px; } .reset-btn:hover { background: rgba(79, 79, 79, 0.9); } .reset-btn a { color: white; text-decoration: none; } </style> </head> <body> <center class='wrapper'> <div class='webkit'> <table class='main'> <tr> <td> <h1>Hi $name!</h1> <p> 你最近在OFAD-APPSYS注册,使用的邮箱是:$email。 </p> <p>点击下方按钮完成账号验证:</p> <div class='reset-btn' style='text-align: center'> <a href='http://localhost/appsys/website/verify.php?token=$verify_token'>验证邮箱</a> </div> <p> 若你未注册OFAD-APPSYS,请忽略此邮件。 </p> </td> </tr> </table> </div> </center> </body> </html> ";
修正说明:
- 把单引号改为双引号,让
$name、$email、$verify_token变量被正确解析 - 移除重复的
</html>标签 - 修复按钮样式,将无效的
font-color改为color,并给a标签单独设置样式确保显示正常
2. 修复verify.php的SQL注入风险与稳定性
原代码直接拼接用户输入到SQL语句,存在注入风险,同时可能因token含特殊字符导致查询失败,改用预处理语句:
<?php session_start(); include('db.php'); if(isset($_GET['token'])) { $token = $_GET['token']; // 预处理查询,防止SQL注入 $verify_query = "SELECT verify_token, verify_status FROM register WHERE verify_token=? LIMIT 1"; $stmt = mysqli_prepare($conn, $verify_query); mysqli_stmt_bind_param($stmt, "s", $token); mysqli_stmt_execute($stmt); $verify_query_run = mysqli_stmt_get_result($stmt); if (mysqli_num_rows($verify_query_run) > 0) { $row = mysqli_fetch_array($verify_query_run); if($row['verify_status'] == "0") { $clicked_token = $row['verify_token']; // 预处理更新语句 $update_query = "UPDATE register SET verify_status='1' WHERE verify_token = ? LIMIT 1"; $update_stmt = mysqli_prepare($conn, $update_query); mysqli_stmt_bind_param($update_stmt, "s", $clicked_token); $update_query_run = mysqli_stmt_execute($update_stmt); if($update_query_run) { $_SESSION['status'] = "账号验证成功!"; header("Location: verify-success.php"); exit(0); } else { $_SESSION['status'] = "验证失败,请重试"; header("Location: login.php"); exit(0); } } else { $_SESSION['status'] = "该邮箱已完成验证,请直接登录"; header("Location: login.php"); exit(0); } } else { $_SESSION['status'] = "无效的验证token"; header("Location: login.php"); } } else { $_SESSION['status'] = "非法访问"; header("Location: login.php"); } ?>
3. 额外验证步骤
- 发送邮件前,先
echo $email_template;查看链接是否包含真实的token值,确认变量替换生效 - 检查用户注册时,
verify_token是否已正确存入register表的对应字段
内容的提问来源于stack exchange,提问作者mistyyy
相关产品推荐
相关产品推荐

