tp5 支付宝电脑网页支付接口

发布时间:2023-10-18作者:小灵龙点击:57

支付宝电脑网页支付

1,https://opendocs.alipay.com/open/54/106682
2,下载demo后放入extend扩展类目录。
3,复制demo/alipay/config.php中的配置参数复制后放置在extra/zhifubao.php中,可以方便调用支付宝配置参数$config=config('zhifubao');


zhifubao.php文件中的内容如下
     return [
     //应用ID,您的APPID。
     'app_id' => "",
     //商户私钥
     'merchant_private_key' =>'
           //异步通知地址,$_SERVER["REQUEST_SCHEME"] => string(4) "http";$_SERVER["HTTP_HOST"] => string(16) "ktgpt.itulan.com";
           'notify_url' => $_SERVER['REQUEST_SCHEME']."://".$_SERVER['HTTP_HOST']."/common/alipay/notify_url",
        
        //同步页面跳转
     'return_url' => "https://".$_SERVER['HTTP_HOST']."/common/alipay/return_url",
          //编码格式 支付宝默认UTF-8。 import('alipay.pagepay.service.AlipayTradeService')中查看          
          'charset' => "UTF-8",

         //签名方式 默认RSA2。 import('alipay.pagepay.service.AlipayTradeService')中查看
           'sign_type'=>"RSA2",

         //支付宝网关  默认。 import('alipay.pagepay.service.AlipayTradeService')中查看         
          'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
         // 'gatewayUrl' => "https://openapi.alipaydev.com/gateway.do",//沙箱模式

        //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
      'alipay_public_key' => "",
     ]
在common模块中写一个alipay类写一个类把支付、退款、查询都放在一起。
<?php

  namespace app\common\controller;

  use think\Controller;
  use think\Db;
  use think\Request;
  use think\Loader;
  use think\Log;
  /**
  * 支付宝
  */

  class Alipay extends Controller{   
       //生成唯一订单号
      public  function build_order_no(){
          return date('Ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
     }  

   //支付宝电脑支付退款  退款用支付宝公钥
    //支付宝电脑支付付款 ,显示付款页面
    public function payOrder($request){      
        import('alipay.pagepay.buildermodel.AlipayTradePagePayContentBuilder');
        import('alipay.pagepay.service.AlipayTradeService');
        $config=config('zhifubao');
        //商户订单号,商户网站订单系统中唯一订单号,必填
        $out_trade_no = trim($request['out_trade_no']);          
        //订单名称,必填       
        $subject = trim($request['trade_name']);
        //付款金额,必填      
        $total_amount = trim($request['total_amount']);
        //商品描述,可空    
        // $body = trim($request->WIDbody);
      //构造参数
      $payRequestBuilder = new \AlipayTradePagePayContentBuilder();
      // $payRequestBuilder->setBody($body);
      $payRequestBuilder->setSubject($subject);
      $payRequestBuilder->setTotalAmount($total_amount);
      $payRequestBuilder->setOutTradeNo($out_trade_no);

      $aop = new \AlipayTradeService($config);//加反斜杠
      /**
       * pagePay 电脑网站支付请求
       * @param $builder 业务参数,使用buildmodel中的对象生成。
       * @param $return_url 同步跳转地址,公网可以访问
       * @param $notify_url 异步通知地址,公网可以访问
       * @return $response 支付宝返回的信息
      */
      $response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);
          
          $product_id=$request['cproduct_id'];
          if(empty($request['cproduct_id'])){
               $product_id=$request['tola_product_id'];
          }
        if($response){       
          Log::info('进入支付宝二维码付款页面');
          $data['out_trade_no']=$out_trade_no;
          $data['money']=$total_amount;                   
          $data['product_id']=$product_id;       
          $data['status']=-1;
          // 客户点击购买进入支付页面后把数据存入数据库
          Db::name('statis')->insert($data);
          echo json_encode(['status'=>1,'msg'=>'success','data'=>$response]);
        }else{
            echo json_encode(['status'=>0,'msg'=>'false','orderid'=>$orderid]);

        }   

    }

    //同步页面跳转
    public function return_url(Request $request){
        Log::info('同步页面跳转');
        import('alipay.pagepay.service.AlipayTradeService');
        $config=config('zhifubao');
        $arr=$request->get();//同步是get方式返回数据
        $alipaySevice = new \AlipayTradeService($config);//加反斜杠
        $result = $alipaySevice->check($arr);
        Log::info("同步回调通知返回信息:".json_encode($arr,true));

      /* 实际验证过程建议商户添加以下校验。
      1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
      2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
      3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
      4、验证app_id是否为该商户本身。
      */
      if($result) {
       //验证成功     
       //请在这里加上商户的业务逻辑程序代码
                  Log::info('同步验证成功');
        
        //——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
          //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表

        //商户订单号
        $out_trade_no = htmlspecialchars($arr['out_trade_no']);

        //支付宝交易号
        $trade_no = htmlspecialchars($arr['trade_no']);
         
        $this->redirect('first/paymentResult');

        //——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
      }   else {
          //验证失败
          echo "验证失败";
      }
    }
     //支付宝支付成功之后异步回调处理,保存数据到数据库,交易号,交易金额,公共参数:授权appid,签名
    public function notify_url(Request $request){
       
      import('alipay.pagepay.service.AlipayTradeService');
          
      Log::info('进入notify_url异步回调函数中');
      $config=config('zhifubao');
      $arr=$request->post();     

      $arr['fund_bill_list']=htmlspecialchars_decode($arr['fund_bill_list']);

        $alipaySevice = new \AlipayTradeService($config);
        $result = $alipaySevice->check($arr);

        /* 实际验证过程建议商户添加以下校验。
        1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
        2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
        3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
        4、验证app_id是否为该商户本身。
        */
        if($result) {//验证成功
          /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
          //请在这里加上商户的业务逻辑程序代
          Log::info('notify_url异步回调处理验证成功');              
          //——请根据您的业务逻辑来编写程序(以下代码仅作参考)——              
            //获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表              
          //商户订单号
          $out_trade_no = $arr['out_trade_no'];
          //支付宝交易号
          $trade_no = $arr['trade_no'];
          //交易状态
          $trade_status = $arr['trade_status'];
          //交易金额
          $total_amount = $arr['total_amount'];       

            if($arr['trade_status'] == 'TRADE_SUCCESS') {
            //判断该笔订单是否在商户网站中已经做过处理
              //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
              //请务必判断请求时的total_amount与通知时获取的total_fee为一致的
              //如果有做过处理,不执行商户的业务程序
                
            //注意:
            //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
         
            // 1,充值消费明细statistics表       
                    //判断该笔订单是否在商户网站中已经做过处理
                    //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                    //请务必判断请求时的total_amount与通知时获取的total_fee为一致的
                    //如果有做过处理,不执行商户的业务程序      
                    //注意:
                    //付款完成后,支付宝系统发送该交易状态通知
                  
          }
          //——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
              echo "success"; //请不要修改或删除
        }else {
            //验证失败
            echo "fail";
          Log::info('异步回调处理验证失败');

        }

      }

    //退款
    public function refund($request){
      import('alipay.pagepay.buildermodel.AlipayTradeRefundContentBuilder');
      import('alipay.pagepay.service.AlipayTradeService');         

      $config=config('zhifubao');      
          //商户订单号,商户网站订单系统中唯一订单号        
          $out_trade_no = trim($request['WIDTRout_trade_no']);
        
          //需要退款的金额,该金额不能大于订单金额,必填       
          $refund_amount = trim($request['WIDTRrefund_amount']);

          //退款的原因说明     
          $refund_reason = trim($request['WIDTRrefund_reason']);

          //标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
          // $out_request_no = trim($arr['WIDTRout_request_no']);

            //构造参数
          $RequestBuilder=new \AlipayTradeRefundContentBuilder();//加反斜杠
          $RequestBuilder->setOutTradeNo($out_trade_no);
          $RequestBuilder->setRefundAmount($refund_amount);
          // $RequestBuilder->setOutRequestNo($out_request_no);
          $RequestBuilder->setRefundReason($refund_reason);

          $aop = new \AlipayTradeService($config);//加反斜杠
          
          /**
           * alipay.trade.refund (统一收单交易退款接口)
           * @param $builder 业务参数,使用buildmodel中的对象生成。
           * @return $response 支付宝返回的信息
           */
          $response = $aop->Refund($RequestBuilder);
          //$response返回值 失败object(stdClass)#19 (6) ["code"] => string(5) "40004"  ["msg"] => string(15) "Business Failed"  ["sub_code"] => string(19) "ACQ.TRADE_NOT_EXIST"  ["sub_msg"] =>string(15) "交易不存在"  ["refund_fee"] => string(4) "0.00"  ["send_back_fee"] => string(4) "0.00"
          //$response返回值,退款成功  ["code"] => string(5) "10000"
        //   ["msg"] => string(7) "Success"
        //   ["buyer_logon_id"] => string(14) "lij***@163.com"
        //   ["buyer_user_id"] => string(16) "2088102616669786"
        //   ["fund_change"] => string(1) "N"
        //   ["gmt_refund_pay"] => string(19) "2021-05-11 17:14:11"
        //   ["out_trade_no"] => string(16) "2021051010210050"
        //   ["refund_fee"] => string(4) "0.01"
        //   ["send_back_fee"] => string(4) "0.00"
        //   ["trade_no"] => string(28) "2021051022001469781454012273"
        // }
          $res['code']=$response->code;
          $res['msg']=$response->msg;       
         return json_encode($res);
    }
}
?>

