Home > Programmierung > Verschlüsselte PayPal-Zahlung (EWP) mit PHP5

Verschlüsselte PayPal-Zahlung (EWP) mit PHP5

Ich hatte die letzten 2 Tage damit zu tun, den Aufruf der Sofortigen Zahlung (Web Payment) von PayPal zu verschlüsseln, damit niemand mit den Parametern schabernack treiben kann. Hierbei gibt es das große Problem, dass auf der PayPal-Developer-Seite zwar viel steht, aber eigentlich doch wieder nichts. Dennoch kommt hier die Lösung in Form einer PHP5-Klasse.

Fündig wurde ich im Supportforum von PayPal, der dortige Link auf ein PHP-Script führt leier ins leere, doch netter weise hat jemand diesen Code überarbeitet und als Anhang an seinen Post der Community zurück gegeben. Ich habe mir den Sourcecode geschnappt, den Code etwas bereinigt und auf PHP5 OOP-Standard umgebaut. Er ist nicht perfekt aber funktioniert problemlos! Wichtig ist hierbei, dass PHP in ein temporäres Verzeichnis schreiben darf und PHP mit OpenSSL-Funktionen ausgestattet ist. Das Verzeichnis ist nötig, da PayPal eine verschlüsselung der Daten fordert, welche eigentlich für die Verschlüsselung von Emails gedacht ist und die entsprechenden PHP-Funktionen also nur mit Dateien umgehen können. Sicherlich könnte man hier auch mit Streams arbeiten, dennoch funktioniert meine Version genauso gut.

Folgende Schritte sind für die verschlüsselten Zahlungsoptionen (Encrypted Website Payments (EWP)) nötig:

  • Erstellen eines privaten und öffentlichen Schlüssels mit OpenSSL (1024bit)openssl genrsa -out my-privatekey.pem 1024
  • Erstellen eines öffentliches Zertifikates mit dem privaten Schlüssel (Gültigkeit: 365 Tage)openssl req -new -key my-privatekey.pem -x509 -days 365 -out my-publiccert.pem
  • Einloggen in den PayPal Business Account und unter Profil auf „Verschlüsselte Zahlungseinstellungen“ klicken. Dort den öffentlichen Schlüssel hochladen und die generierte Zertifikat-ID notieren.
  • Download des öffentlichen PayPal-Zertifikats und nun die eigenen beiden Zertifikate und das PayPal zertifikat an einen sicheren Ort, am besten ausserhalb des DocumentRoot des Webservers kopieren. Niemand darf zugriff auf den eigenen privaten Schlüssel bekommen!

Nun kann meine PHP-PayPal-EWP-Klasse (tolles Wort) von hier heruntergeladen werden. Dem Construcot der Klasse übergibt man 4 Parameter: Zertifikat-ID, den Pfad zum eigenen öffentlichen Schlüssel, den Pfad zum eigenen privaten Schlüssel und den Pfad zum öffentlichen PayPal-Zertifikat. Der anschließende Aufruf der Methode encryptButton() gibt den kompletten verschlüsselten Formulareintrag zurück, welcher in ein hidden-Feld geschrieben werden muss. Die encryptButton() Methode erwartet als Parameter ein Array mit den Optionen für PayPal. Dort muss die Email-Adresse des PayPal-Accounts, sowie die Währung und der Gesamtpreis übergeben werden. Der Rest ist optional, der Wert des cmd Feldes lautet standardmäßig „_xclick“ für eine einfache Zahlung eines festen Betrags. Hier noch ein Codebeispiel für PHP und den HTML-Code:

<?php
require_once(‚class_paypal_ewp.php‘);
$paypal_dir = ‚/pfad/zu/den/zertifikaten/‘;
$paypal_url = ‚http://www.paypal.com‘; // oder www.sandbox.paypal.com fuer Entwickler
$paypal_zertifikat_id = ‚abcdef‘; // Zertifikat-ID von der PayPal Seite

$paypal = new PayPalEWP($paypal_zertifikat_id, $paypal_dir.’my-publickey.pem‘, $paypal_dir.’my-privatekey.pem‘, $paypal_dir.’paypal-cert.pem‘);

$parameters = array(
‚cmd‘ => ‚_xclick‘,
‚business‘ => ‚mein@paypalaccount.de‘,
‚item_name‘ => ‚Test Gegenstand‘, // Name der Bestellung
‚amount‘ => ‚00.01‘, // Wert
’no_shipping‘ => ‚1‘, // Keine Versandkosten
‚return‘ => ‚http://www.beispiel.de/paypal_ok.php‘, // URL fuer erfolgreiche Zahlung
‚cancel_return‘ => ‚http://www.beispiel.de/paypal_cancel.php‘, // URL fuer Zahlungsabbruch
’no_note‘ => ‚1‘, // Keine Notizen vom Kauefer moeglich
‚currency_code‘ => ‚EUR‘,
‚lc‘ => ‚DE‘,
‚rm‘ => ‚2‘, // Der return-URL werden die Paramater als POST uebergeben
‚bn‘ => ‚PP-BuyNowBF‘,
‚custom‘ => ‚Irgendwas was mitgeschickt werden soll‘
);

$encrypted = $paypal->encryptButton($parameters);

?>

<html>
<head><title>PayPal Test</title></head>
<body>
<form action=“<?= $paypal_url ?>/cgi-bin/webscr“ method=“post“>
<input type=“hidden“ name=“cmd“ value=“_s-xclick“ />
<input type=“image“ src=“https://www.paypal.com/de_DE/i/btn/x-click-but01.gif“ border=“0″ name=“submit“ alt=“Zahlen Sie mit PayPal – schnell, kostenlos und sicher!“ />
<img alt=““ border=“0″ src=“https://www.paypal.com/de_DE/i/scr/pixel.gif“ width=“1″ height=“1″>
<input type=“hidden“ name=“encrypted“ value=“<?= $encrypted ?>“ />
</form>
</body>
</html>

Und schon ist der PayPal-Knopf auf der Seite und alle parameter sind verschlüsselt und können nur von PayPal entschlüsselt werden.

Bei meinen Tests vielen mir ein paar ungereimtheiten auf:

Nach der Rückleitung auf die eigene Seite nach einer erfolgreichen Bezahlung in der PayPal-Sandbox werden andere Variablen an die eigene Seite übermittelt, als dies auf dem Live-PayPal der Fall ist. Ausserdem werden die Variablen im Live-PayPal per GET, in der Sandbox per POST übermittelt. Davon steht nirgendwo etwas auf den PayPal-Seiten, also vorsicht bei der Entwicklung! Wenn der Kunde die Rückleitung auf die eigene Seite nicht zulässt oder abbricht, so kann die eigene Seite nicht feststellen, dass jemand gezahlt hat! Am besten ist es also, Web Payment Standard (siehe oben) mit IPN (Instant Payment Notification) zu verbinden, damit man von PayPal über eine URL vom Kauf informationen bekommt.

Im großen und ganzen finde ich die ganzen möglichkeiten bei PayPal sehr schwach und unzureichend dokumentiert, vorallem die Unterschiede mit der Sandbox. Aber vielleicht habe ich auch nur die falschen Quellen benutzt. Wenn jemand detaillierte Dokus hat, bitte melden ! 🙂

