php支付宝多账号支付

支付宝进行app支付

准备工作

支付宝支付的官方服务端demo

项目背景,多个商家在同一个平台支付,根据商家号去查询商家的appid(支付宝分配给开发者的应用ID)
支付宝的应用公钥和私钥以及通过应用公钥生成的支付宝公钥可以多个商家公用一个(方便,给个赞)

商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2

支付宝审核效率较快

服务商版的微信支付开发文档在这里 https://pay.weixin.qq.com/wiki/doc/api/sl.html

这里主要说一下从原来的普通的账号转变为接入服务商要做哪些改变

这是第一个注意的地方
以刷卡支付为例,可以对比看到,多了两个参数sub_appid,sub_mch_id,这两个参数填你原来账号的。
而appid,mch_id填服务商的,服务商会给你的

如果是微信公众账号内h5支付
要求传openid和sub_openid,这里只传sub_openid即可,内容填以前获取的openid,不变

另外,再提醒下,微信app支付比较特殊,它的appid和其它的支付使用的appid是不相同的
微信app支付的appid去open.weixin.qq.com查看
而其它的支付的appid去mp.weixin.qq.com查看

加密(重点)
加密使用商户给的key,自己以前的key已经无效了。

支付目录
开通商户后,商户会叫你提供appid和支付目录,这时自己设置的支付目录已经无效。
注意区分正式目录和测试目录,若使用测试目录,必须要把个人微信号填入白名单切必须要在微信公众账号里打开支付链接。

话不多说,开始

支付宝支付请求

支付宝支付都是json格式

起调

  • 支付宝支付起调
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public function alipay_app(){
//构造业务请求参数的集合(订单信息)
$content = array();
$content['subject'] = $this->subject;//商品的标题/交易标题/订单标题/订单关键字等
$content['out_trade_no'] = $this->out_trade_no;//商户网站唯一订单号
$content['timeout_express'] = $this->timeout_express;//商品的标题/交易标题/订单标题/订单关键字等
$content['total_amount'] = floatval($this->total_amount);//订单总金额(必须定义成浮点型)
$content['product_code'] = $this->product_code;//销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
$con = json_encode($content);//$content是biz_content的值,将之转化成字符串
//构造公共参数
unset($parameter);
$parameter = array(
"app_id" => $this->app_id,//支付宝分配给开发者的应用ID
"method" => $this->method,//接口名称
"charset" => $this->charset,//请求使用的编码格式
"sign_type" => $this->sign_type,//商户生成签名字符串所使用的签名算法类型
"timestamp" => date("Y-m-d H:i:s"),//发送请求的时间
"version" => $this->version,//调用的接口版本,固定为:1.0
"notify_url" => $this->notify_url,//支付宝服务器主动通知地址
"biz_content" => $con,//业务请求参数的集合,长度不限,json格式
);
//生成签名
$Client = new AopClient();
$paramStr = $Client->getSignContent($parameter);//签名字符串
$sign = $Client->alonersaSign($paramStr,$this->rsaPrivateKey,$this->sign_type);
$parameter['sign'] = $sign;
writeLog("| APP支付 | 参数 | ".json_encode($parameter), config('PAY_LOG'),'alipay');
$str = $Client->getSignContentUrlencode($parameter);
return $str;
}

回调

  • 支付宝支付回调
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public function notifyPay(){
//验证生成签名
$Client = new AopClient($this->alipayrsaPublicKey);
$verify_result = $Client->rsaCheckV1($_POST,null);
writeLog("| 支付回调 | 数据验证 | ".json_encode($verify_result),config('PAY_LOG'),'alipay');
if($verify_result) {//验证成功
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//请在这里加上商户的业务逻辑程序代
//——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
//获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
//商户订单号
$out_trade_no = $_POST['out_trade_no'];
//支付宝交易号
$trade_no = $_POST['trade_no'];
//交易状态
$trade_status = $_POST['trade_status'];
if($_POST['trade_status'] == 'TRADE_FINISHED') {
return 'success';
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
//调试用,写文本函数记录程序运行情况是否正常
//logResult("这里写入想要调试的代码变量值,或其他运行的结果记录");
}
else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
return 'success';
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//付款完成后,支付宝系统发送该交易状态通知
//调试用,写文本函数记录程序运行情况是否正常
//logResult("这里写入想要调试的代码变量值,或其他运行的结果记录");
}
else if ($_POST['trade_status'] == 'TRADE_CLOSED') {
return 'success';
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//付款完成后,支付宝系统发送该交易状态通知
//调试用,写文本函数记录程序运行情况是否正常
//logResult("这里写入想要调试的代码变量值,或其他运行的结果记录");
}
//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
return 'fail';
//echo "success"; //请不要修改或删除
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
else {
return 'fail';
//验证失败
// echo "fail";
//调试用,写文本函数记录程序运行情况是否正常
//logResult("这里写入想要调试的代码变量值,或其他运行的结果记录");
}
}

退款

  • 支付宝支付退款
public function refund($param){
    $parameter = $result = [];
    try {
        $aop = new AopClient();
        $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
        $aop->appId = $this->app_id;
        $aop->rsaPrivateKey = $this->rsaPrivateKey;
        $aop->alipayrsaPublicKey = $this->alipayrsaPublicKey;
        $aop->apiVersion = '1.0';
        $aop->signType = 'RSA';
        $aop->postCharset='UTF-8';
        $aop->format='json';
        $parameter = [
            "trade_no" => $param['trade_no'],
            "out_trade_no" => $param['out_trade_no'],
            "out_request_no" => $param['out_request_no'],
            "refund_reason" => '正常退款',
            "refund_amount"=>$param['refund_money'],
        ];
        $request = new request\AlipayTradeRefundRequest ();
        $request->setBizContent(json_encode($parameter));
        $result = $aop->execute ($request);
        $responseNode = 'alipay_trade_refund_response';//str_replace(".", "_", $request->getApiMethodName()) . "_response";
        $data = $result->$responseNode;
        $resultCode = $data->code;
        if(empty($resultCode) || $resultCode != 10000){
            $m = $data->sub_msg?$data->sub_msg:$data->msg;
            throw new \Exception($m, 1);
        }
        $ret['status'] = 'success';
        $ret['msg'] = '退款成功';
        $ret['data'] = $data;
    } catch (\Exception $e) {
        $ret['status'] = 'fail';
        $ret['msg'] = $e->getMessage();
    }
    writeLog("| 支付宝退款 | {$ret['status']}-{$ret['msg']} | 参数:".json_encode($parameter)." | 结果:".json_encode($result), config('PAY_LOG'),'refund');
    return $ret;
}

支付宝支付相对比较简单,有什么问题可以联系我喔!

谢谢您请我喝咖啡!