Model

<?php

/**
* User: Eden
* Date: 2019/3/21
* 共有内容
*/ class WxPayModel extends Model {
protected static $SSL_CERT_PATH = './apiclient_cert.pem';//证书路径
protected static $SSL_KEY_PATH = './apiclient_key.pem';//证书路径 public static function unifiedOrder($openid,$order_num,$total_fee,$products_name,$notify_url = ''){
$trade_no = $order_num;
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$param = [
'appid' => C('APPID'),
'mch_id' => C('MCHID'),
'nonce_str' => self::createNonceStr(),
'sign_type' => 'MD5',
'body' => $products_name, //商品名称组合
'attach' => C('APP_NAME').'-附加信息',
'out_trade_no' => $trade_no, //订单号
'fee_type' => 'CNY',
'total_fee' => $total_fee,
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'goods_tag' => C('APP_NAME').'-商品标记',
'notify_url' => $notify_url ?:C('NOTIFY_URL'),
'trade_type' => 'JSAPI',
'openid' => $openid
]; $sign = self::MakeSign($param);
$param['sign'] = $sign;
$xml = self::ToXml($param);
$result = self::FromXml(Http::postXmlCurl($url,$xml));
setlog($param,$result,__METHOD__); // 加工数据
$data = [
'appId' => $result['appid'] ?: C('APPID'),
'timeStamp' => time(),
'nonceStr' => self::createNonceStr(),
'package' => 'prepay_id=' . $result['prepay_id'],
'signType' => 'MD5'
];
$sign = self::MakeSign($data);
$data['sign'] = $sign;
return $data;
} /**
* 处理退款
* @param $out_trade_no
* @param $total_fee
* @param $refund_fee
* @return array
* @throws Exception
*/
public static function refundOrder($out_trade_no,$total_fee,$refund_fee) {
$refund_no = $out_trade_no.rand('1111,9999');
$param = array(
'appid' => C('APPID'),
'mch_id' => C('MCHID'),
'nonce_str' => self::createNonceStr(),
'out_refund_no' => $refund_no, //由后端生成的退款单号,需要保证唯一,因为多个同样的退款单号只会退款一次。
'out_trade_no' => $out_trade_no, //退款订单在支付时生成的订单号
'total_fee' => $total_fee,
'refund_fee' => $refund_fee,
'op_user_id' => C('MCHID'), //操作员 op_user_id .与商户号相同即可
); $param['sign'] = self::MakeSign($param);
$xml_data = self::ToXml($param);
$xml_result = self::postXmlSSLCurl($xml_data,'https://api.mch.weixin.qq.com/secapi/pay/refund');
$result = self::FromXml($xml_result);
setlog($param,$result,__METHOD__); if (!$result){
$result_arr = [
'num' => '0',
'desc' => '接口错误',
];
return $result_arr;
} if ($result['result_code'] != 'SUCCESS'){
$result_arr = [
'num' => '-1',
'desc' => $result['err_code_des']
];
} else {
$result_arr = [
'num' => '1',
'desc' => '退款成功',
'refund_id' => $result['refund_id'],
'refund_no' => $refund_no,
];
} return $result_arr;
} public static function FromXml($xml)
{
if(!$xml){
throw new Exception("xml数据异常!");
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $values;
} public static function ToXml($array){
if(!is_array($array)|| count($array) <= 0){
return ;
}
$xml = '<xml version="1.0">';
foreach ($array as $key=>$val){
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
} public static function createNonceStr($length = 16) {
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ( $i = 0; $i < $length; $i++ ) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
} public static function MakeSign($data)
{
//签名步骤一:按字典序排序参数
ksort($data);
$string = self::ToUrlParams($data);
//签名步骤二:在string后加入KEY
$string = $string . "&key=".C('WEIXIN_PAY_KEY');
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
} public static function ToUrlParams($array)
{
$buff = "";
foreach ($array as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
} /**
* 需要使用证书的请求
*/
public static function postXmlSSLCurl($xml,$url,$second=30)
{
$ch = curl_init();
//超时时间
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
//这里设置代理,如果有的话
//curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
//默认格式为PEM,可以注释
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERT, self::$SSL_CERT_PATH);
//默认格式为PEM,可以注释
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, self::$SSL_KEY_PATH);
//post提交方式
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
echo "curl出错,错误码:$error" . "<br>";
curl_close($ch);
return false;
}
}
}

