function bit_display_error($pLogMessage, $pSubject, $pFatal = TRUE) { global $gBitSystem; if ($pFatal) { header($_SERVER["SERVER_PROTOCOL"] . ' ' . HttpStatusCodes::getMessageForCode(HttpStatusCodes::HTTP_INTERNAL_SERVER_ERROR)); } error_log($pLogMessage); if (!defined('IS_LIVE') || !IS_LIVE) { print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>bitweaver - White Screen of Death</title> </head> <body style="background:#fff; font-family:monospace;">'; // print "<h1>Upgrade Beta 1 to Beta 2</h1>If you are getting this error because you just upgraded your bitweaver from Beta 1 to Beta 2, please follow this link to the installer, which will guide you through the upgrade process: <a href='".BIT_ROOT_URL."install/install.php?step=4'>Upgrade Beta 1 to Beta 2</a>"; print "<h1 style=\"color:#900; font-weight:bold;\">You are running bitweaver in TEST mode</h1>\n"; print "\n\t\t\t<ul>\n\t\t\t\t<li><a href='http://sourceforge.net/tracker/?func=add&group_id=141358&atid=749176'>Click here to log a bug</a>, if this appears to be an error with the application.</li>\n\t\t\t\t<li><a href='" . BIT_ROOT_URL . "install/install.php'>Go here to begin the installation process</a>, if you haven't done so already.</li>\n\t\t\t\t<li>To hide this message, please <strong>set the IS_LIVE constant to TRUE</strong> in your config/kernel/config_inc.php file.</li>\n\t\t\t</ul>\n\t\t\t<hr />\n\t\t"; print "<pre>" . $pLogMessage . "</pre>"; print "<hr />"; print "</body></html>"; } else { bit_error_email($pSubject, $pLogMessage); if (defined('AUTO_BUG_SUBMIT') && AUTO_BUG_SUBMIT && !empty($gBitSystem) && $gBitSystem->isDatabaseValid()) { mail('*****@*****.**', "{$pSubject}", $pLogMessage); } } if ($pFatal) { die; } }
function processPayment(&$pPaymentParameters, &$pOrder) { global $gCommerceSystem, $messageStack, $response, $gBitDb, $gBitUser, $currencies; $postFields = array(); $responseHash = array(); $this->result = NULL; if (!self::verifyPayment($pPaymentParameters, $pOrder)) { // verify basics failed } elseif (!empty($pPaymentParameters['cc_ref_id']) && empty($pPaymentParameters['charge_amount'])) { $this->mErrors['charge_amount'] = 'Invalid amount'; } elseif (!($orderTotal = number_format($pOrder->info['total'], 2, '.', ''))) { $this->mErrors['charge_amount'] = 'Invalid amount'; } else { if (!empty($pPaymentParameters['cc_ref_id'])) { // reference transaction $this->paymentOrderId = $pOrder->mOrdersId; $paymentCurrency = BitBase::getParameter($pPaymentParameters, 'charge_currency', DEFAULT_CURRENCY); $paymentLocalized = $pPaymentParameters['charge_amount']; $paymentNative = $paymentCurrency != DEFAULT_CURRENCY ? $paymentLocalized / $pPaymentParameters['charge_currency_value'] : $paymentLocalized; // completed orders have a single joined 'name' field $pOrder->billing['firstname'] = substr($pOrder->billing['name'], 0, strpos($pOrder->billing['name'], ' ')); $pOrder->billing['lastname'] = substr($pOrder->billing['name'], strpos($pOrder->billing['name'], ' ') + 1); $pOrder->delivery['firstname'] = substr($pOrder->billing['name'], 0, strpos($pOrder->billing['name'], ' ')); $pOrder->delivery['lastname'] = substr($pOrder->billing['name'], strpos($pOrder->billing['name'], ' ') + 1); } else { $pOrder->info['cc_number'] = $this->cc_number; $pOrder->info['cc_expires'] = $this->cc_expires; $pOrder->info['cc_type'] = $this->cc_type; $pOrder->info['cc_owner'] = $this->cc_owner; $pOrder->info['cc_cvv'] = $this->cc_cvv; // Calculate the next expected order id $this->paymentOrderId = $pOrder->getNextOrderId(); // orderTotal is in the system DEFAULT_CURRENCY. orderTotal * currency_value = localizedPayment $paymentCurrency = BitBase::getParameter($pOrder->info, 'currency', DEFAULT_CURRENCY); $paymentNative = $orderTotal; $paymentLocalized = $paymentCurrency != DEFAULT_CURRENCY ? $paymentNative * $pOrder->getField('currency_value') : $paymentNative; } $paymentEmail = BitBase::getParameter($pOrder->customer, 'email_address', $gBitUser->getField('email')); $paymentUserId = BitBase::getParameter($pOrder->customer, 'user_id', $gBitUser->getField('user_id')); $paymentDecimal = $currencies->get_decimal_places($paymentCurrency); /* === Core Credit Card Parameters === All credit card processors accept the basic parameters described in the following table* with one exception: the PayPal processor does not support SWIPE*. TENDER (Required) The method of payment. Values are: - A = Automated clearinghouse (ACH) - C = Credit card - D = Pinless debit - K = Telecheck - P = PayPal Note: If your processor accepts non-decimal currencies, such as, Japanese Yen, include a decimal in the amount you pass to Payflow (use 100.00 not 100). Payflow removes the decimal portion before sending the value to the processor. // Not implemented RECURRING (Optional) Identifies the transaction as recurring. It is one of the following values: - Y - Identifies the transaction as recurring. - N - Does not identify the transaction as recurring (default). SWIPE (Required for card-present transactions only) Used to pass the Track 1 or Track 2 data (card's magnetic stripe information) for card-present transactions. Include either Track 1 or Track 2 data, not both. If Track 1 is physically damaged, the point-of-sale (POS) application can send Track 2 data instead. ORDERID (Optional) Checks for a duplicate order. If you pass ORDERID in a request and pass it again in the future, the response returns DUPLICATE=2 along with the ORDERID. Note: Do not use ORDERID to catch duplicate orders processed within seconds of each other. Use ORDERID with Request ID to prevent duplicates as a result of processing or communication errors. * bitcommerce note - this cannot be paymentOrderId as a failed process will block any future transactions */ $postFields = array('PWD' => MODULE_PAYMENT_PAYFLOWPRO_PWD, 'USER' => MODULE_PAYMENT_PAYFLOWPRO_LOGIN, 'VENDOR' => MODULE_PAYMENT_PAYFLOWPRO_VENDOR, 'PARTNER' => MODULE_PAYMENT_PAYFLOWPRO_PARTNER, 'VERBOSITY' => 'HIGH', 'TENDER' => 'C', 'REQUEST_ID' => time(), 'STREET' => $pOrder->billing['street_address'], 'ZIP' => $pOrder->billing['postcode'], 'COMMENT1' => 'OrderID: ' . $this->paymentOrderId . ' ' . $paymentEmail . ' (' . $paymentUserId . ')', 'EMAIL' => $paymentEmail, 'NAME' => BitBase::getParameter($pOrder->info, 'cc_owner'), 'BILLTOFIRSTNAME' => $pOrder->billing['firstname'], 'BILLTOLASTNAME' => $pOrder->billing['lastname'], 'BILLTOSTREET' => $pOrder->billing['street_address'], 'BILLTOSTREET2' => $pOrder->billing['suburb'], 'BILLTOCITY' => $pOrder->billing['city'], 'BILLTOSTATE' => $pOrder->billing['state'], 'BILLTOZIP' => $pOrder->billing['postcode'], 'BILLTOCOUNTRY' => $pOrder->billing['country']['countries_iso_code_2'], 'BILLTOPHONENUM' => $pOrder->billing['telephone'], 'SHIPTOFIRSTNAME' => $pOrder->delivery['firstname'], 'SHIPTOLASTNAME' => $pOrder->delivery['lastname'], 'SHIPTOSTREET' => $pOrder->delivery['street_address'], 'SHIPTOCITY' => $pOrder->delivery['city'], 'SHIPTOSTATE' => $pOrder->delivery['state'], 'SHIPTOZIP' => $pOrder->delivery['postcode'], 'SHIPTOCOUNTRY' => $pOrder->delivery['country']['countries_iso_code_2']); if ($paymentUserId != $gBitUser->mUserId) { $postFields['COMMENT1'] .= ' / ' . $gBitUser->getField('login') . ' (' . $gBitUser->mUserId . ')'; } if (!empty($pPaymentParameters['cc_ref_id'])) { $postFields['ORIGID'] = $pPaymentParameters['cc_ref_id']; $postFields['COMMENT2'] = 'Reference Trans for ' . $postFields['ORIGID']; // (Optional) Merchant-defined value for reporting and auditing purposes. Limitations: 128 alphanumeric characters } else { $postFields['ACCT'] = $pOrder->info['cc_number']; // (Required for credit cards) Credit card or purchase card number. For example, ACCT=5555555555554444. For the pinless debit TENDER type, ACCT can be the bank account number. $postFields['CVV2'] = $pOrder->getField('cc_cvv'); // (Optional) A code printed (not imprinted) on the back of a credit card. Used as partial assurance that the card is in the buyer's possession. Limitations: 3 or 4 digits $postFields['EXPDATE'] = $pOrder->info['cc_expires']; // (Required) Expiration date of the credit card. For example, 1215 represents December 2015. $postFields['INVNUM'] = $this->paymentOrderId; // (Optional) Your own unique invoice or tracking number. $postFields['FREIGHTAMT'] = $pOrder->info['shipping_cost']; // (Optional) Total shipping costs for this order. Nine numeric characters plus decimal. } /* TRXTYPE (Required) Indicates the type of transaction to perform. Values are: - A = Authorization - B = Balance Inquiry - C = Credit (Refund) - D = Delayed Capture - F = Voice Authorization - I = Inquiry - K = Rate Lookup - L = Data Upload - N = Duplicate Transaction Note: A type N transaction represents a duplicate transaction (version 4 SDK or HTTPS interface only) with a PNREF that is the same as the original. It appears only in the PayPal Manager user interface and never settles. - S = Sale - V = Void */ // Assume we are charging the native amount in the default currency. Some gateways support multiple currencies, check for that shortly if (DEFAULT_CURRENCY != $this->getProcessorCurrency() && $paymentCurrency == DEFAULT_CURRENCY) { global $currencies; // weird situtation where payflow currency default is different from the site. Need to convert site native to processor native $paymentNative = $currencies->convert($paymentNative, $this->getProcessorCurrency(), $paymentCurrency); bit_error_email('PAYMENT WARNING on ' . php_uname('n') . ': mismatch Payflow currency ' . $this->getProcessorCurrency() . ' != Default Currency ' . DEFAULT_CURRENCY, bit_error_string(), array()); } $paymentAmount = $paymentNative; $postFields['CURRENCY'] = $this->getProcessorCurrency(); if ($this->cc_type == 'American Express') { // TODO American Express Additional Credit Card Parameters } $processors = static::getProcessors(); switch ($gCommerceSystem->getConfig('MODULE_PAYMENT_PAYFLOWPRO_PROCESSOR')) { case 'Cielo Payments': // TODO Additional Credit Card Parameters break; case 'Elavon': // TODO Additional Credit Card Parameters break; case 'First Data Merchant Services Nashville': // TODO Additional Credit Card Parameters break; case 'First Data Merchant Services North': // TODO Additional Credit Card Parameters break; case 'Heartland': // TODO Additional Credit Card Parameters break; case 'Litle': // TODO Additional Credit Card Parameters break; case 'Paymentech Salem New Hampshire': // TODO Additional Credit Card Parameters break; case 'PayPal': if ($gCommerceSystem->isConfigActive('MODULE_PAYMENT_PAYFLOWPRO_MULTI_CURRENCY')) { switch ($paymentCurrency) { // PayPal supports charging natively in these 5 currencies case 'AUD': // Australian dollar // Australian dollar case 'CAD': // Canadian dollar // Canadian dollar case 'EUR': // Euro // Euro case 'GBP': // British pound // British pound case 'JPY': // Japanese Yen // Japanese Yen case 'USD': // US dollar if ($paymentCurrency != $postFields['CURRENCY']) { $paymentAmount = number_format($paymentLocalized, $paymentDecimal, '.', ''); $postFields['CURRENCY'] = strtoupper($paymentCurrency); } break; default: // all other currencies to gateway default break; } } $postFields['CUSTIP'] = $_SERVER['REMOTE_ADDR']; // (Optional) IP address of payer's browser as recorded in its HTTP request to your website. This value is optional but recommended. Note: PayPal records this IP address as a means to detect possible fraud. Limitations: 15-character string in dotted quad format: xxx.xxx.xxx.xxx //$postFields['MERCHDESCR'] = ''; // (Optional) Information that is usually displayed in the account holder's statement, for example, <Your-Not-For-Profit> <State>, <Your-Not-For-Profit> <Branch-Name>, <Your-Website> dues or <Your-Website> list fee. Character length and limitations: 23 alphanumeric characters, can include the special characters dash (-) and dot (.) only. Asterisks (*) are NOT permitted. If it includes a space character (), enclose the "<Soft-Descriptor>" value in double quotes. $postFields['MERCHANTCITY'] = substr($_SERVER['SERVER_NAME'], 0, 21); // (Optional) A unique phone number, email address or URL, which is displayed on the account holder's statement. PayPal recommends passing a toll-free phone number because, typically, this is the easiest way for a buyer to contact the seller in the case of an inquiry. /* === PayPal Specific Parameters Note: You must set CURRENCY to one of the three-character currency codes for any of the supported PayPal currencies. See CURRENCY in this table for details. Limitations: Nine numeric characters plus decimal (.) character. No currency symbol. Specify the exact amount to the cent using a decimal point; use 34.00, not 34. Do not include comma separators; use 1199.95 not 1,199.95. Nine numeric characters plus decimal. * BUTTONSOURCE (Optional) Identification code for use by third-party applications to identify transactions. Limitations: 32 alphanumeric characters. * CAPTURECOMPLETE (Optional) Indicates if this Delayed Capture transaction is the last capture you intend to make. The values are: - Y (default) - N Note: If CAPTURECOMPLETE is Y, any remaining amount of the original reauthorized transaction is automatically voided. Limitations: 12-character alphanumeric string. * CUSTOM (Optional) A free-form field for your own use. Limitations: 256-character alphanumeric string. Limitations: 127 alphanumeric characters. * ITEMAMT (Required if L_COSTn is specified). Sum of cost of all items in this order. * ITEMAMT = L_QTY0 * LCOST0 + L_QTY1 * LCOST1 + L_QTYn * L_COSTn Limitations: Nine numeric characters plus decimal. * TAXAMT (Required if L_TAXAMTn is specified) Sum of tax for all items in this order. Limitations: Nine numeric characters plus decimal. * TAXAMT = L_QTY0 * L_TAXAMT0 + L_QTY1 * L_TAXAMT1 + L_QTYn * L_TAXAMTn * HANDLINGAMT (Optional) Total handling costs for this order. Nine numeric characters plus decimal. * DISCOUNT (Optional) Shipping discount for this order. Specify the discount as a positive amount. Limitations: Nine numeric characters plus decimal (.) character. No currency symbol. Specify the exact amount to the cent using a decimal point; use 34.00, not 34. Do not include comma separators; use 1199.95 not 1,199.95. * INSURANCEAMT (Optional) Total shipping insurance cost for this order. Limitations: Nine numeric characters plus decimal (.) character. No currency symbol. Specify the exact amount to the cent using a decimal point; use 34.00, not 34. Do not include comma separators; use 1199.95 not 1,199.95. * L_NAMEn (Optional) Line-item name. Character length and limitations: 36 alphanumeric characters. * L_DESCn (Optional) Line-item description of the item purchased such as hiking boots or cooking utensils. * L_COSTn (Required if L_QTYn is supplied) Cost of the line item. The line-item unit price must be a positive number and be greater than zero. Note: You must set CURRENCY to one of the three-character currency codes for any of the supported PayPal currencies. See CURRENCY in this table for details. Limitations: Nine numeric characters plus decimal (.) character. No currency symbol. Specify the exact amount to the cent using a decimal point; use 34.00, not 34. Do not include comma separators; use 1199.95 not 1,199.95. Nine numeric characters plus decimal. * L_QTYn (Required if L_COSTn is supplied) Line-item quantity. Limitations: 10-character integer. * L_SKUn (Optional) Product number. Limitations: 18-characters. * L_TAXAMTn (Optional) Line-item tax amount. Limitations: Nine numeric characters plus decimal (.) character. No currency symbol. Specify the exact amount to the cent using a decimal point; use 34.00, not 34. Do not include comma separators; use 1199.95 not 1,199.95. * MERCHANTSESSIONID (Optional) Your customer Direct Payment session identification token. PayPal records this session token as an additional means to detect possible fraud. Limitations: 64 characters. Character length and limitations: 13 characters including special characters, such as, space, !, ", #, $, %, &, ', (, ), +, -,*, /, :, ;, <, =, >, ?, @, comma and period. If it includes the space character (), enclose the "<Soft-Descriptor-City>" value in double quotes. Note: Underscore (_) is an illegal character for this field. If it is passed, then it will be removed leaving the remaining characters in the same order. For example, New_York changes to NewYork. Added in version 115 of the API. * NOTIFYURL (Optional) Your URL for receiving Instant Payment Notification (IPN) about this transaction. If you do not specify NOTIFYURL in the request, the notification URL from your Merchant Profile is used, if one exists. Limitations: 2048 alphanumeric characters. * ORDERDESC (Optional) Description of items the customer is purchasing. Limitations: 127 alphanumeric characters. * RECURRINGTYPE (Optional) Type of transaction occurrence. The values are: - F = First occurrence - S = Subsequent occurrence (default) Limitations: One alpha character. */ break; case 'SecureNet': // TODO Additional Credit Card Parameters break; case 'Vantiv': // TODO Additional Credit Card Parameters break; case 'WorldPay': // TODO Additional Credit Card Parameters break; } if (MODULE_PAYMENT_PAYFLOWPRO_TYPE == 'Authorization') { $postFields['TRXTYPE'] = 'A'; } elseif ($paymentAmount > 0) { $postFields['TRXTYPE'] = 'S'; } elseif ($paymentAmount < 0) { $postFields['TRXTYPE'] = 'C'; $paymentAmount = -1.0 * $paymentAmount; } $postFields['AMT'] = number_format($paymentAmount, $paymentDecimal, '.', ''); // (Required) Amount (Default: U.S. based currency). Nnumeric characters and a decimal only. The maximum length varies depending on your processor. Specify the exact amount to the cent using a decimal point (use 34.00 not 34). Do not include comma separators (use 1199.95 not 1,199.95). Your processor or Internet Merchant Account provider may stipulate a maximum amount. if (MODULE_PAYMENT_PAYFLOWPRO_MODE == 'Test') { $url = 'https://pilot-payflowpro.paypal.com'; } else { $url = 'https://payflowpro.paypal.com'; } // request-id must be unique within 30 days $requestId = md5(uniqid(mt_rand())); $headers[] = 'Content-Type: text/namevalue'; $headers[] = 'X-VPS-Timeout: 45'; $headers[] = 'X-VPS-VIT-Client-Type: PHP/cURL'; $headers[] = 'X-VPS-VIT-Integration-Product: PHP::bitcommerce - Payflow Pro'; $headers[] = 'X-VPS-VIT-Integration-Version: 1.0'; $this->lastHeaders = $headers; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_buildNameValueList($postFields)); $_curlOptions = array(CURLOPT_HEADER => 0, CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => 60, CURLOPT_FOLLOWLOCATION => 0, CURLOPT_SSL_VERIFYPEER => 0, CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_FORBID_REUSE => true, CURLOPT_POST => 1); foreach ($_curlOptions as $name => $value) { curl_setopt($ch, $name, $value); } $response = curl_exec($ch); if ($commError = curl_error($ch)) { $this->mErrors['curl_errno'] = curl_errno($ch); $this->mErrors['curl_info'] = @curl_getinfo($ch); $this->mErrors['process_payment'] = 'CURL ERROR ' . $this->mErrors['curl_errno']; } curl_close($ch); if ($response) { $responseHash = $this->_parseNameValueList($response); $this->result = NULL; $this->pnref = ''; # Check result if (isset($responseHash['PNREF'])) { $this->pnref = $responseHash['PNREF']; } if (isset($responseHash['RESULT'])) { $this->result = (int) $responseHash['RESULT']; if (BitBase::getParameter($responseHash, 'DUPLICATE') == 2) { $duplicateError = 'Duplicate Order ( ' . $responseHash['ORDERID'] . ' )'; $this->mErrors['process_payment'] = $duplicateError; $_SESSION[$this->code . '_error']['number'] = $duplicateError; } elseif ($this->result) { $this->mErrors['process_payment'] = $responseHash['RESPMSG'] . ' (' . $this->result . ')'; $_SESSION[$this->code . '_error']['number'] = $responseHash['RESPMSG']; } else { $this->clearSessionDetails(); } } else { $this->clearSessionDetails(); $this->result = 'X'; } $this->response = $response; } } if (count($this->mErrors) == 0 && $this->result === 0) { $ret = TRUE; $pOrder->info['cc_ref_id'] = $this->getTransactionReference(); if (!empty($postFields['ACCT']) && MODULE_PAYMENT_PAYFLOWPRO_CARD_PRIVACY == 'True') { //replace middle CC num with XXXX $pOrder->info['cc_number'] = substr($postFields['ACCT'], 0, 6) . str_repeat('X', strlen($postFields['ACCT']) - 6) . substr($postFields['ACCT'], -4); } } else { foreach (array('PWD', 'USER', 'VENDOR', 'PARTNER', 'CVV2') as $field) { if (isset($postFields[$field])) { unset($postFields[$field]); } } if (isset($postFields['ACCT'])) { $postFields['ACCT'] = $this->privatizeCard($postFields['ACCT']); } bit_error_email('PAYMENT ERROR on ' . php_uname('n') . ': ' . BitBase::getParameter($this->mErrors, 'process_payment'), bit_error_string(), array('mErrors' => $this->mErrors, 'CURL' => $postFields, 'RESPONSE' => $responseHash)); $this->mDb->RollbackTrans(); $messageStack->add_session('checkout_payment', tra('There has been an error processing your payment, please try again.') . '<br/>' . BitBase::getParameter($responseHash, 'RESPMSG'), 'error'); $ret = FALSE; } $this->logTransaction($responseHash, $pOrder); return $ret; }