Gereksinimler ve Ön Hazırlık
Güvenli bir ödeme sistemi kurmadan önce geliştirme ortamınızın güncel olduğundan emin olmalısınız. Laravel 11 veya üzeri bir sürüm kullanıyor olmanız, modern güvenlik paketlerinden ve güncel PHP 8.3/8.4 özelliklerinden yararlanmanızı sağlar.
- PHP 8.3+ sürümü.
- Composer paket yöneticisi.
- SSL/TLS sertifikası (Yerel geliştirme için Valet veya Sail kullanıyorsanız HTTPS yapılandırması).
- Ödeme sağlayıcısı (Iyzico, Stripe vb.) tarafından sağlanan Sandbox API anahtarları.
Öncelikle, ödeme sağlayıcınızın resmi SDK'sını projenize dahil edin. Örneğin, Iyzico kullanıyorsanız terminal üzerinden şu komutu çalıştırın:
composer require iyzico/iyzipay-php
Ödeme Servis Yapılandırması ve Güvenlik
Ödeme işlemlerini doğrudan Controller içerisinde yönetmek yerine, "Service Pattern" (Servis Deseni) kullanarak iş mantığını ayırmanız gerekir. Bu, kodun test edilebilirliğini artırır ve güvenlik açıklarını azaltır. API anahtarlarınızı asla kod içerisinde sabit olarak yazmayın; bunları .env dosyasında tutun.
.env dosyanıza şu satırları ekleyerek başlayın:
PAYMENT_API_KEY=sandbox_key_12345
PAYMENT_SECRET_KEY=sandbox_secret_67890
PAYMENT_BASE_URL=https://sandbox-api.iyzipay.com
Ardından, bu ayarları okuyacak bir servis sınıfı oluşturun. Bu sınıf, ödeme sağlayıcısı ile olan tüm iletişimi kapsülleyecektir.
namespace App\Services;
class PaymentService
{
protected $apiKey;
protected $secretKey;
public function __construct()
{
$this->apiKey = config('services.payment.key');
$this->secretKey = config('services.payment.secret');
}
public function createPayment(array $data)
{
// Ödeme oluşturma mantığı burada yer alacak
}
}
Adım Adım Ödeme İsteği Oluşturma
Ödeme isteği oluştururken, kullanıcının gönderdiği verileri mutlaka FormRequest sınıfı ile valide etmelisiniz. Asla ham $request->all() verisini kullanmayın. SQL injection ve XSS saldırılarına karşı Laravel'in yerleşik doğrulama kurallarını kullanmak zorunludur.
Aşağıdaki örnekte, ödeme verilerini doğrulamak için kullanılan bir FormRequest yapısını görebilirsiniz:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class PaymentRequest extends FormRequest
{
public function rules(): array
{
return [
'price' => 'required|numeric|min:1',
'card_number' => 'required|digits:16',
'expire_month' => 'required|digits:2',
'expire_year' => 'required|digits:4',
'cvc' => 'required|digits:3',
];
}
}
Kritik Güvenlik Uyarısı: Kredi kartı bilgileri (PAN, CVC) asla kendi veritabanınızda saklanmamalıdır. PCI-DSS uyumluluğu için bu verileri doğrudan ödeme sağlayıcısının güvenli sunucularına iletmeli veya "Tokenization" (Tokenlaştırma) yöntemini kullanmalısınız.
Ödeme Sonuçlarının İşlenmesi ve Callback Yönetimi
Ödeme tamamlandıktan sonra, ödeme sağlayıcısı uygulamanıza bir yanıt (callback/webhook) gönderir. Bu yanıtın doğruluğunu teyit etmek için "Hash Doğrulama" yapmanız şarttır. Sağlayıcıdan gelen verinin değiştirilmediğinden emin olmak için gönderilen imza (signature) ile kendi hesapladığınız imzayı karşılaştırın.
public function handleCallback(Request $request)
{
$signature = $request->header('x-iyzi-signature');
$payload = $request->getContent();
if ($this->verifySignature($payload, $signature)) {
// İşlemi veritabanına kaydet ve siparişi onayla
return response()->json(['status' => 'success']);
}
return response()->json(['status' => 'error'], 403);
}
Ödeme Yöntemlerinin Karşılaştırılması
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| API Entegrasyonu | Tam kontrol, özelleştirilebilir arayüz | PCI-DSS sorumluluğu |
| Hosted Checkout (Yönlendirme) | Güvenlik sorumluluğu sağlayıcıda | Kullanıcı deneyimi kesintisi |
| Tokenization | Yüksek güvenlik, tekrar eden ödeme | Ekstra API karmaşıklığı |
Hata Yönetimi ve Loglama
Ödeme sistemlerinde hata yönetimi, müşteri güveni için hayati önem taşır. API'den dönen hataları kullanıcıya teknik detay vermeden, anlaşılır mesajlar olarak iletin. Ancak, sistem loglarında tüm teknik detayları (Error Code, Request ID) mutlaka tutun.
try {
$result = $this->paymentService->createPayment($validatedData);
} catch (\Exception $e) {
Log::error('Ödeme hatası: ' . $e->getMessage(), ['user_id' => auth()->id()]);
return back()->withErrors(['payment' => 'Ödeme sırasında bir hata oluştu, lütfen tekrar deneyin.']);
}
Sıkça Sorulan Sorular
1. Kredi kartı bilgilerini veritabanında saklamalı mıyım?
Kesinlikle hayır. PCI-DSS standartlarına göre kredi kartı verilerini (özellikle CVC kodunu) saklamak yasaktır ve ciddi yasal yaptırımları vardır. Tokenization yöntemini tercih etmelisiniz.
2. Webhook nedir ve neden gereklidir?
Webhook, ödeme sağlayıcısının işlemin sonucunu (başarılı/başarısız) sunucunuza asenkron olarak bildirmesidir. Kullanıcı tarayıcıyı kapatsa bile işlemin kayıt altına alınmasını sağlar.
3. Ödeme sırasında sunucu çökerse ne olur?
Bu durumu yönetmek için "Transaction" (İşlem) yapısını kullanmalı ve ödeme başarılı olduktan sonra veritabanı işlemlerini gerçekleştirmelisiniz. Ayrıca, ödeme sağlayıcısı üzerinden sorgulama (inquiry) yaparak işlem durumunu her zaman kontrol edebilirsiniz.
4. Laravel'de ödeme güvenliğini nasıl artırırım?
HTTPS kullanımı, API anahtarlarının gizli tutulması, her isteğin doğrulanması ve ödeme sağlayıcısının sunduğu IP beyaz listesi (whitelisting) özelliklerini kullanarak güvenliği maksimuma çıkarabilirsiniz.
5. Sandbox ortamından canlı ortama nasıl geçerim?
Sadece .env dosyasındaki API anahtarlarını ve API base URL'sini canlı (production) bilgilerle değiştirmeniz yeterlidir. Ancak, canlıya geçmeden önce mutlaka test ortamında tüm senaryoları (başarılı, yetersiz bakiye, kart reddi) test etmelisiniz.
Sorumluluk Reddi: Bu rehber genel yazılım eğitimi amaçlıdır. Finansal sistemler, ödeme kuruluşlarının güncel regülasyonlarına (BDDK, PCI-DSS) tabidir. Uygulamanızı canlıya almadan önce ilgili ödeme kuruluşunun teknik dokümantasyonunu ve hukuki gerekliliklerini mutlaka inceleyin.
Ödeme Sistemlerinde İleri Seviye Performans Optimizasyonu
Ödeme süreçleri, veritabanı yazma işlemleri ve dış servis istekleri nedeniyle uygulamanızın en çok kaynak tüketen kısımlarından biridir. Yüksek trafikli bir e-ticaret platformunda, her ödeme isteğinin senkron olarak işlenmesi, sunucu yanıt sürelerini (latency) artırır ve kullanıcı deneyimini olumsuz etkiler. Bu durumu yönetmek için Laravel'in kuyruk (queue) sistemini etkin bir şekilde kullanmalısınız.
Ödeme İşlemlerinde Kuyruk (Queue) Kullanımı
Ödeme onaylandıktan sonra fatura oluşturma, stok güncelleme veya e-posta gönderme gibi işlemleri ana işlem akışından ayırarak arka plana atmak, sistemin tepki süresini milisaniyelere indirir. Aşağıdaki örnekte, ödeme sonrası tetiklenen bir işin (job) nasıl yapılandırılacağı gösterilmiştir:
// app/Jobs/ProcessPaymentSuccess.php
public function handle()
{
// Fatura oluşturma servisini çağır
$invoice = InvoiceService::generate($this->paymentData);
// Stok güncelleme
Inventory::decrement($this->orderItems);
// Müşteriye bildirim gönder
Notification::send($this->user, new PaymentConfirmed($invoice));
}
Bu yapıyı Controller içerisinde şu şekilde tetikleyebilirsiniz:
// PaymentController.php
public function handleCallback(Request $request)
{
if ($request->status === 'success') {
ProcessPaymentSuccess::dispatch($request->all())->onQueue('payments');
return response()->json(['message' => 'İşlem kuyruğa alındı.'], 202);
}
}
Ödeme Entegrasyonlarında Hata Ayıklama ve İzlenebilirlik
Finansal sistemlerde "sessiz hata" (silent failure) en büyük risktir. Bir ödeme isteği başarısız olduğunda, hatanın nedenini (network timeout, geçersiz kart, yetersiz bakiye) tam olarak bilmek gerekir. Laravel'in Log kanallarını kullanarak, ödeme sürecindeki her adımı izole edilmiş bir log dosyasında tutmak, kriz anlarında hayat kurtarıcıdır.
Özel Log Kanalları ile Takip
config/logging.php dosyanızda ödemeler için özel bir kanal tanımlayarak, finansal loglarınızı uygulama loglarından ayırabilirsiniz:
'channels' => [
'payments' => [
'driver' => 'single',
'path' => storage_path('logs/payments.log'),
'level' => 'debug',
],
],
Kod içerisinde kullanımı ise oldukça basittir:
use Illuminate\Support\Facades\Log;
try {
$response = $paymentGateway->charge($amount);
} catch (\Exception $e) {
Log::channel('payments')->error('Ödeme hatası:', [
'order_id' => $order->id,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
throw $e;
}
İpucu: Ödeme loglarını asla açık metin (plain text) olarak saklamayın. Eğer log içerisinde kartın ilk 6 ve son 4 hanesi gibi hassas veriler bulunuyorsa, Laravel'in masking özelliklerini kullanarak bu verileri maskelediğinizden emin olun.
Test Senaryoları ve Mocking
Canlıya geçmeden önce, ödeme servisinizin farklı senaryolara nasıl tepki verdiğini test etmek için Mockery veya Laravel'in yerleşik Http::fake() özelliğini kullanın. Bu, gerçek bir finansal işlem yapmadan tüm hata kodlarını (3D Secure hatası, banka reddi vb.) simüle etmenizi sağlar.
public function test_payment_failure_handling()
{
Http::fake([
'api.odeme-servisi.com/*' => Http::response(['status' => 'failed', 'code' => 'ERR_001'], 400),
]);
$response = $this->post('/odeme/yap');
$response->assertStatus(400);
}
Sonuç
Laravel ile güvenli bir ödeme sistemi entegrasyonu, mimari disiplin ve güvenlik bilinci gerektirir. Servis desenini kullanarak kodunuzu temiz tutmak, verileri asla ham haliyle saklamamak ve webhook mekanizmalarını doğru kurgulamak, uygulamanızın finansal omurgasını oluşturur. Bir sonraki adım olarak, "Tekrarlayan Ödeme" (Subscription) modellerini inceleyerek abonelik tabanlı sistemlerin nasıl yönetileceğine dair pratikler yapabilirsiniz.


Yorumlar (0)
Yorum Yaz