SfPay.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <?php
  2. namespace App\Services;
  3. use App\Util;
  4. class SfPay
  5. {
  6. public $config;
  7. public $merchantKey;
  8. public $aesKey;
  9. public $aesIv;
  10. public $apiUrl;
  11. public function __construct()
  12. {
  13. $payConfigService = new PayConfig();
  14. $this->config = $payConfigService->getConfig('SfPay');
  15. $this->merchantKey = $this->config['merchant_key'] ?? '';
  16. $this->aesKey = $this->config['aes_key'] ?? '';
  17. $this->aesIv = $this->config['aes_iv'] ?? '';
  18. $this->apiUrl = $this->config['apiUrl'] ?? 'https://sfgateway.sforest.io';
  19. }
  20. /**
  21. * AES/CBC/PKCS5Padding 加密
  22. *
  23. * @param string $str 待加密JSON字符串
  24. * @return string base64编码的密文
  25. */
  26. public function encrypt($str)
  27. {
  28. return base64_encode(openssl_encrypt($str, 'AES-128-CBC', $this->aesKey, OPENSSL_RAW_DATA, $this->aesIv));
  29. }
  30. /**
  31. * AES/CBC/PKCS5Padding 解密
  32. *
  33. * @param string $encrypted base64编码的密文
  34. * @return string 解密后的JSON字符串
  35. */
  36. public function decrypt($encrypted)
  37. {
  38. return openssl_decrypt(base64_decode($encrypted), 'AES-128-CBC', $this->aesKey, OPENSSL_RAW_DATA, $this->aesIv);
  39. }
  40. /**
  41. * 验证回调签名
  42. *
  43. * signature_n = MD5(merchantKey + message + amount + status + merchantOrderNo + orderNo + aeskey)
  44. *
  45. * 注意:如果amount为空,则拼接"null"字符串(代付回调可能出现amount为空的情况)
  46. *
  47. * @param array $data 回调data参数
  48. * @param string $signatureN 签名值
  49. * @return bool
  50. */
  51. public function verifySign($data, $signatureN)
  52. {
  53. $message = $data['message'] ?? '';
  54. $amount = $data['amount'] ?? '';
  55. $status = $data['status'] ?? '';
  56. $merchantOrderNo = $data['merchantOrderNo'] ?? '';
  57. $orderNo = $data['orderNo'] ?? '';
  58. // 代付回调中amount为空时,拼接"null"字符串
  59. if ($amount === '' || $amount === null) {
  60. $amount = 'null';
  61. }
  62. $signStr = $this->merchantKey . $message . $amount . $status . $merchantOrderNo . $orderNo . $this->aesKey;
  63. $expectedSign = md5($signStr);
  64. Util::WriteLog('SfPay', "待签名字符串: {$signStr}");
  65. Util::WriteLog('SfPay', "期望签名: {$expectedSign}, 实际签名: {$signatureN}");
  66. return strtolower($expectedSign) === strtolower($signatureN);
  67. }
  68. /**
  69. * POST JSON请求(SfPay格式:data字段AES加密,merchant_key放在header)
  70. *
  71. * @param string $url 请求地址
  72. * @param array $params 待加密的请求参数
  73. * @return string|false
  74. */
  75. public function curlPost($url, $params)
  76. {
  77. $timeout = 30;
  78. $jsonStr = json_encode($params, JSON_UNESCAPED_UNICODE);
  79. // AES加密
  80. $encrypted = $this->encrypt($jsonStr);
  81. $body = json_encode(['data' => $encrypted], JSON_UNESCAPED_UNICODE);
  82. $headers = [
  83. 'Content-Type: application/json;charset=UTF-8',
  84. 'merchant_key: ' . $this->merchantKey,
  85. ];
  86. Util::WriteLog('SfPay', "SfPay请求URL: {$url}");
  87. Util::WriteLog('SfPay', "SfPay请求明文: {$jsonStr}");
  88. Util::WriteLog('SfPay', "SfPay请求密文: {$body}");
  89. $ch = curl_init();
  90. curl_setopt($ch, CURLOPT_URL, $url);
  91. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  92. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  93. curl_setopt($ch, CURLOPT_POST, 1);
  94. curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  95. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  96. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  97. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  98. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  99. $result = curl_exec($ch);
  100. if (curl_errno($ch)) {
  101. $error = curl_error($ch);
  102. Util::WriteLog('SfPay_error', 'CURL Error: ' . $error);
  103. curl_close($ch);
  104. return false;
  105. }
  106. curl_close($ch);
  107. Util::WriteLog('SfPay', "SfPay响应: {$result}");
  108. return $result;
  109. }
  110. }