# 列举多版本对象
![](https://support.huaweicloud.com/sdk-php-devg-obs/public_sys-resources/notice_3.0-zh-cn.png)
开发过程中，您有任何问题可以在GitHub上[提交issue](https://github.com/huaweicloud/huaweicloud-sdk-php-obs/issues)，或者在[华为云对象存储服务论坛](https://bbs.huaweicloud.com/forum/forum-620-1.html)中发帖求助。[接口参考文档](https://support.huaweicloud.com/api-obs_php_sdk_api_zh/obs_38_0001.html)详细介绍了每个接口的参数和使用方法。
您可以通过ObsClient-\>listVersions列举多版本对象。
该接口可设置的参数如下：
| **参数**          | **作用**                                                                                                                    |
|:---|:---|
| Prefix          | 限定返回的对象名必须带有Prefix前缀。                                                                                                    |
| KeyMarker      | 列举多版本对象的起始位置，返回的对象列表将是对象名按照字典序排序后该参数以后的所有对象。                                                                               |
| MaxKeys        | 列举多版本对象的最大数目，取值范围为1\~1000，当超出范围时，按照默认的1000进行处理。                                                                            |
| Delimiter       | 用于对对象名进行分组的字符。对于对象名中包含Delimiter的对象，其对象名（如果请求中指定了Prefix，则此处的对象名需要去掉Prefix）中从首字符至第一个Delimiter之间的字符串将作为一个分组并作为CommonPrefix返回。 |
| VersionIdMarker | 与KeyMarker配合使用，返回的对象列表将是对象名和版本号按照字典序排序后该参数以后的所有对象。                                                                        |
   
![](https://support.huaweicloud.com/sdk-php-devg-obs/public_sys-resources/note_3.0-zh-cn.png)
- 如果VersionIdMarker不是KeyMarker的一个版本号，则该参数无效。
- ObsClient-\>listVersions返回结果包含多版本对象和对象删除标记。
 
#### 简单列举
以下代码展示如何简单列举多版本对象，最多返回1000个对象：
```
<?php
// 引入依赖库
require 'vendor/autoload.php';
// 使用源码安装时引入SDK代码库
// require 'obs-autoloader.php';
// 声明命名空间
use Obs\ObsClient;
use Obs\ObsException;
// 创建ObsClient实例
$obsClient = new ObsClient([
    //推荐通过环境变量获取访问密钥AK/SK，这里也可以使用其他外部引入方式传入，如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK，获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
    'key' => getenv('ACCESS_KEY_ID'),
    'secret' => getenv('SECRET_ACCESS_KEY'),
    'endpoint' => 'https://your-endpoint',
]);
// 列举多版本对象
try {
    $resp = $obsClient->listVersions([
        'Bucket' => 'bucketname'
    ]);
    printf("RequestId:%s\n", $resp['RequestId']);
    // 获取多版本对象
    printf("Versions:\n");
    foreach ($resp['Versions'] as $index => $version) {
        printf("Versions[%d]\n", $index + 1);
        printf("Key:%s\n", $version['Key']);
        printf("VersionId:%s\n", $version['VersionId']);
        printf("IsLatest:%s\n", $version['IsLatest']);
        printf("LastModified:%s\n", $version['LastModified']);
        printf("ETag:%s\n", $version['ETag']);
        printf("Size:%s\n", $version['Size']);
        printf("Owner[ID]:%s\n", $version['Owner']['ID']);
        printf("StorageClass:%s\n", $version['StorageClass']);
    }
    // 对象删除标记
    printf("DeleteMarkers:\n");
    foreach ($resp['DeleteMarkers'] as $index => $deleteMarker) {
        printf("DeleteMarkers[%d]\n", $index + 1);
        printf("Key:%s\n", $deleteMarker['Key']);
        printf("VersionId:%s\n", $deleteMarker['VersionId']);
        printf("LastModified:%s\n", $deleteMarker['LastModified']);
        printf("Owner[ID]:%s\n", $deleteMarker['Owner']['ID']);
    }
} catch (ObsException $e) {
    // 操作失败，获取详细异常信息
    printf("ListVersionsFailed: Status:%d, Code:%s, Message:%s\n",
        $e->getStatusCode(), $e->getExceptionCode(), $e->getExceptionMessage());
} finally {
    // 关闭ObsClient，释放资源
    $obsClient->close();
}
```
![](https://support.huaweicloud.com/sdk-php-devg-obs/public_sys-resources/note_3.0-zh-cn.png)
- 每次至多返回1000个多版本对象，如果指定桶包含的对象数量大于1000，则返回结果中IsTruncated为true表明本次没有返回全部对象，并可通过NextKeyMarker和NextVersionIdMarker获取下次列举的起始位置。
- 如果想获取指定桶包含的所有多版本对象，可以采用分页列举的方式。
 
#### 指定数目列举
以下代码展示如何指定数目列举多版本对象：
```
<?php
// 引入依赖库
require 'vendor/autoload.php';
// 使用源码安装时引入SDK代码库
// require 'obs-autoloader.php';
// 声明命名空间
use Obs\ObsClient;
use Obs\ObsException;
// 创建ObsClient实例
$obsClient = new ObsClient([
    //推荐通过环境变量获取访问密钥AK/SK，这里也可以使用其他外部引入方式传入，如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK，获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
    'key' => getenv('ACCESS_KEY_ID'),
    'secret' => getenv('SECRET_ACCESS_KEY'),
    'endpoint' => 'https://your-endpoint',
]);
// 列举100个多版本对象
try {
    $resp = $obsClient->listVersions([
        'Bucket' => 'bucketname',
        'MaxKeys' => 100
    ]);
    printf("RequestId:%s\n", $resp['RequestId']);
    // 获取多版本对象
    printf("Versions:\n");
    foreach ($resp['Versions'] as $index => $version) {
        printf("Versions[%d]\n", $index + 1);
        printf("Key:%s\n", $version['Key']);
        printf("VersionId:%s\n", $version['VersionId']);
        printf("IsLatest:%s\n", $version['IsLatest']);
        printf("LastModified:%s\n", $version['LastModified']);
        printf("ETag:%s\n", $version['ETag']);
        printf("Size:%s\n", $version['Size']);
        printf("Owner[ID]:%s\n", $version['Owner']['ID']);
        printf("StorageClass:%s\n", $version['StorageClass']);
    }
    // 获取对象删除标记
    printf("DeleteMarkers:\n");
    foreach ($resp['DeleteMarkers'] as $index => $deleteMarker) {
        printf("DeleteMarkers[%d]\n", $index + 1);
        printf("Key:%s\n", $deleteMarker['Key']);
        printf("VersionId:%s\n", $deleteMarker['VersionId']);
        printf("LastModified:%s\n", $deleteMarker['LastModified']);
        printf("Owner[ID]:%s\n", $deleteMarker['Owner']['ID']);
    }
} catch (ObsException $e) {
    // 操作失败，获取详细异常信息
    printf("ListVersionsFailed: Status:%d, Code:%s, Message:%s\n",
        $e->getStatusCode(), $e->getExceptionCode(), $e->getExceptionMessage());
} finally {
    // 关闭ObsClient，释放资源
    $obsClient->close();
}
```
#### 指定前缀列举
以下代码展示如何指定前缀列举多版本对象：
```
<?php
// 引入依赖库
require 'vendor/autoload.php';
// 使用源码安装时引入SDK代码库
// require 'obs-autoloader.php';
// 声明命名空间
use Obs\ObsClient;
use Obs\ObsException;
// 创建ObsClient实例
$obsClient = new ObsClient([
    //推荐通过环境变量获取访问密钥AK/SK，这里也可以使用其他外部引入方式传入，如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK，获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
    'key' => getenv('ACCESS_KEY_ID'),
    'secret' => getenv('SECRET_ACCESS_KEY'),
    'endpoint' => 'https://your-endpoint',
]);
// 设置列举带有prefix前缀的100个多版本对象
try {
    $resp = $obsClient->listVersions([
        'Bucket' => 'bucketname',
        'MaxKeys' => 100,
        'Prefix' => 'prefix'
    ]);
    printf("RequestId:%s\n", $resp['RequestId']);
    // 获取多版本对象
    printf("Versions:\n");
    foreach ($resp['Versions'] as $index => $version) {
        printf("Versions[%d]\n", $index + 1);
        printf("Key:%s\n", $version['Key']);
        printf("VersionId:%s\n", $version['VersionId']);
        printf("IsLatest:%s\n", $version['IsLatest']);
        printf("LastModified:%s\n", $version['LastModified']);
        printf("ETag:%s\n", $version['ETag']);
        printf("Size:%s\n", $version['Size']);
        printf("Owner[ID]:%s\n", $version['Owner']['ID']);
        printf("StorageClass:%s\n", $version['StorageClass']);
    }
    // 对象删除标记
    printf("DeleteMarkers:\n");
    foreach ($resp['DeleteMarkers'] as $index => $deleteMarker) {
        printf("DeleteMarkers[%d]\n", $index + 1);
        printf("Key:%s\n", $deleteMarker['Key']);
        printf("VersionId:%s\n", $deleteMarker['VersionId']);
        printf("LastModified:%s\n", $deleteMarker['LastModified']);
        printf("Owner[ID]:%s\n", $deleteMarker['Owner']['ID']);
    }
} catch (ObsException $e) {
    // 操作失败，获取详细异常信息
    printf("ListVersionsFailed: Status:%d, Code:%s, Message:%s\n",
        $e->getStatusCode(), $e->getExceptionCode(), $e->getExceptionMessage());
} finally {
    // 关闭ObsClient，释放资源
    $obsClient->close();
}
```
#### 指定起始位置列举
以下代码展示如何指定起始位置列举多版本对象：
```
<?php
// 引入依赖库
require 'vendor/autoload.php';
// 使用源码安装时引入SDK代码库
// require 'obs-autoloader.php';
// 声明命名空间
use Obs\ObsClient;
use Obs\ObsException;
// 创建ObsClient实例
$obsClient = new ObsClient([
    //推荐通过环境变量获取访问密钥AK/SK，这里也可以使用其他外部引入方式传入，如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK，获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
    'key' => getenv('ACCESS_KEY_ID'),
    'secret' => getenv('SECRET_ACCESS_KEY'),
    'endpoint' => 'https://your-endpoint',
]);
// 设置列举对象名字典序在"test"之后的100个多版本对象
try {
    $resp = $obsClient->listVersions([
        'Bucket' => 'bucketname',
        'MaxKeys' => 100,
        'Marker' => 'test'
    ]);
    printf("RequestId:%s\n", $resp['RequestId']);
    // 获取多版本对象
    printf("Versions:\n");
    foreach ($resp['Versions'] as $index => $version) {
        printf("Versions[%d]\n", $index + 1);
        printf("Key:%s\n", $version['Key']);
        printf("VersionId:%s\n", $version['VersionId']);
        printf("IsLatest:%s\n", $version['IsLatest']);
        printf("LastModified:%s\n", $version['LastModified']);
        printf("ETag:%s\n", $version['ETag']);
        printf("Size:%s\n", $version['Size']);
        printf("Owner[ID]:%s\n", $version['Owner']['ID']);
        printf("StorageClass:%s\n", $version['StorageClass']);
    }
    // 对象删除标记
    printf("DeleteMarkers:\n");
    foreach ($resp['DeleteMarkers'] as $index => $deleteMarker) {
        printf("DeleteMarkers[%d]\n", $index + 1);
        printf("Key:%s\n", $deleteMarker['Key']);
        printf("VersionId:%s\n", $deleteMarker['VersionId']);
        printf("LastModified:%s\n", $deleteMarker['LastModified']);
        printf("Owner[ID]:%s\n", $deleteMarker['Owner']['ID']);
    }
} catch (ObsException $e) {
    // 操作失败，获取详细异常信息
    printf("ListVersionsFailed: Status:%d, Code:%s, Message:%s\n",
        $e->getStatusCode(), $e->getExceptionCode(), $e->getExceptionMessage());
} finally {
    // 关闭ObsClient，释放资源
    $obsClient->close();
}
```
#### 分页列举全部多版本对象
以下代码展示分页列举全部多版本对象：
```
<?php
// 引入依赖库
require 'vendor/autoload.php';
// 使用源码安装时引入SDK代码库
// require 'obs-autoloader.php';
// 声明命名空间
use Obs\ObsClient;
use Obs\ObsException;
// 创建ObsClient实例
$obsClient = new ObsClient([
    //推荐通过环境变量获取访问密钥AK/SK，这里也可以使用其他外部引入方式传入，如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK，获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
    'key' => getenv('ACCESS_KEY_ID'),
    'secret' => getenv('SECRET_ACCESS_KEY'),
    'endpoint' => 'https://your-endpoint',
]);
// 列举多版本对象
try {
    $keyMarker = null;
    $versionIdMarker = null;
    do {
        $resp = $obsClient->listVersions([
            'Bucket' => 'bucketname',
            'MaxKeys' => 100,
            'Marker' => $keyMarker,
            'VersionIdMarker' => $versionIdMarker
        ]);
    printf( "RequestId:%s\n", $resp['RequestId']);
    // 获取多版本对象
    printf( "Versions:\n" );
    foreach ($resp['Versions'] as $index => $version) {
        printf( "Versions[%d]\n", $index + 1 );
        printf( "Key:%s\n", $version['Key']);
        printf( "VersionId:%s\n", $version['VersionId']);
        printf( "IsLatest:%s\n", $version['IsLatest']);
        printf( "LastModified:%s\n", $version['LastModified']);
        printf( "ETag:%s\n", $version['ETag']);
        printf( "Size:%s\n", $version['Size']);
        printf( "Owner[ID]:%s\n", $version['Owner']['ID']);       }
    // 获取对象删除标记
    printf("DeleteMarkers:\n" );
    foreach ($resp['DeleteMarkers'] as $index => $deleteMarker) {
        printf("DeleteMarkers[%d]\n", $index + 1 );
        printf("Key:%s\n", $deleteMarker['Key']);
        printf("VersionId:%s\n", $deleteMarker['VersionId']);
        printf("LastModified:%s\n", $deleteMarker['LastMod]);']);
        printf("Owner[ID]:%s\n", $deleteMarker['Owner']['ID']);
    }
    $keyMarker = $resp['NextKeyMarker'];
    $versionIdMarker = $resp['NextVersionIdMarker'];
    }while($resp['IsTruncated']);
} catch (ObsException $e) {
    // 操作失败，获取详细异常信息
    printf("ListVersionsFailed: Status:%d, Code:%s, Message:%s\n",
        $e->getStatusCode(), $e->getExceptionCode(), $e->getExceptionMessage());
} finally {
    // 关闭ObsClient，释放资源
    $obsClient->close();
}
```
#### 列举文件夹中的所有多版本对象
OBS本身是没有文件夹的概念的，桶中存储的元素只有对象。文件夹对象实际上是一个大小为0且对象名以"/"结尾的对象，将这个文件夹对象名作为前缀，即可模拟列举文件夹中对象的功能。以下代码展示如何列举文件夹中的多版本对象：
```
<?php
// 引入依赖库
require 'vendor/autoload.php';
// 使用源码安装时引入SDK代码库
// require 'obs-autoloader.php';
// 声明命名空间
use Obs\ObsClient;
use Obs\ObsException;
// 创建ObsClient实例
$obsClient = new ObsClient([
    //推荐通过环境变量获取访问密钥AK/SK，这里也可以使用其他外部引入方式传入，如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK，获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
    'key' => getenv('ACCESS_KEY_ID'),
    'secret' => getenv('SECRET_ACCESS_KEY'),
    'endpoint' => 'https://your-endpoint',
]);
// 分页列举全部多版本对象
try {
    $keyMarker = null;
    $versionIdMarker = null;
    do {
        $resp = $obsClient->listVersions([
            'Bucket' => 'bucketname',
            'MaxKeys' => 100,
            'Marker' => $keyMarker,
            'VersionIdMarker' => $versionIdMarker,
            // 设置文件夹对象名"dir/"为前缀
            'Prefix' => 'dir/'
        ]);
        printf("RequestId:%s\n", $resp['RequestId']);
        // 获取多版本对象
        printf("Versions:\n");
        foreach ($resp['Versions'] as $index => $version) {
            printf("Versions[%d]\n", $index + 1);
            printf("Key:%s\n", $version['Key']);
            printf("VersionId:%s\n", $version['VersionId']);
            printf("IsLatest:%s\n", $version['IsLatest']);
            printf("LastModified:%s\n", $version['LastModified']);
            printf("ETag:%s\n", $version['ETag']);
            printf("Size:%s\n", $version['Size']);
            printf("Owner[ID]:%s\n", $version['Owner']['ID']);
            printf("StorageClass:%s\n", $version['StorageClass']);
        }
        // 获取对象删除标记
        printf("DeleteMarkers:\n");
        foreach ($resp['DeleteMarkers'] as $index => $deleteMarker) {
            printf("DeleteMarkers[%d]\n", $index + 1);
            printf("Key:%s\n", $deleteMarker['Key']);
            printf("VersionId:%s\n", $deleteMarker['VersionId']);
            printf("LastModified:%s\n", $deleteMarker['LastModified']);
            printf("Owner[ID]:%s\n", $deleteMarker['Owner']['ID']);
        }
        $keyMarker = $resp['NextKeyMarker'];
        $versionIdMarker = $resp['NextVersionIdMarker'];
    } while ($resp['IsTruncated']);
} catch (ObsException $e) {
    // 操作失败，获取详细异常信息
    printf("ListVersionsFailed: Status:%d, Code:%s, Message:%s\n",
        $e->getStatusCode(), $e->getExceptionCode(), $e->getExceptionMessage());
} finally {
    // 关闭ObsClient，释放资源
    $obsClient->close();
}
```
#### 按文件夹分组列举所有多版本对象
以下代码展示如何按文件夹分组，列举桶内所有多版本对象：
```
<?php
// 引入依赖库
require 'vendor/autoload.php';
// 使用源码安装时引入SDK代码库
// require 'obs-autoloader.php';
// 声明命名空间
use Obs\ObsClient;
use Obs\ObsException;
// 创建ObsClient实例
$obsClient = new ObsClient([
    //推荐通过环境变量获取访问密钥AK/SK，这里也可以使用其他外部引入方式传入，如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK，获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
    'key' => getenv('ACCESS_KEY_ID'),
    'secret' => getenv('SECRET_ACCESS_KEY'),
    'endpoint' => 'https://your-endpoint',
]);
// 列举多版本对象
try {
    function listVersionsByPrefix($commonPrefixes){
        global $obsClient;
        foreach ($commonPrefixes as $commonPrefix){
            $resp = $obsClient->listVersions([
                'Bucket' => 'bucketname',
                // 设置文件夹分隔符"/"
                'Delimiter' => '/',
                'Prefix' => $commonPrefix['Prefix']
            ]);
        printf( "Objects in folder [%s]:\n ", $commonPrefix['Prefix']);
        // 获取多版本对象
        printf( "Versions:\n" );
        foreach ($resp['Versions'] as $index => $version) {
            printf( "Versions[%d]\n", $index + 1 );
            printf( "Key:%s\n", $version['Key']);
            printf( "VersionId:%s\n", $version['VersionId']);
        }
    // 获取对象删除标记
    printf( "DeleteMarkers:\n" );
    foreach ($resp['DeleteMarkers'] as $index => $deleteMarker) {
        printf( "DeleteMarkers[%d]\n", $index + 1 );
        printf( "Key:%s\n", $deleteMarker['Key']);
        printf( "VersionId:%s\n", $deleteMarker['VersionId']);
    }
    printf("\n");
    listVersionsByPrefix($resp['CommonPrefixes']);
    }
    }
    $resp = $obsClient->listVersions([
        'Bucket' => 'bucketname',
        // 设置文件夹分隔符"/"
        'Delimiter' => '/'
    ]);printf( "Objects in the root directory:\n ");
    // 获取多版本对象
    printf( "Versions:\n" );
    foreach ($resp['Versions'] as $index => $version) {
        printf( "Versions[%d]\n", $index + 1 );
        printf( "Key:%s\n", $version['Key']);
        printf( "VersionId:%s\n", $version['VersionId']);
    }
    // 获取对象删除标记
    printf( "DeleteMarkers:\n" );
    foreach ($resp['DeleteMarkers'] as $index => $deleteMarker) {
        printf( "DeleteMarkers[%d]\n", $index + 1 );
        printf( "Key:%s\n", $deleteMarker['Key']);
        printf( "VersionId:%s\n", $deleteMarker['VersionId']);
    }
    listVersionsByPrefix($resp['CommonPrefixes']);
} catch (ObsException $e) {
    // 操作失败，获取详细异常信息
    printf("ListVersionsFailed: Status:%d, Code:%s, Message:%s\n",
        $e->getStatusCode(), $e->getExceptionCode(), $e->getExceptionMessage());
} finally {
    // 关闭ObsClient，释放资源
    $obsClient->close();
}
```
![](https://support.huaweicloud.com/sdk-php-devg-obs/public_sys-resources/note_3.0-zh-cn.png)
- 以上代码示例没有考虑文件夹中多版本对象数超过1000个的情况。
- 由于是需要列举出文件夹中的对象和子文件夹，且文件夹对象总是以"/"结尾，因此Delimiter总是为"/"。
- 每次递归的返回结果中Versions包含的是文件夹中的对象；DeleteMarkers包含的是文件夹中的删除标记；CommonPrefixes包含的是文件夹的子文件夹。
 
