Paypal PHP Integration Beispiel

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)

paypal-integration-implementierung-php
Paypal API in PHP/MYSQL
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";

23 Kommentare zu „Paypal PHP Integration Beispiel“

  1. 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 😉

  2. 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

      1. 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 ?

        1. 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.

          1. 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.

  3. 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

      1. 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?

  4. 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&notify_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

    1. 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.

  5. 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

    1. 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.

  6. 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 😉

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Nach oben scrollen