国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程

這篇具有很好參考價值的文章主要介紹了php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

?? 申請商戶號

  • 申請地址: https://pay.weixin.qq.com/
  • 如果你還沒有微信商戶號,請點擊上面的鏈接進(jìn)行申請,如果已經(jīng)有了,可以跳過這一步

?? 申請商戶證書

  • 首先點擊 賬戶中心 ? API安全 ? 申請API證書
  • 申請詳細(xì)步驟: https://kf.qq.com/faq/161222NneAJf161222U7fARv.html

php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程,《實戰(zhàn)模擬訓(xùn)練系列》,微信支付,支付,H5支付,php,微信,經(jīng)驗分享,開發(fā)語言

?? 設(shè)置APIv3密鑰

  • 首先點擊 賬戶中心 ? API安全 ? 設(shè)置APIv3密鑰 ? 設(shè)置
  • 會看到有兩個密鑰,分別是 APIv2密鑰APIv3密鑰,由于 APIv2密鑰 已經(jīng)逐漸廢棄了,所以只需要申請 APIv3密鑰 即可
  • 密鑰可由數(shù)字大小寫字母組合,輸入任意的 32 位字符,該密鑰需要保存好,供后面使用

php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程,《實戰(zhàn)模擬訓(xùn)練系列》,微信支付,支付,H5支付,php,微信,經(jīng)驗分享,開發(fā)語言
php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程,《實戰(zhàn)模擬訓(xùn)練系列》,微信支付,支付,H5支付,php,微信,經(jīng)驗分享,開發(fā)語言

// 生成32位的APIv3隨機密鑰
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

echo substr(str_shuffle($chars), 0, $length);

?? 下載 SDK 開發(fā)包

  • 微信官方提供了 JAVA、PHPGO 三種語言版本的開發(fā)庫,請根據(jù)自己開發(fā)語言選擇
  • JAVA語言: wechatpay-java ?推薦?、wechatpay-apache-httpclient
  • PHP語言: wechatpay-php ?推薦?、wechatpay-guzzle-middleware
  • GO語言: wechatpay-go ?推薦?
  • 由于 php 實現(xiàn)支付相對簡單,所以我將以 php 作為支付的講解
  • 首先使用 composer 安裝 sdk
# 初始化文件夾
composer init

# 推薦使用 PHP 包管理工具 Composer 安裝 SDK
composer require wechatpay/wechatpay

?? 下載平臺證書

  • 平臺證書跟上面申請的商戶證書不是同一個東西,在后期請求中,平臺證書和商戶證書都要帶上
  • 上面命令執(zhí)行完之后,會有一個 vendor/bin/CertificateDownloader.php 文件
  • 如果你是第一次申請平臺證書,需要執(zhí)行命令:php CertificateDownloader.php -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}
  • -k: apiv3 秘鑰,上面自己設(shè)置的32位數(shù)的密鑰
  • -m: 商戶號,微信商戶平臺可以查詢
  • -f: 微信商戶API私鑰文件目錄,也就是第二步申請商戶證書里面生成的 apiclient_key.pem 路徑
  • -s: 證書序列號,在 賬戶中心 ? API安全 ? 管理證書 中可以看見,如果有多個證書,找到自己正在使用的證書序列號
  • -o: 生成后的證書保存地址
cd vendor/bin/

php CertificateDownloader.php -k 241xxxxxxxxxxxxxxxxx44 -m 1xxxxxxx1 -f ../../cert/merchant/apiclient_key.pem -s Wxxxxxxxxxxxxxxxx4 -o  ../../cert/wechatpay/

php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程,《實戰(zhàn)模擬訓(xùn)練系列》,微信支付,支付,H5支付,php,微信,經(jīng)驗分享,開發(fā)語言

?? 關(guān)聯(lián) AppID 賬號

  • 因為使用的是微信支付,所以用戶支付后,需要通過微信號通知用戶支付的一些信息,所以需要在商戶號下至少關(guān)聯(lián)一個公眾號

php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程,《實戰(zhàn)模擬訓(xùn)練系列》,微信支付,支付,H5支付,php,微信,經(jīng)驗分享,開發(fā)語言

?? 開通 H5 支付

  • 點擊 產(chǎn)品中心 ? 我的產(chǎn)品 ? H5支付 ? 點擊開通
  • 開通后,選擇 開發(fā)配置 ? H5支付域名 申請?zhí)砑?H5支付域名
  • 申請支付域名需要先做好產(chǎn)品的頁面,申請的時候需要有頁面的截圖,截圖中還要 截取到域名,支付的審核算是很嚴(yán)格的,如果申請不過,駁回后再申請,審核通過的時間會越來越長,所以最好一次性就把材料收集好,另外還要域名的備案的 IPC 截圖
  • IPC 備案查詢地址: https://beian.miit.gov.cn/
  • 關(guān)于域名的填寫,如果只填寫域名不填寫具體域名路徑,微信在支付的時候就只會校驗域名,這也是最方便的,因為域名下有多個項目有支付功能的話,就不需要重復(fù)添加了

