资讯专栏INFORMATION COLUMN

阿里云 OSS 中获取文件列表的方法

Zoom / 1899人阅读

摘要:猜测可能是阿里云服务对控制台下的权限管理还是以服务为单位,目前还没有把权限精确到的单个中。参考阿里云访问控制帮助文档

1. 问题

OSS PHP-SDK 手册中给出使用 listObjects 函数获取某一 Bucket 下文件列表的方法,如下(摘自 OSS PHP-SDK 文档):

    $prefix = "dir/";
    $delimiter = "/";
    $nextMarker = "";
    $maxkeys = 30;
    while (true) {
        $options = array(
            "delimiter" => $delimiter,
            "prefix" => $prefix,
            "max-keys" => $maxkeys,
            "marker" => $nextMarker,
        );
        var_dump($options);
        try {
            $listObjectInfo = $ossClient->listObjects($bucket, $options);
        } catch (OssException $e) {
            printf(__FUNCTION__ . ": FAILED
");
            printf($e->getMessage() . "
");
            return;
        }
        // 得到nextMarker,从上一次listObjects读到的最后一个文件的下一个文件开始继续获取文件列表
        $nextMarker = $listObjectInfo->getNextMarker();
        $listObject = $listObjectInfo->getObjectList();
        $listPrefix = $listObjectInfo->getPrefixList();
        var_dump($listObject); // 这里手册中写的是输出 count($listObject),以下同理
        var_dump($listPrefix);
        if ($nextMarker === "") {
            break;
        }
    }

这段代码的执行结果并没有返回我最开始想象中的文件名称、大小之类的数组,而是在浏览器输出了一些对象,那么这里该如何转换成我们需要的数据格式呢?此外,$options 数组中的 delimitermarker 键值对到底有什么作用呢?

2. 返回值

通过查看 var_dump 输出信息,可以发现执行结果为 OSSModelObjectInfo 对象和 OSSModelPrefixInfo 对象,分别对应 var_dump($listObject)var_dump($listPrefix)
通过查看 PHP-SDK 源码,可以看到 OSSModelObjectInfo 中含有 getKey()getLastModified() 等方法,因而可以借此获取我们想得到的数据格式,如下:

    /* 解析 prefixInfo 类 */
    private function prefixInfoParse(PrefixInfo $prefixInfo){
        return [
            "dir" => $prefixInfo->getPrefix(),
        ];
    }
    /* 解析 objectInfo 类 */
    public function objectInfoParse(ObjectInfo $objectInfo) {
        return [
            "name"      => $objectInfo->getKey(),
            "size"      => $objectInfo->getSize(),
            "update_at" => $objectInfo->getLastModified(),
        ];
    }
3. options 数组键值

阿里云 OSS 中不支持原生的文件夹,而是使用一个 0 字节的末尾为 / 的文件起到文件夹功能。

$options 数组有四个键值对,其中

prefix 是我们想获取的文件的目录,如 test/ 即为列出目录 test 下的所有文件及子文件夹(不递归获取);

delimiter 为行使文件夹功能的分割符号,如 /

max-keys 是限定返回的文件和文件夹数目,这里不是指每次最多返回 max-keys 值的数据,而是以这个值为分页的单页容量。如文件夹下有 100 个文件,这里设定 max-keys 为 30,则执行后的返回结果为:["30 个 ObjectInfo 对象", "30 个 ObjectInfo 对象", "30 个 ObjectInfo 对象", "10 个 ObjectInfo 对象"];

marker 是实现分页时指向下一分页起始位置的标识。

4. 总结

我们可以改写获取文件列表的方法,使其能够返回一个格式合适的数组:

    public function fileList($dir, $maxKey = 30, $delimiter = "/", $nextMarker = "") {
        $fileList = []; // 获取的文件列表, 数组的一阶表示分页结果
        $dirList = []; // 获取的目录列表, 数组的一阶表示分页结果
        $storageList = [
            "file" => [], // 真正的文件数组
            "dir"  => [], // 真正的目录数组
        ];
        while (true) {
            $options = [
                "delimiter" => $delimiter,
                "prefix"    => $dir,
                "max-keys"  => $maxKey,
                "marker"    => $nextMarker,
            ];
            try {
                $fileListInfo = $this->ossClient->listObjects($this->bucket, $options);
                // 得到nextMarker, 从上一次 listObjects 读到的最后一个文件的下一个文件开始继续获取文件列表, 类似分页
            } catch (OssException $e) {
                return $this->send($this->errorCode, $e->getMessage()); // 发送错误信息
            }
            $nextMarker = $fileListInfo->getNextMarker();
            $fileItem = $fileListInfo->getObjectList();
            $dirItem = $fileListInfo->getPrefixList();
            $fileList[] = $fileItem;
            $dirList[] = $dirItem;
            if ($nextMarker === "") break;
        }
        foreach ($fileList[0] as $item){
            $storageList["file"][] = $this->objectInfoParse($item);
        }
        foreach ($dirList[0] as $item){
            $storageList["dir"][] = $this->prefixInfoParse($item);
        }
        return $this->send($this->successCode, $storageList); // 发送正确信息
    }

执行这一方法可以返回一个 json,格式如下:

    {
        "status": 200,
        "message": {
            "file": [
                {
                    "name": "robotac2016/_ide_helper.php",
                    "size": 382295,
                    "update_at": "2016-09-20T13:45:04.000Z"
                },
                {
                    "name": "robotac2016/test.php",
                    "size": 11,
                    "update_at": "2016-09-20T12:06:36.000Z"
                }
            ],
            "dir": [
                {
                    "dir": "robotac2016/innocence/"
                }
            ]
        }
    }
5. 备忘

若想获取某一 Bucket 下的所有文件和文件夹,应该传入的 $prefix 值为空字符串 "" 而不是根目录符号 /,因为阿里云 OSS 本身没有文件夹概念,传入 / 后系统会寻找根目录下所有首字母为 / 的文件,而不是遍历根目录本身;

是在阿里云 OSS 中,删除文件、创建文件操作中若删除的文件不存在或者创建的文件已存在时,OSS 不会返回错误提示,而是静默或替换同名文件。个人认为删除操作的执行准则是使得 OSS 中不具有某一文件而不是删掉它,而创建文件的原则是静默替换。所以在执行这些操作的时候,应该实现检测该文件是否存在以免造成不可恢复的损失。

使用 RAM 访问控制对 OSS 进行权限管理的时候,如果使用自定义的权限策略,该策略只会在使用 SDK 或 API 的时候体现。如现在自定义一个读写 OSS 下某一 Bucket 的权限策略,这一策略在 SDK 中是可以正常起到限制作用的,而在 RAM 控制台中,却被提示没有 OSS 的访问权限。猜测可能是阿里云 OSS 服务对控制台下的权限管理还是以服务为单位,目前还没有把权限精确到 OSS 的单个 Bucket 中。

    {
      "Statement": [
        {
          "Action": "oss:*",
          "Effect": "Allow",
          "Resource": [
            "acs:oss:*:*:oss-test",
            "acs:oss:*:*:oss-test/*"
          ]
        }
      ],
      "Version": "1"
    }

2016.9.22 更新

关于备忘第二点中 RAM 访问控制的问题,我提交了一份工单给 OSS,得到的反馈是,如果想要在 RAM 控制台中以图形化界面访问 Bucket,需要在 Statement 中再添加一个策略,其 Action 值为 ListBuckets,多带带给出一个 * 权限是不够的,如下:

    {
      "Statement": [
        // 策略 1:用于 api 权限限制
        {
          "Action": "oss:*",
          "Effect": "Allow",
          "Resource": [
            "acs:oss:*:*:oss-test",
            "acs:oss:*:*:oss-test/*"
          ]
        },
        // 策略 2:用于 RAM 控制台显示 Bucket 列表
        {
          "Action": [
            "oss:ListBuckets"
          ],
          "Effect": "Allow",
          "Resource": [
            "acs:oss:*:*:*"
          ]
        }
      ],
      "Version": "1"
    }

ListBuckets 这一策略中,Resource 值只能是 acs:oss:*:*:* 而不能是 acs:oss:*:*:oss-test,不然还是会在 RAM 控制台提示没有访问权限。虽然写成这样会使得登录 RAM 控制台的人看到所有的 Buckets,但其对除 oss-test 之外的 Buckets 是没有读写权限的。

6. 参考

阿里云访问控制帮助文档

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30453.html

相关文章

  • 微信公众号图片上传至阿里OSS

    摘要:最近在做微信公众号,需要将图片上传至阿里云。利用模块将图片写到内存微信多媒体文件文件路径图片上传阿里云结果上传文件出错这种方式将图片暂存在内存里面,那如果并发量很大,是不是内存要爆炸了都感觉还是不可取。 最近在做微信公众号,需要将图片上传至阿里云OSS。在做这个功能的过程中,我走了不少弯路,尝试过很多种方法,最后终于研究出一种便捷优美的方式。现在把这些方法和思路记录下来,避免遗忘。 一...

    whatsns 评论0 收藏0
  • ZFile自建免费公共网盘服务-支持阿里OSS,OneDrive,FTP,S3协议等存储

    对于网站存储的需求,大多数人还是以私有网盘为主,目的是为了可以存储属于私人的视频、文档、音频等资料。但是,也有不少的人想要搭建一个公共的网盘,主要目的是可以方便所有人查看、浏览和下载、使用,同时也提供视频在线播放,变成影视站点。这样的公共网盘服务搭建起来并不是很复杂,但是苦于高昂的存储费用,有的人盯上了超大容量且免费的网盘服务,例如OneDrive,团队版甚至可以达到TB以上,将OneDrive变...

    番茄西红柿 评论0 收藏2637
  • ACE认证考试—阿里产品概念深化学习

    摘要:第一课阿里云相关概念深化学习云服务器,简称是一种简单高效处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定安全的应用,提升运维效率,降低成本,使您更专注于核心业务创新。第一课:阿里云相关概念深化学习 ECS 云服务器(Elastic Compute Service,简称 ECS)是一种简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本,使...

    zhichangterry 评论0 收藏0
  • SpringBoot 整合 阿里OSS 存储服务,快来免费搭建一个自己图床

    摘要:笔主很早就开始用阿里云存储服务当做自己的图床了。阿里云对象存储文档,本篇文章会介绍到整合阿里云存储服务实现文件上传下载以及简单的查看。 Github 地址:https://github.com/Snailclimb/springboot-integration-examples(SpringBoot和其他常用技术的整合,可能是你遇到的讲解最详细的学习案例,力争新手也能看懂并且能够在看完...

    邹强 评论0 收藏0

发表评论

0条评论

Zoom

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<