14 commentaires

Automatiser son backoffice avec Paypal IPN

Paypal possède une grande notoriété et je ne vous le présenterai donc pas. C’est un bon choix d’intermédiaire pour récolter des paiements sur son site internet. Qu’il soit seul ou couplé à une solution bancaire, Paypal est devenu indispensable. Seulement, Paypal propose une multiplicité de moyens d’intégration sur son site. Du bouton HTML à l’API NVP, il est parfois difficile d’automatiser son backoffice. De l’envoi d’un email de confirmation de commande à la synchronisation de sa base de données clients, l’automatisation est plus pratique – et efficace – que d’attendre les mails de confirmation paiement de Paypal et d’agir manuellement.

Différentes technologies de paiement

Dans l’ensemble, Paypal dispose de trois moyens d’intégrer sa solution de paiement :

IPN : Instant Payment Notification

schéma paypal ipn
Illustration du fonctionnement de l'IPN
L'IPN, s'est en fait le serveur de Paypal qui va se connecter à votre site pour vous avertir d'un paiement, d'un échec… C'est donc un moyen pour vous de savoir si vous avez été payé pour telle ou telle chose, quand et combien, et d'agir en conséquence. À chaque fois que Paypal veut vous notifier d’un paiement (ou annulation etc), il se connecte à votre site via une url que vous aurez définie et transmet donc les informations à votre script.

Cependant, les deux API de Paypal, de la même manière que l’API ATOS, fonctionnent selon le modèle de dialogue client-serveur, et de ce fait, votre site est immédiatement au courant de la réussite ou de l’échec du paiement. Vous vous dîtes alors, à juste titre, que l’intérêt de l’IPN est limité, il servira uniquement aux sites se servant des boutons html et qui n’ont donc pas immédiatement connaissance du résultat du paiement. Pas tout à fait…

D’une part, c’est sans compter par exemple, sur la possibilité des paiements récurrents de Paypal. Dans ce cas, votre utilisateur souscrit un abonnement, donc au premier paiement, il passe par votre site et l’API (ou les boutons html), mais ensuite, il est débité à l’initiative de Paypal sans devoir repasser par votre site, et donc votre API ne vous sera d’aucun secours pour être notifié de la réussite ou de l’échec du paiement.

D’autre part, un paiement peut-être annulé, ou remboursé, et cela s’effectue aussi en dehors de votre API SOAP ou NVP. En revanche, nous l’avons évoqué plus haut, la connexion de l’IPN est à l’initiative de Paypal, ce dernier notifiera donc votre site aussi pour la réception d’un paiement récurrent. C’est dans ce cas que l’IPN prend tout son intérêt.

La mise en place

La mise en place de l’IPN peut se faire dans divers langages, ASP, Perl, JAVA, ColdFusion… Vous retrouverez des exemple de codes sur le site des développeurs. Pour notre part, nous allons mettre en place l’IPN en PHP. Je vous laisse donc directement avec le code, dûment commenté :

<?php

// prépare la requête de vérification
$req = "cmd=_notify-validate";

// ajoute le message IPN au format NVP à la requête de vérification
foreach ($_POST as $key => $value) {
    $value = urlencode(stripslashes($value));
    $req .= '&$key=$value';
}


// définition des headers pour la requête de vérification
$header  = "POST /cgi-bin/webscr HTTP/1.0rn";

// test
//$header .= "Host: www.sandbox.paypal.com:443rn";

// production
$header .= "Host: ipnpb.paypal.com:443rn";

$header .= "Content-Type: application/x-www-form-urlencodedrn";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";


// Ouverture du socket

// test
//$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);

// production
$fp = fsockopen ('ssl://ipnpb.paypal.com', 443, $errno, $errstr, 30);

// s'il y a une erreur lors de l'ouverture du socket
if (!$fp) {
    // on s'envoie un mail pour être informé de l'erreur
    $msg = 'Erreur de socket, l\'url n\'a pas pu être ouverte';
    mail('payments@monmail.fr', 'erreur socket', $msg);
}

else {
    // on post la requête de vérification
    fputs ($fp, $header . $req);

    // créé une boucle tant qu'on est pas arrivé à la fin du fichier
    while (!feof($fp)) {
        // lit la réponse de paypal
        $res = fgets ($fp, 1024);

        // si paypal répond VERIFIED,
        // tout s'est bien déroulé et on peut procéder à nos traitements
        if (strcmp ($res, 'VERIFIED') == 0) {
            // type de transaction
            // $_POST['txn_type']

            // mail du compte paypal à qui est destiné le paiement
            // $_POST['receiver_email']

            // montant
            // $_POST['mc_gross']

            // id de la transaction
            // $_POST['txn_id']

            // champ personnalisé
            // $_POST['custom']
        }

        // si la transaction est invalide
        else if (strcmp ($res, 'INVALID') == 0) {
            // on s'envoie un mail pour être informé de l'erreur
            $msg = 'Message de l\'IPN : '.$res;
            mail('payments@monmail.fr', 'erreur IPN', $msg);
        }
    }

    fclose ($fp);
}

