PayPal-PHP-SDK(V1.7.4)支付接口实现

paypal支付接口准备工作

  • 首先去申请一个paypal账号,https://www.paypal.com/。
  • 申请完毕并登录,进入https://developer.paypal.com/developer/accounts/。即可看到你申请账号自动配属的两个测试账号,账号类别分别是:BUSINESS和PERSONAL,PERSONAL的账号里面有$9999,测试费用,表激动。
  • 下面去给两个账号设置密码,点击账号展开,然后点击Profile,会弹出账号信息框,里面可以设置密码等一堆属性。如果点击账号始终无法展开,请吐槽下paypal,然后F5再点。
  • 下面进入https://developer.paypal.com/developer/applications/申请APP,点击REST API apps栏目下面的Create App按钮,写进一个APP名称,然后选择一个测试账户作为此APP绑定的账号,如果你在上一步没有申请新的测试账号,那么这里默认就是选择了BUSINESS账号。
  • 然后打开创建的APP,可以看到APP的clientId和clientSecret。
  • paypal的测试环境域名为sandbox.paypal.com,正式域名为www.paypal.com。一下测试均为测试环境。

至此准备工作差不多了,开始动代码。

PayPal-PHP-SDK下载

  • 通过composer(composer安装教程)下载PayPal-PHP-SDK,具体的composer.json如下:
{
    "require" : {
        "paypal/rest-api-sdk-php" : "1.7.4"
    },
    "repositories": {
        "packagist": {
            "type": "composer",
            "url": "https://packagist.phpcomposer.com"
        }
    }
}
  • 切换至项目目录并执行composer install,PayPal-PHP-SDK安装完毕。
  • 因为PayPal-PHP-SDK里面的composer.json里面的require有psr/log,所以在在目录vendor下有三个文件夹:composer,paypal和psr。
  • 此时项目的目录结构如下,其中的app文件夹是下面实例化创建的文件夹。
    PayPal-PHP-SDK(V1.7.4)支付接口实现_第1张图片

PayPal-PHP-SDK支付接口测试

然后就简单了,PayPal-PHP-SDK里面有一个sample项目,里面有各种实例。
打开浏览器,输入http://~/rest-api-sdk-php/sample/index.php,“~”符号改为你自己的路径。
可以看到sample了,如下图:
PayPal-PHP-SDK(V1.7.4)支付接口实现_第2张图片
图中的PayPal Payments - similar to Express Checkout in Classic APIs即为支付接口,对应的代码路径为~/rest-api-sdk-php/sample/payments/CreatePaymentUsingPayPal.php。

PayPal Payments的逻辑大致如下:

  • 创建一个支付,发送到paypal服务端
  • paypal服务端返回一个用户授权地址
  • 转链到用户授权地址,用户授权
  • 用户授权完毕,paypal返回到客户端设置的execute地址,付款实现。

实现如下:
~/rest-api-sdk-php/sample/payments/CreatePaymentUsingPayPal.php有如下代码

// ### Get redirect url
// The API response provides the url that you must redirect
// the buyer to. Retrieve the url from the $payment->getApprovalLink()
// method
// 获取到重定向地址
$approvalUrl = $payment->getApprovalLink();

// NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY
// 将重定向地址打印出来
ResultPrinter::printResult("Created Payment Using PayPal. Please visit the URL to Approve.".$approvalUrl, "Payment", "$approvalUrl", $request, $payment);

点击
这里写图片描述
页面执行完毕,既看到paypal服务端返回的授权地址
PayPal-PHP-SDK(V1.7.4)支付接口实现_第3张图片
转链到授权地址
PayPal-PHP-SDK(V1.7.4)支付接口实现_第4张图片
用户登录授权之后
PayPal-PHP-SDK(V1.7.4)支付接口实现_第5张图片
点击继续,返回用户设置的execute地址
PayPal-PHP-SDK(V1.7.4)支付接口实现_第6张图片
至此,PayPal-PHP-SDK支付接口sample支付过程完毕。

支付接口实例化

在项目根目录创建app文件夹,创建几个必须的文件如下:
PayPal-PHP-SDK(V1.7.4)支付接口实现_第7张图片
其中:
- payment.php,创建支付
- exec.php,执行支付,用户授权返回地址
- cancel.php,用户取消支付
- common.php,公共文件

payment.php文件

php
// +----------------------------------------------------------------------
// | Perfect Is Shit
// +----------------------------------------------------------------------
// | paypal支付DEMO
// +----------------------------------------------------------------------
// | Author: alexander 
// +----------------------------------------------------------------------
// | Datetime: 2016-07-28 10:56:40
// +----------------------------------------------------------------------
// | Copyright: Perfect Is Shit
// +----------------------------------------------------------------------
require_once('./common.php');

