Skip to content

Commit

Permalink
Merge pull request #42 from TheNorthMemory/v1.2
Browse files Browse the repository at this point in the history
bump to v1.2.2
  • Loading branch information
xy-peng authored Sep 9, 2021
2 parents b7398ef + f1cd86c commit a50af01
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 23 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# 变更历史

## 1.2.2 - 2021-09-09

[变更细节](../../compare/v1.2.1...v1.2.2)

-`at sign`形式,温和提示`APIv2``DEP_XML_PROTOCOL_IS_REACHABLE_EOL`,相关[#38](https://github.com/wechatpay-apiv3/wechatpay-php/issues/38)
- 优化`Transformer::toArray`函数,对入参`xml`非法时,返回空`array`,并把最后一条错误信息温和地打入`E_USER_NOTICE`通道;
- 修正`Formatter::ksort`排列键值时兼容问题,使用`字典序(dictionary order)`排序,相关[#41](https://github.com/wechatpay-apiv3/wechatpay-php/issues/41), 感谢 @suiaiyun 报告此问题;

## 1.2.1 - 2021-09-06

[变更细节](../../compare/v1.2.0...v1.2.1)
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ APIv3已内置 `请求签名` 和 `应答验签` 两个middleware中间件,创

## 项目状态

当前版本为`1.2.1`测试版本。
当前版本为`1.2.2`测试版本。
请商户的专业技术人员在使用时注意系统和软件的正确性和兼容性,以及带来的风险。

**版本说明:** `开发版`指: `类库API`随时会变;`测试版`指: 少量`类库API`可能会变;`稳定版`指: `类库API`稳定持续;版本遵循[语义化版本号](https://semver.org/lang/zh-CN/)规则。
Expand Down Expand Up @@ -60,7 +60,7 @@ composer require wechatpay/wechatpay

```json
"require": {
"wechatpay/wechatpay": "^1.2.1"
"wechatpay/wechatpay": "^1.2.2"
}
```

Expand Down Expand Up @@ -402,6 +402,8 @@ try {

商户在平滑迁移时,务必调整`php.ini``display_errors=Off`或者`error_reporting`错误级别,来防止把这条**提醒**信息打送至前台业务系统。

**注:** `v1.2.2`版调整了上述提示,直至`APIv2`生命周期结束,不再强提示。

### 初始化

```php
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wechatpay/wechatpay",
"version": "1.2.1",
"version": "1.2.2",
"description": "[A]Sync Chainable WeChatPay v2&v3's OpenAPI SDK for PHP",
"type": "library",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion src/ClientDecoratorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface ClientDecoratorInterface
/**
* @var string - This library version
*/
public const VERSION = '1.2.1';
public const VERSION = '1.2.2';

/**
* @var string - The HTTP transfer `xml` based protocol
Expand Down
2 changes: 1 addition & 1 deletion src/ClientXmlTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ abstract protected static function withDefaults(array ...$config): array;
public static function transformRequest(?string $mchid = null, string $secret = '', ?array $merchant = null): callable
{
return static function (callable $handler) use ($mchid, $secret, $merchant): callable {
trigger_error(Exception\WeChatPayException::DEP_XML_PROTOCOL_IS_REACHABLE_EOL, E_USER_DEPRECATED);
@trigger_error(Exception\WeChatPayException::DEP_XML_PROTOCOL_IS_REACHABLE_EOL, E_USER_DEPRECATED);

return static function (RequestInterface $request, array $options = []) use ($handler, $mchid, $secret, $merchant): PromiseInterface {
$data = $options['xml'] ?? [];
Expand Down
7 changes: 3 additions & 4 deletions src/Formatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
use function ksort;
use function is_null;

use const SORT_FLAG_CASE;
use const SORT_NATURAL;
use const SORT_STRING;

use InvalidArgumentException;

Expand Down Expand Up @@ -113,15 +112,15 @@ public static function joinedByLineFeed(...$pieces): string
}

/**
* Sort an array by key with `SORT_FLAG_CASE | SORT_NATURAL` flag.
* Sort an array by key with `SORT_STRING` flag.
*
* @param array<string, string|int> $thing - The input array.
*
* @return array<string, string|int> - The sorted array.
*/
public static function ksort(array $thing = []): array
{
ksort($thing, SORT_FLAG_CASE | SORT_NATURAL);
ksort($thing, SORT_STRING);

return $thing;
}
Expand Down
21 changes: 21 additions & 0 deletions src/Transformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,17 @@
use function array_walk;
use function is_array;
use function is_object;
use function is_string;
use function preg_replace;
use function strpos;
use function preg_match;
use function sprintf;
use function trigger_error;
use function libxml_clear_errors;
use function libxml_disable_entity_loader;
use function libxml_get_last_error;
use function libxml_use_internal_errors;
use function simplexml_load_string;

use SimpleXMLElement;
use Traversable;
Expand All @@ -40,10 +48,23 @@ public static function toArray(string $xml = '<xml/>'): array
{
LIBXML_VERSION < 20900 && $previous = libxml_disable_entity_loader(true);

libxml_use_internal_errors(true);
$el = simplexml_load_string(static::sanitize($xml), SimpleXMLElement::class, LIBXML_NONET | LIBXML_COMPACT | LIBXML_NOCDATA | LIBXML_NOBLANKS);

LIBXML_VERSION < 20900 && isset($previous) && libxml_disable_entity_loader($previous);

if (false === $el && false !== ($err = libxml_get_last_error())) {
// while parsing failed, let's clean the internal buffer and
// only leave the last error message which still can be fetched by the `error_get_last()` function.
libxml_clear_errors();
@trigger_error(sprintf(
'Parsing the $xml failed with the last error(level=%d,code=%d,message=%s).',
$err->level, $err->code, $err->message
));

return [];
}

return static::cast($el);
}

Expand Down
58 changes: 56 additions & 2 deletions tests/FormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

namespace WeChatPay\Tests;

use const SORT_FLAG_CASE;
use const SORT_STRING;
use const SORT_NATURAL;
use const SORT_REGULAR;

use function method_exists;
use function strlen;
use function strval;
Expand Down Expand Up @@ -236,7 +241,7 @@ public function testNoneArgumentPassedToJoinedByLineFeed(): void
/**
* @return array<string,array<array<string,string>>>
*/
public function ksortByFlagNaturePhrasesProvider(): array
public function ksortPhrasesProvider(): array
{
return [
'normal' => [
Expand All @@ -247,19 +252,68 @@ public function ksortByFlagNaturePhrasesProvider(): array
['rfc1' => '1', 'b' => '4', 'rfc822' => '2', 'rfc2086' => '3'],
['b' => '4', 'rfc1' => '1', 'rfc822' => '2', 'rfc2086' => '3'],
],
'issue #41 `re_openid` with `remark` keys' => [
[
'mch_billno' => 'etGkDmT3BJyuhnhU9d', 'mch_id' => 'xxxxx', 'wxappid' => 'wx01111111', 'send_name' => 'aaaaa', 're_openid' => 'o8xSOxxxxxxx',
'total_amount' => '100', 'total_num' => '1', 'wishing' => '红包祝福语', 'client_ip' => '192.168.0.1', 'act_name' => '活动名称', 'remark' => '备注',
],
[
'act_name' => '活动名称', 'client_ip' => '192.168.0.1', 'mch_billno' => 'etGkDmT3BJyuhnhU9d', 'mch_id' => 'xxxxx', 're_openid' => 'o8xSOxxxxxxx',
'remark' => '备注', 'send_name' => 'aaaaa', 'total_amount' => '100', 'total_num' => '1', 'wishing' => '红包祝福语', 'wxappid' => 'wx01111111',
],
],
'the key point of the issue #41 different' => [
[
're_openid' => 'o8xSOxxxxxxx', 'remark' => '备注',
],
[
're_openid' => 'o8xSOxxxxxxx', 'remark' => '备注',
],
],
];
}

/**
* @param array<string,string> $thing
* @param array<string,string> $excepted
* @dataProvider ksortByFlagNaturePhrasesProvider
* @dataProvider ksortPhrasesProvider
*/
public function testKsort(array $thing, array $excepted): void
{
self::assertEquals(Formatter::ksort($thing), $excepted);
}

public function testKsortWithDifferentFlags(): void
{
$excepted = ['re_openid' => 'o8xSOxxxxxxx', 'remark' => '备注'];
// `_` chrcode is 95, `m` is 109, the ordering should be the above

$sample1 = ['remark' => '备注', 're_openid' => 'o8xSOxxxxxxx'];
// `natural ordering`
self::assertTrue(ksort($sample1, SORT_FLAG_CASE | SORT_NATURAL));
self::assertNotEquals(array_keys($excepted), array_keys($sample1));

$sample2 = ['remark' => '备注', 're_openid' => 'o8xSOxxxxxxx'];
// `dictionary order`
self::assertTrue(ksort($sample2, SORT_FLAG_CASE | SORT_STRING));
self::assertEquals(array_keys($excepted), array_keys($sample2));

$sample3 = ['remark' => '备注', 're_openid' => 'o8xSOxxxxxxx'];
// `default SORT_REGULAR`
self::assertTrue(ksort($sample3, SORT_REGULAR));
self::assertEquals(array_keys($excepted), array_keys($sample3));

$sample4 = ['remark' => '备注', 're_openid' => 'o8xSOxxxxxxx'];
// `natural ordering`
self::assertTrue(ksort($sample4, SORT_NATURAL));
self::assertEquals(array_keys($excepted), array_keys($sample4));

$sample5 = ['remark' => '备注', 're_openid' => 'o8xSOxxxxxxx'];
// `dictionary order`
self::assertTrue(ksort($sample5, SORT_STRING));
self::assertEquals(array_keys($excepted), array_keys($sample5));
}

/**
* @return array<string,array<array<string,string>>>
*/
Expand Down
25 changes: 13 additions & 12 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,19 @@ Certificate:
vendor/bin/phpunit
PHPUnit 9.5.9 by Sebastian Bergmann and contributors.
............................................................... 63 / 500 ( 12%)
............................................................... 126 / 500 ( 25%)
............................................................... 189 / 500 ( 37%)
............................................................... 252 / 500 ( 50%)
............................................................... 315 / 500 ( 63%)
............................................................... 378 / 500 ( 75%)
............................................................... 441 / 500 ( 88%)
........................................................... 500 / 500 (100%)
Time: 00:00.641, Memory: 12.00 MB
OK (500 tests, 2258 assertions)
............................................................... 63 / 507 ( 12%)
............................................................... 126 / 507 ( 24%)
............................................................... 189 / 507 ( 37%)
............................................................... 252 / 507 ( 49%)
............................................................... 315 / 507 ( 62%)
............................................................... 378 / 507 ( 74%)
............................................................... 441 / 507 ( 86%)
............................................................... 504 / 507 ( 99%)
... 507 / 507 (100%)
Time: 00:00.636, Memory: 12.00 MB
OK (507 tests, 2280 assertions)
rm -rf ./tests/fixtures/mock.*
```

Expand Down
43 changes: 43 additions & 0 deletions tests/TransformerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
use function array_map;
use function file_get_contents;
use function json_encode;
use function is_string;
use function error_clear_last;
use function error_get_last;
use function method_exists;

use WeChatPay\Transformer;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -82,6 +86,45 @@ public function testToArray(string $xmlString, array $keys): void
}, $keys);
}

/**
* @return array<string,array{string,?string}>
*/
public function xmlToArrayBadPhrasesDataProvider(): array
{
$baseDir = __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR;

return [
$f = 'fragment_injection.sample.xml' => [(string)file_get_contents($baseDir . $f), null],
$f = 'invalid.xxe_injection.sample.xml' => [(string)file_get_contents($baseDir . $f), null],
$f = 'invalid.bad_entity.sample.xml' => [(string)file_get_contents($baseDir . $f), '#^Parsing the \$xml failed with the last error#'],
$f = 'invalid.normal_404.sample.html' => [(string)file_get_contents($baseDir . $f), '#^Parsing the \$xml failed with the last error#'],
];
}

/**
* @dataProvider xmlToArrayBadPhrasesDataProvider
* @param string $xmlString
* @param ?string $pattern
*/
public function testToArrayBadPhrases(string $xmlString, ?string $pattern): void
{
error_clear_last();
$array = Transformer::toArray($xmlString);
self::assertIsArray($array);
if (is_string($pattern)) {
self::assertEmpty($array);
/** @var array{'message':string,'type':int,'file':string,'line':int} $err */
$err = error_get_last();
if (method_exists($this, 'assertMatchesRegularExpression')) {
$this->assertMatchesRegularExpression($pattern, $err['message']);
} else {
self::assertRegExp($pattern, $err['message']);
}
} else {
self::assertNotEmpty($array);
}
}

/**
* @return array<string,array{array<mixed>,bool,bool,string,string}>
*/
Expand Down
14 changes: 14 additions & 0 deletions tests/fixtures/fragment_injection.sample.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<batchjob>
<payment>
<account>5678-attacker</account>
<rcpt>206-1234</rcpt>
<amount>100.00</amount>
<comment></comment>
</payment>
<payment>
<account>1234-victim</account>
<rcpt>206-1234</rcpt>
<amount>100.00</amount>
<comment>Hacked</comment>
</payment>
</batchjob>
6 changes: 6 additions & 0 deletions tests/fixtures/invalid.bad_entity.sample.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" standalone="yes"?>
<movies>
<movie>
<titles>PHP: Behind the Parser</title>
</movie>
</movies>
7 changes: 7 additions & 0 deletions tests/fixtures/invalid.normal_404.sample.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
3 changes: 3 additions & 0 deletions tests/fixtures/invalid.xxe_injection.sample.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://tst.qq.com/xxe_inject/463103c2ee4067e1c4f5318440dc245d">]>
<foo><value>&xxe;</value></foo>

0 comments on commit a50af01

Please sign in to comment.