WxNotifyCallBack.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. /**
  3. * WxNotifyCallBack.php UTF-8
  4. * 微信通知回调类
  5. *
  6. * @date : 2018/2/27 21:23
  7. *
  8. * @license 这不是一个自由软件,未经授权不许任何使用和传播。
  9. * @author : wuyonghong <wyh@huosdk.com>
  10. * @version : HUOSDK 8.0
  11. */
  12. namespace huolib\pay\driver;
  13. use think\Exception;
  14. use think\Log;
  15. require_once EXTEND_PATH."pay/wxpay/WxPay.Api.php";
  16. require_once EXTEND_PATH."pay/wxpay/WxPay.Notify.php";
  17. class WxNotifyCallBack extends \WxPayNotify {
  18. private $config
  19. = [
  20. 'app_id' => '', /* 绑定支付的APPID(必须配置,开户邮件中可查看)*/
  21. 'mch_id' => '', /* 商户号(必须配置,开户邮件中可查看) */
  22. 'key' => '', /* 商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置) */
  23. 'app_secret' => '', /* 公众帐号secert */
  24. 'curl_proxy_host' => '0.0.0.0',
  25. 'curl_proxy_port' => '0',
  26. 'report_levenl' => '1',
  27. 'device_info' => 'WEB', /* 终端设备号(门店号或收银设备ID),默认请传"WEB" */
  28. 'sslcert_path' => '',
  29. 'sslkey_path' => '',
  30. ];
  31. function __construct() {
  32. $_conf_file = GLOBAL_CONF_PATH.'extra/pay/wxpay/config.php';
  33. if (file_exists($_conf_file)) {
  34. $_config = include $_conf_file;
  35. } else {
  36. $_config = array();
  37. }
  38. $this->config = array_merge($this->config, $_config);
  39. $this->config['sslcert_path'] = GLOBAL_CONF_PATH.'extra/pay/wxpay/cert/apiclient_cert.pem';
  40. $this->config['sslkey_path'] = GLOBAL_CONF_PATH.'extra/pay/wxpay/cert/apiclient_key.pem';
  41. }
  42. /**
  43. * 设置配置
  44. *
  45. * @param array $config
  46. */
  47. public function setConf($config = []) {
  48. $this->config['app_id'] = $config['app_id'];
  49. $this->config['mch_id'] = $config['mch_id'];
  50. $this->config['key'] = $config['key'];
  51. $this->config['app_secret'] = $config['app_secret'];
  52. }
  53. /**
  54. * @param string $order_id 订单号
  55. * @param float $real_amount 浮点
  56. * @param string $ip 下单IP地址
  57. * @param string $product_id 商品ID
  58. * @param string $product_desc 商品描述
  59. * @param string $notify_url 通知地址
  60. * @param string $trade_type 交易类型
  61. *
  62. * @param string $open_id
  63. *
  64. * @return bool|string|array
  65. * @throws \WxPayException
  66. */
  67. public function unifiedOrder(
  68. $order_id, $real_amount, $ip, $product_id, $product_desc, $notify_url, $trade_type = 'APP', $open_id = ''
  69. ) {
  70. if (empty($notify_url)) {
  71. $notify_url = get_val($this->config, 'notify_url', '');
  72. }
  73. // if ('JSAPI' == $trade_type) {
  74. // $this->config['app_id'] = $this->config['js_app_id'];
  75. // unset($this->config['js_app_id']);
  76. // $this->config['app_secret'] = $this->config['js_app_secret'];
  77. // unset($this->config['js_app_secret']);
  78. // }
  79. if ('MPAPI' == $trade_type) {
  80. $trade_type = 'JSAPI';
  81. }
  82. //统一下单
  83. $_input = new \WxPayUnifiedOrder();
  84. $_input->SetAppid($this->config['app_id']);//公众账号ID
  85. $_input->SetMch_id($this->config['mch_id']);//商户号
  86. $_input->SetDevice_info($this->config['device_info']);//设备号
  87. $_input->SetBody($product_desc); /* 商品描述 */
  88. $_input->SetAttach($product_id); /* 商品描述 */
  89. $_input->SetOut_trade_no($order_id); /* 商户订单号 */
  90. $_input->SetTotal_fee((int)($real_amount * 100)); /* 总金额 */
  91. $_input->SetSpbill_create_ip($ip); /* 终端ip */
  92. $_input->SetTime_start(date("YmdHis")); /* 交易起始时间 */
  93. $_input->SetTime_expire(date("YmdHis", time() + 600)); /* 交易结束时间 */
  94. $_input->SetNotify_url($notify_url); /* 通知地址 */
  95. $_input->SetTrade_type($trade_type); /* 交易类型 */
  96. $_input->setKey($this->config['key']); /* 商户支付密钥 */
  97. if ('JSAPI' == $trade_type) {
  98. $_input->SetOpenid($open_id);//微信用户在商户对应appid下的唯一标识
  99. }
  100. $result = \WxPayApi::unifiedOrder($_input, 6, $this->config);
  101. // Log::error('$result'.json_encode($result));
  102. if ('FAIL' == $result['return_code']) {
  103. \think\Log::write($result, Log::ERROR);
  104. }
  105. if ('APP' == $trade_type) {
  106. /* APP--app支付 */
  107. return $this->setRData($result);
  108. } else if ('MWEB' == $trade_type) {
  109. /* MWEB H5支付 */
  110. return $result;
  111. } else if ('NATIVE' == $trade_type) {
  112. /* NATIVE 扫码支付 */
  113. return $result;
  114. } else if ('JSAPI' == $trade_type) {
  115. /* JSAPI 微信内支付 */
  116. return $this->setJsapiData($result);
  117. }
  118. return false;
  119. }
  120. /**
  121. * app支付参数设置
  122. *
  123. * @param $result
  124. *
  125. * @return string
  126. */
  127. public function setRData($result) {
  128. $_input = new \WxPayUnifiedOrder();
  129. $_token['appid'] = $result['appid'];
  130. $_token['partnerid'] = $result['mch_id'];
  131. $_token['prepayid'] = $result['prepay_id'];
  132. $_token['package'] = 'Sign=WXPay';
  133. $_token['noncestr'] = $result['nonce_str'];
  134. $_token['timestamp'] = time();
  135. $_input->setKey($this->config['key']);
  136. $_input->FromArray($_token);
  137. $_token['sign'] = $_input->SetSign();
  138. return json_encode($_token);
  139. }
  140. /**
  141. * JSAPI参数设置
  142. *
  143. * @param $result
  144. *
  145. * @return bool|string
  146. */
  147. public function setJsapiData($result) {
  148. if (!array_key_exists("appid", $result)
  149. || !array_key_exists("prepay_id", $result)
  150. || empty($result['prepay_id'])) {
  151. return false;
  152. }
  153. $_jsapi_class = new \WxPayJsApiPay();
  154. $_jsapi_class->SetAppid($result["appid"]);
  155. $_ts = time();
  156. $_jsapi_class->setKey($this->config['key']);
  157. $_jsapi_class->SetTimeStamp("$_ts");
  158. $_jsapi_class->SetNonceStr(\WxPayApi::getNonceStr());
  159. $_jsapi_class->SetPackage("prepay_id=".$result['prepay_id']);
  160. $_jsapi_class->SetSignType("MD5");
  161. $_jsapi_class->SetPaySign($_jsapi_class->MakeSign());
  162. $_parameters = json_encode($_jsapi_class->GetValues());
  163. return $_parameters;
  164. }
  165. /**
  166. * @param string $order_id 商户系统内部订单号
  167. * @param string $transaction_id 微信的订单号
  168. *
  169. * @return bool|array
  170. */
  171. public function orderQuery($order_id, $transaction_id = '', $trade_type = '') {
  172. //查询订单
  173. $_input = new \WxPayOrderQuery();
  174. $_input->SetOut_trade_no($order_id); /* 商户系统内部订单号 */
  175. // $_input->SetTransaction_id($transaction_id); /* 微信的订单号,建议优先使用 */
  176. if ('JSAPI' == $trade_type) {
  177. $this->config['app_id'] = $this->config['js_app_id'];
  178. unset($this->config['js_app_id']);
  179. $this->config['app_secret'] = $this->config['js_app_secret'];
  180. unset($this->config['js_app_secret']);
  181. } else {
  182. unset($this->config['js_app_id']);
  183. unset($this->config['js_app_secret']);
  184. }
  185. try {
  186. $_result = \WxPayApi::orderQuery($_input, 6, $this->config);
  187. if (isset($_result['trade_state'])) {
  188. return $_result['trade_state'];
  189. }
  190. } catch (\WxPayException $e) {
  191. return false;
  192. }
  193. return false;
  194. }
  195. /**
  196. * @param array $data
  197. * @param string $msg
  198. *
  199. * @return bool 回调出来完成不需要继续回调,false回调处理未完成需要继续回调
  200. */
  201. public function NotifyProcess($data, &$msg) {
  202. if (!array_key_exists("openid", $data)
  203. || !array_key_exists("mch_id", $data)) {
  204. $msg = "回调数据异常";
  205. return false;
  206. }
  207. /* 商品ID */
  208. $_product_id = $data['attach'];
  209. /* 商户订单号 */
  210. $_out_trade_no = $data['out_trade_no'];
  211. /* 微信支付订单号 */
  212. $_trade_no = $data['transaction_id'];
  213. /* 交易金额 */
  214. $_amount = number_format($data['total_fee'] / 100, 2, '.', '');
  215. try {
  216. $_class = $data['huo_order_class'];
  217. $_func = $data['huo_func'];
  218. if (class_exists($_class)) {
  219. $_order = new $_class();
  220. $_rs = $_order->$_func($_product_id, $_out_trade_no, $_trade_no, $_amount, 'wxpay');
  221. if (true == $_rs) {
  222. $msg = '支付通知成功';
  223. return true;
  224. }
  225. } else {
  226. Log::write(
  227. "func=".__FUNCTION__."&class=".__CLASS__."&order_class=".$_class
  228. ."&func=".$_func, LOG::ERROR
  229. );
  230. }
  231. $msg = '支付通知成功,内部处理失败';
  232. return true;
  233. } catch (Exception $_e) {
  234. Log::write(
  235. "func=".__FUNCTION__."&class=".__CLASS__."&order_class=".$_class
  236. ."&func=".$_func."&err=".$_e->getMessage()."&errCode=".$_e->getCode(), LOG::ERROR
  237. );
  238. $msg = '支付通知成功,内部处理失败';
  239. return false;
  240. }
  241. }
  242. public function selfHandle($needSign = true, $order_class, $func) {
  243. $this->config['huo_order_class'] = $order_class;
  244. $this->config['huo_func'] = $func;
  245. $this->Handle($needSign, $this->config);
  246. }
  247. }