<?php
namespace fast;
class Alipay
{
//应用公钥证书
private $appCertSN=ROOT_PATH."cert".DS.'appCertPublicKey_2021004...crt';
//应用公钥sn
private $app_cert_sn='3298923171e2';
//支付宝公钥证书地址
private $alipayCertSN=ROOT_PATH."cert".DS.'alipayCertPublicKey_RSA2.crt';
//支付宝根证书地址
private $alipayRootCertSN=ROOT_PATH."cert".DS.'alipayRootCert.crt';
//支付宝根证书sn
private $alipay_root_cert_sn='687b59193f3f462dd53';
//应用ID
private $appId='';
//应用私钥值
private $rsaPrivateKey='';
//支付宝公钥
private $alipayPublicKey='';
//aes秘钥
private $aeskey='';
//网关
private $gatewayUrl = "https://openapi.alipay.com/gateway.do";
//模式 true=证书模式,false=公钥模式
private $mode=true;
public function __construct()
{
if($this->mode){
if(!$this->alipayCertSN){
$this->alipayCertSN=realpath('.'.config('site.alipayCertSN'));
}
if(!$this->appCertSN){
$this->appCertSN=realpath('.'.config('site.appCertSN'));
}
if(!$this->alipayPublicKey){
$this->alipayPublicKey=$this->getPublicKey($this->alipayCertSN);
}
if(!$this->app_cert_sn){
$this->app_cert_sn=$this->getCertSN($this->appCertSN);
}
if(!$this->alipay_root_cert_sn){
$this->alipay_root_cert_sn=$this->getRootCertSN($this->alipayRootCertSN);
}
}else{
if(!$this->alipayPublicKey){
$this->alipayPublicKey=config('site.alipay_public_key');
}
}
if(!$this->appId){
$this->appId=config('site.appid_zfb');
}
if(!$this->rsaPrivateKey){
$this->rsaPrivateKey=config('site.merchant_private_key');
}
if(!$this->aeskey){
$this->aeskey=config('site.aeskey');
}
}
/**
* 支付宝授权访问令牌
* https://opendocs.alipay.com/open/02xtla
* @param $code String 授权码
* @return array data=用户支付宝UID
*/
public function aliToken($code){
$params=$this->getPublicParams('alipay.system.oauth.token');
$params['grant_type']='authorization_code';
$params['code']=$code;
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$result=str_replace(".", "_", $params['method']) . "_response";
if(!empty($data[$result])){
return ['code'=>1,'data'=>$data[$result]['user_id']??$data[$result]['open_id'],'token'=>$data[$result]['access_token']];
}else{
$res=$data['error_response'];
return ['code'=>0,'msg'=>$res['msg'].$res['sub_msg']];
}
}
//解密手机号 https://opendocs.alipay.com/mini/api/getphonenumber
public function decodePhone($content){
$aesKey=$this->aeskey;
if(!$aesKey)return ['code'=>0,'msg'=>'未配置aes秘钥'];
$result=openssl_decrypt(base64_decode($content), 'AES-128-CBC', base64_decode($aesKey),OPENSSL_RAW_DATA);
if(!$result) return ['code'=>0,'msg'=>'参数有误'];
$ret=json_decode($result, true);
if($ret['code']!='10000')return ['code'=>0,'msg'=>$ret['msg'].($ret['subMsg']??'')];
return ['code'=>1,'data'=>$ret['mobile']];
}
/**
* 生成支付宝小程序推广二维码
* https://opendocs.alipay.com/mini/03l9b8
* @param $path string 地址
* @param $param string 参数,门店id,管理员id
* @param $desc string 描叙
* @return array
*/
public function qrcode($param,$path='pages/index/index',$desc='打开支付宝[扫一扫]'){
trace('小程序二维码');
// return ['code'=>1,
// 'qr_code_url'=>'',
// 'qr_code_url_circle_white'=>'',
// 'qr_code_url_circle_blue'=>'',
// ];
$order = [
'url_param' => $path,
'query_param' => (string)$param,
'describe' => $desc,
];
$params =$this->getPublicParams('alipay.open.app.qrcode.create');
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$res=$data[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($res['code']) && $res['code']==10000){
return ['code'=>1,
'qr_code_url'=>$res['qr_code_url'],
'qr_code_url_circle_white'=>$res['qr_code_url_circle_white'],
'qr_code_url_circle_blue'=>$res['qr_code_url_circle_blue'],
];
}else{
return ['code'=>0,'msg'=>$res['msg'].'_'.$res['sub_code'].'_'.($res['sub_msg']??'')];
}
}
/**
* 统一收单交易创建接口
* https://opendocs.alipay.com/open/02ekfj
* @param $order_sn string 订单号
* @param $money float 支付金额,单位:元
* @param $subject string 备注
* @param $buyer_id string 支付宝用户ID
* @param $type int 异步通知地址0=pay_notify(order_pay表),1=item_notify(order_item表),2=reserve_notify(reserve表)
* @return array
*/
public function create($order_sn,$money,$subject,$buyer_id,$type=0){
trace('统一收单交易创建接口');
$order = [
'out_trade_no' => $order_sn,
'total_amount' => floatval($money),
'subject' => $subject,
'buyer_id'=>$buyer_id,
];
if(substr($buyer_id,0,4)!='2088'){
unset($order['buyer_id']);
$order['buyer_open_id']=$buyer_id;
}
$params =$this->getPublicParams('alipay.trade.create');
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$notify= 'pay_notify';
switch ($type){
case 1:$notify= 'item_notify';break;
case 2:$notify= 'reserve_notify';break;
}
$params['notify_url']=request()->domain().'/api/index/'.$notify;//异步通知地址
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$res=$data['alipay_trade_create_response'];
if(!empty($res['code']) && $res['code']==10000){
return ['code'=>1,'data'=>$res['trade_no']];
}else{
return ['code'=>0,'msg'=>$res['msg'].$res['sub_msg']];
}
}
//app支付
public function appPay($order_sn,$money,$subject){
$params=$this->getPublicParams('alipay.trade.app.pay');
$order = [
'out_trade_no' => $order_sn,
'total_amount' => floatval($money), //支付金额,单位:元
'subject' => $subject,
];
$params['notify_url']=request()->domain().'/api/index/notify';
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
ksort($params);
return http_build_query($params);
}
/**
* 统一收单交易支付
* @param $auth_no string 支付宝资金授权订单号
* @param $total_amount float 订单总金额
* @param $out_trade_no string 商户订单号
* @param $subject string 订单标题
* @param $type int 0=预授权主动扣,1=预授权自动扣,2=周期扣自动扣
* @return array
*/
public function pay($auth_no,$total_amount,$out_trade_no,$subject='租金',$type=1){
trace('交易支付');
$order = [
'auth_no' => $auth_no, //支付宝资金授权订单号
'total_amount' => $total_amount,//订单总金额。
'out_trade_no' => $out_trade_no,//商户订单号。
'subject' => $subject, //订单标题。
'product_code' => 'PREAUTH_PAY',
// 'enable_pay_channels' => 'balance',//支付方式限制只能余额
];
$params =$this->getPublicParams('alipay.trade.pay');
$params['notify_url']=request()->domain().'/api/index/pay_notify';//item表回调地址
if($type==0){
$params['notify_url']=request()->domain().'/api/index/payNotify';//pay表回调地址
}
if($type==2){
$order['product_code']='GENERAL_WITHHOLDING';
unset($order['auth_no']);
$order['agreement_params']=[
'agreement_no'=>$auth_no
];
}
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$res=$data['alipay_trade_pay_response'];
if(!empty($res['code']) && $res['code']==10000){
return ['code'=>1,'msg'=>'ok','data'=>$res];
}else{
return ['code'=>0,'msg'=>$res['msg'].$res['sub_msg'],'data'=>$res];
}
}
//统一收单交易关闭接口
public function close($order_sn){
trace('交易关闭');
$params =$this->getPublicParams('alipay.trade.close');
$params['biz_content']=json_encode(['out_trade_no' => $order_sn,],JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code']) && $result['code']==10000){
return ['code'=>1,'data'=>$result['trade_no']];
}else{
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
}
//支付宝当面付 https://opendocs.alipay.com/open/f540afd8_alipay.trade.precreate
public function precreate($order_sn,$money,$subject){
trace('支付宝当面付');
$order = [
'out_trade_no' => $order_sn,
'total_amount' => floatval($money), //支付金额,单位:元
'subject' => $subject,
];
$params =$this->getPublicParams('alipay.trade.precreate');
$params['notify_url']=request()->domain().'/api/index/zfbNotify';
$params['biz_content'] = json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$res=$data['alipay_trade_precreate_response'];
if(!empty($res['code'])&&$res['code'] == 10000){
return ['code'=>1,'data'=>$res['qr_code']];
}else{
return ['code'=>0,'msg'=>$res['msg'].$res['sub_msg']];
}
}
/**
* 支付宝退款
* @param $order_sn string 商户订单号
* @param $amount float 退款金额单位为元,支持两位小数。
* @param $out_request_no string 退款请求号
* @return array data=Y为退款成功=N或无此字段值返回时需通过退款查询接口进一步确认退款状态
*/
public function refund($order_sn, $amount, $out_request_no){
trace('退款');
$params =$this->getPublicParams('alipay.trade.refund');
$api_params = [
'out_trade_no' => $order_sn,
'refund_amount' => $amount,
'out_request_no' => $out_request_no,
];
$params['biz_content'] = json_encode($api_params,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$result=$data['alipay_trade_refund_response'];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result['fund_change']];
} else {
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
}
/**
* 退款查询
* @param $order_sn string 商户订单号
* @param $out_request_no string 退款请求号
* @return array data=REFUND_SUCCESS时表示退款成功,否则表示退款没有执行成功。
*/
public function query($order_sn,$out_request_no){
$order = [
'out_trade_no' => $order_sn,
'out_request_no' => $out_request_no,
'query_options'=>'gmt_refund_pay',
];
$params =$this->getPublicParams('alipay.trade.fastpay.refund.query');
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$res=$data['alipay_trade_fastpay_refund_query_response'];
if(!empty($res['code']) && $res['code']==10000){
return ['code'=>1,'data'=>$res['refund_status']??null,'gmt_refund_pay'=>$res['gmt_refund_pay']??null];
}else{
return ['code'=>0,'msg'=>$res['msg'].$res['sub_msg']];
}
}
/**
* 支付宝单笔转账
* https://opendocs.alipay.com/open/02byuo?scene=ca56bca529e64125a2786703c6192d41
* @param $out_biz_no string 转账订单号
* @param $amount float 金额
* @param $type int =0支付宝的会员ID =1支付宝登录号
* @param $identity int 支付宝用户 UID或账号
* @param $name string 支付宝用户姓名
* 调用示例
$Alipay=new \fast\Alipay();
$ret= $Alipay->transfer(time(),100,0,'2088722004869251');
* @return array
*/
public function transfer($out_biz_no,$amount,$type,$identity,$name=''){
trace('单笔转账');
$params=$this->getPublicParams('alipay.fund.trans.uni.transfer');
//请求参数
$api_params = [
'out_biz_no' => $out_biz_no,
'trans_amount' => $amount,
'biz_scene'=>'DIRECT_TRANSFER',
'product_code'=>'TRANS_ACCOUNT_NO_PWD',
'order_title'=>'提现到账',
];
if($type==0){
$api_params['payee_info']=[
'identity_type'=>'ALIPAY_USER_ID',
// 'identity_type'=>'ALIPAY_OPEN_ID',
'identity'=>$identity
];
}else{
$api_params['payee_info']=[
'identity_type'=>'ALIPAY_LOGON_ID',
'identity'=>$identity,
'name'=>$name
];
}
$params['biz_content'] = json_encode($api_params,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result['order_id'],'paydate'=>$result['trans_date']];
} else {
return ['code'=>0,'msg'=>$result['msg'].':'.$result['sub_msg']];
}
}
//---------芝麻免押,https://opendocs.alipay.com/open/03w0ab -------------------
//线上资金授权冻结接口
public function freeze($info){
$params=$this->getPublicParams('alipay.fund.auth.order.app.freeze');
$order = [
'out_order_no' => $info['order_sn'],
'out_request_no' => $info['order_sn'],
'amount' => floatval($info['auth_money']),//需要冻结的金额
'order_title' => '预授权冻结',
'product_code'=>'PRE_AUTH_ONLINE',
'timeout_express'=>'3d',
'deposit_product_mode'=>'DEPOSIT_ONLY',
'extra_param'=>[
'category'=>$info['category'],//信用类目
'serviceId'=>$info['serviceId'],//信用服务id
//以下是申请租押分离参数
// "outStoreCode"=> "test_0001",
// "outStoreAlias"=> config('site.name')."免押服务",
// "creditExtInfo"=> [
// "assessmentAmount"=> $info['price'],
// "carrierDesc"=> $info['title'],//商品标题
// "rentPeriod"=> $info['day'],//订单租期以天为单位
// "rentAmount"=> $info['pay_price'],//订单金额
// "rentGoodsId"=> '',//商品ID
// "deliveryAddress"=>$info['address'],//收货地址
// "deliveryMobile"=>$info['phone'],
// "deliveryName"=>$info['name']
// ]
]
];
$params['notify_url']=request()->domain().'/api/index/freezeNotify';
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
ksort($params);
return http_build_query($params);
}
//资金授权解冻
public function unfreeze($auth_no,$out_request_no,$amount,$remark='解冻资金'){
trace('资金授权解冻');
$order = [
'auth_no' => $auth_no, //支付宝资金授权订单号
'out_request_no' => $out_request_no,//解冻请求流水号
'amount' => $amount, //解冻的金额
'remark' => $remark,
];
$params =$this->getPublicParams('alipay.fund.auth.order.unfreeze');
$params['notify_url']=request()->domain().'/api/index/freezeNotify';
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$res=$data[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($res['code']) && $res['code']==10000){
return ['code'=>1,'msg'=>'ok','data'=>$res];
}else{
return ['code'=>0,'msg'=>$res['msg'].$res['sub_msg']];
}
}
//资金授权操作查询
public function freezeQuery($auth_no,$out_order_no,$out_request_no){
trace('资金授权操作查询');
$order = [
'auth_no' => $auth_no, //支付宝资金授权订单号
'out_order_no' => $out_order_no, //商户的授权资金订单号
'out_request_no' => $out_request_no,//请求流水号
'operation_type' => 'FREEZE',
];
$params =$this->getPublicParams('alipay.fund.auth.operation.detail.query');
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$data=$this->http_request($this->gatewayUrl, $params);
$res=$data[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($res['code']) && $res['code']==10000){
return ['code'=>1,'data'=>$res];
}else{
return ['code'=>0,'msg'=>$res['msg'].$res['sub_msg']];
}
}
//----------------------------支付宝人脸认证服务接口---------------------------------------
/**
* 初始化
* https://opendocs.alipay.com/open/02ahjy?pathHash=ed72e8ea
* @param $outer_order_no string 商户请求的唯一标识
* @param $cert_name string 真实姓名
* @param $cert_no string 证件号码
* @param $return_url string 需要回跳的目标地址
* @return array
*/
public function faceInitialize($outer_order_no,$cert_name,$cert_no,$return_url){
$params =$this->getPublicParams('alipay.user.certify.open.initialize');
//请求参数
$api_params = [
'outer_order_no' => $outer_order_no,
'biz_code' => 'FACE',
'identity_param' => [
'identity_type'=>'CERT_INFO',
'cert_type'=>'IDENTITY_CARD',
'cert_name'=>$cert_name,
'cert_no'=>$cert_no,
], //需要验证的身份信息
'merchant_config' => [
'return_url'=>$return_url
]//商户个性化配置
];
$params['biz_content'] = json_encode($api_params,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result['certify_id']];
} else {
return ['code'=>0,'msg'=>$result['sub_code'].':'.$result['sub_msg']];
}
}
//开始 $certify_id本次申请操作的唯一标识,由开放认证初始化接口调用后生成
public function faceVerify($certify_id){
$params =$this->getPublicParams('alipay.user.certify.open.certify');
$params['biz_content'] = json_encode(['certify_id' => $certify_id],JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
ksort($params);
return $this->gatewayUrl.'?'.http_build_query($params);
}
//查询 $certify_id本次申请操作的唯一标识,由开放认证初始化接口调用后生成
public function faceQuery($certify_id){
$params =$this->getPublicParams('alipay.user.certify.open.query');
$params['biz_content'] = json_encode(['certify_id' => $certify_id],JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result['passed']];//data是否通过,通过为T,不通过为F
} else{
return ['code'=>0,'msg'=>$result['msg'].':'.$result['sub_msg']];
}
}
//----------------------------周期扣接口---------------------------
/**
* 签约
* https://opendocs.alipay.com/open/08bntw?pathHash=725a0634&scene=common&ref=api
* @param $order_sn string 商户签约号
* @param $money float 单次扣款最大金额
* @param $day string 首次执行时间
* @return string
*/
public function agreement($order_sn,$day,$money=100){
$order = [
'product_code' => 'GENERAL_WITHHOLDING',
'personal_product_code' => 'CYCLE_PAY_AUTH_P',
'sign_scene' => 'INDUSTRY|CARRENTAL',
'external_agreement_no' => $order_sn,
'access_params'=>[
'channel'=>'ALIPAYAPP'
],
'period_rule_params'=>[
// 'period_type'=>'MONTH',//按月
'period_type'=>'DAY',//按天
'period'=>1,
'execute_time'=>$day,
'single_amount'=>$money
]
];
$params =$this->getPublicParams('alipay.user.agreement.page.sign');
$params['notify_url']=request()->domain().'/api/index/sign_notify';
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
ksort($params);
return http_build_query($params);
}
/**
* 解约
* @param $agreement_no string 支付宝签约号
* @return array
*/
public function unsign($agreement_no){
trace('周期扣解约');
$params =$this->getPublicParams('alipay.user.agreement.unsign');
$params['notify_url']=request()->domain().'/api/index/sign_notify';
$params['biz_content']=json_encode(['agreement_no' => $agreement_no],JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code']) && $result['code']==10000){
return ['code'=>1,'msg'=>'ok'];
}else{
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
}
/**
* 计划修改
* @param $agreement_no string 支付宝签约号
* @param $day string 商户下一次扣款时间
* @return array
*/
public function modify($agreement_no,$day){
trace('周期扣计划修改');
$order = [
'agreement_no' => $agreement_no,
'deduct_time'=>$day
];
$params =$this->getPublicParams('alipay.user.agreement.executionplan.modify');
$params['biz_content']=json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code']) && $result['code']==10000){
return ['code'=>1,'msg'=>'ok','data'=>$result['deduct_time']];
}else{
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
}
//实名证件信息比对验证预咨询 https://opendocs.alipay.com/open/02qq4q?pathHash=1e8d6efd
public function preconsult($name,$idcard){
trace('实名证件信息比对验证预咨询:');
$params =$this->getPublicParams('alipay.user.certdoc.certverify.preconsult');
$api_params = [
'user_name' => $name,
'cert_type' => 'IDENTITY_CARD',
'cert_no' => $idcard,
];
$params['biz_content'] = json_encode($api_params,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result['verify_id']];
}else{
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
}
//实名证件信息比对验证咨询 https://opendocs.alipay.com/open/02qq4q?pathHash=1e8d6efd
public function consult($verify_id,$auth_token){
trace('实名证件信息比对验证咨询:');
$params =$this->getPublicParams('alipay.user.certdoc.certverify.consult');
$params['auth_token']=$auth_token;
$params['biz_content'] = json_encode(['verify_id' => $verify_id,],JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'passed'=>$result['passed'],'msg'=>$result['passed']=='F'?$result['fail_reason']:''];
}else{
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
}
//----------------------------------分账----------------------------
//分账关系绑定 https://opendocs.alipay.com/open/02c7hq
public function bind(){
$order = [
'out_request_no' => time(),
'receiver_list' => [[
"type"=>"loginName",//用户号: userId支付宝登录号: loginName支付宝openId: openId
"account"=>"",//账号。
"name"=>"",//真实姓名。
"memo"=>"技术服务费",
]],
];
$params =$this->getPublicParams('alipay.trade.royalty.relation.bind');
$params['biz_content'] = json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
dump($ret);
}
//分账结算
public function settle($out_request_no,$trade_no,$money){
$order = [
'out_request_no' => $out_request_no,//请求流水号
'trade_no' => $trade_no,//支付宝订单号
'royalty_parameters'=>[[
'trans_in_type'=>'loginName',//收入方账户
'trans_in'=>'',//收入方账户
'amount'=>$money,//分账的金额,单位为元
'royalty_scene'=>'技术服务费',
]],//分账明细信息
'extend_params' => [
"royalty_finish"=>"true",// 代表该交易分账是否完结,可选值:true/false,不传默认为false。 true:代表分账完结,则本次分账处理完成后会把该笔交易的剩余冻结金额全额解冻。 false:代表分账未完结。
],
];
$params =$this->getPublicParams('alipay.trade.order.settle');
$params['biz_content'] = json_encode($order,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result['settle_no']];
}else{
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
}
//分账查询
function settle_query($settle_no){
$params =$this->getPublicParams('alipay.trade.order.settle.query');
$params['biz_content'] = json_encode([
'settle_no' => $settle_no,//分账请求单号
],JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($this->gatewayUrl, $params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result['royalty_detail_list']];
}else{
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
}
//商品文件上传接口 https://opendocs.alipay.com/mini/03l4lq
public function fileUpload($file){
trace('商品文件上传接口');
$params =$this->getPublicParams('alipay.merchant.item.file.upload');
$params['scene']='SYNC_ORDER';
$params['sign']=$this->getSign($params);
//文件内容不参与签名,本地文件
$params['file_content']=realpath('.'.$file);
//开启oss了需要先下载下来,上传完了再删除
// $url=cdnurl($file,true);
// $name=basename($url);
// file_put_contents('./'.$name,file_get_contents($url));
// $params['file_content']=realpath('./'.$name);
$ret= $this->http_request($params);
// unlink('./'.$name);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result['material_id']];
}
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
//订单数据同步 https://opendocs.alipay.com/mini/043zb5 https://opendocs.alipay.com/mini/024hj6
public function sync($order,$status){
trace('订单数据同步:');
$params =$this->getPublicParams('alipay.merchant.order.sync');
$api_params = [
'out_biz_no' => $order['order_sn'],
'buyer_id' => $order['user']['ali_user_id'],
'order_type' => 'SERVICE_ORDER',
'order_create_time' => date('Y-m-d H:i:s',$order['createtime']),
'order_modified_time' => date('Y-m-d H:i:s'),
'amount'=>$order['price'],
'ext_info'=>[
//待支付 WAIT_PAY(签完合同) 已发货 IN_DELIVERY 已逾期 OVERDUE 履约完成 EXERCISED
['ext_key'=>'merchant_order_status','ext_value'=>$status],
['ext_key'=>'merchant_biz_type','ext_value'=>'3C_RENT'],
['ext_key'=>'merchant_order_link_page','ext_value'=>'pages/order/orderdetail/orderdetail?id='.$order['id']],
['ext_key'=>'tiny_app_id','ext_value'=>config('site.appid_zfb')],
['ext_key'=>'business_info','ext_value'=>json_encode([
"first_rent"=> $order['orderitem'][0]['price'],
"total_rent"=> $order['price'],
"lease"=> count($order['orderitem'])."期",
"cash_pledge"=> 0,
"thaw_deposit"=> 0,
"delivery_time"=> $status!='WAIT_PAY' ? $order['delivery_time'] : '',//发货时间。
"lease_period"=> $order['orderitem'][0]['day'].'--'.$order['orderitem'][count($order['orderitem'])-1]['day'],
"courier_number"=> $status!='WAIT_PAY' ? $order['express_sn'] : '',//快递递送时的单号。
"overdue_amount"=> $status=='OVERDUE' ? $order['overdue_amount'] : '',//逾期的金额。
"receiving_time"=> ($status=='EXERCISED' || $status=='OVERDUE') ? $order['receiving_time'] : '',//收货时间。
"rent_due_date"=> ($status=='EXERCISED' || $status=='OVERDUE') ? $order['orderitem'][count($order['orderitem'])-1]['day'] : '',//租赁到期的日期。
"give_back_date"=> ($status=='EXERCISED' || $status=='OVERDUE') ? $order['orderitem'][count($order['orderitem'])-1]['day'] : '',//应该还机的日期。
],JSON_UNESCAPED_UNICODE)],
],
'item_order_list'=>[[
"unit_price"=>$order['price'],
"quantity"=>1,
"item_name"=> $order['goods_name'].$order['sku_attr'],
"ext_info"=> [[
"ext_key"=> "image_material_id",
"ext_value"=> $order['material_id']
]]
]],
];
$params['biz_content'] = json_encode($api_params,JSON_UNESCAPED_UNICODE);
$params['sign']=$this->getSign($params);
$ret= $this->http_request($params);
$result=$ret[str_replace(".", "_", $params['method']) . "_response"];
if(!empty($result['code'])&&$result['code'] == 10000){
return ['code'=>1,'data'=>$result];
}
return ['code'=>0,'msg'=>$result['msg'].$result['sub_msg']];
}
//公共参数
private function getPublicParams($method){
$param=[
'app_id' => $this->appId,
'method' => $method,
'format' => 'JSON',
'charset' => 'UTF-8',
'sign_type' => 'RSA2',
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
];
if($this->mode){
$param['alipay_root_cert_sn']=$this->alipay_root_cert_sn;
$param['app_cert_sn']=$this->app_cert_sn;
}
return $param;
}
//支付宝签名
private function getSign($params){
ksort($params);
$stringToBeSigned = "";
$i = 0;
foreach ($params as $k => $v) {
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($this->rsaPrivateKey, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
openssl_sign($stringToBeSigned, $sign, $res, OPENSSL_ALGO_SHA256);
return base64_encode($sign);
}
//支付宝验签
public function verify($params) {
trace($params);
if(!isset($params['sign']))return false;
$sign = $params['sign'];
$params['sign_type'] = null;
$params['sign'] = null;
ksort($params);
$stringToBeSigned = "";
$i = 0;
foreach ($params as $k => $v) {
if($v!=null){
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
$res = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($this->alipayPublicKey, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
//调用openssl内置方法验签,返回bool值
return (bool)openssl_verify($stringToBeSigned, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
}
//发起curl请求
private function http_request($data = [],$url = null) {
if(!$url)$url=$this->gatewayUrl;
$post=[];
if(isset($data['biz_content'])){
$post=http_build_query(['biz_content'=>$data['biz_content']]);
unset($data['biz_content']);
}
$postMultipart = false;
if(isset($data['file_content'])){
$postMultipart = true;
$post['file_content'] = new \CURLFile($data['file_content']);
unset($data['file_content']);
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url.'?'.http_build_query($data));
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if($post){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
}
if (!$postMultipart) {
curl_setopt($curl, CURLOPT_HTTPHEADER, ['content-type: application/x-www-form-urlencoded;charset=utf-8']);
}
// curl_setopt($curl, CURLOPT_TIMEOUT, $time);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
$encode = mb_detect_encoding($output, array("ASCII",'UTF-8',"GB2312","GBK",'BIG5'));
$output=mb_convert_encoding($output, 'UTF-8', $encode);//转为utf-8编码
// trace($data);
trace($output);
return json_decode($output,true);
}
/**
* 从证书中提取序列号
* @param $certPath
* @return string
*/
function getCertSN($certPath)
{
$cert = file_get_contents($certPath);
$ssl = openssl_x509_parse($cert);
return md5($this->array2string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']);
}
/**
* 从证书中提取公钥
* @param $certPath
* @return mixed
*/
function getPublicKey($certPath)
{
$cert = file_get_contents($certPath);
$pkey = openssl_pkey_get_public($cert);
$keyData = openssl_pkey_get_details($pkey);
$public_key = str_replace('-----BEGIN PUBLIC KEY-----', '', $keyData['key']);
return trim(str_replace('-----END PUBLIC KEY-----', '', $public_key));
}
/**
* 提取根证书序列号
* @param $certPath string 根证书
* @return string|null
*/
function getRootCertSN($certPath)
{
$cert = file_get_contents($certPath);
$array = explode("-----END CERTIFICATE-----", $cert);
$SN = null;
for ($i = 0; $i < count($array) - 1; $i++) {
$ssl[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----");
if(strpos($ssl[$i]['serialNumber'],'0x') === 0){
$ssl[$i]['serialNumber'] = $this->hex2dec($ssl[$i]['serialNumberHex']);
}
if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") {
if ($SN == null) {
$SN = md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
} else {
$SN = $SN . "_" . md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']);
}
}
}
return $SN;
}
/**
* 0x转高精度数字
* @param $hex
* @return int|string
*/
private function hex2dec($hex)
{
$dec = 0;
$len = strlen($hex);
for ($i = 1; $i <= $len; $i++) {
$dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
}
return $dec;
}
private function array2string($array)
{
$string = [];
if ($array && is_array($array)) {
foreach ($array as $key => $value) {
$string[] = $key . '=' . $value;
}
}
return implode(',', $string);
}
}
PHP TP5 支付宝部分接口整合
于 2023-07-15 14:03:44 首次发布