上传文件至 /

This commit is contained in:
2025-09-24 14:15:48 +00:00
parent 676afc0fba
commit 01f0e6ab1d
5 changed files with 799 additions and 0 deletions

122
sou_api.php Normal file
View File

@@ -0,0 +1,122 @@
<?php
// sou_api.php
// 设置跨域请求头
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
// 初始化响应数组
$response = [
'status' => 'error',
'message' => 'Unknown error',
'count' => 0,
'results' => []
];
try {
// 1. 验证请求方法
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
$response['message'] = 'Method Not Allowed';
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
}
// 2. 验证并获取必要的参数
if (!isset($_GET['action']) || $_GET['action'] !== 'getSou') {
http_response_code(400);
$response['message'] = 'Invalid action. Use ?action=getSou';
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
}
// 检查搜索词是否存在
if (!isset($_GET['s'])) {
http_response_code(400);
$response['message'] = 'Missing search term. Use &s=your_keyword';
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
}
$searchTerm = trim($_GET['s']);
// 如果搜索词为空,则返回空结果
if (empty($searchTerm)) {
$response['status'] = 'success';
$response['message'] = 'Search term is empty, returning no results.';
$response['count'] = 0;
$response['results'] = [];
http_response_code(200);
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
}
// 3. 引入音乐数据
$musicFile = __DIR__ . '/data/music.php';
if (!file_exists($musicFile)) {
http_response_code(500);
$response['message'] = 'Music data file not found at ' . $musicFile;
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
}
// 使用require确保每次都能获取最新数据
$musicList = require $musicFile;
// 验证音乐数据格式
if (!is_array($musicList)) {
http_response_code(500);
$response['message'] = 'Invalid music data format in ' . $musicFile;
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
}
// 4. 定义音乐分类(用于返回更丰富的信息)
$categories = [
'all' => ['name' => '全部音乐', 'color' => '#b89e81', 'text_color' => '#5d4037'],
'cantonese' => ['name' => '粤语歌曲', 'color' => '#c8e6c9', 'text_color' => '#2e7d32'],
'mandarin' => ['name' => '国语歌曲', 'color' => '#fff3e0', 'text_color' => '#e65100'],
'waiyu' => ['name' => '外语歌曲', 'color' => '#e3f2fd', 'text_color' => '#0d47a1'],
'classic' => ['name' => '经典老歌', 'color' => '#efebe9', 'text_color' => '#3e2723'],
'other' => ['name' => '其他音乐', 'color' => '#f3e5f5', 'text_color' => '#6a1b9a']
];
// 5. 执行搜索
$searchResults = [];
$lowerTerm = strtolower($searchTerm);
foreach ($musicList as $music) {
// 检查音乐条目是否有效
if (!is_array($music) || !isset($music['title'], $music['artist'])) {
continue; // 跳过无效条目
}
if (strpos(strtolower($music['title']), $lowerTerm) !== false ||
strpos(strtolower($music['artist']), $lowerTerm) !== false) {
// 为结果添加分类信息,如果分类不存在则使用'other'
$music['category_info'] = $categories[$music['category']] ?? $categories['other'];
$searchResults[] = $music;
}
}
// 6. 构建成功响应
$response = [
'status' => 'success',
'action' => 'getSou',
'search_term' => $searchTerm,
'count' => count($searchResults),
'results' => $searchResults
];
http_response_code(200);
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
} catch (Exception $e) {
// 捕获所有未预见的异常
http_response_code(500);
$response['message'] = 'Server error: ' . $e->getMessage();
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
}
?>

53
submit_recommendation.php Normal file
View File

