Last active
January 25, 2023 19:44
-
-
Save dmzoneill/faaa84782eaed4d2dc28ad55c19119ee to your computer and use it in GitHub Desktop.
PHP Paypal Instant Payment Notification
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require 'site-config.php'; | |
require 'PaypalIPN.php'; | |
if (class_exists('Transaction') === false) { | |
class Transaction | |
{ | |
private $error = array(); | |
public function __construct() | |
{ | |
global $paypal_logs_dir; | |
if(isset($_POST['payment_date'])) { | |
$this->paypal_instant_payment_notification(); | |
} | |
else { | |
$this->normal_http_callback(); | |
} | |
$req_dump = print_r($_REQUEST, true); | |
$ser_dump = print_r($_SERVER, true); | |
@file_put_contents($paypal_logs_dir . '/' . date("Y-m-d h:i:s") . '.log', $req_dump . "\n" . $ser_dump); | |
} | |
private function normal_http_callback() | |
{ | |
global $contact_add_name, $transaction_confirmed_image; | |
$tx = isset($_GET['tx']) ? $_GET['tx'] : ""; | |
$tx = filter_var($tx, FILTER_SANITIZE_STRING); | |
if (is_user_logged_in() === false) { | |
header('Location: ' . get_site_url() . '/wp-login.php?action=login'); | |
return; | |
} | |
get_header(); | |
print "<div id='primary' class='content-area container'><div class='container' style='text-align:center'><span style='display: inline-block; width:60%; vertical-align: middle;'>"; | |
$this->error["1.1"] = "The transaction from paypal was malformed - missing amt"; | |
$this->error["1.2"] = "The transaction from paypal was malformed - missing cc"; | |
$this->error["1.3"] = "The transaction from paypal was malformed - missing item_name"; | |
$this->error["1.4"] = "The transaction from paypal was malformed - missing item_number"; | |
$this->error["1.5"] = "The transaction from paypal was malformed - missing st"; | |
$this->error["1.6"] = "The transaction from paypal was malformed - missing tx"; | |
$this->error["1.7"] = "The transaction from paypal was malformed - item number unknown"; | |
$this->error["1.8"] = "The transaction from paypal was malformed - paypal sent uncompleted transaction"; | |
$this->error["1.9"] = "This transaction has already been added to your account"; | |
$this->error["1.10"] = "The transaction id has invalid length"; | |
$this->error["2.1"] = "Did not receive okay for transation validation request"; | |
$this->error["2.2"] = "Unable to structure the the payal response, possibly malformed"; | |
$this->error["2.3"] = "Paypal did not return success for the transaction"; | |
$this->error["3.1"] = "Failed to save purchased transaction, not adding classes"; | |
$this->error["3.2"] = "Failed to insert bought tokens for the user"; | |
$valres = $this->validate_transaction_request(); | |
$current_user = wp_get_current_user(); | |
if ($valres[0] === false) { | |
print "<h2>Transaction Error</h2>"; | |
print "<p>There was an error with your transaction <br><b>" . $valres[1] . "</b><br><br>"; | |
print "Please quote the <b>Paypal</b> transaction id <b>" . $tx . "</b> with <b>Paypal</b> or <b>$contact_add_name</b> appropriately</p>"; | |
$nse = new Student_Emailer(); | |
$nse->transaction_failed($current_user->user_login, $current_user->user_email, $tx, $valres[1], $valres[2]); | |
} else { | |
$valres = $this->validate_transation(); | |
if ($valres[0] === false) { | |
print "<h2>Transaction Error</h2>"; | |
print "<p>There was an error with your transaction <br><b>" . $valres[1] . "</b><br><br>"; | |
print "Please quote the paypal transaction id <b>" . $tx . "</b> with paypal or $contact_add_name appropriately</p>"; | |
$nse = new Student_Emailer(); | |
$nse->transaction_failed($current_user->user_login, $current_user->user_email, $tx, $valres[1], $valres[2]); | |
} else { | |
$valres = $this->update_member($valres[1]); | |
if ($valres[0] === false) { | |
$nse = new Student_Emailer(); | |
$nse->transaction_failed($current_user->user_login, $current_user->user_email, $tx, $valres[1], $valres[2]); | |
} | |
print "<h2>Transaction Confirmed</h2>"; | |
print "<p>Thank you for completing your transaction.<br><br>"; | |
print "Your credits have been added to your account.<br><br>"; | |
print "To gift this to someone or to get a receipt, please visit your "; | |
print "<a style='text-decoration: underline' href='" . get_site_url() . "/profile/'>profile page.<br><br>"; | |
print "<a style='text-decoration: underline' href='" . get_site_url() . "/classes/'>Take me to the schedule</a></p>"; | |
$nse = new Student_Emailer(); | |
$nse->transaction_confirmed($current_user->user_login, $current_user->user_email, $tx); | |
} | |
} | |
print "</span><span style='display: inline-block; width:30%; vertical-align: middle;'><br>"; | |
print "<img style='width:100%' src='"; | |
if (file_exists(get_template_directory() . rawurldecode($transaction_confirmed_image))) { | |
print get_template_directory_uri() . $transaction_confirmed_image; | |
} else { | |
print $transaction_confirmed_image; | |
} | |
print "'></span></div></div>"; | |
get_footer(); | |
} | |
private function paypal_instant_payment_notification() | |
{ | |
$ipn = new PaypalIPN(); | |
$ipn->useSandbox(); | |
$verified = $ipn->verifyIPN(); | |
if ($verified) { | |
/* | |
* Process IPN | |
* A list of variables is available here: | |
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/ | |
*/ | |
$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]); | |
} | |
} | |
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly. | |
//header("HTTP/1.1 200 OK"); | |
} | |
public function validate_transaction_request() | |
{ | |
global $wpdb, $ashtanga_booking_tables; | |
$amt = isset($_GET['amt']) ? $_GET['amt'] : false; // 0.50 | |
$amt = filter_var($amt, FILTER_VALIDATE_FLOAT); | |
$cc = isset($_GET['cc']) ? $_GET['cc'] : false; // EUR | |
$cc = filter_var($cc, FILTER_SANITIZE_STRING); | |
$item_name = isset($_GET['item_name']) ? $_GET['item_name'] : false; //TestBuy | |
$item_name = filter_var($item_name, FILTER_SANITIZE_STRING); | |
$item_number = isset($_GET['item_number']) ? $_GET['item_number'] : false; // testbuy1 | |
$item_number = filter_var($item_number, FILTER_SANITIZE_STRING); | |
$st = isset($_GET['st']) ? $_GET['st'] : false; // Completed | |
$st = filter_var($st, FILTER_SANITIZE_STRING); | |
$tx = isset($_GET['tx']) ? $_GET['tx'] : false; // 8CY850347S384831W | |
$tx = filter_var($tx, FILTER_SANITIZE_STRING); | |
if ($amt === false) { | |
return array(false, $this->error["1.1"], "1.1"); | |
} | |
if ($cc === false) { | |
return array(false, $this->error["1.2"], "1.2"); | |
} | |
if ($item_name === false) { | |
return array(false, $this->error["1.3"], "1.3"); | |
} | |
if ($item_number === false) { | |
return array(false, $this->error["1.4"], "1.4"); | |
} | |
if ($st === false) { | |
return array(false, $this->error["1.5"], "1.5"); | |
} | |
if ($tx === false) { | |
return array(false, $this->error["1.6"], "1.6"); | |
} | |
if (strlen($tx) !== 17) { | |
return array(false, $this->error["1.10"], "1.10"); | |
} | |
$query = "SELECT * FROM " . $ashtanga_booking_tables['paypal_payment_buttons'] . " ORDER BY id ASC"; | |
$paypal_payment_buttons = $wpdb->get_results($query); | |
$pids = array(); | |
foreach ($paypal_payment_buttons as $paypal_payment_button) { | |
$pids[] = $paypal_payment_button->paypal_button_id; | |
} | |
if (!in_array($item_number, $pids)) { | |
return array(false, $this->error["1.7"], "1.7"); | |
} | |
if ($st !== "Completed") { | |
return array(false, $this->error["1.8"], "1.8"); | |
} | |
$query = "SELECT count(*) FROM " . $ashtanga_booking_tables['student_purchase_history'] . " where txn_id = %s"; | |
$prepared = $wpdb->prepare($query, $tx); | |
$stale_transaction = $wpdb->get_var($prepared); | |
if ($stale_transaction != "0") { | |
return array(false, $this->error["1.9"], "1.9"); | |
} | |
return array(true, ""); | |
} | |
public function validate_transation() | |
{ | |
global $error, $paypal_client_id, $paypal_logs_dir; | |
$tx = isset($_GET['tx']) ? $_GET['tx'] : false; // 8CY850347S384831W | |
$txid = filter_var($tx, FILTER_SANITIZE_STRING); | |
$ch = curl_init(); | |
curl_setopt($ch, CURLOPT_URL, "https://www.paypal.com/cgi-bin/webscr"); | |
curl_setopt($ch, CURLOPT_POST, 1); | |
$queryfields = http_build_query(array( | |
'cmd' => '_notify-synch', | |
'tx' => $txid, | |
'at' => $paypal_client_id, | |
) | |
); | |
curl_setopt($ch, CURLOPT_POSTFIELDS, $queryfields); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |
curl_setopt($ch, CURLOPT_HEADER, 1); | |
$response = curl_exec($ch); | |
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); | |
$headers = substr($response, 0, $header_size); | |
$body = substr($response, $header_size); | |
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
curl_close($ch); | |
@file_put_contents($paypal_logs_dir . "/$txid", $body); | |
if ($httpcode !== 200) { | |
return array(false, $this->error["2.1"], "2.1"); | |
} | |
$lines = explode("\n", $body); | |
if (is_array($lines) === false) { | |
return array(false, $this->error["2.2"], "2.2"); | |
} | |
if (trim($lines[0]) !== "SUCCESS") { | |
return array(false, $this->error["2.3"], "2.3"); | |
} | |
return array(true, $lines); | |
} | |
public function update_member($lines) | |
{ | |
global $wpdb, $ashtanga_booking_tables; | |
$current_wpuser = wp_get_current_user(); | |
$opts = array(); | |
foreach ($lines as $line) { | |
if (strpos($line, "=") !== false) { | |
$parts = explode("=", $line); | |
$opts[trim($parts[0])] = trim($parts[1]); | |
} | |
} | |
$query = "SELECT * from " . $ashtanga_booking_tables['paypal_payment_buttons'] . " order by id asc"; | |
$paypal_payment_buttons = $wpdb->get_results($query); | |
$numclass = array(); | |
$expiryclass = array(); | |
$monthly = array(); | |
$classrestriction = array(); | |
foreach ($paypal_payment_buttons as $paypal_payment_button) { | |
$numclass[$paypal_payment_button->paypal_button_id] = intval($paypal_payment_button->credits); | |
$expiryclass[$paypal_payment_button->paypal_button_id] = date('Y-m-d', strtotime($paypal_payment_button->credit_expiry)); | |
$monthly[$paypal_payment_button->paypal_button_id] = $paypal_payment_button->monthly; | |
$classrestriction[$paypal_payment_button->paypal_button_id] = $paypal_payment_button->class_type_restriction; | |
} | |
$student_user = $wpdb->get_row("SELECT * FROM " . $ashtanga_booking_tables['student'] . " WHERE wp_uid = '" . $current_wpuser->ID . "'"); | |
$vals = array( | |
"student_id" => $student_user->id, | |
"purchase_date" => date("Y-m-d"), | |
"expiry_date" => $expiryclass[$opts['item_number']], | |
"purchase_type" => $opts['item_number'], | |
"purchase_value" => $opts['mc_gross'], | |
"purchase_amount" => $numclass[$opts['item_number']], | |
"payer_id" => $opts['payer_id'], | |
"first_name" => $opts['first_name'], | |
"txn_id" => $opts['txn_id'], | |
"last_name" => $opts['last_name'], | |
"payer_email" => $opts['payer_email'], | |
"receiver_id" => $opts['receiver_id'], | |
"residence_country" => $opts['residence_country'], | |
); | |
// log transaction | |
$res = $wpdb->insert($ashtanga_booking_tables['student_purchase_history'], $vals); | |
//print $wpdb->last_query; | |
$trans_id = $wpdb->insert_id; | |
if ($trans_id !== false) { | |
if ($monthly[$opts['item_number']] != "1") { | |
for ($i = 0; $i < $numclass[$opts['item_number']]; $i++) { | |
$exp = $expiryclass[$opts['item_number']]; | |
$wpdb->insert($ashtanga_booking_tables['student_tokens'], array( | |
"student_id" => $student_user->id, | |
"wp_uid" => $current_wpuser->ID, | |
"purchase_id" => $trans_id, | |
"expiry_date" => $exp, | |
"class_type_restriction" => isset($classrestriction[$opts['item_number']]) ? $classrestriction[$opts['item_number']] : null, | |
) | |
); | |
if ($wpdb->insert_id === false) { | |
return array(false, $this->error["3.2"], "3.2"); | |
} | |
} | |
} | |
} else { | |
return array(false, $this->error["3.1"], "3.1"); | |
} | |
return array(true, "Success"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment