PaySign.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. // 发送请求
  41. $request_result = $this->httpPost($data_content, $url);
  42. // 解密返回报文
  43. $result_json = json_decode($request_result,true);
  44. // 用商户私钥解密aes密钥(是由平台随机生成的)
  45. $result_aes_key = $this->rsaDecode($result_json['encryptKey'], $private_rsa_key);
  46. // 用aes密钥解密报文
  47. $decode_content = $this->aesDecode($result_json['encryptData'], $result_aes_key);
  48. // 用平台公钥验签
  49. if ($this->verifySign($decode_content, $result_json['signData'], $public_rsa_key)) {
  50. return json_decode($decode_content, true);
  51. } else {
  52. // 验签失败
  53. return false;
  54. }
  55. }
  56. private function aesEncode($data, $aes_key): string
  57. {
  58. $encrypt_data = openssl_encrypt($this->pad($data), "aes-128-ecb", $aes_key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
  59. return base64_encode($encrypt_data);
  60. }
  61. public function aesDecode($data,$aes_key)
  62. {
  63. $data = base64_decode($data);
  64. return openssl_decrypt($data, "aes-128-ecb", $aes_key, OPENSSL_RAW_DATA);
  65. }
  66. private function rsaEncode($data, $public_rsa_key)
  67. {
  68. $ret = false;
  69. // if (!self::_checkPadding(OPENSSL_PKCS1_PADDING, 'en')){
  70. // return 'padding error';
  71. // }
  72. $key = openssl_get_publickey($public_rsa_key);
  73. if (openssl_public_encrypt($data,$result,$key,OPENSSL_PKCS1_PADDING)) {
  74. $ret = base64_encode($result);
  75. }
  76. return $ret;
  77. }
  78. private function rsaDecode($data, $private_rsa_key)
  79. {
  80. $ret = false;
  81. $data = base64_decode($data);
  82. if ($data !== false){
  83. if (openssl_private_decrypt($data, $result, $private_rsa_key, OPENSSL_PKCS1_PADDING)){
  84. $ret = $result;
  85. }
  86. }
  87. return $ret;
  88. }
  89. private function rsaSign($data, $private_rsa_key)
  90. {
  91. $res = openssl_get_privatekey($private_rsa_key);
  92. openssl_sign($data,$sign, $res);
  93. openssl_free_key($res);
  94. return base64_encode($sign);
  95. }
  96. private function verifySign($data, $signData, $public_rsa_key): bool
  97. {
  98. $signData =base64_decode($signData);
  99. $res = openssl_get_publickey($public_rsa_key);
  100. $result = openssl_verify($data, $signData, $res);
  101. openssl_free_key($res);
  102. if ($result === 1) {
  103. return true;
  104. } else {
  105. return false;
  106. }
  107. }
  108. private function httpPost($data, $url): string
  109. {
  110. try {
  111. $ch = curl_init();
  112. curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));
  113. curl_setopt($ch,CURLOPT_TIMEOUT,600);
  114. curl_setopt($ch,CURLOPT_URL, $url);
  115. curl_setopt($ch,CURLOPT_POST,true);
  116. curl_setopt($ch,CURLOPT_POSTFIELDS, $data);
  117. curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
  118. if (strpos($url, 'https') !== false) {
  119. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  120. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  121. curl_setopt($ch, CURLOPT_SSLVERSION, 1);
  122. }
  123. $ret_data = trim(curl_exec($ch));
  124. curl_close($ch);
  125. return $ret_data;
  126. } catch (\Exception $e) {
  127. LoggerTool::info($e->getMessage());
  128. return '';
  129. }
  130. }
  131. /*
  132. * 获取授权文件位置.
  133. */
  134. private function getPath()
  135. {
  136. return \Yii::getAlias('@common/runtime/upop/');
  137. // return dirname(__FILE__) . '/';
  138. }
  139. private function randomKeys(): string
  140. {
  141. $key = '';
  142. $pattern = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ';
  143. for ($i = 0; $i < 16; $i++) {
  144. $key .= $pattern[mt_rand(0, 35)];
  145. }
  146. return $key;
  147. }
  148. private function pad($data, $blocksize = 16): string
  149. {
  150. $pad = 16 - (strlen($data) % 16);
  151. return $data . str_repeat(chr($pad), $pad);
  152. }
  153. }