溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PHP微信支付開發(fā)的示例分析

發(fā)布時間:2021-09-01 10:46:49 來源:億速云 閱讀:103 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹PHP微信支付開發(fā)的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

具體內(nèi)容如下

1.開發(fā)環(huán)境
Thinkphp 3.2.3
微信:服務(wù)號,已認證
開發(fā)域名:http://test.paywechat.com (自定義的域名,外網(wǎng)不可訪問)

2.需要相關(guān)文件和權(quán)限
微信支付需申請開通
微信公眾平臺開發(fā)者文檔:http://mp.weixin.qq.com/wiki/home/index.html
微信支付開發(fā)者文檔:https://pay.weixin.qq.com/wiki/doc/api/index.html
微信支付SDK下載地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

3.開發(fā)
下載好微信支付PHP版本的SDK,文件目錄為下圖:

PHP微信支付開發(fā)的示例分析

PHP微信支付開發(fā)的示例分析 

把微信支付SDK的Cert和Lib目錄放入Thinkphp,目錄為

PHP微信支付開發(fā)的示例分析 

現(xiàn)在介紹微信支付授權(quán)目錄問題,首先是微信支付開發(fā)配置里面的支付授權(quán)目錄填寫,

PHP微信支付開發(fā)的示例分析

然后填寫JS接口安全域。

PHP微信支付開發(fā)的示例分析

最后設(shè)置網(wǎng)頁授權(quán)

PHP微信支付開發(fā)的示例分析

PHP微信支付開發(fā)的示例分析

這些設(shè)置完,基本完成一半,注意設(shè)置的目錄和我thinkphp里面的目錄。

PHP微信支付開發(fā)的示例分析

4.微信支付配置

PHP微信支付開發(fā)的示例分析

把相關(guān)配置填寫正確。

/**
* 配置賬號信息
*/

class WxPayConfig
{
 //=======【基本信息設(shè)置】=====================================
 //
 /**
 * TODO: 修改這里配置為您自己申請的商戶信息
 * 微信公眾號信息配置
 * 
 * APPID:綁定支付的APPID(必須配置,開戶郵件中可查看)
 * 
 * MCHID:商戶號(必須配置,開戶郵件中可查看)
 * 
 * KEY:商戶支付密鑰,參考開戶郵件設(shè)置(必須配置,登錄商戶平臺自行設(shè)置)
 * 設(shè)置地址:https://pay.weixin.qq.com/index.php/account/api_cert
 * 
 * APPSECRET:公眾帳號secert(僅JSAPI支付的時候需要配置, 登錄公眾平臺,進入開發(fā)者中心可設(shè)置),
 * 獲取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
 * @var string
 */
 const APPID = '';
 const MCHID = '';
 const KEY = '';
 const APPSECRET = '';

 //=======【證書路徑設(shè)置】=====================================
 /**
 * TODO:設(shè)置商戶證書路徑
 * 證書路徑,注意應(yīng)該填寫絕對路徑(僅退款、撤銷訂單時需要,可登錄商戶平臺下載,
 * API證書下載地址:https://pay.weixin.qq.com/index.php/account/api_cert,下載之前需要安裝商戶操作證書)
 * @var path
 */
 const SSLCERT_PATH = '../cert/apiclient_cert.pem';
 const SSLKEY_PATH = '../cert/apiclient_key.pem';

 //=======【curl代理設(shè)置】===================================
 /**
 * TODO:這里設(shè)置代理機器,只有需要代理的時候才設(shè)置,不需要代理,請設(shè)置為0.0.0.0和0
 * 本例程通過curl使用HTTP POST方法,此處可修改代理服務(wù)器,
 * 默認CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此時不開啟代理(如有需要才設(shè)置)
 * @var unknown_type
 */
 const CURL_PROXY_HOST = "0.0.0.0";//"10.152.18.220";
 const CURL_PROXY_PORT = 0;//8080;

 //=======【上報信息配置】===================================
 /**
 * TODO:接口調(diào)用上報等級,默認緊錯誤上報(注意:上報超時間為【1s】,上報無論成敗【永不拋出異?!?,
 * 不會影響接口調(diào)用流程),開啟上報之后,方便微信監(jiān)控請求調(diào)用的質(zhì)量,建議至少
 * 開啟錯誤上報。
 * 上報等級,0.關(guān)閉上報; 1.僅錯誤出錯上報; 2.全量上報
 * @var int
 */
 const REPORT_LEVENL = 1;
}

現(xiàn)在開始貼出代碼:

