Files
SunShineMusic/forgot_password.php

432 lines
17 KiB
PHP
Raw Normal View History

2025-09-24 14:15:03 +00:00
<?php
// 强制显示所有错误(仅用于调试)
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// 记录错误到日志文件
ini_set('log_errors', 1);
ini_set('error_log', 'error_log.txt');
try {
// 启动会话
session_start();
// 检查用户是否已登录,如果已登录则重定向到首页
if (isset($_SESSION['user_logged_in']) && $_SESSION['user_logged_in'] === true) {
header('Location: index.php');
exit;
}
// --- 配置区 ---
// 数据库连接配置
$servername = "localhost";
$dbusername = "a1sax1m9i";
$dbpassword = "a1sax1m9i";
$dbname = "a1sax1m9i";
// QQ邮箱配置 - 请修改为你的信息
$smtpHost = 'smtp.qq.com'; // QQ邮箱SMTP服务器
$smtpPort = 465; // QQ邮箱SMTP端口(SSL)
$smtpUsername = 'luoriguodu@qq.com'; // 你的QQ邮箱地址
$smtpPassword = 'awjoclnnhqpybiie'; // QQ邮箱授权码(不是登录密码)
$fromName = "音乐分享网站"; // 发件人名称
// 初始化消息变量
$message = "";
$messageType = ""; // success 或 error
// 确保密码重置表存在
function ensurePasswordResetTableExists($conn) {
$sql = "CREATE TABLE IF NOT EXISTS password_reset_tokens (
user_id INT NOT NULL,
token VARCHAR(255) NOT NULL,
expiry DATETIME NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
if (!$conn->query($sql)) {
return "创建密码重置表失败: " . $conn->error;
}
return true;
}
// 生成随机令牌
function generateToken() {
return bin2hex(random_bytes(32));
}
// 使用QQ SMTP发送密码重置邮件
function sendResetEmailViaQQSMTP($toEmail, $resetLink, $smtpHost, $smtpPort, $smtpUsername, $smtpPassword, $fromName) {
// 邮件主题
$subject = "=?UTF-8?B?" . base64_encode("密码重置请求 - 音乐分享网站") . "?=";
// 邮件内容
$message = '
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>密码重置请求 - 音乐分享网站</title>
<!-- 基础样式重置,适配不同邮箱客户端 -->
<style type="text/css">
/* 清除默认边距和内边距 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", "Arial", sans-serif;
}
/* 响应式图片 */
img {
max-width: 100%;
height: auto;
border: none;
}
/* 链接样式统一 */
a {
text-decoration: none;
transition: all 0.3s ease;
}
/* 按钮基础样式 */
.btn {
display: inline-block;
padding: 12px 24px;
background-color: #2c3e50;
color: #ffffff !important;
font-size: 16px;
font-weight: 500;
border-radius: 6px;
text-align: center;
min-width: 180px;
}
.btn:hover {
background-color: #34495e;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
/* 内容容器样式 */
.email-container {
max-width: 600px;
margin: 0 auto;
padding: 20px 15px;
background-color: #f9fafb;
}
/* 邮件头部样式 */
.email-header {
padding: 15px 0;
margin-bottom: 25px;
border-bottom: 1px solid #eee;
}
.header-logo {
display: flex;
align-items: center;
gap: 10px;
color: #2c3e50;
}
.logo-icon {
font-size: 28px;
color: #2c3e50;
}
.logo-text {
font-size: 20px;
font-weight: 600;
}
/* 邮件主体样式 */
.email-body {
padding: 30px;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
}
.body-title {
font-size: 22px;
color: #2c3e50;
margin-bottom: 18px;
font-weight: 600;
}
.body-desc {
font-size: 15px;
color: #666666;
line-height: 1.6;
margin-bottom: 25px;
}
.body-desc p {
margin-bottom: 12px;
}
/* 按钮容器,确保居中 */
.btn-container {
margin: 30px 0;
text-align: center;
}
/* 邮件底部样式 */
.email-footer {
margin-top: 25px;
padding-top: 15px;
border-top: 1px solid #eee;
font-size: 13px;
color: #999999;
text-align: center;
line-height: 1.5;
}
.footer-note {
margin-top: 8px;
}
/* 适配移动设备 */
@media (max-width: 480px) {
.email-body {
padding: 20px 15px;
}
.body-title {
font-size: 19px;
}
.body-desc {
font-size: 14px;
}
.btn {
padding: 10px 20px;
font-size: 14px;
min-width: 150px;
}
}
</style>
<!-- 引入Font Awesome图标若邮箱客户端支持增强视觉效果 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<!-- 邮件整体容器,控制最大宽度和背景 -->
<div class="email-container">
<!-- 邮件头部:显示网站标识 -->
<div class="email-header">
<div class="header-logo">
<i class="fas fa-music logo-icon"></i>
<span class="logo-text">音乐分享网站</span>
</div>
</div>
<!-- 邮件主体:核心内容区域 -->
<div class="email-body">
<h1 class="body-title">您请求重置密码</h1>
<div class="body-desc">
<p>您好!我们收到了您的密码重置请求,若此操作非您本人发起,请忽略此邮件。</p>
<p>请点击下方按钮重置您的密码链接有效期为1小时过期后需重新申请</p>
</div>
<!-- 重置按钮:居中显示,突出引导 -->
<div class="btn-container">
<a href="' . htmlspecialchars($resetLink) . '" class="btn">
<i class="fas fa-key mr-2"></i>立即重置密码
</a>
</div>
<div class="btn-container">
<a href="mailto:luoriguodu@foxmail.com" class="btn">
<i class="fas fa-key mr-2"></i>反馈问题
</a>
</div>
<!-- 备用链接:防止按钮失效时用户仍能操作 -->
<div class="body-desc">
<p>若按钮无法点击,可将下方链接复制到浏览器地址栏访问:</p>
<p style="word-break: break-all; color: #3498db;">
' . htmlspecialchars($resetLink) . '
</p>
</div>
</div>
<!-- 邮件底部:补充说明和版权信息 -->
<div class="email-footer">
<p>此邮件为系统自动发送,请勿直接回复</p>
<p class="footer-note">© 2024 音乐分享网站 版权所有 | 如有疑问,请联系客服</p>
</div>
</div>
</body>
</html>
';
// 创建邮件头部
$headers = [
'From' => $fromName . " <" . $smtpUsername . ">",
'Reply-To' => $smtpUsername,
'X-Mailer' => 'PHP/' . phpversion(),
'MIME-Version' => '1.0',
'Content-Type' => 'text/html; charset=UTF-8'
];
// 组装头部字符串
$headerString = "";
foreach ($headers as $key => $value) {
$headerString .= $key . ": " . $value . "\r\n";
}
// 使用stream_socket_client发送邮件
$socket = stream_socket_client(
'ssl://' . $smtpHost . ':' . $smtpPort,
$errorNumber,
$errorMessage,
30,
STREAM_CLIENT_CONNECT
);
if (!$socket) {
throw new Exception("无法连接到SMTP服务器: $errorMessage ($errorNumber)");
}
// 发送SMTP命令
fwrite($socket, "EHLO " . gethostname() . "\r\n");
fread($socket, 1024);
fwrite($socket, "AUTH LOGIN\r\n");
fread($socket, 1024);
fwrite($socket, base64_encode($smtpUsername) . "\r\n");
fread($socket, 1024);
fwrite($socket, base64_encode($smtpPassword) . "\r\n");
fread($socket, 1024);
fwrite($socket, "MAIL FROM: <" . $smtpUsername . ">\r\n");
fread($socket, 1024);
fwrite($socket, "RCPT TO: <" . $toEmail . ">\r\n");
fread($socket, 1024);
fwrite($socket, "DATA\r\n");
fread($socket, 1024);
fwrite($socket, "Subject: " . $subject . "\r\n");
fwrite($socket, $headerString . "\r\n");
fwrite($socket, $message . "\r\n");
fwrite($socket, ".\r\n");
fread($socket, 1024);
fwrite($socket, "QUIT\r\n");
fread($socket, 1024);
fclose($socket);
return true;
}
// 处理表单提交
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$email = trim($_POST['email'] ?? '');
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$message = "请输入有效的邮箱地址";
$messageType = "error";
} else {
$conn = new mysqli($servername, $dbusername, $dbpassword, $dbname);
if ($conn->connect_error) {
throw new Exception("数据库连接失败: " . $conn->connect_error);
}
$tableCheck = ensurePasswordResetTableExists($conn);
if ($tableCheck !== true) {
throw new Exception($tableCheck);
}
$stmt = $conn->prepare("SELECT id FROM users WHERE email = ?");
if (!$stmt) {
throw new Exception("准备查询语句失败: " . $conn->error);
}
$stmt->bind_param("s", $email);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
$stmt->bind_result($userId);
$stmt->fetch();
$token = generateToken();
$expiry = date('Y-m-d H:i:s', strtotime('+1 hour'));
$updateStmt = $conn->prepare("INSERT INTO password_reset_tokens (user_id, token, expiry) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE token = ?, expiry = ?");
if (!$updateStmt) {
throw new Exception("准备更新语句失败: " . $conn->error);
}
$updateStmt->bind_param("issss", $userId, $token, $expiry, $token, $expiry);
$updateStmt->execute();
// 生成重置链接
$resetLink = "http://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . "/reset_password.php?token=" . $token;
try {
// 发送重置邮件
sendResetEmailViaQQSMTP(
$email,
$resetLink,
$smtpHost,
$smtpPort,
$smtpUsername,
$smtpPassword,
$fromName
);
$message = "密码重置链接已发送到您的邮箱请查收1小时内有效";
$messageType = "success";
} catch (Exception $e) {
$message = "邮件发送失败: " . $e->getMessage();
$messageType = "error";
error_log("邮件发送错误: " . $e->getMessage());
}
$updateStmt->close();
} else {
// 安全考虑,无论邮箱是否存在,都显示相同的成功消息
$message = "如果该邮箱已注册,密码重置链接将发送";
$messageType = "success";
}
$stmt->close();
$conn->close();
}
}
} catch (Exception $e) {
$message = "系统错误: " . $e->getMessage();
$messageType = "error";
error_log("Forgot Password Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>忘记密码 - 音乐分享网站</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
body { font-family: 'Arial', sans-serif; max-width: 500px; margin: 2rem auto; padding: 0 1rem; background-color: #f5f5f7; }
.container { background-color: white; padding: 2rem; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { text-align: center; color: #2c3e50; }
.form-group { margin-bottom: 1.5rem; }
label { display: block; margin-bottom: 0.5rem; color: #333; }
input { width: 100%; padding: 0.8rem; border: 1px solid #ddd; border-radius: 5px; box-sizing: border-box; font-size: 1rem; }
button { width: 100%; padding: 0.8rem; background-color: #2c3e50; color: white; border: none; border-radius: 5px; font-size: 1rem; cursor: pointer; }
.message { padding: 1rem; border-radius: 5px; margin-bottom: 1.5rem; }
.error-message { background-color: #f8d7da; color: #721c24; }
.success-message { background-color: #d4edda; color: #155724; }
.back-link { text-align: center; margin-top: 1.5rem; }
.back-link a { color: #2c3e50; text-decoration: none; }
</style>
</head>
<body>
<div class="container">
<h1><i class="fas fa-key"></i> 忘记密码</h1>
<?php if (!empty($message)): ?>
<div class="message <?php echo $messageType === 'error' ? 'error-message' : 'success-message'; ?>">
<?php echo $message; ?>
</div>
<?php endif; ?>
<form method="post" action="">
<div class="form-group">
<label for="email">请输入您注册时使用的邮箱</label>
<input type="email" id="email" name="email" value="<?php echo htmlspecialchars($_POST['email'] ?? ''); ?>" required>
</div>
<button type="submit">获取重置链接</button>
</form>
<div class="back-link">
<a href="login.php"><i class="fas fa-arrow-left"></i> 返回登录</a>
</div>
</div>
</body>
</html>