tp5微信JSAPI支付(公眾號)


 剛剛接觸支付的時候會遇到很多坑.官方文檔也不是很全面,在網上搜索出來很多版本也不知道哪個好用

下面是本人在tp5內使用的全套代碼(其他框架寫法稍作修改即可).附贈微信支付類

/****************************************調該方法發起支付*******************************************/
  //jsapi微信支付
public function wxpay() {
Vendor("lib.Wechat");
$wechat = new \Wechat();
$openid = Cookie::get('openid'); //公眾號支付和小程序支付必要參數
$body = '微信支付';
$attach = input('id');
$number=DB::name('order')->where('id',$attach)->value('order_number'); //唯一訂單號
$price = 0.01; //價格
$notify_url = 'http://'.$_SERVER['HTTP_HOST'].'/index/Goods/xiadans'; //回調地址
// dump($notify_url);die;
$res = $wechat->createPayOrder($body, $attach, $number, $price, $notify_url, $openid); //發起支付

$data['info']='微信支付';
$data['status']='1';
$data['data']=$res;
return json($data);
}

 /****************************************微信支付回調代碼*******************************************/
    public function xiadans(){
//獲取接口數據,如果$_REQUEST拿不到數據,則使用file_get_contents函數獲取
$post = $_REQUEST['/home/Goods/xiadans'];
if ($post == null) {
$post = file_get_contents("php://input");
}

if ($post == null) {
$post = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
}

if (empty($post) || $post == null || $post == '') {
//阻止微信接口反復回調接口 文檔地址 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7,下面這句非常重要!!!
$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
echo $str;
exit('Notify 非法回調');
}

/*****************微信回調返回數據樣例*******************
$post = '<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx2421b1c4370ec43b]]></appid>
<mch_id><![CDATA[10000100]]></mch_id>
<nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
<sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
<trade_type><![CDATA[APP]]></trade_type>
</xml>';
*************************微信回調返回*****************/

libxml_disable_entity_loader(true); //禁止引用外部xml實體

$xml = simplexml_load_string($post, 'SimpleXMLElement', LIBXML_NOCDATA);//XML轉數組

$post_data = (array)$xml;
/** 解析出來的數組
*Array
* (
* [appid] => wx1c870c0145984d30
* [bank_type] => CFT
* [cash_fee] => 100
* [fee_type] => CNY
* [is_subscribe] => N
* [mch_id] => 1297210301
* [nonce_str] => gkq1x5fxejqo5lz5eua50gg4c4la18vy
* [openid] => olSGW5BBvfep9UhlU40VFIQlcvZ0
* [out_trade_no] => fangchan_588796
* [result_code] => SUCCESS
* [return_code] => SUCCESS
* [sign] => F6890323B0A6A3765510D152D9420EAC
* [time_end] => 20180626170839
* [total_fee] => 100
* [trade_type] => JSAPI
* [transaction_id] => 4200000134201806265483331660
* )
**/
//訂單號
$order_id = isset($post_data['attach']) && !empty($post_data['attach']) ? $post_data['attach'] : 0;

//查詢訂單信息
$order_info = DB::name('order')->where('id',$order_id)->find();


if(count($order_info) > 0){
/* //查詢平台信息
$platform_info = DB::fetch_first("SELECT * FROM pingtaiInfo WHERE `open_pid`= {$order_info['part1']}");

//平台支付key
$wxpay_key = $platform_info['zhifu_key'];

//接收到的簽名
$post_sign = $post_data['sign'];
unset($post_data['sign']);

//重新生成簽名
$newSign = MakeSign($post_data,$wxpay_key);

//簽名統一,則更新數據庫
if($post_sign == $newSign){

$updateData = array();
$updateData['pay_time'] = TIMESTAMP; //支付時間
$updateData['order_status'] = 2; //訂單狀態

//更新order數據庫
//Do what you want...*/
$update['status'] = 2;
Db::name('order')->where('id',$order_id)->update($update);
// }
}

//阻止微信接口反復回調接口 文檔地址 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7,下面這句非常重要!!!
$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
echo $str;

function MakeSign($params,$key){
//簽名步驟一:按字典序排序數組參數
ksort($params);
$string = ToUrlParams($params); //參數進行拼接key=value&k=v
//簽名步驟二:在string后加入KEY
$string = $string . "&key=".$key;
//簽名步驟三:MD5加密
$string = md5($string);
//簽名步驟四:所有字符轉為大寫
$result = strtoupper($string);
return $result;
}

function ToUrlParams( $params ){
$string = '';
if( !empty($params) ){
$array = array();
foreach( $params as $key => $value ){
$array[] = $key.'='.$value;
}
$string = implode("&",$array);
}
return $string;
}
}


/*************************************以下是微信支付三方類的全部代碼****************************************/

<?php


/**
* 自定義微信工具類
*/
class Wechat {

