Anleitung: Paypal in eine eigene Webseite / Online Shop einbauen. Funktionierendes Beispiel inklusive PHP Code. Sandbox Accounts anlegen, Konfiguration, Datenbanken und Programmcode
Ich habe gefühlt einen ganzen Monat gebraucht um Paypal in meinem eigenen selbstprogrammierten Shop zu implementieren.
Alle Tutorials haben entweder nicht funktioniert, waren unvollständig, hatten keine Datenbankanbindung, es wurden notwendige Informationen einfach weggelassen und und und…
Daher hier die Lösung.
Damit erspart Ihr euch einige nervenzerreißende Tage/Wochen:
Sandbox Accounts anlegen
Erstellt jeweils einen Account für den Käufer und den Verkäufer.
Käufer: buyer@DOMAINNAME.de
Verkäufer: seller@DOMAINNAME.de
Diese beiden Accounts nutzt Ihr für eure Testkäufe.
Account Type
Personal (Buyer Account) – bei Käufer
Business (Merchant Account) – bei Verkäufer
Paypal Balance: 1000 (Startguthaben)
https://developer.paypal.com/developer/accounts/
Unter folgendem Link könnt Ihr euch auch dort einloggen um die Transaktionen auf beiden Seiten zu begutachten und Einstellungen zu machen:
https://www.sandbox.paypal.com/myaccount/home
Anforderungen
PayPal Auto Return und Payment Data Transfer muss konfiguriert werden
PayPal muss direkt nach der Zahlung automatisch auf die Bestätigungsseite weiterleiten.
IPN muss aktiviert werden (Instant Payment Notification)
Nach der Zahlung sendet Paypal eine Bestätigung an meinen Server, welche dann wiederrum überprüft wird ob die Zahlung auch wirklich stattgefunden hat.
Andere Währungen müssen akzeptiert und umgerechnet werden
Wenn nicht, steht die Zahlung auf „Pending“ und muss manuell bestätigt werden, was das Konzept der Automatisierung wieder komplett auf den Kopf stellt. Deswegen immer die Währung umrechnen lassen in die Zielwährung, oder diverse Währungen im Paypal Konto haben.
Konfiguration
zu Punkt 1 der Anforderungen
Auto Return: On
Return URL: https://DOMAINNAME.de/success.php
Payment Data Transfer: On
https://www.sandbox.paypal.com/cgi-bin/customerprofileweb?cmd=%5fprofile%2dwebsite%2dpayments
zu Punkt 2 der Anforderungen
Notification URL: https://DOMAINNAME.de/ipn.php
Receive IPN messages (Enabled)
https://www.sandbox.paypal.com/cgi-bin/customerprofileweb?cmd=%5fprofile%2dipn%2dnotify
zu Punkt 3 der Anforderungen
Allow payments sent to me in a currency I do not hold:
– Yes, accept and convert them to U.S. Dollars.
https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_profile-pref
Nice to know)
IPN Historie (als Verkäuferaccount abrufbar):
https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_display-ipns-history
Datenbanken anlegen (in z.B. phpmyadmin)
CREATE TABLE `products` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `image` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `price` float(10,2) NOT NULL, `status` tinyint(1) NOT NULL DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE `payments` ( `payment_id` int(11) NOT NULL AUTO_INCREMENT, `item_number` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `txn_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `payment_gross` float(10,2) NOT NULL, `currency_code` varchar(5) COLLATE utf8_unicode_ci NOT NULL, `payment_status` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `date` datetime NOT NULL, PRIMARY KEY (`payment_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Datenbankverbindung anlegen (dbconnect.php)
<?php $servername = "localhost"; $username = "XXXXXX"; $password = "XXXXXX"; $database = "XXXXXX"; $mysqli = new mysqli($servername, $username, $password, $database); $mysqli->set_charset("utf8"); // check connection if ($mysqli->connect_errno) { die("Connect failed: ".$mysqli->connect_error); } ?>
Produkte in Datenbank manuell anlegen und anzeigen lassen (index.php)
Paypal Button: https://www.paypalobjects.com/en_US/i/btn/btn_buynow_LG.gif
<?php //Include DB configuration file include 'dbconnect.php'; //Set useful variables for paypal form $paypalURL = 'https://www.sandbox.paypal.com/cgi-bin/webscr'; //Test PayPal API URL $paypalID = 'seller@DOMAINNAME.de'; //Business Email $usermail = $idarray->email; ?> <?php //Fetch products from the database $results = $mysqli->query("SELECT * FROM products"); while($row = $results->fetch_assoc()){ ?> Name: <?php echo $row['name']; ?><br> Preis: <?php echo $row['price']; ?>€ <form action="<?php echo $paypalURL; ?>" method="post"> <!-- Identify your business so that you can collect the payments. --> <input type="hidden" name="business" value="<?php echo $paypalID; ?>"> <!-- Specify a Buy Now button. --> <input type="hidden" name="cmd" value="_xclick"> <!-- Specify details about the item that buyers will purchase. --> <input type="hidden" name="item_name" value="<?php echo $row['name']; ?>"> <input type="hidden" name="item_number" value="<?php echo $row['id']; ?>"> <input type="hidden" name="amount" value="<?php echo $row['price'] . '€'; ?>"/> <input type="hidden" name="currency_code" value="EUR"> <!-- Specify URLs --> <input type='hidden' name='cancel_return' value='https://DOMAINNAME.de/cancel.php'> <input type='hidden' name='return' value='https://DOMAINNAME.de/success.php'> <input type='hidden' name='notify_url' value='https://DOMAINNAME.de/ipn.php'> <!-- Display the payment button. --> <input type="image" name="submit" border="0" src="images/paypal-button-de.gif" alt="PayPal - The safer, easier way to pay online"> <img alt="" border="0" width="1" height="1" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" > </form><br><br> <?php } ?>
<form action="<?php echo $paypalURL; ?>" method="post"></form>
Zahlungsbestätigungsseite (success.php)
Diese Seite wird automatisch aufgerufen sobald die Zahlung durchgeführt wurde.
Einen Datenbankeintrag gibt es hier noch nicht, da dies der Paypal IPN Service übernimmt.
Durch diesen Dienst kommt man erst an die verifizierten Daten.
<?php include 'dbconnect.php'; //Get payment information from PayPal $item_number = $_GET['item_number']; $txn_id = $_GET['tx']; $payment_gross = $_GET['amt']; $currency_code = $_GET['cc']; $payment_status = $_GET['st']; //Get product price from database $productResult = $mysqli->query("SELECT price FROM products WHERE id = ".$item_number); $productRow = mysqli_fetch_object($productResult); $productPrice = $productRow->price; if(!empty($txn_id) && $payment_gross == $productPrice){ //Check if payment data exists with the same TXN ID. $prevPaymentResult = $mysqli->query("SELECT payment_id FROM payments WHERE txn_id = '".$txn_id."'"); ?> <h1>Your payment has been successful.</h1> Please wait a few minutes for the transaction to be verified.<br> Then you can directly use your product. <?php }else{ ?> <h1>Your payment has failed.</h1> <?php } ?>
Seite für Zahlungsabbruch (cancel.php)
<h1>Your PayPal transaction has been canceled.</h1>
Paypal Zahlungsbestätigung (ipn.php)
Nachdem der Kunde bezahlt hat wird ihm die success.php angezeigt.
Paypal IPN sendet nach einiger Zeit eine Anfrage an die ipn.php um die erfolgreiche Zahlung zu übermitteln.
Das heißt es kann ein wenig Dauern, bis der Eintrag in der Datenbank landet.
<?php //Include DB configuration file include 'dbconnect.php'; /* * Read POST data * reading posted data directly from $_POST causes serialization * issues with array data in POST. * Reading raw POST data from input stream instead. */ $raw_post_data = file_get_contents('php://input'); $raw_post_array = explode('&', $raw_post_data); $myPost = array(); foreach ($raw_post_array as $keyval) { $keyval = explode ('=', $keyval); if (count($keyval) == 2) $myPost[$keyval[0]] = urldecode($keyval[1]); } // Read the post from PayPal system and add 'cmd' $req = 'cmd=_notify-validate'; if(function_exists('get_magic_quotes_gpc')) { $get_magic_quotes_exists = true; } foreach ($myPost as $key => $value) { if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) { $value = urlencode(stripslashes($value)); } else { $value = urlencode($value); } $req .= "&$key=$value"; } /* * Post IPN data back to PayPal to validate the IPN data is genuine * Without this step anyone can fake IPN data */ $paypalURL = "https://www.sandbox.paypal.com/cgi-bin/webscr"; $ch = curl_init($paypalURL); if ($ch == FALSE) { return FALSE; } curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSLVERSION, 6); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); // Set TCP timeout to 30 seconds curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close', 'User-Agent: company-name')); $res = curl_exec($ch); /* * Inspect IPN validation result and act accordingly * Split response headers and payload, a better way for strcmp */ $tokens = explode("\r\n\r\n", trim($res)); $res = trim(end($tokens)); date_default_timezone_set('Europe/Berlin'); $date = date("Y-m-d H:i:s"); if (strcmp($res, "VERIFIED") == 0 || strcasecmp($res, "VERIFIED") == 0) { //Payment data $item_number = $_POST['item_number']; $txn_id = $_POST['txn_id']; $payment_gross = $_POST['mc_gross']; $currency_code = $_POST['mc_currency']; $payment_status = $_POST['payment_status']; //Check if payment data exists with the same TXN ID. $prevPayment = $mysqli->query("SELECT payment_id FROM payments WHERE txn_id = '".$txn_id."'"); if($prevPayment->num_rows > 0){ exit(); }else{ //Insert tansaction data into the database $insert = $mysqli->query("INSERT INTO payments(item_number,txn_id,payment_gross,currency_code,payment_status,date) VALUES('".$item_number."','".$txn_id."','".$payment_gross."','".$currency_code."','".$payment_status."','".$date."')"); } }
Hier kann man noch die Bestätigungsemail einfügen. Entweder einfach das Array ausgeben oder ein eMail Template basteln und die Variablen ausgeben.
Außerdem wird hier die Zahlung in die Datenbank geschrieben. Eine Freigabe der gekauften Ware wird hier auch eingefügt.
Beispielsweise eine SQL Abfrage um dem Nutzer das Geld auf seinem Kundenkonto gutzuschreiben, die virtuelle gekaufte Ware zu übergeben (SQL Insert oder Update), das Versenden einer eMail an den Nutzer mit den Daten, die er gekauft hat (Videolinks, ZIP Archiv, ….. usw….).
Je nach Anwendungsfall des Einsatzgebietes.
Live Modus
In index.php folgendes ersetzen:
$paypalURL = 'https://www.paypal.com/cgi-bin/webscr'; // echte paypal url $paypalID = 'seller@DOMAINNAME.de'; //echte email vom richtigen paypal account
In der ipn.php folgendes ersetzen:
$paypalURL = "https://www.paypal.com/cgi-bin/webscr";
Datenbank name fehlte und in der mysqli() war dafür nochmal $username
set_charset(„utf8“);
// check connection
if ($mysqli->connect_errno) {
die(„Connect failed: „.$mysqli->connect_error);
}
?>
Danke tolles tutorial 😉
Habe es nun korrigiert. In meinem Fall war der Username und der Datenbankname der selbe
ist dieser Script noch aktuell ?
Irgend wie bekommen ich eine Fehler meldung Warning: mysqli::__construct(): Headers and client library minor version mismatch. Headers:50541 Library:50634 in C:\MAMP\htdocs\einzel-scripte\paypal\dbconnect.php on line 8
Läuft bei mir ohne Probleme.
php5-mysqlnd schon installiert?
https://stackoverflow.com/questions/10759334/headers-and-client-library-minor-version-mismatch
ich habe jetzt die Verbindung mit der Datenbank gelöst aber anscheint werden keine Parameter übergeben wie item_number, tx, amt, cc, st
Notice: Undefined index: item_number in C:\MAMP\htdocs\einzel-scripte\paypal\success.php on line 15
Notice: Undefined index: tx in C:\MAMP\htdocs\einzel-scripte\paypal\success.php on line 16
Notice: Undefined index: amt in C:\MAMP\htdocs\einzel-scripte\paypal\success.php on line 17
Notice: Undefined index: cc in C:\MAMP\htdocs\einzel-scripte\paypal\success.php on line 18
Notice: Undefined index: st in C:\MAMP\htdocs\einzel-scripte\paypal\success.php on line 19
kann man den fertigen Script irgend wo herunterladen ?
Paypal leitet nach erfolgreichem Kauf auf die success.php weiter.
Um dies zu testen muss man in der Sandbox tatsächlich eine Bestellung ausführen damit die Variablen gesetzt sind seitens Paypal.
Direkt darauf zuzugreifen klappt natürlich nicht.
ich führe eine Bestellung aus, von Konto Buyer wird auch Geld abgezogen.
Bis zu Zahlung ist alles ok.
Wenn die Zahlung durchgeführt wurde und ich auf den Buttom zurück zum Händler drücke, werde ich auf die success.php weitergeleitet und in der url sind keine paramet mehr enthalten.
Stimmen die Variablennamen der ipn und success Datei überein?
Eventuell mal alle Variablen ausgeben lassen in der ipn:
print_r($_GET);
hay,
das ist super was du hier gebaut hast und funktioniert wunderbar.
kannst du den noch was bauen, das man auch die zahlungen stornieren kann, also so das man kann mit einem mausklick das geld zurückbuchen kann?
mfg eric
Sollte kein Problem sein. Zahlung in der internen Datenbank löschen und per Paypal API zurücksenden.
Kann man sich eine kleine Seite dafür basteln.
http://paypal.github.io/PayPal-PHP-SDK/sample/doc/payouts/CreateSinglePayout.html
Also gibt es da keine wirkliche Stornierung einer Zahlung in der api?
Bei einer normalen Zahlung zurück fallen doch dann die Gebühren wieder an?
Sollte auch machbar sein. Habe mich damit allerdings noch nicht beschäftigt.
https://developer.paypal.com/docs/classic/api/adaptive-payments/Refund_API_Operation/
Herzlichen Dank für diesen Leitfaden!
Ich bin nun soweit gekommen, dass die Bestellung durchgeführt und das Script success.php die erfolgreiche Zahlung meldet. Leider wird jedoch in der Tabelle payments kein Datensatz hinzugefügt. In der Verlaufsübersicht der Sofortigen Zahlungsbestätigungen (IPN) werden alle Zahlungen korrekt mit Nachrichten-ID und Transaktionscode aufgelistet.
Ich habe auch hierüber eine erneute Zahlungsbestätigung gesendet, auch diese wird nicht in die MySQL-Tabelle geschrieben. Eine Fehlermeldung erhalte ich aber auch nicht. Ich bin nun etwas ratlos….
Eine IPN-Nachricht füge ich unten an, vielleicht hilft diese bei der Fehlersuche?
Viele Grüße,
Marcus
mc_gross=5.00&protection_eligibility=Eligible&address_status=confirmed&payer_id=U6E2ZJPR9B4LU&address_street=ESpachstr. 1&payment_date=08:32:20 Nov 08, 2018 PST&payment_status=Completed&charset=windows-1252&address_zip=79111&first_name=test&mc_fee=0.45&address_country_code=DE&address_name=test buyer¬ify_version=3.9&custom=&payer_status=verified&business=memovest-facilitator@web.de&address_country=Germany&address_city=Freiburg&quantity=1&verify_sign=As8ixQ.poP1sojdamgmb9N5ij9rfACnQJpEA-dRxEcZviZNU2pTa7sQp&payer_email=memovest-buyer@web.de&txn_id=2WK15418J8827620D&payment_type=instant&last_name=buyer&address_state=Empty&receiver_email=memovest-facilitator@web.de&payment_fee=&shipping_discount=0.00&insurance_amount=0.00&receiver_id=VR2W6TMSVSZK2&txn_type=web_accept&item_name=Test2&discount=0.00&mc_currency=EUR&item_number=2&residence_country=DE&test_ipn=1&shipping_method=Default&transaction_subject=&payment_gross=&ipn_track_id=d212c39e98517
Wenn das Problem ist, dass kein Datensatz hinzugefügt wird trotz erfolgreicher Bestellung, würde ich in der IPN Datei mal ein Check einbauen ob die Datenbankverbindung erfolgreich ist. Eventuell dort auch alle paar Blöcke mal eine Ausgabe machen (wenn diese denn angezeigt wird – oder eMail senden, je nachdem) um zu schauen wie weit der Code ausgeführt wird.
Offenbar wird das Skript ipn.php nicht aufgerufen. Die entsprechenden Einstellungen habe ich aber vorgenommen:
https://uploads.disquscdn.com/images/487268fb26735048361a874c25ce008efe3954daf02a067c76a1c4a616dc7bae.png
https://uploads.disquscdn.com/images/dbffdaca40c0ea4376729f5f4a33b10aa3ca60311a21023816698b22775e4309.png
https://uploads.disquscdn.com/images/9269b4aab8d7490373e2d080ce6c25a4137c481bb4a5104582e299d4ac4d49f5.png
Mh…. Geh mal erneut die komplette Anleitung durch. Bei mir hat es so wunderbar funktioniert. Manchmal wird lediglich eine Kleinigkeit vergessen und schon klappt überhaupt nichts mehr.
vielen Dank, für dieses Tutorial…hat mir eine MENGE zeit gespart
Ja die verschiedenen Codeschnipsel sind schon sehr hilfreich. Musste ich leider selbst alles tagelang nachschlagen, bis ich es so letztendlich hinbekommen habe.
Komischerweise Ruft er die ipn.php nicht auf, keine Ahnung wieso er das nicht macht
habe Vor dem ipn Script einen Datenbank Eintrag setzen soll, aber er insertet nix.
woran kann es liegen das er die notify_url nicht aufruft
Die Webserver Logs können da natürlich als Realtime Debugging verwendet werden.
Alternative die Paypal Einstellungen nochmals überprüfen:
https://www.jotform.com/de/help/1030-wie-sie-ipn-in-ihrem-paypal-account-aktivieren/
https://prnt.sc/HUl5Ml4WCqWq
Hallo , kannst du mir biite helfen?
was soll ich hier machen?
Die success.php Seite wird ausschließlich von Paypal selbst aufgerufen. Man selbst kann die Seite nicht korrekt öffnen, da per URL GET Parameter mitgegeben werden, welche in deinem Fall logischerweise nicht gefüllt sind.
danke für diese wunderbare Anleitung.
Heute bin ich mit einem Shop Live gegangen. Es fehlte nur ein Stritt um Live zu gehen.
Was man zusätzlich machen muss ist, vom developer.paypal.com:
– Auf Business Dashbord klicken
– Einstellungen -> Website-Zahlungslösungen -> Sofortige Zahlungsbestätigung
– wieder die Notification URL: https://DOMAINNAME.de/ipn.php einfügen
– und Receive IPN messages (Enabled) setzen.
dann ging es 😉