commit bc0223bf0706e81fd59905c274eacff69a86540c Author: 无闻风 Date: Wed Jun 24 17:45:24 2026 +0800 init diff --git a/.claude/plan.md b/.claude/plan.md new file mode 100644 index 0000000..c1bae7f --- /dev/null +++ b/.claude/plan.md @@ -0,0 +1,231 @@ +# 软件发布平台完善计划 + +## 项目目标 +将现有的简单下载页面升级为功能完整的软件发布平台,包含后端管理、版本管理和配置系统。 + +## 技术方案 + +### 数据库选择 +- 使用 **SQLite** 作为文件数据库(轻量、无需额外配置) +- 数据库文件路径:`data/database.db` + +### 数据库设计 + +**apps 表** - 存储应用版本信息 +```sql +CREATE TABLE apps ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + filename TEXT NOT NULL, + original_name TEXT NOT NULL, + version TEXT, + description TEXT, + upload_time DATETIME DEFAULT CURRENT_TIMESTAMP, + file_size INTEGER +); +``` + +**config 表** - 存储网站配置 +```sql +CREATE TABLE config ( + key TEXT PRIMARY KEY, + value TEXT +); +``` + +预设配置项: +- `site_title` - 网站标题(默认:"OPS 运营管理系统") +- `site_description` - 软件说明(默认:"点击下方按钮下载移动端 APP") +- `logo_path` - Logo 路径(默认:"logo.png") + +### 目录结构 + +``` +php_app_downloader/ +├── index.php # 主页(显示所有版本) +├── download.php # 下载接口(支持按ID下载) +├── logo.png # 默认 Logo +├── admin/ # 管理后端目录 +│ ├── index.php # 登录页面 +│ ├── dashboard.php # 管理面板主页 +│ ├── upload.php # 文件上传处理 +│ ├── config.php # 配置管理页面 +│ ├── delete.php # 删除应用接口 +│ ├── logout.php # 登出 +│ └── auth.php # 认证中间件 +├── includes/ # 共享代码 +│ ├── db.php # 数据库连接和初始化 +│ └── functions.php # 通用函数 +├── data/ # 数据存储目录 +│ ├── apps/ # 上传的 APK 文件 +│ ├── uploads/ # 上传的 Logo +│ └── database.db # SQLite 数据库 +└── assets/ # 静态资源 + └── admin.css # 管理后台样式 +``` + +## 实现步骤 + +### 1. 创建基础设施(includes/) + +#### 1.1 数据库连接(includes/db.php) +- 创建 SQLite 连接 +- 自动初始化数据库结构(如果不存在) +- 插入默认配置数据 + +#### 1.2 通用函数(includes/functions.php) +- `getConfig($key)` - 获取配置 +- `updateConfig($key, $value)` - 更新配置 +- `formatFileSize($bytes)` - 格式化文件大小 +- `isLoggedIn()` - 检查登录状态 + +### 2. 创建目录结构 +- 创建 `data/`, `data/apps/`, `data/uploads/`, `admin/`, `includes/`, `assets/` +- 设置适当的权限(777 for data/ 及子目录) + +### 3. 实现管理后端(admin/) + +#### 3.1 登录页面(admin/index.php) +- 简洁的登录表单 +- 默认用户名/密码:admin/admin +- 使用 Session 管理登录状态 +- 成功后跳转到 dashboard.php + +#### 3.2 认证中间件(admin/auth.php) +- 检查 Session 中的登录状态 +- 未登录则重定向到登录页面 +- 被其他后台页面 include + +#### 3.3 管理面板(admin/dashboard.php) +- 显示所有已上传的应用版本(表格形式) +- 上传新应用的表单(文件 + 版本号 + 描述) +- 删除应用的功能 +- 链接到配置页面 + +#### 3.4 文件上传处理(admin/upload.php) +- 接收 POST 请求 +- 验证文件类型(仅允许 .apk) +- 生成唯一文件名(时间戳_原文件名) +- 移动文件到 data/apps/ +- 插入数据库记录 +- 返回 JSON 响应或重定向 + +#### 3.5 配置管理(admin/config.php) +- 表单显示当前配置 +- 网站标题输入框 +- 软件说明文本框 +- Logo 上传(支持 jpg/png/gif) +- 保存到数据库 +- Logo 上传到 data/uploads/ 并更新配置 + +#### 3.6 删除接口(admin/delete.php) +- 接收 app ID +- 从数据库删除记录 +- 删除物理文件 +- 重定向回 dashboard + +#### 3.7 登出(admin/logout.php) +- 销毁 Session +- 重定向到登录页面 + +### 4. 更新前端 + +#### 4.1 主页(index.php) +**功能改进:** +- 从数据库读取配置(标题、说明、Logo) +- 显示所有已发布的应用版本列表(不只是最新的一个) +- 每个版本显示:版本号、描述、上传时间、文件大小 +- 最新版本在最前面(ORDER BY upload_time DESC) + +**样式重写:** +- 现代化的卡片布局 +- 响应式设计(移动端友好) +- 更好的视觉层次 +- 使用渐变背景和阴影效果 +- 每个版本一个下载按钮 + +#### 4.2 下载接口(download.php) +**功能改进:** +- 接收 `id` 参数(GET 请求) +- 从数据库查询应用信息 +- 返回文件路径用于下载 +- 保留向后兼容(如果没有 id,返回最新版本) + +### 5. 管理后台样式(assets/admin.css) +- 简洁的管理界面样式 +- 表格样式 +- 表单样式 +- 按钮和交互元素 +- 侧边栏导航(可选) + +## 安全考虑 + +1. **文件上传安全:** + - 验证文件扩展名 + - 限制文件大小 + - 使用随机文件名防止覆盖 + +2. **认证安全:** + - 使用 Session 管理 + - 密码硬编码(后续可改为数据库存储的加密密码) + +3. **SQL 注入防护:** + - 使用 PDO 预处理语句 + +4. **XSS 防护:** + - 输出时使用 htmlspecialchars() + +## 实现顺序 + +1. ✅ 创建目录结构 +2. ✅ 实现 includes/db.php(数据库初始化) +3. ✅ 实现 includes/functions.php +4. ✅ 实现 admin/index.php(登录页面) +5. ✅ 实现 admin/auth.php +6. ✅ 实现 admin/dashboard.php +7. ✅ 实现 admin/upload.php +8. ✅ 实现 admin/config.php +9. ✅ 实现 admin/delete.php +10. ✅ 实现 admin/logout.php +11. ✅ 更新 index.php(前端) +12. ✅ 更新 download.php +13. ✅ 创建 assets/admin.css +14. ✅ 测试所有功能 + +## 验证清单 + +- [ ] 可以登录管理后台(admin/admin) +- [ ] 可以上传 APK 文件 +- [ ] 上传的文件保存在 data/apps/ +- [ ] 主页显示所有版本,最新的在前 +- [ ] 可以下载各个版本 +- [ ] 可以在后台删除版本 +- [ ] 可以配置网站标题 +- [ ] 可以配置软件说明 +- [ ] 可以上传和更换 Logo +- [ ] 前端样式美观且响应式 + +## 预计文件清单 + +**新建文件:** +- admin/index.php +- admin/dashboard.php +- admin/upload.php +- admin/config.php +- admin/delete.php +- admin/logout.php +- admin/auth.php +- includes/db.php +- includes/functions.php +- assets/admin.css + +**修改文件:** +- index.php +- download.php + +**创建目录:** +- data/ +- data/apps/ +- data/uploads/ +- admin/ +- includes/ +- assets/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c51daf --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# 数据目录 - 包含上传的文件和数据库 +data/ + +# macOS +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Logs +*.log + +# Temporary files +*.tmp +*.bak +*.backup + +# Environment files +.env +.env.local diff --git a/README.md b/README.md new file mode 100644 index 0000000..2c64124 --- /dev/null +++ b/README.md @@ -0,0 +1,190 @@ +# 软件发布平台 + +一个简单易用的软件发布管理系统,支持多版本管理和在线下载。 + +## 功能特性 + +✅ **后台管理系统** +- 用户登录验证(默认用户名/密码:admin/admin) +- 上传 APK 文件到服务器 +- 版本管理(查看、删除) +- 网站配置(标题、说明、Logo) + +✅ **前端展示** +- 显示所有已发布的应用版本 +- 最新版本优先显示 +- 版本详情(版本号、描述、上传时间、文件大小) +- 一键下载功能 + +✅ **数据存储** +- 使用 SQLite 文件数据库 +- APK 文件存储在 `data/apps/` 目录 +- Logo 文件存储在 `data/uploads/` 目录 + +## 目录结构 + +``` +php_app_downloader/ +├── index.php # 主页(显示所有版本) +├── download.php # 下载接口 +├── logo.png # 默认 Logo +├── admin/ # 管理后台 +│ ├── index.php # 登录页面 +│ ├── dashboard.php # 管理面板 +│ ├── upload.php # 文件上传处理 +│ ├── config.php # 配置管理 +│ ├── delete.php # 删除应用 +│ ├── logout.php # 退出登录 +│ └── auth.php # 认证中间件 +├── includes/ # 共享代码 +│ ├── db.php # 数据库连接 +│ └── functions.php # 通用函数 +├── data/ # 数据存储(需要写权限) +│ ├── apps/ # APK 文件 +│ ├── uploads/ # 上传的 Logo +│ └── database.db # SQLite 数据库 +└── assets/ + └── admin.css # 管理后台样式 +``` + +## 使用说明 + +### 1. 环境要求 +- PHP 7.0+ +- SQLite 支持(PHP 默认包含) +- Web 服务器(Apache/Nginx) + +### 2. 安装步骤 + +1. 将项目文件上传到 Web 服务器 +2. 确保 `data/` 目录有写权限(已设置为 777) +3. 访问网站首页,数据库会自动初始化 + +### 3. 管理后台 + +访问 `/admin/` 进入管理后台 + +**默认登录信息:** +- 用户名:`admin` +- 密码:`admin` + +**功能说明:** + +#### 上传应用 +1. 在管理面板点击"上传新应用" +2. 选择 APK 文件 +3. 填写版本号(可选) +4. 填写版本描述(可选) +5. 点击"上传应用" + +#### 管理版本 +- 查看所有已发布的版本 +- 下载任意版本 +- 删除不需要的版本 + +#### 网站配置 +1. 点击"网站配置" +2. 修改网站标题 +3. 修改软件说明 +4. 上传新的 Logo(支持 JPG/PNG/GIF) +5. 点击"保存配置" + +### 4. 前端使用 + +- 访问网站首页查看所有版本 +- 点击"立即下载"按钮下载对应版本 +- 右下角有"管理后台"快捷入口 + +## 数据库结构 + +### apps 表 +存储应用版本信息 + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | INTEGER | 主键,自增 | +| filename | TEXT | 存储的文件名 | +| original_name | TEXT | 原始文件名 | +| version | TEXT | 版本号 | +| description | TEXT | 版本描述 | +| upload_time | DATETIME | 上传时间 | +| file_size | INTEGER | 文件大小(字节)| + +### config 表 +存储网站配置 + +| 字段 | 类型 | 说明 | +|------|------|------| +| key | TEXT | 配置键(主键)| +| value | TEXT | 配置值 | + +**预设配置项:** +- `site_title` - 网站标题 +- `site_description` - 软件说明 +- `logo_path` - Logo 路径 + +## API 接口 + +### 下载接口 +`GET download.php?id={app_id}` + +**参数:** +- `id` (可选) - 应用 ID,不传则返回最新版本 + +**响应示例:** +```json +{ + "success": true, + "file": "data/apps/1719223456_app.apk", + "filename": "app.apk", + "version": "1.0.0", + "date": "2024-06-24 17:30:56" +} +``` + +## 安全建议 + +1. **修改默认密码** + - 当前密码硬编码在 `admin/index.php` + - 建议修改为复杂密码 + +2. **限制文件上传** + - 当前仅允许 `.apk` 文件 + - 可根据需要调整文件类型限制 + +3. **数据备份** + - 定期备份 `data/` 目录 + - 包含数据库和所有上传的文件 + +4. **访问控制** + - 建议通过 Web 服务器配置限制 `/admin/` 访问 + - 可添加 IP 白名单 + +## 技术栈 + +- **后端:** PHP + SQLite +- **前端:** 原生 HTML/CSS/JavaScript +- **样式:** 现代化渐变设计,响应式布局 + +## 更新日志 + +### v2.0 (2024-06-24) +- ✅ 新增管理后台系统 +- ✅ 新增用户登录功能 +- ✅ 支持多版本管理 +- ✅ 支持在线上传 APK +- ✅ 支持网站配置管理 +- ✅ 重写前端样式 +- ✅ 使用 SQLite 数据库 + +### v1.0 +- 基础下载功能 +- 显示最新版本 + +## 许可证 + +MIT License + +--- + +如有问题或建议,欢迎反馈! diff --git a/admin/auth.php b/admin/auth.php new file mode 100644 index 0000000..1d3094b --- /dev/null +++ b/admin/auth.php @@ -0,0 +1,9 @@ + + + + + + + 网站配置 + + + +
+
+