namespace Wechat\Controller;
use Think\Controller;
/**
 * 父類控制器,需要繼承
 * @file ParentController.class.php
 * @author Gary <lizhiyong2204@sina.com>
 * @date 2015年8月4日
 * @todu
 */
class ParentController extends Controller { 
 protected $options = array (
 'token' => '', // 填寫你設(shè)定的key
 'encodingaeskey' => '', // 填寫加密用的EncodingAESKey
 'appid' => '', // 填寫高級調(diào)用功能的app id
 'appsecret' => '', // 填寫高級調(diào)用功能的密鑰
 'debug' => false,
 'logcallback' => ''
 ); 
 public $errCode = 40001; 
 public $errMsg = "no access"; 

 /**
 * 獲取access_token
 * @return mixed|boolean|unknown
 */
 public function getToken(){
 $cache_token = S('exp_wechat_pay_token');
 if(!empty($cache_token)){
 return $cache_token;
 }
 $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s';
 $url = sprintf($url,$this->options['appid'],$this->options['appsecret']); 
 $result = $this->http_get($url);
 $result = json_decode($result,true); 
 if(empty($result)){
 return false;
 } 
 S('exp_wechat_pay_token',$result['access_token'],array('type'=>'file','expire'=>3600));
 return $result['access_token'];
 }

 /**
 * 發(fā)送客服消息
 * @param array $data 消息結(jié)構(gòu){"touser":"OPENID","msgtype":"news","news":{...}}
 */
 public function sendCustomMessage($data){
 $token = $this->getToken();
 if (empty($token)) return false; 
 $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s';
 $url = sprintf($url,$token);
 $result = $this->http_post($url,self::json_encode($data));
 if ($result)
 {
 $json = json_decode($result,true);
 if (!$json || !empty($json['errcode'])) {
 $this->errCode = $json['errcode'];
 $this->errMsg = $json['errmsg'];
 return false;
 }
 return $json;
 }
 return false;
 }

 /**
 * 發(fā)送模板消息
 * @param unknown $data
 * @return boolean|unknown
 */
 public function sendTemplateMessage($data){
 $token = $this->getToken();
 if (empty($token)) return false;
 $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";
 $url = sprintf($url,$token);
 $result = $this->http_post($url,self::json_encode($data));
 if ($result)
 {
 $json = json_decode($result,true);
 if (!$json || !empty($json['errcode'])) {
 $this->errCode = $json['errcode'];
 $this->errMsg = $json['errmsg'];
 return false;
 }
 return $json;
 }
 return false;
 }


 public function getFileCache($name){
 return S($name);
 }

 /**
 * 微信api不支持中文轉(zhuǎn)義的json結(jié)構(gòu)
 * @param array $arr
 */
 static function json_encode($arr) {
 $parts = array ();
 $is_list = false;
 //Find out if the given array is a numerical array
 $keys = array_keys ( $arr );
 $max_length = count ( $arr ) - 1;
 if (($keys [0] === 0) && ($keys [$max_length] === $max_length )) { //See if the first key is 0 and last key is length - 1
 $is_list = true;
 for($i = 0; $i < count ( $keys ); $i ++) { //See if each key correspondes to its position
 if ($i != $keys [$i]) { //A key fails at position check.
  $is_list = false; //It is an associative array.
  break;
 }
 }
 }
 foreach ( $arr as $key => $value ) {
 if (is_array ( $value )) { //Custom handling for arrays
 if ($is_list)
  $parts [] = self::json_encode ( $value ); /* :RECURSION: */
 else
  $parts [] = '"' . $key . '":' . self::json_encode ( $value ); /* :RECURSION: */
 } else {
 $str = '';
 if (! $is_list)
  $str = '"' . $key . '":';
 //Custom handling for multiple data types
 if (!is_string ( $value ) && is_numeric ( $value ) && $value<2000000000)
  $str .= $value; //Numbers
 elseif ($value === false)
 $str .= 'false'; //The booleans
 elseif ($value === true)
 $str .= 'true';
 else
  $str .= '"' . addslashes ( $value ) . '"'; //All other things
 // :TODO: Is there any more datatype we should be in the lookout for? (Object?)
 $parts [] = $str;
 }
 }
 $json = implode ( ',', $parts );
 if ($is_list)
 return '[' . $json . ']'; //Return numerical JSON
 return '{' . $json . '}'; //Return associative JSON
 }

