mirror of
				https://github.com/v2board/v2board.git
				synced 2025-10-31 17:31:49 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			165 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace Library;
 | |
| 
 | |
| use Illuminate\Support\Facades\Http;
 | |
| 
 | |
| class AlipayF2F {
 | |
|     private $appId;
 | |
|     private $privateKey;
 | |
|     private $alipayPublicKey;
 | |
|     private $signType = 'RSA2';
 | |
|     public $bizContent;
 | |
|     public $method;
 | |
|     public $notifyUrl;
 | |
|     public $response;
 | |
| 
 | |
|     public function __construct()
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     public function verify($data): bool
 | |
|     {
 | |
|         if (is_string($data)) {
 | |
|             parse_str($data, $data);
 | |
|         }
 | |
|         $sign = $data['sign'];
 | |
|         unset($data['sign']);
 | |
|         unset($data['sign_type']);
 | |
|         ksort($data);
 | |
|         $data = $this->buildQuery($data);
 | |
|         $res = "-----BEGIN PUBLIC KEY-----\n" .
 | |
|             wordwrap($this->alipayPublicKey, 64, "\n", true) .
 | |
|             "\n-----END PUBLIC KEY-----";
 | |
|         if ("RSA2" == $this->signType) {
 | |
|             $result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256) === 1);
 | |
|         } else {
 | |
|             $result = (openssl_verify($data, base64_decode($sign), $res) === 1);
 | |
|         }
 | |
|         openssl_free_key(openssl_get_publickey($res));
 | |
|         return $result;
 | |
|     }
 | |
| 
 | |
|     public function setBizContent($bizContent = [])
 | |
|     {
 | |
|         $this->bizContent = json_encode($bizContent);
 | |
|     }
 | |
| 
 | |
|     public function setMethod($method)
 | |
|     {
 | |
|         $this->method = $method;
 | |
|     }
 | |
| 
 | |
|     public function setAppId($appId)
 | |
|     {
 | |
|         $this->appId = $appId;
 | |
|     }
 | |
| 
 | |
|     public function setPrivateKey($privateKey)
 | |
|     {
 | |
|         $this->privateKey = $privateKey;
 | |
|     }
 | |
| 
 | |
|     public function setAlipayPublicKey($alipayPublicKey)
 | |
|     {
 | |
|         $this->alipayPublicKey = $alipayPublicKey;
 | |
|     }
 | |
| 
 | |
|     public function setNotifyUrl($url)
 | |
|     {
 | |
|         $this->notifyUrl = $url;
 | |
|     }
 | |
| 
 | |
|     public function send()
 | |
|     {
 | |
|         $response = Http::get('https://openapi.alipay.com/gateway.do', $this->buildParam())->json();
 | |
|         $resKey = str_replace('.', '_', $this->method) . '_response';
 | |
|         if (!isset($response[$resKey])) throw new \Exception('从支付宝请求失败');
 | |
|         $response = $response[$resKey];
 | |
|         if ($response['msg'] !== 'Success') throw new \Exception($response['sub_msg']);
 | |
|         $this->response = $response;
 | |
|     }
 | |
| 
 | |
|     public function getQrCodeUrl()
 | |
|     {
 | |
|         $response = $this->response;
 | |
|         if (!isset($response['qr_code'])) throw new \Exception('获取付款二维码失败');
 | |
|         return $response['qr_code'];
 | |
|     }
 | |
| 
 | |
|     public function getResponse()
 | |
|     {
 | |
|         return $this->response;
 | |
|     }
 | |
| 
 | |
|     public function buildParam(): array
 | |
|     {
 | |
|         $params = [
 | |
|             'app_id' => $this->appId,
 | |
|             'method' => $this->method,
 | |
|             'charset' => 'UTF-8',
 | |
|             'sign_type' => $this->signType,
 | |
|             'timestamp' => date('Y-m-d H:m:s'),
 | |
|             'biz_content' => $this->bizContent,
 | |
|             'version' => '1.0',
 | |
|             '_input_charset' => 'UTF-8'
 | |
|         ];
 | |
|         if ($this->notifyUrl) $params['notify_url'] = $this->notifyUrl;
 | |
|         ksort($params);
 | |
|         $params['sign'] = $this->buildSign($this->buildQuery($params));
 | |
|         return $params;
 | |
|     }
 | |
| 
 | |
|     public function buildQuery($query)
 | |
|     {
 | |
|         if (!$query) {
 | |
|             throw new \Exception('参数构造错误');
 | |
|         }
 | |
|         //将要 参数 排序
 | |
|         ksort($query);
 | |
| 
 | |
|         //重新组装参数
 | |
|         $params = array();
 | |
|         foreach ($query as $key => $value) {
 | |
|             $params[] = $key . '=' . $value;
 | |
|         }
 | |
|         $data = implode('&', $params);
 | |
|         return $data;
 | |
|     }
 | |
| 
 | |
|     private function buildSign(string $signData): string
 | |
|     {
 | |
|         $privateKey = $this->privateKey;
 | |
|         $p_key = array();
 | |
|         //如果私钥是 1行
 | |
|         if (!stripos($privateKey, "\n")) {
 | |
|             $i = 0;
 | |
|             while ($key_str = substr($privateKey, $i * 64, 64)) {
 | |
|                 $p_key[] = $key_str;
 | |
|                 $i++;
 | |
|             }
 | |
|         }
 | |
|         $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . implode("\n", $p_key);
 | |
|         $privateKey = $privateKey . "\n-----END RSA PRIVATE KEY-----";
 | |
| 
 | |
|         //私钥
 | |
|         $privateId = openssl_pkey_get_private($privateKey, '');
 | |
| 
 | |
|         // 签名
 | |
|         $signature = '';
 | |
| 
 | |
|         if ("RSA2" == $this->signType) {
 | |
| 
 | |
|             openssl_sign($signData, $signature, $privateId, OPENSSL_ALGO_SHA256);
 | |
|         } else {
 | |
| 
 | |
|             openssl_sign($signData, $signature, $privateId, OPENSSL_ALGO_SHA1);
 | |
|         }
 | |
| 
 | |
|         openssl_free_key($privateId);
 | |
| 
 | |
|         //加密后的内容通常含有特殊字符,需要编码转换下
 | |
|         $signature = base64_encode($signature);
 | |
|         return $signature;
 | |
|     }
 | |
| }
 |