微信支付的開發文檔 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
介紹的是相當簡陋啊。。
下載sdk和demo: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
下載好後,放到 component文件夾(我用的是yii2),在sdk文件夾下添加一個 init.php
<?php //init.php 主要是引用lib中的4個文件 require_once dirname(__FILE__).'/lib/WxPay.Api.php'; require_once dirname(__FILE__).'/lib/WxPay.Config.php'; require_once dirname(__FILE__).'/lib/WxPay.Data.php'; require_once dirname(__FILE__).'/lib/WxPay.Exception.php'; require_once dirname(__FILE__).'/lib/WxPay.Notify.php';
支付中需要用到的幾個參數
app_id, app_secret, MCHID, //商戶號 key
這幾個參數在 「微信公衆平臺開發者設置 」 和 「商戶平臺設置 」 都能獲取到,具體百度。。
先看前臺
$("#pay").click(function(){ var pay_way = $("input[type='radio']:checked").val(); if(pay_way == 1){ wap_pay(1) //支付寶 }else if(pay_way == 2){ wechatcallpay() //微信支付 }else if(pay_way == 3){ paypal_pay() //PayPal } });
wechatcallpay(),我是通過 ajax 獲取後臺數據
//wechat 支付 function wechatcallpay() { $.ajax({ type: 'POST', url: '/order/wechatpay', //獲取後臺中的數據 data:"_csrf="+_csrf+"&ssid="+ssid, dataType: 'json', success: function(data){ jsApiParamenters = data 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(); } } }); } function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', jsApiParamenters, 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" ) { //跳轉到[成功界面] window.location.href = "<?php echo Url::to('/order/success')?>"; } else if(res.err_msg == "get_brand_wcpay_request:cancel"){ //跳轉到[取消界面] window.location.href = "<?php echo Url::to('/order/cancel')?>"; } else { //跳轉到「失敗界面」 window.location.href = "<?php echo Url::to('/order/cancel')?>"; } } ); }
再看看 /order/wechatpay
public function actionWechatpay() { if(Yii::$app->request->isPost) { $ssid = Yii::$app->request->post('ssid'); $online_order = OnlineOrder::find()->where('order_code = :ssid',[':ssid'=>$ssid])->one(); $data = OnlineOrder::findOrderDetail($online_order); $rate = Helper::rate(); //第三方 獲取匯率 $money = ceil($data['total_money'] * $rate * 100); //取整,微信支付已分爲單位,而且不能有小數 $order_number = $data['order_number']; $cookies = Yii::$app->request->cookies; $wx_code = $cookies->getValue('wx_code'); //通過cookies獲取wx_code,獲取方法下面有講 $wx_app_id = Yii::$app->params['wechat']['wx_app_id']; $wx_app_secret = Yii::$app->params['wechat']['wx_app_secret']; $open_id = WechatPay::getOpenid($wx_app_id, $wx_app_secret, $wx_code); //獲取方法下面講 $body = "商品簡述"; $notify_url = Yii::$app->params['wechat']['notify_url']; //回調uRL,支付成功後微信會調用這個接口 $jsApiParams = Helper::getjsApiParams($open_id,$body,$ssid,$money,$order_number,$notify_url); //下面講 echo $jsApiParams; } else { echo 0; } }
首先是wx_code的獲取,
/** * 判断是否在微信客户端打开链接 * 如果是就跳转到微信code的重定向url地址 * 如果不是就跳到支付宝支付界面 */ public function actionGetcode() { $isWechat = Helper::isWechatBrowser(); //下面有講到if($isWechat){ $url = Helper::GetWxCodeUrl(); //下面講 header("Location: $url"); exit(); } else { $this->redirect(['order/payment']); } }
/** * 通过微信重定向url获取code, * 并且把code设置为cookie */ public function actionGetwxcode() { $code = Yii::$app->request->get('code'); //把wx_code作爲cookies保存if(!empty($code)){ $cookies = Yii::$app->response->cookies; $cookies->add(new yiiwebCookie([ 'name' => 'wx_code', 'value' => $code, 'expire'=>time()+3600, ])); } $this->redirect(['/order/payment']); }
新建一個 WechatPay.php,主要是獲取 code 和openid
<?php
namespace frontendcomponents;
class WechatPay
{
/**
* 获取微信公众号授权用户唯一标识
* @param $app_id 微信公众号应用唯一标识
* @param $app_secret 微信公众号应用密钥(注意保密)
* @param $code 授权code, 通过调用WxpubOAuth::createOauthUrlForCode来获取
* @return openid 微信公众号授权用户唯一标识, 可用于微信网页内支付
*/
public static function getOpenid($app_id, $app_secret, $code)
{
$url = self::_createOauthUrlForOpenid($app_id, $app_secret, $code);
$res = self::_getRequest($url);
$data = json_decode($res, true);
return $data['openid'];
}
/**
* 用于获取授权code的URL地址,此地址用于用户身份鉴权,获取用户身份信息,同时重定向到$redirect_url
* @param $app_id 微信公众号应用唯一标识
* @param $redirect_url 授权后重定向的回调链接地址,重定向后此地址将带有授权code参数,
* 该地址的域名需在微信公众号平台上进行设置,
* 步骤为:登陆微信公众号平台 => 开发者中心 => 网页授权获取用户基本信息 => 修改
* @param bool $more_info FALSE 不弹出授权页面,直接跳转,这个只能拿到用户openid
* TRUE 弹出授权页面,这个可以通过 openid 拿到昵称、性别、所在地,
* @return string 用于获取授权code的URL地址
*/
public static function createOauthUrlForCode($app_id, $redirect_url, $more_info = false)
{
$urlObj = array();
$urlObj['appid'] = $app_id;
$urlObj['redirect_uri'] = $redirect_url;
$urlObj['response_type'] = 'code';
$urlObj['scope'] = $more_info ? 'snsapi_userinfo' : 'snsapi_base';
$urlObj['state'] = "#state"; //這個參數會原封不動地傳回來
$queryStr = http_build_query($urlObj);
return 'https://open.weixin.qq.com/connect/oauth2/authorize?' . $queryStr;
}
/**
* 获取openid的URL地址
* @param $app_id 微信公众号应用唯一标识
* @param $app_secret 微信公众号应用密钥(注意保密)
* @param $code 授权code, 通过调用WxpubOAuth::createOauthUrlForCode来获取
* @return string 获取openid的URL地址
*/
private static function _createOauthUrlForOpenid($app_id, $app_secret, $code)
{
$urlObj = array();
$urlObj['appid'] = $app_id;
$urlObj['secret'] = $app_secret;
$urlObj['code'] = $code;
$urlObj['grant_type'] = 'authorization_code';
$queryStr = http_build_query($urlObj);
return 'https://api.weixin.qq.com/sns/oauth2/access_token?' . $queryStr;
}
/**
* GET 请求
*/
private static function _getRequest($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$res = curl_exec($ch);
curl_close($ch);
return $res;
}
public static function getSign($params, $key){
ksort($params, SORT_STRING);
$unSignParaString = self::formatQueryParaMap($params, false);
$signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
return $signStr;
}
protected static function formatQueryParaMap($paraMap, $urlEncode = false){
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v){
if (null != $v && "null" != $v) {
if ($urlEncode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
}
$reqPar = '';
if (strlen($buff)>0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
}
Helper.php
//首先引入 init.php require_once dirname(dirname(__FILE__)).'/components/WxpayAPI/init.php'; /** * 判断是否微信打开 * @return boolean */ public static function isWechatBrowser() { if (strpos($_SERVER['HTTP_USER_AGENT'],'MicroMessenger') !== false ) { return true; } return false; } /** * 获取微信code的重定向前的url * @return string */ public static function GetWxCodeUrl() { $wx_app_id = Yii::$app->params['wechat']['wx_app_id']; $redirect_url = Yii::$app->params['wechat']['redirect_url'];//這個就是前面 微信重定向獲取code的ur(/order/getwxcode ) $code_url = WechatPay::createOauthUrlForCode($wx_app_id, $redirect_url); return $code_url; } /** * wechat支付 獲取jsapi參數 */ public static function getjsApiParams($openId,$body,$attach,$money,$order_number,$notify_url,$trade_type="JSAPI") { $input = new WxPayUnifiedOrder(); $input->SetBody($body); $input->SetAttach($attach); $input->SetOut_trade_no($order_number); $input->SetTotal_fee($money); $input->SetTime_start(date("YmdHis")); $input->SetTime_expire(date("YmdHis", time() + 600)); $input->SetGoods_tag("商品"); $input->SetNotify_url($notify_url); $input->SetTrade_type($trade_type); $input->SetOpenid($openId); $input->setDetail("商品簡介"); $order = WxPayApi::unifiedOrder($input); //這個函數在 微信sdk中的 ..libWxPay.Api.php $jsApiParameters = WxPayApi::GetJsApiParameters($order);//這個函數在 微信sdk中的..libWxPay.Api.php return $jsApiParameters; }
接通之後,還需要在 「微信公衆平臺」和 「商戶平臺」設置 授權url,不然是訪問不了微信的接口的,具體百度。。。
「微信回調 Notify_url」
可以完成支付了,還有就是 回調地址的處理,這個地址是在 上面 actionWechaypay() 中設置的,當支付成功後,微信就會調用
class CallbackController extends BaseController { public $enableCsrfValidation = false; //這個要關閉,不然接收不到數據 public function actionWechat() { $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); if ($postObj === false) { die('parse xml error'); } if ($postObj->return_code != 'SUCCESS') { die("error_code: ".$postObj->err_code.",msg: ".$postObj->return_msg); } $key = Yii::$app->params['wechat']['wx_key']; //验证签名 $wechat = new WechatPay(); //這個就是上面的WechatPay.php中的內容 $arr = (array)$postObj; unset($arr['sign']); if($wechat::getSign($arr,$key) != $postObj->sign) { die("签名错误"); }
//之後的邏輯,就是 修改訂單狀態。。。
return '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; } }