This commit is contained in:
2025-10-20 10:02:41 +08:00
parent a4858d47fc
commit dc0a271adf
2805 changed files with 451240 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
composer.phar
/vendor/
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
composer.lock
.vscode/
.idea
.DS_Store
cache/
*.cache
runtime/
.php_cs.cache

View File

@@ -0,0 +1,65 @@
<?php
/*
* This document has been generated with
* https://mlocati.github.io/php-cs-fixer-configurator/#version:2.15|configurator
* you can change this configuration by importing this file.
*/
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setIndent(' ')
->setRules([
'@PSR2' => true,
'@PhpCsFixer' => true,
'@Symfony:risky' => true,
'concat_space' => ['spacing' => 'one'],
'array_syntax' => ['syntax' => 'short'],
'array_indentation' => true,
'combine_consecutive_unsets' => true,
'method_separation' => true,
'single_quote' => true,
'declare_equal_normalize' => true,
'function_typehint_space' => true,
'hash_to_slash_comment' => true,
'include' => true,
'lowercase_cast' => true,
'no_multiline_whitespace_before_semicolons' => true,
'no_leading_import_slash' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'no_spaces_around_offset' => true,
'no_unneeded_control_parentheses' => true,
'no_unused_imports' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'object_operator_without_whitespace' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
'no_extra_consecutive_blank_lines' => [
'curly_brace_block',
'extra',
'parenthesis_brace_block',
'square_brace_block',
'throw',
'use',
],
'binary_operator_spaces' => [
'align_double_arrow' => true,
'align_equals' => true,
],
'braces' => [
'allow_single_line_closure' => true,
],
])
->setFinder(
PhpCsFixer\Finder::create()
->exclude('vendor')
->exclude('tests')
->in(__DIR__)
);

View File

