<?php
/***************************************************************************
*                                                                          *
* Copyright (c) 2005 ISPG Technologies (I) Pvt Ltd. All rights reserved.   *
*                                                                          *
* This  is  commercial  software,  only  users  who have purchased a valid *
* license  and  accept  to the terms of the  License Agreement can install *
* and use this program.                                                    *
*                                                                          *
****************************************************************************
* PLEASE READ THE FULL TEXT  OF THE SOFTWARE  LICENSE   AGREEMENT  IN  THE *
* "copyright.txt" FILE PROVIDED WITH THIS DISTRIBUTION PACKAGE.            *
****************************************************************************/
 //
 //$Id: AuthorizeModel.php, v 1.0 2011/06/14 20:52:11
 
//
class AuthorizeModel extends PaymentModel{ 
//Function to Process to orders		
	public function process($order='',$orderItems='') 
	{
			$ObjCurrency		= new CurrencyModel();
			$ObjCountry    	 	= new CountryModel();
			$ObjState       	= new StateModel();
			parent::listPaymentSettingsValues($order['paymentSettingsGroupID']);		
			$address       		= 	$order['billingAddress']['billingAddress1'];
        	$address       		.= 	($order['billingAddress']['billingAddress2']!='') ? ', '.$order['billingAddress']['billingAddress2'] : '';
			$payAmount			=	$order['orderTotalAmount'];
			$taxAmount			=	$order["orderTaxAmount"];
			$shippingAmount		=	$order["shippingAmount"];
			$serviceCharge   	= 	$order["orderOtherServiceCharge"];
			$orderPromoDiscountAmount 	= $order["orderPromoDiscountAmount"];
			$orderUserCreditAmount 		= $order["orderUserCreditAmount"];
			$supportedCurrencyID	= $order["purchasedCurrency"];
			$paymentCurrency	=	$this->settingsVars["payment_currency"];
			
			$currencyArr	=	'';
			$itemsArray  	= '';
			$itemCounter	=	1;
			
			if ($paymentCurrency != '')
        	{
            	$paymentCurrency = str_replace(", ", ",", $paymentCurrency);
            	$currencyArr     = explode(",", $paymentCurrency);
        	}
			if(count($currencyArr)<1)
			{
				$this->isError 		= true;
				$this->errorMessage	= "Currency not configured , Please contact the site admin";
				return false;
			}
			else
			{
				$currencyFlag = false;
				$purchasedCurrencyDetails 	= $ObjCurrency->getCurrencyByCurrencyID($order["purchasedCurrency"]);
				$currencyCode				= $purchasedCurrencyDetails['currencyCode'];
				$systemCurrencies 			=	$ObjCurrency->listCurrencyCodes();
				if(!in_array($purchasedCurrencyDetails['currencyCode'],$currencyArr))
				{
					foreach ($systemCurrencies as $key => $currency)
        			{
						if(in_array($currency['currencyCode'],$currencyArr))
						{
							$currencyFlag = true;
							$supportedCurrencyCode 	= $currency['currencyCode'];	
							$supportedCurrencyID 	= $currency['currencyID'];
							break;
						}
					}
					if($currencyFlag==true)
					{
						$payAmount = $ObjCurrency->convertValueCustom($payAmount,$order["purchasedCurrency"],$supportedCurrencyID);
						$taxAmount = $ObjCurrency->convertValueCustom($taxAmount,$order["purchasedCurrency"],$supportedCurrencyID);
						$shippingAmount = $ObjCurrency->convertValueCustom($shippingAmount,$order["purchasedCurrency"],
						$supportedCurrencyID);
						$serviceCharge = $ObjCurrency->convertValueCustom($serviceCharge,$order["purchasedCurrency"],
						$supportedCurrencyID);
						$orderPromoDiscountAmount = $ObjCurrency->convertValueCustom($orderPromoDiscountAmount
						,$order["purchasedCurrency"],$supportedCurrencyID);
						$orderUserCreditAmount = $ObjCurrency->convertValueCustom($orderUserCreditAmount
						,$order["purchasedCurrency"],$supportedCurrencyID);
						$currencyCode		=	$supportedCurrencyCode;
					}
					else
					{
						$this->isError 		= true;
						$this->errorMessage	= "Currency not configured , Please contact the site admin";
						return false;
					}
					
				}
			}
			
			if($payAmount<.01)
			{
				$this->isError 		= true;
				$this->errorMessage	= "Invalid amount , please use another method";
				return false;
			}
			
			$languageIDs['Current']=1;
			$country 		= $ObjCountry->getCountryDetails($order['billingAddress']['billingCountry'],$languageIDs);
			$countryName 	= $country['countryName'];
			if ($order['billingAddress']['billingState'] >0)
			{
				$getStateDetails = $ObjState->getStateDetails($languageIDs,$order['billingAddress']['billingState']);
				$stateName       = $getStateDetails['stateShortName'];
			}
			else
			{
				$stateName = $order['billingAddress']['billingProvince'];
			}
			
			$postData 				= 	"";
			$postData				= 	"".
			//form data
			"x_first_name		=	".urlencode($order['postData']["creditCardFirstName"]).
			"&x_last_name		=	".urlencode($order['postData']["creditCardLastName"]).
			"&x_card_num		=	".urlencode($order['postData']["creditCardNumber"]).
			"&x_card_code		=	".urlencode($order['postData']["securityCode"]).
			"&x_exp_date		=	".urlencode($order['postData']["expMonth"]."/".$order['postData']["expYear"]). 
				
			"&x_address			=	".urlencode($address).
			"&x_company			=   ".$order['siteDesc']."
			&x_city			    =	".urlencode($order['billingAddress']["billingCity"]).
			"&x_state			=	".$stateName.
			"&x_zip				=	".urlencode($order['billingAddress']["billingZip"]).
			"&x_country			=	".$countryName.
			"&x_email			=	".urlencode($order['billingAddress']["billingEmail"]).		
			"&x_phone			=	".urlencode($order['billingAddress']["billingPhone"])."";		
			
			if(isset($order['shippingAddress']['shippingCountryID']) && $order['shippingAddress']['shippingCountryID']>0)
			{
				$languageIDs['Current']=1;
				$country 		= $ObjCountry->getCountryDetails($order['shippingAddress']['shippingCountryID'],$languageIDs);
				$countryName 	= $country['countryName'];
				if (isset($order['shippingAddress']['shippingStateID']) && $order['shippingAddress']['shippingStateID'] >0)
				{
					$getStateDetails = $ObjState->getStateDetails($languageIDs,$order['shippingAddress']['shippingStateID']);
					$stateName       = $getStateDetails['stateShortName'];
				}
				else
				{
					$stateName = $order['shippingAddress']['shippingProvince'];
				}
				
				//Shipping data
				$postData	.="&x_ship_to_address	=	".urlencode($order['shippingAddress']["shippingAddress1"]).
				"&x_ship_to_country	    =	".$countryName.
				"&x_ship_to_company		=   ".$order['siteDesc'].
				"&x_ship_to_city	    =	".urlencode($order['shippingAddress']["shippingCity"]).
				"&x_ship_to_first_name	=	".urlencode($order['shippingAddress']["shippingFname"]).
				"&x_ship_to_last_name	=	".urlencode($order['shippingAddress']["shippingLname"]).
				"&x_ship_to_zip			=	".urlencode($order['shippingAddress']["shippingZip"]).
				"&x_ship_to_state		=	".$stateName;
			}
			if (!empty($orderItems))
			{
				foreach ($orderItems as $key => $ordItem)
				{
					$orderGiveAsGift = '';
					$itemsDelimitter ='';
					$itemTaxable='N';
					if($currencyFlag==true) 
					{
						$ordItem['orderItemSubtotal']	=	$ObjCurrency->convertValueCustom($ordItem['orderItemSubtotal'],
						$order["purchasedCurrency"],$supportedCurrencyID);
					
						$ordItem['orderItemPrice'] 		=	$ObjCurrency->convertValueCustom($ordItem['orderItemPrice']
						,$order["purchasedCurrency"],$supportedCurrencyID);
					}
					if($taxAmount>0)
					{
						$itemTaxable='Y';	
					}
					if (isset($ordItem['orderGiveAsGift']) && $ordItem['orderGiveAsGift'] == 'Yes')
					{
						$orderGiveAsGift = ' (As Gift)';
					}
					$fldName = ($order['orderType'] == 'product') ? 'productOptionName' : 'itemName';
					
					if($itemCounter>1 && count($orderItems)>1)
					{
						$itemsDelimitter ="&";	
					}					
					//Format : x_line_item=Item ID<|>item name<|>item description<|>item quantity<|>price<|>taxable
					// item name limit is 31
					$itemsArray = $itemsArray."&x_line_item=Item" .$itemCounter. "<|>".urlencode(substr($ordItem[$fldName], 0, 31))."<|>". $orderGiveAsGift ."<|>" .number_format($ordItem['orderItemQuantity'], 2, ".", "") . "<|>".number_format($ordItem['orderItemPrice'], 2, ".", "")."<|>".$itemTaxable;									
					
					$itemCounter++;
					
				}
				
			}
		
			//Pass Discount variables
			if ($order['orderPromoDiscountAmount'] > 0)
			{
				$orderPromoDiscountAmount = number_format($orderPromoDiscountAmount, 2, ".", "");
				$itemsArray .= "&x_line_item=Item" . $itemCounter . "<|>Promo Code Discount<|><|>1<|>
				".$orderPromoDiscountAmount."<|>N";
				$itemCounter++;
				
			}
			if ($order['orderUserCreditAmount'] > 0)
			{
				$orderUserCreditAmount = number_format($orderUserCreditAmount, 2, ".", "");
				$itemsArray .= "&x_line_item=Item" . $itemCounter . "<|>User Credit Discount<|><|>1<|>"
				.$orderUserCreditAmount."<|>N";
				$itemCounter++;

			}
			$postData = $postData.$itemsArray;		
			$postData = $postData.	
				//order data
				"&x_invoice_num		=	".urlencode($order["masterOrderID"]).
				"&x_po_num			=	".urlencode($order["masterOrderID"]).
				"&x_amount			=	".urlencode(number_format($payAmount, 2, ".", "")).
				"&x_tax				=	".urlencode(number_format($taxAmount, 2, ".", ""));
				if($shippingAmount>0)
				{
					$postData = $postData."&x_freight				=	".urlencode(number_format($shippingAmount, 2, ".", ""));
					
				}
				$postData = $postData."&x_duty				=	".urlencode(number_format($serviceCharge, 2, ".", "")).	
				//setting from admin area
				"&x_login			=	".urlencode($this->settingsVars["payment_login"]).
				"&x_tran_key		=	".urlencode($this->settingsVars["payment_transaction_key"]).
				"&x_test_request	=	".urlencode($this->settingsVars["payment_test"]).
				//advanced gateway data
				"&x_type			=	".urlencode($order['authValue']).
				"&x_delim_char		=	".urlencode("~").
				"&x_delim_data		=	".urlencode("True").
				"&x_version			=	".urlencode("3.1").
				"&x_relay_response	=	".urlencode("False").
				"&x_method			=	".urlencode("CC").
				"&x_customer_ip		=	".urlencode($this->getIpAddress());
				//post data to authorize.net
				$postUrl 			= 	trim($this->settingsVars["payment_gateway_url"])==""?"https://secure.authorize.net/gateway/transact.dll":trim($this->settingsVars["payment_gateway_url"]);
				
				$buffer 			= 	$this->processCurl($postData, $postUrl);

				if($buffer) {					
					$data = explode("~", $buffer);	
					// Approved
					if ($data[0] == "1" || $data[0] == "4") {
						
						$dataResponse 	= 	str_replace("~", "\n", $buffer);
						$dataResponse 	= 	explode("\n", $dataResponse);			
						$transactionID	= 	$dataResponse[6];								
						$paymentMethodName			=	$this->settingsVars["payment_method_name"];
						parent::createTransaction($order,  $transactionID,
						str_replace("~", "\n", $buffer), "", $order['authValue'],
						0,$paymentMethodName,$supportedCurrencyID,$payAmount);						
						if($order['store_cc_info']=='Yes') {									
							parent::saveCCdata($order['postData'],$order["userID"]);
						}
						$this->isError = false;
						$this->errorMessage = "";
						return "Pending";
					} else {
						$this->isError = true;
						switch ($data[0]) {
							case "2" :
							{
								$this->errorMessage = "We are sorry, but this transaction has been declined.<br>Payment gateway response: ".$data[3];
								break;
							}
							case "3" :
							{
								$this->errorMessage = "We are sorry, but there has been an error processing this transaction.<br>Payment gateway response: ".$data[3];
								break;
							}
							default :
							{
								$this->errorMessage = "Error occured while processing...Please try later.";
								break;
							}
						}
					}
				} else {
					$this->isError = true;
					$this->errorMessage = "Incorrect form params. Please contact site administartor.";
				}
				return !$this->isError;
		
	}
//End of function

