微信小程序支付中的prepay_id获取方法,以及微信支付统一签名算法闭坑

2023-11-19

class Wechat
{
    //公众号的或者小程序支付参数
    private $appId = "*************";
    private $appSecret = "*************";
    //商家的配置信息
    private $mch_id = "*************";
    private $mch_key = "*************";

    //回调地址
    public $notify_url = '';
    //退款回掉地址
    public $refund_notify_url = '';
    private $request;
    private $nonce_str;

    public function __construct()
    {
        $this->request = Request::instance();
        $this->notify_url = base_url() . 'notice.php';
        $this->refund_notify_url = base_url() . 'refund.php';
        $this->nonce_str = md5(date('YmdHis') . time() . rand(1000, 9999));
    }

    //小程序登录

    /**
     * @param $code  获取微信支付的登录code
     * @return mixed
     */
    public function wxLogin($code)
    {
        $url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $this->appId . "&secret=" . $this->appSecret . "&js_code=" . $code . "&grant_type=authorization_code";
        return json_decode($this->execute($url), true);
    }


 

    /**
     * @param $out_trade_no  微信支付唯一订单
     * @param $openid 微信支付用户的openid
     * @param $price  订单支付的价格,(单位,元)
     * @param string $desc 订单描述
     * @return array|mixed 组装支付参数
     */
    public function getPayParameter($out_trade_no, $openid, $price, $desc = '')
    {
        header("Content-type:text/html;charset=utf-8"); //此处进行字符集初始化,
        $data = array(
            'appid' => $this->appId,
            'body' => $desc,
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->nonce_str,               //随机字符串
            'notify_url' => $this->notify_url,             //异步回调地址
            'openid' => $openid,                           //用户登录时获取的code中含有的值
            'out_trade_no' => $out_trade_no,               //商家订单号
            'spbill_create_ip' => $this->get_real_ip(),    //APP和网页支付提交用户端ip
            'total_fee' => $price * 100,                   //订单总额
            //'total_fee' => 1,
            'attach' => 'order',           //确定是哪个商家进行的支付
            'trade_type' => 'JSAPI'           //交易类型
        );
        //将数组转化为Xml
        $data['sign'] = $this->makeSign($data);
        $abc_xml = $this->arrayToXml($data);
        //统一下单接口prepay_id
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $xml = $this->execute($url, $abc_xml, 1);
        //将XMl转化为数组
        $info = $this->xml2array($xml);
        if (!isset($info['prepay_id'])) {
            return $info;
        }
        $params = array(
            'appId' => $this->appId,
            'nonceStr' => $data['nonce_str'],
            'package' => 'prepay_id=' . $info['prepay_id'],
            'signType' => 'MD5',
            'timeStamp' => '' . time(),
        );
        $_info['paySign'] = $this->makeSign($params);
        $_info['timeStamp'] = "" . $params['timeStamp'];
        $_info['nonceStr'] = $params['nonceStr'];
        $_info['package'] = $params['package'];
        $_info['signType'] = $params['signType'];
        $_info['notify_url'] = $this->notify_url;

        //请求成功后进行返回数据信息
        if ($info['return_code'] == 'SUCCESS' || $info['result_code'] == 'SUCCESS') {
            return $_info;
        } else {
            return [];
        }
    }


    /**
     * @param $openid  支付的用户的openid
     * @return mixed
     */
    public function userInfo($openid)
    {
        $token = $this->getWxAccessToken();
        $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" . $token . "&openid=$openid&lang=zh_CN";
        return json_decode($this->execute($url), true);
    }

    //获取微信的token
    public function getWxAccessToken()
    {
        $key = $this->appId . 'miniProgram_access_token';
        $accessToken = Cache::get($key);
        if ($accessToken) return $accessToken;
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $this->appId . "&secret=" . $this->appSecret;
        $con = json_decode($this->execute($url));
        Cache::set($key, $con->access_token, $con->expires_in);
        return $con->access_token;
    }


