diff --git a/.gitignore b/.gitignore index 6401eac..6168999 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ # CyberSource config parameters /lib/conf/cybs.ini + +.vscode \ No newline at end of file diff --git a/README.md b/README.md index d6892f4..caae2a2 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,102 @@ # CyberSource PHP Client -This is the PHP client for the [CyberSource SOAP Toolkit API](http://www.cybersource.com/developers/getting_started/integration_methods/soap_toolkit_api). -[![Build Status](https://travis-ci.org/CyberSource/cybersource-sdk-php.png?branch=master)](https://travis-ci.org/CyberSource/cybersource-sdk-php) +This is the PHP client for the [CyberSource Simple Order API](https://www.cybersource.com/en-us/support/technical-documentation/apis-and-integration.html#simple). + +## Important Notice + +From version 1.0.4, the CyberSource PHP SDK has completely shifted to P12 authentication. + +You can upgrade to P12 Authentication in your application by doing the following: + +- Create a P12 certificate. +- Update the files in your project directory. +- Add your certificate information to your code. + +You must upgrade the SOAP Authentication to use P12 by February 13, 2025. + +### Prerequisites + +You must create a P12 certificate. See the [REST Getting Started Developer Guide](https://developer.cybersource.com/docs/cybs/en-us/platform/developer/all/rest/rest-getting-started/restgs-jwt-message-intro/restgs-security-p12-intro.html). + +> > **IMPORTANT : This P12 certificate is considered as a sensitive data. It is advised to store this in a secure manner. If the certificate is compromised, immediately revoke the certificate from EBC and request a new certificate.** ## Packagist + The cybersource/sdk-php is available at [Packagist](https://packagist.org/packages/cybersource/sdk-php). -If you want to install SDK from Packagist,add the following dependency to your application's 'composer.json'. + +If you want to install SDK from Packagist,add the following dependency to your application's `composer.json`. + ```json "require": { "cybersource/sdk-php": "*" - }, +}, ``` + ## Prerequisites - PHP 7.3 or above + - [curl](http://php.net/manual/en/book.curl.php), [openssl](http://php.net/manual/en/book.openssl.php), [soap](http://php.net/manual/en/book.soap.php) extensions must be enabled + - A CyberSource account. You can create an evaluation account [here](http://www.cybersource.com/register/). -- A CyberSource transaction key. You will need to set your merchant ID and transaction key in the ````cybs.ini```` file in ````lib/conf````. Instructions on obtaining a transaction key can be found [here](http://www.cybersource.com/developers/integration_methods/simple_order_and_soap_toolkit_api/soap_api/html/wwhelp/wwhimpl/js/html/wwhelp.htm#href=Intro.04.3.html). + +- A P12 certificate. Instructions on obtaining a P12 certificate can be found [here](https://developer.cybersource.com/docs/cybs/en-us/platform/developer/all/rest/rest-getting-started/restgs-jwt-message-intro/restgs-security-p12-intro.html). ## Installation -You can install the client either via [Composer](https://getcomposer.org/) or manually. Before installing, make sure to configure the merchant ID, transaction key, and the appropriate WSDL file URL in ````cybs.ini````. By default, the WSDL file for the client is for API version 1.120 (the latest when this package was updated). Available WSDL file URLs can be browsed at the following locations: -- [test](https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/) -- [live](https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/) +You can install the client either via [Composer](https://getcomposer.org/) or manually. -### Installing with Composer -You'll first need to make sure you have Composer installed. You can follow the instructions on the [official web site](https://getcomposer.org/download/). Once Composer is installed, you can enter the project root and run: -``` -Linux: composer.phar install -Windows: composer install -``` -If you already have composer installed for the project, you'll need to run the update command as below -``` -Linux: composer.phar update -Windows: composer update +Before installing, make sure that the following data is present in the `cybs.ini` file: + +```text +merchant_id = "YOUR_MERCHANT_ID" + +; Modify the URL to point to either a live or test WSDL file with the desired API version. +wsdl = "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.219.wsdl" + +; Modify the URL to point to either a live or test WSDL file with the desired API version for the name-value pairs transaction API. +nvp_wsdl = "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_NVP_1.219.wsdl" + +[SSL] +KEY_ALIAS = 'YOUR_KEY_ALIAS' +KEY_FILE = 'YOUR_CERTIFICATE_FILE' +KEY_PASS = 'YOUR_KEY_PASS' +KEY_DIRECTORY = 'PATH_TO_CERTIFICATE' ``` +By default, the WSDL file for the client is for API version **1.219**. Available WSDL file URLs can be browsed at the following locations: + +- [Test Endpoints](https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/) +- [Live Endpoints](https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/) + +### Installing with Composer + +You'll first need to make sure you have Composer installed. You can follow the instructions on the [official website](https://getcomposer.org/download/). + +Once Composer is installed, you can enter the project root and run: + +- On Windows: + ```cmd + composer install + ``` + +- On Linux: + ```bash + composer.phar install + ``` + +If you already have composer installed for the project, you'll need to run the `update` command as below: + +- On Windows: + ```cmd + composer update + ``` + +- On Linux: + ```bash + composer.phar update + ``` + Then, to use the client, you'll need to include the Composer-generated autoload file: ```php @@ -43,17 +104,24 @@ require_once('/path/to/project/vendor/autoload.php'); ``` ### Manual installation + To use the client manually, include the CyberSource client in your project: ```php -require_once('/path/to/project/lib/CybsSoapClient.php'); -``` +require_once('//lib/CybsSoapClient.php'); +``` ## Getting Started + The PHP client will generate the request message headers for you, and will contain the methods specified by the WSDL file. ### Creating a simple request -The main method you'll use is ````runTransaction()````. To run a transaction, you'll first need to construct a client to generate a request object, which you can populate with the necessary fields (see [documentation](http://www.cybersource.com/developers/integration_methods/simple_order_and_soap_toolkit_api/soap_api/html/wwhelp/wwhimpl/js/html/wwhelp.htm#href=Intro.04.4.html) for sample requests). The object will be converted into XML, so the properties of the object will need to correspond to the correct XML format. + +The main method you'll use is `runTransaction()`. + +To run a transaction, you'll first need to construct a client to generate a request object, which you can populate with the necessary fields (see [documentation](http://www.cybersource.com/developers/integration_methods/simple_order_and_soap_toolkit_api/soap_api/html/wwhelp/wwhimpl/js/html/wwhelp.htm#href=Intro.04.4.html) for sample requests). + +The object will be converted into XML, so the properties of the object will need to correspond to the correct XML format. ```php $client = new CybsSoapClient(); @@ -62,21 +130,24 @@ $request = $client->createRequest(); $card = new stdClass(); $card->accountNumber = '4111111111111111'; $card->expirationMonth = '12'; -$card->expirationYear = '2020'; +$card->expirationYear = '2035'; $request->card = $card; // Populate $request here with other necessary properties - $reply = $client->runTransaction($request); ``` ### Creating a request from XML -You can create a request from XML either in a file or from an XML string. The XML request format is described in the **Using XML** section [here](http://apps.cybersource.com/library/documentation/dev_guides/Simple_Order_API_Clients/Client_SDK_SO_API.pdf). Here's how to run a transaction from an XML file: + +You can also create a request from XML either in a file or from an XML string. +The XML request format is described in the **Using XML** section [here](http://apps.cybersource.com/library/documentation/dev_guides/Simple_Order_API_Clients/Client_SDK_SO_API.pdf). + +Here's how to run a transaction from an XML file: ```php $referenceCode = 'your_merchant_reference_code'; $client = new CybsSoapClient(); -$reply = $client->runTransactionFromFile('path/to/my.xml', $referenceCode); +$reply = $client->runTransactionFromFile('path/to/file.xml', $referenceCode); ``` Or, you can create your own XML string and use that instead: @@ -89,7 +160,10 @@ $client->runTransactionFromXml($xml); ``` ### Using name-value pairs -In order to run transactions using name-value pairs, make sure to set the value for the WSDL for the NVP transaction processor in ````cybs.ini````. Then use the ````CybsNameValuePairClient```` as so: + +In order to run transactions using name-value pairs, make sure to set the value for the WSDL for the NVP transaction processor in `cybs.ini`. + +Then use the `CybsNameValuePairClient` as follows: ```php $client = new CybsNameValuePairClient(); @@ -97,36 +171,66 @@ $request = array(); $request['ccAuthService_run'] = 'true'; $request['merchantID'] = 'my_merchant_id'; $request['merchantReferenceCode'] = $'my_reference_code'; + // Populate $request $reply = $client->runTransaction($request); ``` ## Running the Samples -After configuring your merchant ID and transaction key in ````cybs.ini````, the samples in the ````samples```` directory can be run from the project root. For example: -``` +After configuring your merchant ID and transaction key in `cybs.ini`, the samples in the `samples` directory can be run from the project root. + +For example: + +```bash php samples/Sale.php ``` -The samples will output the response object for each request if successful. Note that the samples contain test data and should not be run in a live environment. +The samples will output the response object for each request if successful. + +> > **Note that the samples contain test data and should *NOT* be run in a live environment.** ## Meta Key support -Meta Key is a key generated by an entity that can be used to authenticate on behalf of other entities provided that the entity which holds key is a parent entity or associated as a partner. -SOAP PHP SDK supports meta key by default. Additional detail regarding cybs.ini changes. +Meta Key is a key generated by an entity that can be used to authenticate on behalf of other entities provided that the entity which holds the key is a parent entity or associated as a partner. -merchantID=\
-transaction_key=\
-Send transacting merchantID in the sample request. +SOAP PHP SDK supports meta key by default. -## Tests +### Additional detail regarding `cybs.ini` changes. -In order to run tests, you'll need [PHPUnit](https://phpunit.de). You'll also need to use [Composer](https://getcomposer.org/) for autoloading. If you used Composer to install the client, this should already be set up. Otherwise, to use Composer for autoloading only, from the project root run -``` -composer.phar dump-autoload +```text +merchant_id = + +[SSL] +KEY_ALIAS = 'KEY_ALIAS_GENERATED_FOR_CERTIFICATE' +KEY_FILE = 'CERTIFICATE_FILE_GENERATED_FOR_CERTIFICATE' +KEY_PASS = 'KEY_PASS_GENERATED_FOR_CERTIFICATE' +KEY_DIRECTORY = 'PATH_TO_CERTIFICATE_GENERATED_FOR_METAKEY' ``` -If you installed PHPUnit with Composer, run the tests from the project root with the command ````vendor/bin/phpunit````. +Note that the transacting merchant ID needs to be sent in the sample request. + +## Tests + +In order to run tests, you'll need [PHPUnit](https://phpunit.de). + +You'll also need to use [Composer](https://getcomposer.org/) for autoloading. + +If you used Composer to install the client, this should already be set up. + +Otherwise, to use Composer for autoloading only, from the project root run: + +- On Windows: + ```cmd + composer dump-autoload + ``` + +- On Linux: + ```bash + composer.phar dump-autoload + ``` + +If you installed PHPUnit with Composer, run the tests from the project root with the command `vendor/bin/phpunit`. ## Documentation diff --git a/lib/CybsClient.php b/lib/CybsClient.php index f904e90..afb7400 100644 --- a/lib/CybsClient.php +++ b/lib/CybsClient.php @@ -10,92 +10,72 @@ */ class CybsClient extends SoapClient { - const CLIENT_LIBRARY_VERSION = "CyberSource PHP 1.0.0"; + const CLIENT_LIBRARY = "CyberSource PHP"; + const CLIENT_LIBRARY_VERSION = "1.0.4"; + // namespaces defined by standard + const WSU_NS = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'; + const WSSE_NS = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'; + const SOAP_NS = 'http://schemas.xmlsoap.org/soap/envelope/'; + const DS_NS = 'http://www.w3.org/2000/09/xmldsig#'; + + protected $_ssl_options = array(); + protected $_timeout = 6000; + + private $propertiesUtility; + private $securityUtility; + private $wsdl; private $merchantId; - private $transactionKey; - function __construct($options=array(), $properties, $nvp=false) + function __construct($options = array(), $properties = array(), $nvp = false) { - $required = array('merchant_id', 'transaction_key'); + $this->propertiesUtility = new PropertiesUtility(); + $this->securityUtility = new SecurityUtility(); + + $this->merchantId = $properties['merchant_id']; - if (!$properties) { - throw new Exception('Unable to read cybs.ini.'); + if ($nvp === true) + { + $this->wsdl = $properties['nvp_wsdl']; + } + else + { + $this->wsdl = $properties['wsdl']; } - if ($nvp === true) { - array_push($required, 'nvp_wsdl'); - $wsdl = $properties['nvp_wsdl']; - } else { - array_push($required, 'wsdl'); - $wsdl = $properties['wsdl']; + if (!$this->wsdl) + { + throw new Exception('WSDL URL missing in cybs.ini.'); } - foreach ($required as $req) { - if (empty($properties[$req])) { - throw new Exception($req . ' not found in cybs.ini.'); + if(isset($properties['SSL'])) + { + $this->_ssl_options = $properties['SSL']; + if (isset($this->_ssl_options['KEY_FILE'])) + { + if ($this->propertiesUtility->isValidFilePath($this->_ssl_options)) + { + $certificateInfo = pathinfo($this->propertiesUtility->getFilePath($this->_ssl_options)); + if (in_array(strtolower($certificateInfo['extension']), array('p12', 'pfx'))) + { + $this->_ssl_options['certificate_type'] = 'P12'; + } + } } + + $options = array_merge($options, $this->_ssl_options); + } + else + { + throw new InvalidArgumentException("SSL Options are missing."); } - parent::__construct($wsdl, $options); - $this->merchantId = $properties['merchant_id']; - $this->transactionKey = $properties['transaction_key']; - - $nameSpace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; - - $soapUsername = new SoapVar( - $this->merchantId, - XSD_STRING, - NULL, - $nameSpace, - NULL, - $nameSpace - ); - - $soapPassword = new SoapVar( - $this->transactionKey, - XSD_STRING, - NULL, - $nameSpace, - NULL, - $nameSpace - ); - - $auth = new stdClass(); - $auth->Username = $soapUsername; - $auth->Password = $soapPassword; - - $soapAuth = new SoapVar( - $auth, - SOAP_ENC_OBJECT, - NULL, $nameSpace, - 'UsernameToken', - $nameSpace - ); - - $token = new stdClass(); - $token->UsernameToken = $soapAuth; - - $soapToken = new SoapVar( - $token, - SOAP_ENC_OBJECT, - NULL, - $nameSpace, - 'UsernameToken', - $nameSpace - ); - - $security =new SoapVar( - $soapToken, - SOAP_ENC_OBJECT, - NULL, - $nameSpace, - 'Security', - $nameSpace - ); - - $header = new SoapHeader($nameSpace, 'Security', $security, true); - $this->__setSoapHeaders(array($header)); + if(isset($properties['CONNECTION_TIMEOUT']) && intval($properties['CONNECTION_TIMEOUT'])) + { + $this->_timeout = intval($properties['CONNECTION_TIMEOUT']); + } + + parent::__construct($this->wsdl, $options); } /** @@ -106,11 +86,55 @@ public function getMerchantId() return $this->merchantId; } - /** - * @return string The client's transaction key. - */ - public function getTransactionKey() + #[\ReturnTypeWillChange] + function __doRequest($request, $location, $action, $version, $oneWay = false) { - return $this->transactionKey; + // Load request and add security headers + $requestDom = new DOMDocument('1.0', 'utf-8'); + $requestDom->loadXML($request); + + $domXPath = new DOMXPath($requestDom); + $domXPath->registerNamespace('SOAP-ENV', self::SOAP_NS); + + // Mark SOAP-ENV:Body with wsu:Id for signing + $bodyNode = $domXPath->query('/SOAP-ENV:Envelope/SOAP-ENV:Body')->item(0); + $bodyNode->setAttributeNS(self::WSU_NS, 'wsu:Id', 'Body'); + + // Extract or Create SoapHeader + $headerNode = $domXPath->query('/SOAP-ENV:Envelope/SOAP-ENV:Header')->item(0); + if (!$headerNode) + { + $headerNode = $requestDom->documentElement->insertBefore($requestDom->createElementNS(self::SOAP_NS, 'SOAP-ENV:Header'), $bodyNode); + } + + // Prepare Security element + $securityElement = $headerNode->appendChild($requestDom->createElementNS(self::WSSE_NS, 'wsse:Security')); + + $privateKeyId = ''; + + // Update with token data + $securityElement->appendChild($this->securityUtility->generateSecurityToken($requestDom, + $this->propertiesUtility->getFilePath($this->_ssl_options), + $this->propertiesUtility->getCertificatePassword($this->_ssl_options), + $privateKeyId) + ); + + // Create Signature element and build SignedInfo for elements with provided ids + $signatureElement = $securityElement->appendChild($requestDom->createElementNS(self::DS_NS, 'ds:Signature')); + $signInfo = $signatureElement->appendChild($this->securityUtility->buildSignedInfo($requestDom, array('Body'))); + + // Combine Binary Security Token with Signature element + openssl_sign($this->securityUtility->canonicalizeNode($signInfo), $signature, $privateKeyId, OPENSSL_ALGO_SHA256); + + $signatureElement->appendChild($requestDom->createElementNS(self::DS_NS, 'ds:SignatureValue', base64_encode($signature))); + $keyInfo = $signatureElement->appendChild($requestDom->createElementNS(self::DS_NS, 'ds:KeyInfo')); + $securityTokenReferenceElement = $keyInfo->appendChild($requestDom->createElementNS(self::WSSE_NS, 'wsse:SecurityTokenReference')); + $keyReference = $securityTokenReferenceElement->appendChild($requestDom->createElementNS(self::WSSE_NS, 'wsse:Reference')); + $keyReference->setAttribute('URI', "#X509Token"); + + // Convert Document to String + $request = $requestDom->saveXML(); + + return parent::__doRequest($request, $location, $action, $version, $oneWay); } } \ No newline at end of file diff --git a/lib/CybsNameValuePairClient.php b/lib/CybsNameValuePairClient.php index c7ceeb3..843c1ea 100644 --- a/lib/CybsNameValuePairClient.php +++ b/lib/CybsNameValuePairClient.php @@ -13,7 +13,12 @@ class CybsNameValuePairClient extends CybsClient function __construct($options=array()) { - $properties = parse_ini_file('cybs.ini'); + $properties = parse_ini_file('cybs.ini', true); + + if (!$properties) { + throw new Exception('Unable to read cybs.ini.'); + } + parent::__construct($options, $properties, true); } diff --git a/lib/CybsSoapClient.php b/lib/CybsSoapClient.php index fce96e1..2894e90 100644 --- a/lib/CybsSoapClient.php +++ b/lib/CybsSoapClient.php @@ -9,15 +9,19 @@ */ class CybsSoapClient extends CybsClient { - - function __construct($options=array()) + function __construct($options = array()) { - $properties = parse_ini_file('cybs.ini'); + $properties = parse_ini_file('cybs.ini', true); + + if (!$properties) { + throw new Exception('Unable to read cybs.ini.'); + } + parent::__construct($options, $properties); } /** - * Returns a properly formatted request object from a SimpleXMLElement. + * Returns a properly formatted request object from a SimpleXMLElement. * * @param SimpleXMLElement $simpleXml Representation of an XML structure * @return stdClass A request with the data from the SimpleXMLElement. @@ -47,7 +51,7 @@ public function simpleXmlToCybsRequest($simpleXml) foreach($array as $k => $value) { $newArray[$k] = $this->simpleXmlToCybsRequest($value); } - $request->$key = $newArray; + $request->$key = $newArray; } } else if ($element instanceof SimpleXMLElement) { $request->$key = $this->simpleXmlToCybsRequest($element); @@ -67,8 +71,8 @@ public function createRequest($merchantReferenceCode) $request = new stdClass(); $request->merchantID = $this->getMerchantId(); $request->merchantReferenceCode = $merchantReferenceCode; - $request->clientLibrary = self::CLIENT_LIBRARY_VERSION; - $request->clientLibraryVersion = phpversion(); + $request->clientLibrary = self::CLIENT_LIBRARY; + $request->clientLibraryVersion = self::CLIENT_LIBRARY_VERSION; $request->clientEnvironment = php_uname(); return $request; } @@ -78,7 +82,7 @@ public function createRequest($merchantReferenceCode) * * @param string $filePath The path to the XML file * @param string $merchantReferenceCode Desired reference code for the request - * @return stdClass An object representation of the transaction response. + * @return stdClass An object representation of the transaction response. */ public function runTransactionFromXml($xml, $merchantReferenceCode) { @@ -86,7 +90,7 @@ public function runTransactionFromXml($xml, $merchantReferenceCode) $simpleXml = simplexml_load_string($xml); $xmlRequest = $this->simpleXmlToCybsRequest($simpleXml); $mergedRequest = (object) array_merge((array) $request, (array) $xmlRequest); - return $this->runTransaction($mergedRequest); + return parent::runTransaction($mergedRequest); } /** @@ -94,7 +98,7 @@ public function runTransactionFromXml($xml, $merchantReferenceCode) * * @param string $filePath The path to the XML file * @param string $merchantReferenceCode Desired reference code for the request - * @return stdClass An object representation of the transaction response. + * @return stdClass An object representation of the transaction response. */ public function runTransactionFromFile($filePath, $merchantReferenceCode) { diff --git a/lib/PropertiesUtility.php b/lib/PropertiesUtility.php new file mode 100644 index 0000000..ee09638 --- /dev/null +++ b/lib/PropertiesUtility.php @@ -0,0 +1,47 @@ + \ No newline at end of file diff --git a/lib/SecurityUtility.php b/lib/SecurityUtility.php new file mode 100644 index 0000000..f6ca618 --- /dev/null +++ b/lib/SecurityUtility.php @@ -0,0 +1,137 @@ +createElementNS(self::WSSE_NS, 'wsse:BinarySecurityToken', $pubcert); + $tokenElement->setAttribute('ValueType', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3'); + $tokenElement->setAttribute('EncodingType', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'); + $tokenElement->setAttributeNS(self::WSU_NS, 'wsu:Id', "X509Token"); + return $tokenElement; + } + + /** + * XML canonicalization + * + * @param string $data + * @return string + */ + function canonicalizeXML($data) + { + $result = ''; + $fname = tempnam(sys_get_temp_dir(), 'temporaryBinarySecurityToken'); + $f = fopen($fname, 'w+'); + fwrite($f, $data); + fclose($f); + + $tempFile = new DOMDocument('1.0', 'utf-8'); + $tempFile->load($fname); + unlink($fname); + + $result = $tempFile->C14N(true, true); + + return $result; + } + + /** + * Canonicalize DOMNode instance and return result as string + * + * @param DOMNode $domNode + * @return string + */ + function canonicalizeNode($domNode) + { + $domDocument = new DOMDocument('1.0', 'utf-8'); + $domDocument->appendChild($domDocument->importNode($domNode, true)); + return $this->canonicalizeXML($domDocument->saveXML($domDocument->documentElement)); + } + + /** + * Prepares SignedInfo DOMElement with required data + * + * @param DOMDocument $domDocument + * @param array $ids + * @return DOMNode + */ + function buildSignedInfo($domDocument, $ids) + { + $domXPath = new DOMXPath($domDocument); + $domXPath->registerNamespace('SOAP-ENV', self::SOAP_NS); + $domXPath->registerNamespace('wsu', self::WSU_NS); + $domXPath->registerNamespace('wsse', self::WSSE_NS); + $domXPath->registerNamespace('ds', self::DS_NS); + + $signedInfo = $domDocument->createElementNS(self::DS_NS, 'ds:SignedInfo'); + + // Canonicalization algorithm + $method = $signedInfo->appendChild($domDocument->createElementNS(self::DS_NS, 'ds:CanonicalizationMethod')); + $method->setAttribute('Algorithm', 'http://www.w3.org/2001/10/xml-exc-c14n#'); + + // Signature algorithm + $method = $signedInfo->appendChild($domDocument->createElementNS(self::DS_NS, 'ds:SignatureMethod')); + $method->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'); + + foreach ($ids as $id) + { + // find a node and canonicalize it + $nodes = $domXPath->query("//*[(@wsu:Id='$id')]"); + if ($nodes->length == 0) { continue; } + + $canonicalized = $this->canonicalizeNode($nodes->item(0)); + + // Create Reference Element + $referenceElement = $signedInfo->appendChild($domDocument->createElementNS(self::DS_NS, 'ds:Reference')); + $referenceElement->setAttribute('URI', "#$id"); + + // Create Transform Element + $transforms = $referenceElement->appendChild($domDocument->createElementNS(self::DS_NS, 'ds:Transforms')); + $transformElement = $transforms->appendChild($domDocument->createElementNS(self::DS_NS, 'ds:Transform')); + + // Mark node as Canonicalized + $transformElement->setAttribute('Algorithm', 'http://www.w3.org/2001/10/xml-exc-c14n#'); + + // Add a SHA256 digest + $digestValue = hash("sha256", $canonicalized, true); + $method = $referenceElement->appendChild($domDocument->createElementNS(self::DS_NS, 'ds:DigestMethod')); + $method->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmlenc#sha256'); + $referenceElement->appendChild($domDocument->createElementNS(self::DS_NS, 'ds:DigestValue', base64_encode($digestValue))); + } + + return $signedInfo; + } +} + +?> \ No newline at end of file diff --git a/lib/conf/cybs.ini b/lib/conf/cybs.ini index c84f068..1267f6f 100644 --- a/lib/conf/cybs.ini +++ b/lib/conf/cybs.ini @@ -1,8 +1,13 @@ -merchant_id = your_merchant_id -transaction_key = "your_transaction_key" +merchant_id = "YOUR_MERCHANT_ID" ; Modify the URL to point to either a live or test WSDL file with the desired API version. -wsdl = "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.120.wsdl" +wsdl = "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.219.wsdl" ; Modify the URL to point to either a live or test WSDL file with the desired API version for the name-value pairs transaction API. -nvp_wsdl = "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_NVP_1.120.wsdl" +nvp_wsdl = "https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_NVP_1.219.wsdl" + +[SSL] +KEY_ALIAS = 'YOUR_KEY_ALIAS' +KEY_FILE = 'YOUR_CERTIFICATE_FILE' +KEY_PASS = 'YOUR_KEY_PASS' +KEY_DIRECTORY = 'PATH_TO_CERTIFICATE' \ No newline at end of file diff --git a/samples/AuthFollowOnCapture.php b/samples/AuthFollowOnCapture.php index 2a2ee19..d89d333 100644 --- a/samples/AuthFollowOnCapture.php +++ b/samples/AuthFollowOnCapture.php @@ -14,8 +14,8 @@ $client = new CybsSoapClient(); $request = $client->createRequest($referenceCode); -// This section contains a sample transaction request for the authorization -// service with complete billing, payment card, and purchase (two items) information. +// This section contains a sample transaction request for the authorization +// service with complete billing, payment card, and purchase (two items) information. $ccAuthService = new stdClass(); $ccAuthService->run = 'true'; $request->ccAuthService = $ccAuthService; @@ -36,7 +36,7 @@ $card = new stdClass(); $card->accountNumber = '4111111111111111'; $card->expirationMonth = '12'; -$card->expirationYear = '2021'; +$card->expirationYear = '2035'; $request->card = $card; $purchaseTotals = new stdClass(); diff --git a/samples/AuthFromNameValuePairs.php b/samples/AuthFromNameValuePairs.php index 21956d4..c887d4a 100644 --- a/samples/AuthFromNameValuePairs.php +++ b/samples/AuthFromNameValuePairs.php @@ -26,7 +26,7 @@ $request['billTo_email'] = 'jsmith@example.com'; $request['card_accountNumber'] = '4111111111111111'; $request['card_expirationMonth'] = '12'; -$request['card_expirationYear'] = '2021'; +$request['card_expirationYear'] = '2035'; $request['purchaseTotals_currency'] = 'USD'; $request['item_0_unitPrice'] = '12.34'; $request['item_1_unitPrice'] = '56.78'; diff --git a/samples/Sale.php b/samples/Sale.php index 9e8f7ec..156b32f 100644 --- a/samples/Sale.php +++ b/samples/Sale.php @@ -39,7 +39,7 @@ $card = new stdClass(); $card->accountNumber = '4111111111111111'; $card->expirationMonth = '12'; -$card->expirationYear = '2021'; +$card->expirationYear = '2035'; $request->card = $card; $purchaseTotals = new stdClass(); diff --git a/samples/Subscription.php b/samples/Subscription.php index 097ae5f..a2df4c4 100644 --- a/samples/Subscription.php +++ b/samples/Subscription.php @@ -34,7 +34,7 @@ $card = new stdClass(); $card->accountNumber = '4111111111111111'; $card->expirationMonth = '12'; -$card->expirationYear = '2021'; +$card->expirationYear = '2035'; $card->cardType='001'; $request->card = $card; @@ -47,7 +47,7 @@ $recurringSubscriptionInfo->amount = '11.00'; $recurringSubscriptionInfo->automaticRenew = 'false'; $recurringSubscriptionInfo->numberOfPayments = '4'; -$recurringSubscriptionInfo->startDate = '20140221'; +$recurringSubscriptionInfo->startDate = '20250221'; $request->recurringSubscriptionInfo = $recurringSubscriptionInfo; diff --git a/samples/xml/auth.xml b/samples/xml/auth.xml index c677315..3d80bf9 100644 --- a/samples/xml/auth.xml +++ b/samples/xml/auth.xml @@ -1,6 +1,6 @@ --> + xmlns="urn:schemas-cybersource-com:transaction-data-1.219"> your_merchant_reference_code @@ -36,7 +36,7 @@ 4111111111111111 12 - 2021 + 2035 diff --git a/test/CybsSoapClientTest.php b/test/CybsSoapClientTest.php index 5aea2d1..7d11535 100644 --- a/test/CybsSoapClientTest.php +++ b/test/CybsSoapClientTest.php @@ -14,9 +14,5 @@ public function testClient() $properties['merchant_id'], $client->getMerchantId() ); - $this->assertEquals( - $properties['transaction_key'], - $client->getTransactionKey() - ); } }