@@ -0,0 +1,31 @@
[English](README.md) | 简体中文
![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg)
## Alibaba Cloud OpenApi Util
## 安装
### Composer
```bash
composer require alibabacloud/openapi-util
```
## 问题
[提交 Issue](https://github.com/aliyun/openapiutil/issues/new),不符合指南的问题可能会立即关闭。
## 发行说明
每个版本的详细更改记录在[发行说明](./ChangeLog.txt)中。
## 相关
* [最新源码](https://github.com/aliyun/openapiutil)
## 许可证
[Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.

View File

@@ -0,0 +1,31 @@
English | [简体中文](README-CN.md)
![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg)
## Alibaba Cloud OpenApi Util
## Installation
### Composer
```bash
composer require alibabacloud/openapi-util
```
## Issues
[Opening an Issue](https://github.com/aliyun/openapiutil/issues/new), Issues not conforming to the guidelines may be closed immediately.
## Changelog
Detailed changes for each release are documented in the [release notes](./ChangeLog.txt).
## References
* [Latest Release](https://github.com/aliyun/openapiutil)
## License
[Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.

View File

@@ -0,0 +1,17 @@
<?php
spl_autoload_register(function ($class) {
$name = str_replace('AlibabaCloud\\OpenApiUtil\\', '', $class);
$file = __DIR__ . \DIRECTORY_SEPARATOR . 'src' . \DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $name) . '.php';
if (file_exists($file)) {
require_once $file;
return true;
}
return false;
});
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
require_once __DIR__ . '/vendor/autoload.php';
}

View File

@@ -0,0 +1,45 @@
{
"name": "alibabacloud/openapi-util",
"description": "Alibaba Cloud OpenApi Util",
"type": "library",
"license": "Apache-2.0",
"authors": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com"
}
],
"require": {
"php": ">5.5",
"alibabacloud/tea": "^3.1",
"alibabacloud/tea-utils": "^0.2",
"lizhichao/one-sm": "^1.5"
},
"require-dev": {
"phpunit/phpunit": "*"
},
"autoload": {
"psr-4": {
"AlibabaCloud\\OpenApiUtil\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"AlibabaCloud\\OpenApiUtil\\Tests\\": "tests"
}
},
"scripts": {
"fixer": "php-cs-fixer fix ./",
"test": [
"@clearCache",
"./vendor/bin/phpunit --colors=always"
],
"clearCache": "rm -rf cache/*"
},
"config": {
"sort-packages": true,
"preferred-install": "dist",
"optimize-autoloader": true
},
"prefer-stable": true
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./tests/bootstrap.php" colors="true" processIsolation="false" stopOnFailure="false"
convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true"
testSuiteLoaderFile="phpunit/src/Runner/StandardTestSuiteLoader.php">
<testsuites>
<testsuite name="All">
<directory>tests</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>integration</group>
</exclude>
</groups>
<logging>
<log type="coverage-html" target="cache/coverage" lowUpperBound="35" highLowerBound="70"/>
<log type="coverage-clover" target="cache/coverage.clover"/>
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,573 @@
<?php
namespace AlibabaCloud\OpenApiUtil;
use AlibabaCloud\Tea\Model;
use AlibabaCloud\Tea\Request;
use AlibabaCloud\Tea\Utils\Utils;
use OneSm\Sm3;
use Psr\Http\Message\StreamInterface;
/**
* This is for OpenApi Util.
*/
class OpenApiUtilClient
{
/**
* Convert all params of body other than type of readable into content.
*
* @param Model $body source Model
* @param Model $content target Model
*/
public static function convert($body, $content)
{
$map = $body->toMap();
$map = self::exceptStream($map);
$newContent = $content::fromMap($map);
$class = new \ReflectionClass($newContent);
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
$name = $property->getName();
if (!$property->isStatic()) {
$content->{$name} = $property->getValue($newContent);
}
}
}
private static function exceptStream($map)
{
if ($map instanceof StreamInterface) {
return null;
} elseif (\is_array($map)) {
$data = [];
foreach ($map as $k => $v) {
if (null !== $v) {
$item = self::exceptStream($v);
if (null !== $item) {
$data[$k] = $item;
}
} else {
$data[$k] = $v;
}
}
return $data;
}
return $map;
}
/**
* Get the string to be signed according to request.
*
* @param Request $request which contains signed messages
*
* @return string the signed string
*/
public static function getStringToSign($request)
{
$pathname = $request->pathname ?: '';
$query = $request->query ?: [];
$accept = isset($request->headers['accept']) ? $request->headers['accept'] : '';
$contentMD5 = isset($request->headers['content-md5']) ? $request->headers['content-md5'] : '';
$contentType = isset($request->headers['content-type']) ? $request->headers['content-type'] : '';
$date = isset($request->headers['date']) ? $request->headers['date'] : '';
$result = $request->method . "\n" .
$accept . "\n" .
$contentMD5 . "\n" .
$contentType . "\n" .
$date . "\n";
$canonicalizedHeaders = self::getCanonicalizedHeaders($request->headers);
$canonicalizedResource = self::getCanonicalizedResource($pathname, $query);
return $result . $canonicalizedHeaders . $canonicalizedResource;
}
/**
* Get signature according to stringToSign, secret.
*
* @param string $stringToSign the signed string
* @param string $secret accesskey secret
*
* @return string the signature
*/
public static function getROASignature($stringToSign, $secret)
{
return base64_encode(hash_hmac('sha1', $stringToSign, $secret, true));
}
/**
* Parse filter into a form string.
*
* @param array $filter object
*
* @return string the string
*/
public static function toForm($filter)
{
$query = $filter;
if (null === $query) {
return '';
}
if ($query instanceof Model) {
$query = $query->toMap();
}
$tmp = [];
foreach ($query as $k => $v) {
if (0 !== strpos($k, '_')) {
$tmp[$k] = $v;
}
}
$res = self::flatten($tmp);
ksort($res);
return http_build_query($res);
}
/**
* Get timestamp.
*
* @return string the timestamp string
*/
public static function getTimestamp()
{
return gmdate('Y-m-d\\TH:i:s\\Z');
}
/**
* Parse filter into a object which's type is map[string]string.
*
* @param array $filter query param
*
* @return array the object
*/
public static function query($filter)
{
if (null === $filter) {
return [];
}
$dict = $filter;
if ($dict instanceof Model) {
$dict = $dict->toMap();
}
$tmp = [];
foreach ($dict as $k => $v) {
if (0 !== strpos($k, '_')) {
$tmp[$k] = $v;
}
}
return self::flatten($tmp);
}
/**
* Get signature according to signedParams, method and secret.
*
* @param array $signedParams params which need to be signed
* @param string $method http method e.g. GET
* @param string $secret AccessKeySecret
*
* @return string the signature
*/
public static function getRPCSignature($signedParams, $method, $secret)
{
$secret .= '&';
$strToSign = self::getRpcStrToSign($method, $signedParams);
$signMethod = 'HMAC-SHA1';
return self::encode($signMethod, $strToSign, $secret);
}
/**
* Parse object into a string with specified style.
*
* @style specified style e.g. repeatList
*
* @param mixed $object the object
* @param string $prefix the prefix string
* @param string $style
*
* @return string the string
*/
public static function arrayToStringWithSpecifiedStyle($object, $prefix, $style)
{
if (null === $object) {
return '';
}
if ('repeatList' === $style) {
return self::toForm([$prefix => $object]);
}
if ('simple' == $style || 'spaceDelimited' == $style || 'pipeDelimited' == $style) {
$strs = self::flatten($object);
switch ($style) {
case 'spaceDelimited':
return implode(' ', $strs);
case 'pipeDelimited':
return implode('|', $strs);
default:
return implode(',', $strs);
}
} elseif ('json' === $style) {
self::parse($object, $parsed);
return json_encode($parsed);
}
return '';
}
/**
* Transform input as array.
*
* @param mixed $input
*
* @return array
*/
public static function parseToArray($input)
{
self::parse($input, $result);
return $result;
}
/**
* Transform input as map.
*
* @param mixed $input
*
* @return array
*/
public static function parseToMap($input)
{
self::parse($input, $result);
return $result;
}
public static function getEndpoint($endpoint, $useAccelerate, $endpointType = 'public')
{
if ('internal' == $endpointType) {
$tmp = explode('.', $endpoint);
$tmp[0] .= '-internal';
$endpoint = implode('.', $tmp);
}
if ($useAccelerate && 'accelerate' == $endpointType) {
return 'oss-accelerate.aliyuncs.com';
}
return $endpoint;
}
/**
* Encode raw with base16.
*
* @param int[] $raw encoding data
*
* @return string encoded string
*/
public static function hexEncode($raw)
{
if (is_array($raw)) {
$raw = Utils::toString($raw);
}
return bin2hex($raw);
}
/**
* Hash the raw data with signatureAlgorithm.
*
* @param int[] $raw hashing data
* @param string $signatureAlgorithm the autograph method
*
* @return array hashed bytes
*/
public static function hash($raw, $signatureAlgorithm)
{
$str = Utils::toString($raw);
switch ($signatureAlgorithm) {
case 'ACS3-HMAC-SHA256':
case 'ACS3-RSA-SHA256':
$res = hash('sha256', $str, true);
return Utils::toBytes($res);
case 'ACS3-HMAC-SM3':
$res = self::sm3($str);
return Utils::toBytes(hex2bin($res));
}
return [];
}
/**
* Get the authorization.
*
* @param Request $request request params
* @param string $signatureAlgorithm the autograph method
* @param string $payload the hashed request
* @param string $accesskey the accessKey string
* @param string $accessKeySecret the accessKeySecret string
*
* @return string authorization string
* @throws \ErrorException
*
*/
public static function getAuthorization($request, $signatureAlgorithm, $payload, $accesskey, $accessKeySecret)
{
$canonicalURI = $request->pathname ? $request->pathname : '/';
$query = $request->query ?: [];
$method = strtoupper($request->method);
$canonicalQueryString = self::getCanonicalQueryString($query);
$signHeaders = [];
foreach ($request->headers as $k => $v) {
$k = strtolower($k);
if (0 === strpos($k, 'x-acs-') || 'host' === $k || 'content-type' === $k) {
$signHeaders[$k] = $v;
}
}
ksort($signHeaders);
$headers = [];
foreach ($request->headers as $k => $v) {
$k = strtolower($k);
if (0 === strpos($k, 'x-acs-') || 'host' === $k || 'content-type' === $k) {
$headers[$k] = trim($v);
}
}
$canonicalHeaderString = '';
ksort($headers);
foreach ($headers as $k => $v) {
$canonicalHeaderString .= $k . ':' . trim(self::filter($v)) . "\n";
}
if (empty($canonicalHeaderString)) {
$canonicalHeaderString = "\n";
}
$canonicalRequest = $method . "\n" . $canonicalURI . "\n" . $canonicalQueryString . "\n" .
$canonicalHeaderString . "\n" . implode(';', array_keys($signHeaders)) . "\n" . $payload;
$strtosign = $signatureAlgorithm . "\n" . self::hexEncode(self::hash(Utils::toBytes($canonicalRequest), $signatureAlgorithm));
$signature = self::sign($accessKeySecret, $strtosign, $signatureAlgorithm);
$signature = self::hexEncode($signature);
return $signatureAlgorithm .
' Credential=' . $accesskey .
',SignedHeaders=' . implode(';', array_keys($signHeaders)) .
',Signature=' . $signature;
}
public static function sign($secret, $str, $algorithm)
{
$result = '';
switch ($algorithm) {
case 'ACS3-HMAC-SHA256':
$result = hash_hmac('sha256', $str, $secret, true);
break;
case 'ACS3-HMAC-SM3':
$result = self::hmac_sm3($str, $secret, true);
break;
case 'ACS3-RSA-SHA256':
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . $secret . "\n-----END RSA PRIVATE KEY-----";
@openssl_sign($str, $result, $privateKey, OPENSSL_ALGO_SHA256);
}
return Utils::toBytes($result);
}
/**
* Get encoded path.
*
* @param string $path the raw path
*
* @return string encoded path
*/
public static function getEncodePath($path)
{
$tmp = explode('/', $path);
foreach ($tmp as &$t) {
$t = rawurlencode($t);
}
return implode('/', $tmp);
}
/**
* Get encoded param.
*
* @param string $param the raw param
*
* @return string encoded param
*/
public static function getEncodeParam($param)
{
return rawurlencode($param);
}
private static function getRpcStrToSign($method, $query)
{
ksort($query);
$params = [];
foreach ($query as $k => $v) {
if (null !== $v) {
$k = rawurlencode($k);
$v = rawurlencode($v);
$params[] = $k . '=' . (string)$v;
}
}
$str = implode('&', $params);
return $method . '&' . rawurlencode('/') . '&' . rawurlencode($str);
}
private static function encode($signMethod, $strToSign, $secret)
{
switch ($signMethod) {
case 'HMAC-SHA256':
return base64_encode(hash_hmac('sha256', $strToSign, $secret, true));
default:
return base64_encode(hash_hmac('sha1', $strToSign, $secret, true));
}
}
/**
* @param array $items
* @param string $delimiter
* @param string $prepend
*
* @return array
*/
private static function flatten($items = [], $delimiter = '.', $prepend = '')
{
$flatten = [];
foreach ($items as $key => $value) {
$pos = \is_int($key) ? $key + 1 : $key;
if ($value instanceof Model) {
$value = $value->toMap();
} elseif (\is_object($value)) {
$value = get_object_vars($value);
}
if (\is_array($value) && !empty($value)) {
$flatten = array_merge(
$flatten,
self::flatten($value, $delimiter, $prepend . $pos . $delimiter)
);
} else {
if (\is_bool($value)) {
$value = true === $value ? 'true' : 'false';
}
$flatten[$prepend . $pos] = $value;
}
}
return $flatten;
}
private static function getCanonicalizedHeaders($headers, $prefix = 'x-acs-')
{
ksort($headers);
$str = '';
foreach ($headers as $k => $v) {
if (0 === strpos(strtolower($k), $prefix)) {
$str .= $k . ':' . trim(self::filter($v)) . "\n";
}
}
return $str;
}
private static function getCanonicalizedResource($pathname, $query)
{
if (0 === \count($query)) {
return $pathname;
}
ksort($query);
$tmp = [];
foreach ($query as $k => $v) {
if (!empty($v)) {
$tmp[] = $k . '=' . $v;
} else {
$tmp[] = $k;
}
}
return $pathname . '?' . implode('&', $tmp);
}
private static function parse($input, &$output)
{
if (null === $input || '' === $input) {
$output = [];
}
$recursive = function ($input) use (&$recursive) {
if ($input instanceof Model) {
$input = $input->toMap();
} elseif (\is_object($input)) {
$input = get_object_vars($input);
}
if (!\is_array($input)) {
return $input;
}
$data = [];
foreach ($input as $k => $v) {
$data[$k] = $recursive($v);
}
return $data;
};
$output = $recursive($input);
if (!\is_array($output)) {
$output = [$output];
}
}
private static function filter($str)
{
return str_replace(["\t", "\n", "\r", "\f"], '', $str);
}
private static function hmac_sm3($data, $key, $raw_output = false)
{
$pack = 'H' . \strlen(self::sm3('test'));
$blocksize = 64;
if (\strlen($key) > $blocksize) {
$key = pack($pack, self::sm3($key));
}
$key = str_pad($key, $blocksize, \chr(0x00));
$ipad = $key ^ str_repeat(\chr(0x36), $blocksize);
$opad = $key ^ str_repeat(\chr(0x5C), $blocksize);
$hmac = self::sm3($opad . pack($pack, self::sm3($ipad . $data)));
return $raw_output ? pack($pack, $hmac) : $hmac;
}
private static function sm3($message)
{
return (new Sm3())->sign($message);
}
private static function getCanonicalQueryString($query)
{
ksort($query);
$params = [];
foreach ($query as $k => $v) {
if (null === $v) {
continue;
}
$str = rawurlencode($k);
if ('' !== $v && null !== $v) {
$str .= '=' . rawurlencode($v);
} else {
$str .= '=';
}
$params[] = $str;
}
return implode('&', $params);
}
}

View File

@@ -0,0 +1,126 @@
<?php
// This file is auto-generated, don't edit it. Thanks.
namespace AlibabaCloud\OpenApiUtil\Tests\Models;
use AlibabaCloud\Tea\Model;
use GuzzleHttp\Psr7\Stream;
class SourceModel extends Model {
protected $_name = [
'test' => 'Test',
'empty' => 'empty',
'bodyObject' => 'body',
'listObject' => 'list',
];
public function validate() {}
public function toMap() {
$res = [];
if (null !== $this->test) {
$res['Test'] = $this->test;
}
if (null !== $this->empty) {
$res['empty'] = $this->empty;
}
if (null !== $this->bodyObject) {
$res['body'] = $this->bodyObject;
}
if (null !== $this->listObject) {
$res['list'] = $this->listObject;
}
if (null !== $this->urlListObject) {
$res['urlList'] = [];
if(null !== $this->urlListObject && is_array($this->urlListObject)){
$n = 0;
foreach($this->urlListObject as $item){
$res['urlList'][$n++] = null !== $item ? $item->toMap() : $item;
}
}
}
return $res;
}
/**
* @param array $map
* @return SourceModel
*/
public static function fromMap($map = []) {
$model = new self();
if(isset($map['Test'])){
$model->test = $map['Test'];
}
if(isset($map['empty'])){
$model->empty = $map['empty'];
}
if(isset($map['body'])){
$model->bodyObject = $map['body'];
}
if(isset($map['list'])){
if(!empty($map['list'])){
$model->listObject = $map['list'];
}
}
if(isset($map['urlList'])){
if(!empty($map['urlList'])){
$model->urlListObject = [];
$n = 0;
foreach($map['urlList'] as $item) {
$model->urlListObject[$n++] = null !== $item ? urlListObject::fromMap($item) : $item;
}
}
}
return $model;
}
/**
* @var string
*/
public $test;
/**
* @var float
*/
public $empty;
/**
* @var Stream
*/
public $bodyObject;
/**
* @var Stream[]
*/
public $listObject;
public $urlListObject;
}
class urlListObject extends Model {
protected $_name = [
'urlObject' => 'url',
];
public function validate() {}
public function toMap() {
$res = [];
if (null !== $this->urlObject) {
$res['url'] = $this->urlObject;
}
return $res;
}
/**
* @param array $map
* @return urlListObject
*/
public static function fromMap($map = []) {
$model = new self();
if(isset($map['url'])){
$model->urlObject = $map['url'];
}
return $model;
}
/**
* @var Stream
*/
public $urlObject;
}

View File

@@ -0,0 +1,125 @@
<?php
// This file is auto-generated, don't edit it. Thanks.
namespace AlibabaCloud\OpenApiUtil\Tests\Models;
use AlibabaCloud\Tea\Model;
use GuzzleHttp\Psr7\Stream;
class TargetModel extends Model {
protected $_name = [
'test' => 'Test',
'empty' => 'empty',
'body' => 'body',
'list' => 'list',
];
public function validate() {}
public function toMap() {
$res = [];
if (null !== $this->test) {
$res['Test'] = $this->test;
}
if (null !== $this->empty) {
$res['empty'] = $this->empty;
}
if (null !== $this->body) {
$res['body'] = $this->body;
}
if (null !== $this->list) {
$res['list'] = $this->list;
}
if (null !== $this->urlList) {
$res['urlList'] = [];
if(null !== $this->urlList && is_array($this->urlList)){
$n = 0;
foreach($this->urlList as $item){
$res['urlList'][$n++] = null !== $item ? $item->toMap() : $item;
}
}
}
return $res;
}
/**
* @param array $map
* @return TargetModel
*/
public static function fromMap($map = []) {
$model = new self();
if(isset($map['Test'])){
$model->test = $map['Test'];
}
if(isset($map['empty'])){
$model->empty = $map['empty'];
}
if(isset($map['body'])){
$model->body = $map['body'];
}
if(isset($map['list'])){
if(!empty($map['list'])){
$model->list = $map['list'];
}
}
if(isset($map['urlList'])){
if(!empty($map['urlList'])){
$model->urlList = [];
$n = 0;
foreach($map['urlList'] as $item) {
$model->urlList[$n++] = null !== $item ? urlList::fromMap($item) : $item;
}
}
}
return $model;
}
/**
* @var string
*/
public $test;
/**
* @var float
*/
public $empty;
/**
* @var Stream
*/
public $body;
/**
* @var string[]
*/
public $list;
public $urlList;
}
class urlList extends Model {
protected $_name = [
'url' => 'url',
];
public function validate() {}
public function toMap() {
$res = [];
if (null !== $this->url) {
$res['url'] = $this->url;
}
return $res;
}
/**
* @param array $map
* @return urlList
*/
public static function fromMap($map = []) {
$model = new self();
if(isset($map['url'])){
$model->url = $map['url'];
}
return $model;
}
/**
* @var string
*/
public $url;
}

View File

@@ -0,0 +1,501 @@
<?php
namespace AlibabaCloud\OpenApiUtil\Tests;
use AlibabaCloud\OpenApiUtil\OpenApiUtilClient;
use AlibabaCloud\OpenApiUtil\Tests\Models\SourceModel;
use AlibabaCloud\OpenApiUtil\Tests\Models\urlListObject;
use AlibabaCloud\OpenApiUtil\Tests\Models\TargetModel;
use AlibabaCloud\Tea\Model;
use AlibabaCloud\Tea\Request;
use AlibabaCloud\Tea\Utils\Utils;
use PHPUnit\Framework\TestCase;
use GuzzleHttp\Psr7\Stream;
/**
* @internal
* @coversNothing
*/
class OpenApiUtilClientTest extends TestCase
{
public function testConvert()
{
$model = new MockModel();
$model->a = 'foo';
$output = new MockModel();
OpenApiUtilClient::convert($model, $output);
$this->assertEquals($model->a, $output->a);
if (\function_exists('\GuzzleHttp\Psr7\stream_for')) {
// @deprecated stream_for will be removed in guzzlehttp/psr7:2.0
$stream = \GuzzleHttp\Psr7\stream_for('test');
} else {
$stream = \GuzzleHttp\Psr7\Utils::streamFor('test');
}
$source = new SourceModel();
$source->test = 'test';
$source->bodyObject = $stream;
$source->listObject = [
$stream
];
$urlListObject = new urlListObject();
$urlListObject->urlObject = $stream;
$source->urlListObject = [
$urlListObject
];
$target = new TargetModel();
OpenApiUtilClient::convert($source, $target);
$this->assertEquals('test', $target->test);
$this->assertNull($target->empty);
$this->assertNull($target->body);
$this->assertTrue(empty($target->list));
$this->assertNotNull($target->urlList[0]);
$this->assertNull($target->urlList[0]->url);
}
public function testGetStringToSign()
{
$request = new Request();
$request->method = 'GET';
$request->pathname = '/';
$request->headers['accept'] = 'application/json';
$this->assertEquals("GET\napplication/json\n\n\n\n/", OpenApiUtilClient::getStringToSign($request));
$request->headers = [
'accept' => 'application/json',
'content-md5' => 'md5',
'content-type' => 'application/json',
'date' => 'date',
];
$this->assertEquals("GET\napplication/json\nmd5\napplication/json\ndate\n/", OpenApiUtilClient::getStringToSign($request));
$request->headers = [
'accept' => 'application/json',
'content-md5' => 'md5',
'content-type' => 'application/json',
'date' => 'date',
'x-acs-custom-key' => 'any value',
];
$this->assertEquals("GET\napplication/json\nmd5\napplication/json\ndate\nx-acs-custom-key:any value\n/", OpenApiUtilClient::getStringToSign($request));
$request->query = [
'key' => 'val ue with space',
];
$this->assertEquals("GET\napplication/json\nmd5\napplication/json\ndate\nx-acs-custom-key:any value\n/?key=val ue with space", OpenApiUtilClient::getStringToSign($request));
}
public function testGetROASignature()
{
$this->assertEquals('OmuTAr79tpI6CRoAdmzKRq5lHs0=', OpenApiUtilClient::getROASignature('stringtosign', 'secret'));
}
public function testToForm()
{
$this->assertEquals('bool=true&client=test&strs.1=str1&strs.2=str2&strs.3=false&tag.key=value', OpenApiUtilClient::toForm([
'client' => 'test',
'tag' => [
'key' => 'value',
],
'strs' => ['str1', 'str2', false],
'bool' => true,
'null' => null,
]));
}
public function testGetTimestamp()
{
$date = OpenApiUtilClient::getTimestamp();
$this->assertEquals(20, \strlen($date));
}
public function testQuery()
{
$model = new MockModel();
$model->a = 'foo';
$model->c = 'boo';
$model->r = true;
$array = [
'a' => 'a',
'b1' => [
'a' => 'a',
],
'b2' => [
'a' => 'a',
],
'c' => ['x', 'y', 'z'],
'd' => [
$model
],
'e' => true,
'f' => null,
];
$this->assertEquals([
'a' => 'a',
'b1.a' => 'a',
'b2.a' => 'a',
'c.1' => 'x',
'c.2' => 'y',
'c.3' => 'z',
'd.1.A' => 'foo',
'd.1.b' => '',
'd.1.c' => 'boo',
'd.1.c' => 'boo',
'd.1.r' => 'true',
'e' => 'true',
'f' => null
], OpenApiUtilClient::query($array));
}
public function testGetRPCSignature()
{
$request = new Request();
$request->pathname = '';
$request->query = [
'query' => 'test',
'body' => 'test',
];
$this->assertEquals('XlUyV4sXjOuX5FnjUz9IF9tm5rU=', OpenApiUtilClient::getRPCSignature($request->query, $request->method, 'secret'));
}
public function testArrayToStringWithSpecifiedStyle()
{
$data = ['ok', 'test', 2, 3];
$this->assertEquals(
'instance.1=ok&instance.2=test&instance.3=2&instance.4=3',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$data,
'instance',
'repeatList'
)
);
$this->assertEquals(
'["ok","test",2,3]',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$data,
'instance',
'json'
)
);
$test = new ParseModel([
'str' => 'A',
'model' => new ParseModel(['str' => 'sub model']),
'array' => [1, 2, 3],
]);
$this->assertEquals(
'{"str":"A","model":{"str":"sub model","model":null,"array":null},"array":[1,2,3]}',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$test,
'instance',
'json'
)
);
// model item in array
$test = [
new ParseModel([
'str' => 'A',
]),
];
$this->assertEquals(
'[{"str":"A","model":null,"array":null}]',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$test,
'instance',
'json'
)
);
// model item in map
$test = [
'model' => new ParseModel([
'str' => 'A',
]),
];
$this->assertEquals(
'{"model":{"str":"A","model":null,"array":null}}',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$test,
'instance',
'json'
)
);
$this->assertEquals(
'ok,test,2,3',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$data,
'instance',
'simple'
)
);
$this->assertEquals(
'ok test 2 3',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$data,
'instance',
'spaceDelimited'
)
);
$this->assertEquals(
'ok|test|2|3',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$data,
'instance',
'pipeDelimited'
)
);
$this->assertEquals(
'',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
$data,
'instance',
'piDelimited'
)
);
$this->assertEquals(
'',
OpenApiUtilClient::arrayToStringWithSpecifiedStyle(
null,
'instance',
'pipeDelimited'
)
);
}
public function testParseToArray()
{
$test = $this->parseData();
$data = $test['data'];
$expected = $test['expected'];
foreach ($data as $index => $item) {
$this->assertEquals($expected[$index], OpenApiUtilClient::parseToArray($item));
}
}
public function testParseToMap()
{
$test = $this->parseData();
$data = $test['data'];
$expected = $test['expected'];
foreach ($data as $index => $item) {
$this->assertEquals($expected[$index], OpenApiUtilClient::parseToMap($item));
}
}
public function testGetEndpoint()
{
$endpoint = 'ecs.cn-hangzhou.aliyun.cs.com';
$useAccelerate = false;
$endpointType = 'public';
$this->assertEquals('ecs.cn-hangzhou.aliyun.cs.com', OpenApiUtilClient::getEndpoint($endpoint, $useAccelerate, $endpointType));
$endpointType = 'internal';
$this->assertEquals('ecs-internal.cn-hangzhou.aliyun.cs.com', OpenApiUtilClient::getEndpoint($endpoint, $useAccelerate, $endpointType));
$useAccelerate = true;
$endpointType = 'accelerate';
$this->assertEquals('oss-accelerate.aliyuncs.com', OpenApiUtilClient::getEndpoint($endpoint, $useAccelerate, $endpointType));
}
public function testHexEncode()
{
$data = OpenApiUtilClient::hash(Utils::toBytes('test'), 'ACS3-HMAC-SHA256');
$this->assertEquals(
Utils::toBytes(hex2bin('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08')),
$data
);
$data = OpenApiUtilClient::hash(Utils::toBytes('test'), 'ACS3-RSA-SHA256');
$this->assertEquals(
Utils::toBytes(hex2bin('9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08')),
$data
);
$data = OpenApiUtilClient::hash(Utils::toBytes('test'), 'ACS3-HMAC-SM3');
$this->assertEquals(
Utils::toBytes(hex2bin('55e12e91650d2fec56ec74e1d3e4ddbfce2ef3a65890c2a19ecf88a307e76a23')),
$data
);
$data = OpenApiUtilClient::hash(Utils::toBytes('test'), 'ACS3-HM-SHA256');
$this->assertEquals('', Utils::toString($data));
}
public function testGetEncodePath()
{
$this->assertEquals(
'/path/%20test',
OpenApiUtilClient::getEncodePath('/path/ test')
);
}
public function testGetEncodeParam()
{
$this->assertEquals(
'a%2Fb%2Fc%2F%20test',
OpenApiUtilClient::getEncodeParam('a/b/c/ test')
);
}
public function testGetAuthorization()
{
$request = new Request();
$request->method = '';
$request->pathname = '';
$request->query = [
'test' => 'ok',
'empty' => '',
];
$request->headers = [
'x-acs-test' => 'http',
'x-acs-TEST' => 'https',
];
$res = OpenApiUtilClient::getAuthorization($request, 'ACS3-HMAC-SHA256', '55e12e91650d2fec56ec74e1d3e4ddbfce2ef3a65890c2a19ecf88a307e76a23', 'acesskey', 'secret');
$this->assertEquals('ACS3-HMAC-SHA256 Credential=acesskey,SignedHeaders=x-acs-test,Signature=0a0f89a45f1ec3537a2d1a1046c71b95513a8f1f02526056968da19b99a5b914', $res);
$request->query = null;
$res = OpenApiUtilClient::getAuthorization($request, 'ACS3-HMAC-SHA256', '55e12e91650d2fec56ec74e1d3e4ddbfce2ef3a65890c2a19ecf88a307e76a23', 'acesskey', 'secret');
$this->assertEquals('ACS3-HMAC-SHA256 Credential=acesskey,SignedHeaders=x-acs-test,Signature=af6d32deb090ae85a21d7183055cf18dca17751da96979cdf964f8f0853e9dd2', $res);
}
public function testSign()
{
$this->assertEquals(
'b9ff646822f41ef647c1416fa2b8408923828abc0464af6706e18db3e8553da8',
OpenApiUtilClient::hexEncode(OpenApiUtilClient::sign('secret', 'source', 'ACS3-HMAC-SM3'))
);
$this->assertEquals(
'1d93c62698a1c26427265668e79fac099aa26c1df873669599a2fb2f272e64c9',
OpenApiUtilClient::hexEncode(OpenApiUtilClient::sign('secret', 'source', 'ACS3-HMAC-SHA256'))
);
}
private function parseData()
{
return [
'data' => [
'NotArray',
new ParseModel([
'str' => 'A',
'model' => new ParseModel(['str' => 'sub model']),
'array' => [1, 2, 3],
]),
[ // model item in array
new ParseModel([
'str' => 'A',
]),
],
[ // model item in map
'model' => new ParseModel([
'str' => 'A',
]),
],
],
'expected' => [
['NotArray'],
[
'str' => 'A',
'model' => [
'str' => 'sub model',
'model' => null,
'array' => null,
],
'array' => [1, 2, 3],
],
[
[
'str' => 'A',
'model' => null,
'array' => null,
],
],
[
'model' => [
'str' => 'A',
'model' => null,
'array' => null,
],
],
],
'expectedJsonStr' => [
'["NotArray"]',
'NotArray',
'NotArray',
'NotArray',
],
];
}
}
class MockModel extends Model
{
public $a = 'A';
public $b = '';
public $c = '';
public $r;
public function __construct()
{
$this->_name['a'] = 'A';
$this->_required['c'] = true;
parent::__construct([]);
}
public function toMap()
{
$res = [];
if (null !== $this->a) {
$res['A'] = $this->a;
}
if (null !== $this->b) {
$res['b'] = $this->b;
}
if (null !== $this->c) {
$res['c'] = $this->c;
}
if (null !== $this->r) {
$res['r'] = $this->r;
}
return $res;
}
public static function fromMap($map = [])
{
$model = new self();
if (isset($map['A'])) {
$model->a = $map['A'];
}
if (isset($map['b'])) {
$model->b = $map['b'];
}
if (isset($map['c'])) {
$model->c = $map['c'];
}
if (isset($map['r'])) {
$model->r = $map['r'];
}
return $model;
}
}
class ParseModel extends Model
{
public $str;
public $model;
public $array;
}

View File

@@ -0,0 +1,3 @@
<?php
require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';