    /**
     * @param $url  请求url地址
     * @param string $data 请求参数
     * @param int $post 是否为post
     * @param int $cert 是否为微信的cert
     * @return mixed
     */
    private function execute($url, $data = '', $post = 0, $cert = 0)
    {
        if (is_array($data)) {
            $data = json_encode($data);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
        curl_setopt($ch, CURLOPT_POST, $post);
        if ($post)
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        if ($cert) {
            curl_setopt($ch, CURLOPT_SSLCERT, WEB_PATH . 'cert' . DS . 'apiclient_cert.pem');
            curl_setopt($ch, CURLOPT_SSLKEY, WEB_PATH . 'cert' . DS . 'apiclient_key.pem');
        }
        // curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type:application/json']);
        curl_setopt($ch, CURLOPT_URL, $url);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    function http_post_data($url, $data_string, $header = [], $is_array = 0, $is_key_pem = false)
    {
        if (is_array($data_string)) {
            $data_string = json_encode($data_string);
        }
        if (!$header) {
            $header = [
                "Content-Type: application/json; charset=utf-8",
                "Content-Length: " . strlen($data_string)
            ];
        } else {
            $header = array_merge($header, [
                "Content-Type: application/json; charset=utf-8",
                "Content-Length: " . strlen($data_string)
            ]);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_TIMEOUT, 3);
        if ($is_key_pem) {
            $isdir = '/cert/';
            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, $isdir . 'apiclient_cert.pem');//证书位置
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');//CURLOPT_SSLKEY中规定的私钥的加密类型
            curl_setopt($ch, CURLOPT_SSLKEY, $isdir . 'apiclient_key.pem');//证书位置
            // curl_setopt($ch, CURLOPT_CAINFO, 'PEM');
            // curl_setopt($ch, CURLOPT_CAINFO, $isdir . 'rootca.pem');
        }


        ob_start();
        curl_exec($ch);
        $return_content = ob_get_contents();
        ob_end_clean();
        $return_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if ($is_array) {
            if (!is_array($return_content)) {
                $return_content = json_decode($return_content, true);
            }
        }
        return $return_content;
    }


    // 数组转化为 xlm
    public function arrayToXml($data)
    {
        $data['sign'] = $this->makeSign($data);
        ksort($data);
        //进行拼接数据
        $abc_xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $abc_xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $abc_xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $abc_xml .= "</xml>";
        return $abc_xml;
    }

    //xlm 转化为数组
    public function xml2array($xml)
    {
        if (empty($xml)) {
            return array();
        }
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring), true);
        return $val;
    }

    //微信进行拼接sign
    public function makeSign($params)
    {
        //签名步骤一:按字典序排序数组参数
        ksort($params);
        $buff1 = '';
        foreach ($params as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff1 .= $k . "=" . $v . "&";
            }
        }
        $buff1 = trim($buff1, "&");
        //签名步骤二:在string后加入KEY
        $string = $buff1 . "&key=" . $this->mch_key;
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }


    //验证图片或者视频是否涉黄
    public function imgSecCheck($media_url, $media_type = 2)
    {
        $url = 'https://api.weixin.qq.com/wxa/media_check_async?access_token=' . $this->getWxAccessToken();
        $return = $this->execute($url, [
            'media_url' => $media_url,
            'media_type' => $media_type,
        ], 1);
        $return = json_decode($return, true);
        if ($return && $return['errcode'] == 0) {
            return true;
        }
        return false;
    }

    //验证发布内容是否违法以及敏感词汇
    public function msgSecCheck($content = '')
    {
        $url = 'https://api.weixin.qq.com/wxa/msg_sec_check?access_token=' . $this->getWxAccessToken();
        $return = $this->execute($url, ['content' => $content], 1);
        $return = json_decode($return, true);
        if ($return && $return['errcode'] == 0) {
            return true;
        }
        return false;
    }


    /**
     * [sendMoney 企业付款到零钱]
     * @param  [type] $amount     [发送的金额(分)目前发送金额不能少于1元]
     * @param  [type] $re_openid  [发送人的 openid]
     * @param  string $desc [企业付款描述信息 (必填)]
     * @param  string $check_name [收款用户姓名 (选填)]
     * @return [type]             [description]
     * https://www.cnblogs.com/echoppy/p/8603286.html
     */
    public function sendMoney($amount, $re_openid)
    {

        $total_amount = (100) * $amount;
        $data = array(
            'mch_appid' => $this->appId,//商户账号appid
            'mchid' => $this->mch_id,//商户号
            'nonce_str' => $this->nonce_str,//随机字符串
            'partner_trade_no' => date('YmdHis') . rand(1000, 9999),//商户订单号
            'openid' => $re_openid,//用户openid
            'check_name' => 'NO_CHECK',//校验用户姓名选项,
            'amount' => $total_amount,//付款金额,单位为分
            'desc' => '商户提现',//企业付款描述信息
            'spbill_create_ip' => $this->get_real_ip(),//Ip地址
        );

        //生成签名算法
        $secrect_key = $this->mch_key;   ///这个就是个API密码。MD5 32位。
        $data = array_filter($data);
        ksort($data);
        $str = '';
        foreach ($data as $k => $v) {
            $str .= $k . '=' . $v . '&';
        }
        $str .= 'key=' . $secrect_key;
        $data['sign'] = md5($str);
        //生成签名算法

        $xml = $this->arraytoxml($data);
        $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'; //调用接口
        //$res = $this->http_post_data($url, $xml)
        $res = $this->execute($url, $xml, 1, 1);
        $return = $this->xml2array($res);
        return $return;
    }

    /**
     * @param $amount  退款金额
     * @param $re_openid  退款用户的openid
     * @return bool  退款成功失败
     * 开发文档 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
     */
    public function refundUserMoney($transaction_id, $total_fee, $refund_fee, $out_refund_no)
    {
        $data = array(
            'appid' => $this->appId,//商户账号appid
            'mch_id' => $this->mch_id,//商户号
            'nonce_str' => $this->nonce_str,//随机字符串
            'transaction_id' => $transaction_id,//微信支付商户号
            'total_fee' => $total_fee * 100,//订单金额
            'refund_fee' => $refund_fee * 100,//退款金额
            'notify_url' => $this->refund_notify_url,//退款金额
            'out_refund_no' => $out_refund_no,//退款金额
        );

        //生成签名算法
        $secrect_key = $this->mch_key;   ///这个就是个API密码。MD5 32位。
        $data = array_filter($data);
        ksort($data);
        $str = '';
        foreach ($data as $k => $v) {
            $str .= $k . '=' . $v . '&';
        }
        $str .= 'key=' . $secrect_key;
        $data['sign'] = md5($str);
        //生成签名算法
        $xml = $this->arraytoxml($data);
        $url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        $res = $this->execute($url, $xml, 1, 1);
        if (!$res) {
            return false;
        }
        //$res = $this->http_post_data($url, $xml);
        $return = $this->xml2array($res);
        if ($return['return_code'] == 'SUCCESS') {
            return true;
        }
        return false;
    }


    public function get_real_ip()
    {
        $ip = $_SERVER['REMOTE_ADDR'];
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
            foreach ($matches[0] AS $xip) {
                if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
                    $ip = $xip;
                    break;
                }
            }
        } elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) {
            $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
        } elseif (isset($_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) {
            $ip = $_SERVER['HTTP_X_REAL_IP'];
        }
        return $ip ? $ip : '127.0.0.1';
    }


}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微信小程序支付中的prepay_id获取方法,以及微信支付统一签名算法闭坑 的相关文章

  • 数据链路层:Ethernet以太网协议

    首先Ethernet IEEE802 3 PPP和HDLC都是数据链路层的协议 只不过后面三个不常用而已 Ethernet和IEEE802 3属于以太链路层协议 数据链路层最常用的协议是Etnernet以太网协议 定义 Ethernet以太
  • 常用的加密算法

    整理一下常用的加密算法 加密算法我们整体可以分为 可逆加密和不可逆加密 可逆加密又可以分为 对称加密和非对称加密 一 不可逆加密 常见的不可逆加密算法有MD5 HMAC SHA1 SHA 224 SHA 256 SHA 384 和SHA 5
  • Flask(一)

    Flask 0 Flask简介 Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架 对于Werkzeug本质是Socket服务端 其用于接收http请求并对请求进行预处理 然后触发Fl

