php – 如何实现Authorize.NET Hosted Payments iFrame和Laravel
作者:互联网
我发现Authorize.NET提供的官方文档和github示例是一个非常令人困惑的东西,你不需要它.这篇文章总结了最近几个小时的工作,希望它可以帮助别人.
本指南假设您不需要收据页面,并且您希望在成功付款时自动向前移动用户.
解决方法:
网站的后端是Laravel(PHP),但这里的Laravel具体没什么.
首先要做的是添加Authorize.NET SDK:
composer require authorizenet/authorizenet
然后,我设置了一个接受订单的托管付款存储库,但是您可以这样做,这样就可以将托管表单令牌返回给准备传递给视图的控制器.
<?php
namespace ShopApp\Repositories;
use ShopApp\Models\Order;
use ShopApp\Repositories\Contracts\hostedPaymentRepositoryContract;
use Illuminate\Support\Facades\Config;
use net\authorize\api\contract\v1\MerchantAuthenticationType;
use net\authorize\api\contract\v1\TransactionRequestType;
use net\authorize\api\controller\GetHostedPaymentPageController;
use net\authorize\api\contract\v1\GetHostedPaymentPageRequest;
use net\authorize\api\contract\v1\SettingType;
use net\authorize\api\constants\ANetEnvironment;
use net\authorize\api\contract\v1\CustomerAddressType;
use ShopApp\Models\Address;
/**
* Class hostedPaymentRepository
* @package ShopApp\Repositories
* @todo - Implement methods to talk to Authorize.NET and show form.
*/
class hostedPaymentRepository implements hostedPaymentRepositoryContract
{
public $response; //what did we get back?
public $paymentFormToken;
public function getHostedFormToken(Order $order){
$payment_amount = null;
foreach($order->items as $order_item){
$payment_amount += $order_item->price;
}
$billing_address = Address::findOrFail($order->billing_address_id);
// Common setup for API credentials
$merchantAuthentication = new MerchantAuthenticationType();
$merchantAuthentication->setName(Config::get('yoursite.payment_providers.authorize_dot_net.MERCHANT_LOGIN_ID'));
$merchantAuthentication->setTransactionKey(Config::get('yoursite.payment_providers.authorize_dot_net.MERCHANT_TRANSACTION_KEY'));
//create a transaction
$transactionRequestType = new TransactionRequestType();
$transactionRequestType->setTransactionType("authCaptureTransaction");
$transactionRequestType->setAmount($payment_amount);
// Create the Bill To info
$billto = new CustomerAddressType();
$billto->setFirstName($order->billing_first_name);
$billto->setLastName($order->billing_last_name);
$billto->setAddress($billing_address->address_1);
$billto->setCity($billing_address->city);
$billto->setState($billing_address->state);
$billto->setZip($billing_address->zip);
$billto->setCountry($billing_address->country);
if(!is_null($order->phone)){
$billto->setPhoneNumber($order->phone);
}
//@todo - implement user stuff and get email
//$billto->setEmail("changethis@later.com");
$transactionRequestType->setBillTo($billto);
// Set Hosted Form options
$setting1 = new SettingType();
$setting1->setSettingName("hostedPaymentButtonOptions");
$setting1->setSettingValue("{\"text\": \"Pay Now\"}");
$setting2 = new SettingType();
$setting2->setSettingName("hostedPaymentOrderOptions");
$setting2->setSettingValue("{\"show\": false}");
$setting3 = new SettingType();
$setting3->setSettingName("hostedPaymentReturnOptions");
$setting3->setSettingValue("{\"showReceipt\" : false }");
$setting4 = new SettingType();
$setting4->setSettingName("hostedPaymentIFrameCommunicatorUrl");
$setting4->setSettingValue("{\"url\": \"https://yoursite.local/checkout/payment/response\"}");
// Build transaction request
$request = new GetHostedPaymentPageRequest();
$request->setMerchantAuthentication($merchantAuthentication);
$request->setTransactionRequest($transactionRequestType);
$request->addToHostedPaymentSettings($setting1);
$request->addToHostedPaymentSettings($setting2);
$request->addToHostedPaymentSettings($setting3);
$request->addToHostedPaymentSettings($setting4);
//execute request
$controller = new GetHostedPaymentPageController($request);
$response = $controller->executeWithApiResponse(ANetEnvironment::SANDBOX);
if (($response == null) && ($response->getMessages()->getResultCode() != "Ok") )
{
return false;
}
return $response->getToken();
}
}
请注意,我已将showReceipt设置为false,并且我提供了另一个名为hostedPaymentIFrameCommunicatorUrl的设置.不要忘记hostedPaymentIFrameCommunicatorUrl,否则无论将showReceipt设置为false,您都将获得接收页面.
hostedPaymentIFrameCommunicatorUrl必须与您的付款页面和同一端口位于同一个域中.
然后在你的视图中你需要添加iFrame(我只是坐在页面中,我没有打扰灯箱:
<div id="iframe_holder" class="center-block" style="width:90%;max-width: 1000px" data-mediator="payment-form-loader">
<iframe id="load_payment" class="embed-responsive-item" name="load_payment" width="750" height="900" frameborder="0" scrolling="no">
</iframe>
<form id="send_hptoken" action="https://test.authorize.net/payment/payment" method="post" target="load_payment">
<input type="hidden" name="token" value="{{ $hosted_payment_form_token }}" />
</form>
</div>
在同一视图中,您需要至少加载以下javascript(即时通讯使用jQuery并且只有一半实现了transactResponse方法,但您明白了):
$(document).ready(function(){
window.CommunicationHandler = {};
function parseQueryString(str) {
var vars = [];
var arr = str.split('&');
var pair;
for (var i = 0; i < arr.length; i++) {
pair = arr[i].split('=');
vars[pair[0]] = unescape(pair[1]);
}
return vars;
}
window.CommunicationHandler.onReceiveCommunication = function (argument) {
console.log('communication handler enter');
var params = parseQueryString(argument.qstr)
switch(params['action']){
case "resizeWindow" :
console.log('resize'); break;
case "successfulSave" :
console.log('save'); break;
case "cancel" :
console.log('cancel'); break;
case "transactResponse" :
sessionStorage.removeItem("HPTokenTime");
console.log('transaction complete');
var transResponse = JSON.parse(params['response']);
window.location.href = '/checkout/complete';
}
}
//send the token
$('#send_hptoken').submit();
});
上面的代码添加了一个函数来处理从iFrame Communicator返回的消息(下一步),并提交付款表单令牌以获取并加载实际的付款表单.
接下来我们需要设置一个’iframe communicator’这基本上只是Authorize.NET绕过same-domain origin policy的一种方式
为此,请创建一个新路由和一个只返回简单HTML页面(或刀片模板,但它应该没有脚本以外的内容)的视图.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>IFrame Communicator</title>
<script type="text/javascript">
function callParentFunction(str) {
if (str && str.length > 0 && window.parent.parent
&& window.parent.parent.CommunicationHandler && window.parent.parent.CommunicationHandler.onReceiveCommunication) {
var referrer = document.referrer;
window.parent.parent.CommunicationHandler.onReceiveCommunication({qstr : str , parent : referrer});
}
}
function receiveMessage(event) {
if (event && event.data) {
callParentFunction(event.data);
}
}
if (window.addEventListener) {
window.addEventListener("message", receiveMessage, false);
} else if (window.attachEvent) {
window.attachEvent("onmessage", receiveMessage);
}
if (window.location.hash && window.location.hash.length > 1) {
callParentFunction(window.location.hash.substring(1));
}
</script>
</head>
<body></body>
</html>
这里的关键部分是window.parent.parent
Authorize.NET抓取你在开头提供它的hostedPaymentIFrameCommunicatorUrl,并将其嵌入到另一个iFrame中,在他们自己的支付iFrame中.这就是为什么它是window.parent.parent.
然后,您的hostedPaymentIFrameCommunicatorUrl脚本可以将付款响应传递到您的付款页面,您可以编辑上述功能,以便在此之后执行您喜欢的操作.
希望能帮助别人.
Authorize.NET严重缺乏示例,他们的文档充其量是轻量级的.让你通过大量不需要的代码筛选的“全能”示例只是简单的懒惰.
他们的API文档虽然不错,但他们只需要体面的例子……
标签:php,cross-domain,laravel,authorize-net 来源: https://codeday.me/bug/20190611/1217576.html