php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程,《實戰(zhàn)模擬訓(xùn)練系列》,微信支付,支付,H5支付,php,微信,經(jīng)驗分享,開發(fā)語言

php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程,《實戰(zhàn)模擬訓(xùn)練系列》,微信支付,支付,H5支付,php,微信,經(jīng)驗分享,開發(fā)語言

?? H5支付流程

  • H5支付是在微信以外的瀏覽器使用的,如果是微信內(nèi)的話,使用的是 jsapi 支付
  • 所以一般用戶進(jìn)入頁面的第一件事,就是檢測用戶使用的環(huán)境是微信瀏覽器還是其他瀏覽器
  • 前端傳一些用戶挑選商品后的參數(shù),并請求后端處理接口,后端應(yīng)該將一些參數(shù)進(jìn)行入庫,順便請求 H5 支付接口
  • 接口應(yīng)該返回跳轉(zhuǎn)鏈接 h5_url,如果你想用戶付款之后到結(jié)果頁面,需要添加 redirect_url 參數(shù),這個參數(shù)一定要用 encodeURIComponent 進(jìn)行處理
  • 由于官方在 jssapi 支付中說明,不要相信前端的 success 結(jié)果,所以需要在結(jié)果頁中,讓用戶自動觸發(fā)查詢結(jié)果,因此需要返回后端生成的訂單號,用作在結(jié)果頁的用戶手動點擊查詢
// 判斷是否微信瀏覽器
function isWeChat() {
    var ua = navigator.userAgent.toLowerCase();
    if (ua.match(/MicroMessenger/i) == 'micromessenger') {
        return true;
    } else {
        return false;
    }
}

if(isWeChat()) {
    // 是微信中打開的產(chǎn)品頁面
    alert('微信內(nèi)不支持h5支付,請在外部瀏覽器打開頁面');
} else {
    // 非微信內(nèi)打開的產(chǎn)品頁面,請求接口,獲取支付的跳轉(zhuǎn)鏈接
    // 前端用戶選的產(chǎn)品,以及產(chǎn)品的金額,傳一些參數(shù)過去
    let params = {
        total: 2, // 單位:元
        description: 'Image形象店-深圳騰大-QQ公仔' // 產(chǎn)品的介紹
        // ....更多入庫參數(shù)
    };
    
    $.getJSON('后端接口地址/h5?' + $.param(params) + '&callback=?', function(res) {
        // 拉起微信支付界面,成功后會跳轉(zhuǎn)到redirect_url鏈接
        $(location).attr("href", res.data.h5_url + "&redirect_url=" + encodeURIComponent(`https://xxxxxx/finish?out_trade_no=${res.data.out_trade_no}`))
    });
}
<?php
// 僅僅用作展示,不可直接復(fù)制使用
require_once('../vendor/autoload.php');

use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;

// 接受參數(shù),相當(dāng)于原生的$_GET
$input = $request->only(['name', 'total', 'description', 'phone']);

// 生成商戶訂單號
$out_trade_no = getOutTradeNo();

// 處理金額
// 由于微信使用的是分作為單位,所以前端傳的是元的話,需要轉(zhuǎn)換一下
$total = $input['total'] * 100;

// 商戶號
$merchantId = '1xxxxxx1';

// 從本地文件中加載「商戶API私鑰」,「商戶API私鑰」會用來生成請求的簽名
$merchantPrivateKeyFilePath = 'file://../cert/merchant/apiclient_key.pem';
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

// 「商戶API證書」的「證書序列號」
$merchantCertificateSerial = '1xxxxxxxxxxxxxxxxxxxxx91';

// 從本地文件中加載「微信支付平臺證書」,用來驗證微信支付應(yīng)答的簽名
$platformCertificateFilePath = 'file://../cert/wechatpay/wechatpay_4xxxxxxxxxxxxxxxxxxx9.pem';
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

// 從「微信支付平臺證書」中獲取「證書序列號」
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

// 構(gòu)造一個 APIv3 客戶端實例
$instance = Builder::factory([
    'mchid'      => $merchantId,
    'serial'     => $merchantCertificateSerial,
    'privateKey' => $merchantPrivateKeyInstance,
    'certs'      => [
        $platformCertificateSerial => $platformPublicKeyInstance,
    ],
]);


