Note: This script is using the older mysql / mssql PHP functions. I highly recommend using PDO, and that you use this code only as a reference for getting your PayPal IPN setup.
Important!
This script assumes that you sent the users account name through PayPal IPN's 'custom' field when they made the payment. You have to edit your PayPal provided button code to add an input field with the name custom and value account name. This can be hidden if you have the information already by having the user logged into your website, or you can have the user enter their account name by having the field not hidden.
for example:
Code:
<input value='accountname' name='custom' type='hidden'>
- PayPal account that can make payment buttons
- Web server with mssql and mysql php extensions enabled
- MySQL database, for logging payments
- Patience
Setup Setup on your sever side
- Open paypalipnconfig.php and fill out for your server information and what packages you will offer
- Open paypalDB.sql and copy it into your MySQL Database and run it, this creates a table called 'paypal_logs' which will store paypal payments and coins sent out.
- Done on your server's end...
PayPal Setup
- Create a button
- make sure to set a fixed donation amount
- click "Step 3: Customize advanced features
- click add advanced variables and add the following line to the text area with your path to the script
Code:
notify_url="http://www.mydomain.com/folder/paypalipn.php"
Error Logging
If there is an error with a payment, either an invalid IPN, or email, or user name, anything... it will be output to a file _paypal_error_log.txt in the same directory that holds the script. All error messages are timestamped so you can review errors and see what's going on with them.
Make sure to test the system before making it live on your server!
Enjoy!
The Code
paypalipnconfig.php
Code:
<?php // PaypalIPNConfig.php // --- MYSQL CONFIG --- define('MYSQL_HOST', '127.0.0.1'); // Mysql host address define('MYSQL_USER', 'user'); // User name define('MYSQL_PASS', 'password'); // User password define('MYSQL_DB', 'paypal'); // Database name // --- MSSQL CONFIG --- define('MSSQL_HOST', '127.0.0.1'); // Mssql host address define('MSSQL_USER', 'user'); // User name define('MSSQL_PASS', 'password'); // User password // --- PAYPAL CONFIG --- define('PAYPAL_EMAIL', ''); // Your paypal email on which you recieve payments define('CURRENCY', 'USD'); // The type of currency you set up in paypel $paypal_packages = array( // $ Price , Coin amount -- delimit arrays with a comma to add more array(5.99, 1000), array(9.99, 2000), array(20.00, 5000) ); ?>
paypalipn.php
Code:
<?php include 'logger.php'; include 'paypalipnconfig.php'; include 'mysql.class.php'; include 'mssql.class.php'; $req = 'cmd=' . urlencode('_notify-validate'); foreach ($_POST as $key => $value) { $value = urlencode(stripslashes($value)); $req .= "&$key=$value"; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://www.paypal.com/cgi-bin/webscr'); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: www.paypal.com')); $res = curl_exec($ch); curl_close($ch); // assign posted variables to local variables $item_name = $_POST['item_name']; $item_number = $_POST['item_number']; $payment_status = $_POST['payment_status']; $payment_amount = $_POST['mc_gross']; $payment_currency = $_POST['mc_currency']; $txn_id = $_POST['txn_id']; $receiver_email = $_POST['receiver_email']; $payer_email = $_POST['payer_email']; $account = $_POST['custom']; if($account == 0) $acount = 'NO ACCOUNT'; $buff = sprintf("%s %s \$%0.2f %s %s %s", $txn_id, $payment_status, $payment_amount, $receiver_email, $payer_email, $account); $coins_sent = 0; if (strcmp ($res, "VERIFIED") == 0) { // create our db connections $db_mysql = new mysql(); $db_mysql->connect(); $db_mssql = new mssql(); $db_mssql->connect(); // check the payment_status is Completed if($payment_status == 'Completed') { // check that txn_id has not been previously processed $r = $db_mysql->query("SELECT txn_id FROM paypal_logs WHERE txn_id='".$txn_id."';"); if(mysql_num_rows($r) == 0) { // check that receiver_email is your Primary PayPal email if($receiver_email == PAYPAL_EMAIL) { // check that payment_amount/payment_currency are correct $validpackage = false; for($i = 0; $i < count($paypal_packages); ++$i) { if($paypal_packages[$i][0] == $payment_amount && $payment_currency == CURRENCY) { $validpackage = true; break; } } // process payment if valid package if($validpackage) { dbg_log('account = '.$account); $r = $db_mssql->query("SELECT user_no FROM dbo.USER_PROFILE WHERE user_id='".$account."';"); if(mssql_num_rows($r)) { $user_no = mssql_fetch_array($r); mssql_select_db('cash'); $r = $db_mssql->query("UPDATE dbo.user_cash SET amount = amount + ".$paypal_packages[$i][1]." WHERE user_no='".$user_no[0]."';"); // Added coins succesfully! if($r) $coins_sent = 1; else dbg_log('ERROR SENDING COINS: '.$buff); } else dbg_log('ACCOUNT NOT FOUND: '.$buff); // Add record to MySQL $db_mysql->query("INSERT INTO paypal_logs VALUES ('".$txn_id."',".$payment_amount.",'".$payer_email."','".$account."',".$paypal_packages[$i][1].",".$coins_sent.",CURRENT_TIMESTAMP);"); } else dbg_log('INVALID PACKAGE: '.$buff); } else dbg_log('INVALID EMAIL: '.$buff); } else dbg_log('DUPLICATE IPN: '.$buff); } } else if (strcmp ($res, "INVALID") == 0) { // log for manual investigation dbg_log('INVALID IPN: '.$buff); } ?>
mysql.class.php
Code:
<?php // If configuration not loaded, quit if(!defined('MYSQL_HOST')) die; ///////////////////////////////////////////// // CLASS: mysql // // DESCRIPTION: a class used to connect to // and communicate with a mysql database ///////////////////////////////////////////// class mysql { private $queryCount = 0; // count of processed queries private $conn; // connection private $database; // database name private $is_connected = false; // Connection made to DB? private $query = ''; // query string private $q_start = 0; // query start time private $q_finish = 0; // query finish time private $q_time = 0; // query time ////////////////////////////////////////////////// // connect() : establishes a connection to // mysql server // // PARAMS \\ // in > $host : address of database // in > $user : user name // in > $pass : user password // in > $db : database name // in > $stop : should the script stop if // connect failes? // // return : true if successful connection made // false if connection failed ////////////////////////////////////////////////// public function connect($host='',$user='',$pass='',$db='',$stop=1) { // If no parameters passed in use defaults if(!$host) { $host=MYSQL_HOST; $user=MYSQL_USER; $pass=MYSQL_PASS; $db=MYSQL_DB; } $this->database = $db; if($stop) // if stop on fail { $this->conn = mysql_connect($host, $user, $pass); if($this->conn) { if(!mysql_select_db($db, $this->conn)) { //global $err_string; //$err_string = 'ERROR : Can not select database \'$db\''; //include GLOBAL_DIR.'err.htm'; // Display error page die; // return false } } $this->is_connected = true; $this->query("SET NAMES 'utf8'"); return true; } else { $this->conn = @mysql_connect($host, $user, $pass); if($this->conn) { if(!mysql_select_db($db, $this->conn)) return false; $this->is_connected = true; $this->query("SET NAMES 'utf8'"); return true; } else return false; } } ////////////////////////////////////////////////// // query() : query the connected mysql database // // PARAMS \\ // in > $query : string to send as query // in > $err : should we break on error? // // return : query result if success // false if query failed ////////////////////////////////////////////////// public function query($query, $err=1) { if(!$this->isConnected()) $this->connect(); //$this->startQuery($query); $r = mysql_query($query, $this->conn); //$this->finishQuery(); if(!$r) { if($err) { die($this->error($query, mysql_error())); } else { echo $this->error(mysql_error()); return false; } } $this->queryCount++; return $r; } ////////////////////////////////////////////////// // queryr() : query the connected mysql database // // PARAMS \\ // in > $query : string to send as query // in > $err : should we break on error? // // return : query result if success // false if query failed, or numrows = 0 ////////////////////////////////////////////////// public function queryr($query, $err=1) { if(!$this->isConnected()) $this->connect(); $this->startQuery($query); $r = mysql_query($query, $this->conn); $this->finishQuery(); if(!$r) { if($err) { die($this->error($query, mysql_error())); } else { echo $this->error(mysql_error()); return false; } } $this->queryCount++; return (mysql_num_rows($r)==0) ? false : $r; } ////////////////////////////////////////////////// // queryz() : query the connected mysql database // // PARAMS \\ // in > $query : string to send as query // in > $err : should we break on error? // // return : query result if success // false if query failed or no affected ////////////////////////////////////////////////// public function queryz($query, $err=1) { if(!$this->isConnected()) $this->connect(); $this->startQuery($query); $r = mysql_query($query, $this->conn); $this->finishQuery(); if(!$r) { if($err) { die($this->error($query, mysql_error())); } else { echo $this->error(mysql_error()); return false; } } $this->queryCount++; $r=mysql_affected_rows($r); return ($r==0) ? false : $r; } ////////////////////////////////////////////////// // GENERAL USE MYSQL FUNCTIONS ////////////////////////////////////////////////// public function esc($r) { if(!$this->isConnected()) $this->connect(); return mysql_real_escape_string($r, $this->conn); } public function result($r) { return mysql_result($r,0); } public function num_rows($r) { return mysql_num_rows($r); } public function fetch_row($r) { return mysql_fetch_row($r); } public function fetch_object($r) { return mysql_fetch_object($r); } public function fetch_assoc($r) { return mysql_fetch_assoc($r); } public function insert_id() { return mysql_insert_id($this->conn); } private function error($err) { //global $auth; //if($auth->lvl >= UL_ADMIN) return "<p style='color:#ce0000'><em>MySQL Error</em></p>".$error.mysql_errno($this->conn).' '.mysql_error($this->conn); //return "<p style='color:#ce0000'><em>MySQL Error</em></p>Please report error to administrator."; } private function startQuery($query) { $this->query = $query; $this->q_start = getMicroTime(); $this->q_time = 0; } private function finishQuery() { if(!$this->query) return; $this->q_finish = getMicrotime(); $elapsed_time = $this->q_finish - $this->q_start; $this->q_time += $elapsed_time; if($log_slow_queries && $slow_query_time > 0) { $buff = ''; if(!file_exists(MYSQL_SLOW_QUERY_LOG)) $buff = '<?php exit();?>'."\n"; $buff .= sprintf("%s %s \n %0.6f sec\n\n", date("Y-m-h H:i"), $this->query, $elapsed_time); if($file = fopen(MYSQL_SLOW_QUERY_LOG, 'a')) { fwrite($file, $buff); fclose($file); } } else $this->query=null; } public function isConnected() { return $this->is_connected?true:false; } public function close() { if(!$this->isConnected()) return; mysql_close($this->conn); } }; ?>
mssql.class.php
Code:
<?php // If configuration not loaded, quit if(!defined('MSSQL_HOST')) die; // If server does not have the mssql extension enabled, quit if(!extension_loaded('mssql')) die; ///////////////////////////////////////////// // CLASS: mssql // // DESCRIPTION: a class used to connect to // and communicate with a mssql database // with the mssql extension ///////////////////////////////////////////// class mssql { private $conn; private $db; private $is_connected = false; // connect() : connect to mssql server public function connect($host='', $user='', $pass='') { if(!$host) { $host = MSSQL_HOST; $user = MSSQL_USER; $pass = MSSQL_PASS; } $this->conn = mssql_connect($host, $user, $pass); //if(!$conn) // return error('ERROR : Cannot connect to MSSQL Server at '.$host); $this->db = mssql_select_db('account', $this->conn); //if(!$this->db) // return error('ERROR : Cannot connect to MSSQL Database at '.$host); $this->is_connected = true; return true; } // query() : send a query to mssql server public function query($query) { if(!$this->isConnected()) connect(); $r = mssql_query($query); //if(!$r) // error($query.' : '.mssql_get_last_message()); return $r; } // use() : change the database context public function useDB($dbname) { if(!$this->isConnected()) connect(); $this->db = mssql_select_db($dbname, $this->conn); //if(!$this->db) // error('ERROR : Cannot connect to MSSQL Database at '.$host); } // error() : prints an error message and quits public function error($err) { return "<p style='color:#ce0000'><em>$err</em></p>"; } // isConnected() : returns true is connected to mssql, false if not public function isConnected() { return $this->is_connected; } public function get_last_message(){ return mssql_get_last_message(); } public function numrows($r){ return mssql_num_rows($r); } public function numfields($r){ return mssql_num_fields($r); } public function fetch_row($r){ return mssql_fetch_row($r); } public function fetch_array($r){ return mssql_fetch_array($r); } public function rows_affected($r){ return mssql_rows_affected($r); } }; ?>
logger.php
Code:
<?php // debuglogger.php // used to log time stamped strings to a file function dbg_log($msg, $logfile='_paypal_error_log.txt') { $buff = ''; if(!file_exists($logfile)) $buff = '<?php die; ?>'."\n"; $buff .= sprintf("%s %s\n\n", date("Y-m-h H:i"), $msg); $f = fopen($logfile, 'a'); fwrite($f, $buff); fclose($f); } ?>
Edit:Added new file below.
paypalipn.php -> this one stores your paypal logs in mssql. Just make a table with the same layout as the mysql example above in your mssql "cash" db.
Code:
<?php include 'logger.php'; include 'paypalipnconfig.php'; include 'mssql.class.php'; $req = 'cmd=' . urlencode('_notify-validate'); foreach ($_POST as $key => $value) { $value = urlencode(stripslashes($value)); $req .= "&$key=$value"; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://www.paypal.com/cgi-bin/webscr'); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: www.paypal.com')); $res = curl_exec($ch); if(curl_errno($ch)) dbg_log('cURL ERROR: '.curl_error($ch)); curl_close($ch); // assign posted variables to local variables $item_name = $_POST['item_name']; $item_number = $_POST['item_number']; $payment_status = $_POST['payment_status']; $payment_amount = $_POST['mc_gross']; $payment_currency = $_POST['mc_currency']; $txn_id = $_POST['txn_id']; $receiver_email = $_POST['receiver_email']; $payer_email = $_POST['payer_email']; $character = $_POST['custom']; $buff = sprintf("%s\t%s\t\$%0.2f\t%s\t%s\t%s", $txn_id, $payment_status, $payment_amount, $receiver_email, $payer_email, $character); $coins_sent = 0; if($res == "VERIFIED") { $db_mssql = new mssql(); $r = $db_mssql->connect(); // check the payment_status is Completed if($payment_status == 'Completed') { mssql_select_db('cash'); // check that txn_id has not been previously processed $r = $db_mssql->query("SELECT txn_id FROM dbo.paypal_logs WHERE txn_id='".$txn_id."';"); if(mssql_num_rows($r) == 0) { // check that receiver_email is your Primary PayPal email if($receiver_email == PAYPAL_EMAIL) { // check that payment_amount/payment_currency are correct $validpackage = false; for($i = 0; $i < count($paypal_packages); ++$i) { if($paypal_packages[$i][0] == $payment_amount && $payment_currency == CURRENCY) { $validpackage = true; break; } } // process payment if valid package if($validpackage) { mssql_select_db('character'); $r = $db_mssql->query("SELECT user_no FROM dbo.user_character WHERE character_name='".$character."';"); if(mssql_num_rows($r)) { $user_no = mssql_fetch_array($r); mssql_select_db('cash'); $r = $db_mssql->query("UPDATE dbo.user_cash SET amount = amount + ".$paypal_packages[$i][1]." WHERE user_no='".$user_no[0]."';"); // Added coins succesfully! if($r) $coins_sent = 1; else dbg_log('ERROR SENDING COINS: '.$buff); } else dbg_log('ACCOUNT NOT FOUND: '.$buff); mssql_select_db('cash'); // Add record to MSSQL $db_mssql->query("INSERT INTO paypal_logs VALUES ('".$txn_id."',".$payment_amount.",'".$payer_email."','".$account."',".$paypal_packages[$i][1].",".$coins_sent.",CURRENT_TIMESTAMP);"); } else dbg_log('INVALID PACKAGE: '.$buff); } else dbg_log('INVALID EMAIL: '.$buff); } else dbg_log('DUPLICATE IPN: '.$buff); } } else if ($res == "INVALID" ) { // log for manual investigation dbg_log('INVALID IPN: '.$buff); } ?>