Difference between revisions of "Extension:PayPal.php"
m |
m |
||
(13 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | <?php | + | {{legacy}} |
− | /* IpbWiki Paypal WikiMedia extension | + | <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'); | ||
− | |||
$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 = ' | + | $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=\" | + | $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 | + | # 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 | + | 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[ | + | 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() { | function paypalPollUpdater() { | ||
− | sajax_do_call('wfPayPalAjaxUpdater',['$ | + | 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($ | + | 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
<php><?php /* IpbWiki Paypal WikiMedia extension
- IpbWiki (c) 2006
- Installation Instructions: http://www.ipbwiki.com/IpbWiki_Paypal_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';
- If returning from merchant, get item number (form id)
$wgPayPalAfterPurchase = (isset($_POST['item_number']) && !($_REQUEST['title'] == '__ipn_post')) ? $_POST['item_number'] : false;
- 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 = "
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); } } }
- The callback function for converting the input text to HTML output
function wfPayPalRenderButton( $input, $argv ) { global $ipbwiki_paypal, $wgAuth, $wgSiteNotice, $wgPayPalIPN;
$error = '
';
$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; }
- 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) { 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); }
- Update a transaction (id) with a new status or insert a new transaction
- - 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 )); }
- 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; }
- 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"; }
- 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>