 /**
 +----------------------------------------------------------
 * 生成隨機字符串
 +----------------------------------------------------------
 * @param int $length 要生成的隨機字符串長度
 * @param string $type 隨機碼類型:0,數(shù)字+大小寫字母;1,數(shù)字;2,小寫字母;3,大寫字母;4,特殊字符;-1,數(shù)字+大小寫字母+特殊字符
 +----------------------------------------------------------
 * @return string
 +----------------------------------------------------------
 */
 static public function randCode($length = 5, $type = 2){
 $arr = array(1 => "0123456789", 2 => "abcdefghijklmnopqrstuvwxyz", 3 => "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 4 => "~@#$%^&*(){}[]|");
 if ($type == 0) {
 array_pop($arr);
 $string = implode("", $arr);
 } elseif ($type == "-1") {
 $string = implode("", $arr);
 } else {
 $string = $arr[$type];
 }
 $count = strlen($string) - 1;
 $code = '';
 for ($i = 0; $i < $length; $i++) {
 $code .= $string[rand(0, $count)];
 }
 return $code;
 } 


 /**
 * GET 請求
 * @param string $url
 */
 private 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 請求
 * @param string $url
 * @param array $param
 * @param boolean $post_file 是否文件上傳
 * @return string content
 */
 private function http_post($url,$param,$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($param) || $post_file) {
 $strPOST = $param;
 } else {
 $aPOST = array();
 foreach($param 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;
 }
 }
}
namespace Wechat\Controller;
use Wechat\Controller\ParentController;
/**
 * 微信支付測試控制器
 * @file TestController.class.php
 * @author Gary <lizhiyong2204@sina.com>
 * @date 2015年8月4日
 * @todu
 */
class TestController extends ParentController {
 private $_order_body = 'xxx';
 private $_order_goods_tag = 'xxx';
 public function __construct(){
 parent::__construct();
 require_once ROOT_PATH."Api/lib/WxPay.Api.php";
 require_once ROOT_PATH."Api/lib/WxPay.JsApiPay.php";
 }

 public function index(){
 //①、獲取用戶openid
 $tools = new \JsApiPay();
 $openId = $tools->GetOpenid(); 
 //②、統(tǒng)一下單
 $input = new \WxPayUnifiedOrder(); 
 //商品描述
 $input->SetBody($this->_order_body);
 //附加數(shù)據(jù),可以添加自己需要的數(shù)據(jù),微信回異步回調(diào)時會附加這個數(shù)據(jù)
 $input->SetAttach('xxx');
 //商戶訂單號
 $out_trade_no = \WxPayConfig::MCHID.date("YmdHis");
 $input->SetOut_trade_no($out_trade_no);
 //總金額,訂單總金額,只能為整數(shù),單位為分 
 $input->SetTotal_fee(1);
 //交易起始時間
 $input->SetTime_start(date("YmdHis"));
 //交易結(jié)束時間
 $input->SetTime_expire(date("YmdHis", time() + 600));
 //商品標記
 $input->SetGoods_tag($this->_order_goods_tag);
 //通知地址,接收微信支付異步通知回調(diào)地址 SITE_URL=http://test.paywechat.com/Charge
 $notify_url = SITE_URL.'/index.php/Test/notify.html';
 $input->SetNotify_url($notify_url);
 //交易類型
 $input->SetTrade_type("JSAPI");
 $input->SetOpenid($openId);
 $order = \WxPayApi::unifiedOrder($input);
 $jsApiParameters = $tools->GetJsApiParameters($order);
 //獲取共享收貨地址js函數(shù)參數(shù)
 $editAddress = $tools->GetEditAddressParameters();

 $this->assign('openId',$openId);
 $this->assign('jsApiParameters',$jsApiParameters);
 $this->assign('editAddress',$editAddress);
 $this->display(); 
 }

 /**
 * 異步通知回調(diào)方法
 */
 public function notify(){
 require_once ROOT_PATH."Api/lib/notify.php";
 $notify = new \PayNotifyCallBack();
 $notify->Handle(false);
 //這里的IsSuccess是我自定義的一個方法,后面我會貼出這個文件的代碼,供參考。
 $is_success = $notify->IsSuccess(); 
 $bdata = $is_success['data']; 
 //支付成功
 if($is_success['code'] == 1){ 
 $news = array(
  'touser' => $bdata['openid'],
  'msgtype' => 'news',
  'news' => array (
  'articles'=> array (
   array(
   'title' => '訂單支付成功',
   'description' => "支付金額:{$bdata['total_fee']}\n".
   "微信訂單號:{$bdata['transaction_id']}\n"
   'picurl' => '',
   'url' => '' 
   )

  )
  )
 );
 //發(fā)送微信支付通知
 $this->sendCustomMessage($news); 
 }else{//支付失敗

 }
 }

