📞
Повече клиенти чрез ефективна реклама и оптимизиран сайт

Създавам и оптимизирам Google Ads, Facebook Ads и сайтове с цел повече запитвания и продажби.
✔ ясна стратегия
✔ измерими резултати
✔ дългосрочно развитие

Stripe Checkout + Webhook интеграция с PHP 5.4 и MySQL

Stripe Checkout + Webhook интеграция с PHP 5.4 и MySQL

Пълно ръководство за интеграция на Stripe Checkout със стар PHP проект (PHP 5.4), използващ mysql_* функции и класически MySQL flow.

Съдържание

  • Как работи Stripe Checkout
  • Какво е webhook и защо е необходим
  • Защо success.php не е достатъчен
  • Как се създава Checkout Session
  • Как се праща metadata
  • Как Stripe връща order_id
  • Как работи php://input
  • Как се обработва JSON payload
  • Как се update-ва база данни
  • Проблеми с PHP 5.4
  • Как да дебъгваме webhook-и
  • Най-чести грешки
  • Stripe Dashboard
  • Как да тестваме плащания
  • Success page vs webhook
  • Пълен работещ webhook код

Част 1: Какво е Stripe

Stripe е online payment processor. Позволява:

  • плащания с карти
  • Apple Pay / Google Pay
  • банкови плащания
  • subscriptions (recurring billing)
  • invoices
  • checkout страници
  • payment links
Stripe НЕ е твоят сайт. Stripe е външна payment система, която обработва реалните плащания.

Част 2: Как работи Stripe Checkout

1. Клиент добавя продукти
2. Клиент натиска "Плати"
3. Твоят сайт създава Stripe Checkout Session
4. Stripe връща checkout URL
5. Клиентът се прехвърля към Stripe
6. Клиентът плаща
7. Stripe обработва плащането
8. Stripe праща webhook
9. Твоят сайт update-ва поръчката
10. Клиентът вижда success page
    

Част 3: Какво е Checkout Session

Checkout Session е payment session. Примерен Stripe response:

Array
(
    [id] => cs_test_xxxxx
    [object] => checkout.session
    [payment_status] => paid
    [status] => complete
)
    

Най-важните полета:

ПолеЗначение
idID на checkout session
payment_statuspaid / unpaid
statuscomplete / open
metadatacustom данни (order_id)
customer_detailsданни за клиента

Част 4: Защо metadata е много важно

Metadata позволява да свържем Stripe payment с нашата локална поръчка.

'payload' => array(
    'metadata' => array(
        'order_id' => 33
    )
)
    

После Stripe връща:

"metadata": { "order_id": "33" }
Без metadata няма как да знаем коя поръчка да update-нем.

Част 5: Success Page vs Webhook (най-важната концепция)

Много хора мислят: "success.php потвърждава плащането" – това НЕ е вярно.

Success page е само визуална страница. Клиентът може да затвори браузъра, redirect може да fail-не, user може да refresh-не. Success page НЕ е reliable source.

Webhook е server-to-server комуникация. Stripe изпраща POST request към твоя URL. Това е истинското потвърждение.

Част 6: Какво прави success.php

  • показва "Благодаря"
  • показва "Поръчката е приета"
  • може да покаже summary
Но success.php НЕ update-ва базата данни за плащане.

Част 7: Какво е webhook

Stripe изпраща HTTP POST към твоя URL (напр. https://example.com/webhook.php) с JSON payload.

Част 8: Как Stripe извиква webhook.php

Stripe не чете файлове. Stripe просто прави POST заявка към URL-а. Сървърът намира webhook.php и PHP стартира файла.

Част 9: Какво е php://input

$payload = file_get_contents("php://input");

php://input НЕ е файл. Това е HTTP request body. Stripe изпраща JSON, PHP го чете чрез php://input.

Част 10: Какво реално идва от Stripe

{
  "id": "evt_123",
  "type": "checkout.session.completed",
  "data": {
    "object": {
      "metadata": {
        "order_id": "33"
      }
    }
  }
}
    

Част 11: json_decode

$event = json_decode($payload, true);

true означава: върни array, не object.

Част 12: PHP 5.4 проблеми

PHP 5.4 е много стара версия. Някои модерни синтаксиси НЕ работят.

Например $value = $x ?? 'default'; – Това дава Parse error в PHP 5.4.

Част 13: Как се пише PHP 5.4 compatible код

// Вместо:
$x = $value ?? 'default';

// Пиши:
$x = isset($value) ? $value : 'default';

Част 14: Проверка за Stripe Event Type

if (!isset($event['type']) || $event['type'] !== 'checkout.session.completed') {
    http_response_code(200);
    exit;
}

Част 15: Защо връщаме 200

Stripe очаква HTTP 200 OK. Ако няма 200, Stripe счита webhook-а за failed и ще retry-ва автоматично.

Част 16: Retry система на Stripe

Stripe автоматично retry-ва неуспешни webhook-и. Това е много важно за надеждност.

Част 17: Как взимаме order_id от metadata

$order_id = 'NO ORDER';
if (isset($session['metadata']['order_id'])) {
    $order_id = $session['metadata']['order_id'];
}
    

Част 18: Старият mysql_* стил

Много legacy проекти използват mysql_connect() и mysql_query(). Това е deprecated, но работи на стари hosting-и.

mysql_connect("localhost", "db_user", "db_pass");
mysql_select_db("database_name");
    

Част 19: SQL Injection защита

Никога не използвайте $order_id директно в заявката без sanitize!
$order_id = mysql_real_escape_string($order_id);

Част 20: Update Query

mysql_query("
    UPDATE cnt_members_order
    SET act_active = '2'
    WHERE orders_id = $order_id
");
    

Примерна логика на act_active:

СтойностЗначение
0unpaid
1pending
2paid

Част 21: Финален работещ webhook (PHP 5.4 съвместим)

<?php
// Read Stripe payload
$payload = file_get_contents("php://input");
$event = json_decode($payload, true);

// Safety check
if (!isset($event) || !is_array($event)) {
    http_response_code(200);
    exit;
}

// Check event type
if (!isset($event['type']) || $event['type'] !== 'checkout.session.completed') {
    http_response_code(200);
    exit;
}

// Get session object
$session = array();
if (isset($event['data']['object'])) {
    $session = $event['data']['object'];
}

// Get order_id
$order_id = 'NO ORDER';
if (isset($session['metadata']['order_id'])) {
    $order_id = $session['metadata']['order_id'];
}

// Stop if no order
if ($order_id == 'NO ORDER') {
    http_response_code(200);
    exit;
}

// Connect DB
mysql_connect("localhost", "db_user", "db_pass");
mysql_select_db("database_name");

// Sanitize
$order_id = mysql_real_escape_string($order_id);

// Update order
mysql_query("
    UPDATE cnt_members_order
    SET act_active = '2'
    WHERE orders_id = $order_id
");

http_response_code(200);
exit;
?>
    

Част 22: Защо debug.txt беше полезен

file_put_contents(__DIR__.'/debug.txt', "WEBHOOK HIT\n", FILE_APPEND);
file_put_contents(__DIR__.'/debug.txt', "RAW:\n".$payload, FILE_APPEND);
    

Част 23: Най-чести webhook проблеми

ПроблемРешение
Грешен URL в Stripe DashboardПроверете endpoint URL-a
PHP Parse ErrorИзползвайте PHP 5.4 съвместим синтаксис
json_decode failПроверете дали payload е валиден JSON
mysql_query failПроверете DB връзката
Няма metadata order_idДобавете metadata при създаване на session

Част 24: Stripe Dashboard

В Stripe Dashboard можеш да видиш: плащания, webhook-и, retries, failed events, event payload, customer details.

Част 25: Test Mode

Stripe има test mode и live mode. Винаги тествай в test mode. Тестова карта: 4242 4242 4242 4242

Част 26: Защо webhook е по-важен от success page

Success page: зависи от браузъра, зависи от redirect.
Webhook: server-to-server, reliable, автоматичен.

Част 27: Какво става без webhook

Stripe ✔ получава парите. Сайтът ❌ не знае че е платено.

Част 28: Webhook URL трябва да е public и HTTPS

Stripe сървърите трябва да могат да достъпят URL-a. localhost НЕ работи. Използвайте https://, не http://.

Финален извод: Stripe webhook + metadata + PHP 5.4 съвместим код + mysql_* е напълно работещо решение за legacy проекти. Уверете се, че webhook endpoint е правилно настроен в Stripe Dashboard, че metadata съдържа order_id, и че обработвате само checkout.session.completed събития.