v8:观影落地(MovieLog 整体迁入统一事件原语)+ 三处 UI 撤除
- Schema v8:events / movie_details / event_attendees / event_photos 四张表, uk_event_source(family_id, source_ref) 作迁移幂等锚 - Movie 模型:时间线/详情/增删改、同行人整组替换、照片逐张管理、感受英→中映射 - ImageSlot 新增 poster(2:3) / ticket(free) / photo(free) 三槽位; free 槽位不裁剪、整图等比缩进框(只缩不放大) - OssDriver::copyObject:同桶 CopyObject(手写 V1 签名,x-oss-* 头按字典序进签名串) - 路由:movies 时间线/详情/新增/编辑/删除/补照片/删照片;同行人按家庭过滤; 访客只读(requireWrite) - UI 撤除:首页「我的一句话」、家谱页「补充我的亲属关系 / 看整个名册」两个按钮; 顶栏加「观影」入口 - 修潜伏 bug:ImageSlot::parseRatio 的正则用 / 作分隔符,字符类里的 / 把模式 提前截断(Unknown modifier ']')—— ratio() 只在上传 POST 里被调到,一直没被观察到 - 线上数据迁移(临时 token 门禁页,用完即删):MovieLog 219 条观影 → events, 14 位观影人新增进名册(带 MovieLog 头像),431 个 OSS 对象同桶拷贝 (movielog/uploads/<dir>/x → family/<dir>/x),review/feelings/影院三段/照片全量搬
This commit is contained in:
@@ -262,6 +262,54 @@ final class OssDriver implements StorageDriver
|
||||
return ['ok' => true, 'error' => ''];
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端拷贝(CopyObject)—— v8 迁移用:同一个桶里把 movielog/ 前缀的对象
|
||||
* 复制成 family/ 前缀,不走流量、不用下载重传。
|
||||
*
|
||||
* @param string $srcObjectKey 源对象**完整键**(含前缀,如 movielog/uploads/posters/x.jpg)
|
||||
* @param string $destRelKey 目标**相对键**(不含本站前缀,如 posters/x.jpg)
|
||||
*
|
||||
* ⚠️ 签名注意:所有随请求发送的 x-oss-* 头都必须按字典序拼进签名串
|
||||
* (copy-source 在 security-token 之前),漏一个就是 SignatureDoesNotMatch。
|
||||
* CopyObject 不需要 Content-Type(拷贝沿用源对象的元数据),签名串里留空。
|
||||
*/
|
||||
public function copyObject(string $srcObjectKey, string $destRelKey): array
|
||||
{
|
||||
if ($err = $this->validateConfig()) {
|
||||
return ['ok' => false, 'error' => $err];
|
||||
}
|
||||
$cred = $this->credentials();
|
||||
if (empty($cred['ok'])) {
|
||||
return ['ok' => false, 'error' => $cred['error']];
|
||||
}
|
||||
$bucket = trim((string)$this->cfg['bucket']);
|
||||
$srcKey = ltrim($srcObjectKey, '/');
|
||||
$destKey = $this->objectKey($destRelKey);
|
||||
$date = gmdate('D, d M Y H:i:s \G\M\T');
|
||||
$copySource = '/' . $bucket . '/' . Http::encodeKey($srcKey);
|
||||
|
||||
$canonical = "x-oss-copy-source:{$copySource}\n";
|
||||
if ((string)($cred['token'] ?? '') !== '') {
|
||||
$canonical .= "x-oss-security-token:{$cred['token']}\n";
|
||||
}
|
||||
$stringToSign = "PUT\n\n\n{$date}\n{$canonical}/{$bucket}/{$destKey}";
|
||||
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $cred['secret'], true));
|
||||
|
||||
$h = [
|
||||
'Date: ' . $date,
|
||||
'x-oss-copy-source: ' . $copySource,
|
||||
'Authorization: OSS ' . $cred['id'] . ':' . $signature,
|
||||
];
|
||||
if ((string)($cred['token'] ?? '') !== '') {
|
||||
$h[] = 'x-oss-security-token: ' . $cred['token'];
|
||||
}
|
||||
$res = Http::send('PUT', $this->objectUrl($destKey), $h, null, 60);
|
||||
if (!$res['ok']) {
|
||||
return ['ok' => false, 'error' => 'OSS CopyObject 失败:' . Http::shortError($res)];
|
||||
}
|
||||
return ['ok' => true, 'error' => ''];
|
||||
}
|
||||
|
||||
public function delete(string $key): array
|
||||
{
|
||||
$cred = $this->credentials();
|
||||
|
||||
Reference in New Issue
Block a user