Integration mit einem Zahlungsanbieter; Richtiger und robuster OOP-Ansatz


8

Geschichte

Wir verwenden derzeit ein sogenanntes Weiterleitungsmodell für unsere Online-Zahlungen (bei dem Sie den Zahler an ein Zahlungsgateway senden, wo er seine Zahlungsdetails eingibt - das Gateway führt ihn dann zu einer Rückrufseite für Erfolg / Misserfolg zurück). Das ist einfach und unkompliziert, aber leider ziemlich unpraktisch und manchmal verwirrend für unsere Kunden (Verlassen der Website, Ändern ihrer Kreditkartendaten durch zusätzliches Anmelden auf einer anderen Website usw.).

Absichts- und Problembeschreibung

Wir beabsichtigen nun, durch den Austausch von XML-Anforderungen und -Antworten auf einen integrierten Ansatz umzusteigen. Mein Problem ist, wie ich mit all (oder eher den meisten) Dingen umgehen kann, die während der Verarbeitung passieren können - wenn man bedenkt, dass Einfachheit normalerweise robust ist, während Komplexität fragil ist.

Beispiele

  • Benutzerabbruch: Der Benutzer gibt Kreditkartendetails ein und klickt auf Senden. Eine XML-Nachricht an das Gateway des Anbieters wird gesendet und wartet auf eine Antwort. Der Benutzer drückt in seinem Browser auf "Stopp" oder schließt das Fenster.
    • ignore_user_abort () in PHP kann eine Option sein - aber ist das zuverlässig?
    • Könnte es besser sein, den Benutzer auf eine "Bitte warten" -Seite umzuleiten, die wiederum eine AJAX- oder andere Anfrage an den tatsächlichen Prozessor öffnet, der nicht auf die Verbindung angewiesen ist?
  • Datenbank geht weg
    • klingt überkompliziert, aber mit z. B. einem Webserver in den USA und einer Datenbank in Großbritannien ist es passiert und wird erneut passieren: Der Benutzer klickt seine Bestellung zusammen, die Zahlungsanforderung wurde an den Anbieter gesendet, aber die Antwort kann nicht im gespeichert werden Datenbank. Welchen Ansatz könnte ich verwenden, um mit PHP eine SQL wie "Transaktion" zu starten, die je nach den einzelnen Schritten erst am Ende festgeschrieben oder zurückgesetzt wird? Sollte dann weder ein Commit noch ein Rollback stattgefunden haben, könnte ich den Benutzer sozusagen "sperren", um zu verhindern, dass er erneut zahlt, oder um Zahlungen nicht ordnungsgemäß zu berücksichtigen - aber wie?
  • Und was muss ich technisch noch beachten? Keines der Integrationsbeispiele von z. B. Worldpay, Realex oder SagePay bietet einen Einblick, und entweder meine Suchmaschine oder meine Suchbegriffe waren nicht gut genug, um die Gedanken anderer zu finden.

Vielen Dank für jeden Einblick, wie Sie dies angehen würden!


1
Verwenden Sie einfach Stripe. Vermeiden Sie Kopfschmerzen.
Serggserg

Ich habe mir Stripe angesehen - sie berechnen 2,39% plus 30 Cent pro Transaktion! Das würde mich ungefähr 12 Grand pro Jahr kosten - ich bezahle 0 Prozent und 9 Pence pro Transaktion ...
ExternalUse

Bitte lesen Sie [dies], um einen Einblick in verschiedene Zahlungsgateways zu erhalten, einschließlich XML-basierter. [1] [1]: vpasp.com/virtprog/vpasp_epsystems.htm
Badar

Hallo Badar, das beantwortet meine Frage leider nicht. Ich weiß, wie Zahlungsgateways funktionieren, und meine Wahl für eine XML-Integration ist festgelegt. Ich suche nach Best Practices und Tipps, wie ich es robust machen kann - vielleicht ist meine Frage nicht spezifisch genug?
ExternalUse

Antworten:


8

