CI:3.0.5javascript
微信支付API類庫來自:https://github.com/zhangv/wechat-payphp
請先看一眼官方場景及支付時序圖:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5html
官方API列表:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1java
二維碼生成類庫:phpqrcodegit
走了幾天的彎路,直到遇到Lamtin指點(熱心網友),他說你既然是集成到CI爲什麼不本身寫,我想了想是啊,爲何我一直陷入官方sdk的漩渦裏不能跳出來去看這件事,官方提供了API接口,你只須要去調用這些接口啊,post參數啊,是吧,後悔浪費了3天時間。爲了避免讓大家和我同樣我把個人思路及代碼發佈出來,有什麼問題能夠留言。github
咱們爲何使用三方支付類庫?web
縱觀微信支付的sdk或者其餘的微信支付demo,或多或少的都是圍繞官方API接口來寫,增長些本身用的方法方便調用之類的,而若是我本身再去寫這樣的一個東西,第一可能組織很差,基礎弱啊,第二可能須要花費大量時間,鑑於此我去尋找比較好用的別人封裝的API類庫好了,終於不負所望,真有,只能夠這個類庫幾乎沒有人用,不過真不錯ajax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
class
WechatPay {
const
TRADETYPE_JSAPI =
'JSAPI'
,TRADETYPE_NATIVE =
'NATIVE'
,TRADETYPE_APP =
'APP'
;
const
URL_UNIFIEDORDER =
"https://api.mch.weixin.qq.com/pay/unifiedorder"
;
const
URL_ORDERQUERY =
"https://api.mch.weixin.qq.com/pay/orderquery"
;
const
URL_CLOSEORDER =
'https://api.mch.weixin.qq.com/pay/closeorder'
;
const
URL_REFUND =
'https://api.mch.weixin.qq.com/secapi/pay/refund'
;
const
URL_REFUNDQUERY =
'https://api.mch.weixin.qq.com/pay/refundquery'
;
const
URL_DOWNLOADBILL =
'https://api.mch.weixin.qq.com/pay/downloadbill'
;
const
URL_REPORT =
'https://api.mch.weixin.qq.com/payitil/report'
;
const
URL_SHORTURL =
'https://api.mch.weixin.qq.com/tools/shorturl'
;
const
URL_MICROPAY =
'https://api.mch.weixin.qq.com/pay/micropay'
;
/**
* 錯誤信息
*/
public
$error
= null;
/**
* 錯誤信息XML
*/
public
$errorXML
= null;
/**
* 微信支付配置數組
* appid 公衆帳號appid
* mch_id 商戶號
* apikey 加密key
* appsecret 公衆號appsecret
* sslcertPath 證書路徑(apiclient_cert.pem)
* sslkeyPath 密鑰路徑(apiclient_key.pem)
*/
private
$_config
;
/**
* @param $config 微信支付配置數組
*/
public
function
__construct(
$config
) {
$this
->_config =
$config
;
}
/**
* JSAPI獲取prepay_id
* @param $body
* @param $out_trade_no
* @param $total_fee
* @param $notify_url
* @param $openid
* @return null
*/
public
function
getPrepayId(
$body
,
$out_trade_no
,
$total_fee
,
$notify_url
,
$openid
) {
$data
=
array
();
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$data
[
"body"
] =
$body
;
$data
[
"out_trade_no"
] =
$out_trade_no
;
$data
[
"total_fee"
] =
$total_fee
;
$data
[
"spbill_create_ip"
] =
$_SERVER
[
"REMOTE_ADDR"
];
$data
[
"notify_url"
] =
$notify_url
;
$data
[
"trade_type"
] = self::TRADETYPE_JSAPI;
$data
[
"openid"
] =
$openid
;
$result
=
$this
->unifiedOrder(
$data
);
if
(
$result
[
"return_code"
] ==
"SUCCESS"
&&
$result
[
"result_code"
] ==
"SUCCESS"
) {
return
$result
[
"prepay_id"
];
}
else
{
$this
->error =
$result
[
"return_code"
] ==
"SUCCESS"
?
$result
[
"err_code_des"
] :
$result
[
"return_msg"
];
$this
->errorXML =
$this
->array2xml(
$result
);
return
null;
}
}
private
function
get_nonce_string() {
return
substr
(
str_shuffle
(
"abcdefghijklmnopqrstuvwxyz0123456789"
),0,32);
}
/**
* 統一下單接口
*/
public
function
unifiedOrder(
$params
) {
$data
=
array
();
$data
[
"appid"
] =
$this
->_config[
"appid"
];
$data
[
"mch_id"
] =
$this
->_config[
"mch_id"
];
$data
[
"device_info"
] = (isset(
$params
[
'device_info'
])&&trim(
$params
[
'device_info'
])!=
''
)?
$params
[
'device_info'
]:null;
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$data
[
"body"
] =
$params
[
'body'
];
$data
[
"detail"
] = isset(
$params
[
'detail'
])?
$params
[
'detail'
]:null;
//optional
$data
[
"attach"
] = isset(
$params
[
'attach'
])?
$params
[
'attach'
]:null;
//optional
$data
[
"out_trade_no"
] = isset(
$params
[
'out_trade_no'
])?
$params
[
'out_trade_no'
]:null;
$data
[
"fee_type"
] = isset(
$params
[
'fee_type'
])?
$params
[
'fee_type'
]:
'CNY'
;
$data
[
"total_fee"
] =
$params
[
'total_fee'
];
$data
[
"spbill_create_ip"
] =
$params
[
'spbill_create_ip'
];
$data
[
"time_start"
] = isset(
$params
[
'time_start'
])?
$params
[
'time_start'
]:null;
//optional
$data
[
"time_expire"
] = isset(
$params
[
'time_expire'
])?
$params
[
'time_expire'
]:null;
//optional
$data
[
"goods_tag"
] = isset(
$params
[
'goods_tag'
])?
$params
[
'goods_tag'
]:null;
$data
[
"notify_url"
] =
$params
[
'notify_url'
];
$data
[
"trade_type"
] =
$params
[
'trade_type'
];
$data
[
"product_id"
] = isset(
$params
[
'product_id'
])?
$params
[
'product_id'
]:null;
//required when trade_type = NATIVE
$data
[
"openid"
] = isset(
$params
[
'openid'
])?
$params
[
'openid'
]:null;
//required when trade_type = JSAPI
$result
=
$this
->post(self::URL_UNIFIEDORDER,
$data
);
return
$result
;
}
private
function
post(
$url
,
$data
,
$cert
= false) {
$data
[
"sign"
] =
$this
->sign(
$data
);
$xml
=
$this
->array2xml(
$data
);
$ch
= curl_init();
curl_setopt(
$ch
, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt(
$ch
, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt(
$ch
, CURLOPT_POST, 1);
curl_setopt(
$ch
, CURLOPT_POSTFIELDS,
$xml
);
curl_setopt(
$ch
, CURLOPT_RETURNTRANSFER, true);
curl_setopt(
$ch
, CURLOPT_URL,
$url
);
if
(
$cert
== true){
//使用證書:cert 與 key 分別屬於兩個.pem文件
curl_setopt(
$ch
,CURLOPT_SSLCERTTYPE,
'PEM'
);
curl_setopt(
$ch
,CURLOPT_SSLCERT,
$this
->_config[
'sslcertPath'
]);
curl_setopt(
$ch
,CURLOPT_SSLKEYTYPE,
'PEM'
);
curl_setopt(
$ch
,CURLOPT_SSLKEY,
$this
->_config[
'sslkeyPath'
]);
}
$content
= curl_exec(
$ch
);
$array
=
$this
->xml2array(
$content
);
return
$array
;
}
/**
* 數據簽名
* @param $data
* @return string
*/
private
function
sign(
$data
) {
ksort(
$data
);
$string1
=
""
;
foreach
(
$data
as
$k
=>
$v
) {
if
(
$v
&& trim(
$v
)!=
''
) {
$string1
.=
"$k=$v&"
;
}
}
$stringSignTemp
=
$string1
.
"key="
.
$this
->_config[
"apikey"
];
$sign
=
strtoupper
(md5(
$stringSignTemp
));
return
$sign
;
}
private
function
array2xml(
$array
) {
$xml
=
"<xml>"
. PHP_EOL;
foreach
(
$array
as
$k
=>
$v
) {
if
(
$v
&& trim(
$v
)!=
''
)
$xml
.=
"<$k><![CDATA[$v]]></$k>"
. PHP_EOL;
}
$xml
.=
"</xml>"
;
return
$xml
;
}
private
function
xml2array(
$xml
) {
$array
=
array
();
$tmp
= null;
try
{
$tmp
= (
array
) simplexml_load_string(
$xml
);
}
catch
(Exception
$e
){}
if
(
$tmp
&&
is_array
(
$tmp
)){
foreach
(
$tmp
as
$k
=>
$v
) {
$array
[
$k
] = (string)
$v
;
}
}
return
$array
;
}
/**
* 掃碼支付(模式二)獲取支付二維碼
* @param $body
* @param $out_trade_no
* @param $total_fee
* @param $notify_url
* @param $product_id
* @return null
*/
public
function
getCodeUrl(
$body
,
$out_trade_no
,
$total_fee
,
$notify_url
,
$product_id
){
$data
=
array
();
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$data
[
"body"
] =
$body
;
$data
[
"out_trade_no"
] =
$out_trade_no
;
$data
[
"total_fee"
] =
$total_fee
;
$data
[
"spbill_create_ip"
] =
$_SERVER
[
"SERVER_ADDR"
];
$data
[
"notify_url"
] =
$notify_url
;
$data
[
"trade_type"
] = self::TRADETYPE_NATIVE;
$data
[
"product_id"
] =
$product_id
;
$result
=
$this
->unifiedOrder(
$data
);
if
(
$result
[
"return_code"
] ==
"SUCCESS"
&&
$result
[
"result_code"
] ==
"SUCCESS"
) {
return
$result
[
"code_url"
];
}
else
{
$this
->error =
$result
[
"return_code"
] ==
"SUCCESS"
?
$result
[
"err_code_des"
] :
$result
[
"return_msg"
];
return
null;
}
}
/**
* 查詢訂單
* @param $transaction_id
* @param $out_trade_no
* @return array
*/
public
function
orderQuery(
$transaction_id
,
$out_trade_no
){
$data
=
array
();
$data
[
"appid"
] =
$this
->_config[
"appid"
];
$data
[
"mch_id"
] =
$this
->_config[
"mch_id"
];
$data
[
"transaction_id"
] =
$transaction_id
;
$data
[
"out_trade_no"
] =
$out_trade_no
;
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$result
=
$this
->post(self::URL_ORDERQUERY,
$data
);
return
$result
;
}
/**
* 關閉訂單
* @param $out_trade_no
* @return array
*/
public
function
closeOrder(
$out_trade_no
){
$data
=
array
();
$data
[
"appid"
] =
$this
->_config[
"appid"
];
$data
[
"mch_id"
] =
$this
->_config[
"mch_id"
];
$data
[
"out_trade_no"
] =
$out_trade_no
;
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$result
=
$this
->post(self::URL_CLOSEORDER,
$data
);
return
$result
;
}
/**
* 申請退款 - 使用商戶訂單號
* @param $out_trade_no 商戶訂單號
* @param $out_refund_no 退款單號
* @param $total_fee 總金額(單位:分)
* @param $refund_fee 退款金額(單位:分)
* @param $op_user_id 操做員帳號
* @return array
*/
public
function
refund(
$out_trade_no
,
$out_refund_no
,
$total_fee
,
$refund_fee
,
$op_user_id
){
$data
=
array
();
$data
[
"appid"
] =
$this
->_config[
"appid"
];
$data
[
"mch_id"
] =
$this
->_config[
"mch_id"
];
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$data
[
"out_trade_no"
] =
$out_trade_no
;
$data
[
"out_refund_no"
] =
$out_refund_no
;
$data
[
"total_fee"
] =
$total_fee
;
$data
[
"refund_fee"
] =
$refund_fee
;
$data
[
"op_user_id"
] =
$op_user_id
;
$result
=
$this
->post(self::URL_REFUND,
$data
,true);
return
$result
;
}
/**
* 申請退款 - 使用微信訂單號
* @param $out_trade_no 商戶訂單號
* @param $out_refund_no 退款單號
* @param $total_fee 總金額(單位:分)
* @param $refund_fee 退款金額(單位:分)
* @param $op_user_id 操做員帳號
* @return array
*/
public
function
refundByTransId(
$transaction_id
,
$out_refund_no
,
$total_fee
,
$refund_fee
,
$op_user_id
){
$data
=
array
();
$data
[
"appid"
] =
$this
->_config[
"appid"
];
$data
[
"mch_id"
] =
$this
->_config[
"mch_id"
];
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$data
[
"transaction_id"
] =
$transaction_id
;
$data
[
"out_refund_no"
] =
$out_refund_no
;
$data
[
"total_fee"
] =
$total_fee
;
$data
[
"refund_fee"
] =
$refund_fee
;
$data
[
"op_user_id"
] =
$op_user_id
;
$result
=
$this
->post(self::URL_REFUND,
$data
,true);
return
$result
;
}
/**
* 下載對帳單
* @param $bill_date 下載對帳單的日期,格式:20140603
* @param $bill_type 類型
* @return array
*/
public
function
downloadBill(
$bill_date
,
$bill_type
=
'ALL'
){
$data
=
array
();
$data
[
"appid"
] =
$this
->_config[
"appid"
];
$data
[
"mch_id"
] =
$this
->_config[
"mch_id"
];
$data
[
"bill_date"
] =
$bill_date
;
$data
[
"bill_type"
] =
$bill_type
;
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$result
=
$this
->post(self::URL_DOWNLOADBILL,
$data
);
return
$result
;
}
/**
* 獲取js支付使用的第二個參數
*/
public
function
get_package(
$prepay_id
) {
$data
=
array
();
$data
[
"appId"
] =
$this
->_config[
"appid"
];
$data
[
"timeStamp"
] = time();
$data
[
"nonceStr"
] =
$this
->get_nonce_string();
$data
[
"package"
] =
"prepay_id=$prepay_id"
;
$data
[
"signType"
] =
"MD5"
;
$data
[
"paySign"
] =
$this
->sign(
$data
);
return
$data
;
}
/**
* 獲取發送到通知地址的數據(在通知地址內使用)
* @return 結果數組,若是不是微信服務器發送的數據返回null
* appid
* bank_type
* cash_fee
* fee_type
* is_subscribe
* mch_id
* nonce_str
* openid
* out_trade_no 商戶訂單號
* result_code
* return_code
* sign
* time_end
* total_fee 總金額
* trade_type
* transaction_id 微信支付訂單號
*/
public
function
get_back_data() {
$xml
=
file_get_contents
(
"php://input"
);
$data
=
$this
->xml2array(
$xml
);
if
(
$this
->validate(
$data
)) {
return
$data
;
}
else
{
return
null;
}
}
/**
* 驗證數據簽名
* @param $data 數據數組
* @return 數據校驗結果
*/
public
function
validate(
$data
) {
if
(!isset(
$data
[
"sign"
])) {
return
false;
}
$sign
=
$data
[
"sign"
];
unset(
$data
[
"sign"
]);
return
$this
->sign(
$data
) ==
$sign
;
}
/**
* 響應微信支付後臺通知
* @param $return_code 返回狀態碼 SUCCESS/FAIL
* @param $return_msg 返回信息
*/
public
function
response_back(
$return_code
=
"SUCCESS"
,
$return_msg
=null) {
$data
=
array
();
$data
[
"return_code"
] =
$return_code
;
if
(
$return_msg
) {
$data
[
"return_msg"
] =
$return_msg
;
}
$xml
=
$this
->array2xml(
$data
);
print
$xml
;
}
}
|
1、注意:此類庫集成到ci咱們要更名WechatPay改成Wechatpay讓他符ci類庫規範,並且文件名也要改保持統一性json
2、把Wechatpay.php放在application\libraries文件夾內,將證書之類的,日誌文件之類的放置在和wechatpay.php同級目錄下便可,固然能夠隨便放api
3、將微信配置信息,商戶號、appid、AppSecret、API key、證書位置等信息放在wxpay_config.php文件中,放在application\config目錄中
wxpay_config.php代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?php defined(
'BASEPATH'
) OR
exit
(
'No direct script access allowed'
);
/**
* Created by PhpStorm.
* User: sxq
* Date: 2016-04-20
* Time: 16:59
*/
$config
[
'appid'
] =
'你的公衆號appid'
;
$config
[
'mch_id'
] =
'你的商戶號'
;
$config
[
'apikey'
] =
'你的APIkey'
;
$config
[
'appsecret'
] =
"你的AppSecret"
;
$config
[
'sslcertPath'
] = APPPATH.
'libraries/cert/apiclient_cert.pem'
;
$config
[
'sslkeyPath'
] = APPPATH.
'libraries/cert/apiclient_key.pem'
;
|
4、phpqrcode文件,這份文件在微信官方sdk中,使用文件有phpqrcode文件夾和qrcode.php也一同放置在application\libraries文件夾內
5、日誌文件log.php,這份文件在微信官方sdk中也一同放置在application\libraries文件夾內
1
2
3
4
5
6
|
require_once
(APPPATH.
'libraries/log.php'
);
//初始化日誌
$logHandler
=
new
CLogFileHandler(APPPATH.
"logs/"
.
date
(
'Y-m-d'
).
'.log'
);
Log::Init(
$logHandler
, 15);
//我在控制器最頂部加了這個實例化,日誌文件放在了application/logs文件夾
//調用方式:log::debug("輸出信息");簡單記錄執行信息方便調試
|
6、配置信息寫完後,那麼在控制器裏調用吧(滿滿的全是乾貨)
咱們首先按照常規的加載配置信息代碼同樣去加載微信配置信息,最後再加載三方類庫wechatpay.php
1
2
3
4
5
6
7
8
9
|
$this
->load->config(
'wxpay_config'
);
$wxconfig
[
'appid'
]=
$this
->config->item(
'appid'
);
$wxconfig
[
'mch_id'
]=
$this
->config->item(
'mch_id'
);
$wxconfig
[
'apikey'
]=
$this
->config->item(
'apikey'
);
$wxconfig
[
'appsecret'
]=
$this
->config->item(
'appsecret'
);
$wxconfig
[
'sslcertPath'
]=
$this
->config->item(
'sslcertPath'
);
$wxconfig
[
'sslkeyPath'
]=
$this
->config->item(
'sslkeyPath'
);
//因爲此類庫構造函數須要傳參,咱們初始化類庫就傳參數給他吧
$this
->load->library(
'Wechatpay'
,
$wxconfig
);
|
這步基礎信息配置完畢,接下來咱們須要構造統一下單API接口參數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
$param
[
'body'
]=
"商品名稱(自行看文檔具體填什麼)"
;
$param
[
'attach'
]=
"我有個參數要傳我就穿了個id過來,這裏不要有空格避免出錯"
;
$param
[
'detail'
]=
"我填了商品名稱加訂單號"
;
$param
[
'out_trade_no'
]=
"商戶訂單號"
;
$param
[
'total_fee'
]=
"金額,記得乘以100,微信支付單位默認分"
;
//如$total_fee*100
$param
[
"spbill_create_ip"
] =
$_SERVER
[
'REMOTE_ADDR'
];
//客戶端IP地址
$param
[
"time_start"
] =
date
(
"YmdHis"
);
//請求開始時間
$param
[
"time_expire"
] =
date
(
"YmdHis"
, time() + 600);
//請求超時時間
$param
[
"goods_tag"
] = urldecode(
$productname
);
//商品標籤,自行填寫
$param
[
"notify_url"
] = base_url().
"home/wxnotify"
;
//自行定義異步通知url
$param
[
"trade_type"
] =
"NATIVE"
;
//掃碼支付模式二
$param
[
"product_id"
] =
$order
->productid;
//正好有產品id就傳了個,看文檔說本身定義
//調用統一下單API接口
$result
=
$this
->wechatpay->unifiedOrder(
$param
);
//這裏能夠加日誌輸出,log::debug(json_encode($result));
//成功(return_code和result_code都爲SUCCESS)就會返回含有帶支付二維碼連接的數據
if
(isset(
$result
[
"code_url"
]) && !
empty
(
$result
[
"code_url"
])) { />
//二維碼圖片連接
$data
[
'wxurl'
] =
$result
[
"code_url"
];
//這裏傳遞商戶訂單號到掃碼視圖,是由於我想作跳轉,根據商戶號去查詢訂單是否支付成功,若是成功了就跳轉,定時輪詢微信服務器(這個誰有好的方法能夠分享給我啊,表示感謝啦)
$data
[
'orderno'
] =
$out_trade_no
;
$this
->load->view(
'home/pay'
,
$data
);
}
|
pay.php掃碼視圖頁面代碼以下:這部分代碼來自(https://github.com/Alpha2016/wxpay)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
<?php
if
(isset(
$wxurl
)&&!
empty
(
$wxurl
)){?>
<div
class
=
"bgcolor"
>
<div
class
=
"container"
>
<div
class
=
"panel"
>
<div
class
=
"panel-heading"
>
<ol
class
=
"breadcrumb"
>
<li><a href=
"<?php echo base_url().'home';?>"
>首頁</a><span
class
=
'divider'
>></span></li>
<li
class
=
"active active-tab"
><span><?php
echo
"二維碼支付"
;?></span></li>
</ol>
</div>
<div
class
=
"panel-body"
>
<div
class
=
"page-header"
>二維碼支付</div>
<div
class
=
"text-danger center-block text-center"
>
<input type=
"hidden"
id=
"orderno"
value=
"<?php echo $orderno;?>"
/>
<img alt=
"掃碼支付"
src=
"<?php echo base_url().'home/qrcode?data='.urlencode($wxurl);?>"
style=
"width:200px;height:200px;"
/>
</div>
</div>
</div>
</div>
</div>
<?php }?>
<script>
// 每半秒請求一次數據,而後判斷,跳轉,增長用戶友好性
$(
function
(){
orderno = $(
'#orderno'
).val();
start = self.setInterval(
"checkstatus(orderno)"
, 500);
});
function
checkstatus(order_no){
if
(order_no == undefined || order_no ==
''
){
window.clearInterval(start);
}
else
{
$.ajax({
url:
"<?php echo base_url().'home/queryorder';?>"
,
type:
'POST'
,
dataType:
'json'
,
data:{orderno:orderno},
success:
function
(msg){
if
(msg.trade_state ==
"SUCCESS"
) {
window.clearInterval(start);
alert(
'支付成功'
);
location.href =
"<?php echo base_url().'home/myorder';?>"
;
}
}
});
}
}
</script>
|
其實核心在二維碼連接如何轉換成二維碼圖片和如何定時輪詢支付結果
1
|
<?php
echo
base_url().
'home/qrcode?data='
.urlencode(
$wxurl
);?>這句是調用phpqrcode類庫<br>輪詢方法代碼:<br>該部分在home控制器下
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
function
queryorder()
{
$this
->load->config(
'wxpay_config'
);
$wxconfig
[
'appid'
]=
$this
->config->item(
'appid'
);
$wxconfig
[
'mch_id'
]=
$this
->config->item(
'mch_id'
);
$wxconfig
[
'apikey'
]=
$this
->config->item(
'apikey'
);
$wxconfig
[
'appsecret'
]=
$this
->config->item(
'appsecret'
);
$wxconfig
[
'sslcertPath'
]=
$this
->config->item(
'sslcertPath'
);
$wxconfig
[
'sslkeyPath'
]=
$this
->config->item(
'sslkeyPath'
);
$this
->load->library(
'Wechatpay'
,
$wxconfig
);
$out_trade_no
=
$_POST
[
'orderno'
];
//調用查詢訂單API接口
$array
=
$this
->wechatpay->orderQuery(
''
,
$out_trade_no
);
echo
json_encode(
$array
);
}
|
那麼二維碼類庫調用在這裏
1
2
3
4
5
6
|
function
qrcode()
{
require_once
(APPPATH.
'libraries/phpqrcode/phpqrcode.php'
);
$url
= urldecode(
$_GET
[
"data"
]);
QRcode::png(
$url
);
}
|
那麼二維碼生成支付圖片完成,支付輪詢也完成了,該如何去處理業務邏輯呢?
先說明下,這部分有個弊端,若是客戶一直不支付那麼他就一直輪詢,能夠自行設置個有效期,我沒有設置。若是在輪詢處處理業務邏輯怎麼樣?能夠的,可是也有個問題若是客戶直接關掉了,你來不及處理的業務怎麼辦?因此還要確保不掉單,還須要再微信異步通知url那裏處理下業務
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
//微信異步通知
function
wxnotify()
{
//$postStr = file_get_contents("php://input");//由於不少都設置了register_globals禁止,不能用$GLOBALS["HTTP_RAW_POST_DATA'] //這部分困擾了很久用上面這種一直接受不到數據,或者接受了解析不正確,最終用下面的正常了,有哪位願意指點的能夠告知一二
$xml
=
$GLOBALS
[
'HTTP_RAW_POST_DATA'
];
//這個須要開啓;always_populate_raw_post_data = On
$this
->load->config(
'wxpay_config'
);
$wxconfig
[
'appid'
]=
$this
->config->item(
'appid'
);
$wxconfig
[
'mch_id'
]=
$this
->config->item(
'mch_id'
);
$wxconfig
[
'apikey'
]=
$this
->config->item(
'apikey'
);
$wxconfig
[
'appsecret'
]=
$this
->config->item(
'appsecret'
);
$wxconfig
[
'sslcertPath'
]=
$this
->config->item(
'sslcertPath'
);
$wxconfig
[
'sslkeyPath'
]=
$this
->config->item(
'sslkeyPath'
);
$this
->load->library(
'Wechatpay'
,
$wxconfig
);
libxml_disable_entity_loader(true);
$array
= json_decode(json_encode(simplexml_load_string(
$xml
,
'SimpleXMLElement'
, LIBXML_NOCDATA)), true);
log::debug(
$xml
);
log::debug(json_encode(
$array
));
if
(
$array
!=null)
{
$out_trade_no
=
$array
[
'out_trade_no'
];
$trade_no
=
$array
[
'transaction_id'
];
$data
[
'orderid'
]=
$array
[
'attach'
];
$this
->load->model(
'payorder'
);
$payinfo
=
$this
->payorder->GetPayorder(
array
(
'orderno'
=>
$out_trade_no
));
if
(!
$payinfo
) {
$data
[
'orderno'
] =
$out_trade_no
;
$data
[
'money'
] =
$array
[
'total_fee'
];
$data
[
'tradeno'
] =
$trade_no
;
$rs
=
$this
->payorder->AddPayorder(
$data
);
if
(
$rs
>0)
{
//告知微信我成功了
$this
->wechatpay->response_back();
}
else
{
//告知微信我失敗了繼續發
$this
->wechatpay->response_back(
"FAIL"
);
}
}
else
{
$this
->wechatpay->response_back();
}
}
}
|
花了5天的時間去研究這個類型的微信支付,花了半天的時間去梳理知識點,總體感受就是若是API接口少,又有成熟類庫本身去集成吧
微信支付接口文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
首先你得知道這個jsapi是不能離開微信進行調用支付的,明白了這個道理咱們好下手,頁面是在微信內顯示並經過jsapi調用微信支付組件進行支付。
能夠看看咱們上一篇文章,主要是Native掃碼支付模式二
咱們仍然繼續使用wechatpay.php這個支付集成類,簡單方便好理解,不過若是應用jsapi的話這個類有個bug
在咱們構造jsapi須要的參數時有個時間戳,咱們用time()生成的,會報微信支付調用JSAPI缺乏參數:timeStamp
修改以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/**
* 獲取js支付使用的第二個參數
*/
public
function
get_package(
$prepay_id
) {
$data
=
array
();
$data
[
"appId"
] =
$this
->_config[
"appid"
];
//改動地方,把它變成字符串
$time
=time();
$data
[
"timeStamp"
] =
"\""
.
$time
.
"\""
;
$data
[
"nonceStr"
] =
$this
->get_nonce_string();
$data
[
"package"
] =
"prepay_id=$prepay_id"
;
$data
[
"signType"
] =
"MD5"
;
$data
[
"paySign"
] =
$this
->sign(
$data
);
return
$data
;
}
|
其實這個方法就是獲取jsapi的支付參數了
1、微信JSAPI支付
不能忘記配置受權目錄,調用jsapi我是在http://xxx.com/index.php/home下我配置了這個
首先咱們仍是要調用統一下單接口,獲取咱們要的參數(若是此類的配置放置位置等不會的請參考上篇文章),此爲pay方法,在調用統一下單接口的時候咱們須要知道須要哪些參數
一、要獲取openid,這個我是項目用了一個微信API的類庫,https://github.com/dodgepudding/wechat-php-sdk,主要是用了這裏面的方法
此項目有朋友專門的對接了CodeIgniter框架的擴展類庫,能夠直接用,目錄結構,咱們直接上代碼吧
1
2
3
4
5
6
|
public
function
__construct()
{
parent::__construct();
$this
->load->library(
'CI_Wechat'
);
//因爲個人項目是時刻都跟微信綁在一塊兒,因此直接加載在構造函數裏了,不用每一個方法都加載了。
$this
->load->library(
'pagination'
);
}
|
CI_Model內容你們看下上面的類庫源碼,還有裏面如何配置的,下面咱們看看如何獲取openid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
function
oauthurl()
{
$oauth_url
=
$this
->ci_wechat->getOauthRedirect(base_url() .
'index.php/home/oauth'
, 1);
header(
'Location: '
.
$oauth_url
);
exit
();
}
function
oauth()
{
if
(!isset(
$_GET
[
'code'
])) {
//觸發微信返回code碼
$baseUrl
= urlencode(
'http://'
.
$_SERVER
[
'HTTP_HOST'
] .
$_SERVER
[
'PHP_SELF'
] .
$_SERVER
[
'QUERY_STRING'
]);
$url
=
$this
->__CreateOauthUrlForCode(
$baseUrl
);
Header(
"Location: $url"
);
exit
();
}
else
{
$json
=
$this
->ci_wechat->getOauthAccessToken();
$openid
=
$json
[
'openid'
];
//註冊用戶,成功後能夠搶單
//return $this->_isRegistered($_SESSION['user']['openid']);
return
$openid
;
}
}
|
以上兩個方法就是獲取openid的,獲取以後我是保存在session裏的,我每一個頁面都判斷是否獲取了openid若是沒有獲取直接
1
|
$this
->session->set_userdata(
'openid'
,
$this
->oauth());
|
這樣保證一直能獲得openid
二、構造JSAPI支付所需參數(統一下單的參數構造)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
$this
->load->model(
'publist'
);
//獲取訂單信息
$pub
=
$this
->publist->GetList(
array
(
'id'
=>
$_SESSION
[
'orderid'
]));
//微信支付配置的參數配置讀取
$this
->load->config(
'wxpay_config'
);
$wxconfig
[
'appid'
]=
$this
->config->item(
'appid'
);
$wxconfig
[
'mch_id'
]=
$this
->config->item(
'mch_id'
);
$wxconfig
[
'apikey'
]=
$this
->config->item(
'apikey'
);
$wxconfig
[
'appsecret'
]=
$this
->config->item(
'appsecret'
);
$wxconfig
[
'sslcertPath'
]=
$this
->config->item(
'sslcertPath'
);
$wxconfig
[
'sslkeyPath'
]=
$this
->config->item(
'sslkeyPath'
);
$this
->load->library(
'Wechatpay'
,
$wxconfig
);
//商戶交易單號
$out_trade_no
=
$pub
->listno;
$total_fee
=
$pub
->fee;
$openid
=
$_SESSION
[
'openid'
];
$param
[
'body'
]=
"黑人牙膏"
;
$param
[
'attach'
]=
$pub
->id;
$param
[
'detail'
]=
"黑人牙膏-"
.
$out_trade_no
;
$param
[
'out_trade_no'
]=
$out_trade_no
;
$param
[
'total_fee'
]=
$total_fee
*100;
$param
[
"spbill_create_ip"
] =
$_SERVER
[
'REMOTE_ADDR'
];
$param
[
"time_start"
] =
date
(
"YmdHis"
);
$param
[
"time_expire"
] =
date
(
"YmdHis"
, time() + 600);
$param
[
"goods_tag"
] =
"黑人牙膏"
;
$param
[
"notify_url"
] = base_url().
"index.php/home/notify"
;
$param
[
"trade_type"
] =
"JSAPI"
;
$param
[
"openid"
] =
$openid
;
//統一下單,獲取結果,結果是爲了構造jsapi調用微信支付組件所需參數
$result
=
$this
->wechatpay->unifiedOrder(
$param
);
//若是結果是成功的咱們才能構造所需參數,首要判斷預支付id
if
(isset(
$result
[
"prepay_id"
]) && !
empty
(
$result
[
"prepay_id"
])) {
//調用支付類裏的get_package方法,獲得構造的參數
$data
[
'parameters'
]=json_encode(
$this
->wechatpay->get_package(
$result
[
'prepay_id'
]));
$data
[
'notifyurl'
]=
$param
[
"notify_url"
];
$data
[
'fee'
]=
$total_fee
;
$data
[
'pubid'
]=
$_SESSION
[
'orderid'
];
$this
->load->view(
'home/header'
);
//要有個頁面將以上數據傳遞過去並展現給用戶
$this
->load->view(
'home/pay'
,
$data
);
$this
->load->view(
'home/footer'
);
}
|
三、支付頁面,views視圖pay.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
<?php
$jsApiParameters
=
$parameters
;
//參數賦值
?>
<script type=
"text/javascript"
>
//調用微信JS api 支付
function
jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest'
,
<?php
echo
$jsApiParameters
; ?>,
function
(res){
WeixinJSBridge.log(res.err_msg);
if
(res.err_msg ==
"get_brand_wcpay_request:ok"
){
$.alert(
'支付成功'
);
//我在這裏選擇了前臺只要支付成功將單號傳遞更新數據
$.ajax({
url:
'<?php echo $notifyurl.'
/
'.$pubid;?>'
,
dataType:
'json'
,
success :
function
(ret){
if
(ret==1){
//成功後返回個人訂單頁面
location.href=
"<?php echo base_url().'index.php/home/myorder';?>"
;
}
}
});
}
else
{
//$.alert('支付失敗');
}
//alert(res.err_code+res.err_desc+res.err_msg);
}
);
}
function
callpay()
{
if
(typeof WeixinJSBridge ==
"undefined"
){
if
( document.addEventListener ){
document.addEventListener(
'WeixinJSBridgeReady'
, jsApiCall, false);
}
else
if
(document.attachEvent){
document.attachEvent(
'WeixinJSBridgeReady'
, jsApiCall);
document.attachEvent(
'onWeixinJSBridgeReady'
, jsApiCall);
}
}
else
{
jsApiCall();
}
}
</script>
<div
class
=
"hd"
>
<h1
class
=
"page_title"
>支付佣金</h1>
<p
class
=
"page_desc"
>請認真核對佣金金額</p>
</div>
<div
class
=
"weui_cells"
>
<div
class
=
"weui_cell"
>
<div
class
=
"weui_cell_hd weui_cell_primary"
>
該筆訂單支付金額爲<span style=
"color:#f00;font-size:50px"
><?php
echo
$fee
; ?></span>元錢
</div>
</div>
</div>
<button
class
=
"weui_btn weui_btn_primary"
type=
"button"
onclick=
"callpay()"
>當即支付</button>
|
以上代碼能夠用微信web開發者工具,使用方式本身看看吧,有了這個工具調試再也不難
四、支付成功跳轉頁面,咱們看notify方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function
notify()
{
$id
=
$this
->uri->segment(3);
if
(isset(
$_SESSION
[
'openid'
])) {
$this
->load->model(
'publist'
);
//更新業務邏輯
$rs
=
$this
->publist->UpdateList(
array
(
'id'
=>
$id
,
'feestatus'
=> 1));
if
(
$rs
> 0) {
echo
1;
exit
;
}
else
{
echo
0;
exit
;
}
}
}
|
這樣咱們的支付流程就完全走完了。
2、當咱們支付完以後,有些單子能夠退單的,如何將款項也退回呢
以上場景要弄明白了
咱們申請退款須要參數有哪些?咱們看看支付類裏的退款方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* 申請退款 - 使用商戶訂單號
* @param $out_trade_no 商戶訂單號
* @param $out_refund_no 退款單號
* @param $total_fee 總金額(單位:分)
* @param $refund_fee 退款金額(單位:分)
* @param $op_user_id 操做員帳號
* @return array
*/
public
function
refund(
$out_trade_no
,
$out_refund_no
,
$total_fee
,
$refund_fee
,
$op_user_id
){
$data
=
array
();
$data
[
"appid"
] =
$this
->_config[
"appid"
];
$data
[
"mch_id"
] =
$this
->_config[
"mch_id"
];
$data
[
"nonce_str"
] =
$this
->get_nonce_string();
$data
[
"out_trade_no"
] =
$out_trade_no
;
$data
[
"out_refund_no"
] =
$out_refund_no
;
$data
[
"total_fee"
] =
$total_fee
;
$data
[
"refund_fee"
] =
$refund_fee
;
$data
[
"op_user_id"
] =
$op_user_id
;
$result
=
$this
->post(self::URL_REFUND,
$data
,true);
return
$result
;
}
|
商戶訂單號,商戶提供的退單號,付款金額,退款金額(不能退的比實際付款的多),操做員(通常商戶號)
控制器內寫退款方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//申請退款
function
refund(
$id
=
""
)
{
if
(
$id
==
""
){
//方便我手動調用退單
$id
=
$this
->uri->segment(3);
}
if
(isset(
$id
) &&
$id
!=
""
) {
$this
->load->model(
'publist'
);
//一、取消訂單能夠退款。二、失敗訂單能夠退款
$pub
=
$this
->publist->GetList(
array
(
'id'
=>
$id
));
if
(
$pub
->liststatus == 3 ||
$pub
->liststatus == 4) {
$listno
=
$pub
->listno;
$fee
=
$pub
->fee * 100;
$this
->load->config(
'wxpay_config'
);
$wxconfig
[
'appid'
]=
$this
->config->item(
'appid'
);
$wxconfig
[
'mch_id'
]=
$this
->config->item(
'mch_id'
);
$wxconfig
[
'apikey'
]=
$this
->config->item(
'apikey'
);
$wxconfig
[
'appsecret'
]=
$this
->config->item(
'appsecret'
);
$wxconfig
[
'sslcertPath'
]=
$this
->config->item(
'sslcertPath'
);
$wxconfig
[
'sslkeyPath'
]=
$this
->config->item(
'sslkeyPath'
);
$this
->load->library(
'Wechatpay'
,
$wxconfig
);
if
(isset(
$listno
) &&
$listno
!=
""
) {
$out_trade_no
=
$listno
;
$total_fee
=
$fee
;
$refund_fee
=
$fee
;
//自定義商戶退單號
$out_refund_no
=
$wxconfig
[
'mch_id'
].
date
(
"YmdHis"
);
$result
=
$this
->wechatpay->refund(
$out_trade_no
,
$out_refund_no
,
$total_fee
,
$refund_fee
,
$wxconfig
[
'mch_id'
]);
log::DEBUG(json_encode(
$result
));
if
(isset(
$result
[
"return_code"
]) &&
$result
[
"return_code"
]=
"SUCCESS"
&&isset(
$result
[
"result_code"
]) &&
$result
[
"result_code"
]=
"SUCCESS"
) {
echo
"<script>$.toast('退款成功')</script>"
;
}
//佣金狀態更改成已退款
$this
->publist->UpdateList(
array
(
'id'
=>
$id
,
'liststatus'
=>3,
'listoutno'
=>
$out_refund_no
));
redirect(
'home/myorder'
);
}
}
}
}
|
試試就行了,很快就能夠接到退款消息
以上是這幾天摸索出來的東西,分享給你們。
http://blog.sina.com.cn/s/blog_14955e3b70102wvmj.html