try {
    $resp = $instance
        ->chain('v3/pay/transactions/h5')
        ->post(['json' => [
            'mchid'        => $merchantId, // 商戶號
            'out_trade_no' => $out_trade_no, // 商戶訂單號
            'appid'        => '********換成跟商戶號綁定的公眾號APPID**********',
            'description'  => $input['description'], //商品描述
            'notify_url'   => 'https://xxxxx/notify', // 用戶支付后的回調(diào)地址,在這里修改訂單的狀態(tài)
            'amount'       => [
                'total'    => $total, // 微信處理的單位是分
                'currency' => 'CNY'
            ],
            'scene_info' => [
                'payer_client_ip' => getClientIP(), // 有些框架有自帶獲取獲取客戶端IP
                'h5_info' => [
                    'type' => 'Wap'
                ]
            ]
        ]]);
        
        
   // 如果請求成功,需要將一些參數(shù)進(jìn)行入庫,這里僅作演示,非正式數(shù)據(jù)入庫
   $response = Db::table('order')->insert([
       'name' => $input['name'],
       'description' => $input['description'],
       'total' => $input['total'],
       'phone' => $input['phone'],
       'trade_state' => 'START',
   ]);
   
   // 入庫成功后,將跳轉(zhuǎn)鏈接和訂單號傳給前端,前端拿到跳轉(zhuǎn)地址跳轉(zhuǎn)即可
   if($response) {
       return jsonp([
        'code' => 200,
        'msg' => '操作成功',
        'data' => [
              'out_trade_no' => $out_trade_no,
              'h5_url' => json_decode($resp->getBody(), true)['h5_url']
           ]
        ]);
   } else {
       return jsonp([
        'code' => 100,
        'msg' => '操作失敗'
       ]);
   }
} catch (\Exception $e) {
    // 進(jìn)行錯誤處理
    if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
        $r = $e->getResponse();
        echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
    }
}


// 生成唯一商戶訂單號,訂單號不能超過32位,并且在同一個商戶下訂單號不能重復(fù)
// 如果并發(fā)不高,基本這樣生成就可以,不會有重復(fù)的情況出現(xiàn)的
function getOutTradeNo()
{
    $out_trade_no = date('ymdHis') . mt_rand(1000, 9999) . uniqid();
    return mb_substr($out_trade_no, 0, 32);
}

// 獲取客戶端的IP
function getClientIP()
{
    if (@$_SERVER["HTTP_ALI_CDN_REAL_IP"]) {
        $ip = $_SERVER["HTTP_ALI_CDN_REAL_IP"];
    } elseif (@$_SERVER["HTTP_X_FORWARDED_FOR"] ?: false) {
        $ips = explode(',', $_SERVER["HTTP_X_FORWARDED_FOR"]);
        $ip = $ips[0];
    } elseif (@$_SERVER["HTTP_CDN_SRC_IP"] ?: false) {
        $ip = $_SERVER["HTTP_CDN_SRC_IP"];
    } elseif (getenv('HTTP_CLIENT_IP')) {
        $ip = getenv('HTTP_CLIENT_IP');
    } elseif (getenv('HTTP_X_FORWARDED')) {
        $ip = getenv('HTTP_X_FORWARDED');
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
        $ip = getenv('HTTP_FORWARDED_FOR');
    } elseif (getenv('HTTP_FORWARDED')) {
        $ip = getenv('HTTP_FORWARDED');
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }

    $ip = str_replace(['::ffff:', '[', ']'], ['', '', ''], $ip);
    return $ip;
}
<?php
// 回調(diào)處理,當(dāng)用戶支付訂單后,微信會請求該接口,也就是上面在notify_url中填寫的接口
// 在這里我們可以修改訂單的狀態(tài)啥的
public function notify()
{
    // 獲取參數(shù)
    $inBody = file_get_contents('php://input');

    // APIv3密鑰
    $apiv3Key = 'xxxxxxxxxxxx';

    // 轉(zhuǎn)換通知的JSON文本消息為PHP Array數(shù)組
    $inBodyArray = (array)json_decode($inBody, true);
    
    // 加密文本消息解密
    $inBodyResource = AesGcm::decrypt(
        $inBodyArray['resource']['ciphertext'],
        $apiv3Key,
        $inBodyArray['resource']['nonce'],
        $inBodyArray['resource']['associated_data']
    );

    // 把解密后的文本轉(zhuǎn)換為PHP Array數(shù)組
    $inBodyResourceArray = (array)json_decode($inBodyResource, true);

    try {
        // 獲取訂單信息
        $order = Db::table('order')->where('out_trade_no', $inBodyResourceArray['out_trade_no'])->first();

        Db::startTrans();
        if ($order) {
            // 修改order訂單的狀態(tài)
            Db::table('order')->where('id', $order['id'])->update([
                'openid' => $inBodyResourceArray['payer']['openid'],
                'trade_state' => $inBodyResourceArray['trade_state']
            ]);
            
            
            Db::table('payment')->insert([
                 'out_trade_no' => $inBodyResourceArray['out_trade_no'],
                'transaction_id' => $inBodyResourceArray['transaction_id'],
                'trade_type' => $inBodyResourceArray['trade_type'],
                'trade_state' => $inBodyResourceArray['trade_state'],
                'trade_state_desc' => $inBodyResourceArray['trade_state_desc'],
                'total_amount' => $inBodyResourceArray['amount']['total'],
                'bank_type' => $inBodyResourceArray['bank_type'],
                'success_time' => strtotime($inBodyResourceArray['success_time'])
            ]);

            Db::commit();
        } else {
            Db::rollback();
        }
    } catch (\Exception $e) {
        Db::rollback();
    }
}

?? 開通 JSAPI 支付

  • 點擊 產(chǎn)品中心 ? 我的產(chǎn)品 ? JSAPI支付 ? 點擊開通
  • 開通后,選擇 開發(fā)配置 ? JSAPI支付域名 申請?zhí)砑?JSAPI支付域名
  • 關(guān)于申請支付域名的流程基本都差不多要求也差不多,看上面的 H5支付域名 申請就行,這里就不過多贅述了