@@ -0,0 +1,53 @@
<?php
// 处理推荐提交的后端接口
require 'db_connect.php';
// 仅处理POST请求
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$songName = trim($_POST['songName'] ?? '');
$artistName = trim($_POST['artistName'] ?? '');
$reason = trim($_POST['reason'] ?? '');
// 获取用户标识
function getUserIdentifier() {
if (isset($_COOKIE['user_identifier'])) {
return $_COOKIE['user_identifier'];
}
$identifier = uniqid('user_', true);
setcookie('user_identifier', $identifier, time() + 365 * 24 * 3600, '/');
return $identifier;
}
$userIdentifier = getUserIdentifier();
// 验证必填字段
if (!empty($songName) && !empty($artistName)) {
try {
// 插入数据,包含用户标识
$sql = "INSERT INTO recommendations (song_name, artist_name, reason, user_identifier, status)
VALUES (:song_name, :artist_name, :reason, :user_id, 0)";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':song_name', $songName);
$stmt->bindParam(':artist_name', $artistName);
$stmt->bindParam(':reason', $reason);
$stmt->bindParam(':user_id', $userIdentifier);
$stmt->execute();
// 跳转回主页并显示成功消息
header('Location: index.html?status=success');
exit;
} catch(PDOException $e) {
// 数据库错误
header('Location: index.html?status=error&msg=' . urlencode($e->getMessage()));
exit;
}
} else {
// 字段验证失败
header('Location: index.html?status=error&msg=歌曲名称和歌手名称为必填项');
exit;
}
} else {
// 非POST请求直接跳转回主页
header('Location: index.html');
exit;
}
?>

View File

@@ -0,0 +1,50 @@
<?php
// 引入数据库连接
require_once 'db_connect.php';
// 初始化变量
$id = $_POST['id'] ?? 0;
$status = $_POST['status'] ?? 0;
// 管理员首页地址,确保与实际管理员首页文件名一致
$adminHome = 'admin_recommendations.php';
// 验证参数
if (empty($id) || !in_array($status, [1, 2])) {
header("Location: $adminHome?delete_status=error&msg=参数错误");
exit;
}
// 处理数据库更新
if ($pdo) {
try {
// 准备更新语句
$sql = "UPDATE recommendations
SET status = :status, reviewed_at = CURRENT_TIMESTAMP
WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':status', $status, PDO::PARAM_INT);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
// 执行更新
$result = $stmt->execute();
if ($result) {
$message = $status == 1 ? "推荐已同意" : "推荐已驳回";
header("Location: $adminHome?delete_status=success&msg=$message");
} else {
header("Location: $adminHome?delete_status=error&msg=更新失败,请重试");
}
} catch(PDOException $e) {
// 记录错误日志
$logMsg = date('[Y-m-d H:i:s] ') . "状态更新错误: " . $e->getMessage() . "\n";
file_put_contents('db_error.log', $logMsg, FILE_APPEND);
header("Location: $adminHome?delete_status=error&msg=数据库错误,请稍后再试");
}
} else {
header("Location: $adminHome?delete_status=error&msg=数据库连接失败");
}
exit;
?>

442
upload.php Normal file
View File

