Erreur lors du lancement de paiement paypal

Aljoira_Khyria

Aljoira_Khyria Le 3 mai 2020 à 21:08 (Édité le 3 mai 2020 à 21:19)

Bonjour, j'ai rééssayé de suivre le tuto de paiemet Paypal mais j'ai une erreur 'undefined' lorsque je clique sur le bouton paypal. Je ne sais pas là est ce que j'ai comis l'erreur. voivi d'abord le code

<!DOCTYPE html>
<html>
    <head>
        <title>test paiement</title>
        <meta charset="utf-8">
        <script src="https://www.paypalobjects.com/api/checkout.js"></script>        
    </head>

    <body>

        <div id="bouton-paypal"></div>
        <script>
            paypal.Button.render({
                  env: 'sandbox', // Ou 'production',
                  commit: true, // Affiche le bouton  "Payer maintenant"
                  style: {
                    color: 'black', // ou 'blue', 'silver', 'black'
                    size: 'small' // ou 'small', 'medium', 'large'
                    // Autres options de style disponibles ici : https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/customize-button/
                  },
                  payment: function() {
                    // On crée une variable contenant le chemin vers notre script PHP côté serveur qui se chargera de créer le paiement
                    var CREATE_URL = 'paypal_create_payment.php';

                    // On exécute notre requête pour créer le paiement
                    return paypal.request.post(CREATE_URL)
                      .then(function(data) { // Notre script PHP renvoie un certain nombre d'informations en JSON (vous savez, grâce à notre echo json_encode(...) dans notre script PHP !) qui seront récupérées ici dans la variable "data"
                        if (data.success) { // Si success est vrai (<=> 1), on peut renvoyer l'id du paiement généré par PayPal et stocké dans notre data.paypal_reponse (notre script en aura besoin pour poursuivre le processus de paiement)
                            alert("ok");
                            return data.paypal_response.id;
                        } else { // Sinon, il y a eu une erreur quelque part. On affiche donc à l'utilisateur notre message d'erreur généré côté serveur et passé dans le paramètre data.msg, puis on retourne false, ce qui aura pour conséquence de stopper net le processus de paiement.
                           alert(data.msg);
                           return false;   
                        }
                     });
                  },
                  onAuthorize: function(data, actions) {
                    // On indique le chemin vers notre script PHP qui se chargera d'exécuter le paiement (appelé après approbation de l'utilisateur côté client).
                    var EXECUTE_URL = 'paypal_execute_payment.php';
                    // On met en place les données à envoyer à notre script côté serveur
                    // Ici, c'est PayPal qui se charge de remplir le paramètre data avec les informations importantes :
                    // - paymentID est l'id du paiement que nous avions précédemment demandé à PayPal de générer (côté serveur) et que nous avions ensuite retourné dans notre fonction "payment"
                    // - payerID est l'id PayPal de notre client
                    // Ce couple de données nous permettra, une fois envoyé côté serveur, d'exécuter effectivement le paiement (et donc de recevoir le montant du paiement sur notre compte PayPal).
                    // Attention : ces données étant fournies par PayPal, leur nom ne peut pas être modifié ("paymentID" et "payerID").
                    var data = {
                      paymentID: data.paymentID,
                      payerID: data.payerID
                    };
                    // On envoie la requête à notre script côté serveur
                    return paypal.request.post(EXECUTE_URL, data)
                      .then(function (data) { // Notre script renverra une réponse (du JSON), à nouveau stockée dans le paramètre "data"
                      if (data.success) { // Si le paiement a bien été validé, on peut par exemple rediriger l'utilisateur vers une nouvelle page, ou encore lui afficher un message indiquant que son paiement a bien été pris en compte, etc.
                        // Exemple : window.location.replace("Une url quelconque");
                        alert("Paiement approuvé ! Merci !");
                      } else {
                        // Sinon, si "success" n'est pas vrai, cela signifie que l'exécution du paiement a échoué. On peut donc afficher notre message d'erreur créé côté serveur et stocké dans "data.msg".
                        alert(data.msg);
                      }
                    });
                  },
                  onCancel: function(data, actions) {
                    alert("Paiement annulé : vous avez fermé la fenêtre de paiement.");
                  },
                  onError: function(err) {
                    alert("Paiement annulé : une erreur est survenue. Merci de bien vouloir réessayer ultérieurement.");
                  }
                }, '#bouton-paypal');
          </script>
        </body>
</html>
Aljoira_Khyria

Aljoira_Khyria Le 3 mai 2020 à 21:10

voivi le code du fichier paypal_execute_payment.php

<?php

    $bdd = new PDO('mysql:host=localhost;dbname=tout_histoire', 'root', '');
    $bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $bdd->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);

    require_once "PayPalPayment.php"; // On inclue les fichiers relativement à la position du fichier actuel

    $success = 0;
    $msg = "Une erreur est survenue, merci de bien vouloir réessayer ultérieurement...";//message initialisé par défaut en cas d'ereur du paiement
    $paypal_response = [];//contiendra tout ce que PayPal nous enverra via son API

    if (!empty($_POST['paymentID']) AND !empty($_POST['payerID'])) {
       $paymentID = htmlspecialchars($_POST['paymentID']);
       $payerID = htmlspecialchars($_POST['payerID']);

        $payer = new PayPalPayment();
        $payer->setSandboxMode(1);

        //Information contenues dans My app credentials (pappaldevelopper)
        $payer->setClientID("AS33W5qS9FBYZ-HJzwMhpE-tFW2Eqivn6vwV6fpaz40CqYCH6Ajae5MmwL6yH3SHhSG4loAjWzRsP7VQ"); //mon identité client
        $payer->setSecret("EHIM6BcPZxLdj9XpDqhyBNztFTyz6EKt4ROWvgz9D2yAblqEOBjxib24hPs26fMOF_Zzos7JBbFyCCzn");//mon code secret

        $payment = $bdd->prepare('SELECT * FROM paiements WHERE payment_id = ?');
        $payment->execute(array($paymentID));
        $payment = $payment->fetch();

       if ($payment) {
           $paypal_response = $payer->executePayment($paymentID, $payerID);
           $paypal_response = json_decode($paypal_response);

           $update_payment = $bdd->prepare('UPDATE paiements SET payment_status = ?, payer_email = ? WHERE payment_id = ?');
           $update_payment->execute(array($paypal_response->state, $paypal_response->payer->payer_info->email, $paymentID));

           if ($paypal_response->state == "approved") {
                 $success = 1;
                 $msg = "Votre souscription à l'abonnement a été réalisé avec succès";
           } else {
                 $msg = "Une erreur est survenue durant l'approbation de votre paiement. Merci de réessayer ultérieurement ou contacter un administrateur du site.";
            }

       } else {
          $msg = "Votre paiement n'a pas été trouvé dans notre base de données. Merci de réessayer ultérieurement ou contacter un administrateur du site. (Votre compte PayPal n'a pas été débité)";
       }
    }
    echo json_encode(["success" => $success, "msg" => $msg, "paypal_response" => $paypal_response]);   
?>
Aljoira_Khyria

Aljoira_Khyria Le 3 mai 2020 à 21:15 (Édité le 3 mai 2020 à 21:25)

Le code du fichier paypal_create_payment.php. Lorsque je le lance directement sans passer par mon fichier index pour essayé de voir ou est l'erreur j'ai Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in C:\xampp\htdocs\paypal_create_payment.php:61 Stack trace: #0 C:\xampp\htdocs\paypal_create_payment.php(61): PDOStatement->execute(Array) #1 {main} thrown in C:\xampp\htdocs\paypal_create_payment.php on line 61

