@hsb1007 我想这就是我最终使用的。但我很确定贝宝端有一些设置,这是主要问题。我只记得做了很多很多的测试和等待
<?php
namespace LabIT\CMSBundle\EventListener;
use Buzz\Client\ClientInterface;
use Exception;
use LabIT\CMSBundle\Entity\Payments\DetailsInterface;
use LabIT\CMSBundle\Helper\ApiHelper;
use LabIT\CMSBundle\Helper\PaymentHelper;
use LabIT\CMSBundle\Helper\SubscriptionHelper;
use LabIT\CMSBundle\Helper\UserHelper;
use Payum\Core\Action\PaymentAwareAction;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\Notify;
use Payum\Paypal\Ipn\Api;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
class PaymentListener extends PaymentAwareAction
{
/**
* @var UserHelper
*/
protected $userHelper;
/**
* @var PaymentHelper
*/
protected $paymentHelper;
/**
* @var ApiHelper
*/
protected $apiHelper;
/**
* @var SubscriptionHelper
*/
protected $subscriptionHelper;
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @var
*/
protected $buzz;
/**
* @var
*/
protected $sandbox;
/**
* @var
*/
protected $paypalValidation;
/**
* @param UserHelper $userHelper
* @param PaymentHelper $paymentHelper
* @param ApiHelper $apiHelper
* @param SubscriptionHelper $subscriptionHelper
* @param LoggerInterface $logger
* @param ClientInterface $buzz
* @param $sandbox
* @param $paypalValidation
*/
public function __construct(
UserHelper $userHelper,
PaymentHelper $paymentHelper,
ApiHelper $apiHelper,
SubscriptionHelper $subscriptionHelper,
LoggerInterface $logger,
ClientInterface $buzz,
$sandbox,
$paypalValidation
) {
$this->userHelper = $userHelper;
$this->paymentHelper = $paymentHelper;
$this->apiHelper = $apiHelper;
$this->subscriptionHelper = $subscriptionHelper;
$this->logger = $logger;
$this->buzz = $buzz;
$this->sandbox = $sandbox;
$this->paypalValidation = $paypalValidation;
}
/**
* {@inheritDoc}
*
* This is where all the IPNs from paypal get processed, acts in some ways like a controller
*
* @param Notify $request
*/
public function execute($request)
{
$data = $_POST;
// would be better to get this dynamically. It is the payment name defined in config,
// but also forms part of the url set in the paypal notification backend
$paymentName = 'post_a_job_with_paypal'; // todo maybe get this from the url
$this->logger->notice('IPN received');
// validate with paypal so it stops notifying (do this first because needs to be done within 30 seconds)
if (true === $this->paypalValidation) {
$this->validateWithPaypal($this->getPaypalArray());
}
$notificationDetails = $this->paymentHelper->createPaymentNotification($paymentName, $data);
// todo other inspections of data? check email?
$user = $this->paymentHelper->getNotificationUser($notificationDetails, $data);
// these are only done for individual transactions //TODO STORE TRANSACTIONS IN TABLE?
if (isset($data['txn_id'])) {
$this->paymentHelper->getTransactionProcessed($data['txn_id']); // so don't process more than once //TODO ADD BACK IN AFTER ADDING TRANSACTION CLASS
$this->subscriptionHelper->determineUserMembership($user, $notificationDetails); // automatically demote if payment fails
$this->apiHelper->sendPaymentNotifications($user, $notificationDetails); // notify affiliates
$this->paymentHelper->setTransactionProcessed($data['txn_id']); //set transaction to processed //TODO ADD BACK IN AFTER ADDING TRANSACTION CLASS
}
// handle recurring payment data (recurring payment info, but not recurring payment transaction
if (isset($data['recurring_payment_id']) && !isset($data['txn_id'])) {
$this->paymentHelper->setRecurringPaymentStatus($data);
// cron job will determine user membership level because needs to check timestamp
}
}
/**
* {@inheritDoc}
*/
public function supports($request)
{
return $request instanceof Notify;
}
/**
* Send data back to paypal so paypal knows it was delivered successfully
*
* @param array $data
*
* @throws Exception
*/
protected function validateWithPaypal(array $data)
{
$this->logger->notice('I am here');
$options = array();
$options['sandbox'] = $this->sandbox;
$api = new Api($this->buzz, $options);
// Verify the IPN via PayPal
if (Api::NOTIFY_VERIFIED !== $api->notifyValidate($data)) {
$this->logger->notice('paypal validation UNSUCCESSFUL');
throw new Exception('Invalid IPN');
}
$this->logger->notice('paypal validation SUCCESSFUL');
return;
}
/**
* @return array
*/
protected function getPaypalArray()
{
// Read POST data
// reading posted data directly from $_POST causes serialization
// issues with array data in POST. Reading raw POST data from input stream instead.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
return $myPost;
}