Difference between revisions of "Extension:PayPal.php"

From Organic Design wiki
m
m
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
<?php
+
{{legacy}}
/* IpbWiki Paypal WikiMedia extension{{Category:Extensions|PayPal}}{{php}}{{#filesync:/var/www/extensions/PayPal.php}}
+
<php><?php
 +
/* IpbWiki Paypal WikiMedia extension
 
** IpbWiki (c) 2006
 
** IpbWiki (c) 2006
 
** Installation Instructions: http://www.ipbwiki.com/IpbWiki_Paypal_Extension
 
** Installation Instructions: http://www.ipbwiki.com/IpbWiki_Paypal_Extension
Line 8: Line 9:
 
   - Change button definitions to work from LocalSettings rather than code hack
 
   - Change button definitions to work from LocalSettings rather than code hack
 
   - Output warnings into sitenotice in error box
 
   - Output warnings into sitenotice in error box
 +
  - Log IPN post errors to log file
 
*/
 
*/
  
Line 14: Line 16:
 
define('PAYPAL_VERSION','1.0.3, 2007-12-13');
 
define('PAYPAL_VERSION','1.0.3, 2007-12-13');
  
$wgPayPalAmount  = false;          # Add an input field to enter the amount to donate
 
 
$wgPayPalIPN      = false;          # Use IPN notification
 
$wgPayPalIPN      = false;          # Use IPN notification
 
$wgPayPalTest    = false;          # Set to the email address of the test merchant account if testing IPN in the PayPal sandbox site
 
$wgPayPalTest    = false;          # Set to the email address of the test merchant account if testing IPN in the PayPal sandbox site
 
$wgPayPalPollms  = 5000;            # Number of milliseconds to wait between each call to AJAX updater
 
$wgPayPalPollms  = 5000;            # Number of milliseconds to wait between each call to AJAX updater
$wgPayPalUpdating = '(updating...)'; # Message to add to form totals text (in $3) before IPN post arrives
+
$wgPayPalUpdating = 'updating...';   # Message to add to form totals text (in $3) before IPN post arrives
  
 
$wgExtensionCredits['parserhook'][] = array(
 
$wgExtensionCredits['parserhook'][] = array(
Line 45: Line 46:
 
# Set button 1 to a default value if not defined
 
# Set button 1 to a default value if not defined
 
if (!isset($ipbwiki_paypal[1]))
 
if (!isset($ipbwiki_paypal[1]))
$ipbwiki_paypal[1] = '<form action="https://www.paypal.com/cgi-bin/webscr" method="post"><input type="hidden" name="cmd" value="_xclick"><input type="hidden" name="business" value="ipbwiki@gmail.com"><input type="hidden" name="item_name" value="IpbWiki PayPal"><input type="hidden" name="no_shipping" value="1"><input type="hidden" name="cn" value="Optional Comments"><input type="hidden" name="currency_code" value="EUR"><input type="hidden" name="tax" value="0"><input type="hidden" name="bn" value="PP-DonationsBF"><input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but04.gif" border="0" name="submit" alt="Make payments with PayPal - it\'s fast, free and secure!"></form>';
+
$ipbwiki_paypal[1] = '<form action="https://www.paypal.com/cgi-bin/webscr" method="post"><input type="hidden" name="cmd" value="_xclick">
 +
<input type="hidden" name="business" value="ipbwiki@gmail.com"><input type="hidden" name="item_name" value="IpbWiki PayPal">
 +
<input type="hidden" name="no_shipping" value="1"><input type="hidden" name="cn" value="Optional Comments">
 +
<input type="hidden" name="currency_code" value="EUR"><input type="hidden" name="tax" value="0">
 +
<input type="hidden" name="bn" value="PP-DonationsBF">
 +
<input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but04.gif" border="0" name="submit" alt="Make payments with PayPal - it\'s fast, free and secure!">
 +
</form>';
  
 
# IPN
 
# IPN
Line 59: Line 66:
 
$wgPayPalIPNTable = $db->tableName('PayPalIPN');
 
$wgPayPalIPNTable = $db->tableName('PayPalIPN');
 
if (!$db->tableExists($wgPayPalIPNTable)) {
 
if (!$db->tableExists($wgPayPalIPNTable)) {
$query = "CREATE TABLE $wgPayPalIPNTable (ipn_id VARCHAR(32), ipn_item INTEGER NOT NULL, ipn_from TINYTEXT, ipn_amount NUMERIC, ipn_status TINYTEXT, PRIMARY KEY (ipn_id));";
+
$query = "CREATE TABLE $wgPayPalIPNTable (ipn_id VARCHAR(32), ipn_date TINYTEXT, ipn_item INTEGER NOT NULL, ipn_from TINYTEXT, ipn_amount NUMERIC, ipn_status TINYTEXT, PRIMARY KEY (ipn_id));";
 
$result = $db->query($query);
 
$result = $db->query($query);
 
$db->freeResult($result);
 
$db->freeResult($result);
Line 82: Line 89:
 
$id    = $_POST['txn_id'];
 
$id    = $_POST['txn_id'];
 
$item  = isset($_POST['item_number']) ? $_POST['item_number'] : 1;
 
$item  = isset($_POST['item_number']) ? $_POST['item_number'] : 1;
 +
$date  = $_POST['payment_date'];
 
$from  = $_POST['payer_email'];
 
$from  = $_POST['payer_email'];
 
$cur    = $_POST['mc_currency'];
 
$cur    = $_POST['mc_currency'];
Line 100: Line 108:
 
fputs($fp, $header.$req);
 
fputs($fp, $header.$req);
 
while (!feof($fp)) $res = fgets($fp, 1024);
 
while (!feof($fp)) $res = fgets($fp, 1024);
if ($res === 'VERIFIED') wfPayPalUpdateItem($id,$item,$from,$amount,$status); # Update DB
+
if ($res === 'VERIFIED') wfPayPalUpdateItem($id,$date,$item,$from,$amount,$status); # Update DB
 
else wfPayPalLog("$log returned $res, status: $status");
 
else wfPayPalLog("$log returned $res, status: $status");
 
}
 
}
Line 184: Line 192:
 
$total_donated  = "<span id=\"paypal_donated\">$total_donated</span>";
 
$total_donated  = "<span id=\"paypal_donated\">$total_donated</span>";
 
$total_donations = "<span id=\"paypal_donations\">$total_donations</span>";
 
$total_donations = "<span id=\"paypal_donations\">$total_donations</span>";
$total_updating  = "<span id=\"paypal_donations\">$wgPayPalUpdating</span>";
+
$total_updating  = "<span id=\"paypal_updating\">$wgPayPalUpdating</span>";
 
$input = wfMsgReplaceArgs($input,array($total_donated,$total_donations,$total_updating));
 
$input = wfMsgReplaceArgs($input,array($total_donated,$total_donations,$total_updating));
 
}
 
}
  
 
# Replace $1, $2 and $3 in the text with the total amount donated and the total number of donations
 
