PHP'de WayForPay entegrasyonu: ödeme formu, imza ve geri arama
WayForPay Ukraynalı bir işletmeden UAH, USD ve EUR cinsinden kart ödemelerini kabul etmenin pratik yoludur. Bu kılavuz PHP'nin tam entegrasyonunu anlatmaktadır: ödeme formunu imzalamak, sunucu geri aramasını almak, doğru yanıtlamak ve sipariş durumunu onaylamak.
Kısaca
- Akışın üç bölümü vardır: müşteriyi WayForPay gönderen imzalı bir ödeme formu, sunucular arası geri arama (
serviceUrl) ve kendi sipariş durumu sayfanız. - Her istek ve yanıt, satıcı gizli anahtarınız kullanılarak HMAC_MD5 ile imzalanır; saha sırası önemlidir.
- Bir siparişi yalnızca doğrulanmış bir geri aramadan veya
CHECK_STATUSyanıtından ödendi olarak işaretleyin; asla sitenize dönen müşteriden değil. - Geri aramaya imzalı bir JSON "kabul et" yanıtıyla yanıt vermelisiniz, aksi takdirde WayForPay yeniden denemeye devam eder.
- Tutarları, para birimini ve sipariş referansını veritabanınızda tutun ve bunları geri aramanın söyledikleriyle karşılaştırın.
PHP'deki WayForPay entegrasyonu küçük miktarda bir koddur, ancak sessiz bir hatanın ya ödenmiş olarak işaretlenmiş ödenmemiş siparişler ya da hiçbir zaman yerine getirilmeyen ücretli siparişler anlamına geldiği birkaç yeri vardır. WayForPay ödemesini bu web sitesindeki ücretli hizmetler de dahil olmak üzere kendi sitelerimizde çalıştırıyoruz ve bunu çeşitli müşteri mağazalarına bağladık. Aşağıda, belgelerin listelediği ancak insanların gözden geçirme eğiliminde olduğu ayrıntılarla birlikte kullandığımız yapı bulunmaktadır.
Ödeme akışı nasıl çalışır?
- Müşteri "Öde"ye tıklar. Sunucunuz, veritabanında benzersiz bir
orderReference, sabit bir tutar ve para birimine sahip bir sipariş oluşturur. - Sunucunuz ödeme formu alanlarını oluşturur, bunları imzalar ve WayForPay ödeme sayfasına gönderilen otomatik olarak gönderilen bir HTML formu oluşturur.
- Müşteri WayForPay sayfasında ödeme yapar (kart, Apple Pay, Google Pay ve satıcı hesabınızda etkinleştirilen diğer yöntemler).
- WayForPay işlem sonucunu içeren
serviceUrlçağırır. Bu sunucudan sunucuya çağrı güvendiğiniz şeydir. - Müşteri, mevcut sipariş durumunu gösterdiğiniz
returnUrladresinize yönlendirilir.
5. Adım, 4. Adım tamamlanmadan gerçekleşebilir, bu nedenle geri arama işlenene kadar dönüş sayfasında "ödemeniz onaylanıyor" yazmalıdır.
Satıcı hesabından ihtiyacınız olan şey
merchantAccount- satıcı giriş bilgileriniz.merchantSecretKey- imzalar için kullanılan sır. Bunu bir ortam değişkeninde veya izlenmeyen bir yapılandırma dosyasında saklayın; asla git'te veya ön uç kodunda değil.merchantDomainName- hesapta kayıtlı haliyle sitenizin alan adı.- Hesabınız için etkinleştirilen para birimleri ve ödeme yöntemleri.
1. Adım. Ödeme formunu oluşturun ve imzalayın
İmza, noktalı virgülle birleştirilmiş seçili alanlar üzerinde MD5 içeren bir HMAC'dir. Bir satın alma işlemi için sipariş şu şekildedir: satıcı hesabı, satıcı alan adı, sipariş referansı, sipariş tarihi (Unix zaman damgası), tutar, para birimi, ardından tüm ürün adları, tüm ürün sayıları ve tüm ürün fiyatları.
function wfpSignature(array $parts, string $secret): string
{
return hash_hmac('md5', implode(';', $parts), $secret);
}
$orderReference = 'ORD-' . $orderId . '-' . time();
$orderDate = time();
$amount = '50.00'; // string with a dot, the same value everywhere
$currency = 'EUR';
$products = [['name' => 'Consultation, 1 hour', 'count' => 1, 'price' => '50.00']];
$parts = [$merchantAccount, $merchantDomain, $orderReference, $orderDate, $amount, $currency];
foreach ($products as $p) { $parts[] = $p['name']; }
foreach ($products as $p) { $parts[] = (string) $p['count']; }
foreach ($products as $p) { $parts[] = $p['price']; }
$signature = wfpSignature($parts, $secretKey);
Daha sonra formu render edin. Ürün alanları dizilerdir, dolayısıyla [] sonekini kullanırlar:
<form id="wfp" method="post" action="https://secure.wayforpay.com/pay" accept-charset="utf-8">
<input type="hidden" name="merchantAccount" value="...">
<input type="hidden" name="merchantAuthType" value="SimpleSignature">
<input type="hidden" name="merchantDomainName" value="example.com">
<input type="hidden" name="merchantSignature" value="<?= htmlspecialchars($signature) ?>">
<input type="hidden" name="orderReference" value="<?= htmlspecialchars($orderReference) ?>">
<input type="hidden" name="orderDate" value="<?= $orderDate ?>">
<input type="hidden" name="amount" value="50.00">
<input type="hidden" name="currency" value="EUR">
<input type="hidden" name="productName[]" value="Consultation, 1 hour">
<input type="hidden" name="productCount[]" value="1">
<input type="hidden" name="productPrice[]" value="50.00">
<input type="hidden" name="returnUrl" value="https://example.com/pay/return">
<input type="hidden" name="serviceUrl" value="https://example.com/pay/callback">
</form>
<script>document.getElementById('wfp').submit();</script>
En yaygın imza hataları şunlardır: imzada ve formda farklı bir sayı biçimi (50 vs 50.00), imzalandıktan sonra değiştirilen (kırpılmış, HTML çıkışlı) bir ürün adı ve alanların sırasının sabit olduğunun unutulması.
2. Adım. ServiceUrl'de geri aramayı alın
Ödeme nihai duruma ulaştığında WayForPay sonucu serviceUrl gönderir. Ham gövdeyi okuyun (bu JSON'dur; bazı kurulumlar form alanları da sunar; bu nedenle her ikisini de kullanın) ve imzayı doğrulayın. Geri arama için hesaplanırken satıcı hesabı, sipariş referansı, tutar, para birimi, yetki kodu, kart maskesi, işlem durumu ve neden kodu dikkate alınır.
$raw = file_get_contents('php://input');
$data = json_decode($raw, true) ?: $_POST;
$line = implode(';', [
$data['merchantAccount'] ?? '',
$data['orderReference'] ?? '',
$data['amount'] ?? '',
$data['currency'] ?? '',
$data['authCode'] ?? '',
$data['cardPan'] ?? '',
$data['transactionStatus'] ?? '',
$data['reasonCode'] ?? '',
]);
$expected = hash_hmac('md5', $line, $secretKey);
if (!hash_equals(strtolower($expected), strtolower((string) ($data['merchantSignature'] ?? '')))) {
http_response_code(400);
exit;
}
Zamanlama sızıntılarını önlemek amacıyla karşılaştırma için hash_equals kullanın. Ancak imza geçerli olduktan sonra siparişe bakmalı ve amount ve currency sakladığınız tutarla karşılaştırmalısınız. Farklıysa, kaydedin ve siparişi ödendi olarak işaretlemeyin.
3. Adım. Sırayı güncelleyin ve doğru yanıtlayın
transactionStatus alanı size ne olduğunu anlatır: Approved paranın ele geçirildiği anlamına gelir; Declined, Expired ve benzeri değerler başarısızlık anlamına gelir; Pending veya InProcessing, bekleme anlamına gelir; Refunded ve Voided, paranın geri döndüğü anlamına gelir. Siparişinizi bir işlemde uygun şekilde güncelleyin ve onu bağımsız hale getirin: sipariş zaten ödenmişse, hiçbir şey yapmayın ve yine de başarılı bir şekilde yanıt verin.
WayForPay mesajı aldığınızı bilmesi için imzalı bir yanıt gerektirir. İmza aşırı sipariş referansıdır, accept kelimesi ve geçerli saat:
$time = time();
$status = 'accept';
$reply = [
'orderReference' => $data['orderReference'],
'status' => $status,
'time' => $time,
'signature' => hash_hmac('md5', "{$data['orderReference']};{$status};{$time}", $secretKey),
];
header('Content-Type: application/json');
echo json_encode($reply);
Sunucunuz bu şekilde yanıt vermezse WayForPay teslimatı başarısız olarak değerlendirir ve yeniden dener; bu da aynı geri aramayı birkaç kez alacağınız anlamına gelir. Bu, idempotency kontrolünün başka bir nedenidir.
4. Adım. Durumu CHECK_STATUS ile onaylayın
Geri aramalar kaçırılabilir: sunucunuz kapalıydı, bir güvenlik duvarı isteği engelledi, bir dağıtım rotayı bozdu. WayForPay bir siparişin mevcut durumunu referansına göre döndüren bir CHECK_STATUS API çağrısı sunar. Bunu iki yerde kullanın: birkaç saniye sonra geri arama gelmediyse dönüş sayfasında ve örneğin on beş dakikadan fazla bir süre "beklemede" durumda kalan siparişleri yeniden kontrol eden küçük bir cron işinde. Talep, satıcı hesabı ve sipariş referansı üzerinden HMAC_MD5 ile imzalanır.
$payload = [
'transactionType' => 'CHECK_STATUS',
'merchantAccount' => $merchantAccount,
'orderReference' => $orderReference,
'merchantSignature' => hash_hmac('md5', "{$merchantAccount};{$orderReference}", $secretKey),
'apiVersion' => 1,
];
$ch = curl_init('https://api.wayforpay.com/api');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
]);
$result = json_decode((string) curl_exec($ch), true);
Geri arama için yapılan kontrollerin aynısını uygulayın: Yanıt imzası mevcut olduğunda doğrulayın, tutarı ve para birimini karşılaştırın ve siparişi anında güncelleyin.
Yayına geçmeden önce test etme
- Günlüklerinizde tam ödeme, ret ve geri ödeme görünene kadar WayForPay belgelerindeki test modunu ve test kartlarını kullanın.
serviceUrlinternetten HTTPS üzerinden erişilebilir olmalıdır. Localhost'ta bir tünel kullanın veya bir hazırlama alanına konuşlandırın.- Her geri aramayı ham gövdesi, doğrulama sonucu ve sonucuyla birlikte kaydedin. Asla gizli anahtarı kaydetmeyin.
- WAF veya bot korumasının (örneğin Cloudflare) WayForPay geri arama isteklerine meydan okumadığından veya bunları engellemediğinden emin olun.
Yaygın hatalar
- Dönüş URL'sine güvenme. Müşteri ödeme yapmadan açabilir.
- Bir sipariş referansını yeniden kullanma. Her denemenin benzersiz bir referansa ihtiyacı vardır, aksi takdirde denemeleri karıştırırsınız.
- İmzaladıktan sonra tutarı değiştirmek veya bir fiyatı gösterip diğerini imzaladıktan sonra.
- Geri aramaya imzalı kabul yanıtıyla yanıt vermemek.
- Tutarı ve para birimini kontrol etmeden önce ödendi olarak işaretle.
- Birkaç para birimi, paylaşılan bir sır ve eşleme yok: Para birimini sırayla tutun ve geri aramada doğrulayın.
Nasıl yardımcı olabiliriz?
Ödeme entegrasyonlarını uçtan uca oluşturuyoruz: WayForPay, Stripe, PayPal, yinelenen faturalandırma, geri ödemeler ve mutabakat raporları. Zaten çalışan bir ödemeniz varsa ancak hata modlarından emin değilseniz, bir mimari analizi yaptırın; geri arama yönetimini, önemsizliği ve günlüğe kaydetmeyi inceleyeceğiz. Başka bir sağlayıcıya ilişkin benzer bir kılavuz için PHP'deki Stripe web kancalarına bakın ve genel yaklaşım için başlangıç entegrasyonları taktik kitabımızı okuyun.
Sık sorulan sorular
WayForPay hangi imzayı kullanıyor?
Satıcı gizli anahtarı kullanılarak, noktalı virgülle birleştirilmiş seçili alanlar üzerinde HMAC_MD5. Saha sırası sabittir ve ödeme formu, geri arama ve geri arama yanıtı için farklılık gösterir.
ServiceUrl uç noktasının neyi döndürmesi gerekir?
OrderReference, "accept" durumu, mevcut Unix saati ve "orderReference;accept;time"ın HMAC_MD5 olarak hesaplanan imzayı içeren bir JSON yanıtı. Bu olmadan WayForPay geri aramayı yeniden dener.
Bir siparişi ödendi olarak işaretlemek için returnUrl sayfasına güvenebilir miyim?
Hayır. Müşterinin tarayıcısı bu URL'yi ödeme yapmadan açabilir. Siparişleri yalnızca doğrulanmış bir serviceUrl geri çağrısından veya Onaylandı durumu ve eşleşen tutar ve para birimiyle CHECK_STATUS yanıtı sonrasında ödendi olarak işaretleyin.
WayForPay siparişinin durumunu nasıl kontrol ederim?
Satıcı hesabınız ve sipariş referansınızla birlikte WayForPay API'sine imzalı bir CHECK_STATUS isteği gönderin. Bunu dönüş sayfasında ve beklemede kalan siparişleri yeniden kontrol eden bir cron işinde kullanın.
WayForPay neden imzanın geçersiz olduğunu söylüyor?
Genellikle tutar formatı imza ve form arasında farklılık gösterir (50 vs 50,00), imzalandıktan sonra ürün adı değiştirilmiş, alanların sırası yanlış veya yanlış gizli anahtar kullanılmış.
Ü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.