时间胶囊项目 API 调用信息

时间胶囊 是一个用于存储和展示照片回忆的 Web 应用。前端通过 JavaScript (script.js 和 admin.js) 调用后端 API (photos.php 和 admin.php),实现照片的展示、管理、添加和删除功能。本文档详细描述了所有 API 调用的信息,包括端点、方法、参数、响应格式和使用场景。

当前日期:2025年3月14日
作者:鸭鸭
版本:1.0

项目结构
前端文件:

  • index.html:照片展示页面,调用 api/photos.php 获取照片列表。
  • assets/js/script.js:前端逻辑,处理照片展示和模态框交互。
  • admin.html:管理页面,调用 api/admin.php 进行登录、照片管理和删除。
  • assets/js/admin.js:管理页面的前端逻辑。

后端文件:

  • api/photos.php:提供照片列表 API。
  • api/admin.php:提供登录、照片管理(添加、删除、查询)等 API。
  • api/config.php:数据库配置和连接。

API 调用详情

  1. 获取照片列表 (index.html 和 admin.html)

1.1 获取所有照片 (index.html 调用)
端点:/api/photos.php
方法:GET
参数:无
请求示例:
fetch('/api/photos.php')

.then(response => response.json())
.then(data => {
    if (data.success) {
        renderPhotos(data.data);
    } else {
        gallery.innerHTML = `<p class="error">加载照片失败: ${data.message}</p>`;
    }
});

响应格式:
成功:
{

"success": true,
"data": [
    {
        "id": 1,
        "url": "https://example.com/photo1.jpg",
        "title": "回忆1",
        "username": "admin",
        "created_at": "2025-03-14 10:00:00"
    },
    {
        "id": 2,
        "url": "https://example.com/photo2.jpg",
        "title": "回忆2",
        "username": "admin",
        "created_at": "2025-03-14 11:00:00"
    }
]

}
失败:
{

"success": false,
"message": "数据库连接失败,请检查配置"

}
使用场景:
在 index.html 页面加载时,获取所有照片并渲染到画廊中。
用户点击照片时,显示模态框,展示照片详情(标题、上传时间和上传者)。

1.2 获取所有照片 (admin.html 调用)
端点:/api/admin.php
方法:GET
参数:无
请求头:
credentials: 'include':携带会话 cookie 以验证登录状态。
请求示例:
fetch('/api/admin.php', { credentials: 'include' })

.then(response => response.json())
.then(data => {
    if (data.success) {
        renderPhotos(data.data);
    } else {
        photoList.innerHTML = `<li class="error">${data.message}</li>`;
    }
});

响应格式:
成功:与 photos.php 相同。
未登录:
{

"success": false,
"message": "未登录"

}
失败:
{

"success": false,
"message": "数据库连接失败,请检查配置"

}
使用场景:
在 admin.html 登录后,获取所有照片并渲染到管理页面,供管理员查看和删除,显示照片详情(包括上传者)。

  1. 管理员登录 (admin.html)
    端点:/api/admin.php
    方法:POST
    参数:
    action:login(固定值)
    password:管理员密码(经过 SHA-256 哈希)
    csrf_token:CSRF 令牌
    请求头:
    credentials: 'include':携带会话 cookie。
    请求示例:
    const password = document.getElementById('password').value;
    const hashedPassword = await hashPassword(password);
    const formData = new FormData();
    formData.append('action', 'login');
    formData.append('password', hashedPassword);
    formData.append('csrf_token', csrfToken);

fetch('/api/admin.php', {

method: 'POST',
body: formData,
credentials: 'include'

})

.then(response => response.json())
.then(data => {
    if (data.success) {
        loginFormDiv.style.display = 'none';
        adminContent.style.display = 'block';
        loadPhotos();
    } else {
        loginMessage.textContent = data.message;
        loginMessage.className = 'message error';
    }
});

