Files
youlegames/codes/agent/game/dlweb/api/lib/1.0/pay.php
2026-03-15 01:27:05 +08:00

495 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Created by PhpStorm.
* User: abcdefg
* Date: 2017/10/10
* Time: 11:00
*/
require_once dirname(dirname(__DIR__)) . '/common/ErrorType.php';
require_once dirname(dirname(__DIR__)) . '/common/common.inc.php';
require_once dirname(dirname(__DIR__)) . '/common/BaseMethodHelper.php';
///require_once dirname(dirname(__DIR__)) . '/third/wxpay/lib/wxpay.data.php';
/**
* 数据对象基础类,该类中定义数据类最基本的行为,包括:
* 计算/设置/获取签名、输出xml格式的参数、从xml读取数据对象等
*/
class WechatBaseData
{
protected $Values = array();
protected $SignKey = '';
/**
* 设置签名,详见签名生成算法
* @param mixed $Parameters
* @return string
**/
public function SetSign($Parameters = null)
{
if (is_null($Parameters))
$Parameters = $this->Values;
$Sign = $this->MakeSign($Parameters);
$this->Values['sign'] = $Sign;
return $Sign;
}
/**
* 获取签名,详见签名生成算法的值
* @return mixed
**/
public function GetSign()
{
return $this->Values['sign'];
}
/**
* 判断签名,详见签名生成算法是否存在
* @return bool
**/
public function IsSignSet()
{
return array_key_exists('sign', $this->Values);
}
/**
* 输出xml字符
* @param mixed $Parameters
* @return string
**/
public function ToXml($Parameters = null)
{
if (is_null($Parameters))
$Parameters = $this->Values;
if (is_object($Parameters))
$Parameters = (array)$Parameters;
elseif (!is_array($Parameters))
return '<xml></xml>';
$Result = '';
foreach ($Parameters as $Key => $Value)
{
if (is_numeric($Value))
$Result .= "<{$Key}>{$Value}</{$Key}>";
elseif (is_object($Value) || is_array($Value))
$Result .= "<{$Key}>" . $this->ToXml($Value) . "</{$Key}>";
else
$Result .= "<{$Key}><![CDATA[{$Value}]]></{$Key}>";
}
return "<xml>{$Result}</xml>";
}
/**
* 将xml转为array
* @param string $Parameters
* @return mixed
*/
public function FromXml($Parameters)
{
if (!$Parameters)
return null;
/// 将XML转为array
/// 禁止引用外部xml实体
libxml_disable_entity_loader(true);
$this->Values = json_decode(json_encode(simplexml_load_string($Parameters, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $this->Values;
}
/**
* 格式化参数格式化成url参数
* @param mixed $Parameters
* @return string;
*/
public function ToUrlParams($Parameters = null)
{
if (is_null($Parameters))
$Parameters = $this->Values;
if (empty($Parameters))
return '';
if (is_object($Parameters))
$Parameters = (array)$Parameters;
elseif (!is_array($Parameters))
return $Parameters;
$Result = '';
foreach ($Parameters as $Key => $Value)
{
if (is_object($Value) || is_array($Value))
$Result .= $Key . '=' . $this->ToUrlParams($Value) . '&';
elseif (strcasecmp($Key, 'sign') != 0 && strcasecmp($Value, '') != 0)
$Result .= "{$Key}={$Value}&";
}
return trim($Result, '&');
}
/**
* 生成签名
* @param mixed $Parameters
* @return string 签名本函数不覆盖sign成员变量如要设置签名需要调用SetSign方法赋值
*/
public function MakeSign($Parameters = null)
{
if (is_null($Parameters))
$Parameters = $this->Values;
if (is_object($Parameters))
$Parameters = (array)$Parameters;
elseif (!is_array($Parameters))
return strtoupper(md5("{$Parameters}&key={$this->SignKey}"));
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = $this->ToUrlParams($Parameters);
//签名步骤二在string后加入KEY
$String = "{$String}&key={$this->SignKey}";
//签名步骤三MD5加密
$String = md5($String);
//签名步骤四:所有字符转为大写
$Result = strtoupper($String);
return $Result;
}
/**
* 获取设置的值
*/
public function GetValues()
{
return $this->Values;
}
public function GetSignKey()
{
return $this->SignKey;
}
public function SetSignKey($SignKey)
{
$this->SignKey = $SignKey;
}
}
/// 红包数据对象
class RedPackData extends WechatBaseData
{
public $RequestUrl = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack'; /// 请求URL
/*
nonce_str随机字符串不长于32位
sign签名详见签名生成算法
mch_billno商户订单号每个订单号必须唯一。取值范围0~9a~zA~Z接口根据商户订单号支持重入如出现超时可再调用。
mch_id微信支付分配的商户号
wxappid微信分配的公众账号ID企业号corpid即为此appId。接口传入的所有appid应该为公众号的appid在mp.weixin.qq.com申请的不能为APP的appid在open.weixin.qq.com申请的
send_name红包发送者名称
re_openid接受红包的用户用户在wxappid下的openid
total_amount付款金额单位分
total_num红包发放总人数
wishing红包祝福语
client_ip调用接口的机器Ip地址
act_name活动名称
remark备注信息
scene_id场景id发放红包使用场景红包金额大于200时必传PRODUCT_1:商品促销、PRODUCT_2:抽奖、PRODUCT_3:虚拟物品兑奖、PRODUCT_4:企业内部福利、PRODUCT_5:渠道分润、PRODUCT_6:保险回馈、PRODUCT_7:彩票派奖、PRODUCT_8:税务刮奖)
risk_info活动信息posttime:用户操作的时间戳mobile:业务系统账号的手机号,国家代码-手机号。不需要+号deviceid :mac 地址或者设备唯一标识clientversion :用户操作的客户端版本把值为非空的信息用key=value进行拼接再进行urlencodeurlencode(posttime=xx& mobile =xx&deviceid=xx)
consume_mch_id资金授权商户号服务商替特约商户发放时使用
*/
protected function SetValue($Key, $Value)
{
$this->Values[$Key] = $Value;
}
/// 微信分配的公众账号ID企业号corpid即为此appId。接口传入的所有appid应该为公众号的appid在mp.weixin.qq.com申请的不能为APP的appid在open.weixin.qq.com申请的
public function SetAppId($app_id)
{
$this->SetValue('wxappid', $app_id);
}
/// 微信支付分配的商户号
public function SetMchId($mch_id)
{
$this->SetValue('mch_id', $mch_id);
}
/// 商户订单号每个订单号必须唯一。取值范围0~9a~zA~Z接口根据商户订单号支持重入如出现超时可再调用。
public function SetMchBillNo($mch_billno)
{
$this->SetValue('mch_billno', $mch_billno);
}
/// 红包发送者名称
public function SetSendName($send_name)
{
$this->SetValue('send_name', $send_name);
}
/// 接受红包的用户用户在wxappid下的openid
public function SetOpenId($open_id)
{
$this->SetValue('re_openid', $open_id);
}
/// 付款金额,单位分
public function SetAmount($amount)
{
$this->SetValue('total_amount', $amount);
}
/// 红包发放总人数
public function SetNumber($number)
{
$this->SetValue('total_num', $number);
}
/// 红包祝福语
public function SetWishing($wishing)
{
$this->SetValue('wishing', $wishing);
}
/// 调用接口的机器Ip地址
public function SetClientIp($client_ip)
{
$this->SetValue('client_ip', $client_ip);
}
/// 活动名称
public function SetActiveName($act_name)
{
$this->SetValue('act_name', $act_name);
}
/// 备注信息
public function SetRemark($remark)
{
$this->SetValue('remark', $remark);
}
/// 场景id发放红包使用场景红包金额大于200时必传PRODUCT_1:商品促销、PRODUCT_2:抽奖、PRODUCT_3:虚拟物品兑奖、PRODUCT_4:企业内部福利、PRODUCT_5:渠道分润、PRODUCT_6:保险回馈、PRODUCT_7:彩票派奖、PRODUCT_8:税务刮奖)
public function SetSceneId($scene_id)
{
$this->SetValue('scene_id', $scene_id);
}
/// 活动信息posttime:用户操作的时间戳mobile:业务系统账号的手机号,国家代码-手机号。不需要+号deviceid :mac 地址或者设备唯一标识clientversion :用户操作的客户端版本把值为非空的信息用key=value进行拼接再进行urlencodeurlencode(posttime=xx& mobile =xx&deviceid=xx)
public function SetRiskInfo($risk_info)
{
if (is_object($risk_info))
$risk_info = (array)$risk_info;
elseif(!is_array($risk_info))
$this->SetValue('risk_info', $risk_info);
$risk_info = urlencode("posttime={$risk_info['posttime']}&mobile={$risk_info['mobile']}&deviceid={$risk_info['deviceid']}&clientversion={$risk_info['clientversion']}");
$this->SetValue('risk_info', $risk_info);
}
/// 资金授权商户号,服务商替特约商户发放时使用
public function SetConsumeMchId($consume_mch_id)
{
$this->SetValue('consume_mch_id', $consume_mch_id);
}
/// 随机字符串不长于32位
public function SetNonceString($nonce_str)
{
$this->SetValue('nonce_str', $nonce_str);
}
}
class wechat extends BaseMethod
{
/**
* @var RedPackData
*/
private $RedPackData;
/**
* @var int
*/
private $RequestErrorCode;
/**
* 公钥
*/
private $PublicKey = '/cert/0000000000/apiclient_cert.pem';
/**
* 私钥
*/
private $PrivateKey = '/cert/0000000000/apiclient_key.pem';
/**
* ca证书
*/
private $RootCA = '/cert/0000000000/rootca.pem';
/**
* wechat constructor.
*/
public function __construct()
{
/// todo:
parent::__construct();
$this->PublicKey = __DIR__ . '/cert/1399351902/apiclient_cert.pem';
$this->PrivateKey = __DIR__ . '/cert/1399351902/apiclient_key.pem';
$this->RootCA = __DIR__ . '/cert/1399351902/rootca.pem';
$this->RedPackData = new RedPackData();
/// 初始化红包设置信息
//$this->RedPackData->SetSignKey('0t3xm3w1foyhcmhlux31mwrmybqh4cgd'); /// 支付key
//$this->RedPackData->SetAppId('wxb534983dcd6d77c6'); /// 公众账号appid
//$this->RedPackData->SetMchId('1345625501'); /// 商户号
$this->RedPackData->SetSignKey('YSWDSJ20160620201606202016062020'); /// 支付key
$this->RedPackData->SetAppId('wxfd77eb9fb989e822'); /// 公众账号appid
$this->RedPackData->SetMchId('1399351902'); /// 商户号
$this->RedPackData->SetMchBillNo(''); /// 商户订单号
$this->RedPackData->SetActiveName('test'); /// 活动名称
$this->RedPackData->SetSendName('友乐互动游戏'); /// 商户名称
$this->RedPackData->SetOpenId(''); /// 接受红包的用户用户在wxappid下的openid
$this->RedPackData->SetAmount(100); /// 付款金额,单位分
$this->RedPackData->SetNumber(1); /// 发送红包总人数
$this->RedPackData->SetWishing('test'); /// 红包祝福语
$this->RedPackData->SetRemark('test'); /// 备注信息
$this->RedPackData->SetNonceString($this->create_nonce_str(32)); /// 随机字符串不长于32位
$this->RedPackData->SetClientIp($_SERVER['SERVER_ADDR']); /// 客户端ip
}
/**
* 产生随机字符串不长于32位
* @param int $length
* @return string 产生的随机字符串
*/
public static function create_nonce_str($length = 32)
{
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ($i = 0; $i < $length; $i++)
{
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
/**
* @param string $Url 连接地址
* @param string $Data 发送的数据
* @param int $Second
* @param array $Header
* @return bool|mixed
*/
private function curl_post_ssl($Url, $Data, $Second = 30, $Header = array())
{
$ch = curl_init();
/// 超时时间
curl_setopt($ch, CURLOPT_TIMEOUT, $Second);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
/// 这里设置代理,如果有的话
/// curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
/// 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);
/// 以下两种方式需选择一种
/// 第一种方法cert 与 key 分别属于两个.pem文件
/// 默认格式为PEM可以注释
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
//curl_setopt($ch, CURLOPT_SSLCERT, getcwd() . $this->PublicKey);
curl_setopt($ch, CURLOPT_SSLCERT, $this->PublicKey);
/// 默认格式为PEM可以注释
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
//curl_setopt($ch, CURLOPT_SSLKEY, getcwd() . $this->PrivateKey);
curl_setopt($ch, CURLOPT_SSLKEY, $this->PrivateKey);
/// ca证书
curl_setopt($ch, CURLOPT_CAINFO, $this->RootCA);
/// 第二种方式,两个文件合成一个.pem文件
///curl_setopt($ch, CURLOPT_SSLCERT, getcwd() . '/all.pem');
if (count($Header) >= 1)
curl_setopt($ch, CURLOPT_HTTPHEADER, $Header);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $Data);
$Result = curl_exec($ch);
if ($Result)
{
$this->RequestErrorCode = 0;
curl_close($ch);
return $Result;
}
else
{
$this->RequestErrorCode = curl_errno($ch);
//echo "call faild, errorCode: {$this->RequestErrorCode}\n\n\n\n";
curl_close($ch);
return null;
}
}
/**
* 被请求方法示例参数固定为RequestParameter和ReturnParameter对象返回值固定为true(成功)和false(失败)
* @param RequestParameter $Request
* @param ReturnParameter $Return
* @return bool
*/
public function SendRedPack($Request, &$Return)
{
///https://proxytest.tscce.cn/api/Index.php?method=pay.wechat.SendRedPack&format=json&charset=utf-8&timestamp=1&version=1.0&biz_content={"act_name":"活动名称","open_id":"ogLT2v3XvvB1aphibzHyL8On4_sk","fee":"100","wishing":"红包祝福语","remark":"备注信息"}&user_auth_token=xxxxxxxx
$bill_no = date('YmdHis') . rand(1000, 9999); /// 订单号
$act_name = @$Request->biz_content['act_name']; /// 活动名称
$open_id = @$Request->biz_content['open_id']; /// 接受红包的用户用户在wxappid下的openid /// ogLT2v3XvvB1aphibzHyL8On4_sk
$fee = @$Request->biz_content['fee']; /// 付款金额,单位分
$wishing = @$Request->biz_content['wishing']; /// 红包祝福语
$remark = @$Request->biz_content['remark']; /// 备注信息
$this->RedPackData->SetMchBillNo($bill_no);
$this->RedPackData->SetActiveName($act_name);
$this->RedPackData->SetOpenId($open_id);
$this->RedPackData->SetAmount($fee);
$this->RedPackData->SetWishing($wishing);
$this->RedPackData->SetRemark($remark);
$this->RedPackData->SetSign(); /// 签名
/// 发送数据
$xml = $this->curl_post_ssl($this->RedPackData->RequestUrl, $this->RedPackData->ToXml());
if (empty($xml))
{
$Return->SetErrors(ERRORCODE_WECHATERROR, "curl call faild! error code: {$this->RequestErrorCode}");
return false;
}
$res = (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
if (empty($res))
{
$Return->SetErrors(ERRORCODE_WECHATERROR, $xml);
return false;
}
if (strcasecmp('success', $res['return_code']) != 0)
{
$Return->SetErrors(ERRORCODE_WECHATERROR, $res['return_msg']);
return false;
}
if (strcasecmp('success', $res['result_code']) != 0)
{
$Return->SetErrors(ERRORCODE_WECHATERROR, $res['err_code_des']);
return false;
}
return true;
}
}