PHP'de Stripe webhook'lar: güvenebileceğiniz güvenilir bir işleyici
Dizüstü bilgisayarınızda çalışan Stripe web kancası henüz para konusunda güvenebileceğiniz bir web kancası değildir. Bu kılavuz, bir projeye yapıştırabileceğiniz kodla düz PHP ve Laravel imzaların nasıl doğrulanacağını, hızlı bir şekilde onaylanacağını, olayların tekilleştirilmesini ve yeniden denemelerin nasıl ele alınacağını gösterir.
Kısaca
- Ödeme durumuyla ilgili gerçeğin kaynağı olarak tarayıcı yönlendirmesini değil web kancasını ele alın.
- Ham istek metnini okuyun ve yüke dokunmadan önce
Stripe-Signaturebaşlığını doğrulayın. - Hızlı bir şekilde 2xx yanıtı döndürün ve asıl işi kuyrukta veya olayı kaydettikten sonra yapın.
- Etkinlik kimliğini benzersiz bir dizinle saklayın: Stripe aynı etkinliği birden fazla kez ve sıra dışı olarak sunabilir.
- Canlı yayına geçmeden önce Stripe CLI (
stripe listenvestripe trigger) ile test edin.
Stripe ile ödeme kabul ediyorsanız PHP'deki Stripe web kancaları, siparişlerin ücretli olarak işaretlenip işaretlenmediğine, aboneliklerin etkinleştirilip etkinleştirilmediğine ve geri ödemelerin veritabanınıza yansıtılıp yansıtılmadığına karar veren kısımdır. Ödeme sayfası yalnızca ön kapıdır: müşteriler hesaplarını kapatır, bankalar geç onay verir ve bazı ödeme yöntemleri dakikalar veya günler sonra ödeme yapar. Webhook, Stripe gerçekte ne olduğunu anlatan mesajıdır.
Müşterilerimiz ve kendi ürünlerimiz için ödeme entegrasyonları oluşturuyor ve sürdürüyoruz (örneğin, Stripe ve PayPal ödemelerini halka açık bir ödeme sayfasında alan Bill). Bu makale PHP'de Stripe webhook uç noktası yazarken takip ettiğimiz kontrol listesidir.
Stripe web kancaları bir dakikada nasıl çalışır?
Stripe Dashboard'a (veya API aracılığıyla) bir HTTPS URL'si kaydedersiniz ve hangi etkinlik türlerinin alınacağını seçersiniz. Bir şey olduğunda - Ödeme Oturumu tamamlandığında, fatura ödendiğinde, ücret iade edildiğinde - Stripe bu URL'ye JSON Etkinliği nesnesi içeren bir POST isteği gönderir. Sunucunuz 2xx durum koduyla yanıt vermelidir. Aksi takdirde Stripe, canlı modda üç güne kadar üstel geri çekilmeyle yeniden dener.
Tüm tasarımı üç gerçek şekillendiriyor:
- Etkinlikler birden fazla kez gelebilir. Yeniden denemeler ve ağ sorunları, yinelemeleri normal hale getirir.
- Olaylar sıra dışı gelişebilir.
customer.subscription.createdönceinvoice.paidgörebilirsiniz. - Herkes URL'nize POST yapabilir. İmza doğrulaması olmadan saldırgan kendi siparişini ödendi olarak işaretleyebilir.
1. Adım. SDK'yı yükleyin ve uç noktayı oluşturun
Resmi kütüphane olan stripe/stripe-php kullanın ve uç noktayı (whsec_ ile başlar) bir ortam değişkeninde gizli tutun, asla depoda tutmayın.
composer require stripe/stripe-php
# .env
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
Kontrol Panelindeki her webhook uç noktasının kendi imzalama sırrı vardır ve geliştirme aşamasında stripe listen sırrı yine farklıdır. Çok yaygın bir "imza doğrulaması başarısız oldu" hatası, yanlış imzanın kullanılmasıdır.
2. Adım. Ham gövdedeki imzayı doğrulayın
Stripe her isteği imzalar. Stripe-Signature üstbilgisi, uç nokta sırrınızla birlikte timestamp.payload HMAC-SHA256'sı olarak hesaplanan bir zaman damgasını ve bir veya daha fazla imzayı içerir. Kitaplık imzayı kontrol eder ve varsayılan olarak beş dakikadan eski olayları reddeder.
Önemli ayrıntı: Doğrulama için Stripe gönderdiği ham baytların tam olarak belirtilmesi gerekiyor. Bir çerçeve JSON'u ayrıştırırsa ve onu yeniden kodlarsanız boşluk değişir ve imza artık eşleşmez.
<?php
// public/webhooks/stripe.php (plain PHP)
require __DIR__ . '/../../vendor/autoload.php';
$payload = file_get_contents('php://input');
$sigHeader = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? '';
$secret = getenv('STRIPE_WEBHOOK_SECRET');
try {
$event = \Stripe\Webhook::constructEvent($payload, $sigHeader, $secret);
} catch (\UnexpectedValueException $e) {
http_response_code(400); // invalid JSON
exit;
} catch (\Stripe\Exception\SignatureVerificationException $e) {
http_response_code(400); // bad or missing signature
exit;
}
Laravel, $ $request->all() $request->getContent() öğesini okuyun ve rotayı CSRF korumasının dışında tutun (web kancaları bir CSRF belirteci taşımaz; imza korumadır). Mümkünse rotayı web oturumu ara katman yazılımı grubunun dışına koyun.
3. Adım. İşleyiciyi bağımsız hale getirin
İdempotent şu anlama gelir: aynı olayın iki kez işlenmesi, bir kez işlenmesiyle aynı sonucu verir. En basit güvenilir yaklaşım, benzersiz bir dizine sahip işlenmiş olay kimliklerinin bir tablosudur. İlk önce ekleyin; Kimlik mevcut olduğu için ekleme işlemi başarısız olursa, olayı zaten görmüşsünüzdür.
CREATE TABLE stripe_events (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
event_id VARCHAR(64) NOT NULL,
type VARCHAR(100) NOT NULL,
payload JSON NOT NULL,
status ENUM('received','processed','failed') NOT NULL DEFAULT 'received',
received_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
processed_at TIMESTAMP NULL,
UNIQUE KEY uniq_event (event_id)
);
try {
$pdo->prepare('INSERT INTO stripe_events (event_id, type, payload) VALUES (?, ?, ?)')
->execute([$event->id, $event->type, $payload]);
} catch (PDOException $e) {
if ($e->getCode() === '23000') { // duplicate key: already received
http_response_code(200);
exit;
}
throw $e;
}
Ham yükü depolamak size bir denetim takibi sağlar: Bir müşteri "neden iki kez ücretlendirildim?" diye sorduğunda Stripe size söylediklerini tam olarak tekrarlayabilirsiniz. Ayrıca, bir hatayı düzelttikten sonra başarısız olan olayların yeniden işlenmesini mümkün kılar.
Adım 4. Hızlı onaylayın, ayrı işleyin
Stripe birkaç saniye içinde yanıt bekliyor. İşleyiciniz e-posta gönderirse, diğer API'leri çağırırsa veya satır içi PDF'ler oluşturursa zaman aşımına uğrar, Stripe yeniden dener ve siz de aynı işi yeniden yaparsınız. İstekte minimum olanı yapın - doğrulayın, saklayın, yanıtlayın 200 - ve gerçek mantığı bir kuyruk çalışanında çalıştırın ( Laravel kuyrukları, Symfony Messenger, bir cron işi okuma status = 'received' veya yönetici tarafından yönetilen bir çalışan).
Olay hiçbir şekilde saklanamıyorsa (veritabanı kapalı), 5xx durumunu döndürün. Stripe daha sonra tekrar denemesini isteyeceğiniz tek durum budur.
Adım 5. Önemli olayları ele alın
Her etkinlik türüne ihtiyacınız yoktur. Yalnızca iş mantığınızın kullandığı şeylere abone olun; daha az abonelik, daha az gürültü ve daha küçük bir saldırı yüzeyi anlamına gelir. Tipik bir set:
checkout.session.completed- müşteri Checkout'u tamamladı. Oturumu oluştururken belirlediğinizclient_reference_idveya meta verileri kullanarak siparişinizi arayın.payment_intent.succeededvepayment_intent.payment_failed- özel ödeme akışları için.invoice.paidveinvoice.payment_failed- abonelik faturalandırması.customer.subscription.updatedvecustomer.subscription.deleted- plan değişiklikleri ve iptalleri.charge.refundedvecharge.dispute.created- para geri ödeniyor.
switch ($event->type) {
case 'checkout.session.completed':
$session = $event->data->object;
$orderId = $session->client_reference_id;
if ($session->payment_status === 'paid') {
markOrderPaid($orderId, $session->payment_intent);
}
break;
case 'invoice.payment_failed':
notifyBillingProblem($event->data->object->customer);
break;
case 'charge.refunded':
markOrderRefunded($event->data->object->payment_intent);
break;
default:
// unknown or unsubscribed type: acknowledge and ignore
break;
}
İki alışkanlık çoğu hatayı önler. Öncelikle tarayıcıdan gelen tutarlara asla güvenmeyin: Etkinlikte ödenen tutarı ve para birimini veritabanınızdaki siparişle karşılaştırın. İkincisi, olaylar sıra dışı olabileceğinden, durum değişikliklerini monoton hale getirin: daha eski bir olay geç geldiğinden dolayı bir emri "ücretli" durumundan "beklemede" durumuna getirmeyin. Şüpheye düştüğünüzde, olayın anlık görüntüsüne güvenmek yerine geçerli nesneyi API'den alın.
6. Adım. Stripe CLI ile yerel olarak test edin
Stripe CLI gerçek test modu olaylarını makinenize iletir, böylece genel bir tünele ihtiyacınız olmaz:
stripe login
stripe listen --forward-to http://localhost:8000/webhooks/stripe
# in another terminal:
stripe trigger checkout.session.completed
stripe trigger invoice.payment_failed
stripe listen geçici bir whsec_ sırrı yazdırır. Bunu yerel .env dosyanıza koyun. Ayrıca istenmeyen yolları da bilerek test edin: yanlış imzayla bir istek gönderin (400 bekliyoruz), aynı olayı iki kez gönderin (bir veritabanı efekti bekleyin) ve olayların kaybolmak yerine yığıldığını görmek için kuyruk çalışanınızı bir dakikalığına durdurun.
Denetimlerde gördüğümüz yaygın hatalar
- Yönlendirmeyi ödeme kanıtı olarak kullanma.
success_urlsayfası herkes tarafından açılabilir; webhook gelene kadar "ödemeniz onaylanıyor" ifadesini gösterin. - Doğrulamadan önce JSON ayrıştırılıyor. Yeniden kodlanmış gövdeler imzayı bozar; çerçeve gövdesi ayrıştırıcıları sıklıkla suçludur.
- Test etmek ve yaşamak için bir sır. Test ve canlı mod, ayrı anahtarlara ve ayrı webhook uç noktalarına sahiptir.
- Günlük yok. Saklanan olaylar ve gözle görülür bir hata kanalı olmadığında, ödeme hataları müşteriler tarafından bulunur.
- Yavaş idareciler. Birkaç saniyeden uzun süren herhangi bir şey, yeniden denemeleri ve yinelenen çalışmayı tetikler.
- Stripe güvenlik duvarında veya WAF'ta engelleme. Cloudflare veya başka bir WAF kullanıyorsanız webhook yoluna izin verin ve bot kurallarının Stripe sunucularına 403 döndürmediğini kontrol edin.
İzleme: çalışmaya devam ettiğini nasıl anlarsınız?
Bir web kancası lansmandan aylar sonra bozulabilir: Dağıtılan bir değişiklik bir sütunu yeniden adlandırır, bir sır döndürülür, bir sertifikanın süresi dolar. Stripe Dashboard, uç nokta başına teslimat girişimlerini ve başarısızlıkları gösterir ve bir uç nokta başarısız olmaya devam ettiğinde Stripe size e-posta gönderir. Sizin tarafınızda üç şeye karşı tetikte olun: received veya failed olayların sayısının artması, saat başına olaylarda ani bir düşüş ve webhook rotasındaki herhangi bir 4xx veya 5xx oranı. Veritabanınızdaki ödenmiş siparişleri Stripe başarılı ödemeler listesiyle karşılaştıran küçük bir günlük mutabakat işi gerisini halleder.
Nasıl yardımcı olabiliriz?
İmza kontrolleri, kayıtsızlık, yeniden denemeler ve ekibinizin okuyabileceği günlükler ile üretim ödemesi ve web kancası entegrasyonları tasarlıyor ve oluşturuyoruz. Zaten bir Stripe akışınız varsa ve ikinci bir çift göz istiyorsanız, mimari inceleme veya danışmanlık zayıf noktaları bulmanın en hızlı yoludur. Kritik olayların Zapier veya Make'den taşınmasına ilişkin daha geniş bir resim için, kod yokken okuyun ve başka bir sağlayıcı için PHP'de WayForPay entegrasyonu kılavuzumuza bakın.
Sık sorulan sorular
Stripe webhook imza doğrulaması neden başarısız oluyor?
Genel nedenler arasında yanlış imzalama sırrının kullanılması (test vs canlı, CLI vs Kontrol Paneli uç noktası), ham istek gövdesi yerine ayrıştırılmış veya yeniden kodlanmış bir gövdenin veya yükü değiştiren bir proxy'nin doğrulanması yer alır. Uç noktanın kendi whsec_ sırrı ile tam ham baytlara göre doğrulama yapın.
Bir Stripe olayının iki kez işlenmesini nasıl önleyebilirim?
Her olay kimliğini benzersiz bir dizine sahip bir tabloda saklayın ve herhangi bir iş yapmadan önce bunu ekleyin. Ekleme yinelenen bir anahtarla başarısız olursa, 200 değerini döndürün ve işlemi atlayın. Ayrıca iş eyleminin kendisini tekrarlanmasını güvenli hale getirin.
Stripe webhook'un hangi yanıt kodunu döndürmesi gerekir?
Etkinlik doğrulanır ve kaydedilir kaydedilmez 2xx kodunu (200 veya 204) döndürün. Geçersiz bir imza için 400 değerini, yalnızca etkinliği depolayamadığınızda ve Stripe yeniden denemesini istediğinizde 5xx değerini döndürün.
Stripe başarısız web kancalarını ne kadar sürede yeniden dener?
Canlı modda Stripe üç güne kadar üstel geri çekilmeyle yeniden dener. Test modunda yeniden deneme penceresi çok daha kısa olduğundan, üretim davranışını değerlendirmek için test modundaki yeniden denemelere güvenmeyin.
Stripe web kancalarını genel bir URL olmadan test edebilir miyim?
Evet. Test olaylarını localhost'a iletmek için Stripe CLI ile stripe listen --forward-to komutunu çalıştırın ve örnek olaylar oluşturmak için stripe tetikleyiciyi kullanın.
Ücretsiz keşif görüşmesi
Dağınık bir yığın veya takılmış bir entegrasyon getirin - Integrono en akıllı ilk adımı haritalar.
Bütçe tuzakları, bağımlılıklar ve satın al / yapıştır / inşa kararında kıdemli bir bakış alırsınız - ücretli iş başlamadan. CEO döngüde kalır.