BsPayRequestV2.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. namespace BsPaySdk\core;
  3. use BsPaySdk\config\MerConfig;
  4. class BsPayRequestV2 {
  5. # 请求头
  6. private $httpHeaders;
  7. # 网络应答码
  8. private $httpStateCode;
  9. # 请求数据
  10. private $reqDatas;
  11. # 应答数据
  12. private $rspDatas;
  13. private $url;
  14. # 请求报错
  15. private $error = null;
  16. public function curlRequest(MerConfig $merConfig, $url, $postFields = null, $file = null, $headers=null, $is_json=false) {
  17. $this->url = $url;
  18. // $postFields['needSign'] 是否需要添加签名, $postFields['needVerfySign'] 是否需要验证签名
  19. $needSign = isset($postFields['needSign']) ? $postFields['needSign'] : true;
  20. $needVerfySign = isset($postFields['needVerfySign']) ? $postFields['needVerfySign'] : true;
  21. unset($postFields['needSign'],$postFields['needVerfySign']);
  22. BsPay::writeLog("curl方法参数:". json_encode(func_get_args(), JSON_UNESCAPED_UNICODE));
  23. $ch = curl_init();
  24. curl_setopt($ch, CURLOPT_URL, $url);
  25. curl_setopt($ch, CURLOPT_FAILONERROR, false);
  26. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  27. curl_setopt($ch, CURLOPT_HEADER, false);
  28. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  29. if (is_array($postFields) && 0 < count($postFields)) {
  30. curl_setopt($ch, CURLOPT_POST, true);
  31. $body = $this->createBody($merConfig, $postFields, $file);
  32. if (!$needSign) {
  33. unset($body['sign']);
  34. }
  35. if ($is_json) {
  36. $json_data = json_encode($body);
  37. BsPay::writeLog("post-json请求参数:" . json_encode($body, JSON_UNESCAPED_UNICODE));
  38. array_push($headers, "Content-Length:" . strlen($json_data));
  39. curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
  40. } else {
  41. BsPay::writeLog("post-form请求参数:" . json_encode($body, JSON_UNESCAPED_UNICODE));
  42. curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  43. }
  44. $this->reqDatas = $body;
  45. }
  46. # 拼装请求头
  47. $this->httpHeaders = $this->createHeaders($headers);
  48. BsPay::writeLog("curl请求头:". json_encode($this->httpHeaders, JSON_UNESCAPED_UNICODE));
  49. curl_setopt($ch, CURLOPT_HTTPHEADER, $this->httpHeaders);
  50. # 执行网络请求
  51. $resultString = curl_exec($ch);
  52. # 处理系统的报错
  53. if (curl_errno($ch)) {
  54. $this->error = curl_error($ch);
  55. BsPay::writeLog($this->error, "ERROR");
  56. # 这里报错直接就关闭本次会话return了
  57. curl_close($ch);
  58. return $this;
  59. }
  60. # http应答码
  61. $this->httpStateCode = curl_getinfo($ch,CURLINFO_HTTP_CODE);
  62. # 关闭本次会话
  63. curl_close($ch);
  64. $this->rspDatas = json_decode($resultString, true);
  65. BsPay::writeLog("curl返回参数:". $this->httpStateCode. " ". $resultString);
  66. $resp_sign = isset($this->rspDatas['sign']) ? $this->rspDatas['sign'] : '';
  67. # 不需要对应答数据验签的逻辑分支,斗拱存在一些不用验签的接口,例如:页面版的快捷支付、手机网页支等
  68. if (!$resp_sign || $this->httpStateCode == 401) {
  69. if ($needVerfySign) {
  70. $this->error = array(
  71. 'code' => 'RESP_SIGN_VERIFY_UNDO',
  72. 'msg' => '无法对应答数据进行验签',
  73. );
  74. }
  75. if (!$this->rspDatas) {
  76. # 无法解析出json格式的情况,就直接就把应答数据返回出去,针对返回数据为html页面的接口,例如:页面版的快捷支付等
  77. $this->rspDatas = $resultString;
  78. }
  79. return $this;
  80. }
  81. $resp_data = isset($this->rspDatas['data']) ? $this->rspDatas['data'] : '';
  82. // TODO response 应答错误 hardcode 待优化 --- Charles.huang 2021/09/09
  83. # 对返回数据验签失败的逻辑分支
  84. if (!BsPayTools::verifySign_sort($resp_sign, $resp_data, $merConfig->rsa_huifu_public_key)) {
  85. $this->error = array(
  86. 'code' => 'RESP_SIGN_VERIFY_FAILED',
  87. 'msg' => '接口结果返回签名验证失败',
  88. );
  89. return $this;
  90. }
  91. # 应答码异常情况
  92. if ($this->httpStateCode < 200 || $this->httpStateCode >= 400) {
  93. $this->error = array(
  94. 'code' => 'HTTP_REQUEST_FAILED',
  95. 'msg' => "请求失败: HTTP_STATE_CODE-".$this->httpStateCode,
  96. );
  97. return $this;
  98. }
  99. return $this;
  100. }
  101. private function createHeaders($header_data = array()){
  102. $headers = $header_data;
  103. if (empty($header_data)){
  104. $headers = array('Content-type: application/x-www-form-urlencoded');
  105. }
  106. array_push($headers, 'sdk_version:' . SDK_VERSION);
  107. array_push($headers, 'charset:UTF-8');
  108. return $headers;
  109. }
  110. private function createBody(MerConfig $merChantConfig, $post_data, $file = null){
  111. $body = array();
  112. $body['sys_id'] = $merChantConfig->sys_id;
  113. $body['product_id'] = $merChantConfig->product_id;
  114. ksort($post_data); // 根据key排序
  115. $body['data'] = $post_data;
  116. # 执行签名
  117. $sign = BsPayTools::sha_with_rsa_sign(
  118. json_encode($post_data, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE), // 数据里有中文和斜杠都不转码
  119. $merChantConfig->rsa_merch_private_key);
  120. $body['sign'] = $sign;
  121. if(!empty($file)){
  122. $body['file'] = $file;
  123. $body['data'] = json_encode($post_data, JSON_UNESCAPED_UNICODE);
  124. }
  125. return $body;
  126. }
  127. /**
  128. * 本次请求的http头信息
  129. */
  130. public function getHttpHeaders()
  131. {
  132. return $this->httpHeaders;
  133. }
  134. /**
  135. * 本次请求应答的 http状态码
  136. */
  137. public function getHttpStateCode()
  138. {
  139. return $this->httpStateCode;
  140. }
  141. /**
  142. * 本次请求的数据
  143. */
  144. public function getReqDatas()
  145. {
  146. return $this->reqDatas;
  147. }
  148. /**
  149. * 本次请求的应答数据
  150. */
  151. public function getRspDatas()
  152. {
  153. return $this->rspDatas;
  154. }
  155. /**
  156. * 获取请求执行失败信息
  157. */
  158. public function getErrorInfo()
  159. {
  160. return $this->error;
  161. }
  162. /**
  163. * 请求是否成功执行
  164. */
  165. public function isError()
  166. {
  167. return $this->error != null;
  168. }
  169. /**
  170. * 获取请求url
  171. */
  172. public function getUrl()
  173. {
  174. return $this->url;
  175. }
  176. }