网站配置

+ +
+ +
+ +
+ + + +
+ + +
+

基本设置

+
+
+ + +
+ +
+ + +
+ +
+ +
+ Logo +
+ + 支持 JPG、PNG、GIF 格式 +
+ + +
+
+
+
+ + diff --git a/admin/dashboard.php b/admin/dashboard.php new file mode 100644 index 0000000..7a64f46 --- /dev/null +++ b/admin/dashboard.php @@ -0,0 +1,91 @@ +query("SELECT * FROM apps ORDER BY upload_time DESC"); +$apps = $stmt->fetchAll(PDO::FETCH_ASSOC); +?> + + + + + + 管理面板 + + + +
+
+

管理面板

+
+ 欢迎, + 网站配置 + 退出 +
+
+ +
+
+

上传新应用

+
+
+
+ + +
+
+ + +
+
+
+ + +
+ +
+
+ +
+

已发布应用 ()

+ + +

暂无已发布的应用

+ + + + + + + + + + + + + + + + + + + + + + + + +
文件名版本描述大小上传时间操作
+ 下载 + 删除 +
+ +
+
+
+ + diff --git a/admin/delete.php b/admin/delete.php new file mode 100644 index 0000000..cfc079b --- /dev/null +++ b/admin/delete.php @@ -0,0 +1,27 @@ + 0) { + // 获取应用信息 + $stmt = $db->prepare("SELECT * FROM apps WHERE id = ?"); + $stmt->execute([$id]); + $app = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($app) { + // 删除物理文件 + $file_path = '../data/apps/' . $app['filename']; + if (file_exists($file_path)) { + unlink($file_path); + } + + // 从数据库删除 + $stmt = $db->prepare("DELETE FROM apps WHERE id = ?"); + $stmt->execute([$id]); + } +} + +header('Location: dashboard.php'); +exit; diff --git a/admin/index.php b/admin/index.php new file mode 100644 index 0000000..f248ad6 --- /dev/null +++ b/admin/index.php @@ -0,0 +1,137 @@ + + + + + + + 管理后台登录 + + + +
+

管理后台登录

+ + +
+ + +
+
+ + +
+ +
+ + +
+ + +
+
+ + diff --git a/admin/logout.php b/admin/logout.php new file mode 100644 index 0000000..f7f84cf --- /dev/null +++ b/admin/logout.php @@ -0,0 +1,7 @@ +prepare(" + INSERT INTO apps (filename, original_name, version, description, file_size) + VALUES (?, ?, ?, ?, ?) + "); + $stmt->execute([ + $filename, + $file['name'], + $version, + $description, + $file['size'] + ]); + + // 重定向回管理面板 + header('Location: dashboard.php'); + exit; +} + +// 如果不是 POST 请求,重定向回管理面板 +header('Location: dashboard.php'); +exit; diff --git a/assets/admin.css b/assets/admin.css new file mode 100644 index 0000000..4c42441 --- /dev/null +++ b/assets/admin.css @@ -0,0 +1,280 @@ +/* 管理后台样式 */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background: #f5f7fa; + color: #333; +} + +.admin-container { + min-height: 100vh; +} + +/* 头部 */ +.admin-header { + background: #fff; + padding: 20px 40px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + display: flex; + justify-content: space-between; + align-items: center; +} + +.admin-header h1 { + font-size: 24px; + color: #333; +} + +.header-actions { + display: flex; + gap: 16px; + align-items: center; +} + +.header-actions span { + color: #666; + font-size: 14px; +} + +/* 主内容区 */ +.admin-main { + max-width: 1200px; + margin: 40px auto; + padding: 0 20px; +} + +/* 区块 */ +section { + background: #fff; + border-radius: 12px; + padding: 30px; + margin-bottom: 30px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); +} + +section h2 { + font-size: 20px; + margin-bottom: 20px; + color: #333; +} + +/* 表单 */ +.form-group { + margin-bottom: 20px; +} + +.form-row { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 20px; +} + +label { + display: block; + color: #555; + font-size: 14px; + font-weight: 500; + margin-bottom: 8px; +} + +input[type="text"], +input[type="file"], +textarea { + width: 100%; + padding: 10px 14px; + border: 1px solid #ddd; + border-radius: 6px; + font-size: 14px; + transition: border-color 0.3s; +} + +input[type="text"]:focus, +textarea:focus { + outline: none; + border-color: #667eea; +} + +textarea { + resize: vertical; + font-family: inherit; +} + +.form-hint { + display: block; + margin-top: 6px; + color: #999; + font-size: 12px; +} + +/* 按钮 */ +.btn { + display: inline-block; + padding: 10px 20px; + border-radius: 6px; + font-size: 14px; + font-weight: 500; + text-decoration: none; + border: none; + cursor: pointer; + transition: all 0.2s; +} + +.btn-primary { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: #fff; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4); +} + +.btn-secondary { + background: #f0f0f0; + color: #666; +} + +.btn-secondary:hover { + background: #e5e5e5; +} + +.btn-small { + padding: 6px 12px; + font-size: 12px; + border-radius: 4px; +} + +.btn-info { + background: #3b82f6; + color: #fff; +} + +.btn-info:hover { + background: #2563eb; +} + +.btn-danger { + background: #ef4444; + color: #fff; +} + +.btn-danger:hover { + background: #dc2626; +} + +/* 表格 */ +.apps-table { + width: 100%; + border-collapse: collapse; + margin-top: 20px; +} + +.apps-table thead { + background: #f9fafb; +} + +.apps-table th, +.apps-table td { + padding: 12px; + text-align: left; + border-bottom: 1px solid #e5e7eb; +} + +.apps-table th { + font-weight: 600; + color: #555; + font-size: 13px; +} + +.apps-table td { + font-size: 14px; +} + +.apps-table td.description { + max-width: 250px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.apps-table tbody tr:hover { + background: #f9fafb; +} + +.apps-table td:last-child { + white-space: nowrap; +} + +.apps-table .btn-small { + margin-right: 6px; +} + +/* 提示信息 */ +.alert { + padding: 12px 16px; + border-radius: 6px; + margin-bottom: 20px; + font-size: 14px; +} + +.alert-success { + background: #d1fae5; + color: #065f46; + border: 1px solid #6ee7b7; +} + +.alert-error { + background: #fee; + color: #c33; + border: 1px solid #fca5a5; +} + +/* 空状态 */ +.empty-state { + text-align: center; + color: #999; + padding: 40px; + font-size: 14px; +} + +/* Logo 预览 */ +.logo-preview { + margin: 10px 0; + padding: 20px; + background: #f9fafb; + border-radius: 8px; + text-align: center; +} + +.logo-preview img { + display: block; + margin: 0 auto; +} + +/* 响应式 */ +@media (max-width: 768px) { + .admin-header { + flex-direction: column; + align-items: flex-start; + gap: 16px; + } + + .form-row { + grid-template-columns: 1fr; + } + + .apps-table { + font-size: 12px; + } + + .apps-table th, + .apps-table td { + padding: 8px; + } +} diff --git a/download.php b/download.php new file mode 100644 index 0000000..586a499 --- /dev/null +++ b/download.php @@ -0,0 +1,54 @@ +prepare("SELECT * FROM apps WHERE id = ?"); + $stmt->execute([$id]); + $app = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($app && file_exists('data/apps/' . $app['filename'])) { + echo json_encode([ + 'success' => true, + 'file' => 'data/apps/' . rawurlencode($app['filename']), + 'filename' => $app['original_name'], + 'version' => $app['version'], + 'date' => date('Y-m-d H:i:s', strtotime($app['upload_time'])) + ]); + } else { + echo json_encode([ + 'success' => false, + 'message' => 'APK 文件不存在' + ]); + } + } else { + // 兼容旧版:返回最新版本 + $stmt = $db->query("SELECT * FROM apps ORDER BY upload_time DESC LIMIT 1"); + $app = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($app && file_exists('data/apps/' . $app['filename'])) { + echo json_encode([ + 'success' => true, + 'file' => 'data/apps/' . rawurlencode($app['filename']), + 'filename' => $app['original_name'], + 'version' => $app['version'], + 'date' => date('Y-m-d H:i:s', strtotime($app['upload_time'])) + ]); + } else { + echo json_encode([ + 'success' => false, + 'message' => '未找到 APK 文件' + ]); + } + } +} catch (Exception $e) { + echo json_encode([ + 'success' => false, + 'message' => '查询失败: ' . $e->getMessage() + ]); +} diff --git a/includes/db.php b/includes/db.php new file mode 100644 index 0000000..e17bc59 --- /dev/null +++ b/includes/db.php @@ -0,0 +1,49 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // 如果是新数据库,初始化表结构 + if ($is_new_db) { + // 创建 apps 表 + $db->exec(" + CREATE TABLE IF NOT EXISTS apps ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + filename TEXT NOT NULL, + original_name TEXT NOT NULL, + version TEXT, + description TEXT, + upload_time DATETIME DEFAULT CURRENT_TIMESTAMP, + file_size INTEGER + ) + "); + + // 创建 config 表 + $db->exec(" + CREATE TABLE IF NOT EXISTS config ( + key TEXT PRIMARY KEY, + value TEXT + ) + "); + + // 插入默认配置 + $defaults = [ + ['site_title', 'OPS 运营管理系统'], + ['site_description', '点击下方按钮下载移动端 APP'], + ['logo_path', 'logo.png'] + ]; + + $stmt = $db->prepare("INSERT INTO config (key, value) VALUES (?, ?)"); + foreach ($defaults as $config) { + $stmt->execute($config); + } + } + +} catch (PDOException $e) { + die("数据库连接失败: " . $e->getMessage()); +} diff --git a/includes/functions.php b/includes/functions.php new file mode 100644 index 0000000..b37fe21 --- /dev/null +++ b/includes/functions.php @@ -0,0 +1,51 @@ +prepare("SELECT value FROM config WHERE key = ?"); + $stmt->execute([$key]); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + return $result ? $result['value'] : $default; +} + +/** + * 更新配置值 + */ +function updateConfig($key, $value) { + global $db; + $stmt = $db->prepare("INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)"); + return $stmt->execute([$key, $value]); +} + +/** + * 格式化文件大小 + */ +function formatFileSize($bytes) { + if ($bytes >= 1073741824) { + return number_format($bytes / 1073741824, 2) . ' GB'; + } elseif ($bytes >= 1048576) { + return number_format($bytes / 1048576, 2) . ' MB'; + } elseif ($bytes >= 1024) { + return number_format($bytes / 1024, 2) . ' KB'; + } else { + return $bytes . ' B'; + } +} + +/** + * 检查是否已登录 + */ +function isLoggedIn() { + return isset($_SESSION['admin_logged_in']) && $_SESSION['admin_logged_in'] === true; +} + +/** + * 安全输出 HTML + */ +function e($string) { + return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); +} diff --git a/index.php b/index.php new file mode 100644 index 0000000..7c7d0c7 --- /dev/null +++ b/index.php @@ -0,0 +1,215 @@ +query("SELECT * FROM apps ORDER BY upload_time DESC"); +$apps = $stmt->fetchAll(PDO::FETCH_ASSOC); +?> + + + + + + <?php echo e($site_title); ?> + + + +
+
+ +

+

+
+ +
+ +
+

暂无可用版本

+
+ + +
+
+
+

+ + v + +
+
+ +
+ 📅 + 📦 +
+ + +
+ +
+ + + 立即下载 +
+ + +
+
+ + 管理后台 + + diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..3a22158 Binary files /dev/null and b/logo.png differ