Als Entwickler, der fast ausschließlich mit Zahlungen arbeitet, kann ich Ihnen vielleicht einige Hinweise geben, wo die möglichen Fallstricke liegen. Ich arbeite für eine Website mit hohem Datenverkehr, ~ 40 aktiven Zahlungsdienstleistern (PSPs) und erledige täglich Zehntausende von Transaktionen. Und glauben Sie mir, der Scheiß wird immer den Fan treffen und alles, was Sie tun können, ist sich so gut wie möglich darauf vorzubereiten, von diesem Punkt an mit der Situation umzugehen.

Log, log und log noch mehr ...

Dies ist der wichtigste Teil Ihres Zahlungsprozesses. Stellen Sie sicher, dass Sie über alles Aufzeichnungen haben . Stellen Sie sich die Fragen "Könnte mir diese Information einmal in einer Million Transaktionen helfen?". Wenn die Antwort ja ist, protokollieren Sie es!

Unser Setup ist, dass der Hauptpunkt der Protokollierung die Datenbank ist. Jede initiierte, fehlgeschlagene, abgewickelte, umgeleitete usw. Transaktion wird pro PSP in Tabellen gespeichert. Wenn die PSP eine API verwendet, werden alle API-Aufrufe protokolliert (sowohl gesendete Anforderungen als auch Antworten). Alle Rückrufe werden ebenfalls in Tabellen protokolliert. Und so weiter..

Wenn ein unerwartetes Ereignis oder eine unerwartete Ausnahme auftritt, protokollieren wir sie in der PHP-Protokolldatei mit einem bestimmten Format, damit sie basierend auf der Transaktions-ID, der Benutzer-ID usw. durchsucht und leicht gefunden werden kann.

Sie werden dankbar sein, dass Sie alle Daten haben, wenn Sie zum Beispiel verklagt werden.

Überwachung und Warnungen

Integrierte Überwachungslogik mit einigen einfachen Tests, die Sie per E-Mail benachrichtigen, wenn etwas schief geht. Zum Beispiel, wenn 3 Rückrufe hintereinander für eine PSP fehlschlagen. All diese kleinen Dinge, mit denen Sie Probleme schnell lösen können, anstatt darauf zu reagieren, nachdem Ihre Kunden Sie auf sie aufmerksam gemacht haben (was nicht immer der Fall ist), sind sehr wichtig.

Datenbanktransaktionen

Wenn Sie den Luxus haben, Ihre Datenbankstruktur einzurichten oder zu ändern, um Datenbanktransaktionen zu unterstützen, verwenden Sie beispielsweise InnoDB unter MySQL. Schauen Sie sich diese Antwort an, um zu erfahren, wie Sie im Code damit umgehen können. Sie sollten sicherstellen, dass jeder Schritt einer Transaktion abgeschlossen ist oder keiner abgeschlossen ist. Teilweise abgeschlossene Transaktionen sind nur eine Belastung für Sie und Ihr System. Zum Beispiel: 1) Benutzer schließt Transaktion ab, 2) Benutzer wird irgendwie belohnt. Wenn hier nicht beide Schritte 1 und 2 erfüllt sind, sollte die Transaktion in Schritt 1 nicht als abgeschlossen festgelegt werden.

Technische Ansprechpartner

Wenn Sie ein technisches Problem haben, stellen Sie sicher, dass Sie jemanden haben, den Sie sofort kontaktieren können. Ein Account Manager ist ziemlich nutzlos, besonders wenn diese Person beschließt, zwischen Ihnen und ihrem Techniker zu vermitteln.

Ein Beispiel aus der Live-Welt, das mir passiert ist: Eine PSP funktioniert plötzlich nicht mehr, nichts in unserem Code hat sich geändert und sie sagen, dass sie auch nichts geändert haben. Nachdem einer der Techniker Debug-Informationen mit ihnen (über ihren Account Manager) hin und her gesendet hat, stellt er fest, dass das Abrufen des WSDL-Schemas nicht funktioniert. Dann stellen sie fest, dass sie ihr WSDL-Schema aktualisiert haben, und nach einigem Debuggen stelle ich fest, dass PHP das alte WSDL-Schema zwischengespeichert hat. Dies hätte früher als gelöst erkannt werden können, wenn ich nur eine technische Person auf Skype hätte, die ich direkt kontaktieren könnte. Oder wenn sie nur zugegeben haben, ihr WSDL-Schema geändert zu haben, es aber oft schwierig ist, ein Geständnis von den PSPs zu bekommen, wenn etwas schief geht.

