1. 程式人生 > >微信公共號H5支付。

微信公共號H5支付。

end bstr req 公眾號 nat cancel d參數 ets 字符轉換

1、接受支付信息。

/**
* 發起支付請求
* @return [type] [description]
*/
function pay($openid){
$nonce_str = $this->rand_code(); //調用隨機字符串生成方法獲取隨機字符串
$data[‘appid‘] = $this->appid; //appid
$data[‘mch_id‘] = $this->mch_id ; //商戶號
$data[‘body‘] = ‘ceshi‘;
$data[‘spbill_create_ip‘] = $_SERVER["REMOTE_ADDR"]; //ip地址
$data[‘total_fee‘] = 10; //金額 默認金額:分 *100
$data[‘out_trade_no‘] = time().mt_rand(10000,99999); //商戶訂單號,不能重復
$data[‘nonce_str‘] = $nonce_str; //隨機字符串
$data[‘notify_url‘] = 支付回調地址(自己填寫); //回調地址,用戶接收支付後的通知,必須為能直接訪問的網址,不能跟參數
$data[‘trade_type‘] = ‘JSAPI‘; //支付方式
$data[‘openid‘] = $openid; //openid
//將參與簽名的數據保存到數組 註意:以上幾個參數是追加到$data中的,$data中應該同時包含開發文檔中要求必填的剔除sign以外的所有數據
$data[‘sign‘] = $this->getSign($data); //獲取簽名
$xml = $this->ToXml($data); //數組轉xml
//curl 傳遞給微信方
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
// header("Content-type:text/xml");
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
if(stripos($url,"https://")!==FALSE){
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
} else {
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//嚴格校驗
}
//設置header
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求結果為字符串且輸出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//設置超時
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, TRUE);
//傳輸文件
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//運行curl
$data = curl_exec($ch);
//返回結果
if($data)
{
curl_close($ch);
//返回成功,將xml數據轉換為數組.
$re = $this->FromXml($data);
if($re[‘return_code‘] != ‘SUCCESS‘)
{
return "201";
}
else
{
/*二次簽名*/
$arr =[
‘appId‘ =>$re[‘appid‘],
‘package‘ => ‘prepay_id=‘.$re[‘prepay_id‘],
‘nonceStr‘ => $this->rand_code(),
‘signType‘ => ‘MD5‘,
‘timeStamp‘ => time(),
];
//第二次生成簽名
$arr[‘paySign‘] = $this->getSign($arr);
return $arr;
}
}
else
{
$error = curl_errno($ch);
curl_close($ch);
return ‘201 curl ‘.$error;
}
}

// 生成簽名
function getSign($params)
{
ksort($params); //將參數數組按照參數名ASCII碼從小到大排序
foreach ($params as $key => $item)
{
if (!empty($item))
{ //剔除參數值為空的參數
$newArr[] = $key.‘=‘.$item; // 整合新的參數數組
}
}
$stringA = implode("&", $newArr); //使用 & 符號連接參數
$stringSignTemp = $stringA."&key=".$this->key; //拼接key
// key是在商戶平臺API安全裏自己設置的
$stringSignTemp = MD5($stringSignTemp); //將字符串進行MD5加密
$sign = strtoupper($stringSignTemp); //將所有字符轉換為大寫
return $sign;
}

// 生成隨機字符串
function rand_code()
{
$str = ‘0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ‘;//62個字符
$str = str_shuffle($str);
$str = substr($str,0,32);
return $str;
}

// 數組轉化為xml
function ToXml($data=array())
{
// print_r($data);die;
if(!is_array($data) || count($data) <= 0)
{
return ‘數組異常‘;
}
$xml = "<xml>";
foreach ($data as $key=>$val){
if(is_array($val)){
$xml.="<".$key.">".arrayToXml($val)."</".$key.">";
}else{
$xml.="<".$key.">".$val."</".$key.">";
}
}
$xml.="</xml>";
return $xml;
}

// 將xml數據轉換為數組
function FromXml($xml){
if(!$xml){
echo "xml數據異常!";
}
//將XML轉為array
//禁止引用外部xml實體
libxml_disable_entity_loader(true);
$data = json_decode(json_encode(simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA)), true);
return $data;
}

2、返回H5頁面w.config數據。

public function actionWxpay(){

$model = new Indexs;
$arr = $model->pay();

$token = $model->getToken();
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$token&type=jsapi";
$ticket = file_get_contents($url);
$ticket = json_decode($ticket,true);
$noncestr = $model->rand_code();
$time = time();
$url = ‘http://‘.$_SERVER[‘HTTP_HOST‘].$_SERVER[‘REQUEST_URI‘];
$arrs = [
"noncestr" => $noncestr,
"jsapi_ticket" => $ticket["ticket"],
"timestamp" => $time,
"url" => $url
];
ksort($arrs);
$str = "";
foreach ($arrs as $key => $value) {
$str .= $key."=".$value."&";
}
$str = rtrim($str,"&");
$sign = sha1($str);
$data[‘appid‘] = $this->appid;
$data[‘time‘] = $time;
$data[‘noncestr‘] = $noncestr;
$data[‘sign‘] = $sign;
return $this->renderpartial(‘wxpay‘,[‘arr’=>$arr,‘data‘=>$data]);
}

3、wxpay.php頁面操作。

<script type="text/javascript">
wx.config({
debug: false, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。
appId: "<?=$data[‘appid‘]?>", // 必填,公眾號的唯一標識
timeStamp: <?=$data[‘time‘]?>, // 必填,生成簽名的時間戳
nonceStr: "<?=$data[‘noncestr‘]?>", // 必填,生成簽名的隨機串
signature: "<?=$data[‘sign‘]?>",// 必填,簽名
jsApiList: [
"checkJsApi"
// "chooseWXPay"
] // 必填,需要使用的JS接口列表"chooseWXPay",
});
wx.ready(function(){
// config信息驗證後會執行ready方法,所有接口調用都必須在config接口獲得結果之後,config是一個客戶端的異步操作,所以如果需要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則可以直接調用,不需要放在ready函數中。
wx.checkJsApi({
jsApiList: ["chooseWXPay"], // 需要檢測的JS接口列表,所有JS接口列表見附錄2,
success: function(res) {
// // 以鍵值對的形式返回,可用的api值true,不可用為false
// // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
}
});
wx.chooseWXPay({
timestamp: <?=$arr[‘timeStamp‘]?>, // 支付簽名時間戳,註意微信jssdk中的所有使用timestamp字段均為小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符
nonceStr: "<?=$arr[‘nonceStr‘]?>", // 支付簽名隨機串,不長於 32 位
package: "<?=$arr[‘package‘]?>", // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=\*\*\*)
signType: "<?=$arr[‘signType‘]?>", // 簽名方式,默認為‘SHA1‘,使用新版支付需傳入‘MD5‘
paySign: "<?=$arr[‘paySign‘]?>", // 支付簽名
success: function (res) {
/*支付成功*/
},
cancel: function(res){
/*支付取消*/
},
fail: function(res){
/*支付失敗*/
}
});
});
wx.error(function(res){
// config信息驗證失敗會執行error函數,如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數中查看,對於SPA可以在這裏更新簽名。
});
</script>

微信公共號H5支付。