当前位置:首页>>问题

shopro商城,微信native支付,扫码支付完整代码

第一个文件:index.php,用来发起支付<?php//支付配置$mchid='';//微信支付商户号PartnerID$appid='';//公众

admin

第一个文件:index.php,用来发起支付

<?php
//支付配置
$mchid = '';            //微信支付商户号 PartnerID
$appid = '';            //公众号APPID
$apiKey = '';           //APIv3密钥
$serialNumber = '';     //证书序列号
$privateKey = '';       //apiclient_key.pem的文件内容,可以先将后缀名改为txt,然后获取里面内容
 
//商品信息,可以由前端获取
$payAmount = '';        //付款金额,单位:元
$orderName = '';        //订单标题
 
//默认配置
$outTradeNo = date('YmdHis').uniqid();     //订单号,采用时间加微秒计ID
$notifyUrl = 'https://***/notify.php';     //付款成功后的通知地址,需要用https协议
 
//这里可以填写预下单业务逻辑
 
 
//发起支付
$wxPay = new IndexService($mchid, $appid, $apiKey,$privateKey,$serialNumber);
$wxPay->setTotalFee($payAmount);
$wxPay->setOutTradeNo($outTradeNo);
$wxPay->setOrderName($orderName);
$wxPay->setNotifyUrl($notifyUrl);
$result = $wxPay->doPay();
 
$url = 'https://wenhairu.com/static/api/qr/?size=300&text=' . $result['code_url'];
echo "<img src='{$url}' style='width:100px;'><br>";
echo '二维码内容:' . $result['code_url'];
 
//IndexService类
class IndexService
{
    protected $mchid;
    protected $appid;
    protected $apiKey;
    protected $privateKey;
    protected $serialNumber;
    protected $totalFee;
    protected $outTradeNo;
    protected $orderName;
    protected $notifyUrl;
    protected $auth;
    protected $gateWay='https://api.mch.weixin.qq.com/v3';
 
    public function __construct($mchid, $appid, $apikey, $privateKey, $serialNumber)
    {
        $this->mchid = $mchid;
        $this->appid = $appid;
        $this->apiKey = $apikey;
        $this->privateKey = $privateKey;
        $this->serialNumber = $serialNumber;
    }
 
    public function setTotalFee($totalFee)
    {
        $this->totalFee = floatval($totalFee);
    }
 
    public function setOutTradeNo($outTradeNo)
    {
        $this->outTradeNo = $outTradeNo;
    }
 
    public function setOrderName($orderName)
    {
        $this->orderName = $orderName;
    }
 
    public function setNotifyUrl($notifyUrl)
    {
        $this->notifyUrl = $notifyUrl;
    }
 
    /**
     * 发起支付
     */
    public function doPay()
    {
        $reqParams = array(
            'appid' => $this->appid,        //公众号或移动应用appid
            'mchid' => $this->mchid,        //商户号
            'description' => $this->orderName,     //商品描述
            'attach' => 'pay',              //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
            'notify_url' => $this->notifyUrl,       //通知URL必须为直接可访问的URL,不允许携带查询串。
            'out_trade_no' => $this->outTradeNo,      //商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一,详见【商户订单号】。特殊规则:最小字符长度为6
            'amount'=>array(
                'total'=> floatval($this->totalFee) * 100, //订单总金额,单位为分
                'currency'=> 'CNY', //CNY:人民币,境内商户号仅支持人民币
            ),
            'scene_info'=>array(        //支付场景描述
                'payer_client_ip'=>'127.0.0.1'   //调用微信支付API的机器IP
            )
        );
        $reqUrl = $this->gateWay.'/pay/transactions/native';
        $this->getAuthStr($reqUrl,$reqParams);
        $response = $this->curlPost($reqUrl,$reqParams);
        return json_decode($response,true);
 
    }
 