php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程,《實戰(zhàn)模擬訓(xùn)練系列》,微信支付,支付,H5支付,php,微信,經(jīng)驗分享,開發(fā)語言文章來源地址http://www.zghlxwxcb.cn/news/detail-584277.html

?? JSAPI 支付流程

  • JSAPI支付是在微信內(nèi)的瀏覽器使用的,如果用戶是在微信外打開的話,需要提醒去微信內(nèi)打開頁面
  • JSAPI支付需要使用微信內(nèi)置的 WeixinJSBridge.invoke 方法
  • 由于 JSAPI 調(diào)用支付需要用到用戶的 openid,所以需要想方設(shè)法在用戶調(diào)用 JSAPI 之前獲取到 openid,點擊查看獲取 openid 的官方文檔
  • 獲取用戶 openid,需要先獲取 code,這個經(jīng)常做微信業(yè)務(wù)的人都知道,那么如何在用戶無感知的情況下就獲取到 openid
  • 思路就是,一般支付最少會有3個頁面,這里標(biāo)注為a、bc 三個頁面,通常是在 a 頁面挑選商品,在 b頁面確認(rèn)商品,也就是付款頁面,c 頁面查詢支付狀態(tài)
  • 由于 code 的存在時間只有5分鐘,所以注定 code 獲得后不能長時間不使用,也就是說用戶一旦在某個頁面超過5分鐘,這個 code 就失效了,因此最好的方法就是獲取 code 后,立馬獲取 openid
  • 那么就應(yīng)該設(shè)計成從a 頁面先跳轉(zhuǎn)到獲取 code 頁面再跳轉(zhuǎn)到 b 頁面,而在 b 頁面的一開始就去請求接口,獲取用戶的 openid 即可
  • 跳轉(zhuǎn)到 b 頁面后,鏈接后自動帶上 code參數(shù),鏈接應(yīng)該是 https://xxxx/b.html?code=xxxxxxxx
// a頁面,僅做邏輯演示,更加具體的邏輯需要自己完善
// 判斷是否微信瀏覽器
function isWeChat() {
    var ua = navigator.userAgent.toLowerCase();
    if (ua.match(/MicroMessenger/i) == 'micromessenger') {
        return true;
    } else {
        return false;
    }
}

if(!isWeChat()) {
    // 非微信內(nèi)打開的產(chǎn)品頁面
    alert('微信外不支持JSAPI支付,請在微信中打開頁面');
    return false;
}

// 用戶挑選完商品后跳轉(zhuǎn),這里appid需要上面跟商戶綁定的公眾號appid
// 微信授權(quán)分為靜默授權(quán)和非靜默授權(quán),其中非靜默授權(quán),需要用戶點擊確認(rèn)授權(quán)后,才可以獲取code,
// 因為這里主打一個用戶無感知,而且我們只需要openid即可,所以我們只需要使用靜默授權(quán)即可
// 靜默授權(quán)可以獲取用戶更多的信息,比如頭像、昵稱等,而靜默授權(quán)只能獲取openid,這點需要注意,具體情況選擇不同
// 非靜默授權(quán)
// $(location).attr('href', `https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxxxx&redirect_uri=${encodeURIComponent('https://xxxx/b.html')}&response_type=code&scope=snsapi_userinfo#wechat_redirect`)
// 靜默授權(quán)
$(location).attr('href', `https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxxxx&redirect_uri=${encodeURIComponent('https://xxxx/b.html')}&response_type=code&scope=snsapi_base#wechat_redirect`)
// b頁面,僅做邏輯演示,更加具體的邏輯需要自己完善
let openid = '';

// 獲取code, 請求接口獲取openid
function getParamUrl(name, url) {
  if (!url) url = location.href;
  if (url.indexOf('?') == -1) return '';

  try {
    var re = new RegExp("" + name + "=([^&?]*)", "ig");
    return ((url.match(re)) ? (decodeURIComponent(url.match(re)[0].substr(name.length + 1))) : '');
  } catch (_e) {
    return '';
  }
}

let code = getParamUrl('code');

$.getJSON('后端接口地址/openid?callback=?', function(res) {
    if(res.code == 200) {
        openid = res.data;
    } else {
        console.error(res.msg);
    }
})

// 用戶確定訂單后,拉起支付
let params = {
    total: 2, // 單位:元
    description: 'Image形象店-深圳騰大-QQ公仔', // 產(chǎn)品的介紹
    openid: openid //用戶的openid
    // ....更多入庫參數(shù)
};