Letzte Worte...

Bereite alles vor, was du kannst und gehe davon aus, dass ALLES passieren kann :)

Ich bin mir nicht sicher, ob dies genau die Art von Antwort war, nach der Sie gesucht haben, aber ich versuche, ein reales Beispiel für Zahlungen zu liefern und wie Sie die größten Fallen und Fallstricke verhindern können. Lassen Sie mich wissen, ob ich etwas näher erläutern soll oder ob Sie an einem anderen Thema interessiert sind.


+1 Ich habe vergessen zu erwähnen, wie wichtig verteilte Transaktionen sind. Die Notwendigkeit, ein Altsystem zu warten, das in ein PP integriert ist und keine Transaktionen verwendet, hat mir das Alptraumszenario aus erster Hand gezeigt.
maple_shaft

Hallo Nerdklers, danke dafür - du bekommst eine +1 für "log, log und log noch mehr"! Ich habe jetzt über diesen Ansatz bei "Senden" nachgedacht: Benutzersitzung sperren. Fügen Sie eine Zahlung als ausstehend in die Datenbank ein. Senden Sie die Anfrage ohne "Autosettle" (verzögerte Transaktion). Aktualisieren Sie den Zahlungsdatensatz bei Erfolg als "übertragen". Sende den Befehl "Settle" an PSP. Aktualisieren Sie den Zahlungsdatensatz als "abgeschlossen" und entsperren Sie die Benutzersitzung. (Sperren bedeutet, ein Flag in den Datensatz des Benutzers zu schreiben. Sollte er sich anmelden, während Transaktionen ausstehen, wird eine Seite "Bitte anrufen" angezeigt.) Mir gehen die Zeichen aus, also werde ich das als Antwort auf Kommentare setzen.
ExternalUse

1

Meiner ehrlichen Meinung nach ist der beste Weg, Transaktionen über ein Zahlungsgateway zu verwalten, Webdienste. Eine Reihe verschiedener Zahlungsgateways bieten diese Art von Diensten zu wettbewerbsfähigen Pauschalprozentsätzen pro Transaktion + der typischen Kreditkartenprovision an, die auch die Kreditkarte des Kunden erhält (z. B. Cybersource ). Bei vielem im Leben bekommen Sie das, wofür Sie bezahlen. Es gibt keine 9-Cent-Transaktion mit einem seriösen Zahlungsprozessor, der Sie nicht zwingt, Benutzer umzuleiten.

Tokenisierung und sichere Daten

Das Speichern von Kreditkartendaten auf Ihrem System ist nur ein Problem. Je nachdem, wo Sie wohnen, gibt es möglicherweise sogar gesetzliche Anforderungen und mögliche strafrechtliche Bestimmungen gegen die Verwaltung dieser Daten. Wenn Sie nicht Amazon sind, sollten Sie sich nicht um die technische und rechtliche Komplexität kümmern müssen. Der Zahlungsabwickler nimmt Ihnen dieses Risiko und diese Komplexität ab, indem er über SSL-verschlüsselte Webdienste verfügt, bei denen Kreditkartendaten über Ihre Website an Ihren Server und von Ihrem Server an die Webservices des Zahlungsabwicklers weitergeleitet werden können, um eine Zahlung über Ihr Konto bei der zu übermitteln Prozessor. Im Gegenzug gibt Ihnen der Webdienst einen Autorisierungscode oder ein Token zurück, das die Transaktion auf ihrem System eindeutig kennzeichnet, und gibt Ihnen eine Referenznummer für die schnelle Suche in Ihrem Konto nach bestimmten Transaktionen. Sie können das Token in Ihrer Datenbank behalten, und es hat für die Benutzer keine wirkliche Konsequenz, wenn die Token auf Ihrem System kompromittiert werden. Wenn Sie keine Kreditkartendaten auf Ihrem System speichern, sind die Bankkonten der Benutzer auch dann sicher, wenn Ihr System kompromittiert wurde.

Aufbewahrung von Zahlungsaufzeichnungen

Dieser Ansatz zur Integration in einen Zahlungsabwickler hat den zusätzlichen Vorteil, dass Sie Ihre eigenen Zahlungs- und Kaufaufzeichnungen führen können, die von denen Ihres Zahlungsabwicklers getrennt sind, jedoch über das Token verknüpft sind. Auf diese Weise können Sie Umsatzberichte über Ihr System ausführen, analytische Abfragen durchführen und Benutzer können ihre Einkäufe anzeigen, ohne den Zahlungsprozessor nach Informationen fragen zu müssen.

PCI-Konformität

Jeder seriöse Zahlungsabwickler hat alle seine Systeme und Daten auf PCI-kompatiblen Servern und Einrichtungen gehostet. Weitere Informationen zu den Details der PCI-Konformität selbst und warum dies wichtig ist, finden Sie auf dieser Website .

Es gibt bestimmte Anforderungen, die sie erfüllen müssen. Ihr Rechenzentrum muss sowohl physisch als auch technisch gesichert sein. Sie können keine unverschlüsselten WAPs in ihrem Netzwerk usw. haben. Nichts davon wird Sie wirklich betreffen, es werden jedoch eine Reihe von Anforderungen an Händlersysteme erwartet, damit sie auch die PCI-Konformität beanspruchen können. Einige dieser Anforderungen umfassen, sind aber nicht beschränkt auf:

  • Verwenden der SSL-Verschlüsselung für jede Zahlungsanforderung über Ihre Website.

  • Unter keinen Umständen sollten Kreditkartennummern in einem Ihrer Systeme gespeichert sein, einschließlich Protokolldateien und sogar serialisierten Objekten.

  • Anwendungsserver, die mit dem Zahlungsprozessor kommunizieren, müssen sich hinter einer gut konfigurierten Firewall befinden, die nur die erforderliche Mindestanzahl offener Ports zulässt.

  • Nur geeignetes technisches Personal sollte physischen oder Remotezugriff auf diese Anwendungsserver in Ihrem Netzwerk erhalten.

  • Andere...

In der Regel bieten die meisten Zahlungsabwickler ein Online-Tool an, das in Ihrem Netzwerk ausgeführt werden kann und mögliche Probleme bei der PCI-Konformität identifiziert. Es ist immer noch nicht NOTWENDIG oder ERFORDERLICH, mit einem Zahlungsabwickler zusammenarbeiten zu müssen. Der Zahlungsabwickler behält sich jedoch das Recht vor, Ihnen zusätzliche Gebühren in Rechnung zu stellen, wenn Sie deren Dienste nutzen und die PCI-Compliance-Standards nicht erfüllen.


Entschuldigung, aber auch dies beantwortet oder trifft meine Frage nicht. Wir haben (derzeit) einen seriösen Zahlungsabwickler sowohl bei WorldPay als auch bei Realex Payments. Wir führen permanente Audits zur PCI-Konformität durch und sind konform, um teilweise Kreditkartendaten intern zu speichern. Wir verwenden jedoch RealVault und FuturePay für die wiederkehrende Speicherung. Meine Frage bezog sich auf Best Practices für das, was ich in meiner Frage erwähnt habe.
ExternalUse

@ExternalUse Ich hatte das Gefühl, dass ich ziemlich gut erklärt habe, was die besten Methoden für eine ordnungsgemäße Integration in Ihren Zahlungsanbieter sind. Verwenden Sie SSL, leiten Sie den Benutzer nicht um, führen Sie sichere Webservice-Aufrufe von der Serverseite an das PP durch, speichern Sie keine CC-Details, führen Sie separate Zahlungsaufzeichnungen mit Ihrem Token und berücksichtigen Sie die PCI-Konformität in Ihrem Design. Wenn Sie nicht der Meinung sind, dass ich gute Arbeit geleistet habe, kann vielleicht jemand anderes eine genauere Antwort geben, nach der Sie suchen.
maple_shaft

1

Dank der Ideen aus früheren Antworten möchte ich die Lösung vorschlagen, die ich jetzt habe. Ich hoffe, dass dies ein oder zwei Kommentare aus dem hier vorhandenen zyklopädischen Wissen einlädt und mir hilft, es zu verbessern. Nur zur Verdeutlichung: Obwohl es sich um wichtige Fragen handelte, ging es bei meiner Frage nicht um die Auswahl eines Zahlungsdienstleisters (Payment Service Provider, PSP), PCI-DSS-Anforderungen oder rechtliche Auswirkungen, sondern nur um technische Fallstricke, auf die man bei der Implementierung eines "direkten" Systems stoßen könnte ein "Redirect" -Modell mit einer beliebigen PSP.

Voraussetzungen

Der Kunde befindet sich in der Phase, in der er Kreditkartendaten in Ihr Formular eingibt. Ich weiß, was er schuldet und welchen Betrag und welche Währung ich der von ihm eingereichten Kreditkarte belasten möchte.

Lösung (?)

  1. Nach dem Absenden des Formulars mit den Kreditkartendaten verwende ich Javascript, um die Standardaktion auf der Schaltfläche "Senden" zu stoppen (die, wenn JS oder AJAX nicht verfügbar wären, zu einer Fehlerseite führen könnte, auf der der Benutzer aufgefordert wird, eine aktuellere zu erhalten Browser...)
  2. Die (von einem Timer wiederholte) AJAX-Anforderung würde ein Statusaktualisierungsskript aufrufen, das an sich die eigentliche Verarbeitung in einer separaten Datei auslöst. Verwenden Sie "ignore_user_abort (), falls der Client den Browser schließt oder so
  3. AJAX ruft also zB die Methode -> StatusUpdate () auf - wenn sie zum ersten Mal aufgerufen wird, startet sie den Prozess und gibt "angenehm" zurück. Bei nachfolgenden Aufrufen wird eine Sitzungsvariable oder etwas ausgewertet, um den Status zu aktualisieren
  4. Ich würde den Benutzerdatensatz in der Datenbank aktualisieren, um ein "lockSession" -Flag auf "gesperrt" zu setzen. Sollte vor dem Entsperren etwas passieren, wird der Benutzer bei nachfolgenden Anmeldungen aufgefordert, sich an das Büro zu wenden, um eventuell aufgetretene Probleme zu beheben. .
  5. Fügen Sie einen Zahlungsdatensatz mit dem Status "vorbereitet" in die Datenbank ein
  6. Senden Sie die Anfrage unter Verwendung der Bestell-ID des vorbereiteten Zahlungsdatensatzes an die PSP. Abhängig von der PSP kann die Anfrage als verzögerte Transaktion gesendet werden (was bedeutet, dass sie nicht automatisch abgewickelt wird).
  7. Aktualisieren Sie den vorbereiteten Datensatz mit seinem neuen Status (falls abgelehnt, entsperren Sie die Sitzung und kehren Sie zur Zahlungsseite zurück. Wenn dies erfolgreich ist, aktualisieren Sie ihn mit dem Status "übertragen").
  8. Wenn dies erfolgreich wäre, hätten wir nicht die Authentifizierungsreferenz und andere wichtige Details von der PSP. Senden Sie daher eine "Abrechnungs" -Anforderung an die PSP, um die erhaltene Authentifizierungsreferenz zu erhalten.
  9. Wenn dies erfolgreich ist, aktualisieren Sie den Zahlungsdatensatz auf "Abgeschlossen" (oder verschieben Sie ihn in meinem Fall von "Ausstehende Transaktionen" auf "Zahlungstransaktionen" und aktualisieren Sie ihn).
  10. Entfernen Sie das "Sperren" -Flag aus dem Datensatz des Benutzers

Andere Überlegungen

Bitte verstehen Sie das oben Gesagte als Einladung, Ihr Wissen und Ihre Ideen zu teilen - es sind bisher nur Ideen!

Protokollierung

Ich würde Nerdklern bei der Protokollierung sehr zustimmen - ich denke derzeit darüber nach, für jede Phase des oben genannten Prozesses eine Form der dateibasierten Protokollierung zu verwenden (und Protokolle einige Tage lang aufzubewahren, auch wenn sie vollständig und überprüft sind - wer weiß. ..)

Datenbanktransaktionen

Ich bin mir nicht sicher, ob ich der Verwendung von Datenbanktransaktionen zustimmen würde. Wir verwenden MS SQL. Mit den Standardeinstellungen wird jede Transaktion bei Verbindungsverlust zurückgesetzt. Und wenn die Transaktion so eingestellt wird, dass sie nicht automatisch festgeschrieben oder automatisch zurückgesetzt wird, kann dies zu einigen offenen DB-Transaktionen und einigen Auswirkungen auf das Sperren von Datensätzen / Tabellen usw. führen. Ich denke, ich bevorzuge dabei mehrere Aktualisierungen. Sollte eine dieser Transaktionen fehlschlagen (und der Prozess folglich beendet werden), wird der Benutzer weiterhin daran gehindert, eine möglicherweise abgeschlossene (aber noch nicht aufgezeichnete) Transaktion erneut zu senden, bis sie manuell aufgelöst wurde.

AJAX, politisch

Ich bin mir nicht ganz sicher, ob wir noch Browser in Betracht ziehen müssen, die AJAX nicht unterstützen. Ich denke, das ist sowieso ein "politisches" Thema. Ich denke, wir könnten es uns leisten, uns in unserem Geschäft Freiheiten zu nehmen, andere vielleicht nicht.

AJAX, technisch

Ich bin mir noch nicht so sicher, wie ich eine "StatusUpdate" -Methode asynchron aufrufen soll, die beim ersten Aufruf versucht, den eigentlichen Prozess auszulösen. Aber ich werde dies zu einer separaten Frage machen, sollte ich keine guten Beispiele finden - die ich wohl gut finden könnte. Wie auch immer, wenn Sie eine Best Practice kennen, lassen Sie es mich (und andere) in Ihrem Kommentar wissen.

Abschließende Gedanken

Es wäre schön, wenn ich einen Gedanken hätte, der sich dem Begriff "endgültig" auch nur annähernd nähert - dies wäre für mich in Arbeit und ich bin sehr dankbar für Feedback und weitere Hinweise, wie dies verbessert werden könnte.


Ihre Lösung scheint solide zu sein, aber ich bezweifle die Notwendigkeit dieses Aufwands, wenn in Wirklichkeit eine verteilte Transaktion mit optimistischer Datensatzsperrung für erforderliche Zeilen dasselbe erreichen kann. Ich bin mir bei MSSQL nicht sicher, aber ich bin mir sicher, dass es dazu in der Lage ist, wenn ich dies in InnoDB MySQL tun kann. Ich bin nicht sicher, ob ich Ihrem Argument gegen die Verwendung von Transaktionen folge.
maple_shaft

Ich bin (zu Unrecht?) Besorgt darüber, was passiert, wenn das Skript während der Verarbeitung beendet wird oder wenn die Datenbank (aus welchem ​​Grund auch immer) nicht mehr funktioniert. Was passiert mit der gestarteten Transaktion? Ist es festgeschrieben, rückgängig gemacht oder offen gelassen? Und diese Frage kann je nach Einrichtung und Datenbank mit a, b oder c beantwortet werden, denke ich. Ich überlegte, meine Entwicklung als Open-Source-Klasse zu teilen, falls sie so funktionieren sollte, wie ich es möchte - schließlich bekomme ich Wissen von der Community, also sollte es darauf zurückgreifen.
ExternalUse

Ich würde sagen, Sie überdenken das ein bisschen. Solange Sie aufzeichnen, was passiert, werden Sie im Laufe der Zeit lernen. Ich möchte nur Folgendes kommentieren: "(und Protokolle für ein paar Tage aufbewahren, auch wenn sie vollständig und verifiziert sind - wer weiß ...) ", und sag nein, nein, nein :) Behalte die Protokolle für immer, teile sie zum Beispiel nach Tag auf trx_120917.log. Die Protokolle sind sehr klein und der Speicherplatz ist sehr billig. Wie auch immer, viel Glück mit Ihrem Projekt!
Niklas Modess
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.