Il existe une multitude de possibilités pour faire un bouton de paiement Paypal, la plus courante est de créer le bouton dans l’interface de celui-ci et de copier coller le code qu’il vous donne au final sur votre page. Le défaut de cette méthode c’est que l’on doit créer un bouton pour chaque objet que l’on vend, la flexibilité n’est donc pas au rendez vous avec cette méthode. La deuxième méthode utilisée est la possibilité de créer un formulaire avec les paramètres définis sur cette page. Avec cette méthode la flexibilité est présente mais pas la sécurité. En effet il est alors facile de modifier le prix du panier dans le formulaire avec l’extension Firebug de Firefox et ainsi falsifier le prix à payer… Si la cohérence des informations n’est pas vérifiée lors du feedback de Paypal (IPN) c’est un réel problème !

Je vais donc vous présenter la méthode permettant de générer le bouton Paypal avec un cryptage SSL des données du formulaire vous garantissant un paiement sécurisé de bout en bout… Attention tout de même cette méthode n’est pas à la portée de tout le monde car il y a certaines contraintes techniques.

Comme je le disais il existe des contraintes techniques et votre environnement doit répondre aux besoins suivants :

  • Un accès à la fonction exec de PHP (exit si votre environnement est configuré en safe_mode à on) ou équivalent.
  • Avoir un accès SSH en ligne de commande (Pour pouvoir générer les certificats SSL, même si je pense qu’ils peuvent être générés sur votre machine et envoyés ensuite sur votre serveur)
  • Avoir OpenSSL d’installé sur le serveur

Etape 1 – Génération des certificats SSL

Connectez vous en SSH sur votre serveur. Si OpenSSL n’est pas installé sur celui-ci, installez le avec cette commande (si vous êtes sous Debian) :

apt-get install openssl

Si vous n’avez pas d’accès à SSH vous pouvez toujours installer OpenSSl sur votre poste sous Windows avec les binaires disponibles ici.

NB: Dans la suite de l’article je n’expliquerais pas les commandes sous Windows mais normalement il suffira de vous placer dans le répertoire où l’exécutable OpenSSL.exe est situé et de remplacer les commandes « openssl » par « openssl.exe ».

Pour commencer mettez vous dans un répertoire disponible par FTP (Il faudra par la suite télécharger un certificat pour l’envoyer à Paypal). Ensuite tapez cette commande pour générer la clé privée :

openssl genrsa -out clepriv.pem 1024

Puis cette commande pour générer le certificat publique :

openssl req -new -key clepriv.pem -x509 -days 365 -out certpub.pem

Remplissez les informations demandées (Pays, Email etc…).

Note importante : Le certificat sera ici valable 1 an, il faudra donc penser que dans un an vous devrez re-générer ce certificat ! Vous pouvez augmenter la durée de vie de celui-ci mais ce n’est pas particulièrement recommandé.

Etape 2 – Envoyer le certificat publique à Paypal et télécharger le certificat publique de Paypal

Maintenant il faut envoyer le certificat publique de votre site à Paypal (certpub.pem) et télécharger le certificat publique de Paypal. Pour se faire connectez vous sur votre compte Paypal et allez dans :

  • Mon Compte =>  Préférences => Plus d’Options => Certificats de cryptage pour site marchand (colonne de droite, en bas)

Commencez par télécharger le certificat publique de Paypal en cliquant sur le bouton « Télécharger ». Vous aurez un fichier qui se nomme paypal_cert_pem.txt, renommez le en paypal_cert.pem.

En bas de page, dans la partie « Vos certificats publics » cliquez sur le bouton « Ajouter » et sélectionnez le fichier certpub.pem que vous avez précédemment généré. Vous reviendrez ensuite sur la page de gestion des certificats et vous devriez voir apparaitre une ligne dans le tableau du bas avec comme informations l’ID du certificat, l’autorité de certification (correspondant aux informations saisies lors de la génération de votre certificat publique) et la date d’expiration de celui-ci. Noter dans un coin l’ID du certificat indiqué il servira par la suite.

A cette étape vous aurez donc en votre possession trois fichiers :

  • certpub.pem
  • clepriv.pem
  • paypal_cert.pem

Etape 3 – Mise en place de la génération du bouton en PHP

Tout d’abord placez les trois fichiers pem dans un répertoire de votre serveur inaccessible par le web, pour être plus explicite il doit être en dehors de la racine HTTP de votre serveur mais il doit toujours être accessible par PHP. Si l’option open_base_dir est active sur votre configuration PHP ajoutez ce répertoire pour que PHP puisse y accéder. Si vous ne pouvez pas modifier cette configuration, vous pouvez éventuellement placer les fichiers dans un répertoire de votre site mais vous devrez mettre un .htaccess empêchant l’accès à ces fichiers. Votre .htaccess ressemblera à ceci :

Options -Indexes
<Files ~ "\.(pem)$">
 	order deny,allow
 	deny from all
</Files>
Options -Indexes

A noter que pour un serveur Apache supérieur à la version 1.3 il vaut mieux utiliser :

Options -Indexes
<FilesMatch "\.(pem)$">
 	order deny,allow
 	deny from all
</FilesMatch>

Maintenant il faut générer le bouton en php, pour faire ceci je vais vous fournir une petite classe PHP5 vous permettant de vous simplifier la vie. Créez un fichier qui se nomme PaypalCrypt.class.php et mettez ceci dedans :

<?php
 
class PaypalCrypt{
 
