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
相关产品推荐
相关产品推荐

