function commerce_paypal_process_ipn in Commerce PayPal 7.2
Same name and namespace in other branches
- 7 commerce_paypal.module \commerce_paypal_process_ipn()
Processes an incoming IPN.
Parameters
$payment_method: The payment method instance array that originally made the payment.
$debug_ipn: Optionally specify an IPN array for debug purposes; if left empty, the IPN be pulled from the $_POST. If an IPN is passed in, validation of the IPN at PayPal will be bypassed.
Return value
TRUE or FALSE indicating whether the IPN was successfully processed or not.
1 string reference to 'commerce_paypal_process_ipn'
- commerce_paypal_menu in ./
commerce_paypal.module - Implements hook_menu().
File
- ./
commerce_paypal.module, line 66 - Implements PayPal payment services for use with Drupal Commerce.
Code
function commerce_paypal_process_ipn($payment_method = NULL, $debug_ipn = array()) {
// Retrieve the IPN from $_POST if the caller did not supply an IPN array.
// Note that Drupal has already run stripslashes() on the contents of the
// $_POST array at this point, so we don't need to worry about them.
if (empty($debug_ipn)) {
$ipn = $_POST;
// Exit now if the $_POST was empty.
if (empty($ipn)) {
watchdog('commerce_paypal', 'IPN URL accessed with no POST data submitted.', array(), WATCHDOG_WARNING);
return FALSE;
}
// Prepare an array to POST back to PayPal to validate the IPN.
$variables = array(
'cmd=_notify-validate',
);
foreach ($ipn as $key => $value) {
$variables[] = $key . '=' . urlencode($value);
}
// Determine the proper PayPal server to POST to.
if (!empty($ipn['test_ipn']) && $ipn['test_ipn'] == 1) {
$host = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
}
else {
$host = 'https://www.paypal.com/cgi-bin/webscr';
}
// Setup the cURL request.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $host);
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, implode('&', $variables));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_NOPROGRESS, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
// Commerce PayPal requires SSL peer verification, which may prevent out of
// date servers from successfully processing API requests. If you get an error
// related to peer verification, you may need to download the CA certificate
// bundle file from http://curl.haxx.se/docs/caextract.html, place it in a
// safe location on your web server, and update your settings.php to set the
// commerce_paypal_cacert variable to contain the absolute path of the file.
// Alternately, you may be able to update your php.ini to point to the file
// with the curl.cainfo setting.
if (variable_get('commerce_paypal_cacert', FALSE)) {
curl_setopt($ch, CURLOPT_CAINFO, variable_get('commerce_paypal_cacert', ''));
}
$response = curl_exec($ch);
// If an error occurred during processing, log the message and exit.
if ($error = curl_error($ch)) {
watchdog('commerce_paypal', 'Attempt to validate IPN failed with cURL error: @error', array(
'@error' => $error,
), WATCHDOG_ERROR);
return FALSE;
}
curl_close($ch);
// inspect IPN validation result and act accordingly
if (strcmp($response, "INVALID") == 0) {
// If the IPN was invalid, log a message and exit.
watchdog('commerce_paypal', 'Invalid IPN received and ignored. Response: @response', array(
'@response' => $response,
), WATCHDOG_ALERT);
return FALSE;
}
}
else {
$ipn = $debug_ipn;
}
// If the payment method specifies full IPN logging, do it now.
if (!empty($payment_method['settings']['ipn_logging']) && $payment_method['settings']['ipn_logging'] == 'full_ipn') {
if (!empty($ipn['txn_id'])) {
watchdog('commerce_paypal', 'Attempting to process IPN @txn_id. !ipn_log', array(
'@txn_id' => $ipn['txn_id'],
'!ipn_log' => '<pre>' . check_plain(print_r($ipn, TRUE)) . '</pre>',
), WATCHDOG_NOTICE);
}
else {
watchdog('commerce_paypal', 'Attempting to process an IPN. !ipn_log', array(
'!ipn_log' => '<pre>' . check_plain(print_r($ipn, TRUE)) . '</pre>',
), WATCHDOG_NOTICE);
}
}
// Exit if the IPN has already been processed.
if (!empty($ipn['txn_id']) && ($prior_ipn = commerce_paypal_ipn_load($ipn['txn_id']))) {
if ($prior_ipn['payment_status'] == $ipn['payment_status']) {
watchdog('commerce_paypal', 'Attempted to process an IPN that has already been processed with transaction ID @txn_id.', array(
'@txn_id' => $ipn['txn_id'],
), WATCHDOG_NOTICE);
return FALSE;
}
}
// Load the order based on the IPN's invoice number.
if (!empty($ipn['invoice']) && strpos($ipn['invoice'], '-') !== FALSE) {
list($ipn['order_id'], $timestamp) = explode('-', $ipn['invoice']);
}
elseif (!empty($ipn['invoice'])) {
$ipn['order_id'] = $ipn['invoice'];
}
else {
$ipn['order_id'] = 0;
$timestamp = 0;
}
if (!empty($ipn['order_id'])) {
$order = commerce_order_load($ipn['order_id']);
}
else {
$order = FALSE;
}
// Give the payment method module an opportunity to validate the receiver
// e-mail address and amount of the payment if possible. If a validate
// function exists, it is responsible for setting its own watchdog message.
if (!empty($payment_method)) {
$callback = $payment_method['base'] . '_paypal_ipn_validate';
// If a validator function existed...
if (function_exists($callback)) {
// Only exit if the function explicitly returns FALSE.
if ($callback($order, $payment_method, $ipn) === FALSE) {
return FALSE;
}
}
}
// Give the payment method module an opportunity to process the IPN.
if (!empty($payment_method)) {
$callback = $payment_method['base'] . '_paypal_ipn_process';
// If a processing function existed...
if (function_exists($callback)) {
// Skip saving if the function explicitly returns FALSE, meaning the IPN
// wasn't actually processed.
if ($callback($order, $payment_method, $ipn) !== FALSE) {
// Save the processed IPN details.
commerce_paypal_ipn_save($ipn);
}
}
}
// Invoke the hook here so implementations have access to the order and
// payment method if available and a saved IPN array that includes the payment
// transaction ID if created in the payment method's default process callback.
module_invoke_all('commerce_paypal_ipn_process', $order, $payment_method, $ipn);
}