Paypal Payments REST API支付 沙箱测试 php版本

官方文档

https://developer.paypal.com/docs/integration/direct/payments/paypal-payments/#create-paypal-payment

准备工作

先要在官网注册PayPal账号,然后打开沙箱账号管理
在这里插入图片描述
能看到有自动创建的2个沙箱账号,选中PERSONAL账号点击Profile,设置自定义密码(记录该账号和密码)。
然后点击左边菜单栏DASHBOARD-My Apps & Credentials创建沙箱应用.
在这里插入图片描述
然后回到沙箱账号管理选中BUSSINESS账号,点击Profile,点击API Credentials,点击REST Apps里的App name。
在这里插入图片描述
进入应用页面后,记录下Client ID和Secret。
在这里插入图片描述

支付流程

payment相关接口的支付流程为:
1、获取accesstoken
2、商户根据订单填充订单信息(事例index.php中create_payment()相关操作)
3、填充完后将数据POST到'/v1/payments/payment'接口(事例index.php中create_payment()相关操作)
4、根据返回值,跳转到返回值中links里的’rel’=‘approval_url’对应的地址中(事例index.php中create_payment()相关操作)
5、用户(登陆准备工作时记录的PERSONAL账号)在该网页完成付款确认点击继续则跳转到执行payment的链接(create_payment()中设置的’redirect_urls’中的’return_url’)并把payerid和paymentid设置在url的参数中
6、执行payment的链接中,商户需要获取到这2个参数后调用'/v1/payments/payment/{paymentid}/execute'接口,完成支付流程。(事例index.php中excute()相关操作)

事例

下面是简单封装了一下的payment相关操作的接口调用。访问index.php,create_payment函数构造订单信息,授权成功跳转localhost?a=excute&PayerID=xxx&paymentid=xxx,excute函数调用paypal类的ExcutePayment方法完成付款。
Paypal.php类

<?php
class Paypal{
    protected $appId;
    protected $appSecret;
    protected $baseUrl='https://api.sandbox.paypal.com';
    /*构造函数,把实例化Paypal类时传进来的appId和appSecret保存起来
     *
     *
     * */
    function __construct($appId,$appSecret)
    {
        $this->appId = $appId;
        $this->appSecret = $appSecret;
    }
    /*curl post
     *param
     * $extreUrl string  接口地址
     * $data     array   提交的数据 为空时为get请求
     * $header   array   请求头信息
     * $Oauth    bool    是否使用Oauth验证
     * return    array   响应信息
     * */
    protected function httpRequest($extreUrl,$data,$header,$Oauth=false)
    {
        $url=$this->baseUrl.$extreUrl;
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
        if($Oauth){
            curl_setopt($curl, CURLOPT_USERPWD,$this->appId.":".$this->appSecret);
        }
        //获取请求头信息
        //curl_setopt($curl, CURLINFO_HEADER_OUT, TRUE);
        curl_setopt($curl, CURLOPT_HTTPHEADER,$header);
        if($data){
            curl_setopt($curl, CURLOPT_POSTFIELDS,$data);
            curl_setopt($curl, CURLOPT_POST,1);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        //获取请求头信息
        //var_dump(curl_getinfo($curl)["request_header"]);
        curl_close($curl);
        return json_decode($output,true);
    }
    /*请求头部加上Authorization
     *param
     * $extreUrl string  接口地址
     * $data     array   请求的参数
     * return    array   返回信息
     * */
    protected function httpRequestWithAuth($extreUrl,$data=[])
    {
        $header[]='Content-Type:application/json';
        $header[]='Authorization:Bearer '.$this->getAccessToken();
        return $this->httpRequest($extreUrl,$data,$header);
    }
    /*转化数组为键值对形式
     *param
     * $array    array   需要转化的数组
     * return    string  转化后的字符串:参数1=值1&参数2=值2
     * */
    protected function array2keyvalue($array)
    {
        $res=[];
        foreach($array as $k=>$v){
            $res[]=$k.'='.$v;
        }
        return implode('&',$res);
    }
    /*获取accesstoken
     * 判断存储的accesstoken是否过期,过期则调用接口获取新的accesstoken否则直接返回。
     * 可以把文件读取改成缓存读取 数据库读取。
     * return    string  accesstoken值
     * */
    protected function getAccessToken()
    {
        //从paypal_access_token.json文件中读取accesstoken和过期时间
        $data = json_decode(file_get_contents("paypal_access_token.json"),true);
        if ($data['expire_time'] < time()) {
            $extreUrl='/v1/oauth2/token';
            $postdata['grant_type']='client_credentials';
            $postdata=$this->array2keyvalue($postdata);
            $header[]="Content-type: application/x-www-form-urlencoded";
            $res=$this->httpRequest($extreUrl,$postdata,$header,true);
            $access_token = $res['access_token'];
            if ($access_token) {
                $data['expire_time'] = time()+$res['expires_in'];
                $data['access_token'] = $access_token;
                $fp = fopen("paypal_access_token.json", "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
            }
        } else {
            $access_token = $data['access_token'];
        }
        return $access_token;
    }
    /*创建payment
    *
	*/
    public function CreatePayment($array)
    {
        $extreUrl='/v1/payments/payment';
        $data['intent']='sale';
        $data['payer']=['payment_method'=>'paypal'];
        $transactions['amount']=$array['amount'];
        $transactions['description']=$array['description'];
        $transactions['custom']=$array['orderid'];
        $transactions['invoice_number']=$array['orderid'];
        $transactions['item_list']['items']=$array['items'];
        $transactions['payment_options']['allowed_payment_method']='INSTANT_FUNDING_SOURCE';
        $transactions['item_list']['shipping_address']=$array['shipping_address'];
        $data['transactions'][]=$transactions;
        $data['note_to_payer']=$array['note_to_payer'];
        $data['redirect_urls']=$array['redirect_urls'];
        return $this->httpRequestWithAuth($extreUrl,json_encode($data));
    }
	 /* 获取 完成payment 
    *param
    * paymentId 创建payment后返回的ID
    * PayerID     用户id 用户完成授权后跳转的excute页面中url带的参数
    **/
    public function ExcutePayment($array)
    {
        $extreUrl='/v1/payments/payment/'.$array['paymentId'].'/execute';
        $data['payer_id']=$array['PayerID'];
        return $this->httpRequestWithAuth($extreUrl,json_encode($data));
    }
    /* 获取payment详情 
    *param
    * paymentId 创建payment后返回的ID
    **/
    public function PaymentInfo($array)
    {
        $extreUrl='/v1/payments/payment/'.$array['paymentId'];
        return $this->httpRequestWithAuth($extreUrl);
    }


}

index.php代码

<?php
include('Paypal.php');
$appId='你的Client ID';
$appSecret='你的Secret';
$paypal=new Paypal($appId,$appSecret);
$a=!is_null($_GET['a'])?$_GET['a']:'create_payment';
$a($paypal);


function create_payment($paypal){
    $array['description']='订单说明';
    //orderid调用paypal类CreatePayment时传入‘invoice_number’中 ‘custom’字段可根据需要填充更多信息
    $array['orderid']=time();
    //订单商品详情1
    $product1['name']='hat';
    $product1['sku']=1;
    $product1['description']='Brown hat';
    $product1['price']="3";
    $product1['currency']='USD';
    $product1['tax']='0.01';
    $product1['quantity']=5;
    //订单商品详情2
    $product2['name']='handbag';
    $product2['sku']='xxxx';
    $product2['description']='Black handbag.';
    $product2['price']="15";
    $product2['currency']='USD';
    $product2['tax']='0.02';
    $product2['quantity']=1;
    $array['items'][]=$product1;
    $array['items'][]=$product2;
    /*
    订单费用$array['amount'] 
    其中total 要和subtotal的计费计算统一不然会报错 
    subtotal+tax+shipping+handing_fee+shipping_discount+insurance =total
    */
    $array['amount']['total']='30.11';
    $array['amount']['currency']='USD';
    //订单收费详情
    $array['amount']['details']['subtotal']="30.00";
    $array['amount']['details']['tax']="0.07";
    $array['amount']['details']['shipping']="0.03";
    $array['amount']['details']['handling_fee']="1.00";
    $array['amount']['details']['shipping_discount']="-1.00";
    $array['amount']['details']['insurance']="0.01";
    //订单收货地址详情
    $array['shipping_address']['recipient_name']="Brian Robinson";
    $array['shipping_address']['line1']="4th Floor";
    $array['shipping_address']['line2']="Unit #34";
    $array['shipping_address']['city']="San Jose";
    $array['shipping_address']['country_code']="US";
    $array['shipping_address']['postal_code']="95131";
    $array['shipping_address']['phone']="011862212345678";
    $array['shipping_address']['state']="CA";
    //提示信息
    $array['note_to_payer']="Contact us for any questions on your order.";
    //执行付款回调地址
    $array['redirect_urls']['return_url']="http://localhost?a=excute";
    //取消付款回调地址
    $array['redirect_urls']['cancel_url']="http://localhost?a=cancel";
    $res=$paypal->CreatePayment($array);
    /*这里需要判断是否成功
     *
     * */
    if(!$res['debug_id'] && strtolower($res['state'])!='failed'){
        foreach($res['links'] as $v){
            if(strtolower($v['rel'])=='approval_url'){
                header('Location: '.$v['href']);
                exit;
            }
        }
    }else{
        echo $res['message'];
    }
}

function excute($paypel){
    $data['PayerID']=$_GET['PayerID'];
    $data['paymentId']=$_GET['paymentId'];
    $res=$paypel->ExcutePayment($data);
    if(strtolower($res['state'])=='approved'){
		//完成付款
    }
}

function cancel(){
    echo '用户取消';
}

function check($paypel){
    $data['paymentId']=$_GET['paymentId'];
    $res=$paypel->PaymentInfo($data);
    var_dump($res);
}

create_payment 返回值数据结构

    array(8) {
      ["id"]=>
      string(30) "PAYID-LR7Y6YA3UM97660A4514331H"
      ["intent"]=>
      string(4) "sale"
      ["state"]=>
      string(7) "created"
      ["payer"]=>
      array(1) {
        ["payment_method"]=>
        string(6) "paypal"
      }
      ["transactions"]=>
      array(1) {
        [0]=>
        array(7) {
          ["amount"]=>
          array(3) {
            ["total"]=>
            string(5) "30.11"
            ["currency"]=>
            string(3) "USD"
            ["details"]=>
            array(6) {
              ["subtotal"]=>
              string(5) "30.00"
              ["tax"]=>
              string(4) "0.07"
              ["shipping"]=>
              string(4) "0.03"
              ["insurance"]=>
              string(4) "0.01"
              ["handling_fee"]=>
              string(4) "1.00"
              ["shipping_discount"]=>
              string(5) "-1.00"
            }
          }
          ["description"]=>
          string(12) "订单说明"
          ["custom"]=>
          string(10) "1551863640"
          ["invoice_number"]=>
          string(10) "1551863640"
          ["payment_options"]=>
          array(3) {
            ["allowed_payment_method"]=>
            string(22) "INSTANT_FUNDING_SOURCE"
            ["recurring_flag"]=>
            bool(false)
            ["skip_fmf"]=>
            bool(false)
          }
          ["item_list"]=>
          array(2) {
            ["items"]=>
            array(2) {
              [0]=>
              array(7) {
                ["name"]=>
                string(3) "hat"
                ["sku"]=>
                string(1) "1"
                ["description"]=>
                string(9) "Brown hat"
                ["price"]=>
                string(4) "3.00"
                ["currency"]=>
                string(3) "USD"
                ["tax"]=>
                string(4) "0.01"
                ["quantity"]=>
                int(5)
              }
              [1]=>
              array(7) {
                ["name"]=>
                string(7) "handbag"
                ["sku"]=>
                string(4) "xxxx"
                ["description"]=>
                string(14) "Black handbag."
                ["price"]=>
                string(5) "15.00"
                ["currency"]=>
                string(3) "USD"
                ["tax"]=>
                string(4) "0.02"
                ["quantity"]=>
                int(1)
              }
            }
            ["shipping_address"]=>
            array(8) {
              ["recipient_name"]=>
              string(14) "Brian Robinson"
              ["line1"]=>
              string(9) "4th Floor"
              ["line2"]=>
              string(8) "Unit #34"
              ["city"]=>
              string(8) "San Jose"
              ["state"]=>
              string(2) "CA"
              ["postal_code"]=>
              string(5) "95131"
              ["country_code"]=>
              string(2) "US"
              ["phone"]=>
              string(15) "011862212345678"
            }
          }
          ["related_resources"]=>
          array(0) {
          }
        }
      }
      ["note_to_payer"]=>
      string(43) "Contact us for any questions on your order."
      ["create_time"]=>
      string(20) "2019-03-06T09:14:07Z"
      ["links"]=>
      array(3) {
        [0]=>
        array(3) {
          ["href"]=>
          string(81) "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-LR7Y6YA3UM97660A4514331H"
          ["rel"]=>
          string(4) "self"
          ["method"]=>
          string(3) "GET"
        }
        [1]=>
        array(3) {
          ["href"]=>
          string(94) "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-2VG2711092225420A"
          ["rel"]=>
          string(12) "approval_url"
          ["method"]=>
          string(8) "REDIRECT"
        }
        [2]=>
        array(3) {
          ["href"]=>
          string(89) "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-LR7Y6YA3UM97660A4514331H/execute"
          ["rel"]=>
          string(7) "execute"
          ["method"]=>
          string(4) "POST"
        }
      }
    }

报错

所使用的环境是win10+apache2.4+php7.1,如果是使用php7.1以下版本,需要把构造数组$res=[];改成$res=array();
有的人curl_exec执行报错,并且echo curl_no($curl);为35,是因为curl扩展使用的openssl版本过低,不支持TLS 1.2。
解决方式:如果是linux编译php时使用新版的openssl,如果是windows暂时只能用新版的php。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值