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; });
[…] IMPORTANT UPDATE: I’ve since updated the code substantially, please read my new blog post. […]
[…] IMPORTANT UPDATE: I’ve since updated the code substantially, please read my new blog post. […]