KategorienProgrammierung Tags: ,
  1. frankie1138
    9. Oktober 2008, 09:23 | #1

    Ich habe unter meinem richtigen PayPal Business account
    (nicht Sandbox-account) einen button erstellt. Da steht
    jedoch method=“post“ also genau wie in der Sandbox.
    Daher verstehe ich den oberen Kommentar nicht, dass sich zwischen Live-PayPal und der Sandbox der Unterschied
    in der Post oder Get-Methode befindet.
    Was ist genau mit Live-PayPal gemeint? Mein richtiges PayPal, über dass ich später echte Zahlungen empfangen kann?

    Meine konkreten Fragen: Wie muss ich den Sandbox button genau verändern, wenn ich den Sandbox Button in einen
    echten PayPal-Bezahl Button für meine Kunden verändern möchte? Gerade in Hinblick auf Post und Get?

    Wie kann ich meine Session-Variablen übergeben?
    Bleiben diese bei IPN, bzw. der Rückleitung auf meine
    Seiten erhalten?

    Ich habe den oberen Code probiert, exakt so wie er da steht (mit den richtigen Pfaden und IDs für meine Seite)..leider ohne Erfolg.
    Bei mir ist immer das $encrypted leer. Was habe ich falsch gemacht? Muss ich auf meinem Server erstmal openssl installieren?
    Wenn ja, wie geht das genau?
    Was ist bei PHP4 oder PHP5 zu beachten?

  2. 9. Oktober 2008, 12:22 | #2

    Hallo frankie1138,

    openssl muss für meine obige Klasse auf jeden Fall auf dem Server installiert sein und PHP muss mit der –with-openssl Option compiliert sein, sonst sind die ganzen PHP-openssl Funktionen nicht verfügbar. Falls es dennoch nicht klappt, so sollten die Fehlermeldungen per error_reporting und ini_set aktiviert werden um den Fehler zu finden.

    Im Januar 2008 war es bei meinen Tests so, dass die PayPal Sandbox keine Weiterleitung an die ursprüngliche Seite per HTTP-Post sondern per HTTP-Get gemacht hat, wohingegen die Live-Version HTTP-Post genutzt hat. Ob dies heute noch so ist, kann ich leider nicht sagen.
    Das war unabhängig vom eigenen PayPal-Knopf.

    Die einzige sichere und vernünftige Version zur Rückübergabe von Daten von PayPal zur eigenen Seite sollte über IPN erfolgen. Nur so wird gewährleistet, dass eine Zahlung immer erkannt wird und es keine Tricksereien gibt. Leider war damals die Doku meiner Meinung nach völlig unzureichend, so dass ich für IPN leider kein Beispiel habe.

    Die von mir angebotene Klasse ist für PHP5 optimiert, für PHP4 müsste man die Schlüsselwörter wie „public“ vor den Klassenmethoden entfernen und den Constructor __construct umbenennen in den Namen der Klasse. Mehr sollte nicht nötig sein.

    Für weitere Hilfe schreiben Sie mir einfach eine E-Mail an info >at< jaqe.de und ich versuche so gut wie’s geht zu helfen.

  3. Dexus
    17. Januar 2009, 11:59 | #3

    Hallo!

    Erst mal danke für die Classe, nur leider funktioniert diese nicht oder nicht mehr.

    Ich habe nun die Classe genommen, die verlinkt wurde bei PayPal im Developer Forum. Und etwas angepasst so wie es bei Ihrer Classe vor gesehen war. Nun klappt es. Nur das ich die Classe aus dem PDForum genommen habe.

    Vielen Dank!

  4. Alex
    23. Juni 2009, 07:42 | #4

    Hallo!

    Danke für die Klasse, allerdings funktioniert es bei mir leider nicht so wie es soll die Variable $encrypted bleibt immer leer.

    $this->error ist 1, leider weiß ich nicht genau was das bedeutet.

    Die Zertifikate habe ich so wie Sie es beschrieben haben erstellt und bei PayPal hochgeladden.

    Für Hilfe währe ich sehr dankbar

    MFG

  5. snoarf
    1. Februar 2013, 08:53 | #5

    @Alex
    Hallo,
    da ist ein Fehler im Beispiel, der Error 1 kommt daher, weil der Name des Public Keys falsch angegeben wird, der wird weiter oben als

    my-publiccert.pem und nicht als
    my-publickey.pem

    generiert.

    also aus

    $paypal = new PayPalEWP($paypal_zertifikat_id, $paypal_dir.’my-publickey.pem’, $paypal_dir.’my-privatekey.pem’, $paypal_dir.’paypal-cert.pem’);

    einfach

    $paypal = new PayPalEWP($paypal_zertifikat_id, $paypal_dir.’my-publiccert.pem’, $paypal_dir.’my-privatekey.pem’, $paypal_dir.’paypal-cert.pem’);

    machen!

    Klappt bei mir wunderbar 🙂

    Danke für das tolle Beispiel!

  1. Bisher keine Trackbacks
Du musst Dich anmelden um einen Kommentar zu schreiben