createPayment

Création d'une transaction de paiement avec authentification 3D Secure

Quatre fichiers sont requis pour créer une transaction de paiement avec authentification 3D Secure :

  • le fichier pour les fonctions "function.php".

  • le fichier pour la définition des objets "v5.php".

  • un fichier pour l'opération createPayment :
    <?php
    include_once 'v5.php'; 	// Fichier comportant la définition des différentes objets 
    include_once 'function.php';// Fichier comportant l'ensemble des fonctions utiles (génération de l'uuid, etc...)
    
    //Intialisation des variables
    $shopId = "123456789";
    $key = "123456789123456";	
    $mode = "TEST";
    $wsdl = "https://secure.payzen.eu/vads-ws/v5?wsdl";
    
    //Exemple d'Initialisation d'un client SOAP avec gestion du SNI 
    		/*
    		$client = new soapClient($wsdl,	$options = array('trace'=>1, 
    					'exceptions'=> 0, 			
    					'encoding' => 'UTF-8','soapaction' => '',
    					'uri' => 'http://v5.ws.vads.lyra.com/',	            
    					'cache_wsdl' => WSDL_CACHE_NONE, 
    					//Proxy parameters
    					'proxy_host' => 'my.proxy.host',
    					'proxy_port' => 3128,
    					'stream_context' => stream_context_create (array('ssl' => array( 
    						'SNI_enabled' => true,
    						'SNI_server_name' => 'secure.payzen.eu')))
    					));
    		*/			
    
    //Exemple d'Initialisation d'un client SOAP sans proxy		
    		$client = new soapClient($wsdl, $options = array(
    					'trace'=>1, 
    					'exceptions'=> 0, 			
    					'encoding' => 'UTF-8',
    					'soapaction' => '')
    		);
    
    //Génération du header
    			$requestId = gen_uuid ();
    			$timestamp = gmdate ( "Y-m-d\TH:i:s\Z" );			
    			$authToken = base64_encode(hash_hmac('sha256',$requestId.$timestamp, $key, true));			
    			setHeaders ($shopId, $requestId, $timestamp, $mode, $authToken, $key, $client);
    			
    //Génération du body
    		$commonRequest = new commonRequest;
    			$commonRequest->paymentSource = 'EC';
    			$commonRequest->submissionDate = new DateTime('now',new DateTimeZone('UTC'));		
    		
    		$threeDSRequest = new threeDSRequest;			
    			$threeDSRequest->mode = "ENABLED_CREATE";
    			
    		$paymentRequest = new paymentRequest;			
    			$paymentRequest->amount = "2990";
    			$paymentRequest->currency = "978";			
    			$paymentRequest->manualValidation = '0';			
    			
    		$orderRequest = new orderRequest;
    			$orderRequest->orderId = "myOrder";					
    
    		$cardRequest = new cardRequest;
    			$cardRequest->number = "4970100000000000";
    			$cardRequest->scheme = "VISA";
    			$cardRequest->expiryMonth = "12";
    			$cardRequest->expiryYear = "2023";
    			$cardRequest->cardSecurityCode = "123";
    			$cardRequest->cardHolderBirthDay = "2008-12-31";
    					
    		$customerRequest = new customerRequest;
    			$customerRequest->billingDetails = new billingDetailsRequest;				
    				$customerRequest->billingDetails->email="test@exemple.com";						
    			
    		$customerRequest->extraDetails = new extraDetailsRequest;
    		
    		$techRequest = new techRequest;
    			
    //Appel de l'opération createPayment		
    	  try {		
    		$createPaymentRequest = new createPayment;
    			$createPaymentRequest->commonRequest = $commonRequest; 
    			$createPaymentRequest->threeDSRequest =  $threeDSRequest;
    			$createPaymentRequest->paymentRequest = $paymentRequest;
    			$createPaymentRequest->orderRequest = $orderRequest;
    			$createPaymentRequest->cardRequest = $cardRequest; 
    			$createPaymentRequest->customerRequest = $customerRequest;
    			$createPaymentRequest->techRequest = $techRequest;
    		$createPaymentRequest->commonRequest->submissionDate = $createPaymentRequest->commonRequest->submissionDate->format(dateTime::W3C);
    		$createPaymentResponse= new createPaymentResponse();
    		$createPaymentResponse = $client->createPayment($createPaymentRequest);
    	} catch (SoapFault $fault) {
    	
    //Gestion des exceptions		
    	trigger_error("SOAP Fault: (faultcode: {$fault->faultcode}, faultstring: {$fault->faultstring})", E_USER_ERROR);
    	}
    	
    	/* Affichage des logs XML à remplacer par une écriture dans un fichier de log.	
    	*
    	* ATTENTION VOUS NE DEVEZ PAS ENREGISTRER LES NUMEROS DE CARTE DANS VOS LOGS
    	*/
    		echo "<hr> [Request Header] <br/>", htmlspecialchars($client->__getLastRequestHeaders()), "<br/>";
    		echo "<hr> [Request] <br/>", htmlspecialchars($client->__getLastRequest()), "<br/>";	
    		echo "<hr> [Response Header]<br/>", htmlspecialchars($client->__getLastResponseHeaders()), "<br/>";
    		echo "<hr> [Response]<br/>", htmlspecialchars($client->__getLastResponse()), "<br/>";
    		echo '<hr>';			
    		echo "<hr> [Response SOAP Headers]<br/>";
    
    //Analyse de la réponse
    	//Récupération du SOAP Header de la réponse afin de stocker les en-têtes dans un tableau (ici $responseHeader)	
    		$dom = new DOMDocument;
    		$dom->loadXML($client->__getLastResponse(), LIBXML_NOWARNING);
    		$path = new DOMXPath($dom);
    		$headers = $path->query('//*[local-name()="Header"]/*');			
    		$responseHeader = array();				
    		foreach($headers as $headerItem) {			
    			$responseHeader[$headerItem->nodeName] = $headerItem->nodeValue;				
    		}	
    	
    //Calcul du jeton d'authentification de la réponse				
    		$authTokenResponse = base64_encode(hash_hmac('sha256',$responseHeader['timestamp'].$responseHeader['requestId'], $key, true));			
    		if ($authTokenResponse !== $responseHeader['authToken']){			
    			//Erreur de calcul ou tentative de fraude			
    				echo 'Erreur interne rencontrée';
    		}
    		else{		
    			//Analyse de la réponse
    				if ($createPaymentResponse->createPaymentResult->commonResponse->responseCode != "0"){
    				//process error				
    				}
    				else{
    				//Process terminé avec succès					
    					//Test de la présence du transactionStatusLabel:
    					if (isset ($createPaymentResponse->createPaymentResult->commonResponse->transactionStatusLabel)){
    						//La carte est non enrôlée ou 3DS Désactivé											
    							// Le paiement est accepté	
    								// Le code ci-dessous doit être modifié pour intégrer les mises à jour de base de données etc..
    								switch ($createPaymentResponse->createPaymentResult->commonResponse->transactionStatusLabel) {							
    									case "AUTHORISED":
    											echo "paiement accepté";
    									break;
    									case "WAITING_AUTHORISATION":
    											echo "paiement accepté";
    									break;
    									case "AUTHORISED_TO_VALIDATE":
    											echo "paiement accepté";
    									break;
    									case "WAITING_AUTHORISATION_TO_VALIDATE":
    											echo "paiement accepté";
    									break;							
    								// Le paiement est refusé							
    									default:
    											echo "paiement refusé";
    									break;									
    								}						
    					}
    					else{			
    					// si absent = la transaction n'est pas créée, on est donc dans le cas d'une carte enrôlée
    					// on procède alors à la génération du formulaire de redirection 3DS
    						
    						//On récupère l'identifiant de session afin de maintenir la session lors de l'analyse de la réponse de l'acs
    						$cookie = getJsessionId($client);
    						
    						// On stocke l'identifiant de session dans le champ MD. Ce champ sera renvoyé inchangé par l'ACS
    						$MD=setJsessionId($client)."+".$createPaymentResponse->createPaymentResult->threeDSResponse->authenticationRequestData->threeDSRequestId;
    						
    						//On initialise les autres champs nécessaire à la redirection vers l'ACS
    						$threeDsAcsUrl = $createPaymentResponse->createPaymentResult->threeDSResponse->authenticationRequestData->threeDSAcsUrl;						
    						$threeDsEncodedPareq = $createPaymentResponse->createPaymentResult->threeDSResponse->authenticationRequestData->threeDSEncodedPareq;
    						$threeDsServerResponseUrl = "http://127.0.0.1/webservices/ws-v5/retour3DS.php";
    													
    						//ATTENTION en mode TEST, l'identifiant de session doit être ajouté à l'URL de l'ACS pour maintenir la session HTTP
    							$JSESSIONID=setJsessionId($client);
    							if ($mode == "TEST"){
    								$threeDsAcsUrl = $threeDsAcsUrl.";jsessionid=".$JSESSIONID;
    							}							
    						formConstructor ($threeDsAcsUrl,$MD,$threeDsEncodedPareq,$threeDsServerResponseUrl);
    					}
    				}
    			}
    ?>
  • un fichier pour traiter le retour de l'authentification 3D Secure "retour3DS.php" :
    <?php
    include_once 'v5.php'; 	// Fichier comportant la définition des différentes objets 
    include_once 'function.php';// Fichier comportant l'ensemble des fonctions utiles (génération de l'uuid, etc...)
    
    //Intialisation des variables
    $shopId = "12345678";
    $key = "123456789123456";	
    $mode = "TEST";
    $wsdl = "https://secure.payzen.eu/vads-ws/v5?wsdl";
    
    //Récupération de la réponse de l'ACS
    	//On retrouve l'identifiant de session dans le champ MD afin de maintenir la session HTTP
    	if (isset ($_POST['MD']) AND (isset ($_POST['PaRes']))){
    		list($JSESSIONID, $threeDSRequestId) = explode("+",$_POST['MD']);
    		
    		//On supprime les espaces et les retours à la ligne du message PaRes
    		$pares = str_replace("\r\n","",$_POST['PaRes'],$count);;
    
    //Exemple d'Initialisation d'un client SOAP avec gestion du SNI 
    		/*
    		$client = new soapClient($wsdl,	$options = array('trace'=>1,
    					'exceptions'=> 0, 			
    					'encoding' => 'UTF-8','soapaction' => '',
    					'uri' => 'http://v5.ws.vads.lyra.com/',	            
    					'cache_wsdl' => WSDL_CACHE_NONE, 
    					//Proxy parameters
    					'proxy_host' => 'my.proxy.host',
    					'proxy_port' => 3128,
    					'stream_context' => stream_context_create (array('ssl' => array(
    						'SNI_enabled' => true,
    						'SNI_server_name' => 'secure.payzen.eu')))
    					));
    		*/			
    
    //Exemple d'Initialisation d'un client SOAP sans proxy		
    		$client = new soapClient($wsdl, $options = array(
    					'trace'=>1, 
    					'exceptions'=> 0, 			
    					'encoding' => 'UTF-8',
    					'soapaction' => '')
    		);
    			
    //Génération du header								
    			$requestId = gen_uuid ();
    			$timestamp = gmdate ( "Y-m-d\TH:i:s\Z" );			
    			$authToken = base64_encode(hash_hmac('sha256',$requestId.$timestamp, $key, true));		
    			setHeaders ($shopId, $requestId, $timestamp, $mode, $authToken, $key, $client);
    			
    //Génération du body			
    		$commonRequest = new commonRequest;		
    			$commonRequest->submissionDate = new DateTime('now',new DateTimeZone('UTC'));				
    			
    		$threeDSRequest = new threeDSRequest;		
    			$threeDSRequest->mode = "ENABLED_FINALIZE";
    			$threeDSRequest->requestId = $threeDSRequestId;
    			$threeDSRequest->pares = $pares;		
    		
    		$createPaymentRequest = new createPayment;
    			$createPaymentRequest->commonRequest = $commonRequest; 
    			$createPaymentRequest->threeDSRequest =  $threeDSRequest;
    			
    			$createPaymentRequest->commonRequest->submissionDate = $createPaymentRequest->commonRequest->submissionDate->format(dateTime::W3C);	
    					
    		try {
    			//Maintien de la session HTTP
    			$client->__setCookie('JSESSIONID', $JSESSIONID);
    							
    			//Appel de l'opération createPayment
    			$createPaymentResponse= new createPaymentResponse();
    			$createPaymentResponse = $client->createPayment($createPaymentRequest);
    		
    		} catch (SoapFault $fault) {
    			//gestion des exceptions	
    			trigger_error("SOAP Fault: (faultcode: {$fault->faultcode}, faultstring: {$fault->faultstring})", E_USER_ERROR);
    					 }
    		
    		/* 
    		 *	Affichage des logs XML à remplacer par une écriture dans un fichier de log.		 
    		 */
    			echo "<hr> [Request Header] <br/>", htmlspecialchars($client->__getLastRequestHeaders()), "<br/>";
    			echo "<hr> [Request] <br/>", htmlspecialchars($client->__getLastRequest()), "<br/>";	
    			echo "<hr> [Response Header]<br/>", htmlspecialchars($client->__getLastResponseHeaders()), "<br/>";
    			echo "<hr> [Response]<br/>", htmlspecialchars($client->__getLastResponse()), "<br/>";
    			echo '<hr>';		
    					
    //Analyse de la réponse
    	//Récupération du SOAP Header de la réponse afin de stocker les en-têtes dans un tableau (ici $responseHeader)	
    		$dom = new DOMDocument;
            $dom->loadXML($client->__getLastResponse(), LIBXML_NOWARNING);
            $path = new DOMXPath($dom);
            $headers = $path->query('//*[local-name()="Header"]/*');		
    		$responseHeader = array();				
    		foreach($headers as $headerItem) {		
    			$responseHeader[$headerItem->nodeName] = $headerItem->nodeValue;				
    		}	
    	
    	//Calcul du jeton d'authentification de la réponse.
    				
    		$authTokenResponse = base64_encode(hash_hmac('sha256',$responseHeader['timestamp'].$responseHeader['requestId'], $key, true));
    		if ($authTokenResponse !== $responseHeader['authToken']){
    			
    			//Erreur de calcul ou tentative de fraude			
    				echo 'Erreur interne rencontrée';
    		}
    		else{		
    			//Analyse de la réponse
    				//Vérification du responseCode
    				if ($createPaymentResponse->createPaymentResult->commonResponse->responseCode != "0"){
    				
    				//process error
    					echo 'erreur interne';		
    				}
    				else{
    				//Process terminé avec succès					
    					//test de la présence du transactionStatusLabel:
    					if (isset ($createPaymentResponse->createPaymentResult->commonResponse->transactionStatusLabel)){
    																	
    					// Le paiement est accepté	
    							// Le code ci-dessous doit être modifié pour intégrer les mises à jour de base de données etc..						
    							switch ($createPaymentResponse->createPaymentResult->commonResponse->transactionStatusLabel) {							
    								case "AUTHORISED":
    										echo "paiement accepté";
    								break;
    								case "WAITING_AUTHORISATION":
    										echo "paiement accepté";
    								break;
    								case "AUTHORISED_TO_VALIDATE":
    										echo "paiement accepté";
    								break;
    								case "WAITING_AUTHORISATION_TO_VALIDATE":
    										echo "paiement accepté";
    								break;							
    							// Le paiement est refusé								
    								default:
    									echo "paiement refusé";
    								break;									
    							}						
    					}
    					else{			
    						echo 'erreur interne';						
    					}
    				}
    			}		
    	}
    	else{
    		//retour du 3DS sans paramètre ou accès direct à la page de retour 3DS
    		echo 'error';
    	}
    ?>