Files
SunShineMusic/profile.php
2025-09-24 14:15:37 +00:00

467 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// 错误处理设置
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// 初始化变量
$message = '';
$messageType = '';
$userId = 0;
$currentNickname = '未设置';
$currentEmail = '未设置';
$ossConfigured = false;
$avatarUrl = './static/icon/icon.png';
$ossLoaded = false;
try {
session_start();
// 检查登录状态
if (!isset($_SESSION['user_logged_in']) || $_SESSION['user_logged_in'] !== true) {
throw new Exception("请先<a href='login.php'>登录</a>");
}
// 获取用户ID
if (isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id'])) {
$userId = (int)$_SESSION['user_id'];
} else {
throw new Exception("无法获取用户ID请重新登录");
}
// 加载配置文件
$config = [];
$configFile = 'pmconfig.php';
if (file_exists($configFile)) {
$config = include $configFile;
if (!is_array($config)) {
throw new Exception("配置文件必须返回一个数组");
}
} else {
throw new Exception("配置文件 pmconfig.php 不存在");
}
// 检查OSS配置
$ossParams = ['oss_access_key', 'oss_secret_key', 'oss_endpoint', 'oss_bucket'];
$missingOssParams = [];
foreach ($ossParams as $param) {
if (!isset($config[$param]) || empty($config[$param])) {
$missingOssParams[] = $param;
}
}
$ossConfigured = empty($missingOssParams);
// 引入OSS SDK
if ($ossConfigured) {
$ossSdkPath = __DIR__ . '/oss-sdk/autoload.php';
if (file_exists($ossSdkPath) && is_readable($ossSdkPath)) {
require_once $ossSdkPath;
$ossLoaded = class_exists('OSS\OssClient') && class_exists('OSS\Core\OssException');
}
}
// 生成头像URL
if ($ossConfigured && $ossLoaded) {
$bucket = $config['oss_bucket'];
$endpoint = preg_replace('/^https?:\/\//', '', $config['oss_endpoint']);
$object = 'sunmusic/profile/' . $userId . '头像.png';
$avatarUrl = "https://{$bucket}.{$endpoint}/{$object}?t=" . time();
}
// 数据库连接和用户信息获取
$dbRequired = ['db_host', 'db_user', 'db_name'];
$dbMissing = [];
foreach ($dbRequired as $param) {
if (!isset($config[$param]) || empty($config[$param])) {
$dbMissing[] = $param;
}
}
if (empty($dbMissing)) {
$conn = new mysqli(
$config['db_host'],
$config['db_user'],
$config['db_pass'] ?? '',
$config['db_name']
);
if ($conn->connect_error) {
throw new Exception("数据库连接失败: " . $conn->connect_error);
}
$conn->set_charset("utf8mb4");
// 获取用户信息
$stmt = $conn->prepare("SELECT nickname, email FROM users WHERE id = ?");
$stmt->bind_param("i", $userId);
$stmt->execute();
$result = $stmt->get_result();
if ($userData = $result->fetch_assoc()) {
$currentNickname = $userData['nickname'] ?? '未设置';
$currentEmail = $userData['email'] ?? '未设置';
} else {
throw new Exception("未找到用户信息");
}
$stmt->close();
// 处理基础信息更新
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_basic'])) {
$newNickname = trim($_POST['nickname'] ?? '');
$newEmail = trim($_POST['email'] ?? '');
$updates = [];
$params = [];
$types = '';
if (!empty($newNickname) && $newNickname !== $currentNickname) {
if (strlen($newNickname) < 2 || strlen($newNickname) > 20) {
throw new Exception("用户名长度必须在2-20个字符之间");
}
$updates[] = "nickname = ?";
$params[] = $newNickname;
$types .= "s";
}
if (!empty($newEmail) && $newEmail !== $currentEmail) {
if (!filter_var($newEmail, FILTER_VALIDATE_EMAIL)) {
throw new Exception("请输入有效的邮箱地址");
}
// 检查邮箱是否已被使用
$checkStmt = $conn->prepare("SELECT id FROM users WHERE email = ? AND id != ?");
$checkStmt->bind_param("si", $newEmail, $userId);
$checkStmt->execute();
$checkResult = $checkStmt->get_result();
if ($checkResult->num_rows > 0) {
throw new Exception("该邮箱已被其他用户使用");
}
$checkStmt->close();
$updates[] = "email = ?";
$params[] = $newEmail;
$types .= "s";
}
if (!empty($updates)) {
$sql = "UPDATE users SET " . implode(", ", $updates) . " WHERE id = ?";
$types .= "i";
$params[] = $userId;
$stmt = $conn->prepare($sql);
$bindParams = array_merge([$types], $params);
$tmp = [];
foreach ($bindParams as $key => $value) {
$tmp[$key] = &$bindParams[$key];
}
call_user_func_array([$stmt, 'bind_param'], $tmp);
$stmt->execute();
$stmt->close();
$currentNickname = $newNickname;
$currentEmail = $newEmail;
$message = "信息更新成功";
$messageType = 'success';
} else {
$message = "没有需要更新的信息";
$messageType = 'success';
}
}
$conn->close();
} else {
throw new Exception("数据库配置不完整(缺少: " . implode(', ', $dbMissing) . "");
}
// 处理头像上传
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['upload_avatar']) && $ossConfigured && $ossLoaded) {
if (!isset($_FILES['avatar'])) {
throw new Exception("未收到上传文件");
}
// 检查上传错误
switch ($_FILES['avatar']['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new Exception("请选择要上传的图片");
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new Exception("文件过大,超过上传限制");
default:
throw new Exception("上传错误,代码: " . $_FILES['avatar']['error']);
}
$avatarFile = $_FILES['avatar'];
// 验证文件
if (!is_uploaded_file($avatarFile['tmp_name'])) {
throw new Exception("文件上传异常");
}
$fileInfo = getimagesize($avatarFile['tmp_name']);
if (!$fileInfo) {
throw new Exception("不是有效的图片文件");
}
$allowedMime = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($fileInfo['mime'], $allowedMime)) {
throw new Exception("不支持的图片类型");
}
if ($avatarFile['size'] > 10 * 1024 * 1024) {
throw new Exception("文件过大最大支持10MB");
}
// OSS上传
$object = 'sunmusic/profile/' . $userId . '头像.png';
try {
$ossClient = new OSS\OssClient(
$config['oss_access_key'],
$config['oss_secret_key'],
$config['oss_endpoint']
);
$options = [
OSS\OssClient::OSS_HEADERS => [
'x-oss-object-acl' => 'public-read',
],
];
$ossClient->uploadFile(
$config['oss_bucket'],
$object,
$avatarFile['tmp_name'],
$options
);
$endpoint = preg_replace('/^https?:\/\//', '', $config['oss_endpoint']);
$avatarUrl = "https://{$config['oss_bucket']}.{$endpoint}/{$object}?t=" . time();
$message = "头像上传成功!";
$messageType = 'success';
} catch (OSS\Core\OssException $e) {
throw new Exception("OSS错误: " . $e->getMessage());
}
}
} catch (Exception $e) {
$message = $e->getMessage();
$messageType = 'error';
}
// 检测设备类型
$isMobile = preg_match('/(android|iphone|ipad|ipod|blackberry|windows phone)/i', $_SERVER['HTTP_USER_AGENT']);
?>
<!DOCTYPE html>
<html lang="zh-CN" class="<?php echo $isMobile ? 'mobile' : 'desktop'; ?>">
<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>
/* === 引入自定义字体 === */
@font-face {
font-family: "MyCustomFont";
src: url("./static/font/bbc.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
/* 基础样式 */
:root {
--bg-color: #f5f5f7;
--text-color: #333;
--card-bg: #ffffff;
--card-shadow: 0 4px 12px rgba(0,0,0,0.1);
--primary-color: #2c3e50;
--primary-hover: #34495e;
--border-color: #ddd;
--accent-color: #e74c3c;
--main-font: "MyCustomFont", sans-serif; /* 自定义字体变量 */
}
body {
font-family: var(--main-font);
margin: 0;
padding: 0;
background-color: var(--bg-color);
color: var(--text-color);
}
/* 布局样式 */
.app-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.profile-container {
background-color: var(--card-bg);
border-radius: 12px;
padding: 2rem;
box-shadow: var(--card-shadow);
margin-top: 20px;
}
/* 标题样式 */
h1, h2 {
color: var(--primary-color);
text-align: center;
}
h1 {
margin-bottom: 30px;
}
/* 头像样式 */
.avatar-container {
text-align: center;
margin-bottom: 2rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid var(--border-color);
}
.avatar {
width: 180px;
height: 180px;
border-radius: 50%;
object-fit: cover;
border: 3px solid var(--primary-color);
margin: 0 auto 1rem;
display: block;
}
.avatar-upload {
margin-top: 1rem;
padding: 1.5rem;
border: 1px dashed var(--border-color);
border-radius: 8px;
background-color: rgba(44, 62, 80, 0.03);
}
/* 表单样式 */
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
color: var(--primary-color);
font-weight: 500;
}
.form-control {
width: 100%;
padding: 0.8rem;
border: 1px solid var(--border-color);
border-radius: 8px;
font-size: 1rem;
box-sizing: border-box;
background-color: var(--bg-color);
color: var(--text-color);
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 1rem;
margin-top: 2rem;
}
/* 按钮样式 */
.submit-btn {
background-color: var(--primary-color);
color: white;
border: none;
padding: 0.8rem 2rem;
border-radius: 25px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.3s ease;
}
.submit-btn:hover {
background-color: var(--primary-hover);
}
.btn-secondary {
background-color: transparent;
color: var(--primary-color);
border: 1px solid var(--primary-color);
}
/* 消息提示样式 */
.message {
padding: 1rem;
border-radius: 8px;
margin-bottom: 1rem;
text-align: center;
}
.success {
background-color: #d4edda;
color: #155724;
}
.error {
background-color: #f8d7da;
color: #721c24;
}
</style>
</head>
<body>
<div class="app-container">
<h1>个人信息管理</h1>
<div class="profile-container">
<?php if (!empty($message)): ?>
<div class="message <?php echo $messageType; ?>"><?php echo $message; ?></div>
<?php endif; ?>
<!-- 头像上传区域 -->
<div class="avatar-container">
<h2>个人头像</h2>
<img src="<?php echo htmlspecialchars($avatarUrl); ?>" class="avatar"
alt="用户头像" onerror="this.src='./static/icon/icon.png'">
<div class="avatar-upload">
<form method="post" enctype="multipart/form-data">
<input type="file" name="avatar" accept="image/*" class="form-control">
<p></p>
<button type="submit" name="upload_avatar" class="submit-btn"
<?php echo !$ossConfigured ? 'disabled title="OSS配置不完整无法上传"' : ''; ?>>
上传头像
</button>
</form>
</div>
</div>
<!-- 个人信息编辑区域 -->
<form method="post">
<div class="form-group">
<label for="nickname">用户名</label>
<input type="text" id="nickname" name="nickname"
value="<?php echo htmlspecialchars($currentNickname); ?>"
class="form-control" maxlength="20">
</div>
<div class="form-group">
<label for="email">电子邮箱</label>
<input type="email" id="email" name="email"
value="<?php echo htmlspecialchars($currentEmail); ?>"
class="form-control">
</div>
<div class="form-actions">
<a href="index.php" class="submit-btn btn-secondary">返回</a>
<button type="submit" name="update_basic" class="submit-btn">保存修改</button>
</div>
</form>
</div>
</div>
</body>
</html>