Vendor类

<?php

/**
* User: Eden
* Date: 2019/3/21
* 共有内容
*/ class WxPay {
protected static $SSL_CERT_PATH = './apiclient_cert.pem';//证书路径
protected static $SSL_KEY_PATH = './apiclient_key.pem';//证书路径 public static function unifiedOrder($openid,$order_num,$total_fee,$products_name,$notify_url = ''){
$trade_no = $order_num;
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$param = [
'appid' => C('APPID'),
'mch_id' => C('MCHID'),
'nonce_str' => self::createNonceStr(),
'sign_type' => 'MD5',
'body' => $products_name, //商品名称组合
'attach' => C('APP_NAME').'-附加信息',
'out_trade_no' => $trade_no, //订单号
'fee_type' => 'CNY',
'total_fee' => $total_fee,
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'goods_tag' => C('APP_NAME').'-商品标记',
'notify_url' => $notify_url ?:C('NOTIFY_URL'),
'trade_type' => 'JSAPI',
'openid' => $openid
]; $sign = self::MakeSign($param);
$param['sign'] = $sign;
$xml = self::ToXml($param);
$result = self::FromXml(Http::postXmlCurl($url,$xml));
setlog($param,$result,__METHOD__); // 加工数据
$data = [
'appId' => $result['appid'] ?: C('APPID'),
'timeStamp' => time(),
'nonceStr' => self::createNonceStr(),
'package' => 'prepay_id=' . $result['prepay_id'],
'signType' => 'MD5'
];
$sign = self::MakeSign($data);
$data['sign'] = $sign;
return $data;
} /**
* 处理退款
* @param $out_trade_no
* @param $total_fee
* @param $refund_fee
* @return array
* @throws Exception
*/
public static function refundOrder($out_trade_no,$total_fee,$refund_fee) {
$refund_no = $out_trade_no.rand('1111,9999');
$param = array(
'appid' => C('APPID'),
'mch_id' => C('MCHID'),
'nonce_str' => self::createNonceStr(),
'out_refund_no' => $refund_no, //由后端生成的退款单号,需要保证唯一,因为多个同样的退款单号只会退款一次。
'out_trade_no' => $out_trade_no, //退款订单在支付时生成的订单号
'total_fee' => $total_fee,
'refund_fee' => $refund_fee,
'op_user_id' => C('MCHID'), //操作员 op_user_id .与商户号相同即可
); $param['sign'] = self::MakeSign($param);
$xml_data = self::ToXml($param);
$xml_result = self::postXmlSSLCurl($xml_data,'https://api.mch.weixin.qq.com/secapi/pay/refund');
$result = self::FromXml($xml_result);
setlog($param,$result,__METHOD__); if (!$result){
$result_arr = [
'num' => '0',
'desc' => '接口错误',
];
return $result_arr;
} if ($result['result_code'] != 'SUCCESS'){
$result_arr = [
'num' => '-1',
'desc' => $result['err_code_des']
];
} else {
$result_arr = [
'num' => '1',
'desc' => '退款成功',
'refund_id' => $result['refund_id'],
'refund_no' => $refund_no,
];
} return $result_arr;
} public static function FromXml($xml)
{
if(!$xml){
throw new Exception("xml数据异常!");
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $values;
} public static function ToXml($array){
if(!is_array($array)|| count($array) <= 0){
return ;
}
$xml = '<xml version="1.0">';
foreach ($array as $key=>$val){
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
} public static function createNonceStr($length = 16) {
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ( $i = 0; $i < $length; $i++ ) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
} public static function MakeSign($data)
{
//签名步骤一:按字典序排序参数
ksort($data);
$string = self::ToUrlParams($data);
//签名步骤二:在string后加入KEY
$string = $string . "&key=".C('WEIXIN_PAY_KEY');
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
} public static function ToUrlParams($array)
{
$buff = "";
foreach ($array as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
} /**
* 需要使用证书的请求
*/
public static function postXmlSSLCurl($xml,$url,$second=30)
{
$ch = curl_init();
//超时时间
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
//这里设置代理,如果有的话
//curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
//默认格式为PEM,可以注释
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERT, self::$SSL_CERT_PATH);
//默认格式为PEM,可以注释
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, self::$SSL_KEY_PATH);
//post提交方式
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
echo "curl出错,错误码:$error" . "<br>";
curl_close($ch);
return false;
}
}
}

