JsSdkPay.class.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <?php
  2. /**
  3. * 官方文档:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
  4. * 微信支付:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_1#
  5. * 官方示例:http://demo.open.weixin.qq.com/jssdk/sample.zip
  6. * UCToo示例:http://git.oschina.net/uctoo/uctoo/blob/master/Addons/Jssdk/Controller/JssdkController.class.php
  7. *
  8. * 微信JSSDK支付类,主要实现了微信JSSDK支付,参考官方提供的示例文档,
  9. * @命名空间版本
  10. * @author uctoo (www.uctoo.com)
  11. * @date 2015-5-15 14:10
  12. */
  13. namespace Com;
  14. class JsSdkPay {
  15. private $appId;
  16. private $appSecret;
  17. public $debug = false;
  18. public $weObj; //微信类实例
  19. public $parameters;//获取prepay_id时的请求参数
  20. //受理商ID,身份标识
  21. public $MCHID = '';
  22. //商户支付密钥Key。审核通过后,在微信商户平台中查看 https://pay.weixin.qq.com
  23. public $KEY = '';
  24. //=======【JSAPI路径设置】===================================
  25. //获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
  26. public $JS_API_CALL_URL = '';
  27. //=======【证书路径设置】=====================================
  28. //证书路径,注意应该填写绝对路径
  29. public $SSLCERT_PATH = '/xxx/xxx/xxxx/WxPayPubHelper/cacert/apiclient_cert.pem';
  30. public $SSLKEY_PATH = '/xxx/xxx/xxxx/WxPayPubHelper/cacert/apiclient_key.pem';
  31. //=======【异步通知url设置】===================================
  32. //异步通知url,商户根据实际开发过程设定
  33. //C('url')."admin.php/order/notify_url.html";
  34. public $NOTIFY_URL = '';
  35. //=======【curl超时设置】===================================
  36. //本例程通过curl使用HTTP POST方法,此处可修改其超时时间,默认为30秒
  37. public $CURL_TIMEOUT = 30;
  38. public $prepay_id;
  39. public function __construct($options) {
  40. $this->appId = $options['appid'];
  41. $this->appSecret = $options['appsecret'];
  42. $this->weObj = new TPWechat($options);
  43. }
  44. //微信支付相关方法
  45. /**
  46. * 作用:格式化参数,签名过程需要使用
  47. */
  48. function formatBizQueryParaMap($paraMap, $urlencode)
  49. {
  50. $buff = "";
  51. ksort($paraMap);
  52. foreach ($paraMap as $k => $v)
  53. {
  54. if($urlencode)
  55. {
  56. $v = urlencode($v);
  57. }
  58. //$buff .= strtolower($k) . "=" . $v . "&";
  59. $buff .= $k . "=" . $v . "&";
  60. }
  61. $reqPar = "";
  62. if (strlen($buff) > 0)
  63. {
  64. $reqPar = substr($buff, 0, strlen($buff)-1);
  65. }
  66. return $reqPar;
  67. }
  68. /**
  69. * 作用:设置jsapi的参数
  70. */
  71. public function getParameters()
  72. {
  73. $jsApiObj["appId"] = $this->appId; //请求生成支付签名时需要,js调起支付参数中不需要
  74. $timeStamp = time();
  75. $jsApiObj["timeStamp"] = "$timeStamp"; //用大写的timeStamp参数请求生成支付签名
  76. $jsParamObj["timestamp"] = $timeStamp; //用小写的timestamp参数生成js支付参数,还要注意数据类型,坑!
  77. $jsParamObj["nonceStr"] = $jsApiObj["nonceStr"] = $this->weObj->generateNonceStr();
  78. $jsParamObj["package"] = $jsApiObj["package"] = "prepay_id=$this->prepay_id";
  79. $jsParamObj["signType"] = $jsApiObj["signType"] = "MD5";
  80. $jsParamObj["paySign"] = $jsApiObj["paySign"] = $this->getSign($jsApiObj);
  81. $jsParam = json_encode($jsParamObj);
  82. return $jsParam;
  83. }
  84. /**
  85. * 获取prepay_id
  86. */
  87. function getPrepayId()
  88. {
  89. $result = $this->xmlToArray($this->postXml());
  90. $prepay_id = $result["prepay_id"];
  91. return $prepay_id;
  92. }
  93. /**
  94. * 作用:将xml转为array
  95. */
  96. public function xmlToArray($xml)
  97. {
  98. //将XML转为array
  99. $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  100. return $array_data;
  101. }
  102. /**
  103. * 作用:post请求xml
  104. */
  105. function postXml()
  106. {
  107. $xml = $this->createXml();
  108. return $this->postXmlCurl($xml,"https://api.mch.weixin.qq.com/pay/unifiedorder",$this->CURL_TIMEOUT);
  109. }
  110. /**
  111. * 作用:以post方式提交xml到对应的接口url
  112. */
  113. public function postXmlCurl($xml,$url,$second=30)
  114. {
  115. //初始化curl
  116. $ch = curl_init();
  117. //设置超时
  118. curl_setopt($ch,CURLOP_TIMEOUT, $this->CURL_TIMEOUT);
  119. //这里设置代理,如果有的话
  120. //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
  121. //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
  122. curl_setopt($ch,CURLOPT_URL, $url);
  123. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
  124. curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
  125. //设置header
  126. curl_setopt($ch, CURLOPT_HEADER, FALSE);
  127. //要求结果为字符串且输出到屏幕上
  128. curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  129. //post提交方式
  130. curl_setopt($ch, CURLOPT_POST, TRUE);
  131. curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  132. //运行curl
  133. $data = curl_exec($ch);
  134. curl_close($ch);
  135. //返回结果
  136. if($data)
  137. {
  138. curl_close($ch);
  139. return $data;
  140. }
  141. else
  142. {
  143. $error = curl_errno($ch);
  144. echo "curl出错,错误码:$error"."<br>";
  145. echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
  146. curl_close($ch);
  147. return false;
  148. }
  149. }
  150. /**
  151. * 作用:设置标配的请求参数,生成签名,生成接口参数xml
  152. */
  153. function createXml()
  154. {
  155. $this->parameters["appid"] = $this->appId;//公众账号ID
  156. $this->parameters["mch_id"] = $this->MCHID;//商户号
  157. $this->parameters["nonce_str"] = $this->weObj->generateNonceStr();//随机字符串
  158. $this->parameters["sign"] = $this->getSign($this->parameters);//签名
  159. return $this->arrayToXml($this->parameters);
  160. }
  161. /**
  162. * 作用:array转xml
  163. */
  164. function arrayToXml($arr)
  165. {
  166. $xml = "<xml>";
  167. foreach ($arr as $key=>$val)
  168. {
  169. if (is_numeric($val))
  170. {
  171. $xml.="<".$key.">".$val."</".$key.">";
  172. }
  173. else
  174. $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
  175. }
  176. $xml.="</xml>";
  177. return $xml;
  178. }
  179. /**
  180. * 作用:生成签名
  181. */
  182. public function getSign($Obj)
  183. {
  184. foreach ($Obj as $k => $v)
  185. {
  186. $Parameters[$k] = $v;
  187. }
  188. //签名步骤一:按字典序排序参数
  189. ksort($Parameters);
  190. $String = $this->formatBizQueryParaMap($Parameters, false);
  191. //echo '【string1】'.$String.'</br>';
  192. //签名步骤二:在string后加入KEY
  193. $String = $String."&key=".$this->KEY;
  194. //echo "【string2】".$String."</br>";
  195. //签名步骤三:MD5加密
  196. $String = md5($String);
  197. //echo "【string3】 ".$String."</br>";
  198. //签名步骤四:所有字符转为大写
  199. $result_ = strtoupper($String);
  200. //echo "【result】 ".$result_."</br>";
  201. return $result_;
  202. }
  203. }