IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    微信JSAPI支付V3版本

    陈华发表于 2022-09-08 08:25:45
    love 0

    定义微信配置

    protected $sp_appid = ”;//服务商APPID(目前只有公众号)
    protected $sp_mchid = ”;//服务商商户号
    protected $sub_appid = ”;//小程序APPID
    protected $sub_mchid = ”;//商户号
    protected $apiV3Key = ”;//支付秘钥(服务商V3级别)
    protected $privateKeyPath = ”;//证书物理路径(私钥)
    protected $serialNo = ”;//证书序列号
    protected $app_secret = ”;//小程序通信秘钥
    protected $notify_url = ”;//支付回调地址

    初始化加载配置

    public function _initialize()
    {
    parent::_initialize();
    $wechatconf = config(‘wechat’);//可以写在配置文件,也可写在数据库
    $this->sp_appid = $wechatconf[‘sp_appid’];
    $this->sp_mchid = $wechatconf[‘sp_mchid’];
    $this->sub_appid = $wechatconf[‘sub_appid’];
    $this->sub_mchid = $wechatconf[‘sub_mchid’];
    $this->apiV3Key = $wechatconf[‘apiV3Key’];
    $this->privateKeyPath = $wechatconf[‘privateKeyPath’];
    $this->serialNo = $wechatconf[‘serialNo’];
    $this->app_secret = $wechatconf[‘app_secret’];
    $this->notify_url = $wechatconf[‘notify_url’];
    }

    统一下单(注意signType不参与签名,package必须是下面写的prepay_id=)

    public function unifyPay(){
    $param = $this->request->param();
    if(!$param[‘uid’] || !$param[‘orderno’]){
    return $this->json_result(400,’缺少参数’);
    }
    $orderinfo = Db::name(‘service_order’)->where([‘orderno’=>$param[‘orderno’],’uid’=>$param[‘uid’]])->find();
    if(empty($orderinfo)){
    return $this->json_result(400,’订单不存在’);
    }
    $userinfo = Db::name(‘user’)->where(‘id’,$param[‘uid’])->find();
    if(empty($userinfo)){
    return $this->json_result(400,’用户不存在’);
    }
    ;
    //这个数组里所有的数据都是必填的
    $unifydata = [
    ‘sp_appid’ => $this->sp_appid,
    ‘sp_mchid’ => $this->sp_mchid,
    ‘sub_appid’ => $this->sub_appid,
    ‘sub_mchid’ => $orderinfo[‘sub_mchid’],
    ‘description’ => ‘服务’,
    ‘out_trade_no’ => $param[‘orderno’],//订单号
    ‘notify_url’ => $this->notify_url,//回调地址
    ‘settle_info’=>[‘profit_sharing’=>true],
    ‘amount’=>[‘total’=>(int)bcmul(0.01, ‘100’,0),’currency’=>’CNY’],
    ‘payer’=>[‘sub_openid’=>$userinfo[‘username’]],
    ‘scene_info’=>[‘payer_client_ip’=>$_SERVER[“REMOTE_ADDR”]],
    ];
    $orderResult = $this->create_pay_order($unifydata);
    $timeStamp = time();
    $paydata = [
    ‘appId’ => $this->sub_appid,
    ‘timeStamp’ => “$timeStamp”,
    ‘nonceStr’ => md5(rand(100000,999999)),
    ‘package’ => ‘prepay_id=’ . $orderResult[‘prepay_id’],
    ];
    $sign = $this->getSign($paydata);//给小程序生成验证签名
    $paydata[‘signType’] = ‘RSA’;
    $paydata[‘paySign’] = $sign;
    return $this->json_result(200,’统一下单成功’,$paydata);
    }

    调用微信下单接口

    public function create_pay_order($inputData){
    $inputData = json_encode($inputData);//v3微信传递参数需要json格式
    $headers = $this->getV3Sign(‘https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi’,’POST’,$inputData);//将签名放在报头里
    $result = $this -> post_data(‘https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi’,$inputData,$headers);//下单
    return json_decode($result,true);
    }

    获取签名

    public function getV3Sign($url,$http_method,$body) {
    //商户号
    $mchid = $this->sp_mchid;
    //随机字符串
    $nonce = strtoupper($this -> getNoncestr());
    //商户序列号
    $serialNo = $this->serialNo;
    //时间戳
    $timestamp = time();
    //url
    $url_parts = parse_url($url);
    //获取绝对路径
    $canonical_url = ($url_parts[‘path’] . (!empty($url_parts[‘query’]) ? “?${url_parts[‘query’]}” : “”));
    //密钥key
    $private_key = $this->getPrivateKey($this->privateKeyPath);
    //拼接参数
    $message = $http_method.”\n”.
    $canonical_url.”\n”.
    $timestamp.”\n”.
    $nonce.”\n”.
    $body.”\n”;
    //计算签名值
    openssl_sign($message, $raw_sign, $private_key, ‘sha256WithRSAEncryption’);
    $sign = base64_encode($raw_sign);
    // $token = sprintf(‘mchid=”%s”,nonce_str=”%s”,timestamp=”%d”,serial_no=”%s”,signature=”%s”‘,$mchid, $nonce, $timestamp, $serial_no, $sign);
    $token = sprintf(‘WECHATPAY2-SHA256-RSA2048 mchid=”%s”,nonce_str=”%s”,timestamp=”%d”,serial_no=”%s”,signature=”%s”‘,
    $mchid, $nonce, $timestamp, $serialNo, $sign);
    $headers = [
    ‘Accept: application/json’,
    ‘User-Agent: */*’,
    ‘Content-Type: application/json; charset=utf-8’,
    ‘Authorization: ‘.$token,
    ];
    return $headers;
    }

    生成32位随机字符串

    public 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 getPrivateKey($filepath) {
    return openssl_get_privatekey(file_get_contents($filepath));
    }

    POST调用API

    public function post_data($url,$data=[],$headers=[]){
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    //设置header头
    curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
    // POST数据
    curl_setopt($ch, CURLOPT_POST, 1);
    // 把post的变量加上
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
    }

    给小程序生成验证签名(V3不再用MD5用SHA256)

    protected function getSign($data) {
    $tmpstr = $data[‘appId’] . “\n” . $data[‘timeStamp’] . “\n” . $data[‘nonceStr’] . “\n” . $data[‘package’] . “\n”;
    $privateKey = file_get_contents($this->privateKeyPath);
    $binary_signature = “”;
    $algo = “SHA256”;
    openssl_sign($tmpstr, $binary_signature, $privateKey, $algo);
    $sign = base64_encode($binary_signature);
    return $sign;
    }

    支付回调 v3必须大于php7.2

    public function notify(){
    $result = $this->request->param();
    if($result){
    $text = base64_decode($result[‘resource’][‘ciphertext’]); //解密
    /* =========== 使用V3支付需要PHP7.2.6安装sodium扩展才能进行解密参数 ================ */
    $str = sodium_crypto_aead_aes256gcm_decrypt($text, $result[‘resource’][‘associated_data’], $result[‘resource’][‘nonce’], $this->apiV3Key);
    $res = json_decode($str, true);
    //如果成功返回了
    if($res[‘trade_state’] == ‘SUCCESS’){
    Db::startTrans();
    try {
    Db::name(‘service_order’)->where(‘orderno’,$res[‘out_trade_no’])->update([
    ‘pay_state’=>1,
    ‘transaction_id’=>$res[‘transaction_id’],
    ‘pay_time’=>time(),
    ‘status’=>1
    ]);
    $lid = Db::name(‘service_order’)->where(‘orderno’,$res[‘out_trade_no’])->value(‘lid’);
    if($lid){
    Db::name(‘service_list’)->where(‘id’,$lid)->setInc(‘sales’,1);
    }
    Db::commit();
    return $this->json_result(200,’支付成功’);
    }catch (DbException $e){
    return $this->json_result(400,$e->getMessage());
    }
    }
    }
    return $this->json_result(400,’支付失败’);
    }

    原文链接:https://blog.csdn.net/simplexiaobo/article/details/123945995

    自由转载,转载请注明: 转载自WEB开发笔记 www.chhua.com

    本文链接地址: 微信JSAPI支付V3版本 http://www.chhua.com/web-note5633

    随机笔记

    • 什么是WEB架构(网站架构)
    • PHP数组排序关于按中文拼音排序的问题
    • PHP:ImageMagick完美代替GB类库处理图像
    • WIN7下IE9卸载不能重新安装的解决办法
    • gvim 高亮关键字 开关行号和自动缩进,更改字体,更改行号颜色和背景颜色设置


沪ICP备19023445号-2号
友情链接