PaySign.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <?php
  2. namespace common\helpers\UPOP;
  3. use common\helpers\LoggerTool;
  4. class PaySign {
  5. private $frontPayUrl;
  6. private $backPayUrl;
  7. private $agencyId;
  8. private $terminalId;
  9. private $childMerchantId;
  10. private $notifyUrl;
  11. private $returnUrl;
  12. public function __construct()
  13. {
  14. $this->frontPayUrl = \Yii::$app->params['UPOP']['frontPayUrl'];
  15. $this->backPayUrl = \Yii::$app->params['UPOP']['backPayUrl'];
  16. $this->agencyId = \Yii::$app->params['UPOP']['agencyId'];
  17. $this->terminalId = \Yii::$app->params['UPOP']['terminalId'];
  18. $this->childMerchantId = \Yii::$app->params['UPOP']['childMerchantId'];
  19. $this->notifyUrl = \Yii::$app->params['UPOP']['notifyUrl'];
  20. $this->returnUrl = \Yii::$app->params['UPOP']['returnUrl'];
  21. }
  22. public function sendEncodeData($payload, $url)
  23. {
  24. $json_content = json_encode($payload);
  25. // 随机生成aes密钥
  26. $aes_key = $this->randomKeys();
  27. // 商户RSA私钥
  28. $private_rsa_key = file_get_contents($this->getPath() . $this->agencyId . '/' . $this->agencyId. '.pem');
  29. // 平台RSA公钥
  30. $public_rsa_key = file_get_contents($this->getPath() . $this->agencyId . '/' . 'GHT_ROOT.pem');
  31. // 用随机生成的aes密钥加密请求报文
  32. $data['encryptData'] = $this->aesEncode($json_content, $aes_key);
  33. // 用我司平台rsa公钥加密上面随机生成的aes密钥
  34. $data['encryptKey'] = $this->rsaEncode($aes_key, $public_rsa_key);
  35. // 用商户ras私钥签名
  36. $data['signData'] = $this->rsaSign($json_content, $private_rsa_key);
  37. // 商户号
  38. $data['agencyId'] = $this->agencyId;
  39. $data_content = json_encode($data);
  40. LoggerTool::info($data_content);
  41. // 发送请求
  42. $request_result = $this->httpPost($data_content, $url);
  43. // 解密返回报文
  44. $result_json = json_decode($request_result,true);
  45. LoggerTool::info($result_json);
  46. // 用商户私钥解密aes密钥(是由平台随机生成的)
  47. $result_aes_key = $this->rsaDecode($result_json['encryptKey'], $private_rsa_key);
  48. // 用aes密钥解密报文
  49. $decode_content = $this->aesDecode($result_json['encryptData'], $result_aes_key);
  50. // 用平台公钥验签
  51. if ($this->verifySign($decode_content, $result_json['signData'], $public_rsa_key)) {
  52. return json_decode($decode_content, true);
  53. } else {
  54. // 验签失败
  55. return false;
  56. }
  57. }
  58. private function aesEncode($data, $aes_key): string
  59. {
  60. $encrypt_data = openssl_encrypt($this->pad($data), "aes-128-ecb", $aes_key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
  61. return base64_encode($encrypt_data);
  62. }
  63. public function aesDecode($data,$aes_key)
  64. {
  65. $data = base64_decode($data);
  66. return openssl_decrypt($data, "aes-128-ecb", $aes_key, OPENSSL_RAW_DATA);
  67. }
  68. private function rsaEncode($data, $public_rsa_key)
  69. {
  70. $ret = false;
  71. // if (!self::_checkPadding(OPENSSL_PKCS1_PADDING, 'en')){
  72. // return 'padding error';
  73. // }
  74. $key = openssl_get_publickey($public_rsa_key);
  75. if (openssl_public_encrypt($data,$result,$key,OPENSSL_PKCS1_PADDING)) {
  76. $ret = base64_encode($result);
  77. }
  78. return $ret;
  79. }
  80. private function rsaDecode($data, $private_rsa_key)
  81. {
  82. $ret = false;
  83. $data = base64_decode($data);
  84. if ($data !== false){
  85. if (openssl_private_decrypt($data, $result, $private_rsa_key, OPENSSL_PKCS1_PADDING)){
  86. $ret = $result;
  87. }
  88. }
  89. return $ret;
  90. }
  91. private function rsaSign($data, $private_rsa_key)
  92. {
  93. $res = openssl_get_privatekey($private_rsa_key);
  94. openssl_sign($data,$sign, $res);
  95. openssl_free_key($res);
  96. return base64_encode($sign);
  97. }
  98. private function verifySign($data, $signData, $public_rsa_key): bool
  99. {
  100. $signData =base64_decode($signData);
  101. $res = openssl_get_publickey($public_rsa_key);
  102. $result = openssl_verify($data, $signData, $res);
  103. openssl_free_key($res);
  104. if ($result === 1) {
  105. return true;
  106. } else {
  107. return false;
  108. }
  109. }
  110. private function httpPost($data, $url): string
  111. {
  112. try {
  113. $ch = curl_init();
  114. curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));
  115. curl_setopt($ch,CURLOPT_TIMEOUT,600);
  116. curl_setopt($ch,CURLOPT_URL, $url);
  117. curl_setopt($ch,CURLOPT_POST,true);
  118. curl_setopt($ch,CURLOPT_POSTFIELDS, $data);
  119. curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
  120. if (strpos($url, 'https') !== false) {
  121. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  122. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  123. curl_setopt($ch, CURLOPT_SSLVERSION, 1);
  124. }
  125. $ret_data = trim(curl_exec($ch));
  126. curl_close($ch);
  127. return $ret_data;
  128. } catch (\Exception $e) {
  129. LoggerTool::info($e->getMessage());
  130. return '';
  131. }
  132. }
  133. /*
  134. * 获取授权文件位置.
  135. */
  136. private function getPath()
  137. {
  138. return \Yii::getAlias('@common/runtime/upop/');
  139. // return dirname(__FILE__) . '/';
  140. }
  141. private function randomKeys(): string
  142. {
  143. $key = '';
  144. $pattern = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ';
  145. for ($i = 0; $i < 16; $i++) {
  146. $key .= $pattern[mt_rand(0, 35)];
  147. }
  148. return $key;
  149. }
  150. private function pad($data, $blocksize = 16): string
  151. {
  152. $pad = 16 - (strlen($data) % 16);
  153. return $data . str_repeat(chr($pad), $pad);
  154. }
  155. }