# Replace $1, $2 and $3 in the text with the total amount donated and the total number of donations
$input = wfMsgReplaceArgs($input,array($total_donated,$total_donations,''));
+
# Don't display any text if no donations
 +
$input = $total_donations ? wfMsgReplaceArgs($input,array($total_donated,$total_donations,'')) : '';
 
}
 
}
  
Line 196: Line 205:
 
}
 
}
  
# Obtain the amount donated and total number of donations for this id form the DB
+
# Obtain the amount donated and total number of donations for an item (form number) from the DB
 +
# - must sum all completed transactions associated with the passed item number
 
function wfPayPalGetTotals($item,&$total_donated,&$total_donations) {
 
function wfPayPalGetTotals($item,&$total_donated,&$total_donations) {
 
global $wgPayPalIPNTable;
 
global $wgPayPalIPNTable;
Line 210: Line 220:
 
}
 
}
  
# Update a transaction with a new status or insert a new transaction
+
# Update a transaction (id) with a new status or insert a new transaction
function wfPayPalUpdateItem($id,$item,$from,$amount,$status) {
+
# - if transaction id already exists, only the date and status are updated
 +
function wfPayPalUpdateItem($id,$date,$item,$from,$amount,$status) {
 
global $wgPayPalIPNTable;
 
global $wgPayPalIPNTable;
 
$db = &wfGetDB(DB_MASTER);
 
$db = &wfGetDB(DB_MASTER);
Line 218: Line 229:
 
$exists = $db->fetchRow($result);
 
$exists = $db->fetchRow($result);
 
$db->freeResult($result);
 
$db->freeResult($result);
if ($exists) $db->update($wgPayPalIPNTable,array('ipn_status' => $status),array("ipn_id = '$id'"));
+
if ($exists) $db->update($wgPayPalIPNTable,array('ipn_date' => $date, 'ipn_status' => $status),array("ipn_id = '$id'"));
else $db->insert($wgPayPalIPNTable,array('ipn_id' => $id, 'ipn_item' => $item, 'ipn_from' => $from, 'ipn_amount' => $amount, 'ipn_status' => $status));
+
else $db->insert($wgPayPalIPNTable,array(
 +
'ipn_id'     => $id,
 +
'ipn_date'  => $date,
 +
'ipn_item'   => $item,
 +
'ipn_from'   => $from,
 +
'ipn_amount' => $amount,
 +
'ipn_status' => $status
 +
));
 
}
 
}
  
 
# Adds a JS function to poll for changes to the forms totals after returning from purchase
 