  /**
   *以下內容均在商戶后台獲取
   */
public function __construct() {
$this->token = ''; //商戶平台token(商戶平台自己設置)
$this->appid = ''; //appid
$this->appsec = ''; //appsecrt
$this->mchid = ''; //商戶id
$this->mchkey = ''; //商戶秘鑰
$this->accessToken = $this->getAccessToken();
}

/**
* 生成簽名
*/
public function getSign($data){
ksort($data);
$data['key'] = $this->mchkey;
return md5(urldecode(http_build_query($data)));
}


/**
* 獲取AccessToken
*/
public function getAccessToken(){
$cn = curl_init();
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appid&secret=$this->appsec";
//設置傳輸選項值
curl_setopt($cn,CURLOPT_URL,$url);
//設置傳輸選項值
curl_setopt($cn,CURLOPT_RETURNTRANSFER,1);
//執行 curl
$res = curl_exec($cn);
//關閉 curl
curl_close($cn);
// echo $res;
$data = json_decode($res,true);
$access_token = $data['access_token'];
return $access_token;
}

/**
* 獲取微信js-sdk票據
*/
public function getJsApiTicket(){
$WechatTicket = M('WechatTicket') -> where(array('id'=>1)) -> find();
if(time()>$WechatTicket['expires_times']){
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$this->accessToken";
$res = $this->http_get($url);
$arr = json_decode($res,true);
$data = array('id'=>1,'ticket'=>$arr['ticket'],'expires_times'=>time() + $arr[expires_in] - 300);
M('wechat_ticket') -> save($data);
return M('wechat_ticket') -> where(array('id'=>1)) -> getField('ticket');
}else{
return $WechatTicket['ticket'];
}
}

/**
* 獲取微信js-sdk簽名
*/
public function getSignPackage($url) {
$timestamp = time();
$nonceStr = $this->createNonceStr();
$string = "jsapi_ticket=$this->JsApiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
$signature = sha1($string);
$signPackage = array(
"appId" => $this->appid,
"nonceStr" => $nonceStr,
"timestamp" => $timestamp,
"url" => $url,
"signature" => $signature,
"rawString" => $string
);
return $signPackage;
}

/**
* 生成隨機字符串
*/
private function createNonceStr($length = 16) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}

/**
* 獲取網頁授權地址
*/
public function getAuthCode($callback,$state,$scope){
$url = urlencode($callback);
return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$this->appid&redirect_uri=$url&response_type=code&scope=$scope&state=$state#wechat_redirect";
}

/**
* 獲取Auth協議AccessToken信息
* $res 已轉換為數組類型
*/
public function getAuthAccessToken($code){
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$this->appid&secret=$this->appsec&code=$code&grant_type=authorization_code";
$res= json_decode($this->http_get($url),true);
return $res;
}

/**
* 試用Auth協議獲取用戶信息
* $res 已轉換為數組類型
*/
public function getAuthUserinfo($accessToken,$openId){
$url = "https://api.weixin.qq.com/sns/userinfo?access_token=$accessToken&openid=$openId&lang=zh_CN";
$res= json_decode($this->http_get($url),true);
return $res;
}

/**
* 創建自定義菜單
* 創建成功微信服務器返回json:{"errcode":0,"errmsg":"ok"}
* 創建失敗微信服務器返回json:{"errcode":40018,"errmsg":"invalid button name size"}
* $res 已轉換為數組類型
*/
public function createWechatMenu($data){
$url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=$this->accessToken";
$res= json_decode($this->http_post($url, $data),true);
return $res;
}

/**
* 獲取用戶基本信息
*/
public function getSubscribe($openid){
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=$this->accessToken&openid=$openid&lang=zh_CN";
$res = json_decode($this->http_get($url),true);
return $res;
}

/**
* 企業付款
* $number
* $openid
* $truename
* $amount
* $desc
* $ip
*/
public function createWechatPay($number,$openid,$truename,$amount,$desc,$ip){
$url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';

$data['mch_appid'] = $this->appid;
$data['mchid'] = $this->mchid;
$data['nonce_str'] = $this->createNonceStr();
$data['partner_trade_no'] = $number;//訂單號
$data['openid'] = $openid;
$data['check_name'] = 'FORCE_CHECK';
$data['re_user_name'] = $truename;
$data['amount'] = $amount * 100;
$data['desc'] = $desc;
$data['spbill_create_ip'] = $ip;
$data['sign'] = $this->getSign($data);

$ch = curl_init ();
$MENU_URL="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
curl_setopt ( $ch, CURLOPT_URL, $MENU_URL );
curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );

$zs1="D:\www\sotjb\cert\apiclient_cert.pem";
$zs2="D:\www\sotjb\cert\apiclient_key.pem";
curl_setopt($ch,CURLOPT_SSLCERT,$zs1);
curl_setopt($ch,CURLOPT_SSLKEY,$zs2);

curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
curl_setopt ( $ch, CURLOPT_AUTOREFERER, 1 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $this->arrayToXml($data) );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );

$info = curl_exec ( $ch );

if (curl_errno ( $ch )) {
echo 'Errno' . curl_error ( $ch );
}

curl_close( $ch );
$res = $this->xmlToArray($info);
return $res['result_code'];
}

