至此准备工作差不多了,开始动代码。
{
"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里面有一个sample项目,里面有各种实例。
打开浏览器,输入http://~/rest-api-sdk-php/sample/index.php,“~”符号改为你自己的路径。
可以看到sample了,如下图:
图中的PayPal Payments - similar to Express Checkout in Classic APIs即为支付接口,对应的代码路径为~/rest-api-sdk-php/sample/payments/CreatePaymentUsingPayPal.php。
PayPal Payments的逻辑大致如下:
实现如下:
~/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服务端返回的授权地址
转链到授权地址
用户登录授权之后
点击继续,返回用户设置的execute地址
至此,PayPal-PHP-SDK支付接口sample支付过程完毕。
在项目根目录创建app文件夹,创建几个必须的文件如下:
其中:
- payment.php,创建支付
- exec.php,执行支付,用户授权返回地址
- cancel.php,用户取消支付
- common.php,公共文件
payment.php文件
// +---------------------------------------------------------------------- // | 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 //参数 $shipping = 15;//运费 $tax = 10;//税费 $quantity = 4;//数量 $price = 30;//单价 $subtotal = $quantity * $price;//商品总价=数量*单价 $total = $subtotal + $shipping + $tax;//总费用 $item1 = new Item(); $item1->setName('test pro 1')//购物详情 ->setCurrency('USD') ->setQuantity($quantity) ->setSku("testpro1_01") // Similar to `item_number` in Classic API 物品号 ->setPrice($price); // $item2 = new Item(); // $item2->setName('test pro 2') // ->setCurrency('USD') // ->setQuantity(5) //数量 // ->setSku("testpro2_01") // Similar to `item_number` in Classic API 物品号 // ->setPrice(20); $itemList = new ItemList(); $itemList->setItems(array($item1));//如果多个可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($shipping)//运费 ->setTax($tax)//税费 ->setSubtotal($subtotal);//金额 和上面的物品价格总和对应 // ### Amount // Lets you specify a payment amount. // You can also specify additional details // such as shipping, tax. // 总价要和上面的三项费用一致 $amount = new Amount(); $amount->setCurrency("USD") ->setTotal($total) ->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&subtotal=$subtotal&total=$total&shipping=$shipping&tax=$tax") ->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文件
// +----------------------------------------------------------------------
// | 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' && isset($_GET['shipping']) && isset($_GET['tax']) && isset($_GET['subtotal']) && isset($_GET['total'])) {
//接收参数
$shipping = $_GET['shipping'];//运费
$tax = $_GET['tax'];//税费
$subtotal = $_GET['subtotal'];//商品总价
$total = $_GET['total'];//总费用
// 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($shipping)//运费
->setTax($tax)//税费
->setSubtotal($subtotal);//金额
$amount->setCurrency('USD');
$amount->setTotal($total);
$amount->setDetails($details);
$transaction->setAmount($amount);
// Add the above transaction object inside our Execution object.
$execution->addTransaction($transaction);
header("Content-type: text/html; charset=utf-8");
try {
// Execute the payment
$result = $payment->execute($execution, $apiContext);
echo "支付成功";
// 账单唯一交易号,paypal账户交易记录里面的标示
$data['tradeId'] = '账单唯一交易号:'.$result->transactions[0]->related_resources[0]->sale->id;
// 账单号,paypal账户交易记录里面的标示
$data['billId'] = '账单号:'.$result->transactions[0]->invoice_number;
// payid,接口查询使用的账单id
$data['payId'] = 'payid:'.$result->id;
echo "";
var_dump($data);
} 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文件,得到授权地址,如下:
转链到用户授权地址
用户登录授权,可以看到在我们设置过收货地址之后,支付收货地址是默认无法更改的。
用户点击继续,会转链到我们的支付成功回调地址exec.php。
用户点击取消并返回,会转链到我们的支付失败回调地址cancel.php
支付过后可进入sandbox账号中心查看是否有交易。
https://www.sandbox.paypal.com