	public function processCustom($order='') {
			$ObjCurrency			= new CurrencyModel();
			parent::listPaymentSettingsValues($order['paymentSettingsGroupID']);
			$getPaymentTransactionDetails = parent::getPaymentTransactionDetails(0,
			$order["masterOrderID"]);
			$this->isError = false;
			//check is transaction completed
			if ($order["paymentType"] != "AUTH_ONLY" || $order["paymentStatus"]=='Received' )
			{
				$this->isError 		= true;
				$this->errorMessage = "Transaction already completed";
				return false;
			}
			//get captured total amount & x_trans_id
			$capturedTotalAmount = $getPaymentTransactionDetails['convertedPaymentAmount'];

			$payAmount				= $capturedTotalAmount;
			$transactionID			= $getPaymentTransactionDetails["transactionID"];
			$taxAmount				= (isset($order["finalTaxAmount"])?$order["finalTaxAmount"]:0);
			//process transaction
			$postData = 
				"x_version			=	".urlencode("3.1")."&".
				"x_delim_data		=	".urlencode("True")."&".
				"x_delim_char		=	".urlencode("~")."&".
				"x_relay_response	=	".urlencode("False")."&".
				"x_login			=	".urlencode($this->settingsVars["payment_login"])."&".
				"x_tran_key			=	".urlencode($this->settingsVars["payment_transaction_key"])."&".
				"x_amount			=	".urlencode(number_format($payAmount, 2, ".", ""))."&".
				"x_tax				=	".urlencode(number_format($taxAmount, 2, ".", ""))."&".
				"x_type				=	".urlencode("PRIOR_AUTH_CAPTURE")."&".
				"x_trans_id			=	".urldecode($transactionID)."&".
				"x_invoice_num		=	".urlencode($order["masterOrderID"])."&".
				"x_po_num			=	".urlencode($order["masterOrderID"])."&".
				"x_test_request		=	".urlencode($this->settingsVars["payment_test"]);
			$postUrl 				= 	trim($this->settingsVars["payment_gateway_url"])==""?"https://secure.authorize.net/gateway/transact.dll":trim($this->settingsVars["payment_gateway_url"]);
			$buffer 				= 	$this->processCurl($postData, $postUrl);
			if($buffer) {					
				$data 				= 	explode("~", $buffer);				
				if ($data[0] == "1") {
					$paymentMethodName			=	$this->settingsVars["payment_method_name"];
					parent::createTransaction($order,  $transactionID,"ORDER TYPE: PRIOR_AUTH_CAPTURE\n\n".str_replace("~", "\n", $buffer), "", "AUTH_CAPTURE",0,$paymentMethodName,$getPaymentTransactionDetails["paymentCurrencyID"],$payAmount);
					return "Success";
				} else {
					$this->logStart();
					$this->log($buffer,$this->settingsVars["payment_processor_id"]);
					$this->logFinish();
					$this->isError = true;
					switch ($data[0])
					{
						case "2" : 
						{
							$this->errorMessage = "We are sorry, but this transaction has been declined.<br>Payment gateway response: ".$data[3];
							break;
						}
						case "3" :
						{
							$this->errorMessage = "We are sorry, but there has been an error processing this transaction.<br>Payment gateway response: ".$data[3];
							break;
						}
						default :
						{
							$this->errorMessage = "Error occured while processing...Please try later.";
							break;
						}
					}
					
				}				
			}			
			return !$this->isError;
	}
	//Function to Process curl
	public function processCurl($postData, $postUrl)
	{
		$c = curl_init($postUrl);
		curl_setopt($c, CURLOPT_VERBOSE, 0);
		curl_setopt($c, CURLOPT_HEADER, 0);
		curl_setopt($c, CURLOPT_POSTFIELDS, $postData);
		curl_setopt($c, CURLOPT_POST, 1);
		curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($c, CURLOPT_SSL_VERIFYPEER, 1);
		if (!ini_get('safe_mode')) set_time_limit(3000);
		$buffer = curl_exec($c);
		if (curl_errno($c) > 0)
		{
			$this->isError = true;
			$this->errorMessage = curl_error($c);
			return false;
		}
		return !$buffer ? false : $buffer;
	}
	//End of function	
	
	
	//Function to Process Refund
	public function processRefund($order='',$postValues='') 
	{
		parent::listPaymentSettingsValues($postValues['paymentSettingsGroupID']);
		$ObjRefund			=	new RefundModel();
		$ObjCurrency		= new CurrencyModel();
		$totalAmount		=	$order['orderTotalAmount'];
		
		$supportedCurrencyID = $order["purchasedCurrency"];
		$paymentCurrency	 = $this->settingsVars["payment_currency"];
		
		if ($paymentCurrency != '')
		{
			$paymentCurrency = str_replace(", ", ",", $paymentCurrency);
			$currencyArr     = explode(",", $paymentCurrency);
		}
		if(count($currencyArr)<1)
		{
			$this->isError 		= true;
			$this->errorMessage	= "Currency not configured , Please contact the site admin";
			//return false;
		}
		else
		{
			$currencyFlag = false;
			$purchasedCurrencyDetails 	= $ObjCurrency->getCurrencyByCurrencyID($order["purchasedCurrency"]);
			$currencyCode				= $purchasedCurrencyDetails['currencyCode'];
			$systemCurrencies 			= $ObjCurrency->listCurrencyCodes();
			if(!in_array($purchasedCurrencyDetails['currencyCode'],$currencyArr))
			{
				foreach ($systemCurrencies as $key => $currency)
				{
					if(in_array($currency['currencyCode'],$currencyArr))
					{
						$currencyFlag = true;
						$supportedCurrencyCode 	= $currency['currencyCode'];	
						$supportedCurrencyID 	= $currency['currencyID'];
						break;
					}
				}
				if($currencyFlag==true)
				{
					$totalAmount = $ObjCurrency->convertValueCustom($totalAmount,$order["purchasedCurrency"],$supportedCurrencyID);
				}
				else
				{
					$this->isError 		= true;
					$this->errorMessage	= "Currency not configured , Please contact the site admin";
					//return false;
				}
			}
		}
		
		$request 			=	new AuthorizeNetTD;
		$useLive           	=	urlencode($this->settingsVars["payment_test"]);
        if ($useLive == "On") {
            $useLive = false;
        } else {
            $useLive = true;
        }
		$response 			=	$request->getTransactionDetails($postValues['apiPaymentTransactionID'],$useLive,$this->settingsVars["payment_login"],$this->settingsVars["payment_transaction_key"]);
		
		$creditCardNumber 	=	substr($response['transaction']['payment']['creditCard']['cardNumber'], -4);
		//$totalAmount		=	$response['transaction']['settleAmount'];
		
		$postUrl 			= 	trim($this->settingsVars["payment_gateway_url"])=="" ? "https://secure.authorize.net/gateway/transact.dll" : trim($this->settingsVars["payment_gateway_url"]);
		
		$masterOrderID		=	$postValues['masterOrderID'];
		$refundTransactionID=	$postValues['keyRefundTransactionID'];
			
		// set 'x_type' as 'void' to cancel non-settled transactions.
		$postData			= 	"".
		"x_login			=	".urlencode($this->settingsVars["payment_login"]).
		"&x_tran_key		=	".urlencode($this->settingsVars["payment_transaction_key"]).
		"&x_version			=	".urlencode("3.1").
		"&x_delim_char		=	".urlencode("~").
		"&x_delim_data		=	".urlencode("True").
		"&x_relay_response	=	".urlencode("False").
		"&x_type			=	".urlencode('VOID').
		"&x_trans_id		=	".urlencode($postValues['apiPaymentTransactionID']).
		"&x_card_num		=	".urlencode($creditCardNumber).
		"&x_exp_date		=	".urlencode($postValues["expMonth"]."/".$postValues["expYear"]). //"MM/YYYY" format used
		"&x_amount			=	".urlencode(number_format($totalAmount, 2, ".", "")).
		"&x_method			=	".urlencode("CC");

		$voidBuffer			= 	$this->processCurl($postData, $postUrl);
		
		if($voidBuffer){
			$voidData				=	explode("~", $voidBuffer);
			$voidDataResponse 		= 	'VOID Response: '.str_replace("~", "| ", $voidBuffer);
			if($voidData[0] == "1" || $voidData[0] == "4") {	// Approved
				$arrXnResponse['transactionID']	= 	$voidData[6];
				$arrXnResponse['refundResponse']=	$voidDataResponse;	//$buffer
				$arrXnResponse['refundAmount']	= 	$voidData[9];
				$resUpdateRefund	=	$ObjRefund->updateRefundTransaction('',$refundTransactionID,$arrXnResponse,$masterOrderID);
				$this->isError 		=	false;
				$this->errorMessage =	"";
				
				$this->voidSuccess	=	true;
			}
		}
		
		if(!$this->voidSuccess){
		
			$postData			= 	"".
			"x_login			=	".urlencode($this->settingsVars["payment_login"]).
			"&x_tran_key		=	".urlencode($this->settingsVars["payment_transaction_key"]).
			"&x_version			=	".urlencode("3.1").
			"&x_delim_char		=	".urlencode("~").
			"&x_delim_data		=	".urlencode("True").
			"&x_relay_response	=	".urlencode("False").
			"&x_type			=	".urlencode('credit').
			"&x_trans_id		=	".urlencode($postValues['apiPaymentTransactionID']).
			"&x_card_num		=	".urlencode($creditCardNumber).
			"&x_exp_date		=	".urlencode($postValues["expMonth"]."/".$postValues["expYear"]). //"MM/YYYY" format used
			"&x_amount			=	".urlencode(number_format($totalAmount, 2, ".", "")).
			"&x_method			=	".urlencode("CC");
					
			$buffer 			= 	$this->processCurl($postData, $postUrl);
			
			if($buffer) {
				$data 					=	explode("~", $buffer);
				$dataResponse 			= 	'REFUND Response: '.str_replace("~", "| ", $buffer);
				
				if($data[0] == "1" || $data[0] == "4") {	// Approved
					$arrXnResponse['transactionID']	= 	$data[6];
					$arrXnResponse['refundResponse']=	$dataResponse;	//$buffer
					$arrXnResponse['refundAmount']	= 	$data[9];
					$resUpdateRefund	=	$ObjRefund->updateRefundTransaction('',$refundTransactionID,$arrXnResponse,$masterOrderID);
					$this->isError 		=	false;
					$this->errorMessage =	"";
				} else {
					$arrXnResponse['transactionID']	= 	'';
					$arrXnResponse['refundResponse']=	$voidDataResponse.'<br/>'.$dataResponse;
					$arrXnResponse['refundAmount']	= 	'';
					$resUpdateRefund	=	$ObjRefund->updateRefundTransaction('',$refundTransactionID,$arrXnResponse,$masterOrderID);
					$this->isError 		=	true;
					switch ($data[0]) {
						case "2" :
							$this->errorMessage = "This transaction has been declined.<br>Payment gateway response: ".$data[3];
							break;
						case "3" :
							$this->errorMessage = "There has been an error processing this transaction.<br>Payment gateway response: ".$data[3];
							break;
						default :
							$this->errorMessage = "Error occured while processing...Please try later.";
							break;
					}
				}
			} else {
				$this->isError 		=	true;
				$this->errorMessage =	"Incorrect form params. Please contact site administartor.";
			}
		
		}
		return !$this->isError;
	}
	//End of function
}

