作者 竞泽

add

  1 +敏付(第三方清关)
  2 +===
  3 +
  4 +### install
  5 +
  6 +```
  7 +composer require lackoxygen/min-payment
  8 +```
  9 +
  10 +### git
  11 +
  12 +```
  13 +http://47.107.73.162:8099/lackoxygen/min-payment.git
  14 +```
  15 +
  16 +### 配置仓库
  17 +
  18 +```
  19 +{
  20 + "type": "git",
  21 + "url": "http://47.107.73.162:8099/lackoxygen/min-payment.git"
  22 +}
  23 +```
  24 +
  25 +### 配置文件
  26 +
  27 +```
  28 +发布暂时无法生成,手动copy到config
  29 +```
  30 +
  31 +### 示例
  32 +
  33 +```
  34 + $min = new MinPayment();
  35 +
  36 + $ret = $min->identifyOrder(function (IdentifyOrder $realNameAuth) {
  37 + $realNameAuth->setName('hello');
  38 + $realNameAuth->setCid('5234235345x');
  39 + $realNameAuth->setOrderNo('2123');
  40 + $realNameAuth->setType(1);
  41 + });
  42 +
  43 + var_dump($ret->isSuccess());
  44 +```
  45 +
  46 +
  47 +
  1 +{
  2 + "name": "root/min-payment",
  3 + "type": "library",
  4 + "description": "敏付",
  5 + "license": "MIT",
  6 + "authors": [
  7 + {
  8 + "name": "jz",
  9 + "email": "jingzeou@outlook.com"
  10 + }
  11 + ],
  12 + "require": {
  13 + "php": ">=7.1",
  14 + "illuminate/support": "^5.8"
  15 + },
  16 + "require-dev": {
  17 + "phpunit/phpunit": "~4.0"
  18 + },
  19 + "autoload": {
  20 + "psr-4": {
  21 + "Lackoxygen\\MinPayment\\": "src/"
  22 + }
  23 + },
  24 + "extra": {
  25 + "laravel": {
  26 + "providers": [
  27 + "Lackoxygen\\MinPayment\\MinPaymentProvider"
  28 + ]
  29 + }
  30 + }
  31 +}
  1 +<?php
  2 +
  3 +return [
  4 + 'merchant_id' => '',
  5 + 'secret' => '',
  6 + 'version' => '',
  7 + 'options' => [
  8 + 'client' => [
  9 + 'base_uri' => 'https://openapi.minfupay.cn',
  10 + 'time' => 30,
  11 + ],
  12 + 'retry' => 1
  13 + ]
  14 +];
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment\Constant;
  4 +
  5 +use Illuminate\Support\Arr;
  6 +
  7 +class Status
  8 +{
  9 + public const SUCCESS = '00';
  10 +
  11 + public static $constants = [
  12 + '00' => '操作成功',
  13 + '1007' => '缺少必要信息或参数格式不符合',
  14 + '1043' => '异常提交',
  15 + '1009' => '签名错误',
  16 + '1008' => '商户状态异常或配置错误',
  17 + '1004' => '商户不存在',
  18 + '1403' => '业务未开通或业务状态非正常',
  19 + '1503' => '系统未开启该业务或未被支持',
  20 + '1019' => '余额不足',
  21 + '1021' => '账户状态非正常',
  22 + '1020' => '扣款失败',
  23 + '1024' => '账户不存在',
  24 + '1010' => '系统异常',
  25 + '1018' => '订单支付信息异常(支付人实名认证信息与订单不匹配或实名认证未通过)',
  26 + '1011' => '身份验证异常',
  27 + '1015' => '订单已存在',
  28 + '1014' => '申报订单不存在',
  29 + '1001' => '证件号码与姓名一致',
  30 + '1002' => '证件号码与姓名不一致',
  31 + '1003' => '身份验证异常(网络原因可重新发起)'
  32 + ];
  33 +
  34 + /**
  35 + * @param string $code
  36 + * @param string $default
  37 + *
  38 + * @return array|\ArrayAccess|mixed
  39 + */
  40 + public static function translation(string $code, string $default = '')
  41 + {
  42 + return Arr::get(self::$constants, $code, $default);
  43 + }
  44 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment\Contract;
  4 +
  5 +interface ResponseInterface
  6 +{
  7 + /**
  8 + * @return bool
  9 + */
  10 + public function isSuccess(): bool;
  11 +
  12 + /**
  13 + * @return array
  14 + */
  15 + public function toArray(): array;
  16 +
  17 + /**
  18 + * @return string
  19 + */
  20 + public function toString(): string;
  21 +
  22 + /**
  23 + * @return string
  24 + */
  25 + public function getContent(): string;
  26 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment\Exception;
  4 +
  5 +class Exception extends \Exception
  6 +{
  7 +
  8 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment;
  4 +
  5 +use Lackoxygen\MinPayment\Contract\ResponseInterface;
  6 +use Lackoxygen\MinPayment\Request\CustomsOrder;
  7 +use Lackoxygen\MinPayment\Request\CustomsQuery;
  8 +use Lackoxygen\MinPayment\Request\IdentifyOrder;
  9 +use Lackoxygen\MinPayment\Utils\Client;
  10 +use Lackoxygen\MinPayment\Utils\Signature;
  11 +
  12 +class MinPayment
  13 +{
  14 + /**
  15 + * @var Client $client
  16 + */
  17 + protected $client;
  18 +
  19 +
  20 + public function __construct(array $config = [])
  21 + {
  22 + $this->client = new Client($config + (array)\config('min-payment'));
  23 + }
  24 +
  25 + /**
  26 + * @param callable $options
  27 + *
  28 + * @return ResponseInterface
  29 + * @throws Exception\Exception
  30 + */
  31 + public function identifyOrder(callable $options): ResponseInterface
  32 + {
  33 + $identifyOrder = new IdentifyOrder;
  34 +
  35 + $options(new IdentifyOrder);
  36 +
  37 + $client = $this->client;
  38 +
  39 + return $client($identifyOrder);
  40 + }
  41 +
  42 +
  43 + /**
  44 + * @param callable $options
  45 + *
  46 + * @return ResponseInterface
  47 + * @throws Exception\Exception
  48 + */
  49 + public function customsOrder(callable $options): ResponseInterface
  50 + {
  51 + $customsOrder = new CustomsOrder;
  52 +
  53 + $options($customsOrder);
  54 +
  55 + $client = $this->client;
  56 +
  57 + return $client($customsOrder);
  58 + }
  59 +
  60 + /**
  61 + * @param callable $options
  62 + *
  63 + * @return ResponseInterface
  64 + * @throws Exception\Exception
  65 + */
  66 + public function customsQuery(callable $options): ResponseInterface
  67 + {
  68 + $customsQuery = new CustomsQuery;
  69 +
  70 + $options($customsQuery);
  71 +
  72 + $client = $this->client;
  73 +
  74 + return $client($customsQuery);
  75 + }
  76 +
  77 +
  78 + /**
  79 + * @param array $input
  80 + * @param string $signName
  81 + *
  82 + * @return bool
  83 + */
  84 + public function verify(array $input, string $signName = 'sign'): bool
  85 + {
  86 + $sign = \Arr::get($input, $signName);
  87 + unset($input[$signName]);
  88 +
  89 + return Signature::make($input) === $sign;
  90 + }
  91 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment;
  4 +
  5 +use Illuminate\Support\ServiceProvider;
  6 +
  7 +class MinPaymentProvider extends ServiceProvider
  8 +{
  9 + public function boot()
  10 + {
  11 + $configPath = __DIR__ . '/../config/min-payment.php';
  12 + $this->publishes([$configPath => config_path('min-payment.php')], 'lackoxygen');
  13 + }
  14 +
  15 + /**
  16 + * @return string[]
  17 + */
  18 + public function provides()
  19 + {
  20 + return ['minPayment', MinPayment::class];
  21 + }
  22 +
  23 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment\Request;
  4 +
  5 +class CustomsOrder extends Request
  6 +{
  7 + /**
  8 + * @var string
  9 + */
  10 + private $appType;
  11 +
  12 + /**
  13 + * @var string
  14 + */
  15 + private $customsType;
  16 +
  17 + /**
  18 + * @var string
  19 + */
  20 + private $payTransactionId;
  21 +
  22 + /**
  23 + * @var string
  24 + */
  25 + private $orderNo;
  26 +
  27 + /**
  28 + * @var string
  29 + */
  30 + private $ebpCode;
  31 +
  32 + /**
  33 + * @var string
  34 + */
  35 + private $ebpName;
  36 +
  37 + /**
  38 + * @var string
  39 + */
  40 + private $payerIdNumber;
  41 +
  42 + /**
  43 + * @var string
  44 + */
  45 + private $payerName;
  46 +
  47 + /**
  48 + * @var string
  49 + */
  50 + private $telephone;
  51 +
  52 + /**
  53 + * @var string
  54 + */
  55 + private $amountPaid;
  56 +
  57 + /**
  58 + * @var string
  59 + */
  60 + private $payTime;
  61 +
  62 + /**
  63 + * @var string
  64 + */
  65 + private $note;
  66 +
  67 + /**
  68 + * @var string
  69 + */
  70 + private $commodityName;
  71 +
  72 + /**
  73 + * @var string
  74 + */
  75 + private $commodityDetails;
  76 +
  77 + /**
  78 + * @var string
  79 + */
  80 + private $isSplit;
  81 +
  82 + /**
  83 + * @var string
  84 + */
  85 + private $subOrderNo;
  86 +
  87 + /**
  88 + * @var string
  89 + */
  90 + private $productType;
  91 +
  92 + /**
  93 + * @var string
  94 + */
  95 + private $logisticsCompany;
  96 +
  97 + /**
  98 + * @var string
  99 + */
  100 + private $logisticsNumber;
  101 +
  102 +
  103 + public function __construct()
  104 + {
  105 + $this->service = 'service.customsOrder';
  106 + }
  107 +
  108 + /**
  109 + * @param string $appType
  110 + */
  111 + public function setAppType(string $appType): void
  112 + {
  113 + $this->appType = $appType;
  114 + }
  115 +
  116 + /**
  117 + * @param string $customsType
  118 + */
  119 + public function setCustomsType(string $customsType): void
  120 + {
  121 + $this->customsType = $customsType;
  122 + }
  123 +
  124 + /**
  125 + * @param string $payTransactionId
  126 + */
  127 + public function setPayTransactionId(string $payTransactionId): void
  128 + {
  129 + $this->payTransactionId = $payTransactionId;
  130 + }
  131 +
  132 + /**
  133 + * @param string $orderNo
  134 + */
  135 + public function setOrderNo(string $orderNo): void
  136 + {
  137 + $this->orderNo = $orderNo;
  138 + }
  139 +
  140 + /**
  141 + * @param string $ebpCode
  142 + */
  143 + public function setEbpCode(string $ebpCode): void
  144 + {
  145 + $this->ebpCode = $ebpCode;
  146 + }
  147 +
  148 + /**
  149 + * @param string $ebpName
  150 + */
  151 + public function setEbpName(string $ebpName): void
  152 + {
  153 + $this->ebpName = $ebpName;
  154 + }
  155 +
  156 + /**
  157 + * @param string $payerIdNumber
  158 + */
  159 + public function setPayerIdNumber(string $payerIdNumber): void
  160 + {
  161 + $this->payerIdNumber = $payerIdNumber;
  162 + }
  163 +
  164 + /**
  165 + * @param string $payerName
  166 + */
  167 + public function setPayerName(string $payerName): void
  168 + {
  169 + $this->payerName = $payerName;
  170 + }
  171 +
  172 + /**
  173 + * @param string $telephone
  174 + */
  175 + public function setTelephone(string $telephone): void
  176 + {
  177 + $this->telephone = $telephone;
  178 + }
  179 +
  180 + /**
  181 + * @param string $amountPaid
  182 + */
  183 + public function setAmountPaid(string $amountPaid): void
  184 + {
  185 + $this->amountPaid = $amountPaid;
  186 + }
  187 +
  188 + /**
  189 + * @param string $payTime
  190 + */
  191 + public function setPayTime(string $payTime): void
  192 + {
  193 + $this->payTime = $payTime;
  194 + }
  195 +
  196 + /**
  197 + * @param string $note
  198 + */
  199 + public function setNote(string $note): void
  200 + {
  201 + $this->note = $note;
  202 + }
  203 +
  204 + /**
  205 + * @param string $commodityName
  206 + */
  207 + public function setCommodityName(string $commodityName): void
  208 + {
  209 + $this->commodityName = $commodityName;
  210 + }
  211 +
  212 + /**
  213 + * @param string $commodityDetails
  214 + */
  215 + public function setCommodityDetails(string $commodityDetails): void
  216 + {
  217 + $this->commodityDetails = $commodityDetails;
  218 + }
  219 +
  220 + /**
  221 + * @param string $isSplit
  222 + */
  223 + public function setIsSplit(string $isSplit): void
  224 + {
  225 + $this->isSplit = $isSplit;
  226 + }
  227 +
  228 + /**
  229 + * @param string $subOrderNo
  230 + */
  231 + public function setSubOrderNo(string $subOrderNo): void
  232 + {
  233 + $this->subOrderNo = $subOrderNo;
  234 + }
  235 +
  236 + /**
  237 + * @param string $productType
  238 + */
  239 + public function setProductType(string $productType): void
  240 + {
  241 + $this->productType = $productType;
  242 + }
  243 +
  244 + /**
  245 + * @param string $logisticsCompany
  246 + */
  247 + public function setLogisticsCompany(string $logisticsCompany): void
  248 + {
  249 + $this->logisticsCompany = $logisticsCompany;
  250 + }
  251 +
  252 + /**
  253 + * @param string $logisticsNumber
  254 + */
  255 + public function setLogisticsNumber(string $logisticsNumber): void
  256 + {
  257 + $this->logisticsNumber = $logisticsNumber;
  258 + }
  259 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment\Request;
  4 +
  5 +class CustomsQuery extends Request
  6 +{
  7 + /**
  8 + * @var string
  9 + */
  10 + private $appType;
  11 +
  12 + /**
  13 + * @var string
  14 + */
  15 + private $customsType;
  16 +
  17 + /**
  18 + * @var string
  19 + */
  20 + private $payTransactionId;
  21 +
  22 + /**
  23 + * @var string
  24 + */
  25 + private $orderNo;
  26 +
  27 + /**
  28 + * @var string
  29 + */
  30 + private $subOrderNo;
  31 +
  32 + /**
  33 + * @var string
  34 + */
  35 + private $subPayTransactionId;
  36 +
  37 + /**
  38 + * @param mixed $appType
  39 + */
  40 + public function setAppType($appType): void
  41 + {
  42 + $this->appType = $appType;
  43 + }
  44 +
  45 + /**
  46 + * @param mixed $customsType
  47 + */
  48 + public function setCustomsType($customsType): void
  49 + {
  50 + $this->customsType = $customsType;
  51 + }
  52 +
  53 + /**
  54 + * @param mixed $payTransactionId
  55 + */
  56 + public function setPayTransactionId($payTransactionId): void
  57 + {
  58 + $this->payTransactionId = $payTransactionId;
  59 + }
  60 +
  61 + /**
  62 + * @param mixed $orderNo
  63 + */
  64 + public function setOrderNo($orderNo): void
  65 + {
  66 + $this->orderNo = $orderNo;
  67 + }
  68 +
  69 + /**
  70 + * @param mixed $subOrderNo
  71 + */
  72 + public function setSubOrderNo($subOrderNo): void
  73 + {
  74 + $this->subOrderNo = $subOrderNo;
  75 + }
  76 +
  77 + /**
  78 + * @param mixed $subPayTransactionId
  79 + */
  80 + public function setSubPayTransactionId($subPayTransactionId): void
  81 + {
  82 + $this->subPayTransactionId = $subPayTransactionId;
  83 + }
  84 +
  85 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment\Request;
  4 +
  5 +class IdentifyOrder extends Request
  6 +{
  7 + /**
  8 + * @var string
  9 + */
  10 + protected $name;
  11 +
  12 + /**
  13 + * @var string
  14 + */
  15 + protected $cid;
  16 +
  17 + /**
  18 + * @var string
  19 + */
  20 + protected $orderNo;
  21 +
  22 + /**
  23 + * @var string
  24 + */
  25 + protected $type;
  26 +
  27 +
  28 + public function __construct()
  29 + {
  30 + $this->service = 'service.identifyOrder';
  31 + }
  32 +
  33 + /**
  34 + * @param mixed $name
  35 + */
  36 + public function setName(string $name): void
  37 + {
  38 + $this->name = $name;
  39 + }
  40 +
  41 + /**
  42 + * @param mixed $cid
  43 + */
  44 + public function setCid(string $cid): void
  45 + {
  46 + $suffix = substr($cid, -1, 1);
  47 + if (ord($suffix) === 120) {
  48 + $cid[strlen($cid) - 1] = chr(88);
  49 + }
  50 + $this->cid = $cid;
  51 + }
  52 +
  53 + /**
  54 + * @param mixed $orderNo
  55 + */
  56 + public function setOrderNo(string $orderNo): void
  57 + {
  58 + $this->orderNo = $orderNo;
  59 + }
  60 +
  61 + /**
  62 + * @param mixed $type
  63 + */
  64 + public function setType(string $type): void
  65 + {
  66 + $this->type = $type;
  67 + }
  68 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment\Request;
  4 +
  5 +use GuzzleHttp\RequestOptions;
  6 +use Illuminate\Support\Arr;
  7 +use Lackoxygen\MinPayment\Utils\Signature;
  8 +use ReflectionProperty;
  9 +
  10 +class Request
  11 +{
  12 + /**
  13 + * @var string
  14 + */
  15 + protected $mchtId;
  16 +
  17 + /**
  18 + * @var string
  19 + */
  20 + protected $service;
  21 +
  22 + /**
  23 + * @var string
  24 + */
  25 + protected $ver;
  26 +
  27 + /**
  28 + * @var string
  29 + */
  30 + protected $token;
  31 +
  32 + /**
  33 + * @return string
  34 + */
  35 + public function getMethod(): string
  36 + {
  37 + return 'POST';
  38 + }
  39 +
  40 + /**
  41 + * @return string
  42 + */
  43 + public function getPath(): string
  44 + {
  45 + return 'Gateway';
  46 + }
  47 +
  48 + /**
  49 + * @return string
  50 + */
  51 + public function getOption(): string
  52 + {
  53 + return RequestOptions::JSON;
  54 + }
  55 +
  56 +
  57 + /**
  58 + * @param array $config
  59 + *
  60 + * @return array
  61 + */
  62 + public function __invoke(array $config = []): array
  63 + {
  64 +
  65 + $this->paddingHead($config);
  66 +
  67 + $body = $this->extract();
  68 +
  69 + $this->signature($body);
  70 +
  71 + return $body;
  72 + }
  73 +
  74 + private function signature(&$body)
  75 + {
  76 + $body['sign'] = Signature::make($body);
  77 + }
  78 +
  79 + private function paddingHead(array $config)
  80 + {
  81 + $this->mchtId = Arr::get($config, 'merchant_id');
  82 + $this->token = Signature::encode(microtime(true) . uniqid(''));
  83 + $this->ver = Arr::get($config, 'version', 'V3.1');
  84 + }
  85 +
  86 + /**
  87 + * @return array
  88 + */
  89 + private function extract(): array
  90 + {
  91 + $propertiesArray = [];
  92 +
  93 + $ref = new \ReflectionClass($this);
  94 +
  95 + $properties = $ref->getProperties(ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_PROTECTED);
  96 +
  97 + foreach ($properties as $property) {
  98 + $property->setAccessible(true);
  99 +
  100 + $propertiesArray[$property->getName()] = $property->getValue($this);
  101 + }
  102 +
  103 + return $propertiesArray;
  104 + }
  105 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment;
  4 +
  5 +use Lackoxygen\MinPayment\Constant\Status;
  6 +use Lackoxygen\MinPayment\Contract\ResponseInterface;
  7 +use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
  8 +
  9 +class Response implements ResponseInterface
  10 +{
  11 + /**
  12 + * @var PsrResponseInterface $response
  13 + */
  14 + protected $response;
  15 +
  16 + /**
  17 + * @param PsrResponseInterface $response
  18 + */
  19 + public function __construct(PsrResponseInterface $response)
  20 + {
  21 + $this->response = $response;
  22 + }
  23 +
  24 + /**
  25 + * @return bool
  26 + */
  27 + public function isSuccess(): bool
  28 + {
  29 + return Status::SUCCESS === (string)\Arr::get($this->toArray(), 'code');
  30 + }
  31 +
  32 + /**
  33 + * @return array
  34 + */
  35 + public function toArray(): array
  36 + {
  37 + return (array)\json_decode($this->getContent(), true);
  38 + }
  39 +
  40 + /**
  41 + * @return string
  42 + */
  43 + public function toString(): string
  44 + {
  45 + return $this->getContent();
  46 + }
  47 +
  48 + /**
  49 + * @return string
  50 + */
  51 + public function getContent(): string
  52 + {
  53 + static $content = null;
  54 +
  55 + if (is_null($content)) {
  56 + $this->response->getBody()->rewind();
  57 +
  58 + $content = $this->response->getBody()->getContents();
  59 + }
  60 +
  61 + return $content;
  62 + }
  63 +}
  1 +<?php
  2 +
  3 +namespace Lackoxygen\MinPayment\Utils;
  4 +
  5 +use GuzzleHttp\Exception\ConnectException;
  6 +use GuzzleHttp\Exception\GuzzleException;
  7 +use Lackoxygen\MinPayment\Exception\Exception;
  8 +use Lackoxygen\MinPayment\Request\Request;
  9 +use Lackoxygen\MinPayment\Response;
  10 +
  11 +class Client
  12 +{
  13 + /**
  14 + * @var Request $request
  15 + */
  16 + protected $request;
  17 +
  18 + /**
  19 + * @var array $config
  20 + */
  21 + protected $config = [];
  22 +
  23 + /**
  24 + * @param array $config
  25 + */
  26 + public function __construct(array $config)
  27 + {
  28 + $this->config = $config;
  29 + }
  30 +
  31 + /**
  32 + * @param Request $request
  33 + *
  34 + * @return Response
  35 + * @throws Exception
  36 + */
  37 + public function __invoke(Request $request)
  38 + {
  39 + $this->request = $request;
  40 +
  41 + $body = $request($this->config);
  42 +
  43 + return $this->send($body);
  44 + }
  45 +
  46 + /**
  47 + * @param array $body
  48 + *
  49 + * @return Response
  50 + * @throws Exception
  51 + */
  52 + protected function send(array $body)
  53 + {
  54 + $client = new \GuzzleHttp\Client(\Arr::get($this->config, 'options.client'));
  55 + $retries = (int)\Arr::get($this->config, 'retry');
  56 +
  57 + $retry = 0;
  58 +
  59 + do {
  60 + try {
  61 + $response = $client->request($this->request->getMethod(), $this->request->getPath(), [
  62 + $this->request->getOption() => $body
  63 + ]);
  64 +
  65 + return new Response($response);
  66 + } catch (GuzzleException $e) {
  67 + throw new Exception($e);
  68 + }
  69 + } while ($retry++ < $retries);
  70 + }
  71 +}
  1 +<?php
  2 +
  3 +
  4 +namespace Lackoxygen\MinPayment\Utils;
  5 +
  6 +class Signature
  7 +{
  8 + /**
  9 + * @var array $item
  10 + */
  11 + protected $item = [];
  12 +
  13 + protected function __construct(array $item)
  14 + {
  15 + $this->item = $item;
  16 + }
  17 +
  18 + public static function make(array $items): string
  19 + {
  20 + $signature = new self($items);
  21 +
  22 + return $signature->toString();
  23 + }
  24 +
  25 + protected function sortByASCII()
  26 + {
  27 + $item = &$this->item;
  28 +
  29 + ksort($item);
  30 + }
  31 +
  32 + /**
  33 + * @param array $item
  34 + * @param callable $filter
  35 + *
  36 + * @return string
  37 + */
  38 + protected function map(array $item, callable $filter): string
  39 + {
  40 + $array = [];
  41 + foreach ($item as $key => $value) {
  42 + if ($filter($key, $value) !== false) {
  43 + $array[] = $key . '=' . $value;
  44 + }
  45 + }
  46 +
  47 + return join($array, '&');
  48 + }
  49 +
  50 + /**
  51 + * @param string $string
  52 + *
  53 + * @return string
  54 + */
  55 + public static function encode(string $string): string
  56 + {
  57 + return strtoupper(md5($string));
  58 + }
  59 +
  60 + /**
  61 + * @return string
  62 + */
  63 + protected function toString(): string
  64 + {
  65 + $this->sortByASCII();
  66 +
  67 + $string = $this->map($this->item, function ($k, $v) {
  68 + return !($v === '' || $v === null);
  69 + });
  70 +
  71 + return self::encode($string);
  72 + }
  73 +}