 /**
 * 支付成功頁面
 * 不可靠的回調(diào)
 */
 public function ajax_PaySuccess(){
 //訂單號
 $out_trade_no = I('post.out_trade_no');
 //支付金額
 $total_fee = I('post.total_fee');
 /*相關(guān)邏輯處理*/

 }

貼上模板HTML

<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>
 <script type="text/javascript">
 //調(diào)用微信JS api 支付
 function jsApiCall()
 {
 WeixinJSBridge.invoke(
 'getBrandWCPayRequest',
 {$jsApiParameters},
 function(res){
 WeixinJSBridge.log(res.err_msg);
 //取消支付
 if(res.err_msg == 'get_brand_wcpay_request:cancel'){
 //處理取消支付的事件邏輯
 }else if(res.err_msg == "get_brand_wcpay_request:ok"){
 /*使用以上方式判斷前端返回,微信團隊鄭重提示:
 res.err_msg將在用戶支付成功后返回 ok,但并不保證它絕對可靠。
 這里可以使用Ajax提交到后臺,處理一些日志,如Test控制器里面的ajax_PaySuccess方法。
 */
 }
 alert(res.err_code+res.err_desc+res.err_msg);
 }
 );
 }

 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();
 }
 }
 //獲取共享地址
 function editAddress()
 {
 WeixinJSBridge.invoke(
 'editAddress',
 {$editAddress},
 function(res){
 var value1 = res.proviceFirstStageName;
 var value2 = res.addressCitySecondStageName;
 var value3 = res.addressCountiesThirdStageName;
 var value4 = res.addressDetailInfo;
 var tel = res.telNumber; 
 alert(value1 + value2 + value3 + value4 + ":" + tel);
 }
 );
 }

 window.onload = function(){
 if (typeof WeixinJSBridge == "undefined"){
 if( document.addEventListener ){
 document.addEventListener('WeixinJSBridgeReady', editAddress, false);
 }else if (document.attachEvent){
 document.attachEvent('WeixinJSBridgeReady', editAddress); 
 document.attachEvent('onWeixinJSBridgeReady', editAddress);
 }
 }else{
 editAddress();
 }
 };

 </script>
</head>
<body>
 <br/>
 <font color="#9ACD32"><b>該筆訂單支付金額為<span >1分</span>錢</b></font><br/><br/>
 <div align="center">
 <button  type="button" onclick="callpay()" >立即支付</button>
 </div>
</body>
</html>

notify.php文件代碼,這里有在官方文件里新添加的一個自定義方法。

require_once ROOT_PATH."Api/lib/WxPay.Api.php";
require_once ROOT_PATH.'Api/lib/WxPay.Notify.php';
require_once ROOT_PATH.'Api/lib/log.php';

//初始化日志
$logHandler= new \CLogFileHandler(ROOT_PATH."/logs/".date('Y-m-d').'.log');
$log = \Log::Init($logHandler, 15);

class PayNotifyCallBack extends WxPayNotify
{
 protected $para = array('code'=>0,'data'=>'');
 //查詢訂單
 public function Queryorder($transaction_id)
 {
 $input = new \WxPayOrderQuery();
 $input->SetTransaction_id($transaction_id);
 $result = \WxPayApi::orderQuery($input);
 \Log::DEBUG("query:" . 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;
 }
 $this->para['code'] = 0;
 $this->para['data'] = '';
 return false;
 }

 //重寫回調(diào)處理函數(shù)
 public function NotifyProcess($data, &$msg)
 {
 \Log::DEBUG("call back:" . json_encode($data));
 $notfiyOutput = array();

 if(!array_key_exists("transaction_id", $data)){
 $msg = "輸入?yún)?shù)不正確";
 $this->para['code'] = 0;
 $this->para['data'] = '';
 return false;
 }
 //查詢訂單,判斷訂單真實性
 if(!$this->Queryorder($data["transaction_id"])){
 $msg = "訂單查詢失敗";
 $this->para['code'] = 0;
 $this->para['data'] = '';
 return false;
 }

 $this->para['code'] = 1;
 $this->para['data'] = $data;
 return true;
 }

 /**
 * 自定義方法 檢測微信端是否回調(diào)成功方法
 * @return multitype:number string
 */
 public function IsSuccess(){
 return $this->para;
 }
}

以上是“PHP微信支付開發(fā)的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI