130 lines
4.7 KiB
PHP
130 lines
4.7 KiB
PHP
<?php
|
|
/**
|
|
* Ereignis-Log fuer Bestellvorgaenge (25.08.2026).
|
|
*
|
|
* Warum PostgreSQL und nicht der Shop selbst:
|
|
* Die MySQL-Tabelle `orders` hat keine einzige Spalte mit Uhrzeit -- `order_date` und alle
|
|
* anderen Datumsfelder sind Typ DATE, und `order_history.timestamp` wird bei der
|
|
* Bestellanlage nicht gefuellt. Damit laesst sich weder eine Abbruchquote sauber messen
|
|
* noch belegen, ob eine Aenderung am Bezahlweg etwas gebracht hat. Genau daran ist die
|
|
* Analyse der PayPal-Abbrueche zuerst haengengeblieben.
|
|
*
|
|
* Grundregel dieser Datei: **Der Bestellvorgang darf hier NIEMALS haengenbleiben.**
|
|
* Ist Postgres weg, langsam oder die Tabelle fehlt, wird still weitergemacht. Ein
|
|
* Messwerkzeug, das den Kaufvorgang gefaehrdet, ist sein Geld nicht wert. Deshalb
|
|
* connect_timeout, deshalb ueberall @ und Rueckgabepruefung statt Exceptions.
|
|
*
|
|
* Ereignisse:
|
|
* order_created Bestellung in MySQL angelegt (bei PayPal: noch nicht bezahlt!)
|
|
* payment_started Kunde wurde zu PayPal geschickt, Token steht
|
|
* paid Geld eingezogen (DoExpressCheckoutPayment erfolgreich)
|
|
* cancelled Kunde hat bei PayPal abgebrochen
|
|
* failed PayPal hat den Abschluss abgelehnt
|
|
* duplicate_blocked zweiter Versuch desselben Vorgangs abgefangen
|
|
* mail_sent Bestellbestaetigung ausgeloest
|
|
*
|
|
* Auswertung z. B.:
|
|
* SELECT date_trunc('day', zeitpunkt) AS tag,
|
|
* count(*) FILTER (WHERE ereignis = 'payment_started') AS gestartet,
|
|
* count(*) FILTER (WHERE ereignis = 'paid') AS bezahlt
|
|
* FROM shop_order_events GROUP BY 1 ORDER BY 1;
|
|
*/
|
|
|
|
if (!function_exists('shop_event')) {
|
|
|
|
/**
|
|
* Schreibt ein Ereignis. Schlaegt das fehl, passiert nichts weiter.
|
|
*
|
|
* @param string $ereignis siehe Liste oben
|
|
* @param array $daten order_id, order_number, payment_method, betrag,
|
|
* paypal_token, transaction_id, customer_id, detail
|
|
* @return bool true wenn geschrieben, sonst false
|
|
*/
|
|
function shop_event($ereignis, $daten = array()) {
|
|
static $verbindung = null;
|
|
static $tot = false;
|
|
|
|
// Einmal gescheitert -> fuer diesen Request nicht weiter versuchen. Sonst wartet
|
|
// jeder Aufruf erneut auf einen Timeout.
|
|
if ($tot) {
|
|
return false;
|
|
}
|
|
|
|
if (!function_exists('pg_connect')) {
|
|
$tot = true;
|
|
return false;
|
|
}
|
|
|
|
if ($verbindung === null) {
|
|
$ini_pfad = dirname(__FILE__) . '/config.ini';
|
|
|
|
if (!is_readable($ini_pfad)) {
|
|
$tot = true;
|
|
return false;
|
|
}
|
|
|
|
$ini = @parse_ini_file($ini_pfad, true);
|
|
if (!$ini || empty($ini['postgresql'])) {
|
|
$tot = true;
|
|
return false;
|
|
}
|
|
|
|
$pg = $ini['postgresql'];
|
|
|
|
// connect_timeout ist der wichtigste Parameter hier: liegt Postgres,
|
|
// wartet der Checkout hoechstens zwei Sekunden statt bis zum PHP-Timeout.
|
|
$dsn = sprintf(
|
|
'host=%s port=%s dbname=%s user=%s password=%s connect_timeout=2',
|
|
isset($pg['host']) ? $pg['host'] : 'localhost',
|
|
isset($pg['port']) ? $pg['port'] : '5432',
|
|
isset($pg['database']) ? $pg['database'] : '',
|
|
isset($pg['user']) ? $pg['user'] : '',
|
|
isset($pg['password']) ? $pg['password'] : ''
|
|
);
|
|
|
|
$verbindung = @pg_connect($dsn);
|
|
|
|
if (!$verbindung) {
|
|
$verbindung = null;
|
|
$tot = true;
|
|
error_log('shop_event: keine PG-Verbindung -- Ereignisprotokoll uebersprungen');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$werte = array(
|
|
(string)$ereignis,
|
|
isset($daten['order_id']) && $daten['order_id'] !== '' ? (int)$daten['order_id'] : null,
|
|
isset($daten['order_number']) ? (string)$daten['order_number'] : null,
|
|
isset($daten['payment_method']) && $daten['payment_method'] !== '' ? (int)$daten['payment_method'] : null,
|
|
isset($daten['betrag']) && $daten['betrag'] !== '' ? (float)$daten['betrag'] : null,
|
|
isset($daten['paypal_token']) ? (string)$daten['paypal_token'] : null,
|
|
isset($daten['transaction_id']) ? (string)$daten['transaction_id'] : null,
|
|
isset($daten['customer_id']) && $daten['customer_id'] !== '' ? (int)$daten['customer_id'] : null,
|
|
function_exists('session_id') && session_id() ? session_id() : null,
|
|
isset($daten['detail']) ? (string)$daten['detail'] : null
|
|
);
|
|
|
|
$ergebnis = @pg_query_params(
|
|
$verbindung,
|
|
'INSERT INTO shop_order_events
|
|
(ereignis, order_id, order_number, payment_method, betrag,
|
|
paypal_token, transaction_id, customer_id, session_id, detail)
|
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)',
|
|
$werte
|
|
);
|
|
|
|
if (!$ergebnis) {
|
|
// Einmal melden, dann Ruhe -- ein volllaufendes Log hilft niemandem.
|
|
$tot = true;
|
|
error_log('shop_event: INSERT fehlgeschlagen (' . $ereignis . ') -- '
|
|
. @pg_last_error($verbindung));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* EOF */
|