Il y a beaucoup beaucoup de variables disponibles. Il est toujours utile de faire un foreach de $_POST et de logger le résultat ou de se l’envoyer par mail pour voir ce qu’il contient. Il va aussi vous falloir jouer un peu avec le simulateur de messages IPN.

Cependant, le simulateur n’est pas parfaitement complet, en effet, il n’offre pas toutes les possibilités, par exemple les paiements récurrents n’y figurent pas… Il faudra donc finir par se faire quelques tests “réels” en s’envoyant de vrais paiements puis en se remboursant entre deux vrais comptes Paypal. Enfin, face à la richesse des variables et des infos, il vous sera bien utile de jeter un œil à la doc qui regroupe les différentes variables IPN.

Par ailleurs, je souligne l’intérêt de la variable custom, qui permet par exemple, de faire passer l’id d’un membre et d’ainsi créditer son compte du paiement. Celle-ci se transmet très facilement, par exemple via les boutons html. Notons néanmoins qu’elle ne permet du coup pas le chiffrement du boutons :

<input type="hidden" name="custom" value="2">

À propos du chiffrement, sachez que Paypal permet de chiffrer les boutons HTML; Ils ne sont ainsi pas modifiable dans le code de la page. Je préfère pour ma part les boutons non chiffrés (avec une validation à posteriori des montants etc.) car on peut directement les modifier côté serveur ou même directement en javascript. J’ai remarqué que par défaut Paypal enregistre les boutons si vous êtes connecté. Déconnectez-vous avant tout puis rendez-vous sur la page de création de bouton.

Enfin, une fois votre script en place, vous devez configurer votre serveur web pour qu’il soit accessible via une url particulière. Ensuite il faut vous connecter à votre compte paypal et aller à Mes préférences > mes ventes > notifications instantanées de paiement, pour configurer l’url auquel paypal doit notifier votre site.

interface de configuration de l'ipn paypal
Page de configuration de l'IPN
Je vous souhaite bien entendu une bonne mise en place, et par la suite, de recevoir beaucoup de paiements !

Commentaires

Franck dit –

Pourquoi la quasi totalité des tutos, outre le fait d'user d'un même scripte, font l'impasse systématique sur l'intégration des variable ipn dans la base de donnée du serveur client ? Est-ce à dire que c'est impossible ???

Merci

Franck

Buzut dit –

Si je comprend bien ta demande, tu cherches à enregistrer en BDD les données que tu reçois de l'ipn, telles que le montant, la date, la ref transaction etc.

Si oui, la plupart des tuto n'en parlent certainement pas puisqu'une fois tes variables récupérées, les enregistrer dans la base n'est pas spécifique à IPN mais à la base que tu utilises et à l'interface choisie pour te connecter à cette dernière (ex. PDO).

Franck dit –

Si je crais un tuto pour enseigner la conduite auto, même si la motorisation est multiple, je ne ferais pas l'impasse sur le fait qu'une bonne conduite ne se fait pas sans énergie (essence, gasoil, gaz, électricité... Donc en ce qui concerne l'ipn il me semble NORMAL d'évoquer l'enregistrement en BDD, ne serait-ce que pour la manière de récupérer les infos (commun à TOUS les traitements possible) et ensuite trois mots pour expliquer que l'enregoistrement dépend du mode de "stockage" ! Ou je n'ai rien compris, ou le but d'un tuto est d'apporter une aide su un sujet non maitrisé par l'utilisateur dudit tuto !!

Buzut dit –

Les infos sont dans des variables, je les donne et dit ce qu'elles contiennent : $_POST['txn_type'] … c'est donc la base pour récupérer les infos, les enregistrer en base, ce n'est pas du ressort de ce tuto.

Oui un tuto est sensé apporter une aide sur un sujet nom maitrisé, en l’occurrence paypal ipn. Pas MySQL, ou postgre ou php. Il faudrait que j'explique comment on se sert de php aussi ? Et d'un ordinateur, puisque pour se servir de paypal, le prérequis est aussi de savoir se servir d'un ordinateur.

L'enregistrement en base de données, je le répète, dépend du moteur de base, du schéma qui est propre à l'utilisateur et de pleins d'autres facteurs. Cela dépend donc de l'utilisateur et j'estime que les gens qui lisent ce tuto savent se servir d'une base de données. Si ce n'est pas le cas, il y a sur le net de très bon tutos sur la multitude de bases existantes.

Franck dit –

Ce qui se conçoit bien s'énonce clairement et les mots pour le dire arrivent aisément : donc sur ce sujet pécis il n'est pas question de donner un cours hors sujet, mais SIMPLEMENT d'indiquer comment retrouver les variables et à quelle étape les traiter, à moins qu'il faille un tuto pour expliquer qu'à un moment la procédure expliquée devient hors sujet? D'où : Si je crais un tuto pour enseigner la conduite auto, même si la motorisation est multiple, je ne ferais pas l’impasse sur le fait qu’une bonne conduite ne se fait pas sans énergie (essence, gasoil, gaz, électricité…) Sans avoir à donner des cours de chimie et de physique quant à la composition ou à la production de l'énergie choisie !!!

Vengeur dit –

Franck, t'es con comme une bite, remercie plutôt l'auteur de ce bon tuto et nous les brise pas.

Vincent dit –

Bonjour,

et merci pour ce tuto qui tombe à point: j'essaie de mettre en place un principe d'abonnement sur mon site web et j'avoue que tout n'est pas simple, notamment la mise à jour de ma BDD en fonction des règlements mensuels de mes clients.

Mais dans votre article, je ne comprends pas plusieurs choses... D'un côté vous dites "[...]la connexion de l’IPN est à l’initiative de Paypal, ce dernier notifiera donc votre site aussi pour la réception d’un paiement récurrent. C’est dans ce cas que l’IPN prend tout son intérêt." De l'autre votre code est à l'initiative du site web (et doit fonctionner par cron j'imagine). Quelle est la bonne solution? Doit-on attendre que l'IPN contacte le site web pour enregistrer un paiement récurrent ? Tout ceci est assez confus pour le moment de mon côté.

Merci pour votre aide. Vincent

Buzut dit –

Bonjour Vincent,

On comprend son fonctionnement à travers le schéma et cette phrase juste ensuite : "L’IPN, c’est en fait le serveur de Paypal qui va se connecter à votre site pour vous avertir d’un paiement, d’un échec…". Cependant, j'ai ajouté en bas fin d'article la procédure pour enregistrer l'url de notif dans paypal, ce sera plus clair ainsi.

En réalité le code ipn réside donc sur votre site web mais il n'est pas activé par un cron. Il répond à une certaine URL que vous spécifiez dans l'interface de paypal. A chaque fois que paypal veut vous notifier d'un paiement (ou annulation etc), il se connecte à votre site via cette url et transmet donc les informations à votre script.

Ai-je éclairé vos lanternes ?

Vincent dit –

Bonsoir Franck,

ok bien compris. J'aurais pu le déceler puisqu'en effet vous parcourez les valeurs du $_POST en début de script... mea culpa ! Merci pour votre réponse et pour ce tuto, c'est effectivement limpide maintenant. Je vous tiens au courant dès que ça fonctionne.

Bonne soirée, Vincent

Franck dit –

En fait le défaut de beaucoup de tuto est de tenir pour acquis des connaissances dont l'absence est la raison d'être du tuto... Mon expérience personnelle : en 3 ans j'ai appris beaucoup de langages pour le développement internet, mais je ne veux pas passer ma vie à apprendre encore et encore simplement pour l'intégration d'un script... Pourtant il semble que beaucoup de forum ne sont là que pour se poser en "enseignant" pour ne donner que la voie... Rassurez-vous, hormis le point de détail relevé, votre tuto rempli son rôle...

Cordialement

Mark dit –

Bonjour à tous, merci pour ce bon tuto. Cependant j'aimerais savoir comment faire si le client fait un paiement différé par virement. En appliquant ce tuto, le paiement est "VERIFIED" et son abonnement est validé. Sauf que le client peut annulé son virement par la suite. Merci

Mark dit –

J'ai oublié de précisé que j'ai quand même essayé avec:

if ( $payment_status == "Completed") {$JeValideLabonnement;}

Buzut dit –

Côté sécurisation des paiements et remboursement, c'est du côté du compte qu'il faut voir. Est-il possible de le bloquer ? À voir avec Paypal mais tu ne pourras pas agir là dessus dans le code…

max dit –

bonjour je ne sais pas si c'est encore valide en 2021 mais je ne récupère pas les post. Comment avoir tous les noms des posts qui existe ? pas trouver je voudrais récupérer le nom de l'article, si c'est bien en euro etc

Rejoignez la discussion !

Vous pouvez utiliser Markdown pour les liens [ancre de lien](url), la mise en *italique* et en **gras**. Enfin pour le code, vous pouvez utiliser la syntaxe `inline` et la syntaxe bloc

```
ceci est un bloc
de code
```