1
0

first commit

This commit is contained in:
Snowz 2025-04-14 16:50:30 +08:00
commit c827a784dd
19 changed files with 746 additions and 0 deletions

1
.htaccess Normal file
View File

@ -0,0 +1 @@

26
404.html Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

106
assets/css/style.css Normal file
View 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
View File

View 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
View 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
View 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
View 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());
}