use PayPal\Api\Amount;
use PayPal\Api\Details;
use PayPal\Api\Item;
use PayPal\Api\ItemList;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Api\ShippingAddress;

// ### Payer
// A resource representing a Payer that funds a payment
// For paypal account payments, set payment method
// to 'paypal'.
$payer = new Payer();
$payer->setPaymentMethod("paypal");

// ### Itemized information
// (Optional) Lets you specify item wise
// information
$item1 = new Item();
$item1->setName('test pro 1')
    ->setCurrency('USD')
    ->setQuantity(1)
    ->setSku("testpro1_01") // Similar to `item_number` in Classic API
    ->setPrice(20);
$item2 = new Item();
$item2->setName('test pro 2')
    ->setCurrency('USD')
    ->setQuantity(5)
    ->setSku("testpro2_01") // Similar to `item_number` in Classic API
    ->setPrice(10);

$itemList = new ItemList();
$itemList->setItems(array($item1, $item2));

// 自定义用户收货地址,避免用户在paypal上账单的收货地址和销售方收货地址有出入
// 这里定义了收货地址,用户在支付过程中就不能更改收货地址,否则,用户可以自己更改收货地址
$address = new ShippingAddress();
$address->setRecipientName('什么名字')
        ->setLine1('什么街什么路什么小区')
        ->setLine2('什么单元什么号')
        ->setCity('城市名')
        ->setState('浙江省')
        ->setPhone('12345678911')
        ->setPostalCode('12345')
        ->setCountryCode('CN');

$itemList->setShippingAddress($address);


// ### Additional payment details
// Use this optional field to set additional
// payment information such as tax, shipping
// charges etc.
$details = new Details();
$details->setShipping(5)
    ->setTax(10)
    ->setSubtotal(70);

// ### Amount
// Lets you specify a payment amount.
// You can also specify additional details
// such as shipping, tax.
$amount = new Amount();
$amount->setCurrency("USD")
    ->setTotal(85)
    ->setDetails($details);

// ### Transaction
// A transaction defines the contract of a
// payment - what is the payment for and who
// is fulfilling it.
$transaction = new Transaction();
$transaction->setAmount($amount)
    ->setItemList($itemList)
    ->setDescription("Payment description")
    ->setInvoiceNumber(uniqid());

// ### Redirect urls
// Set the urls that the buyer must be redirected to after
// payment approval/ cancellation.
$baseUrl = getBaseUrl();
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl("$baseUrl/exec.php?success=true")
    ->setCancelUrl("$baseUrl/cancel.php?success=false");

// ### Payment
// A Payment Resource; create one using
// the above types and intent set to 'sale'
$payment = new Payment();
$payment->setIntent("sale")
    ->setPayer($payer)
    ->setRedirectUrls($redirectUrls)
    ->setTransactions(array($transaction));

$payment->create($apiContext);

$approvalUrl = $payment->getApprovalLink();
// 打印出用户授权地址,这里仅仅实现支付过程,流程没有进一步完善。
dump($approvalUrl);

exec.php文件


// +----------------------------------------------------------------------
// | Perfect Is Shit
// +----------------------------------------------------------------------
// | 执行支付DEMO
// +----------------------------------------------------------------------
// | Author: alexander 
// +----------------------------------------------------------------------
// | Datetime: 2016-07-28 11:53:10
// +----------------------------------------------------------------------
// | Copyright: Perfect Is Shit
// +----------------------------------------------------------------------
set_time_limit(3600);
require_once('./common.php');

use PayPal\Api\Amount;
use PayPal\Api\Details;
use PayPal\Api\ExecutePayment;
use PayPal\Api\Payment;
use PayPal\Api\PaymentExecution;
use PayPal\Api\Transaction;

// ### Approval Status
// Determine if the user approved the payment or not
if (isset($_GET['success']) && $_GET['success'] == 'true') {

    // Get the payment Object by passing paymentId
    // payment id was previously stored in session in
    // CreatePaymentUsingPayPal.php
    $paymentId = $_GET['paymentId'];
    $payment = Payment::get($paymentId, $apiContext);

    // ### Payment Execute
    // PaymentExecution object includes information necessary
    // to execute a PayPal account payment.
    // The payer_id is added to the request query parameters
    // when the user is redirected from paypal back to your site
    $execution = new PaymentExecution();
    $execution->setPayerId($_GET['PayerID']);

    // ### Optional Changes to Amount
    // If you wish to update the amount that you wish to charge the customer,
    // based on the shipping address or any other reason, you could
    // do that by passing the transaction object with just `amount` field in it.
    // Here is the example on how we changed the shipping to $1 more than before.
    $transaction = new Transaction();
    $amount = new Amount();
    $details = new Details();

    $details->setShipping(5)
        ->setTax(10)
        ->setSubtotal(70);

    $amount->setCurrency('USD');
    $amount->setTotal(85);
    $amount->setDetails($details);
    $transaction->setAmount($amount);

    // Add the above transaction object inside our Execution object.
    $execution->addTransaction($transaction);

    try {
        // Execute the payment
        $result = $payment->execute($execution, $apiContext);
        echo "支付成功";
    } catch (Exception $ex) {
        echo "支付失败";
        exit(1);
    }

    return $payment;
} else {
    echo "PayPal返回回调地址参数错误";
}