class ArrayToXML {

    /**
     * The main function for converting to an XML document.
     * Pass in a multi dimensional array and this recrusively loops through and builds up an XML document.
     *
     * @param array $data
     * @param string $rootNodeName - what you want the root node to be - defaultsto data.
     * @param SimpleXMLElement $xml - should only be used recursively
     * @return string XML
     */
    public static function toXML($data, $rootNodeName = 'ResultSet', &$xml=null) {
        // turn off compatibility mode as simple xml throws a wobbly if you don't.
        if (ini_get('zend.ze1_compatibility_mode') == 1)
            ini_set('zend.ze1_compatibility_mode', 0);
        if (is_null($xml)) {
            $xml = simplexml_load_string("<$rootNodeName />");
            $rootNodeName = rtrim($rootNodeName, 's');
        }
        // loop through the data passed in.
        foreach ($data as $key => $value) {
            // no numeric keys in our xml please!
            $numeric = 0;
            if (is_numeric($key)) {
                $numeric = 1;
                $key = $rootNodeName;
            }
            // delete any char not allowed in XML element names
            $key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
            // if there is another array found recursively call this function
            if (is_array($value)) {
                $node = ( ArrayToXML::isAssoc($value) || $numeric ) ? $xml->addChild($key) : $xml;
                // recursive call.
                if ($numeric)
                    $key = 'anon';
                ArrayToXML::toXml($value, $key, $node);
            } else {
                // add single node.
                $value = htmlentities($value);
                $xml->addChild($key, $value);
            }
        }
        // pass back as XML
        return $xml->asXML();
        // if you want the XML to be formatted, use the below instead to return the XML

    }

    /**
     * Convert an XML document to a multi dimensional array
     * Pass in an XML document (or SimpleXMLElement object) and this recrusively loops through and builds a representative array
     *
     * @param string $xml - XML document - can optionally be a SimpleXMLElement object
     * @return array ARRAY
     */
    public static function toArray($xml) {
        if (is_string($xml))
            $xml = @new SimpleXMLElement($xml);
        $children = $xml->children();
        if (!$children)
            return (string) $xml;
        $arr = array();
        foreach ($children as $key => $node) {
            $node = ArrayToXML::toArray($node);
            // support for 'anon' non-associative arrays
            if ($key == 'anon')
                $key = count($arr);
            // if the node is already set, put it into an array
            if (array_key_exists($key, $arr) && isset($arr[$key])) {
                if (!is_array($arr[$key]) || !array_key_exists(0, $arr[$key]) || ( array_key_exists(0, $arr[$key]) && ($arr[$key][0] == null)))
                    $arr[$key] = array($arr[$key]);
                $arr[$key][] = $node;
            } else {
                $arr[$key] = $node;
            }
        }
        return $arr;
    }
    // determine if a variable is an associative array
    public static function isAssoc($array) {
        return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
    }
}

abstract class AuthorizeNetRequest
{
    protected $_api_login;
    protected $_transaction_key;
    protected $_post_string; 
    public $VERIFY_PEER = false; // Set to false if getting connection errors.
    protected $_sandbox = true;
    protected $_log_file = false;
    /**
     * Set the _post_string
     */
    abstract protected function _setPostString();
    /**
     * Handle the response string
     */
    abstract protected function _handleResponse($string);
    
