wxpay2.php 5.7 KB

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