BsPayRequestV2.php 6.4 KB

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