MihuaPayService.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: lts
  5. * Date: 2019-02-23
  6. * Time: 14:39
  7. */
  8. namespace app\main\service;
  9. use app\main\constants\ApiConstants;
  10. use GuzzleHttp\Client as Http;
  11. use GuzzleHttp\Exception\GuzzleException;
  12. use think\Exception;
  13. class MihuaPayService
  14. {
  15. private $privateKey;
  16. private $publicKey;
  17. private $isPrivate;
  18. private $keyFormat;
  19. private $keyProvider;
  20. function __construct($privateKey, $publicKey)
  21. {
  22. $this->privateKey = $privateKey;
  23. $this->publicKey = $publicKey;
  24. $this->keyFormat = 1;
  25. }
  26. protected static $self = null;
  27. public static function instance($privateKey, $publicKey)
  28. {
  29. if (self::$self == null) {
  30. self::$self = new self($privateKey, $publicKey);
  31. }
  32. return self::$self;
  33. }
  34. /**
  35. * 获取签名
  36. * @param $params 参数
  37. * @return string
  38. */
  39. public function getSign($params)
  40. {
  41. ksort($params);
  42. $data = "";
  43. foreach ($params as $key => $value) {
  44. $data .= $value;
  45. }
  46. $sign = strtoupper(md5($data . $this->privateKey));
  47. return $sign;
  48. }
  49. /**
  50. * 验证签名
  51. * @param $params 参数
  52. * @return bool
  53. */
  54. public function checkSign($params)
  55. {
  56. ksort($params);
  57. $psign = "";
  58. $data = "";
  59. foreach ($params as $key => $value) {
  60. if ($key == "sign") {
  61. $psign = $value;
  62. } else {
  63. $data .= $value;
  64. }
  65. }
  66. $sign = strtoupper(md5($data . $this->publicKey));
  67. if ($psign == $sign) {
  68. return true;
  69. } else {
  70. return false;
  71. }
  72. }
  73. public function encrypt($data)
  74. {
  75. ksort($data);
  76. $data = json_encode($data);
  77. $this->_makesure_provider($this->privateKey);
  78. $encrypted = '';
  79. if ($this->isPrivate) {
  80. foreach (str_split($data, 117) as $chunk) {
  81. $r = openssl_private_encrypt($chunk, $encryptData, $this->keyProvider, OPENSSL_PKCS1_PADDING);
  82. $encrypted .= $encryptData;
  83. }
  84. } else {
  85. foreach (str_split($data, 117) as $chunk) {
  86. $r = openssl_public_encrypt($chunk, $encryptData, $this->keyProvider, OPENSSL_PKCS1_PADDING);
  87. $encrypted .= $encryptData;
  88. }
  89. }
  90. return $r ? $data = base64_encode($encrypted) : null;
  91. }
  92. public function decrypt($data)
  93. {
  94. $this->_makesure_provider($this->publicKey);
  95. $data = base64_decode($data);
  96. $crypto = '';
  97. foreach (str_split($data, 128) as $chunk) {
  98. if ($this->isPrivate) {
  99. $r = openssl_private_decrypt($chunk, $decrypted, $this->keyProvider, OPENSSL_PKCS1_PADDING);
  100. } else {
  101. $r = openssl_public_decrypt($chunk, $decrypted, $this->keyProvider, OPENSSL_PKCS1_PADDING);
  102. }
  103. $crypto .= $decrypted;
  104. }
  105. return $crypto;
  106. }
  107. private function _makesure_provider($key)
  108. {
  109. $this->isPrivate = strlen($key) > 500;
  110. $key = chunk_split($key, 64, "\r\n");//转换为pem格式的公钥
  111. if ($this->isPrivate) {
  112. $key = "-----BEGIN PRIVATE KEY-----\r\n" . $key . "-----END PRIVATE KEY-----";
  113. } else {
  114. $key = "-----BEGIN PUBLIC KEY-----\r\n" . $key . "-----END PUBLIC KEY-----";
  115. }
  116. $this->keyProvider = $this->isPrivate ? openssl_pkey_get_private($key) : openssl_pkey_get_public($key);
  117. }
  118. /**
  119. * 米花调用API接口
  120. * @param $postData 发送到API的数据
  121. * @param $data 加密前的明文参数
  122. * @param $payInfo 支付信息
  123. * @param $goodsInfo 商品信息
  124. * @param $orderInfo 订单信息
  125. * @param int $loopIndex 循环调用API的次数
  126. * @return mixed|\Psr\Http\Message\ResponseInterface
  127. * @throws Exception
  128. */
  129. public function payMihuaApi($postData, $data, $payInfo, $goodsInfo, $orderInfo, $loopIndex = 1)
  130. {
  131. $payUrl = ApiConstants::MIHUA_PAY_URL;
  132. $mihuaApiStartTime = microtime(true);
  133. try {
  134. $client = new Http([
  135. 'connect_timeout' => 10,
  136. 'timeout' => 30,
  137. 'http_errors' => true, //抛出异常 true是 false否
  138. 'verify' => false, //不验证ssl证书
  139. ]);
  140. $result = $client->post($payUrl, ['form_params' => $postData]);
  141. $mihuaApiEndTime = microtime(true);
  142. $apiRunTime = round($mihuaApiEndTime - $mihuaApiStartTime, 3);
  143. if ($result->getStatusCode() != '200') {
  144. LogService::error(sprintf('mihuapay_create_order_fail!wxpay_id:%s,wxpay_name:%s,mch_id:%s,channel_id:%s,user_id:%s,money:%s,good_id:%s,out_trade_no:%s,api_run_time:%s s,loop_index:%s,errmessage:%s'
  145. , $payInfo['id'], $payInfo['name'], $payInfo['quartet_merchant_id'], $orderInfo['admin_id'],
  146. $orderInfo['user_id'], $goodsInfo['money'], $orderInfo['goods_id'], $orderInfo['out_trade_no'],
  147. $apiRunTime, $loopIndex, json_encode(var_export($result, true), JSON_UNESCAPED_UNICODE)));
  148. LogService::error(sprintf('米花平台订单创建失败!订单内容明文: %s 订单内容密文: %s 米花平台返回内容: %s',
  149. json_encode(var_export($data, true), JSON_UNESCAPED_UNICODE),
  150. json_encode(var_export($postData, true), JSON_UNESCAPED_UNICODE),
  151. json_encode(var_export($result, true), JSON_UNESCAPED_UNICODE)
  152. ));
  153. throw new Exception('订单创建失败,请重新下单!');
  154. } else {
  155. $result = json_decode($result->getBody()->getContents(), true);
  156. if ($result['code'] != '000000') {
  157. LogService::error(sprintf('mihuapay_create_order_fail!wxpay_id:%s,wxpay_name:%s,mch_id:%s,channel_id:%s,user_id:%s,money:%s,good_id:%s,out_trade_no:%s,api_run_time:%s s,loop_index:%s,errmessage:%s'
  158. , $payInfo['id'], $payInfo['name'], $payInfo['quartet_merchant_id'], $orderInfo['admin_id'],
  159. $orderInfo['user_id'], $goodsInfo['money'], $orderInfo['goods_id'], $orderInfo['out_trade_no'],
  160. $apiRunTime, $loopIndex, json_encode(var_export($result, true), JSON_UNESCAPED_UNICODE)));
  161. LogService::error(sprintf('米花平台订单创建失败!订单内容明文: %s 订单内容密文: %s 米花平台返回内容: %s',
  162. json_encode(var_export($data, true), JSON_UNESCAPED_UNICODE),
  163. json_encode(var_export($postData, true), JSON_UNESCAPED_UNICODE),
  164. json_encode(var_export($result, true), JSON_UNESCAPED_UNICODE)
  165. ));
  166. throw new Exception('订单创建失败,请重新下单!');
  167. }
  168. }
  169. LogService::info(sprintf('mihuapay_create_order_success!wxpay_id:%s,wxpay_name:%s,mch_id:%s,channel_id:%s,user_id:%s,money:%s,good_id:%s,out_trade_no:%s,api_run_time:%s s,loop_index:%s'
  170. , $payInfo['id'], $payInfo['name'], $payInfo['quartet_merchant_id'], $orderInfo['admin_id'],
  171. $orderInfo['user_id'], $goodsInfo['money'], $orderInfo['goods_id'], $orderInfo['out_trade_no'],
  172. $apiRunTime, $loopIndex));
  173. return $result;
  174. } catch (GuzzleException $exception) {
  175. $mihuaApiEndTime = microtime(true);
  176. $apiRunTime = round($mihuaApiEndTime - $mihuaApiStartTime, 3);
  177. LogService::error(sprintf('mihuapay_create_order_fail!wxpay_id:%s,wxpay_name:%s,mch_id:%s,channel_id:%s,user_id:%s,money:%s,good_id:%s,out_trade_no:%s,api_run_time:%s s,loop_index:%s,errmessage:%s'
  178. , $payInfo['id'], $payInfo['name'], $payInfo['quartet_merchant_id'], $orderInfo['admin_id'],
  179. $orderInfo['user_id'], $goodsInfo['money'], $orderInfo['goods_id'], $orderInfo['out_trade_no'],
  180. $apiRunTime,
  181. $loopIndex, $exception->getMessage()));
  182. LogService::error(sprintf('米花平台订单创建失败!订单内容明文: %s 订单内容密文:%s',
  183. json_encode(var_export($data, true), JSON_UNESCAPED_UNICODE),
  184. json_encode(var_export($postData, true), JSON_UNESCAPED_UNICODE)));
  185. LogService::error($exception->getMessage());
  186. LogService::error($exception->getTraceAsString());
  187. if ($loopIndex <= ApiConstants::LOOP_EXEC_API_COUNT) {
  188. $loopIndex++;
  189. return $this->payMihuaApi($postData, $data, $payInfo, $goodsInfo, $orderInfo, $loopIndex);
  190. }
  191. throw new Exception('订单创建失败,请重新下单!');
  192. }
  193. }
  194. }