/**
* 微信支付-下單請求
* $body
* $number
* $price
* $notify_url
* $openid
*/
public function createPayOrder($body,$attach,$number,$price,$notify_url,$openid){
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

$data['appid'] = $this->appid;
$data['mch_id'] = $this->mchid;
$data['nonce_str'] = $this->createNonceStr();
$data['body'] = $body;
$data['attach'] = $attach;
$data['out_trade_no'] = $number;
$data['total_fee'] = $price*100;
$data['spbill_create_ip'] = $this->get_client_ip();
$data['notify_url'] = $notify_url;
$data['trade_type'] = 'JSAPI';
$data['openid'] = $openid;
$data['sign'] = $this->getSign($data);

$res = $this->xmlToArray($this->http_post($url, $this->arrayToXml($data)));
// dump($res);die();
if($res['return_code']=='SUCCESS'){
if ($res['result_code'] == 'SUCCESS') {
unset($data);
$data['appId'] = $this->appid;
$data['timeStamp'] = (string)NOW_TIME;
$data['nonceStr'] = $this->createNonceStr();
$data['package'] = 'prepay_id='.$res['prepay_id'];
$data['signType'] = 'MD5';
$data['paySign'] = $this->getSign($data);
return json_encode($data);
}
if($res['result_code']=='FAIL'&& $res['err_code']=='OUT_TRADE_NO_USED'){
return "repeat";//訂單號重復
}
if($res['result_code']=='FAIL'&& $res['err_code']=='ORDERPAID'){
return "payed";//已經支付
}
}else{
return $res;
}
}

/**
* 支付結果通知
*/
public function getNotify() {
return $res = $this->xmlToArray($GLOBALS["HTTP_RAW_POST_DATA"]);
}

/**
* 微信支付通知回應
*/
public function returnNotify() {
$data = array('return_code'=>'SUCCESS');
exit($this->arrayToXml($data));
}

/**
* 數組轉xml
*/
public function arrayToXml($data){
$xml='<xml>';
foreach ($data as $k => $v){
$xml.="<".$k.">".$v."</".$k.">";
}
$xml.="</xml>";
return $xml;
}

/**
* xml轉數組
*/
public function xmlToArray($xml){
return (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
}

/**
* GET 請求
* @param string $url
*/
public function http_get($url){
$oCurl = curl_init();
if(stripos($url,"https://")!==FALSE){
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
}
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if(intval($aStatus["http_code"])==200){
return $sContent;
}else{
return false;
}
}

/**
* POST 請求
*/
public function http_post($url,$data,$post_file=false){
$oCurl = curl_init();
if(stripos($url,"https://")!==FALSE){
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($oCurl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
}
if (is_string($data) || $post_file) {
$strPOST = $data;
} else {
$aPOST = array();
foreach($data as $key=>$val){
$aPOST[] = $key."=".urlencode($val);
}
$strPOST = join("&", $aPOST);
}
curl_setopt($oCurl, CURLOPT_URL, $url);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt($oCurl, CURLOPT_POST,true);
curl_setopt($oCurl, CURLOPT_POSTFIELDS,$strPOST);
$sContent = curl_exec($oCurl);
$aStatus = curl_getinfo($oCurl);
curl_close($oCurl);
if(intval($aStatus["http_code"])==200){
return $sContent;
}else{
return false;
}
}

/**
* 帶證書的支付請求
* @param unknown_type $url
* @param unknown_type $params
* @param unknown_type $method
* @param unknown_type $ssl
* @return boolean|mixed
*/
private function http($url, $params = array(), $method = 'GET', $ssl = false){
$opts = array(
CURLOPT_TIMEOUT => 30,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false
);
/* 根據請求類型設置特定參數 */
switch(strtoupper($method)){
case 'GET':
$opts[CURLOPT_URL] = $url .'?'. http_build_query($params);
break;
case 'POST':
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = $params;
break;
}
if ($ssl) {
$pemPath = 'D:\www\sotjb\cert';
$pemCret = $pemPath.'\apiclient_cert.pem';
$pemKey = $pemPath.'\apiclient_key.pem';
if (!file_exists($pemCret)) {
echo '證書不存在1';
return false;
}
if (!file_exists($pemKey)) {
echo '密鑰不存在';
return false;
}
$opts[CURLOPT_SSLCERTTYPE] = 'PEM';
$opts[CURLOPT_SSLCERT] = $pemCret;
$opts[CURLOPT_SSLKEYTYPE] = 'PEM';
$opts[CURLOPT_SSLKEY] = $pemKey;
}
/* 初始化並執行curl請求 */
$ch = curl_init();
curl_setopt_array($ch, $opts);
$data = curl_exec($ch);
$err = curl_errno($ch);
$errmsg = curl_error($ch);
curl_close($ch);
if ($err > 0) {
echo $errmsg;
return false;
}else {
return $data;
}
}

public function get_client_ip(){
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'),'unknown')) {

$ip = getenv('HTTP_CLIENT_IP');

} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'),'unknown')) {

$ip = getenv('HTTP_X_FORWARDED_FOR');

} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'),'unknown')) {

$ip = getenv('REMOTE_ADDR');

} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {

$ip = $_SERVER['REMOTE_ADDR'];

}

return preg_match ( '/[\d\.]{7,15}/', $ip, $matches ) ? $matches [0] : '';
}

}

?>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM