【php接入PayPal】贝宝支付2020-12月版

支付逻辑简介

跟微信和支付宝支付不一样,微信和支付宝都是先走统一下单接口,然后返回创建的下单会话id等然后传给前端,贝宝支付是我们先通过API发起个支付请求,然后贝宝给我们个支付链接,前端打开我们的支付链接:例如https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-7K8740615W719670D ,然后该链接会有我们支付订单的部分信息,然后利用沙盒的账号支付确认要支付后,会返回到下单时设置的回调支付那里,如下图:

const accept_url = 'http://fumei.com:8082/service.php?action=paypal_callback&com_id=1210';//返回地址
$redirectUrls = new RedirectUrls();
         $redirectUrls->setReturnUrl(self::accept_url.'&orderId='.$order->orderId.'&success=true')
             ->setCancelUrl(self::accept_url.'&orderId='.$order->orderId.'&success=false');

这里回调会带着订单号和发起是否成功或者失败,如果成功,其实到这里我们并没有完成支付,只有在回调地址里才能完成payment支付,不像微信和支付宝,前端调起真实的支付,支付完毕后就要跳转前端准备的支付成功或失败的页面。

PayPal账号设置

  • 创建账号:
    创建沙盒账号 https://www.paypal.com/c2/webapps/mpp/account-selection

  • 登录沙盒后台
    https://developer.paypal.com/developer/applications/

  • 创建项目APP 查看 APPID和Secret
    【php接入PayPal】贝宝支付2020-12月版
    【php接入PayPal】贝宝支付2020-12月版

  • 设置沙盒支付测试账号,充值,创建
    【php接入PayPal】贝宝支付2020-12月版

  • 设置回调地址
    【php接入PayPal】贝宝支付2020-12月版
    代码实现

  • SDK下载

  • 引入composer 管理包或者直接下载

  • 引入文件

    use PayPal\Api\Payer;
    use PayPal\Api\Item;
    use PayPal\Api\ItemList;
    use PayPal\Api\Details;
    use PayPal\Api\Amount;
    use PayPal\Api\Transaction;
    use PayPal\Api\RedirectUrls;
    use PayPal\Api\Payment;
    use PayPal\Auth\OAuthTokenCredential;
    use PayPal\Exception\PayPalConnectionException;
    use PayPal\Rest\ApiContext;
    use PayPal\Api\PaymentExecution;
    
  • 初始化

       protected $PayPal;
    
       public function __construct()
       {
           $this->PayPal = new ApiContext(
               new OAuthTokenCredential(
                   self::clientId,
                   self::clientSecret
               )
           );
           $this->PayPal->setConfig(
               array(
                   'mode' => 'sandbox',//线上的则配置为live
                   'log.LogEnabled' => true,
                   'log.FileName' => '../PayPal.log',
                   'log.LogLevel' => 'DEBUG', // PLEASE USE `INFO` LEVEL FOR LOGGING IN LIVE ENVIRONMENTS
                   'cache.enabled' => true
               )
           );
       }
    
  • 创建支付链接(即下单接口)

    /**
        * @param
        * $product 商品
        * $price 价钱
        * $shipping 运费
        * $description 描述内容
        */
       public function pay()
       {
           global $db,$request,$comId;
           $fenbiao = getFenbiao($comId,20);
           $userId = (int)$request['user_id'];
           $oid = $request['order_id'];
           $order = $db->get_row("select * from order$fenbiao where id = $oid");
    
           $product_json = json_decode($order->product_json);
           $subject = '';
           $daizhifu = $order->price;
           $item = [];
           foreach ($product_json as $pdt) {
               $product_item = array(
                   'title' => $pdt->title,
                   'sn' => $pdt->sn,
                   'num' => (int)$pdt->num,
                   'price' => (int) $pdt->price_sale
               );
               $subject.=','.$pdt->title.'*'.$pdt->num;
           }
           $body = substr($subject,1);
           $subject = sys_substr($body,30,true);
           $subject = str_replace('_','',$subject);
           $num = (int)$order->pdtNums;
           $price = (int)$order->price;
           try {
               $payer = new Payer();
               $payer->setPaymentMethod('paypal');
               $item = new Item();
               $item->setName($product_item['title']) // 子订单的名称
               ->setDescription($product_item['sn']) // 子订单描述
               ->setCurrency(self::Currency) // 币种
               ->setQuantity($product_item['num']) // 数量
               ->setPrice($product_item['price']); // 价格
    
               $itemList = new ItemList();
               $itemList->setItems([$item]); // 设置子订单列表
    
               // 这里是设置运费等
               $details = new Details();
               $details->setShipping(0)
                   ->setSubtotal($price);
               // 设置总计费用
               $amount = new Amount();
               $amount->setCurrency(self::Currency)
                   ->setTotal($price)
                   ->setDetails($details);
               // 创建交易
               $transaction = new Transaction();
               $transaction->setAmount($amount)
                   ->setItemList($itemList)
                   ->setDescription($subject)
                   ->setInvoiceNumber($order->orderId);
               
               // 这里设置支付成功和失败后的跳转链接
               $redirectUrls = new RedirectUrls();
    
               $redirectUrls->setReturnUrl(self::accept_url.'&orderId='.$order->orderId.'&success=true')
                   ->setCancelUrl(self::accept_url.'&orderId='.$order->orderId.'&success=false');
    
               $payment = new Payment();
               $payment->setIntent('sale')
                   ->setPayer($payer)
                   ->setRedirectUrls($redirectUrls)
                   ->setTransactions([$transaction]);
    
               $payment->create($this->PayPal);
    
               // 得到支付链接
               $link = $payment->getApprovalLink();
               $return['code'] = 1;
               $return['message'] = '';
               $return['data'] = array();
               $return['data']['link'] = $link;
               return json_encode($return,JSON_UNESCAPED_UNICODE);
           } catch (HttpException $e) {
               $data = (['msg' => $e->getMessage(), 'code' => $e->getStatusCode(), 'data' => ['order' => ['no' => '1112323231']]]);
               return null;
           }
       }
    
  • 前端支付密码输入完毕后,发起支付

        /**
        * 回调
        */
       public function callback()
       {
           global $db,$request,$comId;
           $fenbiao = getFenbiao($comId,20);
           $success = trim($_GET['success']);
    
           if ($success == 'false' && !isset($_GET['paymentId']) && !isset($_GET['PayerID'])) {
               echo '取消付款';die;
           }
    
           $paymentId = trim($_GET['paymentId']);
           $PayerID = trim($_GET['PayerID']);
           $orderId = trim($_GET['orderId']);
    
           if (!isset($success, $paymentId, $PayerID)) {
               echo '支付失败';die;
           }
    
           if ((bool)$_GET['success'] === 'false') {
               echo  '支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
           }
    
           $payment = Payment::get($paymentId, $this->PayPal);
    
           $execute = new PaymentExecution();
    
           $execute->setPayerId($PayerID);
    
           try {
               $payment->execute($execute, $this->PayPal);
               //todo 记录
               $db->query("update order10 set paypal_no = '$paymentId', paypal_payerId ='$PayerID' where orderId = '$orderId'");
               //todo 直接跳转前端页面
               $url = '';
               header("localtion:$url");
           } catch (Exception $e) {
               echo ',支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
           }
           echo '支付成功,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
       }
    
  • 支付后台回调,更改订单状态等

       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;
       }
    
  • 代码总:

    namespace Zhishang;
    
    use PayPal\Api\Payer;
    use PayPal\Api\Item;
    use PayPal\Api\ItemList;
    use PayPal\Api\Details;
    use PayPal\Api\Amount;
    use PayPal\Api\Transaction;
    use PayPal\Api\RedirectUrls;
    use PayPal\Api\Payment;
    use PayPal\Auth\OAuthTokenCredential;
    use PayPal\Exception\PayPalConnectionException;
    use PayPal\Rest\ApiContext;
    use PayPal\Api\PaymentExecution;
    
    class Paypal{
        const clientId = 'AV-SNw2j-1wNqAb1ygg0I4iKT8E8zHT1QCh8eLEbeFZQN2slHhq4dX5pKn4mfz7CHGDhCaVX1N';//ID
        const clientSecret = 'EHjumNJEwf5lkurMyNqo1DJ1v64jsZ9mpFYlKIkVQBh6Kksygxx_u77F8G0rSQHW9Awezdqd4RCd';//秘钥
        const accept_url = 'http://fumei.com:8082/service.php?action=paypal_callback&com_id=1210';//返回地址
        const Currency = 'USD';//币种
        protected $PayPal;
    
        public function __construct()
        {
            $this->PayPal = new ApiContext(
                new OAuthTokenCredential(
                    self::clientId,
                    self::clientSecret
                )
            );
            //如果是沙盒测试环境不设置,请注释掉
    //        $this->paypal->setConfig(
    //            array(
    //                'mode' => 'sandbox',
    //            )
    //        );
    
    //        $this->PayPal->setConfig([
    //            'mode' => 'sandbox',
    //            'log.LogEnabled' => true,
    //            'log.FileName' => 'logs/PayPal.log',
    //            'log.LogLevel' => 'DEBUG', // PLEASE USE `INFO` LEVEL FOR LOGGING IN LIVE ENVIRONMENTS
    //            'cache.enabled' => true,
    //        ]);
            $this->PayPal->setConfig(
                array(
                    'mode' => 'sandbox',
                    'log.LogEnabled' => true,
                    'log.FileName' => '../PayPal.log',
                    'log.LogLevel' => 'DEBUG', // PLEASE USE `INFO` LEVEL FOR LOGGING IN LIVE ENVIRONMENTS
                    'cache.enabled' => true
                )
            );
        }
    
        /**
         * @param
         * $product 商品
         * $price 价钱
         * $shipping 运费
         * $description 描述内容
         */
        public function pay()
        {
            global $db,$request,$comId;
            $fenbiao = getFenbiao($comId,20);
            $userId = (int)$request['user_id'];
            $oid = $request['order_id'];
            $order = $db->get_row("select * from order$fenbiao where id = $oid");
    
            $product_json = json_decode($order->product_json);
            $subject = '';
            $daizhifu = $order->price;
            $item = [];
            foreach ($product_json as $pdt) {
                $product_item = array(
                    'title' => $pdt->title,
                    'sn' => $pdt->sn,
                    'num' => (int)$pdt->num,
                    'price' => (int) $pdt->price_sale
                );
                $subject.=','.$pdt->title.'*'.$pdt->num;
            }
            $body = substr($subject,1);
            $subject = sys_substr($body,30,true);
            $subject = str_replace('_','',$subject);
            $num = (int)$order->pdtNums;
            $price = (int)$order->price;
            try {
                $payer = new Payer();
                $payer->setPaymentMethod('paypal');
                $item = new Item();
                $item->setName($product_item['title']) // 子订单的名称
                ->setDescription($product_item['sn']) // 子订单描述
                ->setCurrency(self::Currency) // 币种
                ->setQuantity($product_item['num']) // 数量
                ->setPrice($product_item['price']); // 价格
    
                $itemList = new ItemList();
                $itemList->setItems([$item]); // 设置子订单列表
    
                // 这里是设置运费等
                $details = new Details();
                $details->setShipping(0)
                    ->setSubtotal($price);
                // 设置总计费用
                $amount = new Amount();
                $amount->setCurrency(self::Currency)
                    ->setTotal($price)
                    ->setDetails($details);
                // 创建交易
                $transaction = new Transaction();
                $transaction->setAmount($amount)
                    ->setItemList($itemList)
                    ->setDescription($subject)
                    ->setInvoiceNumber($order->orderId);
                
                // 这里设置支付成功和失败后的跳转链接
                $redirectUrls = new RedirectUrls();
    
                $redirectUrls->setReturnUrl(self::accept_url.'&orderId='.$order->orderId.'&success=true')
                    ->setCancelUrl(self::accept_url.'&orderId='.$order->orderId.'&success=false');
    
                $payment = new Payment();
                $payment->setIntent('sale')
                    ->setPayer($payer)
                    ->setRedirectUrls($redirectUrls)
                    ->setTransactions([$transaction]);
    
                $payment->create($this->PayPal);
    
                // 得到支付链接
                $link = $payment->getApprovalLink();
                $return['code'] = 1;
                $return['message'] = '';
                $return['data'] = array();
                $return['data']['link'] = $link;
                return json_encode($return,JSON_UNESCAPED_UNICODE);
            } catch (HttpException $e) {
                $data = (['msg' => $e->getMessage(), 'code' => $e->getStatusCode(), 'data' => ['order' => ['no' => '1112323231']]]);
                return null;
            }
        }
    
        /**
         * 回调
         */
        public function callback()
        {
            global $db,$request,$comId;
            $fenbiao = getFenbiao($comId,20);
            $success = trim($_GET['success']);
    
            if ($success == 'false' && !isset($_GET['paymentId']) && !isset($_GET['PayerID'])) {
                echo '取消付款';die;
            }
    
            $paymentId = trim($_GET['paymentId']);
            $PayerID = trim($_GET['PayerID']);
            $orderId = trim($_GET['orderId']);
    
            if (!isset($success, $paymentId, $PayerID)) {
                echo '支付失败';die;
            }
    
            if ((bool)$_GET['success'] === 'false') {
                echo  '支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
            }
    
            $payment = Payment::get($paymentId, $this->PayPal);
    
            $execute = new PaymentExecution();
    
            $execute->setPayerId($PayerID);
    
            try {
                $payment->execute($execute, $this->PayPal);
                //todo 记录
                $db->query("update order10 set paypal_no = '$paymentId', paypal_payerId ='$PayerID' where orderId = '$orderId'");
            } catch (Exception $e) {
                echo ',支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
            }
            echo '支付成功,支付ID【' . $paymentId . '】,支付人ID【' . $PayerID . '】';die;
        }
    
        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;
        }
    }
    
上一篇:【中生代59期直播实录-Paypal张军】 | 研发,产品,架构,业务,项目管理五角关系下的多元组织


下一篇:paypal payflow设置视频教程