    /**
     * Get the post url. We need this because until 5.3 you
     * you could not access child constants in a parent class.
     */
    abstract protected function _getPostUrl();
    
    /**
     * Constructor.
     *
     * @param string $api_login_id       The Merchant's API Login ID.
     * @param string $transaction_key The Merchant's Transaction Key.
     */
    public function __construct($api_login_id = false, $transaction_key = false)
    {

        $this->_sandbox = (defined('AUTHORIZENET_SANDBOX') ? AUTHORIZENET_SANDBOX : true);
        $this->_log_file = (defined('AUTHORIZENET_LOG_FILE') ? AUTHORIZENET_LOG_FILE : false);
    }
    
    /**
     * Alter the gateway url.
     *
     * @param bool $bool Use the Sandbox.
     */
    public function setSandbox($bool)
    {
        $this->_sandbox = $bool;
    }
    
    /**
     * Set a log file.
     *
     * @param string $filepath Path to log file.
     */
    public function setLogFile($filepath)
    {
        $this->_log_file = $filepath;
    }
    
    /**
     * Return the post string.
     *
     * @return string
     */
    public function getPostString()
    {
        return $this->_post_string;
    }
    
    /**
     * Posts the request to AuthorizeNet & returns response.
     *
     * @return AuthorizeNetARB_Response The response.
     */
    protected function _sendRequest($sandbox)
    {
        $this->_setPostString();
		if($sandbox)
		{
        $post_url = "https://apitest.authorize.net/xml/v1/request.api";
		}
		else
		{
		$post_url = "https://api.authorize.net/xml/v1/request.api";	
		}
        $curl_request = curl_init($post_url);
        curl_setopt($curl_request, CURLOPT_POSTFIELDS, $this->_post_string);
        curl_setopt($curl_request, CURLOPT_HEADER, 0);
        curl_setopt($curl_request, CURLOPT_TIMEOUT, 45);
        curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl_request, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($curl_request, CURLOPT_SSL_VERIFYPEER, false);
        if (preg_match('/xml/',$post_url)) {
            curl_setopt($curl_request, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
        }
        $response = curl_exec($curl_request);
        curl_close($curl_request);
		return ArrayToXML::toArray($response);
    }
}
class AuthorizeNetTD extends AuthorizeNetRequest
{
    const LIVE_URL = "";
    const SANDBOX_URL = "";
    private $_xml;
    /**
     * This function returns full transaction details for a specified transaction ID.
     *
     * @param int $transId
     *
     * @return AuthorizeNetTD_Response
     */    
    public function getTransactionDetails($transId,$sandbox,$user,$key)
    {
        $this->_constructXml("getTransactionDetailsRequest",$user,$key);
        $this->_xml->addChild("transId", $transId);
        return $this->_sendRequest($sandbox);
    }
    /**
     * @return string
     */
    protected function _getPostUrl()
    {
        return ($this->_sandbox ? self::SANDBOX_URL : self::LIVE_URL);
    }
    /**
     *
     *
     * @param string $response
     * 
     * @return AuthorizeNetTransactionDetails_Response
     */
    protected function _handleResponse($response)
    {
        return new AuthorizeNetTD_Response($response);
    }
    /**
     * Prepare the XML post string.
     */
    protected function _setPostString()
    {
        $this->_post_string = $this->_xml->asXML();
        
    }
    /**
     * Start the SimpleXMLElement that will be posted.
     *
     * @param string $request_type The action to be performed.
     */
    private function _constructXml($request_type,$user,$key)
    {
        $string = '<?xml version="1.0" encoding="utf-8"?><'.$request_type.' xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"></'.$request_type.'>';
        $this->_xml = @new SimpleXMLElement($string);
        $merchant = $this->_xml->addChild('merchantAuthentication');
        $merchant->addChild('name',$user);
        $merchant->addChild('transactionKey',$key);
    }
}