$.getJSON('后端接口地址/jssapi?' + $.param(params) + '&callback=?', function(res) {
    WeixinJSBridge.invoke('getBrandWCPayRequest', {
      'appId': res.data.sign.appId,
      'timeStamp': res.data.sign.timeStamp,
      'nonceStr': res.data.sign.nonceStr,
      'package': res.data.sign.package,
      'signType': res.data.sign.signType,
      'paySign': res.data.sign.paySign
    }, function (response) {
      if (response.err_msg == "get_brand_wcpay_request:ok") {
        $(location).attr("href", `https://xxxxxx/finish?out_trade_no=${res.data.out_trade_no}`)
      } else {
        // 有些用戶調(diào)起了支付,但是未付款取消的處理方式,你可以給他簡單簡單提示
        toast('支付異常取消')

        // 當(dāng)然有些用戶是誤操作,你可以提醒二次支付
        if(confirm('檢測到你操作有誤,是否重新支付?')) {
            WeixinJSBridge.invoke('getBrandWCPayRequest', {
                  'appId': res.data.sign.appId,
                  'timeStamp': res.data.sign.timeStamp,
                  'nonceStr': res.data.sign.nonceStr,
                  'package': res.data.sign.package,
                  'signType': res.data.sign.signType,
                  'paySign': res.data.sign.paySign
                }, function (response) {
                if (response.err_msg == "get_brand_wcpay_request:ok") {
                    $(location).attr("href", `https://xxxxxx/finish?out_trade_no=${res.data.out_trade_no}`)
                }
            })
        }
      }
    });
});
<?php
// 獲取用戶的openid

$input = $request->only(['code']);

$response = getCurl("https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appid}&secret={$this->secret}&code={$input['code']}&grant_type=authorization_code");

$openid = json_decode($response, true)['openid'];

// 返回openid
return jsonp([
    'code' => 200,
    'msg' => '獲取成功',
    'data' => $openid
]);


// 封裝的GET請求
function getCurl($url, $timeout = 5)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    $result = curl_exec($ch);
    curl_close($ch);

    return $result;
}
<?php
// 僅僅用作展示,不可直接復(fù)制使用
require_once('../vendor/autoload.php');

use WeChatPay\Builder;
use WeChatPay\Formatter;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;

// 接受參數(shù),相當(dāng)于原生的$_GET,這里會比h5支付多一個openid
$input = $request->only(['openid', 'name', 'total', 'description', 'phone']);

// 生成商戶訂單號
$out_trade_no = getOutTradeNo();

// 處理金額
// 由于微信使用的是分作為單位,所以前端傳的是元的話,需要轉(zhuǎn)換一下
$total = $input['total'] * 100;

// 商戶號
$merchantId = '1xxxxxx1';

// 從本地文件中加載「商戶API私鑰」,「商戶API私鑰」會用來生成請求的簽名
$merchantPrivateKeyFilePath = 'file://../cert/merchant/apiclient_key.pem';
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

// 「商戶API證書」的「證書序列號」
$merchantCertificateSerial = '1xxxxxxxxxxxxxxxxxxxxx91';

// 從本地文件中加載「微信支付平臺證書」,用來驗證微信支付應(yīng)答的簽名
$platformCertificateFilePath = 'file://../cert/wechatpay/wechatpay_4xxxxxxxxxxxxxxxxxxx9.pem';
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

// 從「微信支付平臺證書」中獲取「證書序列號」
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

// 構(gòu)造一個 APIv3 客戶端實例
$instance = Builder::factory([
    'mchid'      => $merchantId,
    'serial'     => $merchantCertificateSerial,
    'privateKey' => $merchantPrivateKeyInstance,
    'certs'      => [
        $platformCertificateSerial => $platformPublicKeyInstance,
    ],
]);


try {
    // 調(diào)用 transactions/jsapi 接口后會生成prepay_id
    $resp = $this->instance()
        ->chain('v3/pay/transactions/jsapi')
        ->post(['json' => [
            'mchid'        => $merchantId, // 商戶號
            'out_trade_no' => $out_trade_no, // 商戶訂單號
            'appid'        => '********換成跟商戶號綁定的公眾號APPID**********',
            'description'  => $input['description'], //商品描述
            'notify_url'   => 'https://xxxxx/notify', // 用戶支付后的回調(diào)地址,在這里修改訂單的狀態(tài)
            'amount' => [
                'total' => $total,
                'currency' => 'CNY'
            ],
            'payer' => [
                'openid' => $input['openid']
            ]
        ]]);
        
    // 需要根據(jù)prepay_id去生成加密的信息
    $prepay_id = json_decode($resp->getBody(), true)['prepay_id'];
    $sign = getSign($prepay_id);
        
   // 如果請求成功,需要將一些參數(shù)進(jìn)行入庫,這里僅作演示,非正式數(shù)據(jù)入庫
   $response = Db::table('order')->insert([
       'openid' => $input['openid'],
       'name' => $input['name'],
       'description' => $input['description'],
       'total' => $input['total'],
       'phone' => $input['phone'],
       'trade_state' => 'START',
   ]);
   
   // 入庫成功后,將跳轉(zhuǎn)鏈接和訂單號傳給前端,前端拿到跳轉(zhuǎn)地址跳轉(zhuǎn)即可
   if($response) {
       return jsonp([
        'code' => 200,
        'msg' => '操作成功',
        'data' => [
              'out_trade_no' => $out_trade_no,
              'sign' => $sign
           ]
        ]);
   } else {
       return jsonp([
        'code' => 100,
        'msg' => '操作失敗'
       ]);
   }
} catch (\Exception $e) {
    // 進(jìn)行錯誤處理
    if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
        $r = $e->getResponse();
        echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
    }
}