    private $privateKey = '';
    private $publicKey = '';
    private $paypalKey = '';
    private $pathOpenSSL = '/usr/bin/openssl';
    private $data = array(
        'bn' => 'Boutique_BuyNow_WPS_FR',
        'cmd' => '_xclick',
        'lc' => 'FR',
        'custom' => '',
        'invoice' => '',
        'currency_code' => 'EUR',
        'charset' => 'UTF-8', //Définit le charset utilisé sur le site
        'no_shipping' => '1'
    );
 
    public function __construct(){
        // Nothing
    }
 
    public function addData($key, $data){
        $this->data[$key] = $data;
        return $this;
    }
 
    public function setPrivateKey($privateKey){
        $this->privateKey = $privateKey;
        return $this;
    }
 
    public function setPublicKey($publicKey){
        $this->publicKey = $publicKey;
        return $this;
    }
 
    public function setPaypalKey($paypalKey){
        $this->paypalKey = $paypalKey;
        return $this;
    }
 
    public function getCryptedData(){
        if (!file_exists($this->privateKey))
            throw new Exception('ERROR: MY_KEY_FILE '.$this->privateKey.' not found');
        if (!file_exists($this->publicKey))
            throw new Exception('ERROR: MY_CERT_FILE '.$this->publicKey.' not found');
        if (!file_exists($this->paypalKey))
            throw new Exception('ERROR: PAYPAL_CERT_FILE '.$this->paypalKey.' not found');
 
        $openssl_cmd = "$this->pathOpenSSL  smime -sign -signer $this->publicKey  -inkey $this->privateKey ".
                "-outform der -nodetach -binary| $this->pathOpenSSL smime -encrypt ".
                "-des3 -binary -outform pem $this->paypalKey";
 
        $descriptors = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
        );
 
        $process = proc_open($openssl_cmd, $descriptors, $pipes);
        if (is_resource($process)) {
            foreach ($this->data as $key => &$value)
                if ($value != "")
                    fwrite($pipes[0], "$key=$value\n");
            fflush($pipes[0]);
            fclose($pipes[0]);
 
            $output = "";
            while (!feof($pipes[1]))
                $output .= fgets($pipes[1]);
 
            fclose($pipes[1]);
            $return_value = proc_close($process);
            return $output;
        }
        throw new Exception('ERROR: encryption failed');
    }
 
    public function setOpenSSLPath($path){
        if(!file_exists($path))
            throw new Exception('OpenSSLPath "'.$path.'" don\'t exists');
        $this->pathOpenSSL = $path;
    }
}
?>

Cette classe est au final assez simple, elle permet de définir les certificats à utiliser, d’insérer des valeurs avec la méthode addData (Suivant la documentation Paypal pour les paramètres possibles) et de générer la chaîne cryptée via la méthode getCryptedData. Quelques informations sont prédéfinies dans la propriété $data de l’objet, se sont celles qui ne varient pas. Par défaut le chemin vers l’exécutable OpenSSL sur le serveur est /usr/bin/openssl (valable sous Debian), cette valeur peut être modifiée dans le constructeur de l’objet.

Voici donc un exemple d’utilisation pour la vente d’un objet « Boite à meuh » au prix de 10€ sur le compte Paypal « toto@toto.com » :

<?php
require('/chemin/vers/PaypalCrypt.class.php');
// Initialisation cryptage Paypal
$paypalCrypt = new PaypalCrypt();
$paypalCrypt->setPrivateKey('/chemin/vers/clepriv.pem');
$paypalCrypt->setPublicKey('/chemin/vers/certpub.pem');
$paypalCrypt->setPaypalKey('/chemin/vers/cert/paypal_cert.pem');
$paypalCrypt->addData('cert_id','id_certificat_fourni_par_paypal')
            ->addData('business','toto@toto.com')
            ->addData('no_note','1')
            ->addData('shipping','0')
            ->addData('tax','0')
            ->addData('rm','2')
            ->addData('cbt','Retour sur la boutique')
            ->addData('custom','id_membre')
            ->addData('return','http://mon_site.com/return.php')
            ->addData('cancel_return','http://mon_site.com/cancel.php')
            ->addData('notify_url','http://mon_site.com/ipn.php')
            ->addData('amount','10')
            ->addData('item_name', 'Boite à meuh')
            ->addData('item_number', 'identifiant_produit');
$data = $paypalCrypt->getCryptedData();
?>
<form action="https://www.paypal.com/fr/cgi-bin/webscr" method="post">
    <input type="hidden" name="cmd" value="_s-xclick">
    <input type="hidden" name="encrypted" value="<?php echo $data?>"/>
    <input type="submit" value="Commander" class="input_button">
</form>

Pour l’information cert_id il faut bien entendu fournir la valeur que Paypal vous a donné à l’étape 2 (Oui oui j’ai écrit qu’il fallait le noter :) ).

Et voilà vous avez un joli bouton Paypal crypté en SSL pour faire vos demandes de paiement. Pour connaître toutes les valeurs possibles que vous pouvez ajouter je vous laisse regarder la documentation Paypal. N’oubliez pas non plus que cela ne vous dispense pas de faire toutes les vérifications nécessaires lors du feedback de Paypal (IPN) pour vérifier la cohérence entre la commande passée chez vous et le paiement que vous avez reçu.

MAJ 30/08/2011: Changement de méthode pour l’appel à OpenSSL pour maximiser la compatibilité avec les différentes plateformes (Windows).