# Adds a JS function to poll for changes to the forms totals after returning from purchase
 
function wfPayPalAddAjaxUpdater(&$out) {
 
function wfPayPalAddAjaxUpdater(&$out) {
global $wgJsMimeType,$wgPayPalPollms,$wgPayPalAfterPurchase;
+
global $wgJsMimeType,$wgPayPalPollms;
 +
$id = $_POST['txn_id'];
 
$out->addScript("<script type='$wgJsMimeType'>
 
$out->addScript("<script type='$wgJsMimeType'>
 
var poll = setInterval('paypalPollUpdater()',$wgPayPalPollms);
 
var poll = setInterval('paypalPollUpdater()',$wgPayPalPollms);
Line 230: Line 249:
 
var totals = new Array();
 
var totals = new Array();
 
totals = xmlhttp.responseText.split('|');
 
totals = xmlhttp.responseText.split('|');
if (totals[1] > document.getElementById('paypal_donated').innerHTML) {
+
if (totals[2] == 'Completed') clearTimeout(poll);
clearTimeout(poll);
+
document.getElementById('paypal_donated').innerHTML = totals[0];
document.getElementById('paypal_donated').innerHTML = totals[0];
+
document.getElementById('paypal_donations').innerHTML = totals[1];
document.getElementById('paypal_donations').innerHTML = totals[1];
+
document.getElementById('paypal_updating').innerHTML = totals[2];
document.getElementById('paypal_updating').innerHTML = '';
 
}
 
 
}
 
}
 
function paypalPollUpdater() {
 
function paypalPollUpdater() {
sajax_do_call('wfPayPalAjaxUpdater',['$wgPayPalAfterPurchase'],paypalResponseHandler);
+
sajax_do_call('wfPayPalAjaxUpdater',['$id'],paypalResponseHandler);
 
}</script>");
 
}</script>");
 
return true;
 
return true;
Line 244: Line 261:
  
 
# The function called by the AJAX dispatcher to return the current totals of the form used to make the purchase
 
# The function called by the AJAX dispatcher to return the current totals of the form used to make the purchase
function wfPayPalAjaxUpdater($item) {
+
function wfPayPalAjaxUpdater($id) {
 +
global $wgPayPalIPNTable;
 
$db = &wfGetDB(DB_SLAVE);
 
$db = &wfGetDB(DB_SLAVE);
wfPayPalGetTotals($item,$total_donated,$total_donations);
+
$result = $db->query("SELECT ipn_status,ipn_item FROM $wgPayPalIPNTable WHERE ipn_id = '$id'");
 +
if ($result instanceof ResultWrapper) $result = $result->result;
 +
$total_donated = $total_donations = 0;
 +
$status = "Transaction $id not found!";
 +
if ($row = $db->fetchRow($result)) {
 +
list($status,$item) = $row;
 +
wfPayPalGetTotals($item,$total_donated,$total_donations);
 +
}
 
$total_donated = number_format($total_donated,2);
 
$total_donated = number_format($total_donated,2);
return "$total_donated|$total_donations";
+
return "$total_donated|$total_donations|$status";
 
}
 
}
  
Line 257: Line 282:
 
@file_put_contents($wgPayPalLog,"$ts $text\n",FILE_APPEND);
 
@file_put_contents($wgPayPalLog,"$ts $text\n",FILE_APPEND);
 
}
 
}
 +
</php>
 +
[[Category:Legacy Extensions|PayPal]][[Category:PayPal]]

Latest revision as of 14:59, 22 October 2014