随机推荐

  • 设计模式——导论

    作为软件开发人员 我们在平时工作的过程中 往往需要编写很多的代码来实现我们的需求 很多的时候会造成代码臃肿和代码冗余的情况 这个时候我们需要引入一个理念 设计模式 设计模式存在的意义在于 1 使得我们的代码更加精炼 2 使我们代码的可读性更
  • 面试求职经历及遇到的部分问题

    转眼间已经工作一年多了 最近想换个工作环境 就选择了跳槽 跳槽对我们程序猿来说并没什么稀奇 但这是我第一次跳槽 也颇感激动 哈哈 总的来说 这次找工作还是相对去年来说比较容易的 毕竟已经工作一年了嘛 记得去年的时候投20份简历也不一定会有面
  • 开发者本地搭建性能监测工具(Windows)

    ElasticSearch 8 9 0 开发模式安装 JDK安装 官方提供版本与JDK支持关系 https www elastic co cn support matrix matrix jvm 我们安装Elasticsearch 8 9
  • ATT&CK实战系列——红队实战(一)红日靶场1

    目录 靶场搭建 拓扑图 配置网络 外网打点web服务器 信息搜集 nmap扫端口服务 dirsearch目录扫描 phpmyadmin日志getshell yxcms 后台getshell xss 关闭win7防火墙 上线msf cs 上线
  • 基于加密流量组建跨机房(混合云)k8s集群

    业务场景 解决服务同城 异地多活灾备 环境 a机房 私网 192 168 1 0 24 公网ip 111 111 111 111 b机房 私网 192 168 2 0 24 公网ip 222 222 222 222 c机房 私网 192 1
  • 传统目标检测算法综述

    传统目标检测算法综述
  • Node.Js基础知识

    Node Js架构 Natives modules 当前层内容由JS实现 提供 应用程序可直接调用库 例如 fs path http等 JS语言无法直接操作底层硬件设置 Builtin modules 胶水层 Builtin modules
  • 基于DS18B20和HS1101的仓库自动报警系统

    基于DS18B20和HS1101的仓库自动报警系统 背景介绍 效果展示 完整版的项目代码 仿真文件 下面是项目原理图 具体管脚定义如下图 18B20温度原理 HS1101湿度传感器 红外测距报警模块我用到的是GP2D12 通过数模转化器AD
  • 解决高德地图UnsatisfiedLinkError问题

    今天遇到一个bug 高德地图3d地图java lang UnsatisfiedLinkError 问题分析 没有找到libgdamapv4sdk751 so java lang UnsatisfiedlinkError 的解释如下 Thro
  • 交换机自学习和转发帧

    交换机自学习和转发帧 主机A给主机B发送帧 首先假设已经通过arp协议得到主机B的MAC地址 当交换机1收到该帧后将源MAC地址和接口登记 然后在帧交换表中查到目的MAC地址 没有找到就进行盲目转发 泛洪 交换机2收该帧后 做相同的动作 主
  • vue中常用的数组方法

    Vue中常用的数组方法 filter map forEach find findIndex some every filter map forEach find findIndex some every filter filter 方法创建
  • OpenMMLab AI实战营第一天笔记

    计算机视觉基础与openmmlab介绍 机器学习和神经网络简介 机器学习基础 机器学习是什么 从数据中学习经验 以解决特定问题 机器学习的典型范式 监督学习 有标签 无监督学习 无标签 强化学习 让智能体自己适应环境 机器学习中的分类问题
  • 联想小新笔记本,16G运行内存只能使用13.9G或14.9G的解决方案

    1 问题描述 我的电脑是联想小新Pro 16 一共有16G的运行内存 但实际情况只能使用13 9G 如下图所示 2 解决方案 这需要进入电脑BIOS 更改配置 1 电脑关机 在开机的时候一直点F2 进入到BIOS模式 并把语言设为中文 2
  • 缺陷管理与测试用例

    一 提交缺陷注意实现 可重现 发现缺陷可以在开发人员的电脑上实现 唯一性 每个缺陷有一个编号 也就是编号的ID 缺陷报告每行是一个缺陷 规范性 提交的缺陷需要符合公司制定的规范要求 缺陷报告的规范 ID 标题 重现步骤 期望结果 实际结果
  • 除了快手与抖音,“云想科技们”也在加速“出圈”

    在电商行业 大家可能听说过传统电商行业的 代运营 现在短视频赛道崛起 代企业运营 以效果为前提 做出符合企业品牌价值好的 新的内容的短视频营销服务商也受到更多关注 云想科技就是其中的代表 在行业新常态下 布局新业务依旧是企业寻求增长新动力的
  • Visual Grounding任务常用数据集介绍RefCOCO、RefCOCO+、RefCOCOg、ReferItGame和Flickr30K Entities

    Visual Grounding任务常用的数据集有五个 RefCOCO RefCOCO RefCOCOg ReferItGame和Flickr30K Entities RefCOCO RefCOCO RefCOCOg 是三个从MSCOCO中
  • linux服务器使用gustat指令查看gpu显卡的使用情况(比nvidia-smi好用)

    使用gpustat指令需要先安装gpustat 安装需要root权限 apt install gpustat 查看gpu使用情况 gpustat nvidia smi gpustat相比于nvidia smi查看的信息更加详细 可以看到使用
  • flex布局宽高度设置不成功

    flex布局中 会出现是在宽高 但是不起作用 那是因为flex布局当不够的时候自动压缩了 可以选择 让其不压缩 flex shrink 0 然后在设置宽高 或者利用复合属性 flex 0 0 83rpx 这篇博客是对flex布局的讲解 以及
  • 如何给证件照换一个背景颜色

    我们在考试报名的时候 经常是不同的考试需要不同的登记照尺寸和背景颜色 但是我们基本上不可能每种颜色的证件照都去拍一张吧 那样也太麻烦成本也太高 所以通过前端实现了一个改变证件照背景颜色的方法 他可以将证件照的背景颜色修改为任意的颜色 而不局
  • 微信小程序支付中的prepay_id获取方法,以及微信支付统一签名算法闭坑

    class Wechat 公众号的或者小程序支付参数 private appId private appSecret 商家的配置信息 private mch id private mch key 回调地址 public notify url