使用效果差不多。

封装一个Model或者Vender类的更多相关文章

  1. python+selenium之自定义封装一个简单的Log类

    python+selenium之自定义封装一个简单的Log类 一. 问题分析: 我们需要封装一个简单的日志类,主要有以下内容: 1. 生成的日志文件格式是 年月日时分秒.log 2. 生成的xxx.l ...

  2. Python之自定义封装一个简单的Log类

    参考:http://www.jb51.net/article/42626.htm 参考:http://blog.csdn.net/u011541946/article/details/70198676 ...

  3. Python+Selenium中级篇之8-Python自定义封装一个简单的Log类《转载》

    Python+Selenium中级篇之8-Python自定义封装一个简单的Log类: https://blog.csdn.net/u011541946/article/details/70198676

  4. java模板模式项目中使用--封装一个http请求工具类

    需要调用http接口的代码继承FundHttpTemplate类,重写getParamData方法,在getParamDate里写调用逻辑. 模板: package com.crb.ocms.fund ...

  5. PHP封装一个通用好用的文件上传处理类

    封装一个文件上传类完成基本功能如下: 1.可上传多个或单个文件 2.上传成功返回一个或多个文件名 3.上传失败则返回每个失败文件的错误信息 上传类中的基本功能: 1.构造参数,用户可以自定义配置参数, ...

  6. Directx11学习笔记【四】 封装一个简单的Dx11DemoBase

    根据前面两个笔记的内容,我们来封装一个简单的基类,方便以后的使用. 代码和前面类似,没有什么新的内容,直接看代码吧(由于代码上次都注释了,这次代码就没怎么写注释o(╯□╰)o) Dx11DemoBas ...

  7. 第二十二章、 Model/View便利类树型部件QTreeWidget

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.引言 树部件(Tree Widget)是Qt Designer中 Item Widgets(It ...

  8. Swift - 简单封装一个工具类模板

    创建模板类(封装一个类) 例1:新建一个名字叫做 Product 的类 Product.swift File 的内容 class Product { var name: String var desc ...

  9. 基于AFNetWorking封装一个网络请求数据的类

    1.新建一个继承于NSObject类的类,在.h文件中 #import "AFHTTPRequestOperationManager.h" //定义两个block来接收请求成功和失 ...

随机推荐

  1. a problem

    给出两个长度为 $n$ 的数组 $a, b$对于任意的 $a_i + b_j$, 求第 $k$ 大 不妨设 $a_i < a_{i + 1}, b_i < b_{i + 1}$ 对于任意的 ...

  2. 【luogu3950】部落冲突--树剖

    题目背景 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多 ...

  3. Unity使用Xcode将项目打包成IPA

    https://blog.csdn.net/Superficialtise/article/details/79699813 Unity是个开放性的平台,打包时也可以选择多种打包类型,几乎包含了所有的 ...

  4. 扩展kmp学习笔记

    kmp没写过,扩展kmp没学过可还行. 两个愿望,一次满足 (该博客仅用于防止自己忘记,不保证初学者能看懂我在瞎bb什么qwq) 用途 对于串\(s1,s2\),可以求出\(s2\)与\(s1\)的每 ...

  5. kaptcha 配置

    问题所在: 这一段配置,不要写在 SpringMVC 文件中,要写在 Spring 配置文件! <!-- kaptcha 验证码 --> <bean id="captcha ...

  6. Java 多线程示例

    /** * 多线程案例 两种方式 模拟买票程序(不考虑线程安全问题) */ public class ThreadTest { public static void main(String[] arg ...

  7. 【java反射】

    反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释. 一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的.于是我们直接对这个类进行实例化,之后使用这个类对象进行操作. A ...

  8. 走进JavaWeb技术世界10:从JavaBean讲到Spring

    Java 帝国之Java bean (上) 转自: 刘欣 码农翻身 2016-05-27 前言: 最近看到到spring 的bean 配置, 突然想到可能很多人不一定知道这个叫bean的东西的来龙去脉 ...

  9. JAVA爬虫对font-face字体反爬虫解密

    1.参考博客          https://www.jianshu.com/p/9975de57b0ce          https://blog.csdn.net/litang199612/a ...

  10. SVG-概述/容器与通用属性

    参考: SVG 图像入门教程 MDN SVG SVG教程 SVG入门-踏得 工具: svg在线编辑 概述 SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector ...