=== modified file 'payment/uc_paypal/uc_paypal.module' --- payment/uc_paypal/uc_paypal.module 2008-11-10 20:17:14 +0000 +++ payment/uc_paypal/uc_paypal.module 2009-10-24 18:59:40 +0000 @@ -602,117 +602,107 @@ $req .= '&'. $key .'='. $value; } - if (variable_get('uc_paypal_wpp_server', '') == 'https://api-3t.paypal.com/nvp') { + // Per the PayPal Sandbox User Guide, test_ipn signifies a SandBox request + if (isset($_POST['test_ipn']) && $_POST['test_ipn'] == "1") { + $host = 'https://www.sandbox.paypal.com/cgi-bin/webscr'; + } + else { $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); + + $response = drupal_http_request($host, array(), 'POST', $req); + + // TODO: Change this to property_exists when we have a PHP requirement >= 5.1. + if (array_key_exists('error', $response)) { + watchdog('uc_paypal', t('IPN failed with HTTP error @error, code @code.', array('@error' => $response->error, '@code' => $response->code)), WATCHDOG_ERROR); + _uc_paypal_send_error_response(); 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': - $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); + if (strcmp($response->data, '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); + } + 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': + $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; + default: + uc_order_comment_save($order_id, 0, t('Unknown IPN payment status @status', array('@status' => $payment_status)), 'admin'); + watchdog('uc_paypal', t('Unknown IPN payment status @status', array('@status' => $payment_status)), WATCHDOG_ERROR); + _uc_paypal_send_error_response(); + break; + } + } + elseif (strcmp($response->data, 'INVALID') == 0) { + watchdog('uc_paypal', t('IPN transaction failed verification. '.print_r($response, true)), WATCHDOG_ERROR); + uc_order_comment_save($order_id, 0, t('An IPN transaction failed verification for this order.'), 'admin'); + _uc_paypal_send_error_response(); + } + else { + watchdog('uc_paypal', t('Unknown IPN verification response @res', array('@res' => $response->data)), WATCHDOG_ERROR); + _uc_paypal_send_error_response(); + } } // Handles a complete Website Payments Standard sale. @@ -1526,7 +1516,13 @@ } } +// Outputs the proper HTTP response for failed incoming PayPal requests. +function _uc_paypal_send_error_response() { + drupal_set_header('HTTP/1.1 500 Internal Server Error'); +} + // Returns an array of possible currency codes. function _uc_paypal_currency_array() { return drupal_map_assoc(array('AUD', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HUF', 'JPY', 'NOK', 'NZD', 'PLN', 'SEK', 'SGD', 'USD')); } +