<?php

    require_once "config.php";
    require_once "PayPalPayment.php"; // On inclue les fichiers relativement à la position du fichier actuel

    $success = 0;
    $msg = "Une erreur est survenue, merci de bien vouloir réessayer ultérieurement...";//message initialisé par défaut en cas d'ereur du paiement
    $paypal_response = [];//contiendra tout ce que PayPal nous enverra via son API

    //initialisation d'un objet à partir de notre classe PayPalPayment
    $payer = new PayPalPayment();//Nouveau paiement
    $payer->setSandboxMode(1); // On active le mode Sandbox

    //Information contenues dans My app credentials (pappaldevelopper)
    $payer->setClientID("AS33W5qS9FBYZ-HJzwMhpE-tFW2Eqivn6vwV6fpaz40CqYCH6Ajae5MmwL6yH3SHhSG4loAjWzRsP7VQ"); //mon identité client
    $payer->setSecret("EHIM6BcPZxLdj9XpDqhyBNztFTyz6EKt4ROWvgz9D2yAblqEOBjxib24hPs26fMOF_Zzos7JBbFyCCzn");//mon code secret

    //données de paiement
    $payment_data = [
        "intent" => "sale",
            "redirect_urls" =>[
                "return_url" => "http://localhost/",//url de retour
                "cancel_url" => "http://localhost/"//url de retour après annulation/échouement
            ],
            "payer" => [
                "payment_method" => "paypal" //methode de paiement
            ],
            "transactions" => [
                [
                    "amount" => [
                    "total" => "9.99",//prix totale de la commande
                    "currency" => "EUR"//devise à utiliser
                ],
                "item_list" => [
                    "items" => [
                        [
                            "sku" => "1PK5Z9",//code référentiel du produit
                            "quantity" => "1",//Nombre d'article à commander
                            "name" => "Un produit quelconque",
                            "price" => "9.99",//prix de notre produit
                            "currency" => "EUR"//devise à utiliser
                           ]
                        ]
                     ],
                  "description" => "ACHAT PC"//description du produit
                  ]
               ]
    ];

    $paypal_response = $payer->createPayment($payment_data);//on utiliste la fonct. createPayment et en récupère les datas du payment ($payment_data)
    $paypal_response = json_decode($paypal_response);//on fait appel au json_decode pour lire les données comme des tableaux / objets en PHP

    if (!empty($paypal_response->id)) {
           $insert = $bdd->prepare("INSERT INTO paiements (payment_id, payment_status, payment_amount, payment_currency, payment_date, payer_email, payer_paypal_id, payer_first_name, payer_last_name) VALUES (:payment_id, payment_status, payment_amount, payment_currency, NOW(), '', '', '', '')");

              $insert_ok = $insert->execute(array(
                 "payment_id" => $paypal_response->id,
                 "payment_status" => $paypal_response->state,
                 "payment_amount" => $paypal_response->transactions[0]->amount->total,
                 "payment_currency" => $paypal_response->transactions[0]->amount->currency,
              ));

           if ($insert_ok) {
              $success = 1;
              $msg = "";
           }
        } else {
           $msg = "Une erreur est survenue durant la communication avec les serveurs de PayPal. Merci de bien vouloir réessayer ultérieurement.";
        }

        echo json_encode(["success" => $success, "msg" => $msg, "paypal_response" => $paypal_response]);
?>

et celui de config.php

<?php
    session_start();

    $bdd = new PDO('mysql:host=localhost;dbname=tout_histoire', 'root', '');
    $bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $bdd->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
?>

pour celui de PayPalPaiement.php je ne l'ai pas touché voici son code

<?php
class PayPalPayment {

    protected $sandbox_mode,
          $client_id,
          $client_secret,
          $access_token;

    public function __construct() {
        $this->sandbox_mode = 1;
        $this->client_id = "";
        $this->client_secret = "";
        $this->access_token = "";
    }

    /**
     * Définit le mode Sandbox / Live du paiement : 1 (ou true) pour le mode Sandbox, 0 (ou false) pour le mode Live
     */
    public function setSandboxMode($mode) {
        $this->sandbox_mode = ($mode) ? true : false;
    }

    /**
     * Définit le Client ID à utiliser (à récupérer dans les Credentials PayPal)
     */
    public function setClientID($clientid) {
        $this->client_id = $clientid;
    }

    /**
     * Définit le Secret à utiliser (à récupérer dans les Credentials PayPal)
     */
    public function setSecret($secret) {
        $this->client_secret = $secret;
    }

    /**
     * Génère un access token depuis l'API PayPal et le stock en variable de session
     * Renvoie l'access token généré si réussi sinon false
     * (Pour communiquer avec l'API PayPal, il est obligatoire de s'authentifier à l'aide de ce "Access Token" qui est généré à partir des Credentials : Client ID et Secret)
     */
    public function generateAccessToken() {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        if ($this->sandbox_mode) {
            curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/v1/oauth2/token");  //DUMMY
        } else {
            curl_setopt($ch, CURLOPT_URL, "https://api.paypal.com/v1/oauth2/token");  //LIVE
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=client_credentials");
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_USERPWD, $this->client_id . ":" . $this->client_secret);

        $headers = array();
        $headers[] = "Accept: application/json";
        $headers[] = "Accept-Language: en_US";
        $headers[] = "Content-Type: application/x-www-form-urlencoded";
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        $result = curl_exec($ch);
        $data = json_decode($result);
        curl_close ($ch);

        $access_token = $data->access_token;

        // Récupérer le nombre de secondes avant expiration :
        $timestamp_expiration = intval($data->expires_in) - 120; // Timestamp donné -2 minutes (marge supplémentaire)

        // Création des variables de session avec expiration_date et access_token
        $_SESSION['paypal_token'] = [];
        $_SESSION['paypal_token']['access_token'] = $access_token;
        $_SESSION['paypal_token']['expiration_timestamp'] = time() + $timestamp_expiration;

        if ($access_token) {
            return $access_token;
        } else {
            return false;
        }
    }

