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