You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 9中按前缀搜索S3存储文件的解决方案求助

解决方案

你遇到的错误是因为当前版本的League\Flysystem\AwsS3V3\AwsS3V3Adapter已不再提供getClient()方法,Laravel的S3磁盘本身就支持直接获取AWS客户端,无需绕到适配器层。

以下提供两种可行实现,同时考虑到文件数量较多(数千个),加入了分页获取逻辑(S3的ListObjectsV2接口单次最多返回1000条数据):

方式一:使用Laravel S3磁盘原生方法(推荐)

public static function searchS3ByPrefix($path, $prefix) {
    try {
        $disk = Storage::disk('s3');
        $client = $disk->getClient(); // 直接通过磁盘实例获取AWS客户端
        $bucket = $disk->getAdapter()->getBucket();
        // 处理路径拼接,避免多余斜杠
        $fullPrefix = rtrim($path, '/') . '/' . ltrim($prefix, '/');
        
        $results = [];
        $nextToken = null;
        
        // 循环分页获取所有符合条件的文件
        do {
            $commandParams = [
                'Bucket' => $bucket,
                'Prefix' => $fullPrefix,
                'ContinuationToken' => $nextToken
            ];
            
            $result = $client->listObjectsV2($commandParams);
            
            // 提取文件Key并过滤出PDF格式文件
            foreach ($result['Contents'] as $object) {
                if (pathinfo($object['Key'], PATHINFO_EXTENSION) === 'pdf') {
                    $results[] = $object['Key'];
                }
            }
            
            $nextToken = $result['NextContinuationToken'] ?? null;
        } while ($nextToken);
        
        return $results;
    } catch (\Exception $e) {
        Log::error($e);
        return [];
    }
}

关键说明:

  • 用listObjectsV2替代已弃用的ListObjects接口,这是AWS官方推荐的新版本接口
  • 分页逻辑确保能获取全部文件,不会遗漏超过1000条后的内容
  • 手动过滤.pdf后缀,因为S3的前缀匹配无法直接筛选文件后缀
  • 路径处理避免出现//这类无效拼接

方式二:适配旧版本Flysystem的反射获取法

如果你的Flysystem版本较旧,适配器的客户端是protected属性,可通过反射获取:

public static function searchS3ByPrefix($path, $prefix) {
    try {
        $disk = Storage::disk('s3');
        $adapter = $disk->getAdapter();
        
        // 通过反射访问protected的client属性
        $reflection = new \ReflectionClass($adapter);
        $clientProperty = $reflection->getProperty('client');
        $clientProperty->setAccessible(true);
        $client = $clientProperty->getValue($adapter);
        
        $bucket = $adapter->getBucket();
        $fullPrefix = rtrim($path, '/') . '/' . ltrim($prefix, '/');
        
        $results = [];
        $nextToken = null;
        
        do {
            $commandParams = [
                'Bucket' => $bucket,
                'Prefix' => $fullPrefix,
                'ContinuationToken' => $nextToken
            ];
            
            $result = $client->listObjectsV2($commandParams);
            
            foreach ($result['Contents'] as $object) {
                if (pathinfo($object['Key'], PATHINFO_EXTENSION) === 'pdf') {
                    $results[] = $object['Key'];
                }
            }
            
            $nextToken = $result['NextContinuationToken'] ?? null;
        } while ($nextToken);
        
        return $results;
    } catch (\Exception $e) {
        Log::error($e);
        return [];
    }
}

关键说明:

  • 反射方式不推荐,因为依赖适配器内部实现,版本更新后可能失效
  • 同样包含分页和后缀过滤逻辑,确保功能完整

使用示例

若要查找ID为123的所有日期格式PDF文件,调用方式:

$targetFiles = YourClassName::searchS3ByPrefix('your-storage-folder', '123_');

内容的提问来源于stack exchange,提问作者Văn Hữu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 04:54:16