PayPal IPN/PDT Libraries

A long time ago, I wrote a few PHP scripts to help me work with PayPal IPN & PDT requests. I’ve been using them in my projects ever since, but they’ve been in desperate need of an update. Recently I was refactoring a client’s website, and decided to rewrite my PayPal scripts while I was at it.

The new scripts are namespaced, and much cleaner. They are available over on GitHub at brandonwamboldt/paypal-tools. These scripts don’t do much on their own, but are meant to be integrated with your own code base.

Here is a real world example of how I am using the code in my WordPress payments module (which I hope to release on GitHub as well).

$ipn = new \PayPal\IpnRequest();
$ipn->process(function($data) {
  parse_str(urldecode($data['custom']), $custom);

  // Check to see if we should handle it
  if (!isset($custom['wpipn'])) {
    return;
  }

  // Parent?
  if (isset($data['parent_txn_id'])) {
    $parent = Transaction::find_one_by('transaction_id', $data['parent_txn_id']);
  }

  // Does it already exist in our system (from PDT most likely)
  $transaction     = Transaction::find_one_by('transaction_id', $data['txn_id']);
  $new_transaction = false;

  if (!$transaction) {
    $new_transaction = true;
    $transaction     = new Transaction;
    $transaction->set_processed(0);
  }

  // Create a transaction
  $transaction->set_parent_id($parent ? $parent->primary_key() : 0);
  $transaction->set_transaction_id($data['txn_id']);
  $transaction->set_user_id($custom['user']);
  $transaction->set_transaction_gross($data['mc_gross']);
  $transaction->set_transaction_fee($data['mc_fee']);
  $transaction->set_transaction_tax($data['tax']);
  $transaction->set_currency($data['mc_currency']);
  $transaction->set_action($custom['action']);
  $transaction->set_link_to('');
  $transaction->set_previous_value($custom['prev']);
  $transaction->set_new_value($custom['next']);
  $transaction->set_effective_date(new DateTime($custom['effective']));
  $transaction->set_payment_processor('paypal_standard');
  $transaction->set_payment_processor_data($data);
  $transaction->set_other_data([]);
  $transaction->set_sandbox(isset($data['test_ipn']) ? $data['test_ipn'] : 0);
  $transaction->set_payment_date(new DateTime($data['payment_date']));
  $transaction->set_status($data['payment_status']);

  // If the transaction is a refund, void, etc, we need to reverse the
  // action being performed, so switch previous/next values
  if ($transaction->is_unsuccessful()) {
    $transaction->set_previous_value($custom['next']);
    $transaction->set_new_value($custom['prev']);
  }

  // If the transaction is incomplete, we shouldn't do anything.
  if ($transaction->is_incomplete()) {
    $transaction->set_previous_value($custom['prev']);
    $transaction->set_new_value($custom['prev']);
  }

  // Save
  $transaction->save();

  // Plugin hook
  if ($new_transaction) {
    do_action('payments:transaction:processed', $custom['action'], $transaction);
  }

  http_response_code(200);
  exit;
});

2 Replies to “PayPal IPN/PDT Libraries”

  1. […] IMPORTANT UPDATE: I’ve since updated the code substantially, please read my new blog post. […]

  2. […] IMPORTANT UPDATE: I’ve since updated the code substantially, please read my new blog post. […]

Leave a Reply