WxpayService.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace service;
  12. use basic\AuthBasic;
  13. /**
  14. * 微信扫码支付
  15. * Class WxpayService
  16. * @package service
  17. *
  18. * 调用实例
  19. *
  20. * $data['total_amount'] = $payAmount;//价格
  21. $data['order_id'] = time().$themeEnlist['enlist_card'].mt_rand(10,99);//订单 不能超过32为
  22. ThemeEnlistModel::edit($data,$idB);
  23. $mchid = SystemConfig::getValue('pay_weixin_mchid'); //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
  24. $appid = SystemConfig::getValue('pay_weixin_appid'); //公众号APPID 通过微信支付商户资料审核后邮件发送
  25. $apiKey = SystemConfig::getValue('pay_weixin_key'); //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
  26. $wxPay = new WxpayService($mchid,$appid,$apiKey);//实例化微信扫码类
  27. $outTradeNo = $data['order_id']; //你自己的商品订单号
  28. $notifyUrl = SystemConfig::getValue('site_url').Url::build('index/Themeenlist/wapay_success_notify'); //付款成功后的回调地址(不要有问号)
  29. $payTime = time(); //付款时间
  30. $arr = $wxPay->createJsBizPackage($payAmount,$outTradeNo,$orderName,$notifyUrl,$payTime);//创建成功会微信返回的数据
  31. $url = 'http://pan.baidu.com/share/qrcode?w=104&h=100&url='.$arr['code_url'];//生成二维码 http://pan.baidu.com/share/qrcode 百度在线生成二维码链家
  32. */
  33. class WxpayService extends AuthBasic
  34. {
  35. protected $mchid;
  36. protected $appid;
  37. protected $apiKey;
  38. public function __construct($mchid, $appid, $key)
  39. {
  40. $this->mchid = $mchid;
  41. $this->appid = $appid;
  42. $this->apiKey = $key;
  43. }
  44. /**
  45. * 发起订单
  46. * @param float $totalFee 收款总费用 单位元
  47. * @param string $outTradeNo 唯一的订单号
  48. * @param string $orderName 订单名称
  49. * @param string $notifyUrl 支付结果通知url 不要有问号
  50. * @param string $timestamp 订单发起时间
  51. * @return array
  52. */
  53. public function createJsBizPackage($totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp)
  54. {
  55. $config = array(
  56. 'mch_id' => $this->mchid,
  57. 'appid' => $this->appid,
  58. 'key' => $this->apiKey,
  59. );
  60. //$orderName = iconv('GBK','UTF-8',$orderName);
  61. $unified = array(
  62. 'appid' => $config['appid'],
  63. 'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
  64. 'body' => $orderName,
  65. 'mch_id' => $config['mch_id'],
  66. 'nonce_str' => self::createNonceStr(),
  67. 'notify_url' => $notifyUrl,
  68. 'out_trade_no' => $outTradeNo,
  69. 'spbill_create_ip' => '127.0.0.1',
  70. 'total_fee' => intval($totalFee * 100), //单位 转为分
  71. 'trade_type' => 'NATIVE',
  72. );
  73. $unified['sign'] = self::getSign($unified, $config['key']);
  74. $responseXml = parent::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', self::arrayToXml($unified));
  75. $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
  76. if ($unifiedOrder === false) {
  77. die('parse xml error');
  78. }
  79. if ($unifiedOrder->return_code != 'SUCCESS') {
  80. die($unifiedOrder->return_msg);
  81. }
  82. if ($unifiedOrder->result_code != 'SUCCESS') {
  83. die($unifiedOrder->err_code);
  84. }
  85. $codeUrl = (array)($unifiedOrder->code_url);
  86. if(!$codeUrl[0]) exit('get code_url error');
  87. $arr = array(
  88. "appId" => $config['appid'],
  89. "timeStamp" => $timestamp,
  90. "nonceStr" => self::createNonceStr(),
  91. "package" => "prepay_id=" . $unifiedOrder->prepay_id,
  92. "signType" => 'MD5',
  93. "code_url" => $codeUrl[0],
  94. );
  95. $arr['paySign'] = self::getSign($arr, $config['key']);
  96. return $arr;
  97. }
  98. public function notify()
  99. {
  100. $config = array(
  101. 'mch_id' => $this->mchid,
  102. 'appid' => $this->appid,
  103. 'key' => $this->apiKey,
  104. );
  105. $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
  106. $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
  107. if ($postObj === false) {
  108. die('parse xml error');
  109. }
  110. if ($postObj->return_code != 'SUCCESS') {
  111. die($postObj->return_msg);
  112. }
  113. if ($postObj->result_code != 'SUCCESS') {
  114. die($postObj->err_code);
  115. }
  116. $arr = (array)$postObj;
  117. unset($arr['sign']);
  118. if (self::getSign($arr, $config['key']) == $postObj->sign) {
  119. echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
  120. return $postObj;
  121. }
  122. }
  123. public static function createNonceStr($length = 16)
  124. {
  125. $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  126. $str = '';
  127. for ($i = 0; $i < $length; $i++) {
  128. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  129. }
  130. return $str;
  131. }
  132. public static function arrayToXml($arr)
  133. {
  134. $xml = "<xml>";
  135. foreach ($arr as $key => $val) {
  136. if (is_numeric($val)) {
  137. $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
  138. } else
  139. $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
  140. }
  141. $xml .= "</xml>";
  142. return $xml;
  143. }
  144. /**
  145. * 获取签名
  146. */
  147. public static function getSign($params, $key)
  148. {
  149. ksort($params, SORT_STRING);
  150. $unSignParaString = self::formatQueryParaMap($params, false);
  151. $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
  152. return $signStr;
  153. }
  154. protected static function formatQueryParaMap($paraMap, $urlEncode = false)
  155. {
  156. $buff = "";
  157. ksort($paraMap);
  158. foreach ($paraMap as $k => $v) {
  159. if (null != $v && "null" != $v) {
  160. if ($urlEncode) {
  161. $v = urlencode($v);
  162. }
  163. $buff .= $k . "=" . $v . "&";
  164. }
  165. }
  166. $reqPar = '';
  167. if (strlen($buff) > 0) {
  168. $reqPar = substr($buff, 0, strlen($buff) - 1);
  169. }
  170. return $reqPar;
  171. }
  172. }