Legacy.svg Legacy: This article describes a concept that has been superseded in the course of ongoing development on the Organic Design wiki. Please do not develop this any further or base work on this concept, this is only useful for a historic record of work done. You may find a link to the currently used concept or function in this article, if not you can contact the author to find out what has taken the place of this legacy item.

<php><?php /* IpbWiki Paypal WikiMedia extension

Changes by User:Nad (1.0.3 - 2007-12-04):

 - Added IPN support (which can also work with AJAX updating if $wgUseAjax set)
 - Change button definitions to work from LocalSettings rather than code hack
 - Output warnings into sitenotice in error box
 - Log IPN post errors to log file
  • /

if (!defined('MEDIAWIKI')) die('Not an entry point.');

define('PAYPAL_VERSION','1.0.3, 2007-12-13');

$wgPayPalIPN = false; # Use IPN notification $wgPayPalTest = false; # Set to the email address of the test merchant account if testing IPN in the PayPal sandbox site $wgPayPalPollms = 5000; # Number of milliseconds to wait between each call to AJAX updater $wgPayPalUpdating = 'updating...'; # Message to add to form totals text (in $3) before IPN post arrives

$wgExtensionCredits['parserhook'][] = array( 'name' => 'IpbWiki PayPal', 'version' => PAYPAL_VERSION, 'author' => 'Peter De Decker, (IPN support by User:Nad)', 'url' => 'http://www.ipbwiki.com/IpbWiki_Paypal_Extension', 'description' => 'Mediawiki PayPal Extension' );

$wgPayPalLog = str_replace('.php','.log',__FILE__); $ipbwiki_paypal = array(); $wgExtensionFunctions[] = "wfPayPalExtension"; $wgAjaxExportList[] = 'wfPayPalAjaxUpdater';

  1. If returning from merchant, get item number (form id)

$wgPayPalAfterPurchase = (isset($_POST['item_number']) && !($_REQUEST['title'] == '__ipn_post')) ? $_POST['item_number'] : false;

  1. Set up the extension

function wfPayPalExtension() { global $wgParser, $ipbwiki_paypal, $wgPayPalIPN;

# Register the extension with the WikiText parser $wgParser->setHook( "paypal", "wfPayPalRenderButton" );

# Set button 1 to a default value if not defined if (!isset($ipbwiki_paypal[1])) $ipbwiki_paypal[1] = '<form action="https://www.paypal.com/cgi-bin/webscr" method="post"><input type="hidden" name="cmd" value="_xclick"> <input type="hidden" name="business" value="ipbwiki@gmail.com"><input type="hidden" name="item_name" value="IpbWiki PayPal"> <input type="hidden" name="no_shipping" value="1"><input type="hidden" name="cn" value="Optional Comments"> <input type="hidden" name="currency_code" value="EUR"><input type="hidden" name="tax" value="0"> <input type="hidden" name="bn" value="PP-DonationsBF"> <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but04.gif" border="0" name="submit" alt="Make payments with PayPal - it\'s fast, free and secure!"> </form>';

# IPN if ($wgPayPalIPN) {

global $wgHooks, $wgPayPalTest, $wgPayPalIPNTable, $wgUseAjax, $wgPayPalAfterPurchase; $db = &wfGetDB(DB_MASTER);

# If using AJAX add JS updater after page rendered if ($wgUseAjax && $wgPayPalAfterPurchase) $wgHooks['OutputPageBeforeHTML'][] = 'wfPayPalAddAjaxUpdater';

# Create the IPN database table if it doesn't exist $wgPayPalIPNTable = $db->tableName('PayPalIPN'); if (!$db->tableExists($wgPayPalIPNTable)) { $query = "CREATE TABLE $wgPayPalIPNTable (ipn_id VARCHAR(32), ipn_date TINYTEXT, ipn_item INTEGER NOT NULL, ipn_from TINYTEXT, ipn_amount NUMERIC, ipn_status TINYTEXT, PRIMARY KEY (ipn_id));"; $result = $db->query($query); $db->freeResult($result); }

# If the table couldn't be created, disable IPN and add error to site notice if (!$db->tableExists($wgPayPalIPNTable)) { global $wgSiteNotice; $wgPayPalIPN = false;

$wgSiteNotice = "

PayPal IPN Error! Could not create IPN database table, IPN functionality is disabled.
Please ensure the wiki database user has CREATE permission, or add the table manually with the following query:
$query

";

}

# If this is an IPN post from paypal, validate and update the DB if verified if ($_REQUEST['title'] == '__ipn_post') {

# Disable normal wiki rendering and output global $wgOut; $wgOut->disable(); wfResetOutputBuffers();

# Read the relavent info from posted data $id = $_POST['txn_id']; $item = isset($_POST['item_number']) ? $_POST['item_number'] : 1; $date = $_POST['payment_date']; $from = $_POST['payer_email']; $cur = $_POST['mc_currency']; $amount = $_POST['payment_gross']; $status = $_POST['payment_status'];

# Post variables back to PayPal (with cmd appended) system (or sandbox if testing) to validate $log = "Transaction $id ($cur$amt) from $from"; $req = 'cmd=_notify-validate'; foreach ($_POST as $k => $v) $req .= "&$k=".urlencode(stripslashes($v)); $header .= "POST /cgi-bin/webscr HTTP/1.0\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: ".strlen($req)."\r\n\r\n"; $domain = $wgPayPalTest ? 'www.sandbox.paypal.com' : 'www.paypal.com'; $fp = fsockopen ($domain, 80, $errno, $errstr, 30); if (!$fp) wfPayPalLog("$log: Could not open HTTP socket to $domain!"); else { fputs($fp, $header.$req); while (!feof($fp)) $res = fgets($fp, 1024); if ($res === 'VERIFIED') wfPayPalUpdateItem($id,$date,$item,$from,$amount,$status); # Update DB else wfPayPalLog("$log returned $res, status: $status"); } fclose ($fp); } } }

  1. The callback function for converting the input text to HTML output

function wfPayPalRenderButton( $input, $argv ) { global $ipbwiki_paypal, $wgAuth, $wgSiteNotice, $wgPayPalIPN;

$error = '

warning, specified paypal button not found, defaulting to button 1

';

$pos_space = strpos($input,' '); if (!$pos_space) { if (is_numeric($input)) { // format <paypal>number</paypal> $part1 = $input; $part2 = ; if (!$ipbwiki_paypal[$part1]) { $wgSiteNotice .= $error; $part1 = 1; $part2 = $input; } } else { // format <paypal>text</paypal> & format <paypal></paypal> $part1 = 1; $part2 = $input; } } else { // format <paypal>number text</paypal> $part1 = substr($input,0,$pos_space); $part2 = substr($input,$pos_space+1); if (is_numeric($part1)) { if (!$ipbwiki_paypal[$part1]) { $wgSiteNotice .= $error; $part1 = 1; } } else { // format <paypal>text</paypal> $part1 = 1; $part2 = $input; } } $form = $ipbwiki_paypal[$part1]; // if the ipbwiki interface is available, then use the clean function which is defined there, otherwise just clean the necessities... if (class_exists ('ipbwiki')) { $input = $wgAuth->ipbwiki->ipbwiki->clean_value ($part2); } else { $part2 = str_replace( ">", ">", $part2 ); $part2 = str_replace( "<", "<", $part2 ); $part2 = str_replace( "\"", """, $part2 ); $part2 = str_replace( "!", "!", $part2 ); $part2 = str_replace( "'", "'", $part2 ); $input = $part2; }

# IPN if ($wgPayPalIPN) { global $wgParser, $wgServer, $wgScript, $wgTitle, $wgPayPalIPNTable, $wgPayPalTest, $wgPayPalUpdating, $wgPayPalAfterPurchase; $wgParser->disableCache();

# Set item_number to this forms id $form = str_replace('</form>',"<input type=\"hidden\" name=\"item_number\" value=\"$part1\" /></form>",$form);

# Add a notify_url value in the form to tell paypal to post account changes to this script # todo: append shared secret to notify url $form = str_replace('</form>',"<input type=\"hidden\" name=\"notify_url\" value=\"$wgServer$wgScript/__ipn_post\" /></form>",$form);

# Add the receiver_email and change the URL's to sandbox site if testing in the paypal sandbox if ($wgPayPalTest) { $form = str_replace('www.paypal.com','www.sandbox.paypal.com',$form); $form = str_replace('business','receiver_email',$form); $form = str_replace('</form>',"<input type=\"hidden\" name=\"business\" value=\"$wgPayPalTest\" /></form>",$form); }

# Set return URL to this page and method to GET (and include the item id of the submitted form) $url = $wgTitle->getFullUrl(); $form = str_replace('</form>',"<input type=\"hidden\" name=\"return\" value=\"$url\" /></form>",$form); #$form = str_replace('</form>',"<input type=\"hidden\" name=\"rm\" value=\"1\" /></form>",$form);

# Get the current totals for this form from DB wfPayPalGetTotals($part1,$total_donated,$total_donations); $total_donated = number_format($total_donated,2);

# If returning from paypal purchase which used this form, wrap totals in spans with id's so they can be updated by AJAX if ($wgPayPalAfterPurchase == $part1) { $total_donated = "$total_donated"; $total_donations = "$total_donations"; $total_updating = "$wgPayPalUpdating"; $input = wfMsgReplaceArgs($input,array($total_donated,$total_donations,$total_updating)); }

# Replace $1, $2 and $3 in the text with the total amount donated and the total number of donations # Don't display any text if no donations $input = $total_donations ? wfMsgReplaceArgs($input,array($total_donated,$total_donations,)) : ; }

$output = "

$form$input

";

return $output; }

  1. Obtain the amount donated and total number of donations for an item (form number) from the DB
  2. - must sum all completed transactions associated with the passed item number

function wfPayPalGetTotals($item,&$total_donated,&$total_donations) { global $wgPayPalIPNTable; $db = &wfGetDB(DB_SLAVE); $result = $db->query("SELECT ipn_amount FROM $wgPayPalIPNTable WHERE ipn_item = $item AND ipn_status = 'Completed'"); if ($result instanceof ResultWrapper) $result = $result->result; $total_donated = $total_donations = 0; while ($row = $db->fetchRow($result)) { $total_donations++; $total_donated += $row[0]; } $db->freeResult($result); }

  1. Update a transaction (id) with a new status or insert a new transaction
  2. - if transaction id already exists, only the date and status are updated

function wfPayPalUpdateItem($id,$date,$item,$from,$amount,$status) { global $wgPayPalIPNTable; $db = &wfGetDB(DB_MASTER); $result = $db->query("SELECT ipn_status FROM $wgPayPalIPNTable WHERE ipn_id = '$id'"); if ($result instanceof ResultWrapper) $result = $result->result; $exists = $db->fetchRow($result); $db->freeResult($result); if ($exists) $db->update($wgPayPalIPNTable,array('ipn_date' => $date, 'ipn_status' => $status),array("ipn_id = '$id'")); else $db->insert($wgPayPalIPNTable,array( 'ipn_id' => $id, 'ipn_date' => $date, 'ipn_item' => $item, 'ipn_from' => $from, 'ipn_amount' => $amount, 'ipn_status' => $status )); }

  1. Adds a JS function to poll for changes to the forms totals after returning from purchase

function wfPayPalAddAjaxUpdater(&$out) { global $wgJsMimeType,$wgPayPalPollms; $id = $_POST['txn_id']; $out->addScript("<script type='$wgJsMimeType'> var poll = setInterval('paypalPollUpdater()',$wgPayPalPollms); function paypalResponseHandler(xmlhttp) { var totals = new Array(); totals = xmlhttp.responseText.split('|'); if (totals[2] == 'Completed') clearTimeout(poll); document.getElementById('paypal_donated').innerHTML = totals[0]; document.getElementById('paypal_donations').innerHTML = totals[1]; document.getElementById('paypal_updating').innerHTML = totals[2]; } function paypalPollUpdater() { sajax_do_call('wfPayPalAjaxUpdater',['$id'],paypalResponseHandler); }</script>"); return true; }

  1. The function called by the AJAX dispatcher to return the current totals of the form used to make the purchase

function wfPayPalAjaxUpdater($id) { global $wgPayPalIPNTable; $db = &wfGetDB(DB_SLAVE); $result = $db->query("SELECT ipn_status,ipn_item FROM $wgPayPalIPNTable WHERE ipn_id = '$id'"); if ($result instanceof ResultWrapper) $result = $result->result; $total_donated = $total_donations = 0; $status = "Transaction $id not found!"; if ($row = $db->fetchRow($result)) { list($status,$item) = $row; wfPayPalGetTotals($item,$total_donated,$total_donations); } $total_donated = number_format($total_donated,2); return "$total_donated|$total_donations|$status"; }

  1. A log file for recording IPN error conditions

function wfPayPalLog($text) { global $wgPayPalLog; $ts = date("Y-m-d H:i:s"); @file_put_contents($wgPayPalLog,"$ts $text\n",FILE_APPEND); } </php>