wxpay.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <?php
  2. class WeixinPay {
  3. protected $appid;
  4. protected $mch_id;
  5. protected $key;
  6. protected $openid;
  7. protected $out_trade_no;
  8. protected $body;
  9. protected $total_fee;
  10. protected $root;
  11. function __construct($appid, $openid, $mch_id, $key,$out_trade_no,$body,$total_fee,$root) {
  12. $this->appid = $appid;
  13. $this->openid = $openid;
  14. $this->mch_id = $mch_id;
  15. $this->key = $key;
  16. $this->out_trade_no = $out_trade_no;
  17. $this->body = $body;
  18. $this->total_fee = $total_fee;
  19. $this->root = $root;
  20. }
  21. public function pay() {
  22. //统一下单接口
  23. $return = $this->weixinapp();
  24. return $return;
  25. }
  26. //统一下单接口
  27. private function unifiedorder() {
  28. $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
  29. $parameters = array(
  30. 'appid' => $this->appid, //小程序ID
  31. 'mch_id' => $this->mch_id, //商户号
  32. 'nonce_str' => $this->createNoncestr(), //随机字符串
  33. // 'body' => 'test', //商品描述
  34. 'body' => $this->body,
  35. // 'out_trade_no' => '2015450806125348', //商户订单号
  36. 'out_trade_no'=> $this->out_trade_no,
  37. // 'total_fee' => floatval(0.01 * 100), //总金额 单位 分
  38. 'total_fee' => $this->total_fee,
  39. // 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], //终端IP
  40. 'spbill_create_ip' => '192.168.0.161', //终端IP
  41. // 'notify_url' => 'http://www.weixin.qq.com/wxpay/pay.php', //通知地址 确保外网能正常访问
  42. 'notify_url' => $this->root.'addons/zh_tcwq/payment/wechat/notify.php', //通知地址 确保外网能正常访问
  43. 'openid' => $this->openid, //用户id
  44. 'trade_type' => 'JSAPI'//交易类型
  45. );
  46. //统一下单签名
  47. $parameters['sign'] = $this->getSign($parameters);
  48. $xmlData = $this->arrayToXml($parameters);
  49. $return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60));
  50. return $return;
  51. }
  52. private static function postXmlCurl($xml, $url, $second = 30)
  53. {
  54. $ch = curl_init();
  55. //设置超时
  56. curl_setopt($ch, CURLOPT_TIMEOUT, $second);
  57. curl_setopt($ch, CURLOPT_URL, $url);
  58. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  59. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验
  60. //设置header
  61. curl_setopt($ch, CURLOPT_HEADER, FALSE);
  62. //要求结果为字符串且输出到屏幕上
  63. curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  64. //post提交方式
  65. curl_setopt($ch, CURLOPT_POST, TRUE);
  66. curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  67. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
  68. curl_setopt($ch, CURLOPT_TIMEOUT, 40);
  69. set_time_limit(0);
  70. //运行curl
  71. $data = curl_exec($ch);
  72. //返回结果
  73. if ($data) {
  74. curl_close($ch);
  75. return $data;
  76. } else {
  77. $error = curl_errno($ch);
  78. curl_close($ch);
  79. throw new WxPayException("curl出错,错误码:$error");
  80. }
  81. }
  82. //数组转换成xml
  83. private function arrayToXml($arr) {
  84. $xml = "<root>";
  85. foreach ($arr as $key => $val) {
  86. if (is_array($val)) {
  87. $xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
  88. } else {
  89. $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
  90. }
  91. }
  92. $xml .= "</root>";
  93. return $xml;
  94. }
  95. //xml转换成数组
  96. private function xmlToArray($xml) {
  97. //禁止引用外部xml实体
  98. libxml_disable_entity_loader(true);
  99. $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
  100. $val = json_decode(json_encode($xmlstring), true);
  101. return $val;
  102. }
  103. //微信小程序接口
  104. private function weixinapp() {
  105. //统一下单接口
  106. $unifiedorder = $this->unifiedorder();
  107. // print_r($unifiedorder);
  108. $parameters = array(
  109. 'appId' => $this->appid, //小程序ID
  110. 'timeStamp' => '' . time() . '', //时间戳
  111. 'nonceStr' => $this->createNoncestr(), //随机串
  112. 'package' => 'prepay_id=' . $unifiedorder['prepay_id'], //数据包
  113. 'signType' => 'MD5'//签名方式
  114. );
  115. //签名
  116. $parameters['paySign'] = $this->getSign($parameters);
  117. return $parameters;
  118. }
  119. //作用:产生随机字符串,不长于32位
  120. private function createNoncestr($length = 32) {
  121. $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  122. $str = "";
  123. for ($i = 0; $i < $length; $i++) {
  124. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  125. }
  126. return $str;
  127. }
  128. //作用:生成签名
  129. private function getSign($Obj) {
  130. foreach ($Obj as $k => $v) {
  131. $Parameters[$k] = $v;
  132. }
  133. //签名步骤一:按字典序排序参数
  134. ksort($Parameters);
  135. $String = $this->formatBizQueryParaMap($Parameters, false);
  136. //签名步骤二:在string后加入KEY
  137. $String = $String . "&key=" . $this->key;
  138. //签名步骤三:MD5加密
  139. $String = md5($String);
  140. //签名步骤四:所有字符转为大写
  141. $result_ = strtoupper($String);
  142. return $result_;
  143. }
  144. ///作用:格式化参数,签名过程需要使用
  145. private function formatBizQueryParaMap($paraMap, $urlencode) {
  146. $buff = "";
  147. ksort($paraMap);
  148. foreach ($paraMap as $k => $v) {
  149. if ($urlencode) {
  150. $v = urlencode($v);
  151. }
  152. $buff .= $k . "=" . $v . "&";
  153. }
  154. $reqPar;
  155. if (strlen($buff) > 0) {
  156. $reqPar = substr($buff, 0, strlen($buff) - 1);
  157. }
  158. return $reqPar;
  159. }
  160. }