PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


PayPal-Integration: Instant Payment Notifications (IPN) einbauen

with 6 comments

Über PayPal gibt es unterschiedlichste Meinungen, die Sperrungen von Accounts sind teilweise willkürlich, in wie weit die amerikanische Regierung die Finger im Spiel hat mag man sich auch ausmalen. Nichtsdestotrotz ist es der aktuell am meisten verbreitete Online-Zahlungsdienst und man kann nahezu überall damit bezahlen. Kein Shop kann sich erlauben keine PayPal Zahlungen anzunehmen, einige Studien sprechen von 18% mehr Umsatz bei Einkäufen wenn PayPal angeboten wird.

Wenn man selbst PayPal Zahlungen entgegen nehmen möchte und diese automatisiert abarbeiten möchte benötigt man die Funktion Instant Payment Notification von PayPal. Im deutschen PayPal wird es „Sofortige Zahlungsbestätigung“ genannt. Ich nehme immer die Abkürzung IPN.

IPN ist ein einfaches Feature: Wann immer eine Transaktion auf dem eigenen Konto stattfindet wird eine bestimmte URL aufgerufen die wir spezifizieren können. Eine Transaktion ist beispielsweise eine erfolgte Zahlung, ein Abonnement, eine Rückzahlung, Rückbuchung, offene oder abgelehnte Zahlung.

Um das IPN-Feature zu aktivieren geht man im PayPal Interface auf „Mein Profil -> Mehr -> Einstellungen für sofortige Zahlungsbestätigung“ und trägt dort eine URL ein, beispielsweise http://www.meinshop.de/payment/paypalipn.php

Dort legen wir dann ein Script hin, und PayPal schickt uns dorthin via POST die Details zum Zahlungsvorgang. Diese können wir dann verifizieren, eigene Prüfungen auf Korrektheit, Sinnhaftigkeit und Vollständigkeit machen, und dann die Zahlung im Shop als bezahlt markieren.

Für die Verifizierung bietet PayPal einen kleinen Dienst an, dorthin kann man die Daten einer Transaktion schicken und sich bestätigen lassen dass sie alle korrekt sind und es diese Zahlung wirklich gegeben hat. Sonst könnte jemand, der die URL herausfindet, gefälschte Daten an unser paypalipn.php Script schicken. Dann ist also sichergestellt dass es die Transaktion bei PayPal gegeben hat, wir prüfen als nächstes ob die Empfänger-E-Mail-Adresse eine unserer E-Mail-Adressen ist, denn ein findiger Mensch könnte ja einfach die Transaktionsdaten an unser Script schicken wie er sich selbst Geld geschickt hat. Als letztes prüfen wir noch den Betrag sowie die eventuell vorhandene Anzahl von gekauften Waren etc.

Wenn das alles geprüft wurde können wir sicher sein dass es eine reguläre Zahlung war und die Bestellung im Shop als bezahlt markieren, eine nette E-Mail an den Kunden schicken dass wir das Geld erhalten haben und die Ware verschicken, bzw. den gekauften Artikel zum Download anbieten, oder was auch immer man machen muss wenn der Kunde bezahlt hat.

Um diese Validierung gegen die PayPal Server und die weiteren Prüfungen etwas zu vereinfachen habe ich eine Klasse geschrieben die die Arbeit auf das notwendigste beschränkt. Ihr findet sie auf GitHub unter dem Namen „PayPal IPN“.

Dort sind Beispieldateien hinterlegt wie die Klasse zu benutzen ist. Meine Basisklasse PHPGangsta_PayPalIPN sollte dazu erweitert werden und mit den nötigen Dingen versehen werden, wie beispielsweise dem E-Mail-Check und den Dingen die bei erfolgter Zahlung passieren sollen (Datenbankeintrag, E-Mail…).

So sieht dann die Benutzung aus. Hier ein Beispiel des Hauptscripts, das nur die Klasse benutzt und die $_POST Daten übergibt:

<?php

/**
 * This is an example using the PayPalIPN class
 *
 *
 * @author Michael Kliewe
 * @copyright 2012 Michael Kliewe
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @link http://www.phpgangsta.de/
 */

require_once '../App/PayPalIPN.php';
$paypalIpn = new App_PayPalIPN();
$paypalIpn->setLogFile('../paypalipn.log')  // make sure this is outside the document root
    ->processIPN($_POST);

Die eigentliche „Arbeit“ macht dann die folgende Klasse, darin sind die benötigten Methoden überschrieben und mit Leben gefüllt:

<?php

/**
 * @author Michael Kliewe
 * @copyright 2012 Michael Kliewe
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @link http://www.phpgangsta.de/
 */

require_once dirname(__FILE__) . '/../PHPGangsta/PayPalIPN.php';

class App_PayPalIPN extends PHPGangsta_PayPalIPN
{
    protected $_useSandbox = true;  // set this to false if you want to run this in Paypal Live Environment

    protected function _checkEmail() {
        $validEmailAddresses = array(
            'seller_1321807401_biz@tg-tg.de',
            'paypal@phpgangsta.de',
            'payment@myshop.de',
        );

        // we check if the receiver email address we got from paypal is one of our email addresses.
        if (!in_array($this->_postData['receiver_email'], $validEmailAddresses)) {
            $this->_writeLog('Invalid receiver email address: ' . $this->_postData['receiver_email']);
            throw new Exception('Invalid receiver email address: ' . $this->_postData['receiver_email']);
        }

        $this->_writeLog('Valid receiver email address found: ' . $this->_postData['receiver_email']);
    }

    protected function _statusCompleted()
    {
        $this->_writeLog('Status completed, writing to database now');

        // Here you can now set the status of the order in the database, send a mail to the customer
        // or whatever is needed in this situation.
        // You can use all variables from $this->_postData array.

    }
}

Das ist das einfache Beispiel, in einem vollständigen Script würde man wahrscheinlich auch noch _checkTxnId(), _checkAmount() und die weiteren _status*() Methoden überschreiben. Aber für einen ersten Test reicht dieses Beispiel.

Bei Fragen und Verbesserungen würde ich mich freuen wenn ihr Kommentare hinterlasst, mich würde interessieren wie ihr das bisher gemacht habt falls ihr schonmal mit PayPal IPNs zu tun hattet. Welche Features fehlen noch?

Written by Michael Kliewe

März 5th, 2012 at 10:01 am

6 Responses to 'PayPal-Integration: Instant Payment Notifications (IPN) einbauen'

Subscribe to comments with RSS or TrackBack to 'PayPal-Integration: Instant Payment Notifications (IPN) einbauen'.

  1. Vielen Dank!
    Zufälligerweise ist das bei uns gerade ziemlich weit oben im Backlog 🙂

    Eric Reiche

    5 Mrz 12 at 10:11

  2. @Eric
    Nimm doch gleich einen Paymentprovider, welcher Paypal mit anbietet. Nach Paypal musst du meist eh zügig Kreditkarte produktseitig nachliefern und so bekommst du beides auf einmal. Und solange du nicht Google, FB oder Amazon bist, brauchst du für KK-Daten einen externen Dienstleister (oder dich kümmert das deutsche Gesetz nicht… 😉 ).

    Mit einem guten Zahlungsprovider erspart man sich auch selbst die mühselige, eigene Sicherheitsvalidierung, welche immer up-to-date sein muss.. Auch ist diese Prüfung wirkich so kritisch, kritisch, die muss du eigentlich bei jedem Verlust eines Mitarbeiters wieder anpassen. Auch muss dein Server wirklich 24/7 verfügbar sein (wenn Paypal zurück anruft). Viel Mühe um wenig Ertrag…

    Ulf Kirsten

    5 Mrz 12 at 20:45

  3. Ich musste nur die Zeile im curl handler „ssl://“ in „https://“ umändern. Ansonsten supi! 🙂

    Oliver

    18 Jul 12 at 14:22

  4. @Oliver In der curl-Funktion wird doch gar kein ssl:// genutzt, wo genau hast du was geändert?

    Michael Kliewe

    18 Jul 12 at 14:48

  5. hm, gute Frage … ich habe es von der Github Seite kopiert und musste das ändern!? Jetzt seh ich es aber auch nicht mehr.

    Oliver

    18 Jul 12 at 16:39

  6. Das ganze geht aber nicht, wenn die Payment Data Transfer per GET übertragen werden in Zusammenhang mit Auto Return, oder? 🙁

    Patrick

    12 Apr 13 at 17:36

Leave a Reply

You can add images to your comment by clicking here.