Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@iloveitaly
Created July 5, 2010 18:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iloveitaly/464570 to your computer and use it in GitHub Desktop.
Save iloveitaly/464570 to your computer and use it in GitHub Desktop.
<?php
/* PHP Paypal IPN Integration Class Demonstration File
* 6.25.2008 - Eric Wang, http://code.google.com/p/paypal-ipn-class-php/
*
* This file demonstrates the usage of paypal.class.php, a class designed
* to aid in the interfacing between your website, paypal, and the instant
* payment notification (IPN) interface. This single file serves as 4
* virtual pages depending on the "action" varialble passed in the URL. It's
* the processing page which processes form data being submitted to paypal, it
* is the page paypal returns a user to upon success, it's the page paypal
* returns a user to upon canceling an order, and finally, it's the page that
* handles the IPN request from Paypal.
*
* If you want submit a payment form to Paypal sandbox. Please add the
* _GET[sandbox=1] parameter to link. ie: paypal.php?sandbox=1.
*
* I tried to comment this file, aswell as the acutall class file, as well as
* I possibly could. Please email me with questions, comments, and suggestions.
* See the header of paypal.class.php for additional resources and information.
*/
require_once('paypal_class.php');
$p = new paypal_class();
$p->sandbox = true;
if($p->sandbox) {
$p->admin_mail = 'notification@gmail.com';
$p->paypal_mail = 'owner@softwarebusiness.com'; // equivilent to: $p->add_field('business', 'email@domain.com')
} else {
}
// $p->admin_mail = EMAIL_ADD;
//$p -> paypal_mail = PAYPAL_EMAIL_ADD; // If set, class will verify the receiver.
switch ($_GET['action']) {
default:
// There should be no output at this point. To process the POST data,
// the submit_paypal_post() function will output all the HTML tags which
// contains a FORM which is submited instantaneously using the BODY onload
// attribute. In other words, don't echo or printf anything when you're
// going to be calling the submit_paypal_post() function.
// adds or edits a "$p->add_field(key, value);" in following, which is what will be
// sent to paypal as POST variables. Refer to PayPal HTML Variables:
// https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_html_Appx_websitestandard_htmlvariables
// This is where you would have your form validation and all that jazz.
// You would take your POST vars and load them into the class like below,
// only using the POST values instead of constant string expressions.
// setup a current URL variable for this script
$this_script = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$p->add_field('return', $this_script.'?action=success');
$p->add_field('cancel_return', $this_script.'?action=cancel');
$p->add_field('notify_url', $this_script.'?action=ipn');
$p->add_field('item_name', 'Paypal Test Transaction');
$p->add_field('cmd', '_donations');
$p->add_field('custom', 9);
$p->add_field('rm', '2'); // Return method = POST
$p->submit_paypal_post(); // submit the fields to paypal
$p->dump_fields(); // for debugging, output a table of all the fields
break;
case 'success': // Order was successful...
// This is where you would probably want to thank the user for their order
// or what have you. The order information at this point is in POST
// variables. However, you don't want to "process" the order until you
// get validation from the IPN. That's where you would have the code to
// email an admin, update the database with payment status, activate a
// membership, etc.
echo "<html><head><title>Success</title></head><body><h3>Thank you for your order.</h3>";
foreach ($_POST as $key => $value) { echo "$key: $value<br>"; }
echo "</body></html>";
// You could also simply re-direct them to another page, or your own
// order status page which presents the user with the status of their
// order based on a database (which can be modified with the IPN code
// below).
break;
case 'cancel': // Order was canceled...
// The order was canceled before being completed.
echo "<html><head><title>Canceled</title></head><body><h3>The order was canceled.</h3>";
echo "</body></html>";
break;
case 'ipn':
if ($p->validate_ipn()) {
$subject = 'Instant Payment Notification - Received Payment';
$p->send_report($subject);
} else {
$subject = 'Instant Payment Notification - Payment Fail';
$p->send_report ( $subject );
}
break;
}
?>
<?php
/**
* PHP Paypal IPN Integration Class
* 6.25.2008 - Eric Wang, http://code.google.com/p/paypal-ipn-class-php/
*
* This file provides neat and simple method to validate the paid result with Paypal IPN.
* It's NOT intended to make the paypal integration "plug 'n' play".
* It still requires the developer to understand the paypal process and know the variables
* you want/need to pass to paypal to achieve what you want.
*
* @author Eric Wang <eric.wzy@gmail.com>
* @copyright (C) 2008 - 2009 Eric.Wang
*
*/
define('LOG_FILE', 'ipn_results.log');
define('DEBUG_LOG_FILE', 'ipn_results_debug.log');
class paypal_class {
private $ipn_status;
public $admin_mail; // receive the ipn status report pre transaction
public $paypal_mail; // paypal account, if set, class need to verify receiver
public $txn_id; // array: if the txn_id array existed, class need to verified the txn_id duplicate
private $ipn_response; // holds the IPN response from paypal
public $ipn_data = array(); // array contains the POST values for IPN
private $fields = array(); // array holds the fields to submit to paypal
public $sandbox = false;
private $ipn_debug = false;
public $ipn_log = true;
function __construct() {
$this->ipn_status = '';
$this->admin_mail = null;
$this->paypal_mail = null;
$this->txn_id = null;
$this->tax = null;
$this->ipn_response = '';
}
// adds a key=>value pair to the fields array, which is what will be
// sent to paypal as POST variables.
public function add_field($field, $value) {
$this->fields["$field"] = $value;
}
// this function actually generates an entire HTML page consisting of
// a form with hidden elements which is submitted to paypal via the
// BODY element's onLoad attribute. We do this so that you can validate
// any POST vars from you custom form before submitting to paypal. So
// basically, you'll have your own form which is submitted to your script
// to validate the data, which in turn calls this function to create
// another hidden form and submit to paypal.
// The user will briefly see a message on the screen that reads:
// "Please wait, your order is being processed..." and then immediately
// is redirected to paypal.
public function submit_paypal_post() {
echo "<html>\n";
echo "<head><title>Processing Payment...</title></head>\n";
echo "<body onLoad=\"document.forms['paypal_form'].submit();\">\n";
echo "<center><h2>Please wait, your order is being processed and you";
echo " will be redirected to the paypal website.</h2></center>\n";
echo "<form method=\"post\" name=\"paypal_form\" ";
echo "action=\"".$this->getPaypalURL()."\">\n";
if(isset($this->paypal_mail)) {
echo "<input type=\"hidden\" name=\"business\" value=\"$this->paypal_mail\"/>\n";
}
foreach ($this->fields as $name => $value) {
echo "<input type=\"hidden\" name=\"$name\" value=\"$value\"/>\n";
}
echo "<center><br/><br/>If you are not automatically redirected to ";
echo "paypal within 5 seconds...<br/><br/>\n";
echo "<input type=\"submit\" value=\"Click Here\"></center>\n";
echo "</form>\n";
echo "</body></html>\n";
}
public function validate_ipn() {
$hostname = gethostbyaddr ( $_SERVER ['REMOTE_ADDR'] );
if (! preg_match ( '/paypal\.com$/', $hostname )) {
$this->ipn_status = 'Validation post isn\'t from PayPal';
$this->log_ipn_results ( false );
return false;
}
if (isset($this->paypal_mail) && strtolower ( $_POST['receiver_email'] ) != strtolower(trim( $this->paypal_mail ))) {
$this->ipn_status = "Receiver Email Not Match";
$this->log_ipn_results ( false );
return false;
}
if (isset($this->txn_id) && in_array($_POST['txn_id'],$this->txn_id)) {
$this->ipn_status = "txn_id have a duplicate";
$this->log_ipn_results ( false );
return false;
}
// parse the paypal URL
$url_parsed = parse_url($this->getPaypalURL());
// generate the post string from the _POST vars aswell as load the
// _POST vars into an arry so we can play with them from the calling
// script.
$post_string = '';
foreach ($_POST as $field=>$value) {
$this->ipn_data["$field"] = $value;
$post_string .= $field.'='.urlencode(stripslashes($value)).'&';
}
$post_string.="cmd=_notify-validate"; // append ipn command
// open the connection to paypal
if($this->sandbox) {
$fp = fsockopen('ssl://www.sandbox.paypal.com', "443", $err_num, $err_str, 60 );
} else {
$fp = fsockopen('ssl://www.paypal.com', "443", $err_num, $err_str, 60 );
}
if(!$fp) {
// could not open the connection. If loggin is on, the error message
// will be in the log.
$this->ipn_status = "fsockopen error no. $err_num: $err_str";
$this->log_ipn_results(false);
return false;
} else {
// Post the data back to paypal
fputs($fp, "POST $url_parsed[path] HTTP/1.1\r\n");
fputs($fp, "Host: $url_parsed[host]\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($post_string)."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $post_string . "\r\n\r\n");
// loop through the response from the server and append to variable
while(!feof($fp)) {
$this->ipn_response .= fgets($fp, 1024);
}
fclose($fp);
}
// Invalid IPN transaction. Check the $ipn_status and log for details.
if (stristr($this->ipn_response, "VERIFIED") === FALSE) {
$this->ipn_status = 'IPN Validation Failed';
$this->log_ipn_results(false);
return false;
} else {
$this->ipn_status = "IPN VERIFIED";
$this->log_ipn_results(true);
return true;
}
}
private function log_ipn_results($success) {
$hostname = gethostbyaddr ( $_SERVER ['REMOTE_ADDR'] );
// Timestamp
$text = '[' . date ( 'm/d/Y g:i A' ) . '] - ';
// Success or failure being logged?
if ($success)
$this->ipn_status = $text . 'SUCCESS:' . $this->ipn_status . "!\n";
else
$this->ipn_status = $text . 'FAIL: ' . $this->ipn_status . "!\n";
// Log the POST variables
$this->ipn_status .= "[From:" . $hostname . "|" . $_SERVER ['REMOTE_ADDR'] . "]IPN POST Vars Received By Paypal_IPN Response API:\n";
foreach ( $this->ipn_data as $key => $value ) {
$this->ipn_status .= "$key=$value \n";
}
// Log the response from the paypal server
$this->ipn_status .= "IPN Response from Paypal Server:\n" . $this->ipn_response;
$this->write_to_log();
}
private function write_to_log() {
if (! $this->ipn_log)
return; // is logging turned off?
$fp = fopen ( LOG_FILE , 'a' );
fwrite ( $fp, $this->ipn_status . "\n\n" );
fclose ( $fp ); // close file
chmod ( LOG_FILE , 0600 );
}
public function send_report($subject) {
$body .= "from " . $this->ipn_data ['payer_email'] . " on " . date ( 'm/d/Y' );
$body .= " at " . date ( 'g:i A' ) . "\n\nDetails:\n" . $this->ipn_status;
mail ( $this->admin_mail, $subject, $body );
}
public function print_report() {
$find [] = "\n";
$replace [] = '<br/>';
$html_content = str_replace ( $find, $replace, $this->ipn_status );
echo $html_content;
}
public function getPaypalURL() {
return $this->sandbox ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
}
public function dump_fields() {
// Used for debugging, this function will output all the field/value pairs
// that are currently defined in the instance of the class using the
// add_field() function.
echo "<h3>paypal_class->dump_fields() Output:</h3>";
echo "<table width=\"95%\" border=\"1\" cellpadding=\"2\" cellspacing=\"0\">
<tr>
<td bgcolor=\"black\"><b><font color=\"white\">Field Name</font></b></td>
<td bgcolor=\"black\"><b><font color=\"white\">Value</font></b></td>
</tr>";
ksort($this->fields);
foreach ($this->fields as $key => $value) {echo "<tr><td>$key</td><td>".urldecode($value)."&nbsp;</td></tr>";}
echo "</table><br>";
}
private function debug($msg) {
if(!$this->ipn_debug)
return;
$today = date ( "Y-m-d H:i:s " );
$fh = fopen (DEBUG_LOG_FILE, 'a' ) or die ( "Can't open debug file. Please manually create the 'debug.log' file and make it writable." );
$ua_simple = preg_replace ( "/(.*)\s\(.*)/", "\\1", $_SERVER ['HTTP_USER_AGENT'] );
fwrite ( $fh, $today . " [from: " . $_SERVER ['REMOTE_ADDR'] . "|$ua_simple] - " . $msg . "\n" );
fclose ( $fh );
chmod (DEBUG_LOG_FILE, 0600 );
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment