admin/vendor/wechatpay/wechatpay-guzzle-middleware/src/WechatPayMiddleware.php

178 lines
4.8 KiB
PHP

<?php
/**
* WechatPayMiddleware
* PHP version 5
*
* @category Class
* @package WechatPay
* @author WeChat Pay Team
* @link https://pay.weixin.qq.com
*/
namespace WechatPay\GuzzleMiddleware;
use Psr\Http\Message\UriInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use WechatPay\GuzzleMiddleware\Credentials;
use WechatPay\GuzzleMiddleware\Validator;
use WechatPay\GuzzleMiddleware\WechatPayMiddlewareBuilder;
/**
* WechatPayMiddleware
*
* @category Class
* @package WechatPay
* @author WeChat Pay Team
* @link https://pay.weixin.qq.com
*/
class WechatPayMiddleware
{
/**
* WechatPayMiddleware version
*
* @var string
*/
const VERSION = "0.1.0";
/**
* WechatPay API domain
*
* @var string
*/
protected static $API_DOMAINS = [
'api.mch.weixin.qq.com',
'api2.mch.weixin.qq.com'
];
/**
* WechatPay API base urls
*
* @var array of string
*/
protected static $BASE_URLS = [
'/v3/',
'/sandbox/v3/'
];
/**
* Merchant credentials
*
* @var Credentials
*/
protected $credentials;
/**
* Response Validator
*
* @var Validator
*/
protected $validator;
/**
* Constructor
*/
public function __construct(Credentials $credentials, Validator $validator)
{
$this->credentials = $credentials;
$this->validator = $validator;
}
/**
* Use as Guzzle middleware
*
* @param callable $handler
*
* @return callable
*/
public function __invoke(callable $handler)
{
return function (RequestInterface $request, array $options) use ($handler) {
if (!self::isWechatPayApiUrl($request->getUri())) {
return $handler($request, $options);
}
$schema = $this->credentials->getSchema();
$token = $this->credentials->getToken($request);
$request = $request->withHeader("Authorization", $schema.' '.$token);
if (self::isUserAgentOverwritable($request)) {
$request = $request->withHeader('User-Agent', self::getUserAgent());
}
return $handler($request, $options)->then(
function (ResponseInterface $response) use ($request) {
$code = $response->getStatusCode();
if ($code >= 200 && $code < 300 && !$this->validator->validate($response)) {
if (\class_exists('\\GuzzleHttp\\Exception\\ServerException')) {
throw new \GuzzleHttp\Exception\ServerException(
"应答的微信支付签名验证失败", $request, $response);
} else {
throw new \RuntimeException("应答的微信支付签名验证失败", $code);
}
}
return $response;
}
);
};
}
/**
* Create a new builder
*
* @return WechatPayMiddlewareBuilder
*/
public static function builder()
{
return new WechatPayMiddlewareBuilder();
}
/**
* Check whether url is WechatPay API V3 url
*/
protected static function isWechatPayApiUrl(UriInterface $url)
{
if ($url->getScheme() !== 'https' || !\in_array($url->getHost(), self::$API_DOMAINS)) {
return false;
}
foreach (self::$BASE_URLS as $baseUrl) {
if (\substr($url->getPath(), 0, strlen($baseUrl)) === $baseUrl) {
return true;
}
}
return false;
}
/**
* Get User Agent
* @return string
*/
protected static function getUserAgent()
{
static $userAgent = '';
if (!$userAgent) {
$agent = 'WechatPay-Guzzle/'.self::VERSION;
if (\class_exists('\\GuzzleHttp\\Client')) {
$agent .= ' GuzzleHttp/'.\GuzzleHttp\Client::VERSION;
}
if (extension_loaded('curl') && function_exists('curl_version')) {
$agent .= ' curl/'.\curl_version()['version'];
}
$agent .= \sprintf(" (%s/%s) PHP/%s", PHP_OS, \php_uname('r'), PHP_VERSION);
$userAgent = $agent;
}
return $userAgent;
}
private static function isUserAgentOverwritable(RequestInterface $request)
{
if (!$request->hasHeader('User-Agent')) {
return true;
}
$headers = $request->getHeader('User-Agent');
$userAgent = $headers[\count($headers) - 1];
if (\function_exists('\\GuzzleHttp\\default_user_agent')) {
return $userAgent === \GuzzleHttp\default_user_agent();
}
return false;
}
}