├── README.md
├── authorize.php
├── barcode.php
├── h5.php
├── jsapi.php
├── jsapi_v3.php
├── native.php
├── native_v3.php
├── notify.php
├── notify_v3.php
├── orderquery.php
├── redpack.php
├── refund.php
├── refund_query.php
├── reverse.php
└── transfers.php
/README.md:
--------------------------------------------------------------------------------
1 | # weixinPay
2 | 一个PHP文件搞定微信支付系列
3 |
4 | 网上的很多PHP微信支付接入教程都颇为复杂,且需要配置和引入较多的文件,本人通过整理后给出一个单文件版的(代码只有200行左右),每个文件独立运行,不依赖和引入其他文件,希望可以给各位想接入微信支付的带来些许帮助和借鉴意义。
5 |
6 | 一个PHP文件搞定支付宝系列请移步:https://github.com/dedemao/alipay
7 |
8 | # 在线演示
9 | https://www.dedemao.com/wx/demo.html
10 |
11 | # 环境依赖
12 |
13 | PHP5.0以上,且需要开启CURL服务、SSL服务。
14 |
15 | # 文件对应说明
16 |
17 | native.php 原生支付(扫码支付)
18 |
19 | barcode.php 刷卡支付(商户扫描用户收款码)
20 |
21 | jsapi.php 公众号支付
22 |
23 | H5.php H5支付
24 |
25 | redpack.php 现金红包
26 |
27 | transfers.php 企业付款到零钱
28 |
29 | notify.php 异步回调通知
30 |
31 | refund.php 退款
32 |
33 | # 注意事项
34 |
35 | 1.需要用到微信支付的哪一种支付方式,就只下载对应的单个文件即可。
36 |
37 | 2.文件开头的配置信息必须完善
38 |
39 | 3.文件需放到支付授权目录下,可以在微信支付商户平台->产品中心->开发配置中设置。
40 |
41 | 4.如提示签名错误可以通过微信支付签名验证工具进行验证:https://pay.weixin.qq.com/wiki/tools/signverify/
42 |
43 |
44 | # 若对您有帮助,可以赞助并支持下作者哦,谢谢!
45 |
46 |
47 |
48 |
联系邮箱:884358@qq.com
49 |
50 |
--------------------------------------------------------------------------------
/authorize.php:
--------------------------------------------------------------------------------
1 | 开发->基本配置->AppID
6 | $appKey = ''; //微信公众平台->开发->基本配置->AppSecret
7 | /* 配置结束 */
8 |
9 | //①、获取用户openid
10 | $wxPay = new WxService($appid,$appKey);
11 | $data = $wxPay->GetOpenid(); //获取openid
12 | if(!$data['openid']) exit('获取openid失败');
13 | //②、获取用户信息
14 | $user = $wxPay->getUserInfo($data['openid'],$data['access_token']);
15 | ?>
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 微信获取用户信息demo
24 |
25 |
26 |
27 |
28 |
29 |
30 |
你的基本信息如下:
31 |
32 |
33 | openid |
34 | =$user['openid']?> |
35 |
36 |
37 | unionid |
38 | =$user['unionid']?> |
39 |
40 |
41 | 昵称 |
42 | =$user['nickname']?> |
43 |
44 |
45 | 头像 |
46 |  |
47 |
48 |
49 | 性别 |
50 | |
63 |
64 |
65 | 省份 / 城市 |
66 | =$user['province'].' / '.$user['city']?> |
67 |
68 |
69 | language |
70 | =$user['language']?> |
71 |
72 |
73 |
74 |
75 |
76 |
77 | appid = $appid; //微信支付申请对应的公众号的APPID
88 | $this->appKey = $appKey; //微信支付申请对应的公众号的APP Key
89 | }
90 |
91 | /**
92 | * 通过跳转获取用户的openid,跳转流程如下:
93 | * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
94 | * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
95 | *
96 | * @return 用户的openid
97 | */
98 | public function GetOpenid()
99 | {
100 | //通过code获得openid
101 | if (!isset($_GET['code'])){
102 | //触发微信返回code码
103 | $baseUrl = $this->getCurrentUrl();
104 | $url = $this->__CreateOauthUrlForCode($baseUrl);
105 | Header("Location: $url");
106 | exit();
107 | } else {
108 | //获取code码,以获取openid
109 | $code = $_GET['code'];
110 | $openid = $this->getOpenidFromMp($code);
111 | return $openid;
112 | }
113 | }
114 |
115 | public function getCurrentUrl()
116 | {
117 | $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
118 | $uri = $_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING'];
119 | if($_SERVER['REQUEST_URI']) $uri = $_SERVER['REQUEST_URI'];
120 | $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$uri);
121 | return $baseUrl;
122 | }
123 |
124 | /**
125 | * 通过code从工作平台获取openid机器access_token
126 | * @param string $code 微信跳转回来带上的code
127 | * @return openid
128 | */
129 | public function GetOpenidFromMp($code)
130 | {
131 | $url = $this->__CreateOauthUrlForOpenid($code);
132 | $res = self::curlGet($url);
133 | $data = json_decode($res,true);
134 | $this->data = $data;
135 | return $data;
136 | }
137 |
138 | /**
139 | * 构造获取open和access_toke的url地址
140 | * @param string $code,微信跳转带回的code
141 | * @return 请求的url
142 | */
143 | private function __CreateOauthUrlForOpenid($code)
144 | {
145 | $urlObj["appid"] = $this->appid;
146 | $urlObj["secret"] = $this->appKey;
147 | $urlObj["code"] = $code;
148 | $urlObj["grant_type"] = "authorization_code";
149 | $bizString = $this->ToUrlParams($urlObj);
150 | return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
151 | }
152 |
153 | /**
154 | * 构造获取code的url连接
155 | * @param string $redirectUrl 微信服务器回跳的url,需要url编码
156 | * @return 返回构造好的url
157 | */
158 | private function __CreateOauthUrlForCode($redirectUrl)
159 | {
160 | $urlObj["appid"] = $this->appid;
161 | $urlObj["redirect_uri"] = "$redirectUrl";
162 | $urlObj["response_type"] = "code";
163 | $urlObj["scope"] = "snsapi_userinfo";
164 | $urlObj["state"] = "STATE";
165 | $bizString = $this->ToUrlParams($urlObj);
166 | return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
167 | }
168 |
169 | /**
170 | * 拼接签名字符串
171 | * @param array $urlObj
172 | * @return 返回已经拼接好的字符串
173 | */
174 | private function ToUrlParams($urlObj)
175 | {
176 | $buff = "";
177 | foreach ($urlObj as $k => $v)
178 | {
179 | if($k != "sign") $buff .= $k . "=" . $v . "&";
180 | }
181 | $buff = trim($buff, "&");
182 | return $buff;
183 | }
184 |
185 | /**
186 | * 获取用户信息
187 | * @param string $openid 调用【网页授权获取用户信息】接口获取到用户在该公众号下的Openid
188 | * @return string
189 | */
190 | public function getUserInfo($openid,$access_token)
191 | {
192 |
193 | $response = self::curlGet('https://api.weixin.qq.com/sns/userinfo?access_token='.$access_token.'&openid='.$openid.'&lang=zh_CN');
194 | return json_decode($response,true);
195 |
196 | }
197 |
198 | public static function curlGet($url = '', $options = array())
199 | {
200 | $ch = curl_init($url);
201 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
202 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
203 | if (!empty($options)) {
204 | curl_setopt_array($ch, $options);
205 | }
206 | //https请求 不验证证书和host
207 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
208 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
209 | $data = curl_exec($ch);
210 | curl_close($ch);
211 | return $data;
212 | }
213 |
214 | public static function curlPost($url = '', $postData = '', $options = array())
215 | {
216 | if (is_array($postData)) {
217 | $postData = http_build_query($postData);
218 | }
219 | $ch = curl_init();
220 | curl_setopt($ch, CURLOPT_URL, $url);
221 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
222 | curl_setopt($ch, CURLOPT_POST, 1);
223 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
224 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
225 | if (!empty($options)) {
226 | curl_setopt_array($ch, $options);
227 | }
228 | //https请求 不验证证书和host
229 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
230 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
231 | $data = curl_exec($ch);
232 | curl_close($ch);
233 | return $data;
234 | }
235 |
236 | }
237 |
--------------------------------------------------------------------------------
/barcode.php:
--------------------------------------------------------------------------------
1 | setTotalFee($payAmount);
17 | $wxPay->setOutTradeNo($outTradeNo);
18 | $wxPay->setOrderName($orderName);
19 | $wxPay->setAuthCode($authCode);
20 | $arr = $wxPay->createJsBizPackage();
21 | if($arr['return_code']=='SUCCESS'){
22 | echo '付款成功!返回信息如下:
';
23 | echo ''.print_r($arr).'
';
24 | exit();
25 | }
26 | exit('error');
27 | class WxpayService
28 | {
29 | protected $mchid;
30 | protected $appid;
31 | protected $apiKey;
32 | protected $totalFee;
33 | protected $outTradeNo;
34 | protected $orderName;
35 | protected $authCode;
36 | public function __construct($mchid='', $appid='', $key='')
37 | {
38 | $this->mchid = $mchid;
39 | $this->appid = $appid;
40 | $this->apiKey = $key;
41 | }
42 |
43 | public function setTotalFee($totalFee)
44 | {
45 | $this->totalFee = $totalFee;
46 | }
47 |
48 | public function setOutTradeNo($outTradeNo)
49 | {
50 | $this->outTradeNo = $outTradeNo;
51 | }
52 |
53 | public function setOrderName($orderName)
54 | {
55 | $this->orderName = $orderName;
56 | }
57 |
58 | public function setAuthCode($authCode)
59 | {
60 | $this->authCode = $authCode;
61 | }
62 |
63 | /**
64 | * 发起订单
65 | * @return array
66 | */
67 | public function createJsBizPackage()
68 | {
69 | $config = array(
70 | 'mch_id' => $this->mchid,
71 | 'appid' => $this->appid,
72 | 'key' => $this->apiKey,
73 | 'total_fee' => $this->totalFee,
74 | 'out_trade_no' => $this->outTradeNo,
75 | 'order_name' => $this->orderName,
76 | 'auth_code' => $this->authCode,
77 | );
78 | //$orderName = iconv('GBK','UTF-8',$orderName);
79 | $unified = array(
80 | 'appid' => $config['appid'],
81 | 'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
82 | 'body' => $config['order_name'],
83 | 'mch_id' => $config['mch_id'],
84 | 'nonce_str' => self::createNonceStr(),
85 | 'out_trade_no' => $config['out_trade_no'],
86 | 'spbill_create_ip' => '127.0.0.1',
87 | 'total_fee' => floatval($config['total_fee']) * 100, //单位 转为分
88 | 'auth_code'=>$config['auth_code'], //收款码,
89 | 'device_info'=>'dedemao001', //终端设备号(商户自定义,如门店编号)
90 | // 'limit_pay'=>'no_credit' //指定支付方式 no_credit--指定不能使用信用卡支付
91 | );
92 | $unified['sign'] = self::getSign($unified, $config['key']);
93 | $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/micropay', self::arrayToXml($unified));
94 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
95 | if ($unifiedOrder === false) {
96 | die('parse xml error');
97 | }
98 | if ($unifiedOrder->return_code != 'SUCCESS') {
99 | die('支付失败:错误码:'.$unifiedOrder->err_code.'。错误码说明:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1#7');
100 | }
101 | if ($unifiedOrder->result_code != 'SUCCESS') {
102 | die('支付失败:错误码:'.$unifiedOrder->err_code.'。错误码说明:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1#7');
103 | }
104 | return (array)$unifiedOrder;
105 | }
106 | public function notify()
107 | {
108 | $config = array(
109 | 'mch_id' => $this->mchid,
110 | 'appid' => $this->appid,
111 | 'key' => $this->apiKey,
112 | );
113 | $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
114 | $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
115 | if ($postObj === false) {
116 | die('parse xml error');
117 | }
118 | if ($postObj->return_code != 'SUCCESS') {
119 | die($postObj->return_msg);
120 | }
121 | if ($postObj->result_code != 'SUCCESS') {
122 | die($postObj->err_code);
123 | }
124 | $arr = (array)$postObj;
125 | unset($arr['sign']);
126 | if (self::getSign($arr, $config['key']) == $postObj->sign) {
127 | echo '';
128 | return $postObj;
129 | }
130 | }
131 | /**
132 | * curl get
133 | *
134 | * @param string $url
135 | * @param array $options
136 | * @return mixed
137 | */
138 | public static function curlGet($url = '', $options = array())
139 | {
140 | $ch = curl_init($url);
141 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
142 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
143 | if (!empty($options)) {
144 | curl_setopt_array($ch, $options);
145 | }
146 | //https请求 不验证证书和host
147 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
148 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
149 | $data = curl_exec($ch);
150 | curl_close($ch);
151 | return $data;
152 | }
153 | public static function curlPost($url = '', $postData = '', $options = array())
154 | {
155 | if (is_array($postData)) {
156 | $postData = http_build_query($postData);
157 | }
158 | $ch = curl_init();
159 | curl_setopt($ch, CURLOPT_URL, $url);
160 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
161 | curl_setopt($ch, CURLOPT_POST, 1);
162 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
163 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
164 | if (!empty($options)) {
165 | curl_setopt_array($ch, $options);
166 | }
167 | //https请求 不验证证书和host
168 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
169 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
170 | $data = curl_exec($ch);
171 | curl_close($ch);
172 | return $data;
173 | }
174 | public static function createNonceStr($length = 16)
175 | {
176 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
177 | $str = '';
178 | for ($i = 0; $i < $length; $i++) {
179 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
180 | }
181 | return $str;
182 | }
183 | public static function arrayToXml($arr)
184 | {
185 | $xml = "";
186 | foreach ($arr as $key => $val) {
187 | if (is_numeric($val)) {
188 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
189 | } else
190 | $xml .= "<" . $key . ">" . $key . ">";
191 | }
192 | $xml .= "";
193 | return $xml;
194 | }
195 | /**
196 | * 获取签名
197 | */
198 | public static function getSign($params, $key)
199 | {
200 | ksort($params, SORT_STRING);
201 | $unSignParaString = self::formatQueryParaMap($params, false);
202 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
203 | return $signStr;
204 | }
205 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
206 | {
207 | $buff = "";
208 | ksort($paraMap);
209 | foreach ($paraMap as $k => $v) {
210 | if (null != $v && "null" != $v) {
211 | if ($urlEncode) {
212 | $v = urlencode($v);
213 | }
214 | $buff .= $k . "=" . $v . "&";
215 | }
216 | }
217 | $reqPar = '';
218 | if (strlen($buff) > 0) {
219 | $reqPar = substr($buff, 0, strlen($buff) - 1);
220 | }
221 | return $reqPar;
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/h5.php:
--------------------------------------------------------------------------------
1 | setTotalFee($payAmount);
29 | $wxPay->setOutTradeNo($outTradeNo);
30 | $wxPay->setOrderName($orderName);
31 | $wxPay->setNotifyUrl($notifyUrl);
32 | $wxPay->setReturnUrl($returnUrl);
33 | $wxPay->setWapUrl($wapUrl);
34 | $wxPay->setWapName($wapName);
35 |
36 | $mwebUrl= $wxPay->createJsBizPackage($payAmount,$outTradeNo,$orderName,$notifyUrl);
37 | echo "";
38 | exit();
39 | class WxpayService
40 | {
41 | protected $mchid;
42 | protected $appid;
43 | protected $apiKey;
44 | protected $totalFee;
45 | protected $outTradeNo;
46 | protected $orderName;
47 | protected $notifyUrl;
48 | protected $returnUrl;
49 | protected $wapUrl;
50 | protected $wapName;
51 |
52 | public function __construct($mchid, $appid, $key)
53 | {
54 | $this->mchid = $mchid;
55 | $this->appid = $appid;
56 | $this->apiKey = $key;
57 | }
58 |
59 | public function setTotalFee($totalFee)
60 | {
61 | $this->totalFee = $totalFee;
62 | }
63 | public function setOutTradeNo($outTradeNo)
64 | {
65 | $this->outTradeNo = $outTradeNo;
66 | }
67 | public function setOrderName($orderName)
68 | {
69 | $this->orderName = $orderName;
70 | }
71 | public function setWapUrl($wapUrl)
72 | {
73 | $this->wapUrl = $wapUrl;
74 | }
75 | public function setWapName($wapName)
76 | {
77 | $this->wapName = $wapName;
78 | }
79 | public function setNotifyUrl($notifyUrl)
80 | {
81 | $this->notifyUrl = $notifyUrl;
82 | }
83 | public function setReturnUrl($returnUrl)
84 | {
85 | $this->returnUrl = $returnUrl;
86 | }
87 |
88 | /**
89 | * 发起订单
90 | * @return array
91 | */
92 | public function createJsBizPackage()
93 | {
94 | $config = array(
95 | 'mch_id' => $this->mchid,
96 | 'appid' => $this->appid,
97 | 'key' => $this->apiKey,
98 | );
99 | $scene_info = array(
100 | 'h5_info' =>array(
101 | 'type'=>'Wap',
102 | 'wap_url'=>$this->wapUrl,
103 | 'wap_name'=>$this->wapName,
104 | )
105 | );
106 | $unified = array(
107 | 'appid' => $config['appid'],
108 | 'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
109 | 'body' => $this->orderName,
110 | 'mch_id' => $config['mch_id'],
111 | 'nonce_str' => self::createNonceStr(),
112 | 'notify_url' => $this->notifyUrl,
113 | 'out_trade_no' => $this->outTradeNo,
114 | 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
115 | 'total_fee' => floatval($this->totalFee) * 100, //单位 转为分
116 | 'trade_type' => 'MWEB',
117 | 'scene_info'=>json_encode($scene_info)
118 | );
119 | $unified['sign'] = self::getSign($unified, $config['key']);
120 | $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', self::arrayToXml($unified));
121 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
122 | if ($unifiedOrder->return_code != 'SUCCESS') {
123 | die($unifiedOrder->return_msg);
124 | }
125 | if($unifiedOrder->mweb_url){
126 | return $unifiedOrder->mweb_url.'&redirect_url='.urlencode($this->returnUrl);
127 | }
128 | exit('error');
129 | }
130 | public static function curlPost($url = '', $postData = '', $options = array())
131 | {
132 | if (is_array($postData)) {
133 | $postData = http_build_query($postData);
134 | }
135 | $ch = curl_init();
136 | curl_setopt($ch, CURLOPT_URL, $url);
137 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
138 | curl_setopt($ch, CURLOPT_POST, 1);
139 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
140 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
141 | if (!empty($options)) {
142 | curl_setopt_array($ch, $options);
143 | }
144 | //https请求 不验证证书和host
145 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
146 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
147 | $data = curl_exec($ch);
148 | curl_close($ch);
149 | return $data;
150 | }
151 | public static function createNonceStr($length = 16)
152 | {
153 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
154 | $str = '';
155 | for ($i = 0; $i < $length; $i++) {
156 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
157 | }
158 | return $str;
159 | }
160 | public static function arrayToXml($arr)
161 | {
162 | $xml = "";
163 | foreach ($arr as $key => $val) {
164 | if (is_numeric($val)) {
165 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
166 | } else
167 | $xml .= "<" . $key . ">" . $key . ">";
168 | }
169 | $xml .= "";
170 | return $xml;
171 | }
172 | /**
173 | * 获取签名
174 | */
175 | public static function getSign($params, $key)
176 | {
177 | ksort($params, SORT_STRING);
178 | $unSignParaString = self::formatQueryParaMap($params, false);
179 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
180 | return $signStr;
181 | }
182 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
183 | {
184 | $buff = "";
185 | ksort($paraMap);
186 | foreach ($paraMap as $k => $v) {
187 | if (null != $v && "null" != $v) {
188 | if ($urlEncode) {
189 | $v = urlencode($v);
190 | }
191 | $buff .= $k . "=" . $v . "&";
192 | }
193 | }
194 | $reqPar = '';
195 | if (strlen($buff) > 0) {
196 | $reqPar = substr($buff, 0, strlen($buff) - 1);
197 | }
198 | return $reqPar;
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/jsapi.php:
--------------------------------------------------------------------------------
1 | GetOpenid(); //获取openid
10 | if(!$openId) exit('获取openid失败');
11 | //②、统一下单
12 | $outTradeNo = uniqid(); //你自己的商品订单号
13 | $payAmount = 0.01; //付款金额,单位:元
14 | $orderName = '支付测试'; //订单标题
15 | $notifyUrl = 'https://www.xxx.com/wx/notify.php'; //付款成功后的回调地址(不要有问号)
16 | $payTime = time(); //付款时间
17 | $jsApiParameters = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$orderName,$notifyUrl,$payTime);
18 | $jsApiParameters = json_encode($jsApiParameters);
19 | ?>
20 |
21 |
22 |
23 |
24 | 微信支付样例-支付
25 |
56 |
57 |
58 |
59 | 该笔订单支付金额为元钱
60 |
61 |
62 |
63 |
64 |
65 | mchid = $mchid; //https://pay.weixin.qq.com 产品中心-开发配置-商户号
76 | $this->appid = $appid; //微信支付申请对应的公众号的APPID
77 | $this->appKey = $appKey; //微信支付申请对应的公众号的APP Key
78 | $this->apiKey = $key; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
79 | }
80 | /**
81 | * 通过跳转获取用户的openid,跳转流程如下:
82 | * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
83 | * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
84 | * @return 用户的openid
85 | */
86 | public function GetOpenid()
87 | {
88 | //通过code获得openid
89 | if (!isset($_GET['code'])){
90 | //触发微信返回code码
91 | $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
92 | $uri = $_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING'];
93 | if($_SERVER['REQUEST_URI']) $uri = $_SERVER['REQUEST_URI'];
94 | $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$uri);
95 | $url = $this->__CreateOauthUrlForCode($baseUrl);
96 | Header("Location: $url");
97 | exit();
98 | } else {
99 | //获取code码,以获取openid
100 | $code = $_GET['code'];
101 | $openid = $this->getOpenidFromMp($code);
102 | return $openid;
103 | }
104 | }
105 | /**
106 | * 通过code从工作平台获取openid机器access_token
107 | * @param string $code 微信跳转回来带上的code
108 | * @return openid
109 | */
110 | public function GetOpenidFromMp($code)
111 | {
112 | $url = $this->__CreateOauthUrlForOpenid($code);
113 | $res = self::curlGet($url);
114 | //取出openid
115 | $data = json_decode($res,true);
116 | $this->data = $data;
117 | $openid = $data['openid'];
118 | return $openid;
119 | }
120 | /**
121 | * 构造获取open和access_toke的url地址
122 | * @param string $code,微信跳转带回的code
123 | * @return 请求的url
124 | */
125 | private function __CreateOauthUrlForOpenid($code)
126 | {
127 | $urlObj["appid"] = $this->appid;
128 | $urlObj["secret"] = $this->appKey;
129 | $urlObj["code"] = $code;
130 | $urlObj["grant_type"] = "authorization_code";
131 | $bizString = $this->ToUrlParams($urlObj);
132 | return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
133 | }
134 | /**
135 | * 构造获取code的url连接
136 | * @param string $redirectUrl 微信服务器回跳的url,需要url编码
137 | * @return 返回构造好的url
138 | */
139 | private function __CreateOauthUrlForCode($redirectUrl)
140 | {
141 | $urlObj["appid"] = $this->appid;
142 | $urlObj["redirect_uri"] = "$redirectUrl";
143 | $urlObj["response_type"] = "code";
144 | $urlObj["scope"] = "snsapi_base";
145 | $urlObj["state"] = "STATE"."#wechat_redirect";
146 | $bizString = $this->ToUrlParams($urlObj);
147 | return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
148 | }
149 | /**
150 | * 拼接签名字符串
151 | * @param array $urlObj
152 | * @return 返回已经拼接好的字符串
153 | */
154 | private function ToUrlParams($urlObj)
155 | {
156 | $buff = "";
157 | foreach ($urlObj as $k => $v)
158 | {
159 | if($k != "sign") $buff .= $k . "=" . $v . "&";
160 | }
161 | $buff = trim($buff, "&");
162 | return $buff;
163 | }
164 | /**
165 | * 统一下单
166 | * @param string $openid 调用【网页授权获取用户信息】接口获取到用户在该公众号下的Openid
167 | * @param float $totalFee 收款总费用 单位元
168 | * @param string $outTradeNo 唯一的订单号
169 | * @param string $orderName 订单名称
170 | * @param string $notifyUrl 支付结果通知url 不要有问号
171 | * @param string $timestamp 支付时间
172 | * @return string
173 | */
174 | public function createJsBizPackage($openid, $totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp)
175 | {
176 | $config = array(
177 | 'mch_id' => $this->mchid,
178 | 'appid' => $this->appid,
179 | 'key' => $this->apiKey,
180 | );
181 | //$orderName = iconv('GBK','UTF-8',$orderName);
182 | $unified = array(
183 | 'appid' => $config['appid'],
184 | 'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
185 | 'body' => $orderName,
186 | 'mch_id' => $config['mch_id'],
187 | 'nonce_str' => self::createNonceStr(),
188 | 'notify_url' => $notifyUrl,
189 | 'openid' => $openid, //rade_type=JSAPI,此参数必传
190 | 'out_trade_no' => $outTradeNo,
191 | 'spbill_create_ip' => '127.0.0.1',
192 | 'total_fee' => floatval($totalFee) * 100, //单位 转为分
193 | 'trade_type' => 'JSAPI',
194 | );
195 | $unified['sign'] = self::getSign($unified, $config['key']);
196 | $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', self::arrayToXml($unified));
197 | //禁止引用外部xml实体
198 | libxml_disable_entity_loader(true);
199 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
200 | if ($unifiedOrder === false) {
201 | die('parse xml error');
202 | }
203 | if ($unifiedOrder->return_code != 'SUCCESS') {
204 | die($unifiedOrder->return_msg);
205 | }
206 | if ($unifiedOrder->result_code != 'SUCCESS') {
207 | die($unifiedOrder->err_code);
208 | }
209 | $arr = array(
210 | "appId" => $config['appid'],
211 | "timeStamp" => "$timestamp", //这里是字符串的时间戳,不是int,所以需加引号
212 | "nonceStr" => self::createNonceStr(),
213 | "package" => "prepay_id=" . $unifiedOrder->prepay_id,
214 | "signType" => 'MD5',
215 | );
216 | $arr['paySign'] = self::getSign($arr, $config['key']);
217 | return $arr;
218 | }
219 | public static function curlGet($url = '', $options = array())
220 | {
221 | $ch = curl_init($url);
222 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
223 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
224 | if (!empty($options)) {
225 | curl_setopt_array($ch, $options);
226 | }
227 | //https请求 不验证证书和host
228 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
229 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
230 | $data = curl_exec($ch);
231 | curl_close($ch);
232 | return $data;
233 | }
234 | public static function curlPost($url = '', $postData = '', $options = array())
235 | {
236 | if (is_array($postData)) {
237 | $postData = http_build_query($postData);
238 | }
239 | $ch = curl_init();
240 | curl_setopt($ch, CURLOPT_URL, $url);
241 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
242 | curl_setopt($ch, CURLOPT_POST, 1);
243 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
244 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
245 | if (!empty($options)) {
246 | curl_setopt_array($ch, $options);
247 | }
248 | //https请求 不验证证书和host
249 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
250 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
251 | $data = curl_exec($ch);
252 | curl_close($ch);
253 | return $data;
254 | }
255 | public static function createNonceStr($length = 16)
256 | {
257 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
258 | $str = '';
259 | for ($i = 0; $i < $length; $i++) {
260 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
261 | }
262 | return $str;
263 | }
264 | public static function arrayToXml($arr)
265 | {
266 | $xml = "";
267 | foreach ($arr as $key => $val) {
268 | if (is_numeric($val)) {
269 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
270 | } else
271 | $xml .= "<" . $key . ">" . $key . ">";
272 | }
273 | $xml .= "";
274 | return $xml;
275 | }
276 | public static function getSign($params, $key)
277 | {
278 | ksort($params, SORT_STRING);
279 | $unSignParaString = self::formatQueryParaMap($params, false);
280 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
281 | return $signStr;
282 | }
283 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
284 | {
285 | $buff = "";
286 | ksort($paraMap);
287 | foreach ($paraMap as $k => $v) {
288 | if (null != $v && "null" != $v) {
289 | if ($urlEncode) {
290 | $v = urlencode($v);
291 | }
292 | $buff .= $k . "=" . $v . "&";
293 | }
294 | }
295 | $reqPar = '';
296 | if (strlen($buff) > 0) {
297 | $reqPar = substr($buff, 0, strlen($buff) - 1);
298 | }
299 | return $reqPar;
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/jsapi_v3.php:
--------------------------------------------------------------------------------
1 | GetOpenid(); //获取openid
19 | if(!$openId) exit('获取openid失败');
20 | //②、统一下单
21 | $wxPay->setOrderName($orderName);
22 | $wxPay->setOutTradeNo($outTradeNo);
23 | $wxPay->setTotalFee($payAmount);
24 | $wxPay->setNotifyUrl($notifyUrl);
25 | $wxPay->setOpenid($openId);
26 | $result = $wxPay->doPay();
27 | $jsApiParameters = json_encode($result);
28 | ?>
29 |
30 |
31 |
32 |
33 | 微信支付样例-支付
34 |
65 |
66 |
67 |
68 | 该笔订单支付金额为元钱
69 |
70 |
71 |
72 |
73 |
74 | mchid = $mchid;
95 | $this->appid = $appid;
96 | $this->apiKey = $apikey;
97 | $this->appKey = $appkey;
98 | $this->privateKeyPath = $privateKeyPath;
99 | $this->serialNumber = $serialNumber;
100 | }
101 |
102 | public function setTotalFee($totalFee)
103 | {
104 | $this->totalFee = floatval($totalFee);
105 | }
106 |
107 | public function setOutTradeNo($outTradeNo)
108 | {
109 | $this->outTradeNo = $outTradeNo;
110 | }
111 |
112 | public function setOrderName($orderName)
113 | {
114 | $this->orderName = $orderName;
115 | }
116 |
117 | public function setNotifyUrl($notifyUrl)
118 | {
119 | $this->notifyUrl = $notifyUrl;
120 | }
121 |
122 | public function setOpenid($openid)
123 | {
124 | $this->openid = $openid;
125 | }
126 |
127 | /**
128 | * 发起支付
129 | */
130 | public function doPay()
131 | {
132 | $reqParams = array(
133 | 'appid' => $this->appid, //公众号或移动应用appid
134 | 'mchid' => $this->mchid, //商户号
135 | 'description' => $this->orderName, //商品描述
136 | 'attach' => 'pay', //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
137 | 'notify_url' => $this->notifyUrl, //通知URL必须为直接可访问的URL,不允许携带查询串。
138 | 'out_trade_no' => $this->outTradeNo, //商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一,详见【商户订单号】。特殊规则:最小字符长度为6
139 | 'amount'=>array(
140 | 'total'=>intval($this->totalFee * 100), //订单总金额,单位为分
141 | 'currency'=>'CNY', //CNY:人民币,境内商户号仅支持人民币
142 | ),
143 | 'scene_info'=>array( //支付场景描述
144 | 'payer_client_ip'=>'127.0.0.1' //调用微信支付API的机器IP
145 | ),
146 | 'payer'=>array( //支付场景描述
147 | 'openid'=>$this->openid //调用微信支付API的机器IP
148 | )
149 | );
150 | $reqUrl = $this->gateWay.'/pay/transactions/jsapi';
151 | $this->getAuthStr($reqUrl,$reqParams);
152 | $response = $this->curlPost($reqUrl,$reqParams);
153 | $response = json_decode($response,true);
154 |
155 | if(isset($response['code'])){
156 | echo $response['code'].':'.$response['message'];exit();
157 | }
158 | $timestamp = time();
159 | $arr = array(
160 | "appId" => $this->appid,
161 | "timeStamp" => "$timestamp", //这里是字符串的时间戳,不是int,所以需加引号
162 | "nonceStr" => $this->getNonce(),
163 | "package" => "prepay_id=" . $response['prepay_id'],
164 | "signType" => 'RSA',
165 | );
166 | $message = $this->appid . "\n" .
167 | $timestamp . "\n" .
168 | $arr['nonceStr'] . "\n" .
169 | "prepay_id=" . $response['prepay_id'] . "\n";
170 | $arr['paySign'] = $this->sign($message, 'RSA');
171 | return $arr;
172 | }
173 |
174 | private function sign($message,$signType='sha256WithRSAEncryption')
175 | {
176 | $res = file_get_contents($this->privateKeyPath);
177 | if($signType=='RSA'){
178 | $result = openssl_sign($message, $sign, $res,version_compare(PHP_VERSION,'5.4.0', '<') ? SHA256 : OPENSSL_ALGO_SHA256);
179 | }else{
180 | if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
181 | throw new \RuntimeException("当前PHP环境不支持SHA256withRSA");
182 | }
183 | $result = openssl_sign($message, $sign, $res, 'sha256WithRSAEncryption');
184 | }
185 | if (!$result) {
186 | throw new \UnexpectedValueException("签名验证过程发生了错误");
187 | }
188 | return base64_encode($sign);
189 | }
190 |
191 | public function curlPost($url = '', $postData = array(), $options = array())
192 | {
193 | if (is_array($postData)) {
194 | $postData = json_encode($postData);
195 | }
196 | $ch = curl_init();
197 | curl_setopt($ch, CURLOPT_URL, $url);
198 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
199 | curl_setopt($ch, CURLOPT_POST, 1);
200 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
201 | curl_setopt($ch, CURLOPT_HTTPHEADER, array(
202 | 'Authorization:'.$this->auth,
203 | 'Content-Type:application/json',
204 | 'Accept:application/json',
205 | 'User-Agent:'.$_SERVER['HTTP_USER_AGENT']
206 | ));
207 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
208 | if (!empty($options)) {
209 | curl_setopt_array($ch, $options);
210 | }
211 | //https请求 不验证证书和host
212 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
213 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
214 | $data = curl_exec($ch);
215 | curl_close($ch);
216 | return $data;
217 | }
218 |
219 | private function getSchema()
220 | {
221 | return 'WECHATPAY2-SHA256-RSA2048';
222 | }
223 |
224 | public function getAuthStr($requestUrl,$reqParams=array())
225 | {
226 | $schema = $this->getSchema();
227 | $token = $this->getToken($requestUrl,$reqParams);
228 | $this->auth = $schema.' '.$token;
229 | return $this->auth;
230 | }
231 |
232 | private function getNonce()
233 | {
234 | static $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
235 | $charactersLength = strlen($characters);
236 | $randomString = '';
237 | for ($i = 0; $i < 32; $i++) {
238 | $randomString .= $characters[rand(0, $charactersLength - 1)];
239 | }
240 | return $randomString;
241 | }
242 |
243 | public function getToken($requestUrl,$reqParams=array())
244 | {
245 | $body = $reqParams ? json_encode($reqParams) : '';
246 | $nonce = $this->getNonce();
247 | $timestamp = time();
248 | $message = $this->buildMessage($nonce, $timestamp, $requestUrl,$body);
249 | $sign = $this->sign($message);
250 | $serialNo = $this->serialNumber;
251 | return sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
252 | $this->mchid, $nonce, $timestamp, $serialNo, $sign
253 | );
254 | }
255 |
256 | private function buildMessage($nonce, $timestamp, $requestUrl, $body = '')
257 | {
258 | $method = 'POST';
259 | $urlParts = parse_url($requestUrl);
260 | $canonicalUrl = ($urlParts['path'] . (!empty($urlParts['query']) ? "?{$urlParts['query']}" : ""));
261 | return strtoupper($method) . "\n" .
262 | $canonicalUrl . "\n" .
263 | $timestamp . "\n" .
264 | $nonce . "\n" .
265 | $body . "\n";
266 | }
267 |
268 | /**
269 | * 通过跳转获取用户的openid,跳转流程如下:
270 | * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
271 | * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
272 | * @return 用户的openid
273 | */
274 | public function GetOpenid()
275 | {
276 | //通过code获得openid
277 | if (!isset($_GET['code'])){
278 | //触发微信返回code码
279 | $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
280 | $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
281 | $url = $this->__CreateOauthUrlForCode($baseUrl);
282 | Header("Location: $url");
283 | exit();
284 | } else {
285 | //获取code码,以获取openid
286 | $code = $_GET['code'];
287 | $openid = $this->getOpenidFromMp($code);
288 | return $openid;
289 | }
290 | }
291 |
292 | /**
293 | * 构造获取code的url连接
294 | * @param string $redirectUrl 微信服务器回跳的url,需要url编码
295 | * @return 返回构造好的url
296 | */
297 | private function __CreateOauthUrlForCode($redirectUrl)
298 | {
299 | $urlObj["appid"] = $this->appid;
300 | $urlObj["redirect_uri"] = "$redirectUrl";
301 | $urlObj["response_type"] = "code";
302 | $urlObj["scope"] = "snsapi_base";
303 | $urlObj["state"] = "STATE"."#wechat_redirect";
304 | $bizString = $this->ToUrlParams($urlObj);
305 | return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
306 | }
307 |
308 | /**
309 | * 通过code从工作平台获取openid机器access_token
310 | * @param string $code 微信跳转回来带上的code
311 | * @return openid
312 | */
313 | public function GetOpenidFromMp($code)
314 | {
315 | $url = $this->__CreateOauthUrlForOpenid($code);
316 | $res = self::curlGet($url);
317 | //取出openid
318 | $data = json_decode($res,true);
319 | // $this->data = $data;
320 | $openid = $data['openid'];
321 | return $openid;
322 | }
323 |
324 | public static function curlGet($url = '', $options = array())
325 | {
326 | $ch = curl_init($url);
327 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
328 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
329 | if (!empty($options)) {
330 | curl_setopt_array($ch, $options);
331 | }
332 | //https请求 不验证证书和host
333 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
334 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
335 | $data = curl_exec($ch);
336 | curl_close($ch);
337 | return $data;
338 | }
339 |
340 | /**
341 | * 构造获取open和access_toke的url地址
342 | * @param string $code,微信跳转带回的code
343 | * @return 请求的url
344 | */
345 | private function __CreateOauthUrlForOpenid($code)
346 | {
347 | $urlObj["appid"] = $this->appid;
348 | $urlObj["secret"] = $this->appKey;
349 | $urlObj["code"] = $code;
350 | $urlObj["grant_type"] = "authorization_code";
351 | $bizString = $this->ToUrlParams($urlObj);
352 | return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
353 | }
354 |
355 | /**
356 | * 拼接签名字符串
357 | * @param array $urlObj
358 | * @return 返回已经拼接好的字符串
359 | */
360 | private function ToUrlParams($urlObj)
361 | {
362 | $buff = "";
363 | foreach ($urlObj as $k => $v)
364 | {
365 | if($k != "sign") $buff .= $k . "=" . $v . "&";
366 | }
367 | $buff = trim($buff, "&");
368 | return $buff;
369 | }
370 | }
--------------------------------------------------------------------------------
/native.php:
--------------------------------------------------------------------------------
1 | createJsBizPackage($payAmount,$outTradeNo,$orderName,$notifyUrl,$payTime);
13 | //生成二维码
14 | $url = 'https://wenhairu.com/static/api/qr/?size=300&text='.$arr['code_url'];
15 | echo "
";
16 | echo '二维码内容:'.$arr['code_url'];
17 | class WxpayService
18 | {
19 | protected $mchid;
20 | protected $appid;
21 | protected $apiKey;
22 | public function __construct($mchid, $appid, $key)
23 | {
24 | $this->mchid = $mchid;
25 | $this->appid = $appid;
26 | $this->apiKey = $key;
27 | }
28 | /**
29 | * 发起订单
30 | * @param float $totalFee 收款总费用 单位元
31 | * @param string $outTradeNo 唯一的订单号
32 | * @param string $orderName 订单名称
33 | * @param string $notifyUrl 支付结果通知url 不要有问号
34 | * @param string $timestamp 订单发起时间
35 | * @return array
36 | */
37 | public function createJsBizPackage($totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp)
38 | {
39 | $config = array(
40 | 'mch_id' => $this->mchid,
41 | 'appid' => $this->appid,
42 | 'key' => $this->apiKey,
43 | );
44 | //$orderName = iconv('GBK','UTF-8',$orderName);
45 | $unified = array(
46 | 'appid' => $config['appid'],
47 | 'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
48 | 'body' => $orderName,
49 | 'mch_id' => $config['mch_id'],
50 | 'nonce_str' => self::createNonceStr(),
51 | 'notify_url' => $notifyUrl,
52 | 'out_trade_no' => $outTradeNo,
53 | 'spbill_create_ip' => '127.0.0.1',
54 | 'total_fee' => floatval($totalFee) * 100, //单位 转为分
55 | 'trade_type' => 'NATIVE',
56 | );
57 | $unified['sign'] = self::getSign($unified, $config['key']);
58 | $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', self::arrayToXml($unified));
59 | //禁止引用外部xml实体
60 | libxml_disable_entity_loader(true);
61 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
62 | if ($unifiedOrder === false) {
63 | die('parse xml error');
64 | }
65 | if ($unifiedOrder->return_code != 'SUCCESS') {
66 | die($unifiedOrder->return_msg);
67 | }
68 | if ($unifiedOrder->result_code != 'SUCCESS') {
69 | die($unifiedOrder->err_code);
70 | }
71 | $codeUrl = (array)($unifiedOrder->code_url);
72 | if(!$codeUrl[0]) exit('get code_url error');
73 | $arr = array(
74 | "appId" => $config['appid'],
75 | "timeStamp" => $timestamp,
76 | "nonceStr" => self::createNonceStr(),
77 | "package" => "prepay_id=" . $unifiedOrder->prepay_id,
78 | "signType" => 'MD5',
79 | "code_url" => $codeUrl[0],
80 | );
81 | $arr['paySign'] = self::getSign($arr, $config['key']);
82 | return $arr;
83 | }
84 | public function notify()
85 | {
86 | $config = array(
87 | 'mch_id' => $this->mchid,
88 | 'appid' => $this->appid,
89 | 'key' => $this->apiKey,
90 | );
91 | $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
92 | $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
93 | if ($postObj === false) {
94 | die('parse xml error');
95 | }
96 | if ($postObj->return_code != 'SUCCESS') {
97 | die($postObj->return_msg);
98 | }
99 | if ($postObj->result_code != 'SUCCESS') {
100 | die($postObj->err_code);
101 | }
102 | $arr = (array)$postObj;
103 | unset($arr['sign']);
104 | if (self::getSign($arr, $config['key']) == $postObj->sign) {
105 | echo '';
106 | return $postObj;
107 | }
108 | }
109 | /**
110 | * curl get
111 | *
112 | * @param string $url
113 | * @param array $options
114 | * @return mixed
115 | */
116 | public static function curlGet($url = '', $options = array())
117 | {
118 | $ch = curl_init($url);
119 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
120 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
121 | if (!empty($options)) {
122 | curl_setopt_array($ch, $options);
123 | }
124 | //https请求 不验证证书和host
125 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
126 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
127 | $data = curl_exec($ch);
128 | curl_close($ch);
129 | return $data;
130 | }
131 | public static function curlPost($url = '', $postData = '', $options = array())
132 | {
133 | if (is_array($postData)) {
134 | $postData = http_build_query($postData);
135 | }
136 | $ch = curl_init();
137 | curl_setopt($ch, CURLOPT_URL, $url);
138 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
139 | curl_setopt($ch, CURLOPT_POST, 1);
140 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
141 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
142 | if (!empty($options)) {
143 | curl_setopt_array($ch, $options);
144 | }
145 | //https请求 不验证证书和host
146 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
147 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
148 | $data = curl_exec($ch);
149 | curl_close($ch);
150 | return $data;
151 | }
152 | public static function createNonceStr($length = 16)
153 | {
154 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
155 | $str = '';
156 | for ($i = 0; $i < $length; $i++) {
157 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
158 | }
159 | return $str;
160 | }
161 | public static function arrayToXml($arr)
162 | {
163 | $xml = "";
164 | foreach ($arr as $key => $val) {
165 | if (is_numeric($val)) {
166 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
167 | } else
168 | $xml .= "<" . $key . ">" . $key . ">";
169 | }
170 | $xml .= "";
171 | return $xml;
172 | }
173 | /**
174 | * 获取签名
175 | */
176 | public static function getSign($params, $key)
177 | {
178 | ksort($params, SORT_STRING);
179 | $unSignParaString = self::formatQueryParaMap($params, false);
180 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
181 | return $signStr;
182 | }
183 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
184 | {
185 | $buff = "";
186 | ksort($paraMap);
187 | foreach ($paraMap as $k => $v) {
188 | if (null != $v && "null" != $v) {
189 | if ($urlEncode) {
190 | $v = urlencode($v);
191 | }
192 | $buff .= $k . "=" . $v . "&";
193 | }
194 | }
195 | $reqPar = '';
196 | if (strlen($buff) > 0) {
197 | $reqPar = substr($buff, 0, strlen($buff) - 1);
198 | }
199 | return $reqPar;
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/native_v3.php:
--------------------------------------------------------------------------------
1 | setTotalFee($payAmount);
17 | $wxPay->setOutTradeNo($outTradeNo);
18 | $wxPay->setOrderName($orderName);
19 | $wxPay->setNotifyUrl($notifyUrl);
20 | $result = $wxPay->doPay();
21 | if(isset($result['code'])){
22 | echo $result['code'].':'.$result['message'];exit();
23 | }
24 | //生成二维码
25 | $url = 'https://wenhairu.com/static/api/qr/?size=300&text=' . $result['code_url'];
26 | echo "
";
27 | echo '二维码内容:' . $result['code_url'];
28 |
29 | class WxpayService
30 | {
31 | protected $mchid;
32 | protected $appid;
33 | protected $apiKey;
34 | protected $privateKeyPath;
35 | protected $serialNumber;
36 | protected $totalFee;
37 | protected $outTradeNo;
38 | protected $orderName;
39 | protected $notifyUrl;
40 | protected $auth;
41 | protected $gateWay='https://api.mch.weixin.qq.com/v3';
42 |
43 | public function __construct($mchid, $appid, $apikey, $privateKeyPath, $serialNumber)
44 | {
45 | $this->mchid = $mchid;
46 | $this->appid = $appid;
47 | $this->apiKey = $apikey;
48 | $this->privateKeyPath = $privateKeyPath;
49 | $this->serialNumber = $serialNumber;
50 | }
51 |
52 | public function setTotalFee($totalFee)
53 | {
54 | $this->totalFee = floatval($totalFee);
55 | }
56 |
57 | public function setOutTradeNo($outTradeNo)
58 | {
59 | $this->outTradeNo = $outTradeNo;
60 | }
61 |
62 | public function setOrderName($orderName)
63 | {
64 | $this->orderName = $orderName;
65 | }
66 |
67 | public function setNotifyUrl($notifyUrl)
68 | {
69 | $this->notifyUrl = $notifyUrl;
70 | }
71 |
72 | /**
73 | * 发起支付
74 | */
75 | public function doPay()
76 | {
77 | $reqParams = array(
78 | 'appid' => $this->appid, //公众号或移动应用appid
79 | 'mchid' => $this->mchid, //商户号
80 | 'description' => $this->orderName, //商品描述
81 | 'attach' => 'pay', //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
82 | 'notify_url' => $this->notifyUrl, //通知URL必须为直接可访问的URL,不允许携带查询串。
83 | 'out_trade_no' => $this->outTradeNo, //商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一,详见【商户订单号】。特殊规则:最小字符长度为6
84 | 'amount'=>array(
85 | 'total'=> floatval($this->totalFee) * 100, //订单总金额,单位为分
86 | 'currency'=> 'CNY', //CNY:人民币,境内商户号仅支持人民币
87 | ),
88 | 'scene_info'=>array( //支付场景描述
89 | 'payer_client_ip'=>'127.0.0.1' //调用微信支付API的机器IP
90 | )
91 | );
92 | $reqUrl = $this->gateWay.'/pay/transactions/native';
93 | $this->getAuthStr($reqUrl,$reqParams);
94 | $response = $this->curlPost($reqUrl,$reqParams);
95 | return json_decode($response,true);
96 |
97 | }
98 |
99 | public function curlPost($url = '', $postData = array(), $options = array())
100 | {
101 | if (is_array($postData)) {
102 | $postData = json_encode($postData);
103 | }
104 | $ch = curl_init();
105 | curl_setopt($ch, CURLOPT_URL, $url);
106 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
107 | curl_setopt($ch, CURLOPT_POST, 1);
108 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
109 | curl_setopt($ch, CURLOPT_HTTPHEADER, array(
110 | 'Authorization:'.$this->auth,
111 | 'Content-Type:application/json',
112 | 'Accept:application/json',
113 | 'User-Agent:'.$_SERVER['HTTP_USER_AGENT']
114 | ));
115 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
116 | if (!empty($options)) {
117 | curl_setopt_array($ch, $options);
118 | }
119 | //https请求 不验证证书和host
120 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
121 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
122 | $data = curl_exec($ch);
123 | curl_close($ch);
124 | return $data;
125 | }
126 |
127 | private function getSchema()
128 | {
129 | return 'WECHATPAY2-SHA256-RSA2048';
130 | }
131 |
132 | public function getAuthStr($requestUrl,$reqParams=array())
133 | {
134 | $schema = $this->getSchema();
135 | $token = $this->getToken($requestUrl,$reqParams);
136 | $this->auth = $schema.' '.$token;
137 | return $this->auth;
138 | }
139 |
140 | private function getNonce()
141 | {
142 | static $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
143 | $charactersLength = strlen($characters);
144 | $randomString = '';
145 | for ($i = 0; $i < 32; $i++) {
146 | $randomString .= $characters[rand(0, $charactersLength - 1)];
147 | }
148 | return $randomString;
149 | }
150 |
151 | public function getToken($requestUrl,$reqParams=array())
152 | {
153 | $body = $reqParams ? json_encode($reqParams) : '';
154 | $nonce = $this->getNonce();
155 | $timestamp = time();
156 | $message = $this->buildMessage($nonce, $timestamp, $requestUrl,$body);
157 | $sign = $this->sign($message);
158 | $serialNo = $this->serialNumber;
159 | return sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
160 | $this->mchid, $nonce, $timestamp, $serialNo, $sign
161 | );
162 | }
163 |
164 | private function buildMessage($nonce, $timestamp, $requestUrl, $body = '')
165 | {
166 | $method = 'POST';
167 | $urlParts = parse_url($requestUrl);
168 | $canonicalUrl = ($urlParts['path'] . (!empty($urlParts['query']) ? "?{$urlParts['query']}" : ""));
169 | return strtoupper($method) . "\n" .
170 | $canonicalUrl . "\n" .
171 | $timestamp . "\n" .
172 | $nonce . "\n" .
173 | $body . "\n";
174 | }
175 |
176 | private function sign($message)
177 | {
178 | if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
179 | throw new \RuntimeException("当前PHP环境不支持SHA256withRSA");
180 | }
181 | $res = file_get_contents($this->privateKeyPath);
182 | if (!openssl_sign($message, $sign, $res, 'sha256WithRSAEncryption')) {
183 | throw new \UnexpectedValueException("签名验证过程发生了错误");
184 | }
185 | return base64_encode($sign);
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/notify.php:
--------------------------------------------------------------------------------
1 | notify();
14 | if($result){
15 | //完成你的逻辑
16 | //例如连接数据库,获取付款金额$result['cash_fee'],获取订单号$result['out_trade_no'],修改数据库中的订单状态等;
17 | //现金支付金额:$result['cash_fee']
18 | //订单金额:$result['total_fee']
19 | //商户订单号:$result['out_trade_no']
20 | //付款银行:$result['bank_type']
21 | //货币种类:$result['fee_type']
22 | //是否关注公众账号:$result['is_subscribe']
23 | //用户标识:$result['openid']
24 | //业务结果:$result['result_code'] SUCCESS/FAIL
25 | //支付完成时间:$result['time_end'] 格式为yyyyMMddHHmmss
26 | //具体详细请看微信文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
27 | }else{
28 | echo 'pay error';
29 | }
30 | class WxpayService
31 | {
32 | protected $mchid;
33 | protected $appid;
34 | protected $apiKey;
35 | public function __construct($mchid, $appid, $key)
36 | {
37 | $this->mchid = $mchid;
38 | $this->appid = $appid;
39 | $this->apiKey = $key;
40 | }
41 |
42 | public function notify()
43 | {
44 | $config = array(
45 | 'mch_id' => $this->mchid,
46 | 'appid' => $this->appid,
47 | 'key' => $this->apiKey,
48 | );
49 | $postStr = file_get_contents('php://input');
50 | //禁止引用外部xml实体
51 | libxml_disable_entity_loader(true);
52 | $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
53 | if ($postObj === false) {
54 | die('parse xml error');
55 | }
56 | if ($postObj->return_code != 'SUCCESS') {
57 | die($postObj->return_msg);
58 | }
59 | if ($postObj->result_code != 'SUCCESS') {
60 | die($postObj->err_code);
61 | }
62 | $arr = (array)$postObj;
63 | unset($arr['sign']);
64 | if (self::getSign($arr, $config['key']) == $postObj->sign) {
65 | echo '';
66 | return $arr;
67 | }
68 | }
69 |
70 | /**
71 | * 获取签名
72 | */
73 | public static function getSign($params, $key)
74 | {
75 | ksort($params, SORT_STRING);
76 | $unSignParaString = self::formatQueryParaMap($params, false);
77 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
78 | return $signStr;
79 | }
80 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
81 | {
82 | $buff = "";
83 | ksort($paraMap);
84 | foreach ($paraMap as $k => $v) {
85 | if (null != $v && "null" != $v) {
86 | if ($urlEncode) {
87 | $v = urlencode($v);
88 | }
89 | $buff .= $k . "=" . $v . "&";
90 | }
91 | }
92 | $reqPar = '';
93 | if (strlen($buff) > 0) {
94 | $reqPar = substr($buff, 0, strlen($buff) - 1);
95 | }
96 | return $reqPar;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/notify_v3.php:
--------------------------------------------------------------------------------
1 | validate();
10 | if($result===false){
11 | //验证签名失败
12 | exit('sign error');
13 | }
14 | $result = $wxPay->notify();
15 | if ($result === false) {
16 | exit('pay error');
17 | }
18 | if ($result['trade_state'] == 'SUCCESS') {
19 | //支付成功,完成你的逻辑
20 | //例如连接数据库,获取付款金额$result['amount']['total'],获取订单号$result['out_trade_no']修改数据库中的订单状态等;
21 | //订单总金额,单位为分:$result['amount']['total']
22 | //用户支付金额,单位为分:$result['amount']['payer_total']
23 | //商户订单号:$result['out_trade_no']
24 | //微信支付订单号:$result['transaction_id']
25 | //银行类型:$result['bank_type']
26 | //支付完成时间:$result['success_time'] 格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE
27 | //用户标识:$result['payer']['openid']
28 | //交易状态:$result['trade_state']
29 | //具体详细请看微信文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transactions/chapter3_11.shtml
30 | echo 'success';
31 | }
32 |
33 |
34 | class WxpayService
35 | {
36 | protected $apiKey;
37 | protected $publicKeyPath;
38 | protected $publicKey;
39 |
40 | public function __construct($apikey, $publicKeyPath)
41 | {
42 | $this->apiKey = $apikey;
43 | $this->publicKeyPath = $publicKeyPath;
44 | }
45 |
46 | public function getHeader($key = '')
47 | {
48 | $headers = getallheaders();
49 | if ($key) {
50 | return $headers[$key];
51 | }
52 | return $headers;
53 | }
54 |
55 | public function validate()
56 | {
57 | $serialNo = $this->getHeader('Wechatpay-Serial');
58 | $sign = $this->getHeader('Wechatpay-Signature');
59 | $timestamp = $this->getHeader('Wechatpay-Timestamp');
60 | $nonce = $this->getHeader('Wechatpay-Nonce');
61 | if (!isset($serialNo, $sign, $timestamp, $nonce)) {
62 | return false;
63 | }
64 | // if (!$this->checkTimestamp($timestamp)) {
65 | // return false;
66 | // }
67 | $body = file_get_contents('php://input');
68 | $message = "$timestamp\n$nonce\n$body\n";
69 |
70 | $certificate = openssl_x509_read(file_get_contents($this->publicKeyPath));
71 | $_serialNo = $this->parseSerialNo($certificate);
72 | if ($serialNo !== $_serialNo) return false;
73 | $this->publicKey = openssl_get_publickey($certificate);
74 | return $this->verify($message, $sign);
75 | }
76 |
77 | private function verify($message, $signature)
78 | {
79 | if (!$this->publicKey) {
80 | return false;
81 | }
82 | if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
83 | exit("当前PHP环境不支持SHA256withRSA");
84 | }
85 | $signature = base64_decode($signature);
86 | return (bool)openssl_verify($message, $signature, $this->publicKey, 'sha256WithRSAEncryption');
87 | }
88 |
89 | private function parseSerialNo($certificate)
90 | {
91 | $info = openssl_x509_parse($certificate);
92 | if (!isset($info['serialNumber']) && !isset($info['serialNumberHex'])) {
93 | exit('证书格式错误');
94 | }
95 |
96 | $serialNo = '';
97 | if (isset($info['serialNumberHex'])) {
98 | $serialNo = $info['serialNumberHex'];
99 | } else {
100 | if (strtolower(substr($info['serialNumber'], 0, 2)) == '0x') { // HEX format
101 | $serialNo = substr($info['serialNumber'], 2);
102 | } else { // DEC format
103 | $value = $info['serialNumber'];
104 | $hexvalues = ['0', '1', '2', '3', '4', '5', '6', '7',
105 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
106 | while ($value != '0') {
107 | $serialNo = $hexvalues[bcmod($value, '16')] . $serialNo;
108 | $value = bcdiv($value, '16', 0);
109 | }
110 | }
111 | }
112 |
113 | return strtoupper($serialNo);
114 | }
115 |
116 | protected function checkTimestamp($timestamp)
117 | {
118 | return abs((int)$timestamp - time()) <= 120;
119 | }
120 |
121 | public function notify()
122 | {
123 | $postStr = file_get_contents('php://input');
124 | $postData = json_decode($postStr, true);
125 | if ($postData['resource']) {
126 | $data = $this->decryptToString($postData['resource']['associated_data'], $postData['resource']['nonce'], $postData['resource']['ciphertext']);
127 | $data = json_decode($data, true);
128 | return is_array($data) ? $data : false;
129 | }
130 | return false;
131 | }
132 |
133 | public function decryptToString($associatedData, $nonceStr, $ciphertext)
134 | {
135 | $ciphertext = base64_decode($ciphertext);
136 | if (strlen($ciphertext) <= 16) {
137 | return false;
138 | }
139 |
140 | // ext-sodium (default installed on >= PHP 7.2)
141 | if (function_exists('sodium_crypto_aead_aes256gcm_is_available') &&
142 | sodium_crypto_aead_aes256gcm_is_available()) {
143 | return sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->apiKey);
144 | }
145 |
146 | // ext-libsodium (need install libsodium-php 1.x via pecl)
147 | if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&
148 | \Sodium\crypto_aead_aes256gcm_is_available()) {
149 | return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->apiKey);
150 | }
151 |
152 | // openssl (PHP >= 7.1 support AEAD)
153 | if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', openssl_get_cipher_methods())) {
154 | $ctext = substr($ciphertext, 0, -16);
155 | $authTag = substr($ciphertext, -16);
156 |
157 | return openssl_decrypt($ctext, 'aes-256-gcm', $this->apiKey, OPENSSL_RAW_DATA, $nonceStr,
158 | $authTag, $associatedData);
159 | }
160 |
161 | exit('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/orderquery.php:
--------------------------------------------------------------------------------
1 | orderquery($outTradeNo);
13 | echo json_encode($result);die;
14 |
15 | class WxpayService
16 | {
17 | protected $mchid;
18 | protected $appid;
19 | protected $apiKey;
20 | protected $returnUrl;
21 | public function __construct($mchid, $appid, $key)
22 | {
23 | $this->mchid = $mchid;
24 | $this->appid = $appid;
25 | $this->apiKey = $key;
26 | }
27 |
28 | public function setReturnUrl($returnUrl)
29 | {
30 | $this->returnUrl = $returnUrl;
31 | }
32 |
33 | public function orderquery($outTradeNo)
34 | {
35 | $config = array(
36 | 'mch_id' => $this->mchid,
37 | 'appid' => $this->appid,
38 | 'key' => $this->apiKey,
39 | );
40 | //$orderName = iconv('GBK','UTF-8',$orderName);
41 | $unified = array(
42 | 'appid' => $config['appid'],
43 | 'mch_id' => $config['mch_id'],
44 | 'out_trade_no' => $outTradeNo,
45 | 'nonce_str' => self::createNonceStr(),
46 | );
47 | $unified['sign'] = self::getSign($unified, $config['key']);
48 | $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/orderquery', self::arrayToXml($unified));
49 | $queryResult = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
50 | if ($queryResult === false) {
51 | die('parse xml error');
52 | }
53 | if ($queryResult->return_code != 'SUCCESS') {
54 | die($queryResult->return_msg);
55 | }
56 | $trade_state = $queryResult->trade_state;
57 | $data['code'] = $trade_state=='SUCCESS' ? 0 : 1;
58 | $data['data'] = $trade_state;
59 | $data['msg'] = $this->getTradeSTate($trade_state);
60 | $data['time'] = date('Y-m-d H:i:s');
61 | return $data;exit();
62 | }
63 |
64 | public function getTradeSTate($str)
65 | {
66 | switch ($str){
67 | case 'SUCCESS';
68 | return '支付成功';
69 | case 'REFUND';
70 | return '转入退款';
71 | case 'NOTPAY';
72 | return '未支付';
73 | case 'CLOSED';
74 | return '已关闭';
75 | case 'REVOKED';
76 | return '已撤销(刷卡支付)';
77 | case 'USERPAYING';
78 | return '用户支付中';
79 | case 'PAYERROR';
80 | return '支付失败';
81 | }
82 | }
83 | /**
84 | * curl get
85 | *
86 | * @param string $url
87 | * @param array $options
88 | * @return mixed
89 | */
90 | public static function curlGet($url = '', $options = array())
91 | {
92 | $ch = curl_init($url);
93 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
94 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
95 | if (!empty($options)) {
96 | curl_setopt_array($ch, $options);
97 | }
98 | //https请求 不验证证书和host
99 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
100 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
101 | $data = curl_exec($ch);
102 | curl_close($ch);
103 | return $data;
104 | }
105 | public static function curlPost($url = '', $postData = '', $options = array())
106 | {
107 | if (is_array($postData)) {
108 | $postData = http_build_query($postData);
109 | }
110 | $ch = curl_init();
111 | curl_setopt($ch, CURLOPT_URL, $url);
112 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
113 | curl_setopt($ch, CURLOPT_POST, 1);
114 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
115 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
116 | if (!empty($options)) {
117 | curl_setopt_array($ch, $options);
118 | }
119 | //https请求 不验证证书和host
120 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
121 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
122 | $data = curl_exec($ch);
123 | curl_close($ch);
124 | return $data;
125 | }
126 | public static function createNonceStr($length = 16)
127 | {
128 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
129 | $str = '';
130 | for ($i = 0; $i < $length; $i++) {
131 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
132 | }
133 | return $str;
134 | }
135 | public static function arrayToXml($arr)
136 | {
137 | $xml = "";
138 | foreach ($arr as $key => $val) {
139 | if (is_numeric($val)) {
140 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
141 | } else
142 | $xml .= "<" . $key . ">" . $key . ">";
143 | }
144 | $xml .= "";
145 | return $xml;
146 | }
147 | /**
148 | * 获取签名
149 | */
150 | public static function getSign($params, $key)
151 | {
152 | ksort($params, SORT_STRING);
153 | $unSignParaString = self::formatQueryParaMap($params, false);
154 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
155 | return $signStr;
156 | }
157 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
158 | {
159 | $buff = "";
160 | ksort($paraMap);
161 | foreach ($paraMap as $k => $v) {
162 | if (null != $v && "null" != $v) {
163 | if ($urlEncode) {
164 | $v = urlencode($v);
165 | }
166 | $buff .= $k . "=" . $v . "&";
167 | }
168 | }
169 | $reqPar = '';
170 | if (strlen($buff) > 0) {
171 | $reqPar = substr($buff, 0, strlen($buff) - 1);
172 | }
173 | return $reqPar;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/redpack.php:
--------------------------------------------------------------------------------
1 | 账户设置->API安全->下载证书
5 | * 2.默认的使用场景是抽奖(即scene_id参数为PRODUCT_2),额度是1-200元,所以测试时的最低金额是1元。如需修改在产品中心->产品大全->现金红包->产品设置中修改
6 | * 3.错误码参照 :https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
7 | */
8 | header('Content-type:text/html; Charset=utf-8');
9 | $mchid = 'xxxxx'; //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
10 | $appid = 'xxxxx'; //微信支付申请对应的公众号的APPID
11 | $appKey = 'xxxxx'; //微信支付申请对应的公众号的APP Key
12 | $apiKey = 'xxxxx'; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
13 | //填写证书所在位置,证书在https://pay.weixin.qq.com 账户中心->账户设置->API安全->下载证书,下载后将apiclient_cert.pem和apiclient_key.pem上传到服务器。
14 | $apiclient_cert = getcwd().'/cert/apiclient_cert.pem';
15 | $apiclient_key = getcwd().'/cert/apiclient_key.pem';
16 |
17 | //①、获取当前访问页面的用户openid(如果给指定用户发送红包,则填写指定用户的openid)
18 | $wxPay = new WxpayService($mchid,$appid,$appKey,$apiKey,$apiclient_cert,$apiclient_key);
19 | $openId = $wxPay->GetOpenid(); //获取openid
20 | if(!$openId) exit('获取openid失败');
21 | //②、发送红包
22 | $outTradeNo = uniqid(); //你自己的商品订单号
23 | $payAmount = 1; //红包金额,单位:元
24 | $sendName = '元旦'; //红包发送者名称
25 | $wishing = '祝您元旦快乐!'; //红包祝福语
26 | $act_name='元旦快乐'; //活动名称
27 | $result = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$sendName,$wishing,$act_name);
28 | echo 'success';
29 | class WxpayService
30 | {
31 | protected $mchid;
32 | protected $appid;
33 | protected $appKey;
34 | protected $apiKey;
35 | protected $apiclient_cert;
36 | protected $apiclient_key;
37 | public $data = null;
38 |
39 | public function __construct($mchid, $appid, $appKey,$key,$apiclient_cert,$apiclient_key)
40 | {
41 | $this->mchid = $mchid;
42 | $this->appid = $appid;
43 | $this->appKey = $appKey;
44 | $this->apiKey = $key;
45 | $this->apiclient_cert = $apiclient_cert;
46 | $this->apiclient_key = $apiclient_key;
47 | }
48 |
49 | /**
50 | * 通过跳转获取用户的openid,跳转流程如下:
51 | * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
52 | * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
53 | * @return 用户的openid
54 | */
55 | public function GetOpenid()
56 | {
57 | //通过code获得openid
58 | if (!isset($_GET['code'])){
59 | //触发微信返回code码
60 | $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
61 | $uri = $_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING'];
62 | if($_SERVER['REQUEST_URI']){
63 | $uri = $_SERVER['REQUEST_URI'];
64 | }
65 | $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$uri);
66 | $url = $this->__CreateOauthUrlForCode($baseUrl);
67 | Header("Location: $url");
68 | exit();
69 | } else {
70 | //获取code码,以获取openid
71 | $code = $_GET['code'];
72 | $openid = $this->getOpenidFromMp($code);
73 | return $openid;
74 | }
75 | }
76 |
77 | /**
78 | * 通过code从工作平台获取openid机器access_token
79 | * @param string $code 微信跳转回来带上的code
80 | * @return openid
81 | */
82 | public function GetOpenidFromMp($code)
83 | {
84 | $url = $this->__CreateOauthUrlForOpenid($code);
85 | $res = self::curlGet($url);
86 | //取出openid
87 | $data = json_decode($res,true);
88 | $this->data = $data;
89 | $openid = $data['openid'];
90 | return $openid;
91 | }
92 |
93 | /**
94 | * 构造获取open和access_toke的url地址
95 | * @param string $code,微信跳转带回的code
96 | * @return 请求的url
97 | */
98 | private function __CreateOauthUrlForOpenid($code)
99 | {
100 | $urlObj["appid"] = $this->appid;
101 | $urlObj["secret"] = $this->appKey;
102 | $urlObj["code"] = $code;
103 | $urlObj["grant_type"] = "authorization_code";
104 | $bizString = $this->ToUrlParams($urlObj);
105 | return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
106 | }
107 |
108 | /**
109 | * 构造获取code的url连接
110 | * @param string $redirectUrl 微信服务器回跳的url,需要url编码
111 | * @return 返回构造好的url
112 | */
113 | private function __CreateOauthUrlForCode($redirectUrl)
114 | {
115 | $urlObj["appid"] = $this->appid;
116 | $urlObj["redirect_uri"] = "$redirectUrl";
117 | $urlObj["response_type"] = "code";
118 | $urlObj["scope"] = "snsapi_base";
119 | $urlObj["state"] = "STATE"."#wechat_redirect";
120 | $bizString = $this->ToUrlParams($urlObj);
121 | return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
122 | }
123 |
124 | /**
125 | * 拼接签名字符串
126 | * @param array $urlObj
127 | * @return 返回已经拼接好的字符串
128 | */
129 | private function ToUrlParams($urlObj)
130 | {
131 | $buff = "";
132 | foreach ($urlObj as $k => $v)
133 | {
134 | if($k != "sign") $buff .= $k . "=" . $v . "&";
135 | }
136 | $buff = trim($buff, "&");
137 | return $buff;
138 | }
139 |
140 | /**
141 | * 统一下单
142 | * @param string $openid 调用【网页授权获取用户信息】接口获取到用户在该公众号下的Openid
143 | * @param float $totalFee 收款总费用 单位元
144 | * @param string $outTradeNo 唯一的订单号
145 | * @param string $orderName 订单名称
146 | * @param string $notifyUrl 支付结果通知url 不要有问号
147 | * @param string $timestamp 支付时间
148 | * @return string
149 | */
150 | public function createJsBizPackage($openid, $totalFee, $outTradeNo, $sendName,$wishing,$actName)
151 | {
152 | $config = array(
153 | 'mch_id' => $this->mchid,
154 | 'appid' => $this->appid,
155 | 'key' => $this->apiKey,
156 | );
157 | $unified = array(
158 | 'wxappid' => $config['appid'],
159 | 'send_name' => $sendName,
160 | 'mch_id' => $config['mch_id'],
161 | 'nonce_str' => self::createNonceStr(),
162 | 're_openid' => $openid,
163 | 'mch_billno' => $outTradeNo,
164 | 'client_ip' => '127.0.0.1',
165 | 'total_amount' => floatval($totalFee) * 100, //单位 转为分
166 | 'total_num'=>1, //红包发放总人数
167 | 'wishing'=>$wishing, //红包祝福语
168 | 'act_name'=>$actName, //活动名称
169 | 'remark'=>'remark', //备注信息,如为中文注意转为UTF8编码
170 | 'scene_id'=>'PRODUCT_2', //发放红包使用场景,红包金额大于200时必传。https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
171 | );
172 | $unified['sign'] = self::getSign($unified, $config['key']);
173 | $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack', self::arrayToXml($unified));
174 | file_put_contents('1.txt',print_r($responseXml,true));
175 | // print_r($responseXml,true);die;
176 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
177 | if ($unifiedOrder === false) {
178 | die('parse xml error');
179 | }
180 | if ($unifiedOrder->return_code != 'SUCCESS') {
181 | die($unifiedOrder->return_msg);
182 | }
183 | if ($unifiedOrder->result_code != 'SUCCESS') {
184 | die($unifiedOrder->err_code);
185 | }
186 | return true;
187 | }
188 |
189 | public static function curlGet($url = '', $options = array())
190 | {
191 | $ch = curl_init($url);
192 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
193 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
194 | if (!empty($options)) {
195 | curl_setopt_array($ch, $options);
196 | }
197 | //https请求 不验证证书和host
198 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
199 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
200 | $data = curl_exec($ch);
201 | curl_close($ch);
202 | return $data;
203 | }
204 |
205 | public function curlPost($url = '', $postData = '', $options = array())
206 | {
207 | if (is_array($postData)) {
208 | $postData = http_build_query($postData);
209 | }
210 | $ch = curl_init();
211 | curl_setopt($ch, CURLOPT_URL, $url);
212 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
213 | curl_setopt($ch, CURLOPT_POST, 1);
214 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
215 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
216 | if (!empty($options)) {
217 | curl_setopt_array($ch, $options);
218 | }
219 | //https请求 不验证证书和host
220 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
221 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
222 |
223 | //第一种方法,cert 与 key 分别属于两个.pem文件
224 | //默认格式为PEM,可以注释
225 | curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
226 | curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/cert/apiclient_cert.pem');
227 | //默认格式为PEM,可以注释
228 | curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
229 | curl_setopt($ch,CURLOPT_SSLKEY,getcwd().'/cert/apiclient_key.pem');
230 | //第二种方式,两个文件合成一个.pem文件
231 | // curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
232 |
233 | $data = curl_exec($ch);
234 | var_dump($data);die;
235 | curl_close($ch);
236 | return $data;
237 | }
238 |
239 | public static function createNonceStr($length = 16)
240 | {
241 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
242 | $str = '';
243 | for ($i = 0; $i < $length; $i++) {
244 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
245 | }
246 | return $str;
247 | }
248 | public static function arrayToXml($arr)
249 | {
250 | $xml = "";
251 | foreach ($arr as $key => $val) {
252 | if (is_numeric($val)) {
253 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
254 | } else
255 | $xml .= "<" . $key . ">" . $key . ">";
256 | }
257 | $xml .= "";
258 | file_put_contents('1.txt',$xml);
259 | return $xml;
260 | }
261 |
262 | public static function getSign($params, $key)
263 | {
264 | ksort($params, SORT_STRING);
265 | $unSignParaString = self::formatQueryParaMap($params, false);
266 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
267 | return $signStr;
268 | }
269 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
270 | {
271 | $buff = "";
272 | ksort($paraMap);
273 | foreach ($paraMap as $k => $v) {
274 | if (null != $v && "null" != $v) {
275 | if ($urlEncode) {
276 | $v = urlencode($v);
277 | }
278 | $buff .= $k . "=" . $v . "&";
279 | }
280 | }
281 | $reqPar = '';
282 | if (strlen($buff) > 0) {
283 | $reqPar = substr($buff, 0, strlen($buff) - 1);
284 | }
285 | return $reqPar;
286 | }
287 | }
288 | ?>
289 |
--------------------------------------------------------------------------------
/refund.php:
--------------------------------------------------------------------------------
1 | 账户设置->API安全->下载证书,证书路径在第119行和122行修改
5 | * 2.错误码参照 :https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
6 | */
7 | header('Content-type:text/html; Charset=utf-8');
8 | $mchid = 'xxxxx'; //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
9 | $appid = 'xxxxx'; //微信支付申请对应的公众号的APPID
10 | $apiKey = 'xxxxx'; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
11 | $orderNo = ''; //商户订单号(商户订单号与微信订单号二选一,至少填一个)
12 | $wxOrderNo = ''; //微信订单号(商户订单号与微信订单号二选一,至少填一个)
13 | $totalFee = 0.01; //订单金额,单位:元
14 | $refundFee = 0.01; //退款金额,单位:元
15 | $refundNo = 'refund_'.uniqid(); //退款订单号(可随机生成)
16 | $wxPay = new WxpayService($mchid,$appid,$apiKey);
17 | $result = $wxPay->doRefund($totalFee, $refundFee, $refundNo, $wxOrderNo,$orderNo);
18 | if($result===true){
19 | echo 'refund success';exit();
20 | }
21 | echo 'refund fail';
22 |
23 | class WxpayService
24 | {
25 | protected $mchid;
26 | protected $appid;
27 | protected $apiKey;
28 | public $data = null;
29 |
30 | public function __construct($mchid, $appid, $key)
31 | {
32 | $this->mchid = $mchid; //https://pay.weixin.qq.com 产品中心-开发配置-商户号
33 | $this->appid = $appid; //微信支付申请对应的公众号的APPID
34 | $this->apiKey = $key; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
35 | }
36 |
37 | /**
38 | * 退款
39 | * @param float $totalFee 订单金额 单位元
40 | * @param float $refundFee 退款金额 单位元
41 | * @param string $refundNo 退款单号
42 | * @param string $wxOrderNo 微信订单号
43 | * @param string $orderNo 商户订单号
44 | * @return string
45 | */
46 | public function doRefund($totalFee, $refundFee, $refundNo, $wxOrderNo='',$orderNo='')
47 | {
48 | $config = array(
49 | 'mch_id' => $this->mchid,
50 | 'appid' => $this->appid,
51 | 'key' => $this->apiKey,
52 | );
53 | $unified = array(
54 | 'appid' => $config['appid'],
55 | 'mch_id' => $config['mch_id'],
56 | 'nonce_str' => self::createNonceStr(),
57 | 'total_fee' => floatval($totalFee) * 100, //订单金额 单位 转为分
58 | 'refund_fee' => floatval($refundFee) * 100, //退款金额 单位 转为分
59 | 'sign_type' => 'MD5', //签名类型 支持HMAC-SHA256和MD5,默认为MD5
60 | 'transaction_id'=>$wxOrderNo, //微信订单号
61 | 'out_trade_no'=>$orderNo, //商户订单号
62 | 'out_refund_no'=>$refundNo, //商户退款单号
63 | 'refund_desc'=>'商品已售完', //退款原因(选填)
64 | );
65 | $unified['sign'] = self::getSign($unified, $config['key']);
66 | $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/secapi/pay/refund', self::arrayToXml($unified));
67 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
68 | if ($unifiedOrder === false) {
69 | die('parse xml error');
70 | }
71 | if ($unifiedOrder->return_code != 'SUCCESS') {
72 | die($unifiedOrder->return_msg);
73 | }
74 | if ($unifiedOrder->result_code != 'SUCCESS') {
75 | die($unifiedOrder->err_code);
76 | }
77 | return true;
78 | }
79 |
80 | public static function curlGet($url = '', $options = array())
81 | {
82 | $ch = curl_init($url);
83 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
84 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
85 | if (!empty($options)) {
86 | curl_setopt_array($ch, $options);
87 | }
88 | //https请求 不验证证书和host
89 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
90 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
91 | $data = curl_exec($ch);
92 | curl_close($ch);
93 | return $data;
94 | }
95 |
96 | public function curlPost($url = '', $postData = '', $options = array())
97 | {
98 | if (is_array($postData)) {
99 | $postData = http_build_query($postData);
100 | }
101 | $ch = curl_init();
102 | curl_setopt($ch, CURLOPT_URL, $url);
103 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
104 | curl_setopt($ch, CURLOPT_POST, 1);
105 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
106 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
107 | if (!empty($options)) {
108 | curl_setopt_array($ch, $options);
109 | }
110 | //https请求 不验证证书和host
111 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
112 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
113 |
114 | //第一种方法,cert 与 key 分别属于两个.pem文件
115 | //默认格式为PEM,可以注释
116 | curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
117 | curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/cert/apiclient_cert.pem');
118 | //默认格式为PEM,可以注释
119 | curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
120 | curl_setopt($ch,CURLOPT_SSLKEY,getcwd().'/cert/apiclient_key.pem');
121 | //第二种方式,两个文件合成一个.pem文件
122 | // curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
123 | $data = curl_exec($ch);
124 | curl_close($ch);
125 | return $data;
126 | }
127 |
128 | public static function createNonceStr($length = 16)
129 | {
130 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
131 | $str = '';
132 | for ($i = 0; $i < $length; $i++) {
133 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
134 | }
135 | return $str;
136 | }
137 | public static function arrayToXml($arr)
138 | {
139 | $xml = "";
140 | foreach ($arr as $key => $val) {
141 | if (is_numeric($val)) {
142 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
143 | } else
144 | $xml .= "<" . $key . ">" . $key . ">";
145 | }
146 | $xml .= "";
147 | return $xml;
148 | }
149 |
150 | public static function getSign($params, $key)
151 | {
152 | ksort($params, SORT_STRING);
153 | $unSignParaString = self::formatQueryParaMap($params, false);
154 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
155 | return $signStr;
156 | }
157 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
158 | {
159 | $buff = "";
160 | ksort($paraMap);
161 | foreach ($paraMap as $k => $v) {
162 | if (null != $v && "null" != $v) {
163 | if ($urlEncode) {
164 | $v = urlencode($v);
165 | }
166 | $buff .= $k . "=" . $v . "&";
167 | }
168 | }
169 | $reqPar = '';
170 | if (strlen($buff) > 0) {
171 | $reqPar = substr($buff, 0, strlen($buff) - 1);
172 | }
173 | return $reqPar;
174 | }
175 | }
176 | ?>
177 |
--------------------------------------------------------------------------------
/refund_query.php:
--------------------------------------------------------------------------------
1 | 商户退款订单号 > 微信订单号 > 商户订单号
8 | $orderNo = ''; //商户订单号
9 | $wxOrderNo = ''; //微信订单号
10 | $refundNo=''; //商户退款订单号
11 | $refundId = ''; //微信退款单号(微信生成的退款单号,在申请退款接口有返回)
12 |
13 | $wxPay = new WxpayService($mchid,$appid,$apiKey);
14 | $result = $wxPay->doRefundQuery($refundNo, $wxOrderNo,$orderNo,$refundId);
15 | if($result===true){
16 | echo 'refund success';exit();
17 | }
18 | echo 'refund fail';
19 |
20 | class WxpayService
21 | {
22 | protected $mchid;
23 | protected $appid;
24 | protected $apiKey;
25 | public $data = null;
26 |
27 | public function __construct($mchid, $appid, $key)
28 | {
29 | $this->mchid = $mchid; //https://pay.weixin.qq.com 产品中心-开发配置-商户号
30 | $this->appid = $appid; //微信支付申请对应的公众号的APPID
31 | $this->apiKey = $key; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
32 | }
33 |
34 | /**
35 | * 退款查询
36 | * @param string $refundNo 商户退款单号
37 | * @param string $wxOrderNo 微信订单号
38 | * @param string $orderNo 商户订单号
39 | * @param string $refundId 微信退款单号
40 | * @return string
41 | */
42 | public function doRefundQuery($refundNo='', $wxOrderNo='',$orderNo='',$refundId='')
43 | {
44 | $config = array(
45 | 'mch_id' => $this->mchid,
46 | 'appid' => $this->appid,
47 | 'key' => $this->apiKey,
48 | );
49 | $unified = array(
50 | 'appid' => $config['appid'],
51 | 'mch_id' => $config['mch_id'],
52 | 'nonce_str' => self::createNonceStr(),
53 | 'sign_type' => 'MD5', //签名类型 支持HMAC-SHA256和MD5,默认为MD5
54 | 'transaction_id'=>$wxOrderNo, //微信订单号
55 | 'out_trade_no'=>$orderNo, //商户订单号
56 | 'out_refund_no'=>$refundNo, //商户退款单号
57 | 'refund_id'=>$refundId, //微信退款单号
58 | );
59 | $unified['sign'] = self::getSign($unified, $config['key']);
60 | $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/pay/refundquery', self::arrayToXml($unified));
61 | file_put_contents('2.txt',$responseXml);
62 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
63 | if ($unifiedOrder === false) {
64 | die('parse xml error');
65 | }
66 | if ($unifiedOrder->return_code != 'SUCCESS') {
67 | die($unifiedOrder->return_msg);
68 | }
69 | if ($unifiedOrder->result_code != 'SUCCESS') {
70 | die($unifiedOrder->err_code);
71 | }
72 | return true;
73 | }
74 |
75 | public static function curlGet($url = '', $options = array())
76 | {
77 | $ch = curl_init($url);
78 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
79 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
80 | if (!empty($options)) {
81 | curl_setopt_array($ch, $options);
82 | }
83 | //https请求 不验证证书和host
84 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
85 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
86 | $data = curl_exec($ch);
87 | curl_close($ch);
88 | return $data;
89 | }
90 |
91 | public function curlPost($url = '', $postData = '', $options = array())
92 | {
93 | if (is_array($postData)) {
94 | $postData = http_build_query($postData);
95 | }
96 | $ch = curl_init();
97 | curl_setopt($ch, CURLOPT_URL, $url);
98 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
99 | curl_setopt($ch, CURLOPT_POST, 1);
100 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
101 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
102 | if (!empty($options)) {
103 | curl_setopt_array($ch, $options);
104 | }
105 | //https请求 不验证证书和host
106 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
107 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
108 | $data = curl_exec($ch);
109 | curl_close($ch);
110 | return $data;
111 | }
112 |
113 | public static function createNonceStr($length = 16)
114 | {
115 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
116 | $str = '';
117 | for ($i = 0; $i < $length; $i++) {
118 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
119 | }
120 | return $str;
121 | }
122 | public static function arrayToXml($arr)
123 | {
124 | $xml = "";
125 | foreach ($arr as $key => $val) {
126 | if (is_numeric($val)) {
127 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
128 | } else
129 | $xml .= "<" . $key . ">" . $key . ">";
130 | }
131 | $xml .= "";
132 | return $xml;
133 | }
134 |
135 | public static function getSign($params, $key)
136 | {
137 | ksort($params, SORT_STRING);
138 | $unSignParaString = self::formatQueryParaMap($params, false);
139 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
140 | return $signStr;
141 | }
142 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
143 | {
144 | $buff = "";
145 | ksort($paraMap);
146 | foreach ($paraMap as $k => $v) {
147 | if (null != $v && "null" != $v) {
148 | if ($urlEncode) {
149 | $v = urlencode($v);
150 | }
151 | $buff .= $k . "=" . $v . "&";
152 | }
153 | }
154 | $reqPar = '';
155 | if (strlen($buff) > 0) {
156 | $reqPar = substr($buff, 0, strlen($buff) - 1);
157 | }
158 | return $reqPar;
159 | }
160 | }
161 | ?>
--------------------------------------------------------------------------------
/reverse.php:
--------------------------------------------------------------------------------
1 | 账户设置->API安全->下载证书
7 | * 2.错误码参照 :https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
8 | */
9 | header('Content-type:text/html; Charset=utf-8');
10 | /* 配置开始 */
11 | $mchid = ''; //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
12 | $appid = ''; //微信支付申请对应的公众号的APPID
13 | $appKey = ''; //微信支付申请对应的公众号的APP Key
14 | $apiKey = ''; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
15 | //填写证书所在位置,证书在https://pay.weixin.qq.com 账户中心->账户设置->API安全->下载证书,下载后将apiclient_cert.pem和apiclient_key.pem上传到服务器。
16 | $apiclient_cert = getcwd().'/cert/apiclient_cert.pem';
17 | $apiclient_key = getcwd().'/cert/apiclient_key.pem';
18 | $transaction_id = ''; //微信的订单号,优先使用。微信订单号与商户订单号不能同时为空
19 | $out_trade_no = ''; //商户订单号。微信订单号与商户订单号不能同时为空
20 | /* 配置结束 */
21 | $wxPay = new WxpayService($mchid,$appid,$appKey,$apiKey);
22 | $wxPay->setApiclientCert($apiclient_cert);
23 | $wxPay->setApiclientKey($apiclient_key);
24 | $wxPay->setTransactionId($transaction_id);
25 | $wxPay->setOutTradeNo($out_trade_no);
26 | $result = $wxPay->doReverse();
27 | echo 'success';
28 | class WxpayService
29 | {
30 | protected $mchid;
31 | protected $appid;
32 | protected $appKey;
33 | protected $apiKey;
34 | protected $apiclient_cert;
35 | protected $apiclient_key;
36 | protected $transactionId;
37 | protected $outTradeNo;
38 | public $data = null;
39 |
40 | public function __construct($mchid, $appid, $appKey,$key)
41 | {
42 | $this->mchid = $mchid;
43 | $this->appid = $appid;
44 | $this->appKey = $appKey;
45 | $this->apiKey = $key;
46 | }
47 |
48 | public function setApiclientCert($apiclient_cert)
49 | {
50 | $this->apiclient_cert = $apiclient_cert;
51 | }
52 |
53 | public function setApiclientKey($apiclient_key)
54 | {
55 | $this->apiclient_key = $apiclient_key;
56 | }
57 |
58 | public function setTransactionId($transaction_id)
59 | {
60 | $this->transactionId = $transaction_id;
61 | }
62 |
63 | public function setOutTradeNo($out_trade_no)
64 | {
65 | $this->outTradeNo = $out_trade_no;
66 | }
67 |
68 | /**
69 | * 撤销订单
70 | */
71 | public function doReverse()
72 | {
73 | $unified = array(
74 | 'mch_id' => $this->mchid,
75 | 'appid' => $this->appid,
76 | 'transaction_id' => $this->transactionId,
77 | 'out_trade_no' => $this->outTradeNo,
78 | 'nonce_str' => self::createNonceStr(),
79 | );
80 | $unified['sign'] = self::getSign($unified, $this->apiKey);
81 | $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/secapi/pay/reverse', self::arrayToXml($unified));
82 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
83 | if ($unifiedOrder === false) {
84 | die('parse xml error');
85 | }
86 | if ($unifiedOrder->return_code != 'SUCCESS') {
87 | die($unifiedOrder->return_msg);
88 | }
89 | if ($unifiedOrder->result_code != 'SUCCESS') {
90 | die($unifiedOrder->err_code.':'.$unifiedOrder->err_code_des);
91 | }
92 |
93 | return true;
94 | }
95 |
96 | public static function curlGet($url = '', $options = array())
97 | {
98 | $ch = curl_init($url);
99 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
100 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
101 | if (!empty($options)) {
102 | curl_setopt_array($ch, $options);
103 | }
104 | //https请求 不验证证书和host
105 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
106 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
107 | $data = curl_exec($ch);
108 | curl_close($ch);
109 | return $data;
110 | }
111 |
112 | public function curlPost($url = '', $postData = '', $options = array())
113 | {
114 | if (is_array($postData)) {
115 | $postData = http_build_query($postData);
116 | }
117 | $ch = curl_init();
118 | curl_setopt($ch, CURLOPT_URL, $url);
119 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
120 | curl_setopt($ch, CURLOPT_POST, 1);
121 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
122 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
123 | if (!empty($options)) {
124 | curl_setopt_array($ch, $options);
125 | }
126 | //https请求 不验证证书和host
127 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
128 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
129 |
130 | //第一种方法,cert 与 key 分别属于两个.pem文件
131 | //默认格式为PEM,可以注释
132 | curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
133 | curl_setopt($ch,CURLOPT_SSLCERT,$this->apiclient_cert);
134 | //默认格式为PEM,可以注释
135 | curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
136 | curl_setopt($ch,CURLOPT_SSLKEY,$this->apiclient_key);
137 | //第二种方式,两个文件合成一个.pem文件
138 | // curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
139 |
140 | $data = curl_exec($ch);
141 | //var_dump($data);die;
142 | curl_close($ch);
143 | return $data;
144 | }
145 |
146 | public static function createNonceStr($length = 16)
147 | {
148 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
149 | $str = '';
150 | for ($i = 0; $i < $length; $i++) {
151 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
152 | }
153 | return $str;
154 | }
155 | public static function arrayToXml($arr)
156 | {
157 | $xml = "";
158 | foreach ($arr as $key => $val) {
159 | if (is_numeric($val)) {
160 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
161 | } else
162 | $xml .= "<" . $key . ">" . $key . ">";
163 | }
164 | $xml .= "";
165 | file_put_contents('1.txt',$xml);
166 | return $xml;
167 | }
168 |
169 | public static function getSign($params, $key)
170 | {
171 | ksort($params, SORT_STRING);
172 | $unSignParaString = self::formatQueryParaMap($params, false);
173 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
174 | return $signStr;
175 | }
176 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
177 | {
178 | $buff = "";
179 | ksort($paraMap);
180 | foreach ($paraMap as $k => $v) {
181 | if (null != $v && "null" != $v) {
182 | if ($urlEncode) {
183 | $v = urlencode($v);
184 | }
185 | $buff .= $k . "=" . $v . "&";
186 | }
187 | }
188 | $reqPar = '';
189 | if (strlen($buff) > 0) {
190 | $reqPar = substr($buff, 0, strlen($buff) - 1);
191 | }
192 | return $reqPar;
193 | }
194 | }
195 | ?>
--------------------------------------------------------------------------------
/transfers.php:
--------------------------------------------------------------------------------
1 | 账户设置->API安全->下载证书,证书路径在第207行和210行修改
5 | * 2.错误码参照 :https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
6 | */
7 | header('Content-type:text/html; Charset=utf-8');
8 | $mchid = 'xxxxx'; //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
9 | $appid = 'xxxxx'; //微信支付申请对应的公众号的APPID
10 | $appKey = 'xxxxx'; //微信支付申请对应的公众号的APP Key
11 | $apiKey = 'xxxxx'; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
12 |
13 | //①、获取当前访问页面的用户openid(如果给指定用户转账,则直接填写指定用户的openid)
14 | $wxPay = new WxpayService($mchid,$appid,$appKey,$apiKey);
15 | $openId = $wxPay->GetOpenid(); //获取openid
16 | if(!$openId) exit('获取openid失败');
17 | //②、付款
18 | $outTradeNo = uniqid(); //订单号
19 | $payAmount = 1; //转账金额,单位:元。转账最小金额为1元
20 | $trueName = '张三'; //收款人真实姓名
21 | $result = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$trueName);
22 | echo 'success';
23 | class WxpayService
24 | {
25 | protected $mchid;
26 | protected $appid;
27 | protected $appKey;
28 | protected $apiKey;
29 | public $data = null;
30 |
31 | public function __construct($mchid, $appid, $appKey,$key)
32 | {
33 | $this->mchid = $mchid;
34 | $this->appid = $appid;
35 | $this->appKey = $appKey;
36 | $this->apiKey = $key;
37 | }
38 |
39 | /**
40 | * 通过跳转获取用户的openid,跳转流程如下:
41 | * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
42 | * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
43 | * @return 用户的openid
44 | */
45 | public function GetOpenid()
46 | {
47 | //通过code获得openid
48 | if (!isset($_GET['code'])){
49 | //触发微信返回code码
50 | $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
51 | $uri = $_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING'];
52 | if($_SERVER['REQUEST_URI']){
53 | $uri = $_SERVER['REQUEST_URI'];
54 | }
55 | $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$uri);
56 | $url = $this->__CreateOauthUrlForCode($baseUrl);
57 | Header("Location: $url");
58 | exit();
59 | } else {
60 | //获取code码,以获取openid
61 | $code = $_GET['code'];
62 | $openid = $this->getOpenidFromMp($code);
63 | return $openid;
64 | }
65 | }
66 |
67 | /**
68 | * 通过code从工作平台获取openid机器access_token
69 | * @param string $code 微信跳转回来带上的code
70 | * @return openid
71 | */
72 | public function GetOpenidFromMp($code)
73 | {
74 | $url = $this->__CreateOauthUrlForOpenid($code);
75 | $res = self::curlGet($url);
76 | //取出openid
77 | $data = json_decode($res,true);
78 | $this->data = $data;
79 | $openid = $data['openid'];
80 | return $openid;
81 | }
82 |
83 | /**
84 | * 构造获取open和access_toke的url地址
85 | * @param string $code,微信跳转带回的code
86 | * @return 请求的url
87 | */
88 | private function __CreateOauthUrlForOpenid($code)
89 | {
90 | $urlObj["appid"] = $this->appid;
91 | $urlObj["secret"] = $this->appKey;
92 | $urlObj["code"] = $code;
93 | $urlObj["grant_type"] = "authorization_code";
94 | $bizString = $this->ToUrlParams($urlObj);
95 | return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
96 | }
97 |
98 | /**
99 | * 构造获取code的url连接
100 | * @param string $redirectUrl 微信服务器回跳的url,需要url编码
101 | * @return 返回构造好的url
102 | */
103 | private function __CreateOauthUrlForCode($redirectUrl)
104 | {
105 | $urlObj["appid"] = $this->appid;
106 | $urlObj["redirect_uri"] = "$redirectUrl";
107 | $urlObj["response_type"] = "code";
108 | $urlObj["scope"] = "snsapi_base";
109 | $urlObj["state"] = "STATE"."#wechat_redirect";
110 | $bizString = $this->ToUrlParams($urlObj);
111 | return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
112 | }
113 |
114 | /**
115 | * 拼接签名字符串
116 | * @param array $urlObj
117 | * @return 返回已经拼接好的字符串
118 | */
119 | private function ToUrlParams($urlObj)
120 | {
121 | $buff = "";
122 | foreach ($urlObj as $k => $v)
123 | {
124 | if($k != "sign") $buff .= $k . "=" . $v . "&";
125 | }
126 | $buff = trim($buff, "&");
127 | return $buff;
128 | }
129 |
130 | /**
131 | * 企业付款
132 | * @param string $openid 调用【网页授权获取用户信息】接口获取到用户在该公众号下的Openid
133 | * @param float $totalFee 收款总费用 单位元
134 | * @param string $outTradeNo 唯一的订单号
135 | * @param string $orderName 订单名称
136 | * @param string $notifyUrl 支付结果通知url 不要有问号
137 | * @param string $timestamp 支付时间
138 | * @return string
139 | */
140 | public function createJsBizPackage($openid, $totalFee, $outTradeNo,$trueName)
141 | {
142 | $config = array(
143 | 'mch_id' => $this->mchid,
144 | 'appid' => $this->appid,
145 | 'key' => $this->apiKey,
146 | );
147 | $unified = array(
148 | 'mch_appid' => $config['appid'],
149 | 'mchid' => $config['mch_id'],
150 | 'nonce_str' => self::createNonceStr(),
151 | 'openid' => $openid,
152 | 'check_name'=>'FORCE_CHECK', //校验用户姓名选项。NO_CHECK:不校验真实姓名,FORCE_CHECK:强校验真实姓名
153 | 're_user_name'=>$trueName, //收款用户真实姓名(不支持给非实名用户打款)
154 | 'partner_trade_no' => $outTradeNo,
155 | 'spbill_create_ip' => '127.0.0.1',
156 | 'amount' => floatval($totalFee) * 100, //单位 转为分
157 | 'desc'=>'付款', //企业付款操作说明信息
158 | );
159 | $unified['sign'] = self::getSign($unified, $config['key']);
160 | $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', self::arrayToXml($unified));
161 | $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
162 | if ($unifiedOrder === false) {
163 | die('parse xml error');
164 | }
165 | if ($unifiedOrder->return_code != 'SUCCESS') {
166 | die($unifiedOrder->return_msg);
167 | }
168 | if ($unifiedOrder->result_code != 'SUCCESS') {
169 | die($unifiedOrder->err_code);
170 | }
171 | return true;
172 | }
173 |
174 | public static function curlGet($url = '', $options = array())
175 | {
176 | $ch = curl_init($url);
177 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
178 | curl_setopt($ch, CURLOPT_TIMEOUT, 30);
179 | if (!empty($options)) {
180 | curl_setopt_array($ch, $options);
181 | }
182 | //https请求 不验证证书和host
183 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
184 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
185 | $data = curl_exec($ch);
186 | curl_close($ch);
187 | return $data;
188 | }
189 |
190 | public function curlPost($url = '', $postData = '', $options = array())
191 | {
192 | if (is_array($postData)) {
193 | $postData = http_build_query($postData);
194 | }
195 | $ch = curl_init();
196 | curl_setopt($ch, CURLOPT_URL, $url);
197 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
198 | curl_setopt($ch, CURLOPT_POST, 1);
199 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
200 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
201 | if (!empty($options)) {
202 | curl_setopt_array($ch, $options);
203 | }
204 | //https请求 不验证证书和host
205 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
206 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
207 |
208 | //第一种方法,cert 与 key 分别属于两个.pem文件
209 | //默认格式为PEM,可以注释
210 | curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
211 | curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/cert/apiclient_cert.pem');
212 | //默认格式为PEM,可以注释
213 | curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
214 | curl_setopt($ch,CURLOPT_SSLKEY,getcwd().'/cert/apiclient_key.pem');
215 | //第二种方式,两个文件合成一个.pem文件
216 | // curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
217 | $data = curl_exec($ch);
218 | if($data === false)
219 | {
220 | echo 'Curl error: ' . curl_error($ch);exit();
221 | }
222 | curl_close($ch);
223 | return $data;
224 | }
225 |
226 | public static function createNonceStr($length = 16)
227 | {
228 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
229 | $str = '';
230 | for ($i = 0; $i < $length; $i++) {
231 | $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
232 | }
233 | return $str;
234 | }
235 | public static function arrayToXml($arr)
236 | {
237 | $xml = "";
238 | foreach ($arr as $key => $val) {
239 | if (is_numeric($val)) {
240 | $xml .= "<" . $key . ">" . $val . "" . $key . ">";
241 | } else
242 | $xml .= "<" . $key . ">" . $key . ">";
243 | }
244 | $xml .= "";
245 | return $xml;
246 | }
247 |
248 | public static function getSign($params, $key)
249 | {
250 | ksort($params, SORT_STRING);
251 | $unSignParaString = self::formatQueryParaMap($params, false);
252 | $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
253 | return $signStr;
254 | }
255 | protected static function formatQueryParaMap($paraMap, $urlEncode = false)
256 | {
257 | $buff = "";
258 | ksort($paraMap);
259 | foreach ($paraMap as $k => $v) {
260 | if (null != $v && "null" != $v) {
261 | if ($urlEncode) {
262 | $v = urlencode($v);
263 | }
264 | $buff .= $k . "=" . $v . "&";
265 | }
266 | }
267 | $reqPar = '';
268 | if (strlen($buff) > 0) {
269 | $reqPar = substr($buff, 0, strlen($buff) - 1);
270 | }
271 | return $reqPar;
272 | }
273 | }
274 | ?>
275 |
--------------------------------------------------------------------------------