使用PHP的CI框架实现微信的两种支付方式:
JSAPI网页支付,即日常所说的公众号支付,可在微信公众号、朋友圈、聊天会话中点击页面链接,或者用微信“扫一扫”扫描页面地址二维码在微信中打开商户HTML5页面,在页面内下单完成支付。
Native原生支付,即日常所说的扫码支付,商户根据微信支付协议格式生成的二维码,用户通过微信“扫一扫”扫描二维码后即进入付款确认界面,输入密码即完成支付。
方式一:JSApi支付,即:在微信中打开网页,直接调用微信支付,如图一,访问链接(微信中打开):
https://fanqie.tongfawuye.com/wxpay/weixin_pay
方式二:Native支付,即:浏览器访问链接网页,产生微信支付二维码,微信扫码后可完成支付,如图二,访问链接:https://fanqie.tongfawuye.com/wxpay/wxpay_detail
?楼主花了几天的时间对接完成,整理好文档后楼主会将源码及实现过程全程发表出来。谢谢大家!
服务环境描述:PHP CI3框架 mysql数据库
下面是代码实现了:
1.数据库mysql语句
CREATE TABLE `fanqie_pay_log` ( ? `log_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '支付日志ID', ? `name` varchar(32) DEFAULT NULL COMMENT '支付说明', ? `amount` decimal(10,2) DEFAULT '0.00' COMMENT '付款金额', ? `pay_status` tinyint(2) DEFAULT '0' COMMENT '支付状态 0未支付 1已支付 2已退款 3部分退款', ? `add_time_ymd` datetime DEFAULT NULL COMMENT '产生支付日志的时间', ? `prepay_id` varchar(128) DEFAULT NULL COMMENT '微信支付流水ID(没有用)', ? `trade_no` varchar(32) DEFAULT NULL COMMENT '商户编号', ? `pay_mode` tinyint(1) DEFAULT '1' COMMENT '支付方式:1微信 ?2支付宝', ? `pay_user` varchar(128) DEFAULT NULL COMMENT '支付的用户(微信openid)', ? `pay_trans_id` varchar(256) DEFAULT NULL COMMENT '支付订单id(微信流ID)', ? `pay_code` varchar(32) DEFAULT NULL COMMENT '支付回调产生的结果代码(微信支付成功SUCCESS)', ? `pay_message` varchar(50) DEFAULT NULL COMMENT '支付回调返回的信息(失败时返回)', ? `refund_amount` decimal(10,2) DEFAULT '0.00' COMMENT '退款金额', ? `add_time` int(10) DEFAULT '0' COMMENT '创建时间戳', ? `last_time` int(10) DEFAULT '0' COMMENT '更新时间戳', ? PRIMARY KEY (`log_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='平台支付日志';
application/controllers/Wxpay.php
<?php
defined ( 'BASEPATH' ) or exit ( 'No direct script access allowed' );
require_once(APPPATH."/libraries/wxpay/api/WxPay.JsApiPay.php");
require_once(APPPATH."/libraries/wxpay/api/WxPay.NativePay.php");
require_once(APPPATH."/libraries/wxpay/lib/WxPay.Api.php");
require_once(APPPATH."/libraries/wxpay/lib/WxPay.Notify.php");
class Wxpay extends MY_Controller {
function __construct()
{
parent::__construct(false);
$this->load->model('Pay_log_model');
}
/**
* 微信支付二维码显示页面
*/
public function wxpay_detail(){
//$amount = $this->input->get('amount');
//$phone = $this->input->get('phone');
$amount = 0.01;
$phone = '13427790490';
if($amount < 0.01){
$data['error'] = '请输入有效的支付金额';
$this->load->view('wxpay_detail', $data);
return;
}
$pay_log = array();
$pay_log['pay_user'] = $phone;
$pay_log['name'] = '订单微信扫码支付';
$pay_log['amount'] = $amount;
$pay_log['add_time'] = time();
$pay_log['add_time_ymd'] = date("Y-m-d H:i:s");
$this->Pay_log_model->save($pay_log);
$log_id = $pay_log['log_id'];
$data = $this->get_wxpay_native_data($log_id,"微信扫码测试商品");
$this->load->view('wxpay_detail',$data);
}
/**
* 微信扫码支付内容
* @param $log_id 订单日志id
* @param $name 商品名称
*/
private function get_wxpay_native_data($log_id,$name){
$notify = new NativePay();
$input = new WxPayUnifiedOrder();
$input->SetBody($name);
$input->SetAttach($log_id);
$input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis").$log_id);//商户订单号
$input->SetTotal_fee(1 );//总金额
$input->SetTime_start(date("YmdHis"));//交易起始时间
$input->SetTime_expire(date("YmdHis", time() + 600));//交易结束时间
$input->SetNotify_url(base_url('/wxpay/wxpay_recharge_notify_url'));//通知地址
$input->SetTrade_type("NATIVE");
$input->SetProduct_id("1");//商品ID,可随意定
return $notify->GetPayUrl($input);
}
/**
* 微信网页调用JsApi支付
* @throws WxPayException
*/
public function weixin_pay()
{
$amount = (float)0.01;
if($amount < 0.01){
$data['error'] = '请输入有效的支付金额';
$this->load->view('weixin_pay', $data);
return;
}
//$openid = $this->get_openid();
$openid = 'ocJaB1lcjS-xA5V3w-VOKQJjynUU';//对应公众号的openid
//插入支付日志
$pay_log = array();
$pay_log['pay_user'] = $openid;
$pay_log['name'] = '微信JSAPI订单支付';
$pay_log['amount'] = $amount;
$pay_log['add_time'] = time();
$pay_log['add_time_ymd'] = date("Y-m-d H:i:s");
$this->Pay_log_model->save($pay_log);
$log_id = $pay_log['log_id'];
$request_data = $this->get_wxpay_request_data($openid, $log_id, $amount, $pay_log['name']);
$data['jsApiParameters'] = $request_data;
$this->load->view('weixin_pay', $data);
}
/**
* 得到微信支付请求数据
* @param unknown $log_id
* @param unknown $amount
* @param unknown $name
* @return json数据,可直接填入js函数作为参数
* @throws WxPayException
*/
private function get_wxpay_request_data($openId, $log_id, $amount, $name)
{
$tools = new JsApiPay();
$input = new WxPayUnifiedOrder();
$input->SetBody($name);//商品描述
$input->SetAttach($log_id);//附加数据
$input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis").$log_id);//商户订单号
$input->SetTotal_fee($amount * 100);//总金额
$input->SetTime_start(date("YmdHis"));//交易起始时间
$input->SetTime_expire(date("YmdHis", time() + 600));//交易结束时间
$input->SetNotify_url(base_url('/wxpay/wxpay_recharge_notify_url'));//通知地址
$input->SetTrade_type("JSAPI");//交易类型
$input->SetOpenid($openId);//用户标识
$order = WxPayApi::unifiedOrder($input);
if($order['return_code'] == 'FAIL'){
echo $order['return_msg'].',请去到后台进行微信支付配置';exit;
}
return $tools->GetJsApiParameters($order);
}
/**
* 微信支付异步通知
*/
public function wxpay_recharge_notify_url()
{
//log_message('error', "POST_XML:" . file_get_contents("php://input"));
$notify = new PayNotifyCallBack();
$notify->Handle(false);
}
}
class PayNotifyCallBack extends WxPayNotify
{
//查询订单
public function Queryorder($transaction_id)
{
$input = new WxPayOrderQuery();
$input->SetTransaction_id($transaction_id);
try {
$result = WxPayApi::orderQuery($input);
} catch (WxPayException $e) {
return false;
}
//Log::DEBUG("Queryorder:" . json_encode($result));
if(array_key_exists("return_code", $result)
&& array_key_exists("result_code", $result)
&& $result["return_code"] == "SUCCESS"
&& $result["result_code"] == "SUCCESS")
{
return true;
}
return false;
}
//重写回调处理函数
public function NotifyProcess($data, &$msg)
{
//Log::DEBUG("NotifyProcess:" . json_encode($data));
if(!array_key_exists("transaction_id", $data)){
$msg = "输入参数不正确";
return false;
}
//查询订单,判断订单真实性
if(!$this->Queryorder($data["transaction_id"])){
$msg = "订单查询失败";
return false;
}
//逻辑处理
$log_id = $data['attach'];
$ci_obj = &get_instance();
$ci_obj->load->model('Pay_log_model');
$pay_log = $ci_obj->Pay_log_model->get_info($log_id);
if(!empty($pay_log))
{
/* 检查支付的金额是否相符 */
if($pay_log['amount'] == $data['total_fee']/100 && $pay_log['pay_status'] == 0)
{
//修改支付状态
$log_data = array(
'pay_status'=>1,
'trade_no'=>$data['out_trade_no'],
'pay_user'=>$data['openid'],
'pay_trans_id'=>$data['transaction_id'],
'pay_code'=>$data['result_code'],
'pay_message'=>empty($data['return_msg'])?'':$data['return_msg'],
);
$ci_obj->Pay_log_model->save($log_data, $log_id);
//给微信返回成功
return true;
}
}
}
}
application/models/Pay_log_model
<?php
class Pay_log_model extends MY_Model {
public $_table = 'pay_log';
public $primary_key = 'log_id';
function get_info($id, $select=null){
if(!empty($select)){
$this->db->select($select);
}
return $this->get($id);
}
function save(&$data, $id = 0) {
$data['last_time'] = time();
if ($id > 0) {
$this->db->set ( $data );
$this->db->where ( $this->primary_key, $id );
$this->db->update ( $this->_table );
$err = $this->db->error();
$data['db_code'] = $err['code'];
$data [$this->primary_key] = $id;
return $this->db->affected_rows ();
}
$data['add_time'] = time();
$this->db->insert ( $this->_table, $data );
$err = $this->db->error();
$data['db_code'] = $err['code'];
$data [$this->primary_key] = $this->db->insert_id ();
return $this->db->affected_rows ();
}
}
application/views/weixin_pay.php
<!DOCTYPE html>
<html>
<head>
<title>微信安全支付</title>
<base href="<?php echo base_url()?>" id="base_url">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
</head>
<body>
<div class="conainer">
微信支付
</div>
<script>
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
<?php echo isset($jsApiParameters) ? $jsApiParameters : 'null'?>,
function(res){
//WeixinJSBridge.log(res.err_msg);
//alert(res.err_code+res.err_desc+res.err_msg);
if(res.err_msg == "get_brand_wcpay_request:ok"){
alert("支付成功!");
}else{
alert("取消支付!");
}
window.history.go(-1);
}
);
WeixinJSBridge.call('hideOptionMenu');
WeixinJSBridge.call('hideToolbar');
};
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();
}
};
callpay();
</script>
</body>
</html>
?application/views/wxpay_detail.php
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>微信扫描支付样例</title>
</head>
<body>
<div style="text-align:center;margin-left: 10px;color:#556B2F;font-size:30px;font-weight: bolder;">扫描支付0.01元钱</div>
<br/>
<div style="text-align:center;">
<img alt="扫码支付" src="<?php echo base_url('/qrcode?data='.urlencode($code_url))?>" style="width:300px;height:300px;"/>
</div>
</body>
</html>
需要修改微信支付demo中的配置文件代码
application/libraries/wxpay/lib/WxPay.Config.php
/**
* TODO: 修改这里配置为您自己申请的商户信息
* 微信公众号信息配置
*
* APPID:绑定支付的APPID(必须配置,开户邮件中可查看)
*
* MCHID:商户号(必须配置,开户邮件中可查看)
*
* KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置)
* 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert
*
* APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置),
* 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
* @var string
*/
const APPID = 'XXX';
const MCHID = 'XXX';
const KEY = 'XXX';
const APPSECRET = 'XXX';
微信支付文件路径及位置?
|