遇到问题:

问题1,each()函数报错

支付宝支付的时候遇到的,因为php7+以上版本抛弃了each函数导致,找到extend\alipay\aop\AopClient.php:

while (list ($key, $val) = each ($para_temp)) {

改为

foreach ($para_temp as $key => $val) {

问题二:收不到异步通知自查方案-支付宝接口常见错误系列

  1.需http://或者https://格式的完整路径 
  例:https://您的域名/notify_url.php  ,支持ip地址方式。(推荐使用域名) 

  2.不能加?id=123这类自定义参数 
  错误示例:https://您的域名/notify_url.php?id=123&test=abc 

  3.必须外网可以正常访问,这个不难理解,在您的异步地址没有代码逻辑的情况下,直接访问应该是一个空白页面并且http状态是200(不支持http200以外的状态),不能在本机电脑测试,要到服务器上做测试,同时也要确保外部可以访问该页面。
  4,首先支付宝Notify_url 调用的这个控制器Controller,不能有访问权限的问题。
我把它继承了Allow控制器,这个控制器必须登录后才能访问,所以肯定是不行的。


总结:

1、notify_url:通过 POST 请求的形式将支付结果作为参数通知到商户系统,使用$_POST获取数据

2、return_url:通过 GET 请求的形式,使用$_GET获取数据

3、notify_url是异步通知,异步无法使用Cookie和Session保存数据。return_url是同步页面跳转;

4,notify_url回调地址,支付宝服务器通知商户服务器是否支付成功。支付宝在支付成功后,会带参(比如业务参数类:交易号,交易金额,公共参数:授权appid,签名)来请求你这个地址,服务器告诉你,这一单,我们支付宝收到款了,然后这里肯定有可能会有第三方的恶意请求(伪造请求)。所以你对这些进行验证,然后识别出是支付宝的回调,然后进行业务处理。比如修改订单支付状态。


标签: