<?php
namespace Payment\Common\Ali; use GuzzleHttp\Client; use InvalidArgumentException; use Payment\Common\AliConfig; use Payment\Common\BaseData; use Payment\Common\BaseStrategy; use Payment\Common\PayException; use Payment\Config; use Payment\Utils\ArrayUtil; use Payment\Utils\Rsa2Encrypt; use Payment\Utils\RsaEncrypt; use Payment\Utils\StrUtil; abstract class AliBaseStrategy implements BaseStrategy { protected $method; protected $config; protected $reqData; public function __construct(array $config) { try { $this->config = new AliConfig($config); } catch (PayException $e) { throw $e; } } public function handle(array $data) { $buildClass = $this->getBuildDataClass(); try { $this->reqData = new $buildClass($this->config, $data); } catch (PayException $e) { throw $e; } $this->reqData->setSign(); $data = $this->reqData->getData(); return $this->retData($data); } protected function retData(array $data) { $sign = $data['sign']; $data = ArrayUtil::removeKeys($data, ['sign']); $data = ArrayUtil::arraySort($data); foreach ($data as &$value) { $value = StrUtil::characet($value, $this->config->charset); } $data['sign'] = $sign; return $data; } protected function sendReq(array $data, $method = 'GET') { $client = new Client([ 'base_uri' => $this->config->getewayUrl, 'timeout' => '10.0' ]); $method = strtoupper($method); $options = []; if ($method === 'GET') { $options = [ 'query' => $data, 'http_errors' => false ]; } elseif ($method === 'POST') { $options = [ 'form_params' => $data, 'http_errors' => false ]; } $response = $client->request($method, '', $options); if ($response->getStatusCode() != '200') { throw new PayException('网络发生错误，请稍后再试curl返回码：' . $response->getReasonPhrase()); } $body = $response->getBody()->getContents(); try { $body = \GuzzleHttp\json_decode($body, true); } catch (InvalidArgumentException $e) { throw new PayException('返回数据 json 解析失败'); } $responseKey = str_ireplace('.', '_', $this->config->method) . '_response'; if (! isset($body[$responseKey])) { throw new PayException('支付宝系统故障或非法请求'); } $flag = $this->verifySign($body[$responseKey], $body['sign']); if (! $flag) { throw new PayException('支付宝返回数据被篡改。请检查网络是否安全！'); } return $body[$responseKey]; } protected function verifySign(array $data, $sign) { $preStr = \GuzzleHttp\json_encode($data, JSON_UNESCAPED_UNICODE); if ($this->config->signType === 'RSA') { $rsa = new RsaEncrypt($this->config->rsaAliPubKey); return $rsa->rsaVerify($preStr, $sign); } elseif ($this->config->signType === 'RSA2') { $rsa = new Rsa2Encrypt($this->config->rsaAliPubKey); return $rsa->rsaVerify($preStr, $sign); } else { return false; } } protected function getTradeStatus($status) { switch ($status) { case 'TRADE_SUCCESS': case 'TRADE_FINISHED': return Config::TRADE_STATUS_SUCC; case 'WAIT_BUYER_PAY': case 'TRADE_CLOSED': default: return Config::TRADE_STATUS_FAILD; } } } 