// 獲取加密參數(shù)
function getSign($prepay_id)
{
    $merchantPrivateKeyInstance = Rsa::from($this->merchantPrivateKeyFilePath);

    $params = [
        'appId' => $this->appid,
        'timeStamp' => (string)Formatter::timestamp(),
        'nonceStr' => Formatter::nonce(),
        'package' => 'prepay_id=' . $prepay_id,
    ];

    $params += ['paySign' => Rsa::sign(
        Formatter::joinedByLineFeed(...array_values($params)),
        $merchantPrivateKeyInstance
    ), 'signType' => 'RSA'];

    return $params;
}

?? 通用微信支付庫封裝

  • 由于直接使用微信的支付庫,代碼非常的勻余,所以封裝了一個微信支付庫
  • 由于只針對一些業(yè)務(wù)的 api封裝,所以肯定不全,需要的可以自己添加需要的api
  • 微信支付API接口列表: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/index.shtml
<?php
/**
 * User: tinygeeker
 * Desc: 微信支付庫封裝
 * Date: 2023/08/10
 */

namespace App;

use App\Helper;
use WeChatPay\Builder;
use WeChatPay\Formatter;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;

class WxPay
{
    // appid
    private $appid;

    // 商戶號
    private $merchantId;

    // 商戶API私鑰
    private $merchantPrivateKeyFilePath;

    // 證書序列號
    private $merchantCertificateSerial;

    // 微信支付平臺證書
    private $platformCertificateFilePath;

    /**
     * @param $appid
     * @param $merchantId
     * @param $merchantCertificateSerial
     */
    public function __construct($appid = '', $merchantId = '', $merchantCertificateSerial = '')
    {
        $this->appid = $appid ?: '換成自己的APPID';
        $this->merchantId = $merchantId ?: '換成自己的商戶號';
        $this->merchantCertificateSerial = $merchantCertificateSerial ?: '換成自己的證書序列號';

        $this->merchantPrivateKeyFilePath = 'file:///common/cert/merchant/apiclient_key.pem'; // 換成自己的
        $this->platformCertificateFilePath = 'file:///common/cert/wechatpay/wechatpay_xxx.pem'; // 換成自己的
    }

    /**
     * @return \WeChatPay\BuilderChainable
     */
    protected function instance()
    {
        $merchantPrivateKeyInstance = Rsa::from($this->merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        $platformPublicKeyInstance = Rsa::from($this->platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($this->platformCertificateFilePath);

        $instance = Builder::factory([
            'mchid' => $this->merchantId,
            'serial' => $this->merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);

        return $instance;
    }

    public function getSign($prepay_id)
    {
        $merchantPrivateKeyInstance = Rsa::from($this->merchantPrivateKeyFilePath);

        $params = [
            'appId' => $this->appid,
            'timeStamp' => (string)Formatter::timestamp(),
            'nonceStr' => Formatter::nonce(),
            'package' => 'prepay_id=' . $prepay_id,
        ];

        $params += ['paySign' => Rsa::sign(
            Formatter::joinedByLineFeed(...array_values($params)),
            $merchantPrivateKeyInstance
        ), 'signType' => 'RSA'];

        return $params;
    }

    public function checkOutTradeNo($out_trade_no)
    {
        try {
            $resp = $this->instance()
                ->v3->pay->transactions->outTradeNo->_out_trade_no_
                ->get([
                    // Query 參數(shù)
                    'query' => ['mchid' => $this->merchantId],
                    // 變量名 => 變量值
                    'out_trade_no' => $out_trade_no,
                ]);

            return $resp->getBody();
        } catch (\Exception $e) {
            // 進(jìn)行錯誤處理
            echo $e->getMessage(), PHP_EOL;
            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r = $e->getResponse();
                echo $r->getStatusCode() . ' ' . $r->getReasonPhrase(), PHP_EOL;
                echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
            }
            echo $e->getTraceAsString(), PHP_EOL;
        }
    }
    
    // h5下單
    public function h5($total, $out_trade_no, $description, $notify_url)
    {
        try {
            $resp = $this->instance()
                ->chain('v3/pay/transactions/h5')
                ->post(['json' => [
                    'mchid' => $this->merchantId,
                    'out_trade_no' => $out_trade_no,
                    'appid' => $this->appid,
                    'description' => $description,
                    'notify_url' => $notify_url,
                    'amount' => [
                        'total' => $total,
                        'currency' => 'CNY'
                    ],
                    'scene_info' => [
                        'payer_client_ip' => Helper::getClientIp(),
                        'h5_info' => [
                            'type' => 'Wap'
                        ]
                    ]
                ]]);

            return $resp->getBody();
        } catch (\Exception $e) {
            // 進(jìn)行錯誤處理
            echo $e->getMessage(), PHP_EOL;
            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r = $e->getResponse();
                echo $r->getStatusCode() . ' ' . $r->getReasonPhrase(), PHP_EOL;
                echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
            }
            echo $e->getTraceAsString(), PHP_EOL;
        }
    }
    
    // jsapi下單
    public function jsapi($openid, $total, $out_trade_no, $description, $notify_url)
    {
        try {
            $resp = $this->instance()
                ->chain('v3/pay/transactions/jsapi')
                ->post(['json' => [
                    'mchid' => $this->merchantId,
                    'out_trade_no' => $out_trade_no,
                    'appid' => $this->appid,
                    'description' => $description,
                    'notify_url' => $notify_url,
                    'amount' => [
                        'total' => $total,
                        'currency' => 'CNY'
                    ],
                    'payer' => [
                        'openid' => $openid
                    ]
                ]]);

            return $resp->getBody();
        } catch (\Exception $e) {
            // 進(jìn)行錯誤處理
            echo $e->getMessage(), PHP_EOL;
            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r = $e->getResponse();
                echo $r->getStatusCode() . ' ' . $r->getReasonPhrase(), PHP_EOL;
                echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL;
            }
            echo $e->getTraceAsString(), PHP_EOL;
        }
    }
    
    
   // todo... 更多接口可根據(jù)官方文檔列表自行添加
}
<?php
/**
 * User: tinygeeker
 * Desc: 工具庫
 * Date: 2023/08/10
 */
 
