Paypal IPN不工作,但发布数据确实如此

时间:2015-08-28 16:21:52

标签: symfony paypal paypal-ipn payum

我在这里使用PayPal IPN模拟器:https://developer.paypal.com/webapps/developer/applications/ipn_simulator

将信息发送到使用symfony2和payum bundle(旧版symfony和bundle)构建的应用程序。

它肯定是通过通知URL到达应用程序(因此不是防火墙问题),因为记录存储在数据库中,其中包含付款名称和日期。但是没有存储“细节”。

但是,如果我使用Rest Client来发布到包含数据的网址,请按照此处的建议:https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNIntro/#id08CKFJ00JYK

然后记录存储了付款名称和日期和详细信息!!

这是IPN模拟器的问题吗?我真的不确定这里发生了什么,也许我可以尝试以某种方式记录请求对象?

1 个答案:

答案 0 :(得分:0)

@ hsb1007我觉得这是我最后用的。但我很确定paypal方面有一些设置是主要问题。我只记得做了很多很多测试和等待

<?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;
}