    /**
     * Renvoie un access token (demande à en générer un nouveau si besoin)
     */
    public function getAccessToken() {
        if ($this->access_token) {
            return $this->access_token;
        } else {
            $access_token = "";
            if (!empty($_SESSION['paypal_token'])) {
                // Vérifier si le token n'a pas expiré
                if (time() <= $_SESSION['paypal_token']['expiration_timestamp']) {
                    if (!empty($_SESSION['paypal_token']['access_token'])) {
                        $access_token = $_SESSION['paypal_token']['access_token'];
                    }
                }
            }

            // Si l'access_token renvoyé est vide, on en génère un nouveau
            if (!$access_token) {
                $access_token = $this->generateAccessToken();
            }

            return $access_token;
        }
    }

    /**
     * Crée le paiement via l'API PayPal et renvoie la réponse du serveur PayPal
     */
    public function createPayment($payment_data) {
        /* Exemple de format pour le paramètre $payment_data à passer :
        $payment_data = [
            "intent" => "sale",
            "redirect_urls" => [
                "return_url" => "http://localhost/",
                "cancel_url" => "http://localhost/"
            ],
            "payer" => [
                "payment_method" => "paypal"
            ],
            "transactions" => [
                [
                    "amount" => [
                        "total" => "Montant total de la transaction",
                        "currency" => "EUR" // USD, CAD, etc.
                    ],
                    "item_list" => [
                        "items" => [
                            [
                                "quantity" => "1",
                                "sku" => "Code de l'item"
                                "name" => "Nom de l'item",
                                "price" => "xx.xx",
                                "currency" => "EUR"
                            ]
                        ]
                    ],
                    "description" => "Description du paiement..."
                ]
            ]
        ];
        */

        $authorization = "Authorization: Bearer ".$this->getAccessToken();

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        if ($this->sandbox_mode) {
            curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.paypal.com/v1/payments/payment");
        } else {
            curl_setopt($ch, CURLOPT_URL, "https://api.paypal.com/v1/payments/payment");
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization ));
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payment_data));

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $server_output = curl_exec ($ch);
        curl_close ($ch);

        return $server_output;
    }

    /**
     * Exécute un paiement via l'API PayPal et renvoie la réponse de PayPal
     */
    public function executePayment($paymentID, $payerID) {
        if ($this->sandbox_mode) {
            $paypal_url = "https://api.sandbox.paypal.com/v1/payments/payment/".$paymentID."/execute/";
        } else {
            $paypal_url = "https://api.paypal.com/v1/payments/payment/".$paymentID."/execute/";
        }
        $authorization = "Authorization: Bearer ".$this->getAccessToken();

        $data = ["payer_id" => $payerID];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_URL, $paypal_url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization ));
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $server_output = curl_exec ($ch);
        curl_close ($ch);

        return $server_output;
    }
}
PrimFX

PrimFX Le 20 mai 2020 à 11:48

Bonjour @Aljoira_Khyria !

J'ai malheureusement du mal à voir d'où peut venir l'erreur, même avec le code sous les yeux.

Lorsque tu exécutes le code de paypal_create_payment.php directement (sans passer par ton index), c'est à priori normal qu'une erreur soit affichée puisqu'il "manque" des paramètres que PayPal doit passer depuis ton index pour que le script s'exécute correctement.

Pour ce undefined, est-ce que tu pourrais envoyer deux screenshots :

  • Ce que t'affiches ta console JavaScript après avoir cliqué sur le bouton PayPal (ça donnera peut-être des informations sur la provenance de ce undefined)
  • Dans les outils de développement de ton navigateur (pas loin de la console), tu dois également avoir un onglet "Réseau" ou "Network" : il faudrait que tu ouvres cet onglet, que tu cliques sur le bouton PayPal, puis que tu cliques sur la requête qui vient de s'exécuter (qui devrait terminer par paypal_create_payment.php) pour avoir un aperçu du retour (réponse) du script une fois exécuté. Voiic à quoi ça devrait ressembler (avec un contenu évidemment différent 😅) :

Screenshot network preview console

Ces éléments devraient déjà permettre d'isoler correctement la provenance de l'erreur (JS, scirpt PHP, autre) 😉

A bientôt,

Boris

thomasweb

thomasweb Le 20 août 2020 à 01:41 (Édité le 20 août 2020 à 01:41)

Bonjour ! <br> Alors je crois bien que c'est dans ton paypal_create_payment, j'ai eu le même soucis, il mdoit sûrement manquer les ':' devant tes valeurs dans ta requête préparée. Il ne les considère pas comme des paramètres.

Vous devez être connecté pour poster une réponse. Se connecter ou Créer un compte