65 lines
2.7 KiB
PHP
65 lines
2.7 KiB
PHP
<?php
|
||
|
||
namespace App\Service\common\upload;
|
||
|
||
use App\Service\common\UtilsService;
|
||
|
||
/**
|
||
* ListBucketResult 解析
|
||
*
|
||
* 阿里云 GET Bucket、腾讯云 GET Bucket、S3 ListObjectsV2 回的都是同一套
|
||
* <ListBucketResult><Contents>… 结构,只有续拉游标的节点名不同(NextMarker /
|
||
* NextContinuationToken)。三个驱动共用本 trait,避免同一段 XML 遍历写三遍。
|
||
* 使用方需要有 $this->config 以及 ObjectKeyNormalizeTrait 提供的 key 规整方法。
|
||
*/
|
||
trait ObjectListXmlTrait
|
||
{
|
||
/**
|
||
* @param string $xml 响应体
|
||
* @param string $urlBase 未配置 domain 时兜底拼地址用的主机前缀(不带尾斜杠)
|
||
* @param string $tokenNode 续拉游标节点名
|
||
* @return array{items: array<int, array{key:string,size:int,hash:string,last_modified:int,url:string}>, next_marker: string, finished: bool}
|
||
*/
|
||
protected function parseObjectListXml(string $xml, string $urlBase, string $tokenNode = 'NextMarker'): array
|
||
{
|
||
$doc = @simplexml_load_string($xml);
|
||
if ($doc === false) {
|
||
UtilsService::getInstance()->errorThrow('列举结果解析失败,返回内容不是合法 XML');
|
||
}
|
||
|
||
$items = [];
|
||
$lastRawKey = '';
|
||
$contents = isset($doc->Contents) ? $doc->Contents : [];
|
||
foreach ($contents as $node) {
|
||
$rawKey = (string) $node->Key;
|
||
// 续拉游标必须用服务端原样返回的 key,不能用补过 prefix 的规整值
|
||
$lastRawKey = $rawKey;
|
||
$key = $this->normalizeObjectKey($rawKey);
|
||
if ($key === '' || str_ends_with($key, '/')) {
|
||
// 以 / 结尾的是控制台建目录留下的占位对象,不是素材
|
||
continue;
|
||
}
|
||
$items[] = [
|
||
'key' => $key,
|
||
'size' => (int) $node->Size,
|
||
'hash' => strtolower(trim((string) $node->ETag, '"')),
|
||
'last_modified' => (int) strtotime((string) $node->LastModified),
|
||
'url' => $this->publicUrlOf($key, $urlBase . '/' . $key),
|
||
];
|
||
}
|
||
|
||
$truncated = filter_var((string) ($doc->IsTruncated ?? 'false'), FILTER_VALIDATE_BOOLEAN);
|
||
$next = isset($doc->{$tokenNode}) ? (string) $doc->{$tokenNode} : '';
|
||
if ($truncated && $next === '' && $tokenNode === 'NextMarker') {
|
||
// 部分兼容实现只给 IsTruncated 不给 NextMarker,按协议可用本页最后一个 key 续拉
|
||
$next = $lastRawKey;
|
||
}
|
||
|
||
return [
|
||
'items' => $items,
|
||
'next_marker' => $truncated ? $next : '',
|
||
'finished' => !$truncated || $next === '',
|
||
];
|
||
}
|
||
}
|