caseyamcl / wosclient
一个便携式PHP客户端库,用于访问DDN(WOS)Web对象标量API中的数据
Requires
- php: ~5.5|~7.0
- psr/http-message: ~1.0
Requires (Dev)
- guzzlehttp/guzzle: ~6.2
- mockery/mockery: ~0.9
- phpunit/phpunit: ~5.4
- scrutinizer/ocular: ~1.1
- squizlabs/php_codesniffer: ~2.3
- symfony/console: ~3.1
This package is auto-updated.
Last update: 2024-09-12 06:14:14 UTC
README
这个库是一个便携式HTTP客户端,用于访问DDN Web Object Scalar存储系统的HTTP API。
与官方DDN PHP客户端不同,此库通过HTTP与WOS设备通信,不需要安装任何PHP C扩展。
安装
此库需要PHP v5.5或更高版本。它已在PHP7上进行了测试。如果您想运行测试,您必须运行v5.6或更高版本。
我还建议安装ext-curl
PHP扩展。
通过Composer
$ composer require caseyamcl/wosclient guzzlehttp/guzzle
注意:默认情况下,此库使用Guzzle v6.0。但是,如果您不想使用Guzzle 6,您可以通过自己实现WosClientInterface
来创建自己的实现(详情见下文)。
用法
此库使用PSR-4自动加载。如果您不使用Composer或其他PSR-4自动加载器,您需要手动包含src/
目录中的所有文件(但我强烈建议这样做;使用自动加载器!)。
如果您知道您的WOS API的URL以及您的WOS策略名称或ID,您可以通过调用WosClient::build()
构造函数来创建一个WosClient
实例。传入您的WOS API的URL以及您的WOS策略名称或ID
use WosClient\WosClient; $wosClient = WosClient::build('http://mywos.example.org/', 'my-policy-id');
WosClient
包含几个公共方法,用于与对象存储API交互
// Get an object by its Object ID (OID) $wosObject = $wosClient->getObject('abcdef-ghijkl-mnopqr-12345'); // Get a range of data for a large object (get bytes 50000-100000) $partialWosObject = $wosClient->getObject('abcdef-ghijkl-mnopqr-12345', '50000-100000'); // Get metadata for an Object ID (OID) $wosMetadata = $wosClient->getMetadata('abcdef-ghijkl-mnopqr-12345'); // Put an object $wosObjectId = $wosClient->putObject('some-serializable-or-streamable-data', ['some' => 'metadata']); // Reserve an Object ID, without putting any data in it yet $wosObjectId = $wosClient->reserveObject(); // Put an object having reserved its ID ahead of time with reserveObject() $wosObjectId = $wosClient->putObject('some-serializable-or-streamable-data', [], $reservedObjectId); // Delete an object $wosClient->deleteObject('abcdef-ghijkl-mnopqr-12345');
所有这些方法都可选地接受一个包含Guzzle HTTP请求选项的数组作为最后一个方法参数。如果您以这种方式传递任何选项,它们将覆盖所有默认和计算出的请求选项。如果您以这种方式传递HTTP头,它们将与默认头合并(见Guzzle文档)。
使用响应
WosClient::getObject()
方法返回一个WosClient\WosObject
实例
// Get the object $wosObject = $wosClient->getObject('abcdef-ghijkl-mnopqr-12345'); // Get the data from the response as a string $wosObject->getData()->__toString(); // or, as a shortcut.. $wosObject->__toString(); // Get the Object ID $wosObject->getId();
WosClient::getMetadata()
和WosObject::getMetadata()
方法返回一个WosClient\WosObjectMetadata
实例
// Get the meta-data (instance of WosObjectMetadata; see below) $metadata = $wosObject->getMetadata(); // Get access to the HTTP response $wosObject->getHttpResponse(); // Get the metadata from the object $wosObject = $wosClient->getObject('abcdef-ghijkl-mnopqr-12345'); $metadata = $wosObject->getMetadata(); // ..or just get the metadata for the object from the WOS server without // getting the content $metadata = $wosClient->getMetadata('abcdef-ghijkl-mnopqr-12345'); // Get the object ID $objectId = $metadata->getObjectId(); // Get the object size in bytes - This returns NULL if not known $numBytes = $metadata->getObjectSize(); // Access custom metadata (having been added with `WosObject::putMetadata()` $foo = $metadata->get('foo'); // Conditionally get metadat if it exists if ($metadata->has('bar')) { $bar = $metadata->get('bar'); } // Metadata implements \Countable, \ArrayAccess, and \Traversable $foo = $metadata['foo']; $bar = $metadata['bar']; $num = count($metadata); for ($metadata as $key => $val) { echo "$key: $val"; }
WosClient::putObject()
和WosClient::reserveObject()
方法返回一个WosClient\WosObjectId
实例
// Put an object with auto-generated ID $wosObjectId = $wosClient->putObject('some object data'); // Reserve an object ID $wosObjectId = $wosClient->reserveObject(); // Get the ID as a string $idString = $wosObjectId->getId(); // ..or cast as string.. $idString = (string) $wosObjectId;
流式传输大对象
WOS支持最大5太字节的对象!
如果您从WOS服务器检索的对象非常大,一次性将其全部读入内存不是一个好主意。
幸运的是,默认情况下,此库将从WOS服务器流数据,而不是将其下载到内存中。该库使用PSR-7 StreamableInterface
来完成此操作。
要流式传输大文件,只需在文件中进行查找,而不是将其转换为字符串
$veryLargeWosObject = $wosClient->getObject('abcdef-ghijkl-mnopqr-12345'); $dataStream = $veryLargeWosObject->getData(); // Read the data stream 1024 bytes at a time, and // echo the data out.. You could do anything with the chunked data if // you wish... while ( ! $dataStream->eof()) { echo $dataStream->read(1024); }
另一种从您的WOS服务器流式传输数据的方法是指定WosClient::getObject()
的$range
参数,以一次检索大对象的片段
$metadata = $wosClient->getMetadata('abcdef-ghijkl-mnopqr-12345'); $chunkSize = 1024; // read this many bytes at a time for ($i = 0; $i < $metadata->getLength(); $i+= $chunkSize) { $from = $i; $to = $i + $chunkSize; // WosClient::getObject second parameter accepts range in the format '####-####' (e.g. '1024-2048') echo $wosClient->getObject('abcdef-ghijkl-mnopqr-12345', $from . '- . $to)->__toString(); }
处理错误
此库将所有应用层运行时错误转换为WosClient\Exception\WosException
实例。有三个子类
WosClient\Exception\WosServerException
- 当 WOS 服务器拒绝请求或遇到错误并返回带有除成功(0)之外的其他x-ddn-status
标头的响应时,会抛出此异常。异常代码将对应于 WOS DDN 状态代码,而消息将是服务器返回的代码的详细描述。WosClient\Exception\InvalidResponseException
- 当服务器返回的 HTTP 响应缺少预期存在的 HTTP 标头时,会抛出此异常。例如,当getObject()
服务器响应不包括x-ddn-oid
标头时。WosClient\Exception\InvalidParameterException
- 当提供的头值不是 WOS 所需的预期格式时,会抛出此异常。例如,如果Range
头不是###-###
格式。它在将请求发送到服务器之前抛出。
示例
use WosClient\Exception\WosServerException; try { $wosClient->getObject('does-not-exist'); } catch (WosServerException $e) { // WOS User-friendly message, e.g., 'Object cannot be located' echo $e->getMessage(); // WOS Code, e.g., 207 echo $e->getCode(); // WOS Error Name (machine-friendly, uses CamelCase), e.g., 'ObjNotFound' echo $e->getErrorName(); }
请注意,只有当服务器返回带有 x-ddn-status
标头的响应,并且该标头值不为零时,才会抛出 WosServerException
。
它不会在发生任何其他 HTTP 传输错误(如网络超时或 WOS 服务器内部错误)时抛出。您可以通过捕获 Guzzle 异常来分别捕获这些类型的 HTTP 错误。
use WosClient\Exception\WosServerException; use WosClient\Exception\WosRequestException; use GuzzleHttp\Exception\GuzzleException; try { $wosClient->getObject('does-not-exist'); } catch (WosServerException $e) { // WOS Exception thrown by the WOS Client echo 'WOS Error: ' . $e->getMessage(); } catch (WosRequestException $e) { // Some other application exception occurred, such as // the WOS server returned a response that is missing an // expected header (this really should never happen) echo 'Something strange happened: ' . $e->getMessage(); } catch (GuzzleException $e) { // HTTP Exception thrown by Guzzle echo 'HTTP Error: ' . $e->getMessage(); }
Guzzle 库包含多个不同类型的异常类,以便您在异常处理中更加具体。
使用自定义 Guzzle 6 客户端实例进行实例化
您可能希望使用自己的 Guzzle 6 客户端实例向 WOS 服务器发送请求。您可能希望这样做的一些原因包括
- 您已设置自己的请求/响应中间件,或
- 您希望使用自定义 HTTP 请求默认值(例如
connect_timeout
),或 - 您希望在请求/响应周期中访问 HTTP
Response
对象。
要使用自定义 Guzzle 客户端实例,只需使用 WosClient\WosClient
类的主构造函数,而不是 build()
构造函数。
base_uri
参数必须在您的 Guzzle 客户端类中设置,否则库将在对象构造期间抛出 \RuntimeException
。此值必须是您的 WOS 节点之一的 URL。
您还可以设置 x-ddn-policy
标头,这样您就不必在每次请求中指定它。
use WosClient\WosClient; use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\HandlerStack; use GuzzleHttp\Handler\CurlHandler; // Setup custom Guzzle client $guzzleClient = new GuzzleClient([ 'base_uri' => 'http://mywos.example.org/', 'connect_timeout' => 60, 'handler' => HandlerStack::create(new CurlHandler()), 'headers' => [ 'x-ddn-policy' => 'my-policy' ], /** ..other guzzle options here.. */ ]); // Instantiate a new WOS Client $wosClient = new WosClient($guzzleClient);
创建不同的 WOS 客户端实现
您可能希望为该库中包含的接口编写自己的实现。在这种情况下,唯一的依赖项是您必须包含 "psr/http-message": "~1.0"
包。
如果您的实现使用的是符合 PSR-7 的 HTTP 库,则您只需要实现 WosClient\WosClientInterface
。您可以使用所有其他类的内置实现。
然而,如果您的实现不实现 PSR-7,则您需要实现以下接口
WosClient\WosClientInterface
WosObjectInterface
WosObjectIdInterface
WosObjectMetadataInterface
Psr\Http\Message\StreamInterface
(提示:Guzzle Streams 做得相当不错)
每个接口文件都包含有关其方法应如何行为的相当不错的文档。
请注意,您应在特定情况下仅抛出异常
WosClient\Exception\WosServerException
- 如果 WOS 服务器发出错误代码(请参阅 WOS API 文档),则抛出此异常。WosClient\Exception\InvalidParameterException
- 如果您在发送请求到服务器之前在客户端验证参数或 HTTP 头,则抛出此异常。WosClient\Exception\InvalidResponseException
- 如果服务器生成客户端无法处理的响应,则抛出此异常。例如,服务器不包括预期存在的 HTTP 头。
变更日志
有关最近更改的更多信息,请参阅变更日志。
测试
要运行测试,请确保您已经安装了 composer.json
文件中的 require-dev
部分的所有依赖项。
运行单元测试
$ composer test
此库还包括一个简单的控制台工具,用于测试客户端与您的 WOS 设备。测试套件将两个微小的对象写入 WOS,然后删除它们。
$ composer livetest http://your-wos.example.org your-policy-id
运行 PHP CodeSniffer 检测风格错误
$ composer sniff
贡献
有关详细信息,请参阅 CONTRIBUTING。
安全性
如果您发现任何与安全相关的问题,请通过电子邮件 caseyamcl@gmail.com 联系,而不是使用问题跟踪器。
致谢
许可证
MIT 许可证 (MIT)。有关更多信息,请参阅 许可证文件。