tp5集合h5 wap和公眾號支付
阿新 • • 發佈:2018-11-10
控制器controller:
index.php
<?php namespace app\index\controller; use think\Controller; use think\Request; use app\index\model\Weixin; use app\index\model\Weixin_pay; use think\Session; use think\Db; use think\Log; class Index extends Controller { public function index() {$Weixin=new Weixin(); $code=(input('param.code')); if (!empty($code)) { $res=$Weixin->get_access_token($code); $userinfo=$Weixin->get_openid_userinfo($res['access_token'],$res['openid']); halt($userinfo); }$res=$Weixin->code_shouquan(); } public function pay() { $userAgent = $_SERVER['HTTP_USER_AGENT']; if (strpos($userAgent, 'MicroMessenger')) { $Weixin=new Weixin(); $code=(input('param.code')); if (!empty($code)) {$res=$Weixin->get_access_token($code); $userinfo=$Weixin->get_openid_userinfo($res['access_token'],$res['openid']); $openid=$userinfo['openid']; // halt($openid); $Weixin_pay=new Weixin_pay(); $total_fee=1; $body="JSAPI支付測試"; $order_sn=time(); $res=$Weixin_pay->pay($openid,$total_fee,$body,$order_sn); $this->assign("res",$res); return $this->fetch("index"); }else{ $res=$Weixin->code_shouquan(); } }else{ //非微信瀏覽器 $Weixin_pay=new Weixin_pay(); //h5支付不用傳遞openid 此處與微信jsapi支付不同 $openid=""; $total_fee=1; $body="wamp支付測試"; $order_sn=time(); $res=$Weixin_pay->payh5($openid,$total_fee,$body,$order_sn); // halt($res); $this->assign("res",$res); return $this->fetch("h5"); } } public function orderquery(){ $Weixin_pay=new Weixin_pay(); // $openid="oZX2QwaUBh37C4Ev7I-NUdp6udao"; $total_fee=1; $body="JSAPI支付測試"; $order_sn=time(); $res=$Weixin_pay-> orderquery(); } public function notify(){ $xml = $GLOBALS['HTTP_RAW_POST_DATA']; Log::record($xml); } }
model層
Weixin.php
<?php namespace app\index\model; use think\Db; use think\Validate; use think\Loader; use think\Model; class Weixin extends model { protected $appScrect; protected $appId; public function __construct($appScrect="xxxxxxxxx",$appId="xxxxxxxx"){ $this->appScrect=$appScrect; $this->appId=$appId; } public function code_shouquan(){ // echo $this->appScrect; // echo $this->appId; $redirect_uri=urlencode("你自己的域名/index/index/pay");//微信獲取網頁授權地址 // 1、引導使用者進入授權頁面同意授權,獲取code // 2、通過code換取網頁授權access_token // 3、如果需要,開發者可以重新整理網頁授權access_token,避免過期 // 4、通過網頁授權access_token和openid獲取使用者基本資訊(支援UnionID機制) $url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$this->appId."&redirect_uri=".$redirect_uri."&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"; header("Location: $url"); } public function get_access_token($code){ //檢測快取中是否有access_token(2小時),如果存在直接返回,不存在則檢測快取中的refresh_token(30天), // refresh_token如果存在呼叫重新整理快取;如果不存在重新發起授權code授權 $url="https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appId."&secret=".$this->appScrect."&code=".$code."&grant_type=authorization_code"; $res= file_get_contents($url); $res=json_decode($res,true); return $res; } public function get_refresh_token($refresh_token){ $url="https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=".$this->appId."&grant_type=refresh_token&refresh_token=".$refresh_token; $res= file_get_contents($url); $res=json_decode($res,true); return $res; } public function get_openid_userinfo($access_token,$openid){ $url="https://api.weixin.qq.com/sns/userinfo?access_token=".$access_token."&openid=".$openid."&lang=zh_CN"; $res= file_get_contents($url); $res=json_decode($res,true); return $res; } }
Weixin_pay.php
<?php namespace app\index\model; use think\Db; use think\Validate; use think\Loader; use think\Model; class Weixin_pay extends model { protected $appScrect;//微信公眾平臺的appscrect protected $appId;//微信公眾平臺appid protected $key;//微信商戶平臺配置的祕鑰 protected $mch_id;//微信商戶號 protected $values = array(); public function __construct($appScrect="xxxxxx",$appId="xxxxxx", $key="xxxxxx",$mch_id ='xxxxxx'){ $this->appScrect=$appScrect; $this->appId=$appId; $this->key=$key; $this->mch_id=$mch_id; } public function pay($openid,$total_fee,$body,$out_trade_no){ $config= config('wxpay'); $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; $notify_url ='http://'.$_SERVER['HTTP_HOST'].'/index/index/notify'; $onoce_str = $this->createNoncestr(); $data["appid"] = $this->appId; $data["body"] = $body; $data["mch_id"] = $this->mch_id; $data["nonce_str"] = $onoce_str; $data["notify_url"] = $notify_url; $data["out_trade_no"] = $out_trade_no; $data["spbill_create_ip"] = $this->get_client_ip(); $data["total_fee"] = $total_fee; $data["trade_type"] = "JSAPI"; $data["openid"] = $openid; $sign = $this->getSign($data); // halt($data); $data["sign"] = $sign; $xml = $this->arrayToXml($data); $response = $this->postXmlCurl($xml, $url); //將微信返回的結果xml轉成陣列 $response = $this->xmlToArray($response); $response['package']="prepay_id=".$response['prepay_id']; $jsapi=array(); $timeStamp = time(); $jsapi['appId']=($response["appid"]); $jsapi['timeStamp']=("$timeStamp"); $jsapi['nonceStr']=($this->createNoncestr()); $jsapi['package']=("prepay_id=" . $response['prepay_id']); $jsapi['signType']=("MD5"); $jsapi['paySign']=($this->getSign($jsapi)); $parameters = json_encode($jsapi); // halt($jsapi); //請求資料,統一下單 return $parameters; } public function payh5($openid,$total_fee,$body,$out_trade_no){ $config= config('wxpay'); $ip= request()->ip(); $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; $notify_url ='http://'.$_SERVER['HTTP_HOST'].'/index/index/notify'; $onoce_str = $this->createNoncestr(); $data["appid"] = $this->appId; $data["body"] = $body; $data["mch_id"] = $this->mch_id; $data["nonce_str"] = $onoce_str; $data["notify_url"] = $notify_url; $data["out_trade_no"] = $out_trade_no; $data["spbill_create_ip"] = $ip; $data["total_fee"] = $total_fee; $data["trade_type"] = "MWEB"; // $data["openid"] = $openid; $data["scene_info"] = "{'h5_info': {'type':'Wap','wap_url': $notify_url,'wap_name': '測試充值'}}"; $sign = $this->getSign($data); // halt($data); $data["sign"] = $sign; $xml = $this->arrayToXml($data); $response = $this->postXmlCurl($xml, $url); //將微信返回的結果xml轉成陣列 $response = $this->xmlToArray($response); //請求資料,統一下單 return $response; } public static function getNonceStr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } // /*生成簽名*/ public function getSign($Obj){ foreach ($Obj as $k => $v){ $Parameters[$k] = $v; } //簽名步驟一:按字典序排序引數 ksort($Parameters); $String = $this->formatBizQueryParaMap($Parameters, false); //echo '【string1】'.$String.'</br>'; //簽名步驟二:在string後加入KEY $String = $String."&key=".$this->key; //echo "【string2】".$String."</br>"; //簽名步驟三:MD5加密 $String = md5($String); //echo "【string3】 ".$String."</br>"; //簽名步驟四:所有字元轉為大寫 $result_ = strtoupper($String); //echo "【result】 ".$result_."</br>"; return $result_; } /** * 作用:產生隨機字串,不長於32位 */ public function createNoncestr( $length = 32 ){ $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } //陣列轉xml public function arrayToXml($arr){ $xml = "<xml>"; foreach ($arr as $key=>$val){ if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; } /** * 作用:將xml轉為array */ public function xmlToArray($xml){ //將XML轉為array $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $array_data; } /** * 作用:以post方式提交xml到對應的介面url */ public function postXmlCurl($xml,$url,$second=30){ //初始化curl $ch = curl_init(); //設定超時 curl_setopt($ch, CURLOPT_TIMEOUT, $second); //這裡設定代理,如果有的話 //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8'); //curl_setopt($ch,CURLOPT_PROXYPORT, 8080); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE); //設定header curl_setopt($ch, CURLOPT_HEADER, FALSE); //要求結果為字串且輸出到螢幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); //post提交方式 curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); //執行curl $data = curl_exec($ch); //返回結果 if($data){ curl_close($ch); return $data; }else{ $error = curl_errno($ch); echo "curl出錯,錯誤碼:$error"."<br>"; curl_close($ch); return false; } } /* 獲取當前伺服器的IP */ public function get_client_ip(){ if ($_SERVER['REMOTE_ADDR']) { $cip = $_SERVER['REMOTE_ADDR']; } elseif (getenv("REMOTE_ADDR")) { $cip = getenv("REMOTE_ADDR"); } elseif (getenv("HTTP_CLIENT_IP")) { $cip = getenv("HTTP_CLIENT_IP"); } else { $cip = "unknown"; } return $cip; } /** * 作用:格式化引數,簽名過程需要使用 */ public function formatBizQueryParaMap($paraMap, $urlencode){ $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v){ if($urlencode){ $v = urlencode($v); } $buff .= $k . "=" . $v . "&"; } $reqPar; if (strlen($buff) > 0){ $reqPar = substr($buff, 0, strlen($buff)-1); } return $reqPar; } public function MakeSign($unifiedorder) { $this->values=$unifiedorder; //簽名步驟一:按字典序排序引數 // ksort($this->values); $string = $this->ToUrlParams(); // halt($string); //簽名步驟二:在string後加入KEY $string = $string . "&key=".$this->key; //簽名步驟三:MD5加密 $string = md5($string); //簽名步驟四:所有字元轉為大寫 $result = strtoupper($string); return $result; } public function ToUrlParams() { $buff = ""; foreach ($this->values as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } function array2xml($array) { $xml='<xml>'; foreach($array as $key=>$val){ if(is_numeric($key)){ $key="item id=\"$key\""; }else{ //去掉空格,只取空格之前文字為key list($key,)=explode(' ',$key); } $xml.="<$key>"; $xml.=is_array($val)?$this->_array2xml($val):$val; //去掉空格,只取空格之前文字為key list($key,)=explode(' ',$key); $xml.="</$key>"; } $xml.="</xml>"; return $xml; } function xml2array($xml) { //禁止引用外部xml實體 libxml_disable_entity_loader(true); $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $values; } public function request_post($url = '', $param = '') { if (empty($url) || empty($param)) { return false; } $postUrl = $url; $curlPost = $param; $ch = curl_init(); //初始化curl curl_setopt($ch, CURLOPT_URL, $postUrl); //抓取指定網頁 curl_setopt($ch, CURLOPT_HEADER, 0); //設定header curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求結果為字串且輸出到螢幕上 curl_setopt($ch, CURLOPT_POST, 1); //post提交方式 curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost); $data = curl_exec($ch); //執行curl curl_close($ch); return $data; } function curl_post_ssl($url, $vars, $second=30,$aHeader=array()) { $ch = curl_init(); //curl_setopt($ch,CURLOPT_VERBOSE,'1'); curl_setopt($ch,CURLOPT_TIMEOUT,$second); curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false); curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLCERT,'/data/cert/php.pem'); curl_setopt($ch,CURLOPT_SSLCERTPASSWD,'1234'); curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM'); curl_setopt($ch,CURLOPT_SSLKEY,'/data/cert/php_private.pem'); if( count($aHeader) >= 1 ){ curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader); } curl_setopt($ch,CURLOPT_POST, 1); curl_setopt($ch,CURLOPT_POSTFIELDS,$vars); $data = curl_exec($ch); curl_close($ch); if($data){ return $data; }else{ return false; } } }