cancel.php文件


// +----------------------------------------------------------------------
// | Perfect Is Shit
// +----------------------------------------------------------------------
// | 取消支付DEMO
// +----------------------------------------------------------------------
// | Author: alexander 
// +----------------------------------------------------------------------
// | Datetime: 2016-07-29 11:31:32
// +----------------------------------------------------------------------
// | Copyright: Perfect Is Shit
// +----------------------------------------------------------------------
echo "用户取消支付";

common.php文件


// +----------------------------------------------------------------------
// | Perfect Is Shit
// +----------------------------------------------------------------------
// | 公共文件
// +----------------------------------------------------------------------
// | Author: alexander 
// +----------------------------------------------------------------------
// | Datetime: 2016-07-28 11:55:30
// +----------------------------------------------------------------------
// | Copyright: ShowMore
// +----------------------------------------------------------------------
require_once('../vendor/autoload.php');

use PayPal\Rest\ApiContext;
use PayPal\Auth\OAuthTokenCredential;

// 下面为申请app获得的clientId和clientSecret,必填项,否则无法生成token。
$clientId = '';
$clientSecret = '';
$apiContext = new ApiContext(
    new OAuthTokenCredential(
        $clientId,
        $clientSecret
    )
);
$apiContext->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,
        // 'http.CURLOPT_CONNECTTIMEOUT' => 30
        // 'http.headers.PayPal-Partner-Attribution-Id' => '123123123'
        //'log.AdapterFactory' => '\PayPal\Log\DefaultLogFactory' // Factory class implementing \PayPal\Log\PayPalLogFactory
    )
);


// 浏览器友好的变量输出
function dump($var, $echo=true, $label=null, $strict=true) {
    $label = ($label === null) ? '' : rtrim($label) . ' ';
    if (!$strict) {
        if (ini_get('html_errors')) {
            $output = print_r($var, true);
            $output = "
" . $label . htmlspecialchars($output, ENT_QUOTES) . "
"
; } else { $output = $label . print_r($var, true); } } else { ob_start(); var_dump($var); $output = ob_get_clean(); if (!extension_loaded('xdebug')) { $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output); $output = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'
; } } if ($echo) { echo($output); return null; }else return $output; } /** * ### getBaseUrl function * // utility function that returns base url for * // determining return/cancel urls * * @return string */ function getBaseUrl() { if (PHP_SAPI == 'cli') { $trace=debug_backtrace(); $relativePath = substr(dirname($trace[0]['file']), strlen(dirname(dirname(__FILE__)))); echo "Warning: This sample may require a server to handle return URL. Cannot execute in command line. Defaulting URL to http://localhost$relativePath \n"; return "http://localhost" . $relativePath; } $protocol = 'http'; if ($_SERVER['SERVER_PORT'] == 443 || (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on')) { $protocol .= 's'; } $host = $_SERVER['HTTP_HOST']; $request = $_SERVER['PHP_SELF']; return dirname($protocol . '://' . $host . $request); }

支付接口实例测试

执行payment.php文件,得到授权地址,如下:
这里写图片描述
转链到用户授权地址
PayPal-PHP-SDK(V1.7.4)支付接口实现_第8张图片
用户登录授权,可以看到在我们设置过收货地址之后,支付收货地址是默认无法更改的。
PayPal-PHP-SDK(V1.7.4)支付接口实现_第9张图片
用户点击继续,会转链到我们的支付成功回调地址exec.php。
这里写图片描述
用户点击取消并返回,会转链到我们的支付失败回调地址cancel.php
这里写图片描述
支付过后可进入sandbox账号中心查看是否有交易。
PayPal-PHP-SDK(V1.7.4)支付接口实现_第10张图片
测试的款项都在这里,有个问题,sandbox上面的交易时间总比我这边晚一天,比如今天是7月29日完成的交易,但是在sandbox里面显示的都是7月28日。不知道是不是个BUG。

至此,PayPal-PHP-SDK的支付接口OK。
可以对PayPal-PHP-SDK底层代码进行进一步研究,有时间再弄。

你可能感兴趣的:(php,paypal)