@@ -0,0 +1,442 @@
<?php
// 音乐上传功能(已登录用户自动识别)
require_once 'db_config.php';
$message = '';
$message_type = '';
// 启动会话以检查登录状态
session_start();
// 音乐分类映射
$categories = [
'cantonese' => '粤语歌曲',
'mandarin' => '国语歌曲',
'waiyu' => '外语歌曲',
'classic' => '经典老歌',
'other' => '其他音乐'
];
// 检查用户是否登录
$isLoggedIn = isset($_SESSION['user_logged_in']) && $_SESSION['user_logged_in'] === true;
$uploaderName = $isLoggedIn ? $_SESSION['user_info']['username'] : '匿名用户';
// 处理上传
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['upload_music'])) {
// 验证表单数据
$title = trim($_POST['title'] ?? '');
$artist = trim($_POST['artist'] ?? '');
// 如果用户已登录,强制使用会话中的用户名,忽略表单提交的值
$uploader = $isLoggedIn ? $_SESSION['user_info']['username'] : trim($_POST['uploader'] ?? '匿名用户');
$category = $_POST['category'] ?? 'other';
$description = trim($_POST['description'] ?? '');
$bvid = trim($_POST['bvid'] ?? '');
$duration = trim($_POST['duration'] ?? '');
// 验证时长格式
if (!empty($duration) && !preg_match('/^\d+:\d{2}$/', $duration)) {
$message = "时长格式不正确,请使用 MM:SS 格式(例如 3:45 表示3分45秒";
$message_type = "error";
} elseif (empty($title) || empty($artist)) {
$message = "歌曲名和歌手名不能为空";
$message_type = "error";
} elseif (!isset($_FILES['audio_file']) || $_FILES['audio_file']['error'] !== UPLOAD_ERR_OK) {
$message = "请选择要上传的音频文件";
$message_type = "error";
} else {
// 验证BV号格式
if (!empty($bvid) && !preg_match('/^BV[0-9A-Za-z]+$/', $bvid)) {
$message = "BV号格式不正确应为以BV开头的字符串如BV1Va4y1n7HN";
$message_type = "error";
} else {
// 处理文件上传
$upload_dir = 'uploads/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
$file_ext = pathinfo($_FILES['audio_file']['name'], PATHINFO_EXTENSION);
$allowed_ext = ['mp3', 'wav', 'flac', 'm4a'];
if (!in_array(strtolower($file_ext), $allowed_ext)) {
$message = "不支持的文件格式仅支持mp3, wav, flac, m4a";
$message_type = "error";
} else {
// 检查文件大小限制30MB
$max_file_size = 30 * 1024 * 1024; // 30MB
if ($_FILES['audio_file']['size'] > $max_file_size) {
$message = "文件大小超过限制30MB";
$message_type = "error";
} else {
// 生成唯一文件名
$file_name = uniqid('music_') . '.' . $file_ext;
$target_path = $upload_dir . $file_name;
if (move_uploaded_file($_FILES['audio_file']['tmp_name'], $target_path)) {
// 使用用户输入的时长,如果为空则使用默认值
$final_duration = !empty($duration) ? $duration : "0:00";
// 保存到待审核表
try {
$stmt = $conn->prepare("INSERT INTO pending_music
(uploader_name, title, artist, category, description, file_path, duration, upload_time, bvid)
VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), ?)");
$stmt->execute([$uploader, $title, $artist, $category, $description, $target_path, $final_duration, $bvid]);
$message = "上传成功,已进入待审核队列,感谢您的分享!";
$message_type = "success";
// 清空表单
$_POST = [];
} catch (PDOException $e) {
$message = "数据库错误: " . $e->getMessage();
$message_type = "error";
unlink($target_path); // 数据库错误时删除已上传文件
}
} else {
$message = "文件上传失败";
$message_type = "error";
}
}
}
}
}
}
?>
<!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="icon" href="./static/icon/icon.png" type="image/png">
<link rel="alternate icon" href="./static/icon/icon.ico" type="image/x-icon">
<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 {
--primary-color: #2c3e50;
--primary-hover: #34495e;
--accent-color: #e74c3c;
--bg-color: #f7f9fc;
--text-color: #333;
--muted-color: #7f8c8d;
--card-bg: #ffffff;
--card-shadow: 0 4px 12px rgba(0,0,0,0.08);
--border-color: #dcdfe6;
--main-font: "MyCustomFont", sans-serif; /* 自定义字体变量 */
}
body {
font-family: var(--main-font);
margin: 0;
padding: 0;
background-color: var(--bg-color);
color: var(--text-color);
transition: background-color 0.3s ease, color 0.3s ease;
}
h1, h2, h3 { color: var(--primary-color); }
h1 { font-size: 1.8rem; text-align: center; margin: 1rem 0; }
h2 { font-size: 1.4rem; margin-bottom: 0.5rem; }
.desktop .app-container { display: flex; min-height: 100vh; }
.desktop .main-wrapper { flex: 1; display: flex; flex-direction: column; margin-left: 280px; }
.desktop .main-content { flex: 1; max-width: 1200px; width: 100%; margin: 0 auto; padding: 1rem; box-sizing: border-box; }
.mobile .app-container { display: block; min-height: 100vh; }
.mobile .main-wrapper { margin-left: 0; }
.mobile .main-content { width: 100%; padding: 0.5rem; box-sizing: border-box; }
.top-bar {
display: flex; justify-content: space-between; align-items: center;
padding: 1rem 1.5rem; background-color: var(--card-bg);
box-shadow: 0 2px 8px rgba(0,0,0,0.1); position: sticky; top: 0; z-index: 100;
}
.site-title { margin: 0; font-size: 1.4rem; color: var(--primary-color); }
.theme-toggle, .user-menu-btn {
background: none; border: 1px solid var(--border-color); color: var(--text-color);
padding: 0.5rem 0.8rem; border-radius: 20px; cursor: pointer;
display: flex; align-items: center; gap: 0.5rem; transition: all 0.3s ease; text-decoration: none;
}
.theme-toggle:hover, .user-menu-btn:hover { background-color: var(--primary-color); color: white; border-color: var(--primary-color); }
.form-group { margin-bottom: 1.2rem; text-align: left; }
.form-group label { display: block; margin-bottom: 0.5rem; color: var(--primary-color); font-weight: 500; }
.form-group.required label::after { content: " *"; color: var(--accent-color); }
.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);
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.form-control:read-only { background-color: #e9ecef; cursor: not-allowed; color: #495057; }
.form-control:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 2px rgba(44, 62, 80, 0.1); }
.error-input { border-color: var(--accent-color) !important; box-shadow: 0 0 0 2px rgba(231, 76, 60, 0.1) !important; }
.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, transform 0.1s ease; width: 100%;
box-sizing: border-box; display: flex; align-items: center; justify-content: center; gap: 0.5rem;
}
.submit-btn:hover { background-color: var(--primary-hover); }
.submit-btn:active { transform: translateY(2px); }
.file-info { margin-top: 0.5rem; font-size: 0.85rem; color: var(--muted-color); }
.field-hint { margin-top: 0.3rem; font-size: 0.8rem; color: var(--muted-color); font-style: italic; }
.message { padding: 1rem; border-radius: 8px; margin-bottom: 1rem; text-align: center; font-size: 0.95rem; transition: opacity 0.3s ease, transform 0.3s ease; }
.success { background-color: #d4edda; color: #155724; }
.error { background-color: #f8d7da; color: #721c24; }
.music-item { background-color: var(--card-bg); border-radius: 12px; padding: 1.2rem; box-shadow: var(--card-shadow); margin-bottom: 1.2rem; }
.artist-info { color: var(--muted-color); font-size: 0.9rem; margin-bottom: 1rem; }
.back-to-top {
position: fixed; bottom: 30px; right: 30px; width: 50px; height: 50px;
background-color: var(--primary-color); color: white; border-radius: 50%;
display: flex; align-items: center; justify-content: center; font-size: 1.5rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.2); cursor: pointer;
opacity: 0; visibility: hidden; transition: all 0.3s ease; z-index: 999;
}
.back-to-top.show { opacity: 1; visibility: visible; }
.back-to-top:hover { background-color: var(--primary-hover); transform: translateY(-5px); }
</style>
</head>
<body>
<div class="app-container">
<div class="main-wrapper">
<header class="top-bar">
<h1 class="site-title">
<img src="./static/icon/icon.png" alt="音乐图标" style="width: 24px; height: 24px; vertical-align: middle; margin-right: 8px;">
<a href="./index.php" style="text-decoration: none; color: inherit;">音乐分享平台</a>
</h1>
<?php if ($isLoggedIn): ?>
<a href="user_center.php" class="user-menu-btn"><i class="fas fa-user"></i> <?php echo htmlspecialchars($uploaderName); ?></a>
<?php else: ?>
<a href="login.php" class="user-menu-btn"><i class="fas fa-sign-in-alt"></i> 登录</a>
<?php endif; ?>
</header>
<main class="main-content">
<div class="music-item">
<h2><i class="fas fa-cloud-upload-alt"></i> 上传音乐</h2>
<p class="artist-info">
<?php if ($isLoggedIn): ?>
您好,<strong><?php echo htmlspecialchars($uploaderName); ?></strong>。您已登录,上传将自动记录您的昵称。
<?php else: ?>
您当前未登录,上传后将以“匿名用户”身份显示。<a href="login.php" style="color: var(--primary-color);">登录</a>后可获得更完整的服务。
<?php endif; ?>
</p>
<?php if ($message): ?>
<div class="message <?php echo $message_type; ?>"><?php echo htmlspecialchars($message); ?></div>
<?php endif; ?>
<form id="upload-form" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="uploader">您的昵称</label>
<input type="text" id="uploader" name="uploader" class="form-control"
value="<?php echo htmlspecialchars($isLoggedIn ? $uploaderName : ($_POST['uploader'] ?? '匿名用户')); ?>"
<?php echo $isLoggedIn ? 'readonly' : ''; ?>>
<?php if ($isLoggedIn): ?>
<div class="field-hint">已为您自动填充昵称,该字段不可修改。</div>
<?php else: ?>
<div class="field-hint">未登录状态下,默认为“匿名用户”。</div>
<?php endif; ?>
</div>
<div class="form-group required">
<label for="title">歌曲名称</label>
<input type="text" id="title" name="title" class="form-control" value="<?php echo htmlspecialchars($_POST['title'] ?? ''); ?>" required>
</div>
<div class="form-group required">
<label for="artist">歌手/乐队</label>
<input type="text" id="artist" name="artist" class="form-control" value="<?php echo htmlspecialchars($_POST['artist'] ?? ''); ?>" required>
</div>
<div class="form-group required">
<label for="category">音乐分类</label>
<select id="category" name="category" class="form-control" required>
<?php foreach ($categories as $key => $name): ?>
<option value="<?php echo $key; ?>" <?php echo (($_POST['category'] ?? '') == $key) ? 'selected' : ''; ?>>
<?php echo $name; ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group required">
<label for="duration">音频时长</label>
<input type="text" id="duration" name="duration" class="form-control"
value="<?php echo htmlspecialchars($_POST['duration'] ?? ''); ?>"
placeholder="请输入时长,格式为 MM:SS例如 3:45 表示3分45秒" required>
<div class="field-hint">请按照实际时长填写,格式为 分钟:秒数(例如 4:30 表示4分30秒</div>
</div>
<div class="form-group">
<label for="bvid">B站视频BV号 (可选)</label>
<input type="text" id="bvid" name="bvid" class="form-control"
value="<?php echo htmlspecialchars($_POST['bvid'] ?? ''); ?>"
placeholder="例如: BV1Va4y1n7HN">
<div class="field-hint">若该音乐来自B站视频可填写对应的BV号以BV开头方便用户查看视频来源</div>
</div>
<div class="form-group">
<label for="description">歌曲描述 (可选)</label>
<textarea id="description" name="description" class="form-control" rows="3"><?php echo htmlspecialchars($_POST['description'] ?? ''); ?></textarea>
</div>
<div class="form-group required">
<label for="audio_file">音频文件</label>
<input type="file" id="audio_file" name="audio_file" class="form-control" accept="audio/*" required>
<small class="file-info">支持格式mp3, wav, flac, m4a文件大小不超过30MB</small>
</div>
<button type="submit" name="upload_music" class="submit-btn">
<i class="fas fa-upload"></i> 上传音乐
</button>
</form>
</div>
</main>
</div>
</div>
<script>
// 检测设备类型并添加相应类名
document.addEventListener('DOMContentLoaded', function() {
const isMobile = window.innerWidth < 768;
document.body.classList.add(isMobile ? 'mobile' : 'desktop');
// 表单验证增强
const uploadForm = document.getElementById('upload-form');
if (uploadForm) {
uploadForm.addEventListener('submit', function(e) {
let isValid = true;
const titleInput = document.getElementById('title');
const artistInput = document.getElementById('artist');
const durationInput = document.getElementById('duration');
const bvidInput = document.getElementById('bvid');
// 清除之前的错误状态
titleInput.classList.remove('error-input');
artistInput.classList.remove('error-input');
durationInput.classList.remove('error-input');
bvidInput.classList.remove('error-input');
// 验证必填字段
if (!titleInput.value.trim()) {
titleInput.classList.add('error-input');
isValid = false;
}
if (!artistInput.value.trim()) {
artistInput.classList.add('error-input');
isValid = false;
}
// 验证时长格式
if (durationInput.value.trim() && !/^\d+:\d{2}$/.test(durationInput.value.trim())) {
durationInput.classList.add('error-input');
isValid = false;
}
// 验证BV号格式如果填写了
if (bvidInput.value.trim() && !/^BV[0-9A-Za-z]+$/.test(bvidInput.value.trim())) {
bvidInput.classList.add('error-input');
isValid = false;
}
if (!isValid) {
e.preventDefault();
// 清除已有的错误消息
const existingErrors = document.querySelectorAll('.message.error');
existingErrors.forEach(el => el.remove());
// 显示错误消息
const errorMsg = document.createElement('div');
errorMsg.className = 'message error';
if (durationInput.classList.contains('error-input')) {
errorMsg.textContent = '时长格式不正确,请使用 MM:SS 格式(例如 3:45 表示3分45秒';
} else if (bvidInput.classList.contains('error-input')) {
errorMsg.textContent = 'BV号格式不正确应为以BV开头的字符串如BV1Va4y1n7HN';
} else {
errorMsg.textContent = '请填写所有必填字段';
}
errorMsg.style.marginBottom = '1rem';
uploadForm.parentNode.insertBefore(errorMsg, uploadForm);
// 3秒后自动移除错误消息
setTimeout(() => {
errorMsg.style.opacity = '0';
setTimeout(() => errorMsg.remove(), 300);
}, 3000);
}
});
}
// 文件选择预览(大小和名称)
const fileInput = document.getElementById('audio_file');
if (fileInput) {
fileInput.addEventListener('change', function() {
if (this.files && this.files[0]) {
const fileInfo = document.querySelector('.file-info') || document.createElement('div');
fileInfo.className = 'file-info';
// 格式化文件大小
const fileSize = this.files[0].size;
let sizeText;
if (fileSize < 1024 * 1024) {
sizeText = (fileSize / 1024).toFixed(2) + ' KB';
} else {
sizeText = (fileSize / (1024 * 1024)).toFixed(2) + ' MB';
}
fileInfo.innerHTML = `已选择: ${this.files[0].name} (${sizeText})`;
if (!document.querySelector('.file-info')) {
this.parentNode.appendChild(fileInfo);
}
}
});
}
// 回到顶部按钮功能
const backToTopBtn = document.createElement('button');
backToTopBtn.className = 'back-to-top';
backToTopBtn.innerHTML = '<i class="fas fa-chevron-up"></i>';
backToTopBtn.setAttribute('aria-label', '回到顶部');
document.body.appendChild(backToTopBtn);
window.addEventListener('scroll', () => {
if (window.scrollY > 300) {
backToTopBtn.classList.add('show');
} else {
backToTopBtn.classList.remove('show');
}
});
backToTopBtn.addEventListener('click', () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
// 显示消息动画
const messageEl = document.querySelector('.message');
if (messageEl) {
setTimeout(() => {
messageEl.style.opacity = 1;
}, 100);
// 成功消息5秒后自动消失
if (messageEl.classList.contains('success')) {
setTimeout(() => {
messageEl.style.opacity = 0;
setTimeout(() => messageEl.remove(), 300);
}, 5000);
}
}
});
</script>
</body>
</html>

132
upload_gg.php Normal file
View File

@@ -0,0 +1,132 @@
<?php
// gg.php - 公告管理页面
// 数据库连接信息
$servername = "localhost";
$dbUsername = "a1sax1m9i";
$dbPassword = "a1sax1m9i";
$dbName = "a1sax1m9i";
// 创建连接
$conn = new mysqli($servername, $dbUsername, $dbPassword, $dbName);
if ($conn->connect_error) {
die("数据库连接失败: " . $conn->connect_error);
}
$conn->set_charset("utf8mb4");
$message = "";
$messageType = "";
// 处理表单提交
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['action']) && $_POST['action'] == 'add_announcement') {
$nr = trim($_POST["nr"] ?? "");
if (empty($nr)) {
$message = "公告内容不能为空!";
$messageType = "error";
} else {
$stmt = $conn->prepare("INSERT INTO announcements (nr) VALUES (?)");
$stmt->bind_param("s", $nr);
if ($stmt->execute()) {
$message = "公告发布成功!";
$messageType = "success";
header("Location: " . $_SERVER['PHP_SELF']);
exit;
} else {
$message = "发布失败: " . $conn->error;
$messageType = "error";
}
$stmt->close();
}
}
// 查询所有公告
$announcements = [];
$ggResult = $conn->query("SELECT id, nr, time FROM announcements ORDER BY id DESC");
while($row = $ggResult->fetch_assoc()) {
$announcements[] = $row;
}
$conn->close();
?>
<!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="icon" href="./static/icon/icon.png" type="image/png">
<link rel="alternate icon" href="./static/icon/icon.ico" type="image/x-icon">
<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; background-color: #f5f5f7; color: #333; margin: 0; padding: 20px; }
.container { max-width: 800px; margin: 0 auto; background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
h1, h2 { color: #2c3e50; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 8px; font-weight: bold; }
textarea.form-control { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; min-height: 120px; }
.submit-btn { background-color: #2c3e50; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; }
.submit-btn:hover { background-color: #34495e; }
.announcement-list { margin-top: 30px; }
.announcement-item { padding: 15px; border-bottom: 1px solid #eee; }
.announcement-item:last-child { border-bottom: none; }
.announcement-meta { color: #777; font-size: 14px; margin-bottom: 8px; }
.announcement-content { line-height: 1.6; }
.back-link { display: inline-block; margin-top: 20px; color: #2c3e50; text-decoration: none; }
.back-link:hover { text-decoration: underline; }
.message { padding: 10px; margin-bottom: 15px; border-radius: 4px; }
.success { background-color: #d4edda; color: #155724; }
.error { background-color: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<div class="container">
<h1>公告管理</h1>
<!-- 发布公告表单 -->
<div class="recommend-container">
<h2>发布新公告</h2>
<?php if (!empty($message)): ?>
<div class="message <?php echo $messageType; ?>">
<?php echo $message; // 提示信息仍用纯文本 ?>
</div>
<?php endif; ?>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
<input type="hidden" name="action" value="add_announcement">
<div class="form-group">
<label for="nr">公告内容 (支持HTML)</label>
<textarea id="nr" name="nr" class="form-control" placeholder="请输入公告内容,例如:<b>加粗</b>、<a href='https://shanwogou.cn'>链接</a>..." required></textarea>
</div>
<button type="submit" class="submit-btn">发布公告</button>
</form>
</div>
<!-- 历史公告列表 -->
<div class="announcement-list">
<h2>历史公告</h2>
<?php if (empty($announcements)): ?>
<p>暂无历史公告。</p>
<?php else: ?>
<?php foreach($announcements as $ann): ?>
<div class="announcement-item">
<div class="announcement-meta">
<span>ID: <?php echo $ann['id']; ?></span> |
<span>发布时间: <?php echo $ann['time']; ?></span>
</div>
<div class="announcement-content">
<?php
// 核心修改:移除 htmlspecialchars让HTML标签生效
// 保留 nl2br 以正确处理换行符
echo nl2br($ann['nr']);
?>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<a href="index.php" class="back-link"><i class="fas fa-arrow-left"></i> 返回首页</a>
</div>
</body>
</html>