    public function curlPost($url = '', $postData = array(), $options = array())
    {
        if (is_array($postData)) {
            $postData = json_encode($postData);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Authorization:'.$this->auth,
            'Content-Type:application/json',
            'Accept:application/json',
            'User-Agent:'.$_SERVER['HTTP_USER_AGENT']
        ));
        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https请求 不验证证书和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }
 
    private function getSchema(): string
    {
        return 'WECHATPAY2-SHA256-RSA2048';
    }
 
    public function getAuthStr($requestUrl,$reqParams=array()): string
    {
        $schema = $this->getSchema();
        $token = $this->getToken($requestUrl,$reqParams);
        $this->auth = $schema.' '.$token;
        return $this->auth;
    }
 
    private function getNonce()
    {
        static $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $charactersLength = strlen($characters);
        $randomString = '';
        for ($i = 0; $i < 32; $i++) {
            $randomString .= $characters[rand(0, $charactersLength - 1)];
        }
        return $randomString;
    }
 
    public function getToken($requestUrl,$reqParams=array()): string
    {
        $body = $reqParams ?  json_encode($reqParams) : '';
        $nonce = $this->getNonce();
        $timestamp = time();
        $message = $this->buildMessage($nonce, $timestamp, $requestUrl,$body);
        $sign = $this->sign($message);
        $serialNo = $this->serialNumber;
        return sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $this->mchid, $nonce, $timestamp, $serialNo, $sign
        );
    }
 
    private function buildMessage($nonce, $timestamp, $requestUrl, $body = ''): string
    {
        $method = 'POST';
        $urlParts = parse_url($requestUrl);
        $canonicalUrl = ($urlParts['path'] . (!empty($urlParts['query']) ? "?{$urlParts['query']}" : ""));
        return strtoupper($method) . "\n" .
            $canonicalUrl . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";
    }
 
    private function sign($message): string
    {
        if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
            throw new \RuntimeException("当前PHP环境不支持SHA256withRSA");
        }
        $res = $this->privateKey;
        if (!openssl_sign($message, $sign, $res, 'sha256WithRSAEncryption')) {
            throw new \UnexpectedValueException("签名验证过程发生了错误");
        }
        return base64_encode($sign);
    }
}

第二个文件notify.php,用来接收支付的回调

<?php
//获取返回json数据
$getCallBackJson = file_get_contents('php://input');
 
//转化为关联数组
$getCallBackArray = json_decode($getCallBackJson, true);
 
//获取需要解密字段
$associatedData = $getCallBackArray['resource']['associated_data'];
$nonceStr = $getCallBackArray['resource']['nonce'];
$ciphertext = $getCallBackArray['resource']['ciphertext'];
 
 
//执行解密
$apiKey = '';   //这里需要填写APIv3秘钥
$getData = new NotifyService($apiKey);
$resultJson = $getData->decryptToString($associatedData, $nonceStr, $ciphertext);
 
//解密结果,为关联数组格式
$resultArray = json_decode($resultJson, true);
 
//交易成功
if ($resultArray['trade_state'] === 'SUCCESS') {
 
  //这里填写交易成功的相关业务,如更新账单状态,其中可能需要用到的参数如下
  
  //$resultArray['out_trade_no']       商户订单号
  //$resultArray['transaction_id']     订单号
  //$resultArray['amount']['total']    订单金额
 
}
 
//NotifyService类
class NotifyService
{
    protected $apiKey;
    const AUTH_TAG_LENGTH_BYTE = 16;
    public function __construct($apiKey)
    {
        $this->apiKey = $apiKey;
    }
 
    /**
     * Decrypt AEAD_AES_256_GCM ciphertext
     *
     * @param string $associatedData     AES GCM additional authentication data
     * @param string $nonceStr           AES GCM nonce
     * @param string $ciphertext         AES GCM cipher text
     *
     * @return string|bool      Decrypted string on success or FALSE on failure
     */
    public function decryptToString(string $associatedData, string $nonceStr, string $ciphertext)
    {
 
        $ciphertext = \base64_decode($ciphertext);
        if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
            return false;
        }
        $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
        $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
        return \openssl_decrypt($ctext, 'aes-256-gcm', $this->apiKey, \OPENSSL_RAW_DATA, $nonceStr,
            $authTag, $associatedData);
    }
}

上面这两段代码经过测试是可以正常使用的,需要注意的是配置参数必须要填写正确

参考文档(感谢原作者的分享):https://blog.csdn.net/qq_63573498/article/details/129997511

提交支付成功后,会返回code_url,那么需要将code_url转换成二维码图片,就要用到php的qrcode,下载:

phpqrcode-2010100721_1.1.4.zip

参考文档(感谢原作者的分享):https://blog.csdn.net/username666/article/details/125813233

php的qrcode使用方法:

include 'phpqrcode/qrlib.php';

$code_url = '微信支付的code_url';
$size = 10; // 二维码尺寸
$margin = 2; // 二维码边距
$tempDir = 'temp/'; // 临时目录

if (!file_exists($tempDir)) {
    mkdir($tempDir);
}

$filename = $tempDir .time(). 'qrcode.png';
QRcode::png($code_url, $filename, QR_ECLEVEL_L, $size, $margin);

参考文档(感谢原作者的分享):https://worktile.com/kb/ask/193899.html

native支付的官方指导文档:https://pay.weixin.qq.com/doc/v3/merchant/4012791877


到这里,基本上就算完成了,有问题自行再去研究,基本上问题不大





返回顶部