namespace App;

class Helper
{
    /**
     * @return array|mixed|string|string[]
     */
    static public function getClientIP()
    {
        if (@$_SERVER["HTTP_ALI_CDN_REAL_IP"]) {
            $ip = $_SERVER["HTTP_ALI_CDN_REAL_IP"];
        } elseif (@$_SERVER["HTTP_X_FORWARDED_FOR"] ?: false) {
            $ips = explode(',', $_SERVER["HTTP_X_FORWARDED_FOR"]);
            $ip = $ips[0];
        } elseif (@$_SERVER["HTTP_CDN_SRC_IP"] ?: false) {
            $ip = $_SERVER["HTTP_CDN_SRC_IP"];
        } elseif (getenv('HTTP_CLIENT_IP')) {
            $ip = getenv('HTTP_CLIENT_IP');
        } elseif (getenv('HTTP_X_FORWARDED')) {
            $ip = getenv('HTTP_X_FORWARDED');
        } elseif (getenv('HTTP_FORWARDED_FOR')) {
            $ip = getenv('HTTP_FORWARDED_FOR');
        } elseif (getenv('HTTP_FORWARDED')) {
            $ip = getenv('HTTP_FORWARDED');
        } else {
            $ip = $_SERVER['REMOTE_ADDR'];
        }

        $ip = str_replace(['::ffff:', '[', ']'], ['', '', ''], $ip);
        return $ip;
    }

    /**
     * @param $length
     * @param $type
     * @return false|string
     */
    static public function createRandomStr($length = 32, $type = 0)
    {
        switch ($type) {
            case 1:
                $chars = '0123456789';
                break;
            case 2:
                $chars = 'abcdefghijklmnopqrstuvwxyz';
                break;
            case 3:
                $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
                break;
            case 4:
                $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
                break;
            case 5:
                $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
                break;
            default:
                $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
                break;
        }

        return substr(str_shuffle($chars), 0, $length);
    }

    /**
     * @param $url
     * @param $timeout
     * @return bool|string
     */
    static public function getCurl($url, $timeout = 5)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        $result = curl_exec($ch);
        curl_close($ch);

        return $result;
    }

    /**
     * @param $url
     * @param $data
     * @param $header
     * @param $timeout
     * @return bool|string
     */
    static public function postCurl($url, $data, $header = [], $timeout = 5)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        if ($header) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        $result = curl_exec($ch);
        curl_close($ch);

        return $result;
    }
}

