// API Setup parameters
$gatewayURL = 'https://secure.safesavegateway.com/api/v2/three-step';
$APIKey = '2F822Rw39fx762MaV7Yy86jXGTC7sCDy';
// If there is no POST data or a token-id, print the initial shopping cart form to get ready for Step One.
if (empty($_POST['DO_STEP_1']) && empty($_GET['token-id'])) {
print ' ';
print '
Collect non-sensitive Customer Info
Step One: Collect non-sensitive payment information.
Collect sensitive Customer Info
';
// Uncomment the line below if you would like to print Step One's response
// print 'Step Two: Collect sensitive payment information and POST directly to payment gateway
';
} elseif (!empty($_GET['token-id'])) {
// Step Three: Once the browser has been redirected, we can obtain the token-id and complete
// the transaction through another XML HTTPS POST including the token-id which abstracts the
// sensitive payment information that was previously collected by the Payment Gateway.
$tokenId = $_GET['token-id'];
$xmlRequest = new DOMDocument('1.0','UTF-8');
$xmlRequest->formatOutput = true;
$xmlCompleteTransaction = $xmlRequest->createElement('complete-action');
appendXmlNode($xmlRequest, $xmlCompleteTransaction,'api-key',$APIKey);
appendXmlNode($xmlRequest, $xmlCompleteTransaction,'token-id',$tokenId);
$xmlRequest->appendChild($xmlCompleteTransaction);
// Process Step Three
$data = sendXMLviaCurl($xmlRequest,$gatewayURL);
$gwResponse = @new SimpleXMLElement((string)$data);
print ' ';
print '
Step Three - Complete Transaction
';
print "
Step Three: Script automatically completes the transaction
";
if ((string)$gwResponse->result == 1 ) {
print "
"; } function sendXMLviaCurl($xmlRequest,$gatewayURL) { // helper function demonstrating how to send the xml with curl $ch = curl_init(); // Initialize curl handle curl_setopt($ch, CURLOPT_URL, $gatewayURL); // Set POST URL $headers = array(); $headers[] = "Content-type: text/xml"; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // Add http headers to let it know we're sending XML $xmlString = $xmlRequest->saveXML(); curl_setopt($ch, CURLOPT_FAILONERROR, 1); // Fail on errors curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // Allow redirects curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Return into a variable curl_setopt($ch, CURLOPT_PORT, 443); // Set the port number curl_setopt($ch, CURLOPT_TIMEOUT, 30); // Times out after 30s curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlString); // Add XML directly in POST curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // This should be unset in production use. With it on, it forces the ssl cert to be valid // before sending info. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); if (!($data = curl_exec($ch))) { print "curl error =>" .curl_error($ch) ."\n"; throw New Exception(" CURL ERROR :" . curl_error($ch)); } curl_close($ch); return $data; } // Helper function to make building xml dom easier function appendXmlNode($domDocument, $parentNode, $name, $value) { $childNode = $domDocument->createElement($name); $childNodeValue = $domDocument->createTextNode($value); $childNode->appendChild($childNodeValue); $parentNode->appendChild($childNode); }
Step One: Collect non-sensitive payment information.
Customer Information
Billing Details
'; }else if (!empty($_POST['DO_STEP_1'])) { // Initiate Step One: Now that we've collected the non-sensitive payment information, we can combine other order information and build the XML format. $xmlRequest = new DOMDocument('1.0','UTF-8'); $xmlRequest->formatOutput = true; $xmlSale = $xmlRequest->createElement('sale'); // Amount, authentication, and Redirect-URL are typically the bare minimum. appendXmlNode($xmlRequest, $xmlSale,'api-key',$APIKey); appendXmlNode($xmlRequest, $xmlSale,'redirect-url',$_SERVER['HTTP_REFERER']); appendXmlNode($xmlRequest, $xmlSale, 'amount', '12.00'); appendXmlNode($xmlRequest, $xmlSale, 'ip-address', $_SERVER["REMOTE_ADDR"]); //appendXmlNode($xmlRequest, $xmlSale, 'processor-id' , 'processor-a'); appendXmlNode($xmlRequest, $xmlSale, 'currency', 'USD'); // Some additonal fields may have been previously decided by user appendXmlNode($xmlRequest, $xmlSale, 'order-id', '1234'); appendXmlNode($xmlRequest, $xmlSale, 'order-description', 'Small Order'); appendXmlNode($xmlRequest, $xmlSale, 'merchant-defined-field-1' , 'Red'); appendXmlNode($xmlRequest, $xmlSale, 'merchant-defined-field-2', 'Medium'); appendXmlNode($xmlRequest, $xmlSale, 'tax-amount' , '0.00'); appendXmlNode($xmlRequest, $xmlSale, 'shipping-amount' , '0.00'); /*if(!empty($_POST['customer-vault-id'])) { appendXmlNode($xmlRequest, $xmlSale, 'customer-vault-id' , $_POST['customer-vault-id']); }else { $xmlAdd = $xmlRequest->createElement('add-customer'); appendXmlNode($xmlRequest, $xmlAdd, 'customer-vault-id' ,411); $xmlSale->appendChild($xmlAdd); }*/ // Set the Billing and Shipping from what was collected on initial shopping cart form $xmlBillingAddress = $xmlRequest->createElement('billing'); appendXmlNode($xmlRequest, $xmlBillingAddress,'first-name', $_POST['billing-address-first-name']); appendXmlNode($xmlRequest, $xmlBillingAddress,'last-name', $_POST['billing-address-last-name']); appendXmlNode($xmlRequest, $xmlBillingAddress,'address1', $_POST['billing-address-address1']); appendXmlNode($xmlRequest, $xmlBillingAddress,'city', $_POST['billing-address-city']); appendXmlNode($xmlRequest, $xmlBillingAddress,'state', $_POST['billing-address-state']); appendXmlNode($xmlRequest, $xmlBillingAddress,'postal', $_POST['billing-address-zip']); //billing-address-email appendXmlNode($xmlRequest, $xmlBillingAddress,'country', $_POST['billing-address-country']); appendXmlNode($xmlRequest, $xmlBillingAddress,'email', $_POST['billing-address-email']); appendXmlNode($xmlRequest, $xmlBillingAddress,'phone', $_POST['billing-address-phone']); appendXmlNode($xmlRequest, $xmlBillingAddress,'company', $_POST['billing-address-company']); appendXmlNode($xmlRequest, $xmlBillingAddress,'address2', $_POST['billing-address-address2']); appendXmlNode($xmlRequest, $xmlBillingAddress,'fax', $_POST['billing-address-fax']); $xmlSale->appendChild($xmlBillingAddress); $xmlShippingAddress = $xmlRequest->createElement('shipping'); appendXmlNode($xmlRequest, $xmlShippingAddress,'first-name', $_POST['shipping-address-first-name']); appendXmlNode($xmlRequest, $xmlShippingAddress,'last-name', $_POST['shipping-address-last-name']); appendXmlNode($xmlRequest, $xmlShippingAddress,'address1', $_POST['shipping-address-address1']); appendXmlNode($xmlRequest, $xmlShippingAddress,'city', $_POST['shipping-address-city']); appendXmlNode($xmlRequest, $xmlShippingAddress,'state', $_POST['shipping-address-state']); appendXmlNode($xmlRequest, $xmlShippingAddress,'postal', $_POST['shipping-address-zip']); appendXmlNode($xmlRequest, $xmlShippingAddress,'country', $_POST['shipping-address-country']); appendXmlNode($xmlRequest, $xmlShippingAddress,'phone', $_POST['shipping-address-phone']); appendXmlNode($xmlRequest, $xmlShippingAddress,'company', $_POST['shipping-address-company']); appendXmlNode($xmlRequest, $xmlShippingAddress,'address2', $_POST['shipping-address-address2']); $xmlSale->appendChild($xmlShippingAddress); // Products already chosen by user $xmlProduct = $xmlRequest->createElement('product'); appendXmlNode($xmlRequest, $xmlProduct,'product-code' , 'SKU-123456'); appendXmlNode($xmlRequest, $xmlProduct,'description' , 'test product description'); appendXmlNode($xmlRequest, $xmlProduct,'commodity-code' , 'abc'); appendXmlNode($xmlRequest, $xmlProduct,'unit-of-measure' , 'lbs'); appendXmlNode($xmlRequest, $xmlProduct,'unit-cost' , '5.00'); appendXmlNode($xmlRequest, $xmlProduct,'quantity' , '1'); appendXmlNode($xmlRequest, $xmlProduct,'total-amount' , '7.00'); appendXmlNode($xmlRequest, $xmlProduct,'tax-amount' , '2.00'); appendXmlNode($xmlRequest, $xmlProduct,'tax-rate' , '1.00'); appendXmlNode($xmlRequest, $xmlProduct,'discount-amount', '2.00'); appendXmlNode($xmlRequest, $xmlProduct,'discount-rate' , '1.00'); appendXmlNode($xmlRequest, $xmlProduct,'tax-type' , 'sales'); appendXmlNode($xmlRequest, $xmlProduct,'alternate-tax-id' , '12345'); $xmlSale->appendChild($xmlProduct); $xmlProduct = $xmlRequest->createElement('product'); appendXmlNode($xmlRequest, $xmlProduct,'product-code' , 'SKU-123456'); appendXmlNode($xmlRequest, $xmlProduct,'description' , 'test 2 product description'); appendXmlNode($xmlRequest, $xmlProduct,'commodity-code' , 'abc'); appendXmlNode($xmlRequest, $xmlProduct,'unit-of-measure' , 'lbs'); appendXmlNode($xmlRequest, $xmlProduct,'unit-cost' , '2.50'); appendXmlNode($xmlRequest, $xmlProduct,'quantity' , '2'); appendXmlNode($xmlRequest, $xmlProduct,'total-amount' , '7.00'); appendXmlNode($xmlRequest, $xmlProduct,'tax-amount' , '2.00'); appendXmlNode($xmlRequest, $xmlProduct,'tax-rate' , '1.00'); appendXmlNode($xmlRequest, $xmlProduct,'discount-amount', '2.00'); appendXmlNode($xmlRequest, $xmlProduct,'discount-rate' , '1.00'); appendXmlNode($xmlRequest, $xmlProduct,'tax-type' , 'sales'); appendXmlNode($xmlRequest, $xmlProduct,'alternate-tax-id' , '12345'); $xmlSale->appendChild($xmlProduct); $xmlRequest->appendChild($xmlSale); // Process Step One: Submit all transaction details to the Payment Gateway except the customer's sensitive payment information. // The Payment Gateway will return a variable form-url. $data = sendXMLviaCurl($xmlRequest,$gatewayURL); // Parse Step One's XML response $gwResponse = @new SimpleXMLElement($data); if ((string)$gwResponse->result ==1 ) { // The form url for used in Step Two below $formURL = $gwResponse->{'form-url'}; } else { throw New Exception(print " Error, received " . $data); } // Initiate Step Two: Create an HTML form that collects the customer's sensitive payment information // and use the form-url that the Payment Gateway returns as the submit action in that form. print ' '; print '' . (htmlentities($data)) . ''; print '
Step Two: Collect sensitive payment information and POST directly to payment gateway
';
} elseif (!empty($_GET['token-id'])) {
// Step Three: Once the browser has been redirected, we can obtain the token-id and complete
// the transaction through another XML HTTPS POST including the token-id which abstracts the
// sensitive payment information that was previously collected by the Payment Gateway.
$tokenId = $_GET['token-id'];
$xmlRequest = new DOMDocument('1.0','UTF-8');
$xmlRequest->formatOutput = true;
$xmlCompleteTransaction = $xmlRequest->createElement('complete-action');
appendXmlNode($xmlRequest, $xmlCompleteTransaction,'api-key',$APIKey);
appendXmlNode($xmlRequest, $xmlCompleteTransaction,'token-id',$tokenId);
$xmlRequest->appendChild($xmlCompleteTransaction);
// Process Step Three
$data = sendXMLviaCurl($xmlRequest,$gatewayURL);
$gwResponse = @new SimpleXMLElement((string)$data);
print ' ';
print '
Step Three: Script automatically completes the transaction
";
if ((string)$gwResponse->result == 1 ) {
print " Transaction was Approved, XML response was:
\n"; print '' . (htmlentities($data)) . ''; } elseif((string)$gwResponse->result == 2) { print "
Transaction was Declined.
\n"; print " Decline Description : " . (string)$gwResponse->{'result-text'} ." "; print "XML response was:
\n"; print '' . (htmlentities($data)) . ''; } else { print "
Transaction caused an Error.
\n"; print " Error Description: " . (string)$gwResponse->{'result-text'} ." "; print "XML response was:
\n"; print '' . (htmlentities($data)) . ''; } print ""; } else { print "ERROR IN SCRIPT
"; } function sendXMLviaCurl($xmlRequest,$gatewayURL) { // helper function demonstrating how to send the xml with curl $ch = curl_init(); // Initialize curl handle curl_setopt($ch, CURLOPT_URL, $gatewayURL); // Set POST URL $headers = array(); $headers[] = "Content-type: text/xml"; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // Add http headers to let it know we're sending XML $xmlString = $xmlRequest->saveXML(); curl_setopt($ch, CURLOPT_FAILONERROR, 1); // Fail on errors curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // Allow redirects curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Return into a variable curl_setopt($ch, CURLOPT_PORT, 443); // Set the port number curl_setopt($ch, CURLOPT_TIMEOUT, 30); // Times out after 30s curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlString); // Add XML directly in POST curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // This should be unset in production use. With it on, it forces the ssl cert to be valid // before sending info. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); if (!($data = curl_exec($ch))) { print "curl error =>" .curl_error($ch) ."\n"; throw New Exception(" CURL ERROR :" . curl_error($ch)); } curl_close($ch); return $data; } // Helper function to make building xml dom easier function appendXmlNode($domDocument, $parentNode, $name, $value) { $childNode = $domDocument->createElement($name); $childNodeValue = $domDocument->createTextNode($value); $childNode->appendChild($childNodeValue); $parentNode->appendChild($childNode); }