• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

PayPal IPN - short (original script by stian) v.1, v.2, v.3

Archez

'
Senator
Joined
Jun 26, 2008
Messages
6,589
Solutions
1
Reaction score
70
Location
Mexico
I just made a shortened (clean) version of stian's paypal IPN, even though paypal is suffering downtimes, this will be handy for you.

# the script won't log payments
# the script will reject scammers

I didn't test it, so... have fun.

v.3 (latest)
PHP:
<?php
	
	## ## ## ## ## ## ## ##
	## PayPal IPN script ##
	##     by archez     ##
	## ## ## ## ## ## ## ##
	##  fixes at otland  ##
	## ## ## ## ## ## ## ##
	## first  script  by ##
	## stian,  at otland ##
	## http://otland.net ##
	## ## ## ## ## ## ## ##
	
	if(gethostbyaddr($_SERVER['REMOTE_ADDR']) != 'notify.paypal.com')
	{ 
		exit();
	}
	
	if($_REQUEST['debug'])
	{
		ini_set('display_errors', true);
		error_reporting(E_ALL);
	}
	
	// MySQLi connection
	$mysql = new mysqli('localhost', 'root', 'password', 'database');
	
	// Variables, don't touch!
	$receiverEmail = $_REQUEST['receiver_email'];
	$paymentStatus = $_REQUEST['payment_status'];
	$mcGross = $_REQUEST['mc_gross'];
	$mcCurrency = $_REQUEST['mc_currency'];
	$customValue = stripslashes(ucwords(strtolower(trim($_REQUEST['custom']))));  
	
	// Prices
	$prices = array('10.00' => 20, '20.00' => 40, '30.00' => 60, '40.00' => 80);
	
	// Setup
	$receiver = '[email protected]';
	$currency = 'EUR';
	$whatToDo = 1; // 1 - delete, 2 - custom
	
	if($paymentStatus == 'Completed' && $receiverEmail == $receiver && isset($prices[$mcGross]) && $mcCurrency == $currency)
	{
		$mysql->query('UPDATE `accounts` SET `premium_points` = `premium_points` + ' . $prices[$mc_gross] . ' WHERE `name` = "' . $customValue . '"');
	}
	elseif($paymentStatus == 'Reversed' && $receiverEmail == $receiver)
	{
		if($whatToDo == 1)
		{
			$mysql->query('DELETE FROM `accounts` WHERE `name` = "' . $customValue . '"');
		}
		elseif($whatToDo == 2)
		{
			// if not deleting, what to do?
		}
	}
	else
	{
		exit();
	}
	
?>

v.2 better than v.1
PHP:
<?php
	
	## ## ## ## ## ## ## ##
	## PayPal IPN script ##
	##     by archez     ##
	## ## ## ## ## ## ## ##
	## first  script  by ##
	## stian,  at otland ##
	## http://otland.net ##
	## ## ## ## ## ## ## ##
	
	if($_REQUEST['debug'])
	{
		ini_set('display_errors', true);
		error_reporting(E_ALL);
	}
	
	// MySQL connection
	$mysql = array('host' => 'localhost', 'user' => 'root', 'password' => '#', 'database' => '#');
	$connect = mysql_connect($mysql['host'], $mysql['user'], $mysql['password']);
	$database = mysql_select_db($mysql['database'], $connect);
	
	// Variables, don't touch!
	$receiverEmail = $_REQUEST['receiver_email'];
	$paymentStatus = $_REQUEST['payment_status'];
	$mcGross = $_REQUEST['mc_gross'];
	$mcCurrency = $_REQUEST['mc_currency'];
	$customValue = stripslashes(ucwords(strtolower(trim($_REQUEST['custom']))));  
	
	// Prices
	$prices = array('10.00' => 20, '20.00' => 40, '30.00' => 60, '40.00' => 80);
	
	// Setup
	$receiver = '[email protected]';
	$currency = 'EUR';
	$whatToDo = 1; // 1 - delete, 2 - custom
	
	// Unwanted people IP addresses
	$unwanted = array('66.211.170.66', '216.113.188.202', '216.113.188.203', '216.113.188.204', '216.113.188.205', '66.135.197.163', '66.135.197.164', ' 66.135.197.162',  '66.135.197.141', '216.113.191.33');
	
	if(!in_array($_SERVER['REMOTE_ADDR'], $unwanted))
	{
		die('Error #1, contact the administration.'); // You'll know what to do in case you get this report
	}
	
	if($paymentStatus == 'Completed' && $receiverEmail == $receiver && isset($prices[$mcGross]) && $mcCurrency == $currency)
	{
		mysql_query('UPDATE `accounts` SET `premium_points` = `premium_points` + ' . $prices[$mc_gross] . ' WHERE `name` = "' . $customValue . '"');
	}
	elseif($playmentStatus == 'Reversed' && $receiverEmail == $receiver)
	{
		if($whatToDo == 1)
		{
			mysql_query('DELETE FROM `accounts` WHERE `name` = "' . $customValue . '"');
		}
		elseif($whatToDo == 2)
		{
			// if not deleting, what to do?
		}
	}
	else
	{
		die('Error #2, contact the administration.'); // You'll know what to do in case you get this report
	}
	
