first commit
This commit is contained in:
commit
c827a784dd
26
404.html
Normal file
26
404.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<title>404</title>
|
||||
<style>
|
||||
body{
|
||||
background-color:#444;
|
||||
font-size:14px;
|
||||
}
|
||||
h3{
|
||||
font-size:60px;
|
||||
color:#eee;
|
||||
text-align:center;
|
||||
padding-top:30px;
|
||||
font-weight:normal;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h3>啥也没有</h3>
|
||||
</body>
|
||||
</html>
|
24
README.md
Normal file
24
README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# 🌟 Random Image API Manager
|
||||
|
||||
## 🚀 项目简介
|
||||
嘿,欢迎来到 Random Image API Manager!这是一个用 PHP + MySQL 打造的超级有趣的小工具,让你可以轻松管理随机图片的分类和展示。无论是为你的网站添加趣味图片,还是为你的应用提供动态素材,这个程序都能满足你的需求!🎉
|
||||
|
||||
## 🎨 功能亮点
|
||||
- **分类管理**:后台支持自定义分类,你可以根据需要创建不同的分类,让图片更有条理。
|
||||
- **图片上传**:通过后台轻松添加图片 URL,瞬间扩充你的图片库。
|
||||
- **随机展示**:通过指定分类的 API 接口,每次请求都能随机返回一张图片,让惊喜无处不在!
|
||||
- **简单易用**:基于 PHP + MySQL,部署简单,操作直观。
|
||||
|
||||
## 🛠️ 技术栈
|
||||
- **后端**:PHP
|
||||
- **数据库**:MySQL
|
||||
- **前端**:简单 HTML + CSS(可扩展)
|
||||
|
||||
## 📦 安装与部署
|
||||
### 环境要求
|
||||
- PHP 7.4+(推荐)
|
||||
- MySQL 5.7+
|
||||
- Web 服务器(Apache/Nginx)
|
||||
|
||||
### 📝 许可证
|
||||
本项目采用 MIT License,你可以自由使用和修改代码。
|
10
admin/_log.php
Normal file
10
admin/_log.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// 在每次数据库修改操作后记录
|
||||
$log = sprintf(
|
||||
"[%s] %s 操作:%s \n",
|
||||
date('Y-m-d H:i:s'),
|
||||
$_SESSION['username'],
|
||||
json_encode($_POST)
|
||||
);
|
||||
file_put_contents(__DIR__.'/../logs/admin.log', $log, FILE_APPEND);
|
||||
?>
|
73
admin/admin.php
Normal file
73
admin/admin.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
require_once __DIR__.'/../includes/auth.php';
|
||||
requireLogin();
|
||||
|
||||
// 处理表单提交
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_once __DIR__.'/../includes/db.php';
|
||||
|
||||
$urls = explode("\n", $_POST['urls']);
|
||||
$resolution = $_POST['resolution'];
|
||||
$category = $_POST['category'];
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO images (url, resolution, category) VALUES (?, ?, ?)");
|
||||
|
||||
$success = 0;
|
||||
foreach ($urls as $url) {
|
||||
$url = trim($url);
|
||||
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
try {
|
||||
$stmt->execute([$url, $resolution, $category]);
|
||||
$success++;
|
||||
} catch (PDOException $e) {}
|
||||
}
|
||||
}
|
||||
$message = "成功添加 {$success} 条记录";
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>管理后台</title>
|
||||
<link rel="stylesheet" href="../assets/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="admin-container">
|
||||
<header>
|
||||
<h1>欢迎回来,<?= htmlspecialchars($_SESSION['username']) ?></h1>
|
||||
<a href="logout.php" class="logout-btn">退出登录</a>
|
||||
</header>
|
||||
|
||||
<?php if (isset($message)): ?>
|
||||
<div class="success-msg"><?= $message ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="form-wrapper">
|
||||
<form method="POST">
|
||||
<div class="form-row">
|
||||
<select name="resolution" required>
|
||||
<option value="UHD">UHD</option>
|
||||
<option value="4K">4K</option>
|
||||
<option value="HD">HD</option>
|
||||
</select>
|
||||
|
||||
<select name="category" required>
|
||||
<option value="美女">美女</option>
|
||||
<option value="风景">风景</option>
|
||||
<option value="动物">动物</option>
|
||||
<option value="游戏">游戏</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<textarea name="urls"
|
||||
placeholder="请输入图片URL,每行一个"
|
||||
rows="10"
|
||||
required></textarea>
|
||||
|
||||
<button type="submit">提交数据</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
81
admin/categories.php
Normal file
81
admin/categories.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
require_once __DIR__.'/../includes/auth.php';
|
||||
requireLogin();
|
||||
|
||||
// 处理表单提交
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_once __DIR__.'/../includes/db.php';
|
||||
|
||||
$action = $_POST['action'] ?? '';
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
|
||||
try {
|
||||
if ($action === 'add') {
|
||||
$stmt = $pdo->prepare("INSERT INTO categories (name) VALUES (?)");
|
||||
$stmt->execute([$name]);
|
||||
$msg = "分类添加成功";
|
||||
} elseif ($action === 'delete') {
|
||||
$stmt = $pdo->prepare("DELETE FROM categories WHERE id = ?");
|
||||
$stmt->execute([$_POST['id']]);
|
||||
$msg = "分类删除成功";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error = "操作失败:".$e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取现有分类
|
||||
$categories = $pdo->query("SELECT * FROM categories ORDER BY name")->fetchAll();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>分类管理</title>
|
||||
<link rel="stylesheet" href="../assets/css/admin.css">
|
||||
</head>
|
||||
<body>
|
||||
<?php include '_sidebar.php'; ?>
|
||||
|
||||
<main class="content">
|
||||
<h2>分类管理</h2>
|
||||
|
||||
<!-- 新增分类表单 -->
|
||||
<div class="card">
|
||||
<form method="POST">
|
||||
<input type="text" name="name" placeholder="新分类名称" required>
|
||||
<input type="hidden" name="action" value="add">
|
||||
<button type="submit">添加分类</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 分类列表 -->
|
||||
<div class="card">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>分类名称</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($categories as $cat): ?>
|
||||
<tr>
|
||||
<td><?= $cat['id'] ?></td>
|
||||
<td><?= htmlspecialchars($cat['name']) ?></td>
|
||||
<td>
|
||||
<form method="POST"
|
||||
onsubmit="return confirm('确认删除该分类?')">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="id" value="<?= $cat['id'] ?>">
|
||||
<button type="submit" class="btn-danger">删除</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
9
admin/index.php
Normal file
9
admin/index.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
require_once __DIR__.'/../includes/auth.php';
|
||||
|
||||
if (isLoggedIn()) {
|
||||
header("Location: admin.php");
|
||||
} else {
|
||||
header("Location: login.php");
|
||||
}
|
||||
exit;
|
49
admin/login.php
Normal file
49
admin/login.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
require_once __DIR__.'/../includes/auth.php';
|
||||
|
||||
if (isLoggedIn()) {
|
||||
header("Location: admin.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = '';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = $_POST['username'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
|
||||
if (login($username, $password)) {
|
||||
header("Location: admin.php");
|
||||
exit;
|
||||
} else {
|
||||
$error = "用户名或密码错误";
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>后台登录</title>
|
||||
<link rel="stylesheet" href="../assets/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<div class="login-box">
|
||||
<h2>图片管理系统</h2>
|
||||
<?php if ($error): ?>
|
||||
<div class="error-msg"><?= $error ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="form-group">
|
||||
<input type="text" name="username" placeholder="用户名" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="password" placeholder="密码" required>
|
||||
</div>
|
||||
<button type="submit">立即登录</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
7
admin/logout.php
Normal file
7
admin/logout.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
require_once __DIR__.'/../includes/auth.php';
|
||||
|
||||
session_unset();
|
||||
session_destroy();
|
||||
header("Location: login.php");
|
||||
exit;
|
50
api/api.php
Normal file
50
api/api.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
try {
|
||||
require_once __DIR__.'/../includes/config.php';
|
||||
require_once __DIR__.'/../includes/db.php';
|
||||
require_once __DIR__.'/../includes/api_functions.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// 获取并验证参数
|
||||
$params = validateRequestParams();
|
||||
|
||||
// 构建查询语句
|
||||
$query = buildImageQuery($params);
|
||||
|
||||
// 获取随机图片
|
||||
$image = fetchRandomImage($pdo, $query, $params);
|
||||
|
||||
// 处理结果
|
||||
if ($image) {
|
||||
// 直接跳转模式
|
||||
if (isset($_GET['redirect']) && $_GET['redirect'] === 'true') {
|
||||
// 验证URL有效性
|
||||
if (filter_var($image['url'], FILTER_VALIDATE_URL)) {
|
||||
header("Location: " . $image['url']);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo jsonError('无效的图片URL');
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 正常JSON响应
|
||||
echo jsonResponse([
|
||||
'url' => $image['url'],
|
||||
'resolution' => $params['resolution'],
|
||||
'category' => $params['category']
|
||||
]);
|
||||
} else {
|
||||
echo jsonError('未找到匹配的图片', 404);
|
||||
}
|
||||
|
||||
} catch (InvalidArgumentException $e) {
|
||||
echo jsonError($e->getMessage(), 400);
|
||||
} catch (PDOException $e) {
|
||||
error_log("Database Error: " . $e->getMessage());
|
||||
echo jsonError('数据库查询失败', 500);
|
||||
} catch (Exception $e) {
|
||||
error_log("System Error: " . $e->getMessage());
|
||||
echo jsonError('系统繁忙,请稍后再试', 500);
|
||||
}
|
114
assets/css/admin.css
Normal file
114
assets/css/admin.css
Normal file
@ -0,0 +1,114 @@
|
||||
/* 基础样式 */
|
||||
.admin-container {
|
||||
display: grid;
|
||||
grid-template-columns: 240px 1fr;
|
||||
min-height: 100vh;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background: #2c3e50;
|
||||
padding: 20px;
|
||||
position: fixed;
|
||||
width: 240px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.brand {
|
||||
color: white;
|
||||
font-size: 1.5rem;
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #34495e;
|
||||
}
|
||||
|
||||
.sidebar nav a {
|
||||
display: block;
|
||||
color: #bdc3c7;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin: 8px 0;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.sidebar nav a:hover {
|
||||
background: #34495e;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sidebar nav a.active {
|
||||
background: #3498db;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.content-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
background: white;
|
||||
padding: 8px 15px;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #2c3e50;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #3498db;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #3498db;
|
||||
color: white;
|
||||
padding: 12px 25px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
.hint {
|
||||
color: #7f8c8d;
|
||||
font-size: 0.9em;
|
||||
margin-top: 8px;
|
||||
}
|
48
assets/css/auth.css
Normal file
48
assets/css/auth.css
Normal file
@ -0,0 +1,48 @@
|
||||
.auth-container {
|
||||
background: linear-gradient(135deg, #6366f1 0%, #a855f7 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.auth-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 1rem;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
|
||||
overflow: hidden;
|
||||
max-width: 400px;
|
||||
margin: 0 auto;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.auth-card:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.auth-input-group {
|
||||
position: relative;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.auth-input {
|
||||
width: 100%;
|
||||
padding: 1rem 1rem 1rem 3rem;
|
||||
border: 2px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 1rem;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
.auth-input:focus {
|
||||
border-color: #6366f1;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.auth-icon {
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #6b7280;
|
||||
}
|
0
assets/css/main.css
Normal file
0
assets/css/main.css
Normal file
106
assets/css/style.css
Normal file
106
assets/css/style.css
Normal file
@ -0,0 +1,106 @@
|
||||
/* 通用样式 */
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
margin: 0;
|
||||
background: #f0f2f5;
|
||||
}
|
||||
|
||||
/* 登录页面 */
|
||||
.login-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
.login-box {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.error-msg {
|
||||
color: #dc3545;
|
||||
margin: 1rem 0;
|
||||
padding: 0.5rem;
|
||||
background: #f8d7da;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.form-group input {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
margin: 8px 0;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 6px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-group input:focus {
|
||||
border-color: #667eea;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* 管理后台 */
|
||||
.admin-container {
|
||||
max-width: 1200px;
|
||||
margin: 2rem auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
background: #dc3545;
|
||||
padding: 8px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
select, textarea {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.success-msg {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 6px;
|
||||
}
|
0
assets/js/main.js
Normal file
0
assets/js/main.js
Normal file
79
includes/api_functions.php
Normal file
79
includes/api_functions.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// 参数验证函数
|
||||
function validateRequestParams(): array {
|
||||
$allowedResolutions = ['UHD', '4K', 'HD'];
|
||||
$allowedCategories = ['美女', '风景', '动物', '游戏'];
|
||||
|
||||
// 获取并处理参数
|
||||
$params = [
|
||||
'resolution' => isset($_GET['resolution'])
|
||||
? strtoupper(trim($_GET['resolution']))
|
||||
: null,
|
||||
'category' => isset($_GET['category'])
|
||||
? urldecode(trim($_GET['category']))
|
||||
: null
|
||||
];
|
||||
|
||||
// 验证分辨率参数
|
||||
if ($params['resolution'] && !in_array($params['resolution'], $allowedResolutions, true)) {
|
||||
throw new InvalidArgumentException('无效的分辨率参数');
|
||||
}
|
||||
|
||||
// 验证分类参数
|
||||
if ($params['category'] && !in_array($params['category'], $allowedCategories, true)) {
|
||||
throw new InvalidArgumentException('无效的分类参数');
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
// 构建图片查询语句
|
||||
function buildImageQuery(array $params): string {
|
||||
$query = "SELECT url FROM images WHERE 1=1";
|
||||
|
||||
if ($params['resolution']) {
|
||||
$query .= " AND resolution = :resolution";
|
||||
}
|
||||
|
||||
if ($params['category']) {
|
||||
$query .= " AND category = :category";
|
||||
}
|
||||
|
||||
$query .= " ORDER BY RAND() LIMIT 1";
|
||||
return $query;
|
||||
}
|
||||
|
||||
// 获取随机图片
|
||||
function fetchRandomImage(PDO $pdo, string $query, array $params) {
|
||||
$stmt = $pdo->prepare($query);
|
||||
|
||||
if ($params['resolution']) {
|
||||
$stmt->bindValue(':resolution', $params['resolution']);
|
||||
}
|
||||
|
||||
if ($params['category']) {
|
||||
$stmt->bindValue(':category', $params['category']);
|
||||
}
|
||||
|
||||
$stmt->execute();
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
// 标准化JSON响应
|
||||
function jsonResponse(array $data): string {
|
||||
return json_encode([
|
||||
'code' => 200,
|
||||
'data' => $data
|
||||
], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
// 错误响应格式化
|
||||
function jsonError(string $message, int $code = 400): string {
|
||||
http_response_code($code);
|
||||
return json_encode([
|
||||
'code' => $code,
|
||||
'error' => $message
|
||||
], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
||||
}
|
33
includes/auth.php
Normal file
33
includes/auth.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__.'/db.php';
|
||||
|
||||
// 登录状态检查
|
||||
function isLoggedIn() {
|
||||
return isset($_SESSION['user_id']);
|
||||
}
|
||||
|
||||
// 登录验证
|
||||
function login($username, $password) {
|
||||
global $pdo;
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
|
||||
$stmt->execute([$username]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
// SHA256验证
|
||||
if ($user && hash('sha256', $password) === $user['password']) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 强制登录检查
|
||||
function requireLogin() {
|
||||
if (!isLoggedIn()) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
}
|
17
includes/config.php
Normal file
17
includes/config.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// 禁止直接访问
|
||||
defined('APP_ROOT') or define('APP_ROOT', dirname(__DIR__));
|
||||
|
||||
// 调试模式设置
|
||||
define('DEBUG_MODE', true);
|
||||
|
||||
// 错误报告设置
|
||||
if (DEBUG_MODE) {
|
||||
ini_set('display_errors', '1');
|
||||
ini_set('display_startup_errors', '1');
|
||||
error_reporting(E_ALL);
|
||||
} else {
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('log_errors', '1');
|
||||
ini_set('error_log', APP_ROOT.'/logs/error.log');
|
||||
}
|
19
includes/db.php
Normal file
19
includes/db.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
$host = 'localhost';
|
||||
$dbname = 'localhost';
|
||||
$user = 'localhost';
|
||||
$pass = 'localhost';
|
||||
|
||||
try {
|
||||
$pdo = new PDO(
|
||||
"mysql:host=$host;dbname=$dbname;charset=utf8mb4",
|
||||
$user,
|
||||
$pass,
|
||||
[
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
|
||||
]
|
||||
);
|
||||
} catch (PDOException $e) {
|
||||
die("数据库连接失败: " . $e->getMessage());
|
||||
}
|
Reference in New Issue
Block a user