diff --git a/README.md b/README.md index c3daff5..553d981 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ ### 图片处理 - **内置裁剪器**:基于 Cropper.js,票根 / 海报 / 观影照片 / 观影人头像均可在浏览器内裁剪后再保存,服务端接收 Base64 图片落盘。 - **多图上传**:观影照片支持一次选择多张。 -- **头像兜底**:未上传头像的观影人自动生成"首字母 + 配色"的 SVG 头像,配色由姓名哈希决定,同名同色。 +- **头像兜底**:未上传头像的观影人一律显示 `assets/default-avatar.png` 默认头像(人形剪影);若该资源缺失(例如只部署了 PHP 而漏了 `assets/`),`getAvatarUrl()` 会退化为内联 SVG 剪影 —— 保证任何情况下都不会出现"坏图"。 - 上传目录按类型分离:`uploads/posters/`、`uploads/tickets/`、`uploads/photos/`、`uploads/avatars/`。 - **破图兜底**:图片加载失败时由前端脚本替换为内联占位图,避免会话过期或权限异常时满屏破图刷屏控制台。 @@ -116,7 +116,8 @@ MovieLog_Server/ ├── test_crop.php # 开发调试页:验证 Base64 图片落盘是否正常 ├── css/style.css # 全局样式 ├── js/main.js # 公共脚本(含各页面共用的表单联动函数、破图兜底) -├── assets/.gitkeep # 静态占位资源目录 +├── assets/ # 静态资源 +│ └── default-avatar.png # 默认头像(未上传头像时统一使用) ├── db/movies.db # SQLite 数据库(运行时自动生成,不纳入版本控制) └── uploads/ # 上传图片(运行时自动生成,不纳入版本控制) ├── posters/ # 海报 @@ -565,7 +566,7 @@ curl -sk -H "Host: 你的域名" -H "Cookie: PHPSESSID=xxxx" -o /dev/null \ - 暂无分页,数据量增大后首页与统计页需要补充分页或懒加载。 - `config.php` 的 `initDB()` 在每次请求都会跑一遍建表与迁移,数据量或并发上升后可改为一次性迁移脚本。 - 无「回收站」,删除电影与其图片文件不可恢复。 -- `assets/placeholder-poster.jpg`、`assets/default-avatar.png` 为代码中的兜底引用,当前仓库未包含这两个文件;由于页面在检测到 placeholder 时会改用 CSS 占位块渲染,正常使用不受影响。 +- `assets/placeholder-poster.jpg` 仍是代码中的兜底引用,**仓库未包含该文件**;页面在检测到 placeholder 时会改用 CSS 占位块渲染,正常使用不受影响。`assets/default-avatar.png` 已随仓库提供(默认头像),并在资源缺失时由 `getAvatarUrl()` 退化为内联 SVG 剪影。 - **「直连存储」模式下裁剪功能不可用**:裁剪需要读取图片像素,直连时图片来自对象存储域名,必须同时满足「桶配 CORS」与「``」两个条件才能读像素;本仓库未加 `crossorigin` 属性,因此直连模式下只能上传、不能二次裁剪。需要裁剪请改用「服务端代理」(同源,两个条件全免)。详见《图片存储与对象存储》§3③。 - **服务端代理模式下所有图片流量经服务器中转**,会占用服务器出网带宽,并给每张图增加一次服务器↔存储的往返(同地域约 10–30 ms,跨地域约 60–100 ms)。图片量大且可公开时可考虑改回直连。 - **内网 endpoint 只在服务器与桶同地域时生效**。跨地域部署下这条免费通道用不了,程序会自动跳过并走公网(详见 §4)。 diff --git a/assets/default-avatar.png b/assets/default-avatar.png new file mode 100644 index 0000000..bbe4840 Binary files /dev/null and b/assets/default-avatar.png differ diff --git a/lib/helpers.php b/lib/helpers.php index 4044338..49a1b41 100644 --- a/lib/helpers.php +++ b/lib/helpers.php @@ -135,17 +135,40 @@ function posterUrl($path) { } // ===== 头像处理 ===== + +// 默认头像 URL:未上传头像的人统一使用它。 +// 资源随仓库分发(assets/default-avatar.png)。 +// 若该文件缺失——比如只部署了 PHP 而漏了 assets/——则退化为内联 SVG 剪影, +// 避免出现「兜底图本身就是坏图」:这正是本函数此前的问题(返回了一个并不存在的路径)。 +// 注意:这里用 is_file() 探测,路径在站点目录内,不会像站外路径那样触碰 open_basedir 限制。 +function defaultAvatarUrl() { + static $url = null; + if ($url !== null) { + return $url; + } + $root = defined('ROOT_DIR') ? ROOT_DIR : dirname(__DIR__); + if (is_file($root . '/assets/default-avatar.png')) { + $url = '/assets/default-avatar.png'; + return $url; + } + // 几何比例与 assets/default-avatar.png 保持一致,两种情形视觉无差别 + $svg = "" + . "" + . "" + . "" + . ""; + $url = 'data:image/svg+xml,' . rawurlencode($svg); + return $url; +} + +// 头像 URL:已上传 → 存储层 URL;未上传 → 统一的默认头像。 +// 说明:$name 是历史遗留参数(早期按姓名首字母生成彩色 SVG 头像), +// 现在一律使用默认头像,参数仅保留以兼容既有调用点。 function getAvatarUrl($avatar_path, $name = '') { if (storageExists($avatar_path)) { return storageUrl($avatar_path); } - if (!empty($name)) { - $letter = mb_substr($name, 0, 1, 'UTF-8'); - $colors = ['#e74c3c','#e67e22','#f1c40f','#2ecc71','#3498db','#9b59b6','#1abc9c','#e84393','#00b894','#0984e3']; - $color = $colors[abs(crc32($name)) % count($colors)]; - return "data:image/svg+xml," . urlencode("{$letter}"); - } - return '/assets/default-avatar.png'; + return defaultAvatarUrl(); } // ===== 保存 Base64 图片 ===== diff --git a/persons.php b/persons.php index b4dee44..a51b6cd 100644 --- a/persons.php +++ b/persons.php @@ -68,9 +68,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' // 保存新头像 $avatar_path = $old_avatar; if (!empty($avatar_base64)) { - // 删除旧头像 + // 上传了新头像(优先级最高):先删旧文件,再存新的 deleteStoredFile($old_avatar); $avatar_path = saveBase64Image($avatar_base64, AVATAR_DIR, 'avatar'); + } elseif (isset($_POST['delete_avatar'])) { + // 用户点了「删除」:清空头像字段 → 页面回落到默认头像。 + // (前端 removeAvatar() 会带上 delete_avatar=1;此前后端没有读这个标记, + // 导致点了「删除」保存后头像原样保留 —— 是个静默失效的按钮。) + deleteStoredFile($old_avatar); + $avatar_path = null; } $stmt = $db->prepare("UPDATE persons SET name = ?, color = ?, avatar = ? WHERE id = ?"); @@ -295,11 +301,8 @@ $preset_colors = [
- - - - - + + 点击选择图片,裁剪后生效
@@ -377,6 +380,8 @@ $preset_colors = [