execute("INSERT INTO `znote_paypal` VALUES ('0', '0', ?, '0', '0', '0')", ["Connection from IP: $connectedIp"]); $status = VerifyPaypalIPN(); if ($status) { // Check that the payment_status is Completed if ($payment_status == 'Completed') { // Check that txn_id has not been previously processed $txn_id_check = db()->fetchOne("SELECT `txn_id` FROM `znote_paypal` WHERE `txn_id` = ?", [$txn_id]); if ($txn_id_check === false) { // Check that receiver_email is your Primary PayPal email if ($receiver_email == $paypal['email']) { $status = true; $paidMoney = 0; $paidPoints = 0; $payment = array( 'provider' => 'paypal', 'reference' => (string)$txn_id, 'custom' => $custom_raw, 'account_id' => $custom, 'price' => $payment_amount, 'currency' => $payment_currency, 'points' => 0, 'status' => 'Completed', 'raw' => $_POST, 'resolved' => false, ); if (function_exists('znote_hook_filter')) { $payment = znote_hook_filter('payment.resolve', $payment, array('provider' => 'paypal', 'raw' => $_POST)); } if (!empty($payment['resolved'])) { $custom = (int)($payment['account_id'] ?? 0); $paidMoney = $payment['price'] ?? 0; $paidPoints = (int)($payment['points'] ?? 0); } else { foreach ($prices as $priceValue => $pointsValue) { if ($priceValue == $payment_amount) { $paidMoney = $priceValue; $paidPoints = $pointsValue; } } } if ($paidMoney == 0 || number_format((float)$paidMoney, 2, '.', '') !== number_format((float)$payment_amount, 2, '.', '')) $status = false; // Wrong ammount of money if ($payment_currency != ($payment['currency'] ?? $paypal['currency'])) $status = false; // Wrong currency if ($custom <= 0) $status = false; // Verify that the user havent messed around with POST data if ($status) { // Re-check for a duplicate and credit inside one locked transaction, // so two concurrent IPN deliveries for the same txn_id cannot both credit points. $creditResult = db()->transaction(function ($db) use ($txn_id, $payer_email, $custom, $paidMoney, $paidPoints) { $dup = $db->fetchOne("SELECT `txn_id` FROM `znote_paypal` WHERE `txn_id` = ? LIMIT 1 FOR UPDATE;", [$txn_id]); if ($dup !== false) { return 'duplicate'; } $db->execute("INSERT INTO `znote_paypal` VALUES ('0', ?, ?, ?, ?, ?)", [$txn_id, $payer_email, $custom, $paidMoney, $paidPoints]); $data = $db->fetchOne("SELECT `points` AS `old_points` FROM `znote_accounts` WHERE `account_id` = ? LIMIT 1 FOR UPDATE;", [$custom]); if (!is_array($data)) { return 'no_account'; } $new_points = (int)$data['old_points'] + $paidPoints; $db->execute("UPDATE `znote_accounts` SET `points` = ? WHERE `account_id` = ?", [$new_points, $custom]); return 'credited'; }); if ($creditResult === 'credited') { if (function_exists('znote_hook')) { znote_hook('payment.completed', array_merge($payment, array( 'provider' => 'paypal', 'reference' => (string)$txn_id, 'custom' => $custom_raw, 'account_id' => $custom, 'price' => $paidMoney, 'currency' => $payment_currency, 'points' => $paidPoints, 'status' => 'Completed', ))); } } elseif ($creditResult === 'no_account') { db()->execute("INSERT INTO `znote_paypal` VALUES ('0', ?, ?, '0', '0', '0')", [$txn_id, "ERROR: No znote_accounts row for account_id $custom"]); } } } else { $pmail = $paypal['email']; db()->execute("INSERT INTO `znote_paypal` VALUES ('0', ?, ?, '0', '0', '0')", [$txn_id, "ERROR: Wrong mail. Received: $receiver_email, configured: $pmail"]); } } } } else { // Something is wrong db()->execute("INSERT INTO `znote_paypal` VALUES ('0', ?, ?, '0', '0', '0')", [$txn_id, "ERROR: Invalid data. $postdata"]); } ?>