美文网首页
paypal 支付流程

paypal 支付流程

作者: 云龙789 | 来源:发表于2020-07-11 12:59 被阅读0次

    推荐资料

    主要是参考官方的 SDK PayPal-PHP-SDK wiki 操作的 https://github.com/paypal/PayPal-PHP-SDK/wiki,按照上面的步骤一步步操作

    以下三点也很重要

    1.下载 SDK

    composer require "paypal/rest-api-sdk-php:*" 
    

    2.创建支付订单。比如我们使用first.php 页面

    // 1.引入 sdk 包
    <?php
    // 1. Autoload the SDK Package. This will include all the files and classes to your autoloader
    // Used for composer based installation
    require __DIR__  . '/vendor/autoload.php';
    // Use below for direct download installation
    // require __DIR__  . '/PayPal-PHP-SDK/autoload.php';
    
    // 2. 添加你的 clientId 和 secret
    // After Step 1
    $apiContext = new \PayPal\Rest\ApiContext(
            new \PayPal\Auth\OAuthTokenCredential(
                'ClientID',     // ClientID
                'ClientSecret'      // ClientSecret
            )
    );
    
    // 3.  创建订单
    // 付款人信息
    $payer = new \PayPal\Api\Payer();
    $payer->setPaymentMethod('paypal'); // 付款方式
    
    // 金额信息
    $amount = new \PayPal\Api\Amount();
    $amount->setTotal('1.00');
    $amount->setCurrency('USD');
    
    // 交易信息
    $transaction = new \PayPal\Api\Transaction();
    $transaction->setAmount($amount);
    
    // 回调信息
    $redirectUrls = new \PayPal\Api\RedirectUrls();
    $redirectUrls->setReturnUrl("https://xxx.com/callback.phpl") //支付后, 同步回调 url
        ->setCancelUrl("https://xxx.com/cancel.php");// 取消支付后跳转的的url
    
    // 创建支付实例,并赋值
    $payment = new \PayPal\Api\Payment();
    $payment->setIntent('sale')
        ->setPayer($payer)
        ->setTransactions(array($transaction))
        ->setRedirectUrls($redirectUrls);
    
    // 4. 请求支付
    try {
        $payment->create($apiContext);
                如果支付成功,则肯定有第三方的订单号,我们应该记录此单号。因为paypal 并没有记录我们本地的单号
                // 获取订单id
                $arr = json_decode($payment, true);
                // 订单id 赋值
                $paypal_order_id = isset($arr['id']) ? $arr['id'] : '';
    
        echo $payment; // 支付信息
        echo  $payment->getApprovalLink(); //客户支付,需要跳转的连接
    }
    catch (\PayPal\Exception\PayPalConnectionException $ex) {
        // This will print the detailed information on the exception.
        //REALLY HELPFUL FOR DEBUGGING
        echo $ex->getData();
    }
    

    2.1 请求支付,返回的数据

    > php -f first.php   // 终端执行,也可以直接访问  first.php  路由
    {
        "intent": "sale",
        "payer": {
            "payment_method": "paypal"
        },
        "transactions": [
            {
                "amount": {
                    "total": "1.00",
                    "currency": "USD"
                },
                "related_resources": []
            }
        ],
        "redirect_urls": {
            "return_url": "https://example.com/your_redirect_url.html",
            "cancel_url": "https://example.com/your_cancel_url.html"
        },
        "id": "PAY-3MC96102SY030652JLHXXPMA",
        "state": "created",
        "create_time": "2017-10-24T17:26:07Z",
        "links": [
            {
                "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-3MC96102SY030652JLHXXPMA",
                "rel": "self",
                "method": "GET"
            },
            {
                "href": "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-1NT485541R0509947",
                "rel": "approval_url",
                "method": "REDIRECT"
            },
            {
                "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-3MC96102SY030652JLHXXPMA/execute",
                "rel": "execute",
                "method": "POST"
            }
        ]
    }
    Redirect user to approval_url: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-1NT485541R0509947
    

    3.添加请求日志

    在     $payment->create($apiContext);  之前添加以下代码。必须放在 try catch  之前
    $apiContext->setConfig(
        array(
            'log.LogEnabled' => true,
            'log.FileName' => 'PayPal.log',
            'log.LogLevel' => 'DEBUG',
            'mode' => 'live', // 默认是使用沙盒。开启这个,表示使用正式环境
        )
    );
    

    以下是执行结构,我吧 client 写错,会出现 ERROR 的报错

    [11-07-2020 07:14:37] PayPal\Core\PayPalHttpConnection : INFO: POST https://api.sandbox.paypal.com/v1/oauth2/token
    [11-07-2020 07:14:39] PayPal\Core\PayPalHttpConnection : INFO: Response Status  : 200
    [11-07-2020 07:14:39] PayPal\Core\PayPalHttpConnection : INFO: POST https://api.sandbox.paypal.com/v1/payments/payment
    [11-07-2020 07:14:40] PayPal\Core\PayPalHttpConnection : INFO: Response Status  : 201
    [11-07-2020 07:15:58] PayPal\Core\PayPalHttpConnection : INFO: POST https://api.sandbox.paypal.com/v1/oauth2/token
    [11-07-2020 07:16:00] PayPal\Core\PayPalHttpConnection : INFO: Response Status  : 401
    [11-07-2020 07:16:00] PayPal\Core\PayPalHttpConnection : ERROR: Got Http response code 401 when accessing https://api.sandbox.paypal.com/v1/oauth2/token. {"error":"invalid_client","error_description":"Client Authentication failed"}
    
    

    4. 同步回调

    这个是按照支付流程,付款后,paypal 跳转的 url格式如下
    http://pay.xxx.com/callback.php?r=index/callback&paymentId=PAYID-L4GSHBA2UL56165LM176404F&token=EC-7R537316F06356329&PayerID=HNANHU3TEQETQ
    可以看到看到有 paymentId,token ,PayerID 三个参数。但是 paypal 并没有给支付是否成功的参数。以后我测试下正式环境,参数如果有变化,再做补充
    如果取消,则会跳转到取消后的 url
        /**
         * 回调
         */
        public function Callback()
        {
            if ( !isset($_GET['paymentId']) && !isset($_GET['PayerID'])) {
                echo '取消付款';die;
            }
    
            $paymentId = trim($_GET['paymentId']);
            $PayerID = trim($_GET['PayerID']);
    
            if (!isset( $paymentId, $PayerID)) {
                echo '支付失败';die;
            }
    
            $payment = Payment::get($paymentId, $this->PayPal);
            $execute = new PaymentExecution();
            $execute->setPayerId($PayerID);
    
            try {
                $payment->execute($execute, $this->PayPal);
            } catch (Exception $e) {
                echo ',支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
            }
            echo '支付成功,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
        }
    

    5.异步回调

    这个是在后台设置的 https://developer.paypal.com/developer/applications/->My Apps & Crentials->REST API apps 中的APP name->页面的最下面选择Add Webhook->输入Webhook URL

      public function notify(){
    
            //获取回调结果
            $json_data = $this->get_JsonData();
    
            if(!empty($json_data)){
                 Log::debug("paypal notify info:\r\n".json_encode($json_data));
            }else{
                Log::debug("paypal notify fail:参加为空");
            }
              //自己打印$json_data的值看有那些是你业务上用到的
              //比如我用到
              $data['invoice'] = $json_data['resource']['invoice_number'];
              $data['txn_id'] = $json_data['resource']['id'];
              $data['total'] = $json_data['resource']['amount']['total'];
              $data['status'] = isset($json_data['status'])?$json_data['status']:'';
              $data['state'] = $json_data['resource']['state'];
    
            try {
                     //处理相关业务
            } catch (\Exception $e) {
                //记录错误日志
                Log::error("paypal notify fail:".$e->getMessage());
    
                return "fail";
            }
            return "success";
        }
    
        public function get_JsonData(){
            $json = file_get_contents('php://input');
            if ($json) {
                $json = str_replace("'", '', $json);
                $json = json_decode($json,true);
            }
            return $json;
        }
    

    6.沙盒测试账号 https://developer.paypal.com/developer/accounts/

    图片.png

    相关文章

      网友评论

          本文标题:paypal 支付流程

          本文链接:https://www.haomeiwen.com/subject/soabcktx.html