到了這里,關(guān)于php 開發(fā)微信 h5 支付 APIv3 接入超詳細(xì)流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 微信支付apiV3異常:The corresponding provider for the merchant already exists

    異常信息 原因 這個錯誤是微信SDK拋出的,這是因為微信支付apiV3的RSAConfig重復(fù)build導(dǎo)致,即RSAConfig要保證是 單例 才不會導(dǎo)致報錯。 參數(shù)說明 mchId:商戶號 privateKey:商戶號密鑰 mchSerialNo:商戶證書號 apiV3Key:apiV3密鑰 建議 可以把商戶配置參數(shù)使用數(shù)據(jù)庫保存,服務(wù)啟動的時

    2024年02月11日
    瀏覽(114)
  • H5接入支付流程-微信支付&支付寶支付

    H5接入支付流程-微信支付&支付寶支付

    H5對接微信支付和支付寶支付,app無法發(fā)版,需要支持在app內(nèi)和瀏覽器內(nèi)同時使用。 于是借此機會對前端接入對第三方支付進(jìn)行了調(diào)研,本次只討論微信支付,和支付寶支付。 文檔地址:微信支付 微信支付方式主要包括,對普通商家主要提供以下7種方式 付款碼支付:比如大

    2024年02月19日
    瀏覽(28)
  • 〔支付接入〕微信的 h5 支付和 jsapi 支付

    〔支付接入〕微信的 h5 支付和 jsapi 支付

    申請地址: https://pay.weixin.qq.com/ 如果你還沒有微信商戶號,請點擊上面的鏈接進(jìn)行申請,如果已經(jīng)有了,可以跳過這一步 首先點擊 賬戶中心 ? API安全 ? 申請API證書 申請詳細(xì)步驟: https://kf.qq.com/faq/161222NneAJf161222U7fARv.html 首先點擊 賬戶中心 ? API安全 ? 設(shè)置APIv3密鑰 ?

    2024年02月13日
    瀏覽(53)
  • uniapp - 微信小程序接入騰訊視頻播放器功能插件,uniapp開發(fā)微信小程序端調(diào)用引入并使用騰訊視頻播放組件完整全流程(詳細(xì)示例源碼,一鍵復(fù)制開箱即用)

    uniapp - 微信小程序接入騰訊視頻播放器功能插件,uniapp開發(fā)微信小程序端調(diào)用引入并使用騰訊視頻播放組件完整全流程(詳細(xì)示例源碼,一鍵復(fù)制開箱即用)

    在uniapp 微信小程序項目中,集成騰訊視頻功能插件,實現(xiàn)播放騰訊視頻效果,附帶詳細(xì)示例源碼及注釋, 你可以跟著步驟一步步來,保證幾分鐘就能快速在uniapp小程序項目中植入騰訊視頻功能!

    2024年02月12日
    瀏覽(91)
  • h5 小程序 公眾號 接入微信支付開發(fā)

    h5 小程序 公眾號 接入微信支付開發(fā)

    ps:一般公司開發(fā)不需要確認(rèn) 流程:下單-調(diào)起支付-返回結(jié)果跳回本頁面 開發(fā)準(zhǔn)備: 1: 配置并授權(quán)項目地址(地址需要是完整的)(配置的是點擊支付調(diào)起微信的那個本項目地址) 2: 獲取code(為獲取openid做準(zhǔn)備) window.location.href=?= \\\'https://open.weixin.qq.com/connect/oauth2/authorize?

    2024年02月15日
    瀏覽(27)
  • 使用uniapp開發(fā)微信小程序的微信支付流程

    在我們做一些購物車的結(jié)算功能時是一定會有支付功能的,那我們?nèi)绾稳プ鑫⑿胖Ц哆@個功能呢,首先我們先要理清思路,并且要了解到接口需要哪些數(shù)據(jù)以及會返回哪些數(shù)據(jù) 注意:一定要先看接口文檔! 創(chuàng)建訂單。 ○ 請求創(chuàng)建訂單的 API 接口:把(訂單金額、收貨地址、

    2024年02月09日
    瀏覽(91)
  • android支付寶接入流程

    android支付寶接入流程

    接入APP支付能力前,開發(fā)者需要完成以下前置步驟。 本文檔展示了如何從零開始,使用支付寶開放平臺服務(wù)端 SDK 快速接入App支付產(chǎn)品,完成與支付寶對接的部分。 要在您的應(yīng)用中接入支付寶 App 支付能力,您需要登錄支付寶開放平臺open.alipay.com),在開發(fā)者中心中創(chuàng)建您的

    2024年04月13日
    瀏覽(11)
  • Unity Android平臺接入支付寶支付全流程

    Unity Android平臺接入支付寶支付全流程

    ??Unity3D接入支付寶支付的流程非常復(fù)雜,涉及到很多方面(有任何問題都可以在評論區(qū)留言,我盡量盡快回復(fù))所以寫篇文章記錄一下。支付寶支付和微信支付以及其它支付差不多,但是支付寶有沙箱環(huán)境,可以很方便地調(diào)試,所以選用支付寶平臺作為演示。 ??此教程

    2024年04月29日
    瀏覽(17)
  • 谷歌支付接入流程(一次性支付,連續(xù)訂閱)

    谷歌支付接入流程(一次性支付,連續(xù)訂閱)

    android同胞我相信很多人跟我一樣谷歌支付運行自己的app的時候調(diào)用支付發(fā)現(xiàn)都是出現(xiàn)一個問題簽名不同我們今天就來解決這個問題 先正常導(dǎo)入接入流程后面會提到問題的解決 1、導(dǎo)入依賴 2、清淡文件添加權(quán)限 3、代碼接入kotlin的代碼是在activity里面寫 4、支付的類和接口直接

    2024年02月13日
    瀏覽(19)
  • 微信小程序接入微信支付流程

    微信小程序接入微信支付流程

    1、支付場景:點擊支付按鈕喚起微信支付彈窗,輸入正確密碼后完成支付。 2、基本流程:點擊支付按鈕首先生成一個訂單,然后在后端調(diào)用微信api接口進(jìn)行統(tǒng)一下單,將接口返回的數(shù)據(jù)回傳到前端拉起支付操作,然后異步通知支付結(jié)果。 1、微信公眾平臺配置 點擊功能 –

    2023年04月12日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包