响应格式:
成功:
{

"success": true,
"message": "登录成功"

}
失败:
{

"success": false,
"message": "密码错误"

}
速率限制:
{

"success": false,
"message": "登录尝试过于频繁,请稍后再试"

}
CSRF 失败:
{

"success": false,
"message": "CSRF 验证失败"

}
使用场景:
管理员在 admin.html 输入密码登录,成功后显示照片管理界面。

  1. 检查登录状态 (admin.html)
    端点:/api/admin.php?check_login=true
    方法:GET
    参数:
    check_login:true(固定值)
    请求头:
    credentials: 'include':携带会话 cookie。
    请求示例:
    fetch('/api/admin.php?check_login=true', { credentials: 'include' })
    .then(response => response.json())
    .then(data => {

     if (data.success && data.logged_in) {
         loginFormDiv.style.display = 'none';
         adminContent.style.display = 'block';
         loadPhotos();
     } else {
         loginFormDiv.style.display = 'block';
         adminContent.style.display = 'none';
     }

    });
    响应格式:
    已登录:
    {
    "success": true,
    "logged_in": true
    }
    未登录:
    {
    "success": true,
    "logged_in": false
    }
    使用场景:
    页面加载时检查管理员是否已登录,决定显示登录表单还是管理界面。

  2. 添加照片 (admin.html)
    端点:/api/admin.php
    方法:POST
    参数:
    action:add(固定值)
    url:照片 URL(字符串,必填)

    • 支持格式:
    • 普通 URL(例如 https://example.com/photo.jpg)
    • VRChat fileId(以 file_ 开头,例如 file_12345,会通过 getPhotoUrlFromApi 解析为实际 URL)

    title:照片标题(字符串,可选)
    csrf_token:CSRF 令牌
    请求头:
    credentials: 'include':携带会话 cookie。
    请求示例:
    const formData = new FormData();
    formData.append('action', 'add');
    formData.append('url', document.getElementById('url').value); // 支持 file_12345 或 https://example.com/photo.jpg
    formData.append('title', document.getElementById('title').value);
    formData.append('csrf_token', csrfToken);

fetch('/api/admin.php', {

method: 'POST',
body: formData,
credentials: 'include'

})

.then(response => response.json())
.then(data => {
    if (data.success) {
        message.textContent = '添加成功!';
        message.className = 'message success';
        document.getElementById('url').value = '';
        document.getElementById('title').value = '';
        loadPhotos();
    } else {
        message.textContent = data.message;
        message.className = 'message error';
    }
});

响应格式:
成功:
{

"success": true,
"message": "添加成功"

}
失败:
{

"success": false,
"message": "URL 不能为空"

}

{

"success": false,
"message": "无效的 URL 格式"

}

{

"success": false,
"message": "通过 fileId 获取照片 URL 失败"

}
未登录:
{

"success": false,
"message": "未登录"

}
CSRF 失败:
{

"success": false,
"message": "CSRF 验证失败"

}
使用场景:
管理员在 admin.html 提交照片 URL(支持普通 URL 或 VRChat fileId)和标题,添加到数据库并刷新照片列表。

  1. 删除照片 (admin.html)
    端点:/api/admin.php?id={id}
    方法:DELETE
    参数:
    id:照片 ID(查询参数,必填)
    请求头:
    credentials: 'include':携带会话 cookie。
    X-CSRF-Token:CSRF 令牌
    请求示例:
    fetch(/api/admin.php?id=${id}, {
    method: 'DELETE',
    credentials: 'include',
    headers: {

     'X-CSRF-Token': csrfToken

    }
    })
    .then(response => response.json())
    .then(data => {

     if (data.success) {
         message.textContent = '删除成功!';
         message.className = 'message success';
         loadPhotos();
     } else {
         message.textContent = data.message;
         message.className = 'message error';
     }

    });
    响应格式:
    成功:
    {
    "success": true,
    "message": "删除成功"
    }
    未登录:
    {
    "success": false,
    "message": "未登录"
    }
    CSRF 失败:
    {
    "success": false,
    "message": "CSRF 验证失败"
    }
    使用场景:
    管理员在 admin.html 点击“删除”按钮,删除指定照片并刷新列表。

  2. 退出登录 (admin.html)
    端点:/api/admin.php
    方法:POST
    参数:
    action:logout(固定值)
    csrf_token:CSRF 令牌
    请求头:
    credentials: 'include':携带会话 cookie。
    请求示例:
    fetch('/api/admin.php', {
    method: 'POST',
    body: new URLSearchParams({ action: 'logout', csrf_token: csrfToken }),
    credentials: 'include'
    })
    .then(response => response.json())
    .then(data => {

     if (data.success) {
         checkLoginStatus();
     }

    });
    响应格式:
    成功:
    {
    "success": true,
    "message": "已退出登录"
    }
    CSRF 失败:
    {
    "success": false,
    "message": "CSRF 验证失败"
    }
    使用场景:
    管理员在 admin.html 点击“退出登录”,销毁会话并返回登录页面。

  3. 获取 CSRF 令牌 (admin.html)
    端点:/api/admin.php?get_csrf=true
    方法:GET
    参数:
    get_csrf:true(固定值)
    请求头:
    credentials: 'include':携带会话 cookie。
    请求示例:
    fetch('/api/admin.php?get_csrf=true', { credentials: 'include' })
    .then(response => response.json())
    .then(data => {

     if (data.success) {
         csrfToken = data.csrf_token;
     }

    });
    响应格式:
    成功:
    {
    "success": true,
    "csrf_token": "abc123..."
    }
    使用场景:
    页面加载时获取 CSRF 令牌,用于后续 POST 和 DELETE 请求的验证。

安全机制

  1. CSRF 保护:

    • 所有 POST 和 DELETE 请求需要携带 CSRF 令牌(csrf_token),通过 admin.php?get_csrf=true 获取。
  2. 会话安全:

    • 会话 cookie 设置了 HttpOnly, Secure, 和 SameSite=Strict。
    • 会话超时:30 分钟(1800 秒)。
  3. 速率限制:

    • 登录接口限制 5 次失败尝试后锁定 15 分钟(900 秒)。
  4. XSS 防护:

    • 前端使用 textContent 渲染用户输入(photo.title),防止脚本注入。
  5. CORS 限制:

  6. 密码保护:

    • 管理员密码在前端通过 SHA-256 哈希后传输,后端验证哈希值。

注意事项

  1. HTTPS 要求:

    • 确保服务器使用 HTTPS,否则密码和会话 cookie 可能被拦截。
  2. 环境变量:

    • 数据库凭据和管理员密码应存储在环境变量中,避免硬编码。
  3. 数据库配置:

    • 确保 api/config.php 中的 DB_HOST, DB_USER, DB_PASS, DB_NAME 正确。
  4. 依赖:

    • 后端需要安装 APCu 扩展(用于速率限制)。
    • 确保 PHP 支持 PDO 和 MySQL 扩展。

未来改进建议

  1. 前后端分离:

    • 当前 API 和前端在同一域名下运行,未来可考虑前后端分离,使用更现代的框架(如 React 或 Vue)重构前端。
  2. API 文档:

    • 使用工具(如 Swagger)生成更正式的 API 文档。
  3. 日志系统:

    • 增强日志记录,跟踪所有 API 调用和错误,便于调试和审计。
  4. 用户权限:

    • 当前仅支持单一管理员,未来可添加多用户支持和权限管理。