Paypal可以触发IPN/Webhook而不处理来自return_url的数据?
据我所知,IPN/Webhook是后端通知,并且当前端返回url无法使用时,可以帮助商户端系统可靠地接收事务更新。Paypal可以触发IPN/Webhook而不处理来自return_url的数据?
但是,这并不是我在开发过程中所经历的。除非处理前端退货,否则IPN或Webhook都不会触发。这打破了“后端通知”的全部目的。
我很想被证明是错误的,但我已经测试了Omnipay/PaypalSDK与Order/Auth/Sale的排列,并且在Sandbox/Live环境中等待Webhook/IPN,而且没有任何工作。
这里是我的设置:
- PHP上Laravel,与Omnipay和Paypal SDK
- 码头工人与港口正确转发,所以HTTP和HTTPS可以LAN外部访问
- 在PayPal的REST启用网络挂接应用;在业务配置文件中启用IPN
- 测试交易(销售,订单,捕捉)在沙盒模式下,所有的工作
- 测试PayPal的IPN模拟器和模拟网络挂接,无论是在工作
- 测试订购&销售沙盒&现场模式
- 制造API调用来启动贝宝交易,收到重定向URL
- 打开网址,登录,确认付款,重定向回
return_url
与贝宝的网址查询,包括paymentId
和PayerID
- 在这个时候,
return_url
页面仅显示后面的网址查询,但不处理Paypal的返回回调。 -
没有收到IPN和网络挂接在
callback_url
小号 - IPN Hisotry页和网络挂接活动页不显示新的事件
- 在这个时候,
- 修改代码来处理PayPal的返回回调(即名为
"/v1/payments/orders/{$this->getId()}/capture"
),并刷新为return_url
页面。- 在这个时候,
return_url
页面显示捕获的状态和事务的状态,这是成功 -
难道在
callback_url
小号 - IPN Hisotry收到IPN和网络挂接 page and Webhook活动页面做显示新的事件
- 在这个时候,
所以......都是PayPal的IPN和网络挂接两个并不意味着后端的通知,以及前端的退货处理是必须的?但我见过有人声称“为了避免不可靠的return_url不被用户端触发,我们应该使用IPN”等。我是否错过了某些东西,或者做错了什么?
更新 - 包括代码
-
我的 “支付” 按钮发送POST到这个网址:
https://*PUB_IP_ADDRESS*/v2/payment/paypal/sale
(sale
或order
其相应的动作)这JSON内容:{ "order_id":"test-23-order", "amount":"0.01", "currency":"CAD", "description":"1753 total .01" }
-
在控制器/存储库中,我使用Omnipay和PaypalSDK进行了测试。
a。随着Omnipay,这样做是:
// PaymentController.php ... $result = $this->gateway ->setOrderId($request->get('order_id')) ->setAmount($request->get('amount')) ->setCurrency($request->get('currency')) ->setDescription($request->get('description')) ->initPayment(); ...
哪里
$this->gateway
是Omnipay的信用卡缴交订金。然后:// OmnipayRepository.php ... public function initPayment(){ if (is_null($this->payment_intent)){ throw ExceptionMapping(40000, "You need to set payment intent first with setIntent()"); } $payment_params = $this->getPaymentParameters(); switch ($this->payment_intent){ case self::INTENT_PREAUTH: $payment_action = $this->gateway->authorize($payment_params); break; case self::INTENT_SALE: $payment_action = $this->gateway->purchase($payment_params); break; default: throw ExceptionMapping(40000, "{$this->payment_intent} is an invalid payment intent for this action"); } $response = $payment_action->send(); return $this->handleTransactionResponse($response); } ...
其中
handleTransactionResponse($response)
获取返回的JSON并保存为模型。b。使用PayPal SDK:
// PaymentController.php ... $paypal = new PaypalRepository(); $payment = $paypal->initPayment( $request->get('amount'), $request->get('currency'), $request->get('description'), URL::to("/").config("paypal.options.returnUrl"), URL::to("/").config("paypal.options.cancelUrl"), 'order', $request->get('order_id') ); if ($payment['error']) { echo $payment['error']."ERR_PP"; } else { $approvalUrl = $payment['payment']->getApprovalLink(); echo $approvalUrl; exit; } ...
然后
// PaypalRepository.php::initPayment() ... $payment = null; $payer = new Payer(); $payer->setPaymentMethod("paypal"); $item1 = new Item(); $item1->setName($descr) ->setDescription($descr) ->setCurrency($currency) ->setQuantity(1) ->setSku($sku)// Similar to `item_number` in Classic API ->setPrice($total); $itemList = new ItemList(); $itemList->setItems(array($item1)); $details = new Details(); $details->setShipping(0); $details->setTax(0); $details->setSubtotal($total); $amount = new Amount(); $amount->setCurrency($currency); $amount->setTotal($total); $amount->setDetails($details); $transaction = new Transaction(); $transaction->setAmount($amount); $transaction->setItemList($itemList); $transaction->setDescription($descr); $transaction->setInvoiceNumber(uniqid()); $redirectUrls = new RedirectUrls(); $redirectUrls->setReturnUrl($returnUrl); $redirectUrls->setCancelUrl($cancelUrl); $payment = new Payment(); $payment->setIntent($intent); $payment->setPayer($payer); $payment->setRedirectUrls($redirectUrls); $payment->setTransactions(array($transaction)); $payment->create($this->apiContext);
-
那么支付宝将与此JSON响应:
{ "id":"PAY-4L424927Y2109544NLF2TY2A", "intent":"sale", "state":"created", "payer":{ "payment_method":"paypal" }, "transactions":[ { "amount":{ "total":"0.01", "currency":"CAD" }, "description":"1716 total .01", "related_resources":[ ] } ], "create_time":"2017-07-24T00:16:40Z", "links":[ { "href":"https:\/\/api.sandbox.paypal.com\/v1\/payments\/payment\/PAY-4L424927Y2109544NLF2TY2A", "rel":"self", "method":"GET" }, { "href":"https:\/\/www.sandbox.paypal.com\/cgi-bin\/webscr?cmd=_express-checkout&token=EC-0GN55647HU250615H", "rel":"approval_url", "method":"REDIRECT" }, { "href":"https:\/\/api.sandbox.paypal.com\/v1\/payments\/payment\/PAY-4L424927Y2109544NLF2TY2A\/execute", "rel":"execute", "method":"POST" } ] }
我然后转到这个
approval_url
,并与贝宝帐户登录完成销售或订单交易的批准。-
现在我们回到上面原始的第(3)和第(4)项,其中PayPal不会触发任何IPN或Webhook事件,除非我通过
return_url
处理数据以完成交易,在代码中这个:a。Omnipay:
// PaymentRepository.php, WIP code for callback_return ... public function callback_return(Request $request) { $paymentId = $_GET['paymentId']; $payerId = $_GET['PayerID']; // Once the transaction has been approved, we need to complete it. $transaction = $this->gateway->completePurchase(array( 'payer_id' => $payerId, 'transactionReference' => $paymentId, )); $response = $transaction->send(); if ($response->isSuccessful()) { // The customer has successfully paid. echo "PAID"; } else { echo "ERROR"; // There was an error returned by completePurchase(). You should // check the error code and message from PayPal, which may be something // like "card declined", etc. } } ...
b。贝宝SDK:
// paypal_return.php, code snippet on completing transaction ... $paypal = new paypal(); try { $payment = $paypal->executePaypalIntent(get2('paymentId'), get2('PayerID')); } catch (\Exception $e) { $payment = false; } ...
我注意到你不引用PayPal的IPN在你的PayPal按钮在所有...
尝试增加notify_url
这是我该怎么办它。
$_CONFIG['cart']['test'] = "1"; // 0 (paypal) | 1 (sandebox)
$_CONFIG['cart']['return'] = "http://thx.com";
$_CONFIG['cart']['ipn'] = "http://dev.com/ipn.php";
if (!$_CONFIG['cart']['test']){
$_CONFIG['cart']['webscr'] = "https://www.paypal.com/cgi-bin/webscr?"; // paypal
$_CONFIG['cart']['postback'] = "www.paypal.com";
$_CONFIG['cart']['paypal'] = "[email protected]";
}else{
$_CONFIG['cart']['webscr'] = "https://www.sandbox.paypal.com/cgi-bin/webscr?"; // sandebox
$_CONFIG['cart']['postback'] = "www.sandbox.paypal.com";
$_CONFIG['cart']['paypal'] = "[email protected]";
}
$grand_total = "9.99";
// Bouton Paypal
$paypalURL .= $_CONFIG['cart']['webscr'].'&';
$paypalURL .= 'item_name=ITEM NAME&';
$paypalURL .= 'cmd=_xclick&';
$paypalURL .= 'business='.urlencode($_CONFIG['cart']['paypal']).'&';
$paypalURL .= 'return='.urlencode($_CONFIG['cart']['return']).'&';
$paypalURL .= 'lc=CA&amount='.sprintf("%01.2f", $grand_total).'&';
$paypalURL .= 'currency_code=CAD&';
$paypalURL .= 'button_subtype=products&';
$paypalURL .= 'cn=Ajouter%20des%20instructions%20particuli%c3%a8res%20pour%20le%20vendeur&';
$paypalURL .= 'no_shipping=2&';
$paypalURL .= 'shipping=0&';
$paypalURL .= 'bn=PP%2dBuyNowBF%3abtn_buynowCC_LG%2egif%3aNonHosted&';
$paypalURL .= 'notify_url='.urlencode($_CONFIG['cart']['ipn']);
您可以使用该URL作为按钮或重定向。只要确保您验证了成功交易支付的金额。
您可以在IPN代码中执行的一件事是在执行时触发邮件提醒并将您的自己发送给$ _POST。至少你知道IPN何时访问该页面。只要确保将其添加到顶部以防止PHP错误停止执行。如果收到邮件后没有再处理的事务,你知道什么是错的,它不是PayPal的故障笑
IPN
<?php
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
$mail .= "_POST[$key]: $value<br>";
}
// post back to PayPal system to validate
$header .= "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Host: ".$_CONFIG['cart']['postback']."\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n";
$header .= "Connection: close\r\n\r\n";
$fp = fsockopen ('ssl://'.$_CONFIG['cart']['postback'], 443, $errno, $errstr, 30);
// Si le fsockopen a fonctionner on poursuit
if ($fp) {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (trim($res)=="VERIFIED") {
}elseif ($res=="INVALID") {
}else{
}
}
// On ferme la connexion
fclose ($fp);
}else{
echo "404";
}
$subject = "IPN-DEBUG";
$messagez = "Paypal info:<br />$mail<br /><br />$prod_mail";
$de = "[email protected]";
send_mail($subject, $messagez, $de, '[email protected]');
function send_mail($subject, $message, $de, $to){
require_once ('module/phpmailer/MailClass.php');//send_mail
$send_mail = new FreakMailer();
$send_mail->Subject = $subject;
$send_mail->Body = $message;
$send_mail->isHTML(true);
$send_mail->From = $de;
$send_mail->AddAddress($to);
if(!$send_mail->Send()){return 'false';}else{return 'true';}
$send_mail->ClearAddresses();
$send_mail->ClearAttachments();
}
?>
谢谢你的代码,并提出了!我一定会再次用'notify_url'测试代码并回报。奇怪的是,虽然,我认为我已经测试过,但可能没有正确配置它。在测试过程中,我也没有太在意这个部分,因为我认为IPN和Webhook会依靠PayPal的开发人员门户和商业简档设置中的初始设置URL。事实上,我读过一些开发者遇到他们的'notify_url'设置不会对初始设置生效......此外,_webhook_不会触发什么呢? – user2276986
原来,Omnipay和PayPal的SDK都没有'setNotifyUrl()'方法。所以我尝试了你的代码(通过修改诸如'$ _CONFIG ['cart'] ['ipn']','$ _CONFIG ['cart'] ['paypal']'等)的选项......但是,当我访问该网址时,Paypal仅显示一个错误页面,表示_“事情目前似乎没有工作,请稍后再试。”_我想我们正在使用不同的PayPal付款方式?现在我再次陷入死胡同...... – user2276986
我认为你需要回到基础。上面是一个可用的IPN shell和一个可用的paypal链接。你做错了什么。更改paypal电子邮件,设置一个临时paypal ipn(直接url到php文件)只修改邮件程序()函数来接收邮件并从那里调试你的方式。 –
考虑系统有多少依赖于这方面的工作,包括一些我维护,我只是去不得不说出你的错误。 – rtfm
我使用贝宝IPN作为后端通知服务,它在我的所有项目中都非常出色。请发布您的“付款”按钮和您的IPN代码。 –
谢谢你的评论,@ patrick-simard。我用相对代码更新了我的问题。因此,在用户确认付款后,您的IPN触发器无需任何后处理? – user2276986