?>

v.1 vulnerable
PHP:
<?php
	
	## ## ## ## ## ## ## ##
	## PayPal IPN script ##
	##     by archez     ##
	## ## ## ## ## ## ## ##
	## first  script  by ##
	## stian,  at otland ##
	## http://otland.net ##
	## ## ## ## ## ## ## ##
	
	if($_REQUEST['debug'])
	{
		ini_set('display_errors', true);
		error_reporting(E_ALL);
	}
	
	// MySQL connection
	$mysql = array('host' => 'localhost', 'user' => 'root', 'password' => '#', 'database' => '#');
	$connect = mysql_connect($mysql['host'], $mysql['user'], $mysql['password']);
	$database = mysql_select_db($mysql['database'], $connect);
	
	// Variables, don't touch!
	$receiverEmail = $_REQUEST['receiver_email'];
	$paymentStatus = $_REQUEST['payment_status'];
	$mcGross = $_REQUEST['mc_gross'];
	$mcCurrency = $_REQUEST['mc_currency'];
	$customValue = stripslashes(ucwords(strtolower(trim($_REQUEST['custom']))));  
	
	// Prices
	$prices = array('10.00' => 20, '20.00' => 40, '30.00' => 60, '40.00' => 80);
	
	// Setup
	$receiver = '[email protected]';
	$currency = 'EUR';
	
	// Unwanted people IP addresses
	$unwanted = array('66.211.170.66', '216.113.188.202', '216.113.188.203', '216.113.188.204', '216.113.188.205', '66.135.197.163', '66.135.197.164', ' 66.135.197.162',  '66.135.197.141', '216.113.191.33');
	
	if(!in_array($_SERVER['REMOTE_ADDR'], $unwanted))
	{
		die('Error #1, contact the administration.'); // You'll know what to do in case you get this report
	}
	
	if($paymentStatus == 'Completed' && $receiverEmail == $receiver && isset($prices[$mcGross]) && $mcCurrency == $currency)
	{
		$query = mysql_query('UPDATE `accounts` SET `premium_points` = `premium_points` + ' . $prices[$mc_gross] . ' WHERE `name` = "' . $customValue . '"');
		$result = mysql_result($query);
	}
	else
	{
		die('Error #2, contact the administration.'); // You'll know what to do in case you get this report
	}
	
?>

Report bugs. x_x
 
Last edited:
A good hack:

before "else" add:
PHP:
else if($playmentStatus == 'Reversed' && $receiverEmail == $receiver) {
mysql_query("DELETE FROM `accounts` WHERE `name` = {$customValue}")
}

Delete all accounts that does a chargeback.

(Btw, no need for mysql_result in your code)
 
/\

I've been thinking a lot about using the variable to run a mysql query, and I don't like it, but I just see how you people use it, so I thought it was the correct way, but I usually just run the code.. (ie mysql_query('SELE...');)

About the deletion, what about adding an option at the beginning to choose if you want to delete the account or simply black list the account. :eek:

Sounds interesting for me. c;

NEW VERSION...

PHP:
<?php
	
	## ## ## ## ## ## ## ##
	## PayPal IPN script ##
	##     by archez     ##
	## ## ## ## ## ## ## ##
	## first  script  by ##
	## stian,  at otland ##
	## http://otland.net ##
	## ## ## ## ## ## ## ##
	
	if($_REQUEST['debug'])
	{
		ini_set('display_errors', true);
		error_reporting(E_ALL);
	}
	
	// MySQL connection
	$mysql = array('host' => 'localhost', 'user' => 'root', 'password' => '#', 'database' => '#');
	$connect = mysql_connect($mysql['host'], $mysql['user'], $mysql['password']);
	$database = mysql_select_db($mysql['database'], $connect);
	
	// Variables, don't touch!
	$receiverEmail = $_REQUEST['receiver_email'];
	$paymentStatus = $_REQUEST['payment_status'];
	$mcGross = $_REQUEST['mc_gross'];
	$mcCurrency = $_REQUEST['mc_currency'];
	$customValue = stripslashes(ucwords(strtolower(trim($_REQUEST['custom']))));  
	
	// Prices
	$prices = array('10.00' => 20, '20.00' => 40, '30.00' => 60, '40.00' => 80);
	
	// Setup
	$receiver = '[email protected]';
	$currency = 'EUR';
	$whatToDo = 1; // 1 - delete, 2 - custom
	
	// Unwanted people IP addresses
	$unwanted = array('66.211.170.66', '216.113.188.202', '216.113.188.203', '216.113.188.204', '216.113.188.205', '66.135.197.163', '66.135.197.164', ' 66.135.197.162',  '66.135.197.141', '216.113.191.33');
	
	if(!in_array($_SERVER['REMOTE_ADDR'], $unwanted))
	{
		die('Error #1, contact the administration.'); // You'll know what to do in case you get this report
	}
	
	if($paymentStatus == 'Completed' && $receiverEmail == $receiver && isset($prices[$mcGross]) && $mcCurrency == $currency)
	{
		mysql_query('UPDATE `accounts` SET `premium_points` = `premium_points` + ' . $prices[$mc_gross] . ' WHERE `name` = "' . $customValue . '"');
	}
	elseif($playmentStatus == 'Reversed' && $receiverEmail == $receiver)
	{
		if($whatToDo == 1)
		{
			mysql_query('DELETE FROM `accounts` WHERE `name` = "' . $customValue . '"');
		}
		elseif($whatToDo == 2)
		{
			// if not deleting, what to do?
		}
	}
	else
	{
		die('Error #2, contact the administration.'); // You'll know what to do in case you get this report
	}
	
?>
 
I havent tested it, but this is how I'd do it if I were to use it.
- Used mysqli instead.
- Used switch instead of if/elseif
- Arrays go in row underneath eachother? ;D
- No need to use { and } when all you are doing is resulting a die() commando.

PHP:
<?php
    
	# # # # # # # # #
	# #  U MAD ?  # #
	# # # # # # # # #
	

    if($_REQUEST['debug']) {
        ini_set('display_errors', true);
        error_reporting(E_ALL);
    }
    
    // MySQL connection
    $mysql			= new mysqli('localhost', 'dbusername', 'dbpassword', 'database');
    
    // Variables, don't touch!
    $receiverEmail 	= $_REQUEST['receiver_email'];
    $paymentStatus 	= $_REQUEST['payment_status'];
    $mcGross 		= $_REQUEST['mc_gross'];
    $mcCurrency 	= $_REQUEST['mc_currency'];
    $customValue 	= stripslashes(ucwords(strtolower(trim($_REQUEST['custom']))));  
    
    // Prices
    $prices = array(
		'10.00' => 20,
		'20.00' => 40,
		'30.00' => 60,
		'40.00' => 80
	);
    
    // Setup
    $receiver 		= '[email protected]';
    $currency 		= 'EUR';
    $whatToDo 		= 1; // 1 - delete, 2 - custom
    
    // Unwanted people IP addresses
    $unwanted = array(
		'66.211.170.66',
		'216.113.188.202', 
		'216.113.188.203', 
		'216.113.188.204', 
		'216.113.188.205', 
		'66.135.197.163', 
		'66.135.197.164', 
		'66.135.197.162',  
		'66.135.197.141', 
		'216.113.191.33'
	);
    
    if(!in_array($_SERVER['REMOTE_ADDR'], $unwanted))
        die('Error #1, contact the administration.'); // You'll know what to do in case you get this report
    
    if($paymentStatus == 'Completed' && $receiverEmail == $receiver && isset($prices[$mcGross]) && $mcCurrency == $currency)
        $update	= $mysql->query('UPDATE `accounts` SET `premium_points` = `premium_points` + ' . $prices[$mc_gross] . ' WHERE `name` = "' . $customValue . '"');

    elseif($playmentStatus == 'Reversed' && $receiverEmail == $receiver) {
		switch($whatToDo) {
			case 1:
				$delete	= $mysql->query('DELETE FROM `accounts` WHERE `name` = "' . $customValue . '"');
				break;
			default:
				// If not deleting, what to do bro? U mad?
				break;
		}
    } else
        die('Error #2, contact the administration.'); // You'll know what to do in case you get this report    
