Porting osCommerce iTransact CC Module
Hello,
I am running Zen Cart 1.3.8p3 (PHP 5.2.12) and am working at porting the osCommerce iTransact credit card module (v1.2) for use with my Zen Cart installation.
With that in mind, I downloaded the original osCommerce iTransact module from here http://www.itransact.com/redicart/itransact-osc-1.2.zip and followed the instructions (to the best of my limited abilities) for porting osCommerce modules to Zen Cart found here
http://www.zen-cart.com/wiki/index.p...dules_from_osC
and have managed to get the module to successfully post transactions so that my credit card is charged and iTransact sends me a nice success message saying that all is well.
However, the passback/return functionality appears to be broken because once the transaction is completed on the iTransact web interface the user is returned to Zen Cart and greeted with the following error message:
"Whoops! Sorry, but you are not allowed to perform the action requested. You are still logged in to your account and may continue shopping. Please choose a destination from a menu."
This error comes from Zen Cart and appears to fire due to a "time out" of some sort, but I could be wrong. The "time out" assumption is based on the name of the file in the Zen Cart framework containing the error message (time_out.php
Line #11), but I have no idea which function called the error.
Also, no record of the completed transaction can be found in the Admin interface on Zen Cart, which means that Zen Cart never got a response back from iTransact (at least not in readable form) to tell it about the transaction.
So, being a C# guy used to the rich glories of debugging in Visual Studio and not having a clue what I'm doing in PHP beyond the basics--and being new to debugging in Eclipse, I'm rather lost at the moment. I want to setup remote debugging on my server so I can set breakpoints and see what data is being returned, if any at all, but am throwing out this Hail Mary post before I hassle with SSH and installing debugging tools on my remote server and all that fun stuff.
Can some PHP/Zen Cart God out there please have a look at my ported osCommerce code listed below and spot the glowing flaw in my effort and tell me what I'm doing wrong? I sure hope so because my nerves are shot (not being able to debug effectively is driving me crazy).
Any feedback at all would be most appreciated.
Thanks and very cordially,
Wulf
The code posted below is my modified code:
Code:
<?php
/*
osCommerce, Open Source E-Commerce Solutions
http://www.oscommerce.com
Copyright (c) 2003 osCommerce
iTransact, Inc. (Credit Card) Module v1.2
Copyright (c) 2003 React, Ltd.
http://react.co.nz
Modified for Zen Cart by Wulfmaer
Released under the GNU General Public License
*/
class itransact {
var $code, $title, $description, $enabled;
// class constructor
function itransact() {
global $order;
$this->code = 'itransact';
$this->title = MODULE_PAYMENT_ITRANSACT_TEXT_TITLE;
$this->description = MODULE_PAYMENT_ITRANSACT_TEXT_DESCRIPTION;
$this->enabled = ((MODULE_PAYMENT_ITRANSACT_STATUS == 'True') ? true : false);
$this->sort_order = MODULE_PAYMENT_ITRANSACT_SORT_ORDER;
if ((int)MODULE_PAYMENT_ITRANSACT_ORDER_STATUS_ID > 0) {
$this->order_status = MODULE_PAYMENT_ITRANSACT_ORDER_STATUS_ID;
}
if (is_object($order)) $this->update_status();
if (strstr(MODULE_PAYMENT_ITRANSACT_FORMAT, 'Standard')) {
$this->form_action_url = 'https://secure.paymentclearing.com/cgi-bin/rc/ord.cgi';
} else {
$this->form_action_url = 'https://secure.paymentclearing.com/cgi-bin/mas/split.cgi';
}
}
// class methods
function update_status() {
global $order;
global $db;
if ( ($this->enabled == true) && ((int)MODULE_PAYMENT_ITRANSACT_ZONE > 0) ) {
$check_flag = false;
$check_query = $db->Execute("select zone_id from " . TABLE_ZONES_TO_GEO_ZONES . " where geo_zone_id = '" . MODULE_PAYMENT_ITRANSACT_ZONE . "' and zone_country_id = '" . $order->billing['country']['id'] . "' order by zone_id");
while ($check = $db->Execute($check_query)) {
if ($check['zone_id'] < 1) {
$check_flag = true;
break;
} elseif ($check['zone_id'] == $order->billing['zone_id']) {
$check_flag = true;
break;
}
}
if ($check_flag == false) {
$this->enabled = false;
}
}
}
function javascript_validation() {
if (strstr(MODULE_PAYMENT_ITRANSACT_FORMAT, 'Standard')) {
$js = ' if (payment_value == "' . $this->code . '") {' . "\n" .
' var cc_number = document.checkout_payment.itransact_cc_number.value;' . "\n" .
' if (cc_number == "" || cc_number.length < ' . CC_NUMBER_MIN_LENGTH . ') {' . "\n" .
' error_message = error_message + "' . MODULE_PAYMENT_ITRANSACT_TEXT_JS_CC_NUMBER . '";' . "\n" .
' error = 1;' . "\n" .
' }' . "\n" .
' }' . "\n";
}
return $js;
}
function selection() {
global $order;
for ($i=1; $i<13; $i++) {
$expires_month[] = array('id' => sprintf('%02d', $i), 'text' => strftime('%B',mktime(0,0,0,$i,1,2000)));
}
$today = getdate();
for ($i=$today['year']; $i < $today['year']+10; $i++) {
$expires_year[] = array('id' => strftime('%y',mktime(0,0,0,1,1,$i)), 'text' => strftime('%Y',mktime(0,0,0,1,1,$i)));
}
if (strstr(MODULE_PAYMENT_ITRANSACT_FORMAT, 'Standard')) {
$selection = array('id' => $this->code,
'module' => $this->title,
'fields' => array(array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_NUMBER,
'field' => zen_draw_input_field('itransact_cc_number')),
array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_EXPIRES,
'field' => zen_draw_pull_down_menu('itransact_cc_expires_month', $expires_month) . ' ' . zen_draw_pull_down_menu('itransact_cc_expires_year', $expires_year))));
if (MODULE_PAYMENT_ITRANSACT_CVV == 'True') {
array_push($selection['fields'], array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_CVV,
'field' => zen_draw_input_field('itransact_cc_cvv', '', 'size="4" maxlength="3"') . ' <small>' . MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_CVV_LOCATION . '</small>'));
}
} else {
$selection = array('id' => $this->code,
'module' => $this->title);
}
return $selection;
}
function pre_confirmation_check() {
global $_POST;
if (strstr(MODULE_PAYMENT_ITRANSACT_FORMAT, 'Standard')) {
include(DIR_WS_CLASSES . 'cc_validation.php');
$cc_validation = new cc_validation();
$result = $cc_validation->validate($_POST['itransact_cc_number'], $_POST['itransact_cc_expires_month'], $_POST['itransact_cc_expires_year']);
$error = '';
switch ($result) {
case -1:
$error = sprintf(TEXT_CCVAL_ERROR_UNKNOWN_CARD, substr($cc_validation->cc_number, 0, 4));
break;
case -2:
case -3:
case -4:
$error = TEXT_CCVAL_ERROR_INVALID_DATE;
break;
case false:
$error = TEXT_CCVAL_ERROR_INVALID_NUMBER;
break;
}
if ( ($result == false) || ($result < 1) ) {
$payment_error_return = 'payment_error=' . $this->code . '&error=' . urlencode($error) . '&itransact_cc_expires_month=' . $_POST['itransact_cc_expires_month'] . '&itransact_cc_expires_year=' . $_POST
['itransact_cc_expires_year'] . '&itransact_cc_cvv=' . urlencode($_POST['itransact_cc_cvv']);
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, $payment_error_return, 'SSL', true, false));
}
$this->cc_card_type = $cc_validation->cc_type;
$this->cc_card_number = $cc_validation->cc_number;
$this->cc_expiry_month = $cc_validation->cc_expiry_month;
$this->cc_expiry_year = $cc_validation->cc_expiry_year;
}
}
function confirmation() {
global $_POST;
if (strstr(MODULE_PAYMENT_ITRANSACT_FORMAT, 'Standard')) {
$confirmation = array('title' => $this->title . ': ' . $this->cc_card_type,
'fields' => array(array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_NUMBER,
'field' => substr($this->cc_card_number, 0, 4) . str_repeat('X', (strlen($this->cc_card_number) - 8)) . substr($this->cc_card_number, -4)),
array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_EXPIRES,
'field' => strftime('%B, %Y', mktime(0,0,0,$_POST['itransact_cc_expires_month'], 1, '20' . $_POST['itransact_cc_expires_year'])))));
if (zen_not_null($_POST['itransact_cc_cvv'])) {
array_push($confirmation['fields'], array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_CVV,
'field' => $_POST['itransact_cc_cvv']));
}
}
return $confirmation;
}
function process_button() {
//global $HTTP_SERVER_VARS, $order, $customer_id, $_POST;
global $order, $customer_id, $_POST;
$process_button_string = zen_draw_hidden_field('vendor_id', MODULE_PAYMENT_ITRANSACT_VENDOR_ID) .
zen_draw_hidden_field('home_page', zen_href_link(FILENAME_ACCOUNT_HISTORY, '', 'SSL'));
if (strstr(MODULE_PAYMENT_ITRANSACT_FORMAT, 'Standard')) {
$process_button_string .= zen_draw_hidden_field('ret_addr', zen_href_link(FILENAME_CHECKOUT_PROCESS, '', 'SSL', false));
} else {
$process_button_string .= zen_draw_hidden_field('osc-ret_addr', zen_href_link(FILENAME_CHECKOUT_PROCESS, '', 'SSL', false)) .
zen_draw_hidden_field('passback', 'osc-ret_addr') .
zen_draw_hidden_field('osc-decl_addr', zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(MODULE_PAYMENT_ITRANSACT_TEXT_DECLINED_MESSAGE), 'SSL', true, false)) .
zen_draw_hidden_field('passback', 'osc-decl_addr') .
zen_draw_hidden_field('osc-succ_addr', zen_href_link(FILENAME_CHECKOUT_SUCCESS, '', 'SSL')) .
zen_draw_hidden_field('passback', 'osc-succ_addr') .
zen_draw_hidden_field('osc-err_addr', zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(MODULE_PAYMENT_ITRANSACT_TEXT_ERROR_MESSAGE), 'SSL', true, false)) .
zen_draw_hidden_field('passback', 'osc-err_addr') .
zen_draw_hidden_field('ret_addr', 'https://secure.paymentclearing.com/osc/ret/');
}
$process_button_string .= zen_draw_hidden_field('1_desc', STORE_NAME . ' Order Total') .
zen_draw_hidden_field('1_cost', number_format($order->info['total'], 2, '.', '')) .
zen_draw_hidden_field('1_qty', '1'); // *_anything showaddr
if (MODULE_PAYMENT_ITRANSACT_CVV == 'True') {
if (strstr(MODULE_PAYMENT_ITRANSACT_FORMAT, 'Standard')) {
$process_button_string .= zen_draw_hidden_field('cvv2_number', $_POST['itransact_cc_cvv']);
} else {
$process_button_string .= zen_draw_hidden_field('showcvv', '1');
}
}
$process_button_string .= zen_draw_hidden_field('mername', STORE_NAME) .
zen_draw_hidden_field('acceptcards', '1') .
zen_draw_hidden_field('acceptchecks', '0') .
zen_draw_hidden_field('accepteft', '0') .
zen_draw_hidden_field('altaddr', '0') .
zen_draw_hidden_field('nonum', '1') .
// preauth
zen_draw_hidden_field('ret_mode', 'post') .
zen_draw_hidden_field('post_back_on_error', '1') . // check_num check_memo
zen_draw_hidden_field('passback', zen_session_name()) . // lookup email_text
zen_draw_hidden_field('first_name', $order->billing['firstname']) .
zen_draw_hidden_field('last_name', $order->billing['lastname']) .
zen_draw_hidden_field('address', $order->billing['street_address']) .
zen_draw_hidden_field('city', $order->billing['city']) .
zen_draw_hidden_field('state', $order->billing['state']) .
zen_draw_hidden_field('zip', $order->billing['postcode']) .
zen_draw_hidden_field('country', $order->billing['country']['title']) .
zen_draw_hidden_field('phone', $order->customer['telephone']) .
zen_draw_hidden_field('email', $order->customer['email_address']);
if (strstr(MODULE_PAYMENT_ITRANSACT_FORMAT, 'Standard')) {
$process_button_string .= zen_draw_hidden_field('ccnum', $this->cc_card_number) .
zen_draw_hidden_field('ccmo', strftime('%B',mktime(0,0,0,$this->cc_expiry_month,1,2000))) .
zen_draw_hidden_field('ccyr', $this->cc_expiry_year); // aba account
}
$process_button_string .= zen_draw_hidden_field('sfname', $order->delivery['firstname']) .
zen_draw_hidden_field('slname', $order->delivery['lastname']) .
zen_draw_hidden_field('saddr', $order->delivery['street_address']) .
zen_draw_hidden_field('scity', $order->delivery['city']) .
zen_draw_hidden_field('sstate', $order->delivery['state']) .
zen_draw_hidden_field('szip', $order->delivery['postcode']) .
zen_draw_hidden_field('sctry', $order->delivery['country']['title']);
$process_button_string .= zen_draw_hidden_field(zen_session_name(), zen_session_id());
return $process_button_string;
}
function before_process() {
//global $HTTP_SERVER_VARS, $_POST;
global $_POST;
if (in_array($_SERVER['REMOTE_ADDR'], gethostbynamel("osc-ret.itransact.com"))) {
if (isset($_POST['die'])) {
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(MODULE_PAYMENT_ITRANSACT_TEXT_ERROR_MESSAGE), 'SSL', true, false));
} else if (isset($_POST['err'])) {
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(MODULE_PAYMENT_ITRANSACT_TEXT_DECLINED_MESSAGE), 'SSL', true, false));
} else if (isset($_POST['signature'])) {
return;
} else {
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(MODULE_PAYMENT_ITRANSACT_TEXT_ERROR_MESSAGE), 'SSL', true, false));
}
} else {
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(MODULE_PAYMENT_ITRANSACT_TEXT_ERROR_MESSAGE), 'SSL', true, false));
}
}
function after_process() {
return false;
}
function get_error() {
global $_GET;
$error = array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_ERROR,
'error' => stripslashes(urldecode($_GET['error'])));
return $error;
}
function check() {
global $db;
if (!isset($this->_check)) {
$check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_ITRANSACT_STATUS'");
$this->_check = $check_query->RecordCount();
}
return $this->_check;
}
function install() {
global $db;
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable iTransact,
inc. (<i>Credit Card</I>) Module', 'MODULE_PAYMENT_ITRANSACT_STATUS', 'True', 'Do you want to accept iTransact, inc. (<i>Credit Card</i>) payments?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Vendor ID',
'MODULE_PAYMENT_ITRANSACT_VENDOR_ID', '12345', 'The vendor ID used for the iTransact, inc. service', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Order Form
Format', 'MODULE_PAYMENT_ITRANSACT_FORMAT', 'Split', 'The order form format used for transactions', '6', '0', 'zen_cfg_select_option(array(\'Split\',\'Standard (Requires a SSL certificate)\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Allow CVV?',
'MODULE_PAYMENT_ITRANSACT_CVV', 'False', 'Allow customers to enter the CVV number from their credit card?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.',
'MODULE_PAYMENT_ITRANSACT_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values
('Payment Zone', 'MODULE_PAYMENT_ITRANSACT_ZONE', '0', 'If a zone is selected, only enable this payment method for that zone.', '6', '2', 'zen_get_zone_class_title', 'zen_cfg_pull_down_zone_classes(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set
Order Status', 'MODULE_PAYMENT_ITRANSACT_ORDER_STATUS_ID', '0', 'Set the status of orders made with this payment module to this value', '6', '0', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
}
function remove() {
global $db;
$db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
}
function keys() {
return array('MODULE_PAYMENT_ITRANSACT_STATUS', 'MODULE_PAYMENT_ITRANSACT_VENDOR_ID', 'MODULE_PAYMENT_ITRANSACT_FORMAT', 'MODULE_PAYMENT_ITRANSACT_CVV', 'MODULE_PAYMENT_ITRANSACT_ZONE', 'MODULE_PAYMENT_ITRANSACT_ORDER_STATUS_ID',
'MODULE_PAYMENT_ITRANSACT_SORT_ORDER');
}
}
?>
Re: Porting osCommerce iTransact CC Module
My hunch is that I need to change the https address, here on line# 183:
Code:
zen_draw_hidden_field('ret_addr', 'https://secure.paymentclearing.com/osc/ret/');
But I don't know what to change it to.
Any tips at all would be greatly appreciated.
Thanks,
Wulf
Re: Porting osCommerce iTransact CC Module
OK, for a successful transaction I believe the correct return address (ret_addr) is supposed to be:
Code:
zen_draw_hidden_field('ret_addr', 'https://your_domain_address/zencart_store_directory/index.php?main_page=checkout_success');
Wireshark isn't proving to be as helpful as I'd hoped but it's better than nothing. At least I can watch the transaction flow and know which machine I'm hitting and when it talks back to my server and then see how Zen Cart reacts.
Any feedback from others who've struggled with porting an osCommerce module for Zen Cart would be most appreciated.
Re: Porting osCommerce iTransact CC Module
No, the correct address is checkout_process, but if you set your module into 'Standard' mode, it'll do that automatically for you ... at least, that's what I glean from reading the code you posted.
The other mode (not 'Standard') appears to do something specific to osC, so I have no idea what that's about, and can't speak to whether it should work or not, or whether it's reliable.
Re: Porting osCommerce iTransact CC Module
Thanks for the response but even with the change suggested above I was still getting the "Whoops! You can't do that..." error. So, I went back to the original iTransact module that had been modified ages ago by a guy named "Merlin" and went ahead and ported it per the guidelines for porting osCommerce modules to Zen Cart...and am getting interesting results.
Here is the ported code:
Code:
<?php
/*
osCommerce, Open Source E-Commerce Solutions
http://www.oscommerce.com
Copyright (c) 2003 osCommerce
iTransact, inc. (RediCharge) Module v1.0
Copyright (c) 2003 react Ltd.
http://react.co.nz
Modified to work with Zen cart by Merlin
Released under the GNU General Public License
*/
class itransact {
var $code, $title, $description, $enabled;
// class constructor
function itransact() {
global $order;
$this->code = 'itransact';
$this->title = MODULE_PAYMENT_ITRANSACT_TEXT_TITLE;
$this->description = MODULE_PAYMENT_ITRANSACT_TEXT_DESCRIPTION;
$this->enabled = ((MODULE_PAYMENT_ITRANSACT_STATUS == 'True') ? true : false);
$this->sort_order = MODULE_PAYMENT_ITRANSACT_SORT_ORDER;
if ((int)MODULE_PAYMENT_ITRANSACT_ORDER_STATUS_ID > 0) {
$this->order_status = MODULE_PAYMENT_ITRANSACT_ORDER_STATUS_ID;
}
if (is_object($order)) $this->update_status();
$this->form_action_url = 'https://secure.paymentclearing.com/cgi-bin/rc/ord.cgi';
}
// class methods
function update_status() {
global $order, $db;
if ( ($this->enabled == true) && ((int)MODULE_PAYMENT_ITRANSACT_ZONE > 0) ) {
$check_flag = false;
$check_query = $db->Execute("select zone_id from " . TABLE_ZONES_TO_GEO_ZONES . " where geo_zone_id = '" . MODULE_PAYMENT_ITRANSACT_ZONE . "' and zone_country_id = '" . $order->billing['country']['id'] . "' order by zone_id");
while (!$check_query) {
if ($check['zone_id'] < 1) {
$check_flag = true;
break;
} elseif ($check['zone_id'] == $order->billing['zone_id']) {
$check_flag = true;
break;
}
}
if ($check_flag == false) {
$this->enabled = false;
}
}
}
function javascript_validation() {
$js = ' if (payment_value == "' . $this->code . '") {' . "\n" .
' var cc_number = document.checkout_payment.itransact_cc_number.value;' . "\n" .
' if (cc_number == "" || cc_number.length < ' . CC_NUMBER_MIN_LENGTH . ') {' . "\n" .
' error_message = error_message + "' . MODULE_PAYMENT_ITRANSACT_TEXT_JS_CC_NUMBER . '";' . "\n" .
' error = 1;' . "\n" .
' }' . "\n" .
' }' . "\n";
return $js;
}
function selection() {
global $order;
for ($i=1; $i<13; $i++) {
$expires_month[] = array('id' => sprintf('%02d', $i), 'text' => strftime('%B',mktime(0,0,0,$i,1,2000)));
}
$today = getdate();
for ($i=$today['year']; $i < $today['year']+10; $i++) {
$expires_year[] = array('id' => strftime('%y',mktime(0,0,0,1,1,$i)), 'text' => strftime('%Y',mktime(0,0,0,1,1,$i)));
}
$selection = array('id' => $this->code,
'module' => $this->title,
'fields' => array(array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_NUMBER,
'field' => zen_draw_input_field('itransact_cc_number')),
array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_EXPIRES,
'field' => zen_draw_pull_down_menu('itransact_cc_expires_month', $expires_month) . ' ' . zen_draw_pull_down_menu('itransact_cc_expires_year', $expires_year))));
return $selection;
}
function pre_confirmation_check() {
global $_POST;
include(DIR_WS_CLASSES . 'cc_validation.php');
$cc_validation = new cc_validation();
$result = $cc_validation->validate($_POST['itransact_cc_number'], $_POST['itransact_cc_expires_month'], $_POST['itransact_cc_expires_year']);
$error = '';
switch ($result) {
case -1:
$error = sprintf(TEXT_CCVAL_ERROR_UNKNOWN_CARD, substr($cc_validation->cc_number, 0, 4));
break;
case -2:
case -3:
case -4:
$error = TEXT_CCVAL_ERROR_INVALID_DATE;
break;
case false:
$error = TEXT_CCVAL_ERROR_INVALID_NUMBER;
break;
}
if ( ($result == false) || ($result < 1) ) {
$payment_error_return = 'payment_error=' . $this->code . '&error=' . urlencode($error) . '&itransact_cc_owner=' . urlencode($_POST['itransact_cc_owner']) . '&itransact_cc_expires_month=' . $_POST['itransact_cc_expires_month'] . '&itransact_cc_expires_year=' . $_POST['itransact_cc_expires_year'];
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, $payment_error_return, 'SSL', true, false));
}
$this->cc_card_type = $cc_validation->cc_type;
$this->cc_card_number = $cc_validation->cc_number;
$this->cc_expiry_month = $cc_validation->cc_expiry_month;
$this->cc_expiry_year = $cc_validation->cc_expiry_year;
}
function confirmation() {
global $_POST;
$confirmation = array('title' => $this->title . ': ' . $this->cc_card_type,
'fields' => array(array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_NUMBER,
'field' => substr($this->cc_card_number, 0, 4) . str_repeat('X', (strlen($this->cc_card_number) - 8)) . substr($this->cc_card_number, -4)),
array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_CREDIT_CARD_EXPIRES,
'field' => strftime('%B, %Y', mktime(0,0,0,$_POST['itransact_cc_expires_month'], 1, '20' . $_POST['itransact_cc_expires_year'])))));
return $confirmation;
}
function process_button() {
global $_SERVER, $order, $customer_id;
$process_button_string = zen_draw_hidden_field('vendor_id', MODULE_PAYMENT_ITRANSACT_VENDOR_ID) .
zen_draw_hidden_field('home_page', zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL')) .
zen_draw_hidden_field('ret_addr', zen_href_link(FILENAME_CHECKOUT_PROCESS, '', 'SSL', false)) .
zen_draw_hidden_field('1_desc', STORE_NAME) .
zen_draw_hidden_field('1_cost', number_format($order->info['total'], 2)) .
zen_draw_hidden_field('1_qty', '1') . // *_anything
zen_draw_hidden_field('post_back_on_error', '1') . // check_num check_memo
zen_draw_hidden_field('passback', zen_session_name()) . // lookup email_text
zen_draw_hidden_field('first_name', $order->billing['firstname']) .
zen_draw_hidden_field('last_name', $order->billing['lastname']) .
zen_draw_hidden_field('address', $order->billing['street_address']) .
zen_draw_hidden_field('city', $order->billing['city']) .
zen_draw_hidden_field('state', $order->billing['state']) .
zen_draw_hidden_field('zip', $order->billing['postcode']) .
zen_draw_hidden_field('country', $order->billing['country']['title']) .
zen_draw_hidden_field('phone', $order->customer['telephone']) .
zen_draw_hidden_field('email', $order->customer['email_address']) .
zen_draw_hidden_field('ccnum', $this->cc_card_number) .
zen_draw_hidden_field('ccmo', strftime('%B',mktime(0,0,0,$this->cc_expiry_month,1,2000))) .
zen_draw_hidden_field('ccyr', $this->cc_expiry_year) . // aba account
zen_draw_hidden_field('sfname', $order->delivery['firstname']) .
zen_draw_hidden_field('slname', $order->delivery['lastname']) .
zen_draw_hidden_field('saddr', $order->delivery['street_address']) .
zen_draw_hidden_field('scity', $order->delivery['city']) .
zen_draw_hidden_field('sstate', $order->delivery['state']) .
zen_draw_hidden_field('szip', $order->delivery['postcode']) .
zen_draw_hidden_field('sctry', $order->delivery['country']['title']);
$process_button_string .= zen_draw_hidden_field(zen_session_name(), zen_session_id());
return $process_button_string;
}
function before_process() {
global $_SERVER, $_POST;
if ($_SERVER['REMOTE_ADDR'] == MODULE_PAYMENT_ITRANSACT_IP_ADDRESS) {
if (isset($_POST['signature'])) {
if (isset($_POST['err'])) {
// declined
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(MODULE_PAYMENT_ITRANSACT_TEXT_DECLINED_MESSAGE), 'SSL', true, false));
} else if (!isset($_POST['die'])) {
// got signature and no err or die, assume good
return;
}
}
}
// bad IP, no signature or internal error
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(MODULE_PAYMENT_ITRANSACT_TEXT_ERROR_MESSAGE), 'SSL', true, false));
}
function after_process() {
return false;
}
function get_error() {
global $_GET;
$error = array('title' => MODULE_PAYMENT_ITRANSACT_TEXT_ERROR,
'error' => stripslashes(urldecode($_GET['error'])));
return $error;
}
function check() {
global $db;
if (!isset($this->_check)) {
$check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_ITRANSACT_STATUS'");
$this->_check = $check_query->RecordCount();
}
return $this->_check;
}
function install() {
global $db;
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable iTransact, inc. (<i>RediCharge</I>) Module', 'MODULE_PAYMENT_ITRANSACT_STATUS', 'True', 'Do you want to accept iTransact, inc. (<i>RediCharge</i>) payments?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Vendor ID', 'MODULE_PAYMENT_ITRANSACT_VENDOR_ID', '12345', 'The vendor ID used for the iTransact, inc. service', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('IP Address', 'MODULE_PAYMENT_ITRANSACT_IP_ADDRESS', '65.113.114.142', 'The IP address used for the iTransact, inc. form posts', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_ITRANSACT_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Payment Zone', 'MODULE_PAYMENT_ITRANSACT_ZONE', '0', 'If a zone is selected, only enable this payment method for that zone.', '6', '2', 'zen_get_zone_class_title', 'zen_cfg_pull_down_zone_classes(', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Order Status', 'MODULE_PAYMENT_ITRANSACT_ORDER_STATUS_ID', '0', 'Set the status of orders made with this payment module to this value', '6', '0', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
}
function remove() {
global $db;
$db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
}
function keys() {
return array('MODULE_PAYMENT_ITRANSACT_STATUS', 'MODULE_PAYMENT_ITRANSACT_VENDOR_ID', 'MODULE_PAYMENT_ITRANSACT_IP_ADDRESS', 'MODULE_PAYMENT_ITRANSACT_ZONE', 'MODULE_PAYMENT_ITRANSACT_ORDER_STATUS_ID', 'MODULE_PAYMENT_ITRANSACT_SORT_ORDER');
}
}
?>
My transactions are successful, however, iTransact is returning somesort of PGP (Pretty Good Password) string which includes the return URL of my store and Zen Cart rightly then reports a "Page Not Found" error.
Here's what I am getting back (with my real IP address and domain info removed by me):
Code:
http://my_store_domain/zencart/index.php?main_page=checkout_process?zenid=u16daqg4bgdrubac824e5jbfd2&signature=-----BEGIN%20PGP%20SIGNED%20MESSAGE-----%0A%0Ahttp%3A%2F%2Fmy_store_domain%2Fzencart%2Findex.php%3Fmain_page%3Dcheckout_process%3Fzenid%3Du16daqg4bgdrubac824e5jbfd2%0A-----BEGIN%20PGP%20SIGNATURE-----%0AVersion%3A%202.6.3ia%0ACharset%3A%20noconv%0A%0AiQCVAwUBS90CW7HOJqLFYyxlAQGKIwQAqOkwInu9vJGQCEV%2Flx9e5zRm1wK9DCGT%0AKSRjX5N4MTSg2%2FLXQDkf8%2FSyYYlNisjDZvZHr73a0PwxrZ%2BJhJuRgOvQdsDWLN4H%0A8ytOfYhDi1t2HwaW%2F9qe4kBvqdvEsNLGafqeWKGYokOy%2BPHl8q9EmV%2FGHpFI97Gx%0AvfLX%2FhHT7B8%3D%0A%3DCUi8%0A-----END%20PGP%20SIGNATURE-----%0A
Does this make sense to anyone? Does it have anything to do with the SSL settings/options in the code posted above?
Any feedback would be most appreciated.
Thanks,
Wulf
Re: Porting osCommerce iTransact CC Module
Breakthrough (I hope)!
As it turns out, iTransact's return function uses PGP (Pretty Good Privacy) ON ALL TRANSACTIONS which use the PASSBACK or LOOKUP functions, and my module uses PASSBACK!
After reading this requirement today I realized that my server doesn't have PGP installed on it, so there's no way to handle the PGP signature that's being sent back! D'OH!
Their PGP requirements and public key are listed here:
http://itransact.com/support/pgp.html
So, I just need to find a PGP install for Debian, figure out how the bloody system works, install it on my server and then see what the hell happens!
I'll post back here with details once I have some PGP test results.
Wulf
Re: Porting osCommerce iTransact CC Module
Blast. No luck. We installed PGP on our server but that didn't have any effect on stripping out the PGP signature that comes back. So, it appears we will have to write an intermediate landing page of somesort with a script on it using regular expressions to strip out the PGP stuff and then pass the cleaned url to the checkout_process page for handling all the transaction completion stuff.
Yes, this is an ugly hack, but we can't find anyone who can tell us how to properly interface Zen Cart with the PGP functions of the iTransact gateway, so it appears that we don't really have much choice.
Re: Porting osCommerce iTransact CC Module
You could use the iTransact SOAP API instead of their passback/lookup services. It's probably MUCH more efficient and secure anyway.
Re: Porting osCommerce iTransact CC Module
SOAP? I can't find any mention of this at the iTransact developer site:
http://itransact.com/support/toolkit.html
Do you have a link that you can post to their SOAP API?
Re: Porting osCommerce iTransact CC Module
Sorry, I meant to say XML. The link to their XML API is on the page you quoted.