Files
leonapp/api.php
Leonmmcoset a6ed9fd1cb refactor: 移除收藏功能及相关代码
删除用户收藏表及相关SQL定义
移除前端收藏按钮及JavaScript逻辑
清理API中收藏相关接口
更新README文档移除收藏功能说明
2025-07-15 18:08:39 +08:00

551 lines
20 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
session_start();
require_once 'config.php';
header('Content-Type: application/json');
$requestMethod = $_SERVER['REQUEST_METHOD'];
// API根路径处理 - 返回可用端点信息
if (!isset($_GET['action']) || $_GET['action'] === '') {
http_response_code(200);
echo json_encode([
'status' => 'success',
'message' => 'App Store API',
'version' => '1.0',
'endpoints' => [
'/api?action=list' => '获取应用列表支持search、platform、age_rating、tag、page、limit参数。search搜索关键词platform平台age_rating年龄分级tag标签page页码limit每页数量',
'/api?action=app&id=1' => '获取指定ID的应用详情需传入app_id参数。包含应用基础信息、版本、图片、评价和标签信息',
],
'example' => 'GET /api?action=list&search=游戏&limit=10'
]);
exit;
}
// 支持查询参数路由模式不依赖URL重写
// 以下为各API端点详细处理逻辑
if (isset($_GET['action'])) {
$action = $_GET['action'];
// 处理应用列表请求,支持多条件筛选和分页查询
// 参数:
// search - 搜索关键词,可选
// platform - 平台,可选
// age_rating - 年龄分级,可选
// tag - 标签,可选
// page - 页码可选默认1
// limit - 每页数量可选默认10
// 方法: GET
if ($action === 'list' && $requestMethod === 'GET') {
$sql = "SELECT apps.id, apps.name, apps.description, apps.age_rating, AVG(reviews.rating) as avg_rating
FROM apps
LEFT JOIN reviews ON apps.id = reviews.app_id";
$conditions = [];
$stmtParams = [];
$paramTypes = '';
// 搜索功能
if (isset($_GET['search'])) {
$search = '%' . $_GET['search'] . '%';
$conditions[] = "(apps.name LIKE ? OR apps.description LIKE ?)";
$stmtParams[] = &$search;
$stmtParams[] = &$search;
$paramTypes .= 'ss';
}
// 平台过滤
if (isset($_GET['platform'])) {
$platform = $_GET['platform'];
// Removed platform condition - column does not exist
$stmtParams[] = &$platform;
$paramTypes .= 's';
}
// 年龄分级过滤
if (isset($_GET['age_rating'])) {
$ageRating = $_GET['age_rating'];
$conditions[] = "apps.age_rating = ?";
$stmtParams[] = &$ageRating;
$paramTypes .= 's';
}
// 标签过滤
if (isset($_GET['tag'])) {
$tag = $_GET['tag'];
$conditions[] = "apps.id IN (SELECT app_id FROM app_tags JOIN tags ON app_tags.tag_id = tags.id WHERE tags.name = ?)";
$stmtParams[] = &$tag;
$paramTypes .= 's';
}
// 分页参数处理
$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
$limit = isset($_GET['limit']) ? min(100, max(1, intval($_GET['limit']))) : 10;
$offset = ($page - 1) * $limit;
if (!empty($conditions)) {
$sql .= " WHERE " . implode(" AND ", $conditions);
}
// 添加分页
$sql .= " GROUP BY apps.id, apps.name, apps.description, apps.age_rating ORDER BY apps.created_at DESC LIMIT ? OFFSET ?";
$stmtParams[] = &$limit;
$stmtParams[] = &$offset;
$paramTypes .= 'ii';
// 获取总数用于分页元数据
$countSql = "SELECT COUNT(DISTINCT apps.id) as total FROM apps LEFT JOIN reviews ON apps.id = reviews.app_id";
if (!empty($conditions)) {
$countSql .= " WHERE " . implode(" AND ", $conditions);
}
$countStmt = $conn->prepare($countSql);
if ($paramTypes && count($stmtParams) > 2) {
// 排除最后两个分页参数
$countParams = array_slice($stmtParams, 0, -2);
$countTypes = substr($paramTypes, 0, -2);
call_user_func_array([$countStmt, 'bind_param'], array_merge([$countTypes], $countParams));
}
$countStmt->execute();
$countResult = $countStmt->get_result();
$total = $countResult->fetch_assoc()['total'] ?? 0;
$totalPages = ceil($total / $limit);
// 执行主查询
$stmt = $conn->prepare($sql);
if (!$stmt) {
http_response_code(500);
echo json_encode(['error' => 'Database error: ' . $conn->error]);
exit;
}
call_user_func_array([$stmt, 'bind_param'], array_merge([$paramTypes], $stmtParams));
$stmt->execute();
$result = $stmt->get_result();
$apps = [];
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$apps[] = $row;
}
}
// 返回带分页元数据的响应
echo json_encode([
'data' => $apps,
'pagination' => [
'total' => $total,
'page' => $page,
'limit' => $limit,
'totalPages' => $totalPages
]
]);
exit;
}
// 处理应用详情请求获取指定ID应用的详细信息包含基础信息、版本、图片、评价和标签信息
// 参数: id - 应用ID必需数字类型
// 方法: GET
elseif ($action === 'app' && isset($_GET['id']) && is_numeric($_GET['id']) && $requestMethod === 'GET') {
$appId = $_GET['id'];
error_log("Requesting app details for ID: $appId");
$sqlApp = "SELECT apps.id, apps.name, apps.description, apps.age_rating, apps.created_at, AVG(reviews.rating) as avg_rating
FROM apps
LEFT JOIN reviews ON apps.id = reviews.app_id
WHERE apps.id = ?
GROUP BY apps.id, apps.name, apps.description, apps.age_rating, apps.created_at";
$stmt = $conn->prepare($sqlApp);
$stmt->bind_param("i", $appId);
$stmt->execute();
$resultApp = $stmt->get_result();
error_log("Executing prepared statement for app details");
if (!$resultApp) {
error_log("Database error: " . $conn->error);
http_response_code(500);
echo json_encode(['error' => 'Database query failed']);
exit;
}
$app = $resultApp->fetch_assoc();
error_log("App found: " . ($app ? "Yes" : "No"));
if ($app) {
// 获取版本信息
$sqlVersions = "SELECT * FROM app_versions WHERE app_id = $appId ORDER BY created_at DESC";
$resultVersions = $conn->query($sqlVersions);
$versions = [];
while ($version = $resultVersions->fetch_assoc()) {
$versions[] = $version;
}
$app['versions'] = $versions;
// 获取图片信息
$sqlImages = "SELECT * FROM app_images WHERE app_id = $appId";
$resultImages = $conn->query($sqlImages);
$images = [];
while ($image = $resultImages->fetch_assoc()) {
$images[] = $image;
}
$app['images'] = $images;
// 获取评价信息
$sqlReviews = "SELECT * FROM reviews WHERE app_id = $appId ORDER BY created_at DESC";
$resultReviews = $conn->query($sqlReviews);
$reviews = [];
while ($review = $resultReviews->fetch_assoc()) {
$reviews[] = $review;
}
$app['reviews'] = $reviews;
// 获取应用标签
$sqlTags = "SELECT tags.id, tags.name FROM app_tags JOIN tags ON app_tags.tag_id = tags.id WHERE app_tags.app_id = ?";
$stmtTags = $conn->prepare($sqlTags);
$stmtTags->bind_param("i", $appId);
$stmtTags->execute();
$resultTags = $stmtTags->get_result();
$tags = [];
while ($tag = $resultTags->fetch_assoc()) {
$tags[] = $tag;
}
$app['tags'] = $tags;
echo json_encode($app);
} else {
http_response_code(404);
echo json_encode(['error' => "App with ID $appId not found", 'sql' => $sqlApp]);
}
exit;
}
// 获取所有标签
elseif ($action === 'tags' && $requestMethod === 'GET') {
$sql = "SELECT id, name FROM tags ORDER BY name";
$result = $conn->query($sql);
$tags = [];
while ($row = $result->fetch_assoc()) {
$tags[] = $row;
}
echo json_encode($tags);
exit;
}
// 获取应用推荐列表
elseif ($action === 'recommendations' && $requestMethod === 'GET') {
$sql = "SELECT apps.*, app_recommendations.reason FROM app_recommendations JOIN apps ON app_recommendations.app_id = apps.id";
$result = $conn->query($sql);
$recommendations = [];
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$recommendations[] = $row;
}
}
echo json_encode($recommendations);
exit;
}
// 获取热门应用排行榜
elseif ($action === 'hot_apps' && $requestMethod === 'GET') {
$sql = "SELECT apps.*, SUM(app_versions.download_count) as total_downloads FROM apps JOIN app_versions ON apps.id = app_versions.app_id GROUP BY apps.id ORDER BY total_downloads DESC LIMIT 10";
$result = $conn->query($sql);
$hotApps = [];
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$hotApps[] = $row;
}
}
echo json_encode($hotApps);
exit;
}
// 提交用户反馈
elseif ($action === 'feedback' && isset($_GET['user_id']) && is_numeric($_GET['user_id']) && $requestMethod === 'POST') {
$userId = $_GET['user_id'];
$appId = isset($_GET['app_id']) && is_numeric($_GET['app_id']) ? $_GET['app_id'] : null;
$content = $_POST['content'] ?? '';
if (empty($content)) {
http_response_code(400);
echo json_encode(['error' => 'Feedback content is required']);
exit;
}
$stmt = $conn->prepare("INSERT INTO user_feedback (user_id, app_id, content) VALUES (?, ?, ?)");
$stmt->bind_param("iis", $userId, $appId, $content);
if ($stmt->execute()) {
echo json_encode(['status' => 'success', 'message' => 'Feedback submitted successfully']);
} else {
http_response_code(500);
echo json_encode(['error' => 'Failed to submit feedback']);
}
$stmt->close();
exit;
}
// 处理下载请求
elseif ($action === 'download' && isset($_GET['version_id']) && is_numeric($_GET['version_id']) && $requestMethod === 'GET') {
$versionId = $_GET['version_id'];
$stmt = $conn->prepare("SELECT * FROM app_versions WHERE id = ?");
$stmt->bind_param("i", $versionId);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
$version = $result->fetch_assoc();
// 更新下载计数
$updateStmt = $conn->prepare("UPDATE app_versions SET download_count = download_count + 1 WHERE id = ?");
$updateStmt->bind_param("i", $versionId);
$updateStmt->execute();
$updateStmt->close();
$filePath = $version['file_path'];
if (file_exists($filePath)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
exit;
} else {
http_response_code(404);
echo json_encode(['error' => 'File not found']);
}
} else {
http_response_code(404);
echo json_encode(['error' => 'Version not found']);
}
$stmt->close();
exit;
}
// 获取公告列表(支持分页)
elseif ($action === 'announcements' && $requestMethod === 'GET') {
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
$perPage = isset($_GET['per_page']) && is_numeric($_GET['per_page']) ? (int)$_GET['per_page'] : 10;
$offset = ($page - 1) * $perPage;
// 获取总数
$countSql = "SELECT COUNT(*) as total FROM announcements";
$countResult = $conn->query($countSql);
$total = $countResult->fetch_assoc()['total'];
// 获取分页数据
$sql = "SELECT * FROM announcements ORDER BY created_at DESC LIMIT ?, ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ii", $offset, $perPage);
$stmt->execute();
$result = $stmt->get_result();
$announcements = [];
while ($row = $result->fetch_assoc()) {
$announcements[] = $row;
}
// 返回分页数据和元信息
echo json_encode([
'data' => $announcements,
'pagination' => [
'total' => $total,
'page' => $page,
'per_page' => $perPage,
'total_pages' => ceil($total / $perPage)
]
]);
$stmt->close();
exit;
}
// 获取最新公告
elseif ($action === 'latest_announcement' && $requestMethod === 'GET') {
$sql = "SELECT * FROM announcements ORDER BY created_at DESC LIMIT 1";
$result = $conn->query($sql);
$announcement = $result->fetch_assoc();
echo json_encode($announcement);
exit;
}
// 添加公告
elseif ($action === 'add_announcement' && $requestMethod === 'POST') {
if (!isset($_SESSION['admin']['id'])) {
http_response_code(403);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
$title = $_POST['title'] ?? '';
$content = $_POST['content'] ?? '';
$adminId = $_SESSION['admin']['id'];
if (empty($title) || empty($content)) {
http_response_code(400);
echo json_encode(['error' => 'Title and content are required']);
exit;
}
$stmt = $conn->prepare("INSERT INTO announcements (title, content, admin_id) VALUES (?, ?, ?)");
$stmt->bind_param("ssi", $title, $content, $adminId);
if ($stmt->execute()) {
echo json_encode(['status' => 'success', 'message' => 'Announcement added successfully']);
} else {
http_response_code(500);
echo json_encode(['error' => 'Failed to add announcement']);
}
$stmt->close();
exit;
}
// 删除公告
elseif ($action === 'delete_announcement' && isset($_GET['id']) && is_numeric($_GET['id']) && $requestMethod === 'DELETE') {
if (!isset($_SESSION['admin']['id'])) {
http_response_code(403);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
$id = $_GET['id'];
$stmt = $conn->prepare("DELETE FROM announcements WHERE id = ?");
$stmt->bind_param("i", $id);
if ($stmt->execute()) {
echo json_encode(['status' => 'success', 'message' => 'Announcement deleted successfully']);
} else {
http_response_code(500);
echo json_encode(['error' => 'Failed to delete announcement']);
}
$stmt->close();
exit;
}
// 更新公告
elseif ($action === 'update_announcement' && isset($_GET['id']) && is_numeric($_GET['id']) && $requestMethod === 'PUT') {
if (!isset($_SESSION['admin']['id'])) {
http_response_code(403);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
parse_str(file_get_contents('php://input'), $putData);
$id = $_GET['id'];
$title = $putData['title'] ?? '';
$content = $putData['content'] ?? '';
if (empty($title) || empty($content)) {
http_response_code(400);
echo json_encode(['error' => 'Title and content are required']);
exit;
}
$stmt = $conn->prepare("UPDATE announcements SET title = ?, content = ? WHERE id = ?");
$stmt->bind_param("ssi", $title, $content, $id);
if ($stmt->execute()) {
echo json_encode(['status' => 'success', 'message' => 'Announcement updated successfully']);
} else {
http_response_code(500);
echo json_encode(['error' => 'Failed to update announcement']);
}
$stmt->close();
exit;
}
// 无效操作
else {
http_response_code(400);
echo json_encode(['error' => 'Invalid action or parameters']);
exit;
}
}
// 保留原路径路由逻辑作为兼容 fallback
$requestUri = $_SERVER['REQUEST_URI'];
$path = parse_url($requestUri, PHP_URL_PATH);
$path = preg_replace('/\.php$/', '', $path);
$pathParts = explode('/', trim($path, '/'));
error_log("Path parts: " . print_r($pathParts, true));
if ($pathParts[0] === 'api') {
error_log("Processing API path request: " . print_r($pathParts, true));
// 处理应用详情请求 /api/app/<id>
if (count($pathParts) >= 3 && $pathParts[1] === 'app' && is_numeric($pathParts[2])) {
$appId = $pathParts[2];
error_log("Path-based app details request for ID: $appId");
$sqlApp = "SELECT apps.id, apps.name, apps.description, apps.age_rating, apps.platform, apps.created_at, AVG(reviews.rating) as avg_rating
FROM apps
LEFT JOIN reviews ON apps.id = reviews.app_id
WHERE apps.id = ?
GROUP BY apps.id, apps.name, apps.description, apps.age_rating, apps.platform, apps.created_at";
$stmt = $conn->prepare($sqlApp);
$stmt->bind_param("i", $appId);
$stmt->execute();
$resultApp = $stmt->get_result();
error_log("Executing prepared statement for path-based app details");
if (!$resultApp) {
error_log("Database error: " . $conn->error);
http_response_code(500);
echo json_encode(['error' => 'Database query failed']);
exit;
}
$app = $resultApp->fetch_assoc();
error_log("App found via path: " . ($app ? "Yes" : "No"));
if ($app) {
// 获取版本信息
$sqlVersions = "SELECT * FROM app_versions WHERE app_id = $appId ORDER BY created_at DESC";
$resultVersions = $conn->query($sqlVersions);
$versions = [];
while ($version = $resultVersions->fetch_assoc()) {
$versions[] = $version;
}
$app['versions'] = $versions;
// 获取图片信息
$sqlImages = "SELECT * FROM app_images WHERE app_id = $appId";
$resultImages = $conn->query($sqlImages);
$images = [];
while ($image = $resultImages->fetch_assoc()) {
$images[] = $image;
}
$app['images'] = $images;
// 获取评价信息
$sqlReviews = "SELECT * FROM reviews WHERE app_id = $appId ORDER BY created_at DESC";
$resultReviews = $conn->query($sqlReviews);
$reviews = [];
while ($review = $resultReviews->fetch_assoc()) {
$reviews[] = $review;
}
$app['reviews'] = $reviews;
echo json_encode($app);
} else {
http_response_code(404);
echo json_encode([
'error' => 'Not found',
'path' => $path,
'path_parts' => $pathParts,
'action' => isset($_GET['action']) ? $_GET['action'] : null
]);
}
exit;
}
// 处理其他API路径请求...
}
http_response_code(404);
echo json_encode([
'error' => 'Not found',
'path' => $path,
'path_parts' => $pathParts,
'action' => isset($_GET['action']) ? $_GET['action'] : null
]);
?>