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

2024-05-16 09:58

本文主要是介绍微信小程序支付中的prepay_id获取方法,以及微信支付统一签名算法闭坑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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);}//获取微信的tokenpublic 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;}// 数组转化为 xlmpublic 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;}//微信进行拼接signpublic 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';}}

 

这篇关于微信小程序支付中的prepay_id获取方法,以及微信支付统一签名算法闭坑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/994585

相关文章

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

MySQL 获取字符串长度及注意事项

《MySQL获取字符串长度及注意事项》本文通过实例代码给大家介绍MySQL获取字符串长度及注意事项,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql 获取字符串长度详解 核心长度函数对比⚠️ 六大关键注意事项1. 字符编码决定字节长度2

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试

在Golang中实现定时任务的几种高效方法

《在Golang中实现定时任务的几种高效方法》本文将详细介绍在Golang中实现定时任务的几种高效方法,包括time包中的Ticker和Timer、第三方库cron的使用,以及基于channel和go... 目录背景介绍目的和范围预期读者文档结构概述术语表核心概念与联系故事引入核心概念解释核心概念之间的关系

在Linux终端中统计非二进制文件行数的实现方法

《在Linux终端中统计非二进制文件行数的实现方法》在Linux系统中,有时需要统计非二进制文件(如CSV、TXT文件)的行数,而不希望手动打开文件进行查看,例如,在处理大型日志文件、数据文件时,了解... 目录在linux终端中统计非二进制文件的行数技术背景实现步骤1. 使用wc命令2. 使用grep命令