<?php
/**
* Created by PhpStorm.
* Date: 2019/11/1-11:33
* Author: LuckyHhy
* 微信企业打款到个人,微信退款,微信扫码支付,退款查询,h5支付
*/
namespace service;
const SSLCERT_PATH = 'wxpay/wxcert/apiclient_cert.pem'; //本地证书地址
const SSLKEY_PATH ='wxpay/wxcert/apiclient_key.pem'; //本地证书地址
class WxPayService
{
protected $config;
public function __construct(array $config){
//微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
if(empty($config["Mchid"])){
die("商户号不能为空");
}
//APPID 通过微信支付商户资料审核后邮件发送
if(empty($config['AppID'])){
die("商户账号appid不能为空");
}
//https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
if(empty($config['key'])){
die("key不能为空");
}
$this->config=$config;
}
/**
* @param $openid
* @param $order_id
* @param $user_name
* @param $amount
* @param $desc
* @return array
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: PayMoney
* @describe:企业付款 (给指定用户openid打款,转到用用户微信的零钱包里,用于用户申请提现)
*/
public function PayMoney($openid,$order_id,$user_name,$amount,$desc){
$params = [
'mch_appid'=> $this->config['AppID'],//,, //商户账号appid
'mchid'=>$this->config['Mchid'], //商户号
'nonce_str'=>$this->createNonceStr(), //随机字符串
'openid'=>$openid,//$openid,//"omMIK43hZfZgChb4vvEDMxrRLJ0c",//个人收款账号(用户的openid),
'partner_trade_no'=>$order_id,//$order_id //'pu'.mt_rand(10000,99999), //商户订单号,需保持唯一性(只能是字母或者数字,不能包含有其他字符)
'check_name'=>'NO_CHECK', //NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
're_user_name'=>$user_name, // 收款用户真实姓名。'check_name'='FORCE_CHECK' 必填
'amount'=>intval($amount * 100), // 企业付款金额,单位为元 (不能低于3毛钱)
'desc'=>$desc, //企业付款备注,必填
'spbill_create_ip'=>"", //该IP同在商户平台设置的IP白名单中的IP没有关联,该IP可传用户端或者服务端的IP。'127.0.0.1'
];
//发起打款式的请求
$api_url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
//请求接口
$arr=$this->unifiedorder($api_url,$params);
$resArr=array();
if($arr['result_code'] == 'SUCCESS' && $arr['return_code'] == 'SUCCESS'){
$resArr["code"] = 1;
}else{
$resArr["code"] = 0;
}
$resArr["callback_result"] = json_encode($arr,JSON_UNESCAPED_UNICODE);
return $resArr;
}
/**
* @param $orderInfo
* @return array
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: WxBackMoney
* @describe:微信订单号退款
*/
public function WxBackMoney($orderInfo){
$params = [
'appid'=> $this->config['AppID'],//微信分配的小程序ID
'mch_id'=>$this->config['Mchid'], //微信支付分配的商户号
'nonce_str'=>$this->createNonceStr(), //随机字符串
'out_refund_no'=>$orderInfo["order_code"],//商户退款单号
'total_fee'=>intval($orderInfo["money"]*100),//订单总金额 单位为元
'refund_fee'=>intval($orderInfo["money"]*100),//退款金额 单位为元
'out_trade_no'=>$orderInfo["order_code"],// 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有其他字符)
];
//退款请求地址
$api_url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
//请求接口
$arr=$this->unifiedorder($api_url,$params);
$resArr=array();
if($arr['result_code'] == 'SUCCESS' && $arr['return_code'] == 'SUCCESS'){
$resArr["code"] = 0;
}else{
$resArr["code"] = 1;
}
$resArr["callback_result"] = $arr;
return $resArr;
}
/**
* 使用例子
$mchid = ""; //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
$appid = ""; //公众号APPID 通过微信支付商户资料审核后邮件发送
$apiKey = ""; //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
$wxPay = new WxpayService($mchid,$appid,$apiKey);//实例化微信扫码类
$outTradeNo = time().$themeEnlist['enlist_card'].mt_rand(10,99);//商品订单号
$notifyUrl = SystemConfig::getValue('site_url').Url::build('index/Themeenlist/wapay_success_notify'); //付款成功后的回调地址(不要有问号)
$payTime = time(); //付款时间
$payAmount=1;
$arr = $wxPay->createJsBizPackage($payAmount,$outTradeNo,$orderName,$notifyUrl,$payTime);//创建成功会微信返回的数据
$url = 'http://qr.topscan.com/api.php?text='.$arr['code_url'];//生成二维码(连接失效可以自己生产二维码)
*/
/**
* @param $totalFee //收款总费用 单位元
* @param $outTradeNo //唯一的订单号
* @param $orderName //订单名称
* @param $notifyUrl //支付结果通知url 不要有问号
* @param $timestamp
* @return array
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: createJsBizPackage
* @describe: 发起订单,扫码支付
*/
public function createJsBizPackage($totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp)
{
//$orderName = iconv('GBK','UTF-8',$orderName);
$unified = array(
'appid' => $this->config['AppID'],
'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
'body' => $orderName,
'mch_id' => $this->config['Mchid'],
'nonce_str' =>$this->createNonceStr(),
'notify_url' => $notifyUrl,
'out_trade_no' => $outTradeNo,
'spbill_create_ip' => '127.0.0.1',
'total_fee' => intval($totalFee * 100), //单位 转为分
'trade_type' => 'NATIVE',
);
$unified['sign'] = $this->getSigns($unified, $this->config['key']);
$responseXml = $this->curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', $this->ArrToXml($unified));
$unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($unifiedOrder === false) {
die('parse xml error');
}
if ($unifiedOrder->return_code != 'SUCCESS') {
die($unifiedOrder->return_msg);
}
if ($unifiedOrder->result_code != 'SUCCESS') {
die($unifiedOrder->err_code);
}
$codeUrl = (array)($unifiedOrder->code_url);
if(!$codeUrl[0]) exit('get code_url error');
$arr = array(
"appId" => $this->config['AppID'],
"timeStamp" => $timestamp,
"nonceStr" => $this->createNonceStr(),
"package" => "prepay_id=" . $unifiedOrder->prepay_id,
"signType" => 'MD5',
"code_url" => $codeUrl[0],
);
$arr['paySign'] = $this->getSigns($arr, $this->config['key']);
return $arr;
}
/**
* @param string $refundNo 商户退款单号
* @param string $wxOrderNo 微信订单号
* @param string $orderNo 商户订单号
* @param string $refundId 微信退款单号
* @return bool
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: doRefundQuery
* @describe:退款查询
*/
public function doRefundQuery($refundNo='', $wxOrderNo='',$orderNo='',$refundId='')
{
$unified = array(
'appid' => $this->config['AppID'],
'mch_id' => $this->config['Mchid'],
'nonce_str' => $this->createNonceStr(),
'sign_type' => 'MD5', //签名类型 支持HMAC-SHA256和MD5,默认为MD5
'transaction_id'=>$wxOrderNo, //微信订单号
'out_trade_no'=>$orderNo, //商户订单号
'out_refund_no'=>$refundNo, //商户退款单号
'refund_id'=>$refundId, //微信退款单号
);
$unified['sign'] = $this->getSign($unified, $this->config['key']);
$responseXml = $this->curlPost('https://api.mch.weixin.qq.com/pay/refundquery', $this->ArrToXml($unified));
@file_put_contents('2.txt',$responseXml);
$unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($unifiedOrder === false) {
die('parse xml error');
}
if ($unifiedOrder->return_code != 'SUCCESS') {
die($unifiedOrder->return_msg);
}
if ($unifiedOrder->result_code != 'SUCCESS') {
die($unifiedOrder->err_code);
}
return true;
}
/**
* @param //金额
* @param $out_trade_no //订单号
* @param $order_name //订单标题
* @param $auth_code //用户付款码(商户使用设备扫码用户的付款条码读取到的条码数字,或 打开微信-》我-》钱包-》收付款 点击可查看付款码数字)
* @return array
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: PayCardPackage
* @describe: 微信刷码支付
*/
public function PayCardPackage($total_fee,$out_trade_no,$order_name,$auth_code)
{
//$order_name = iconv('GBK','UTF-8',$order_name);
$unified = array(
'appid' => $this->config['AppID'],
'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
'body' => $order_name,
'mch_id' => $this->config['Mchid'],
'nonce_str' => $this->createNonceStr(),
'out_trade_no' => $out_trade_no,
'spbill_create_ip' => '127.0.0.1',
'total_fee' => intval($total_fee * 100), //单位 转为分
'auth_code'=>$auth_code, //收款码,
'device_info'=>'dedemao001', //终端设备号(商户自定义,如门店编号)
// 'limit_pay'=>'no_credit' //指定支付方式 no_credit--指定不能使用信用卡支付
);
$unified['sign'] = $this->getSign($unified, $this->config['key']);
$responseXml = $this->curlPost('https://api.mch.weixin.qq.com/pay/micropay', $this->ArrToXml($unified));
$unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($unifiedOrder === false) {
die('parse xml error');
}
if ($unifiedOrder->return_code != 'SUCCESS') {
die('支付失败:错误码:'.$unifiedOrder->err_code.'。错误码说明:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1#7');
}
if ($unifiedOrder->result_code != 'SUCCESS') {
die('支付失败:错误码:'.$unifiedOrder->err_code.'。错误码说明:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1#7');
}
return (array)$unifiedOrder;
}
/**
* @param $wapUrl //WAP网站URL地址
* @param $wapName //WAP 网站名
* @param $orderName //订单标题
* @param $notifyUrl //付款成功后的回调地址(不要有问号)
* @param $outTradeNo //订单号
* @param $totalFee //金额
* @return \SimpleXMLElement
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: PayH5Package
* @describe: 微信H5 支付
*/
public function PayH5Package($wapUrl,$wapName,$orderName,$notifyUrl,$outTradeNo,$totalFee)
{
$scene_info = array(
'h5_info' =>array(
'type'=>'Wap',
'wap_url'=>$wapUrl,
'wap_name'=>$wapName,
)
);
$unified = array(
'appid' =>$this->config['appid'],
'attach' => 'pay', //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
'body' => $orderName,
'mch_id' => $this->config['mch_id'],
'nonce_str' => $this->createNonceStr(),
'notify_url' => $notifyUrl,
'out_trade_no' => $outTradeNo,
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'total_fee' => intval($totalFee * 100), //单位 转为元
'trade_type' => 'MWEB',
'scene_info'=>json_encode($scene_info)
);
$unified['sign'] = $this->getSign($unified, $this->config['key']);
$responseXml = $this->curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', $this->ArrToXml($unified));
$unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($unifiedOrder->return_code != 'SUCCESS') {
die($unifiedOrder->return_msg);
}
if($unifiedOrder->mweb_url){
return $unifiedOrder->mweb_url;
}
exit('error');
}
/**
* @return \SimpleXMLElement
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: notify
* @describe:回调通知
*/
public function notify()
{
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($postObj === false) {
die('parse xml error');
}
if ($postObj->return_code != 'SUCCESS') {
die($postObj->return_msg);
}
if ($postObj->result_code != 'SUCCESS') {
die($postObj->err_code);
}
$arr = (array)$postObj;
unset($arr['sign']);
if ($this->getSigns($arr, $this->config['key']) == $postObj->sign) {
echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
return $postObj;
}
}
/**
* 获取签名
*/
private function getSigns($params, $key)
{
ksort($params, SORT_STRING);
$unSignParaString = $this->formatQueryParaMap($params, false);
$signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
return $signStr;
}
/**
* @param $paraMap
* @param bool $urlEncode
* @return bool|string
* @author: hhygyl <hhygyl520@qq.com>
* @name: formatQueryParaMap
* @describe:格式化
*/
private function formatQueryParaMap($paraMap, $urlEncode = false)
{
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if (null != $v && "null" != $v) {
if ($urlEncode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
}
$reqPar = '';
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
/**
* @param int $length
* @return string
* @author: hhygyl <hhygyl520@qq.com>
* @name: createNonceStr
* @describe:生成随机字符串
*/
private function createNonceStr($length = 16)
{
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
/**
* @param $api_url
* @param $params
* @return mixed|string
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: unifiedorder
* @describe: //文档对接地址: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4
*/
private function unifiedorder($api_url,$params){
//获取到带签名的数组
$params = $this->setSign($params);
//数组转xml
$xml = $this->ArrToXml($params);
//发送数据到统一下单API地址
$data = $this->curlPost($api_url,$xml);
$arr = $this->XmlToArr($data);
return $arr;
}
/**
* @param $arr
* @return string
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: getSign
* @describe: 获取签名
*/
private function getSign($arr){
//去除数组的空值
array_filter($arr);
if(isset($arr['sign'])){
unset($arr['sign']);
}
//排序
ksort($arr);
//组装字符
$str = $this->arrToUrl($arr) . '&key=' . $this->config['key'];
//使用md5 加密 转换成大写
return strtoupper(md5($str));
}
/**
* @param $arr
* @return mixed
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: setSign
* @describe:获取带签名的数组
*/
private function setSign($arr){
$arr['sign'] = $this->getSign($arr);
return $arr;
}
/**
* @param $arr
* @return string
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: arrToUrl
* @describe:数组转URL字符串 不带key
*/
private function arrToUrl($arr){
return urldecode(http_build_query($arr));
}
/**
* @return false|string
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: getPost
* @describe:
*/
protected function getPost(){
return @file_get_contents('php://input');
}
/**
* @param $xml
* @return mixed|string
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: XmlToArr
* @describe:Xml 文件转数组
*/
private function XmlToArr($xml)
{
if($xml == '') return '';
libxml_disable_entity_loader(true);
$arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $arr;
}
/**
* @param $arr
* @return string
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: ArrToXml
* @describe:数组转XML
*/
private function ArrToXml($arr)
{
if(!is_array($arr) || count($arr) == 0) return '';
$xml = "<xml>";
foreach ($arr as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
/**
* @param string $url
* @param string $postData
* @param array $options
* @return bool|string
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: curlPost
* @describe:
*/
private function curlPost($url = '', $postData = '', $options = array())
{
if (is_array($postData)) {
$postData = http_build_query($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_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);
//第一种方法,cert 与 key 分别属于两个.pem文件
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT,SSLCERT_PATH);
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY,SSLKEY_PATH);
//第二种方式,两个文件合成一个.pem文件
// curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
/**
* @param string $url
* @param array $options
* @return bool|string
* @author: LuckyHhy <jackhhy520@qq.com>
* @name: curlGet
* @describe:get 请求
*/
private function curlGet($url = '', $options = array())
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
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;
}
}
记录一个微信支付类
最新推荐文章于 2023-06-09 16:12:03 发布