You are here

function uc_paypal_ipn in Ubercart 5

Same name and namespace in other branches
  1. 6.2 payment/uc_paypal/uc_paypal.pages.inc \uc_paypal_ipn()
  2. 7.3 payment/uc_paypal/uc_paypal.pages.inc \uc_paypal_ipn()
1 string reference to 'uc_paypal_ipn'
uc_paypal_menu in payment/uc_paypal/uc_paypal.module
Implementation of hook_menu().

File

payment/uc_paypal/uc_paypal.module, line 570
Integrates various PayPal payment services and Instant Payment Notifications (IPN) with Ubercart!

Code

function uc_paypal_ipn($order_id = 0) {
  watchdog('uc_paypal', t('Receiving IPN at URL for order @order_id. <pre>@debug</pre>', array(
    '@order_id' => $order_id,
    '@debug' => variable_get('uc_paypal_wps_debug_ipn', FALSE) ? print_r($_POST, TRUE) : '',
  )));
  if (!isset($_POST['invoice'])) {
    watchdog('uc_paypal', t('IPN attempted with invalid order ID.'), WATCHDOG_ERROR);
    return;
  }
  if (($len = strpos($_POST['invoice'], '-')) > 0) {
    $order_id = intval(substr($_POST['invoice'], 0, $len));
  }
  else {
    $order_id = intval($_POST['invoice']);
  }
  $order = uc_order_load($order_id);
  if ($order == FALSE) {
    watchdog('uc_paypal', t('IPN attempted for non-existent order.'), WATCHDOG_ERROR);
    return;
  }

  // Assign posted variables to local variables
  $payment_status = check_plain($_POST['payment_status']);
  $payment_amount = check_plain($_POST['mc_gross']);
  $payment_currency = check_plain($_POST['mc_currency']);
  $payment_fee = check_plain($_POST['mc_fee']);
  $receiver_email = check_plain($_POST['receiver_email']);
  $txn_id = check_plain($_POST['txn_id']);
  $txn_type = check_plain($_POST['txn_type']);
  $payer_email = check_plain($_POST['payer_email']);

  // Express Checkout IPNs may not have the WPS email stored. But if it is, make
  // sure that the right account is being paid.
  if (variable_get('uc_paypal_wps_email', '') && $receiver_email != variable_get('uc_paypal_wps_email', '')) {
    watchdog('uc_paypal', t('IPN for a different PayPal account attempted.'), WATCHDOG_ERROR);
    return;
  }
  $req = 'cmd=_notify-validate';
  foreach ($_POST as $key => $value) {
    $value = urlencode(stripslashes($value));
    $req .= '&' . $key . '=' . $value;
  }
  if (variable_get('uc_paypal_wpp_server', '') == 'https://api-3t.paypal.com/nvp') {
    $host = 'https://www.paypal.com/cgi-bin/webscr';
  }
  else {
    $host = variable_get('uc_paypal_wps_server', 'https://www.sandbox.paypal.com/cgi-bin/webscr');
  }
  $host = explode('/', substr($host, 8));

  // Post back to PayPal to validate
  $header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
  $header .= 'Host: ' . $host[0] . "\r\n";
  $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
  $header .= 'Content-Length: ' . strlen($req) . "\r\n\r\n";

  // Address a screw-up on PayPal's Sandbox that prevents normal validation.
  if (strpos($host[0], 'sandbox') !== FALSE && function_exists('openssl_open')) {
    $fp = fsockopen('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
  }
  else {

    // The old "normal" way of validating an IPN.
    $fp = fsockopen($host[0], 80, $errno, $errstr, 30);
  }
  if (!$fp) {
    watchdog('uc_paypal', t('IPN failed with HTTP error.'), WATCHDOG_ERROR);
    return;
  }
  fputs($fp, $header . $req);
  while (!feof($fp)) {
    $res = fgets($fp, 1024);
    if (strcmp($res, 'VERIFIED') == 0) {
      watchdog('uc_paypal', t('IPN transaction verified.'));
      $duplicate = db_result(db_query("SELECT COUNT(*) FROM {uc_payment_paypal_ipn} WHERE txn_id = '%s' AND status != 'Pending'", $txn_id));
      if ($duplicate > 0) {
        if ($order->payment_method != 'credit') {
          watchdog('uc_paypal', t('IPN transaction ID has been processed before.'), WATCHDOG_NOTICE);
        }
        fclose($fp);
        return;
      }
      db_query("INSERT INTO {uc_payment_paypal_ipn} VALUES (%d, '%s', '%s', '%s', " . "'%s', '%s', '%s', %d)", $order_id, $txn_id, $txn_type, $payment_amount, $payment_status, $receiver_email, $payer_email, time());

      /*if (variable_get('uc_paypal_wps_email', '') != $receiver_email) {
          watchdog('uc_paypal', t('IPN received for an e-mail that is not your primary e-mail: @email', array('@email' => $receiver_email)));
        }*/
      switch ($payment_status) {
        case 'Canceled_Reversal':
          uc_order_comment_save($order_id, 0, t('PayPal has cancelled the reversal and returned !amount !currency to your account.', array(
            '!amount' => uc_currency_format($payment_amount, FALSE),
            '!currency' => $payment_currency,
          )), 'admin');
          break;
        case 'Completed':
          if ($payment_amount != $order->order_total) {
            watchdog('uc_paypal', t('Payment @txn_id for order @order_id did not equal the order total.', array(
              '@txn_id' => $txn_id,
              '@order_id' => $order->order_id,
            )), WATCHDOG_WARNING, l(t('view'), 'admin/store/orders/' . $order->order_id));
          }
          $comment = t('PayPal transaction ID: @txn_id', array(
            '@txn_id' => $txn_id,
          ));
          uc_payment_enter($order_id, 'paypal_wps', $payment_amount, $order->uid, NULL, $comment);
          uc_cart_complete_sale($order);
          uc_order_comment_save($order_id, 0, t('Payment of !amount !currency submitted through PayPal.', array(
            '!amount' => uc_currency_format($payment_amount, FALSE),
            '!currency' => $payment_currency,
          )), 'order', 'payment_received');
          uc_order_comment_save($order_id, 0, t('PayPal IPN reported a payment of !amount !currency.', array(
            '!amount' => uc_currency_format($payment_amount, FALSE),
            '!currency' => $payment_currency,
          )));
          break;
        case 'Denied':
          uc_order_comment_save($order_id, 0, t("You have denied the customer's payment."), 'admin');
          break;
        case 'Expired':
          uc_order_comment_save($order_id, 0, t('The authorization has failed and cannot be captured.'), 'admin');
          break;
        case 'Failed':
          uc_order_comment_save($order_id, 0, t("The customer's attempted payment from a bank account failed."), 'admin');
          break;
        case 'Pending':
          uc_order_update_status($order_id, 'paypal_pending');
          uc_order_comment_save($order_id, 0, t('Payment is pending at PayPal: @reason', array(
            '@reason' => _uc_paypal_pending_message($_POST['pending_reason']),
          )), 'admin');
          break;

        // You, the merchant, refunded the payment.
        case 'Refunded':
          $comment = t('PayPal transaction ID: @txn_id', array(
            '@txn_id' => $txn_id,
          ));
          uc_payment_enter($order_id, 'paypal_wps', $payment_amount, $order->uid, NULL, $comment);
          break;
        case 'Reversed':
          watchdog('uc_paypal', t('PayPal has reversed a payment!'), WATCHDOG_ERROR);
          uc_order_comment_save($order_id, 0, t('Payment has been reversed by PayPal: @reason', array(
            '@reason' => _uc_paypal_reversal_message($_POST['reason_code']),
          )), 'admin');
          break;
        case 'Processed':
          uc_order_comment_save($order_id, 0, t('A payment has been accepted.'), 'admin');
          break;
        case 'Voided':
          uc_order_comment_save($order_id, 0, t('The authorization has been voided.'), 'admin');
          break;
      }
    }
    elseif (strcmp($res, 'INVALID') == 0) {
      watchdog('uc_paypal', t('IPN transaction failed verification.'), WATCHDOG_ERROR);
      uc_order_comment_save($order_id, 0, t('An IPN transaction failed verification for this order.'), 'admin');
    }
  }
  fclose($fp);
}