WxPay.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <?php
  2. namespace app\common\lib;
  3. class WxPay
  4. {
  5. private $config = array(
  6. 'appid' => "", // 微信开放平台上的应用id
  7. 'mch_id' => "1550903451", // 微信申请成功之后的商户号
  8. 'api_key' => "b3ae6bbf3cc4fa017eb169ae219e2c27" // 在微信商户平台上自己设定的32位api密钥
  9. );
  10. /**
  11. * 发起预支付订单
  12. *
  13. * $body 订单描述
  14. * $out_trade_no 订单号
  15. * $total_fee 订单金额,单位为 分
  16. * $notify_url 异步通知回调地址
  17. */
  18. public function getPrePayOrder($body, $out_trade_no, $total_fee, $notify_url)
  19. {
  20. $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
  21. $onoce_str = $this->getRandChar(32);
  22. $data["appid"] = $this->config["appid"];
  23. $data["body"] = $body;
  24. $data["mch_id"] = $this->config['mch_id'];
  25. $data["nonce_str"] = $onoce_str;
  26. $data["notify_url"] = $notify_url;
  27. $data["out_trade_no"] = $out_trade_no;
  28. $data["spbill_create_ip"] = $this->get_client_ip();
  29. $data["total_fee"] = $total_fee;
  30. $data["trade_type"] = "APP";
  31. $s = $this->getSign($data, false);
  32. $data["sign"] = $s;
  33. $xml = $this->arrayToXml($data);
  34. $response = $this->postXmlCurl($xml, $url);
  35. //将微信返回的结果xml转成数组
  36. return $this->xmltoarray($response);
  37. }
  38. public function getOrder($prepayId)
  39. {
  40. $data["appid"] = $this->config["appid"];
  41. $data["noncestr"] = $this->getRandChar(32);;
  42. $data["package"] = "Sign=WXPay";
  43. $data["partnerid"] = $this->config['mch_id'];
  44. $data["prepayid"] = $prepayId;
  45. $data["timestamp"] = time();
  46. $sign = $this->getSign($data, false);
  47. $data["sign"] = $sign;
  48. return $data;
  49. }
  50. //生成签名
  51. function getSign($obj)
  52. {
  53. foreach ($obj as $k => $v) {
  54. $Parameters[strtolower($k)] = $v;
  55. }
  56. ksort($Parameters);
  57. $String = $this->formatBizQueryParaMap($Parameters, false);
  58. $String = $String."&key=".$this->config['api_key'];
  59. //签名步骤三:MD5加密
  60. $result = strtoupper(md5($String));
  61. return $result;
  62. }
  63. //获取指定长度的随机字符串
  64. function getRandChar($length)
  65. {
  66. $str = null;
  67. $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
  68. $max = strlen($strPol) - 1;
  69. //rand($min,$max)生成介于min和max两个数之间的一个随机整数
  70. for ($i=0;$i<$length;$i++) {
  71. $str.= $strPol[rand(0,$max)];
  72. }
  73. return $str;
  74. }
  75. //数组转xml
  76. function arrayToXml($arr)
  77. {
  78. $xml = "<xml>";
  79. foreach ($arr as $key => $val) {
  80. if (is_numeric($val)) {
  81. $xml.= "<".$key.">".$val."</".$key.">";
  82. } else {
  83. $xml.= "<".$key."><![CDATA[".$val."]]></".$key.">";
  84. }
  85. }
  86. $xml.= "</xml>";
  87. return $xml;
  88. }
  89. //post https请求,CURLOPT_POSTFIELDS xml 格式
  90. function postXmlCurl($xml, $url, $second = 30)
  91. {
  92. //初始化curl
  93. $ch = curl_init();
  94. //超时时间
  95. curl_setopt($ch,CURLOPT_TIMEOUT,$second);
  96. //这里设置代理,如果有的话
  97. //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
  98. //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
  99. curl_setopt($ch,CURLOPT_URL, $url);
  100. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
  101. curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
  102. //设置header
  103. curl_setopt($ch, CURLOPT_HEADER, FALSE);
  104. //要求结果为字符串且输出到屏幕上
  105. curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  106. //post提交方式
  107. curl_setopt($ch, CURLOPT_POST, TRUE);
  108. curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  109. //运行curl
  110. $data = curl_exec($ch);
  111. //返回结果
  112. if ($data) {
  113. curl_close($ch);
  114. return $data;
  115. } else {
  116. $error = curl_errno($ch);
  117. echo "curl出错,错误码:$error"."<br>";
  118. echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
  119. curl_close($ch);
  120. return false;
  121. }
  122. }
  123. //获取当前服务器的IP
  124. function get_client_ip()
  125. {
  126. if ($_SERVER['REMOTE_ADDR']) {
  127. $cip = $_SERVER['REMOTE_ADDR'];
  128. } elseif (getenv("REMOTE_ADDR")) {
  129. $cip = getenv("REMOTE_ADDR");
  130. } elseif (getenv("HTTP_CLIENT_IP")) {
  131. $cip = getenv("HTTP_CLIENT_IP");
  132. } else {
  133. $cip = "unknown";
  134. }
  135. return $cip;
  136. }
  137. //将数组转成uri字符串
  138. function formatBizQueryParaMap($paraMap, $urlencode)
  139. {
  140. $buff = "";
  141. ksort($paraMap);
  142. foreach ($paraMap as $k => $v) {
  143. if ($urlencode) {
  144. $v = urlencode($v);
  145. }
  146. $buff.= strtolower($k) . "=" . $v . "&";
  147. }
  148. $reqPar = '';
  149. if (strlen($buff) > 0) {
  150. $reqPar = substr($buff, 0, strlen($buff)-1);
  151. }
  152. return $reqPar;
  153. }
  154. //xml转成数组
  155. public function xmltoarray($xml)
  156. {
  157. //禁止引用外部xml实体
  158. libxml_disable_entity_loader(true);
  159. $xmlstring = simplexml_load_string($xml,'SimpleXMLElement', LIBXML_NOCDATA);
  160. $val = json_decode(json_encode($xmlstring),true);
  161. return $val;
  162. }
  163. function domnode_to_array($node)
  164. {
  165. $output = array();
  166. switch ($node->nodeType) {
  167. case XML_CDATA_SECTION_NODE:
  168. case XML_TEXT_NODE:
  169. $output = trim($node->textContent);
  170. break;
  171. case XML_ELEMENT_NODE:
  172. for ($i=0, $m=$node->childNodes->length; $i < $m; $i++) {
  173. $child = $node->childNodes->item($i);
  174. $v = $this->domnode_to_array($child);
  175. if (isset($child->tagName)) {
  176. $t = $child->tagName;
  177. if (!isset($output[$t])) {
  178. $output[$t] = array();
  179. }
  180. $output[$t][] = $v;
  181. } elseif ($v) {
  182. $output = (string)$v;
  183. }
  184. }
  185. if (is_array($output)) {
  186. if ($node->attributes->length) {
  187. $a = array();
  188. foreach ($node->attributes as $attrName => $attrNode) {
  189. $a[$attrName] = (string) $attrNode->value;
  190. }
  191. $output['@attributes'] = $a;
  192. }
  193. foreach ($output as $t => $v) {
  194. if (is_array($v) && count($v)==1 && $t!='@attributes') {
  195. $output[$t] = $v[0];
  196. }
  197. }
  198. }
  199. break;
  200. }
  201. return $output;
  202. }
  203. }