?>
 
Last edited:
PHP:
    elseif($paymentStatus == 'Reversed' && $receiverEmail == $receiver && $whatToDo == 1)
    {
            mysql_query('DELETE FROM `accounts` WHERE `name` = "' . $customValue . '"');
    }
@Boyka:
The IPn is called for every status change. Everything from Pending, Denied, Reserved, Reversed and Completed.

EDIT: Typo
 
Last edited:
Stian, you can't say it's a hack cuz it already checks if payment is "Completed". The thing you did is just that if payment is reversed it'll delete players account, but even if you didn't made that check, it'd still not any points to account unless the payment is "Completed"
That's what I meant.
 
Last edited:
@Boyka:

IPN is called when status == completed and give points, but the IPN is also called when the player does a chargeback, but this time with another status...
 
awesome..

@#edit

But still... the .ipn thats with Boyka's donation system is much much much much better :p ~no offence ofc~ :D
 
Last edited:
Your scripts are flawed and vulnerable.

1. You must ONLY allow PayPal to access that script! It can be done like this:
PHP:
if (gethostbyaddr($_SERVER['REMOTE_ADDR']) != 'notify.paypal.com') {
	exit();
}
2. You are currently only allowing unwanted people to access the script! !in_array($_SERVER['REMOTE_ADDR'], $unwanted), you are calling "die" if the remote_addr is not in the array $unwanted.
3. $mc_gross is not defined.
4. $customValue is not being escaped!
5. You are not handling the magic_gpc_quotes function in PHP properly.
6. You are allowing anyone to enable the debug mode.
7. You are not handling MySQL connection or query errors properly (do not rely on that the error output is safe, some libraries tend to spit out the password on SQL connection failure).

There are other things to look at too, but these are the most important points that must be addressed immediately!
 
Here's my (only ipn.php)
PHP:
<?PHP
## SCRIPTED BY ZONET=BOYKA
require('../config.php');
$paypal['email'] = "[email protected]";
$account_name = stripslashes(ucwords(strtolower(trim($_REQUEST['custom']))));
$myEmail = $_REQUEST['receiver_email'];
$status = $_REQUEST['payment_status'];
$points = $_REQUEST['item_name'];
$mysqli = new mysqli($config['database']['host'], $config['database']['login'], $config['database']['password'], $config['database']['database']) or die('Cant connect');

if(gethostbyaddr($_SERVER['REMOTE_ADDR']) != 'notify.paypal.com') {
    exit('...');
}
if($status == "Completed" && $myEmail == $paypal['email']) {
	$mysqli->query('UPDATE `accounts` SET `premium_points` = `premium_points`+'.$points.' WHERE `name` = "'.$mysqli->real_escape_string($account_name).'";');
	$f = fopen("paypal.txt", "a");
	$log = "Status: ".$status.", Points: ".$points.", Account: ".$account_name."\n";
	fwrite($f, $log);
	fclose($f);
}
else
	echo 'Error.';
?>
I added the gethostbyaddr when I saw Talaturens post, but it worked well before too.
 
I don't need this script since i have one of my own.. but i think that logging transactions is a good feature.. think you should re-add it :p
 
Here's my (only ipn.php)
PHP:
<?PHP
## SCRIPTED BY ZONET=BOYKA
require('../config.php');
$paypal['email'] = "[email protected]";
$account_name = stripslashes(ucwords(strtolower(trim($_REQUEST['custom']))));
$myEmail = $_REQUEST['receiver_email'];
$status = $_REQUEST['payment_status'];
$points = $_REQUEST['item_name'];
$mysqli = new mysqli($config['database']['host'], $config['database']['login'], $config['database']['password'], $config['database']['database']) or die('Cant connect');

if(gethostbyaddr($_SERVER['REMOTE_ADDR']) != 'notify.paypal.com') {
    exit('...');
}
if($status == "Completed" && $myEmail == $paypal['email']) {
	$mysqli->query('UPDATE `accounts` SET `premium_points` = `premium_points`+'.$points.' WHERE `name` = "'.$mysqli->real_escape_string($account_name).'";');
	$f = fopen("paypal.txt", "a");
	$log = "Status: ".$status.", Points: ".$points.", Account: ".$account_name."\n";
	fwrite($f, $log);
	fclose($f);
}
else
	echo 'Error.';
?>
I added the gethostbyaddr when I saw Talaturens post, but it worked well before too.

Except for that anyone could access the script and add as many premium points as they wanted.
 
Back
Top