
PHP Form İşleme: Doğrulama, CSRF ve Güvenli Kayıt
Form işleme, kullanıcıdan veri alan her uygulamanın temel akışı. Akış üç adımdan oluşur: veriyi okumak, doğrulamak ve kalıcı hale getirmek. Bu adımların herhangi birinde atlanan kontrol, doğrudan güvenlik açığına dönüşür.
Akışın tamamı tek bir varsayım üzerine kurulur: tarayıcıdan gelen hiçbir değer güvenilir değildir. Alan adı, alan sayısı, alan tipi ve uzunluk dahil her şey istek gönderen tarafça değiştirilebilir. Sunucu tarafı doğrulama bu yüzden isteğe bağlı bir iyileştirme değil, akışın zorunlu parçasıdır.
HTML tarafı ve yöntem seçimi
Veriyi değiştiren işlemler POST ile gönderilir. GET yalnızca okuma amaçlı isteklerde, örneğin arama ve filtrelemede kullanılır; çünkü GET istekleri tarayıcı tarafından önbelleğe alınabilir ve adres olarak paylaşılabilir:
<form method="post" action="/kayit.php">
<input type="text" name="ad" required>
<input type="email" name="eposta" required>
<button type="submit">Gönder</button>
</form>HTML tarafındaki required ve type bildirimleri kullanım kolaylığı sağlar, güvenlik sağlamaz. Tarayıcı kontrolleri kolayca devre dışı bırakılabildiği için sunucu tarafında aynı kontrollerin tekrarlanması zorunludur.
Veriyi okumak ve doğrulamak
Doğrulama, verinin beklenen biçimde olup olmadığını kontrol eder. Hatalar tek tek toplanır ve tamamı kullanıcıya birlikte gösterilir; ilk hatada durmak kötü bir deneyim üretir:
$hatalar = [];
$ad = trim($_POST['ad'] ?? '');
$eposta = trim($_POST['eposta'] ?? '');
if (mb_strlen($ad) < 2) {
$hatalar['ad'] = 'Ad en az iki karakter olmalı.';
}
if (!filter_var($eposta, FILTER_VALIDATE_EMAIL)) {
$hatalar['eposta'] = 'Geçerli bir eposta adresi girin.';
}Doğrulama ile temizleme birbirinden ayrı işlerdir. Doğrulama veriyi reddeder ya da kabul eder; temizleme ise veriyi değiştirir. İkisi karıştırıldığında kullanıcının girdiği değer sessizce başkalaşır.
Hataları gösterirken kaçış
Form hatalı doldurulduğunda önceki değerlerin ekrana geri basılması gerekir. Bu noktada kaçış yapılmazsa siteler arası betik çalıştırma açığı oluşur. Ekrana basılan her kullanıcı verisi htmlspecialchars ile kaçırılmalıdır:
<input type="text" name="ad"
value="<?= htmlspecialchars($ad, ENT_QUOTES, 'UTF-8') ?>">
<?php if (isset($hatalar['ad'])): ?>
<p class="hata"><?= htmlspecialchars($hatalar['ad'], ENT_QUOTES, 'UTF-8') ?></p>
<?php endif; ?>CSRF koruması
Siteler arası istek sahteciliği, kullanıcının oturumunu kullanarak farkında olmadan işlem yaptırmaya dayanır. Korunma yöntemi, forma oturumda saklanan rastgele bir belirteç eklemek ve gelen isteği bu belirtece göre doğrulamaktır:
// form üretilirken
if (empty($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(random_bytes(32));
}
// form içinde gizli alan olarak gönderilir
// işleme tarafında
if (!hash_equals($_SESSION['csrf'], $_POST['csrf'] ?? '')) {
http_response_code(419);
exit;
}Karşılaştırmada hash_equals kullanılır. Normal eşitlik karşılaştırması, eşleşmeyen ilk karakterde sonlandığı için zamanlama üzerinden bilgi sızdırabilir.
Veritabanına yazmak
Doğrulanan veri hazır sorgu ile yazılır. Değerlerin sorgu metnine birleştirilmesi SQL injection açığı üretir; konunun ayrıntısı PDO ile güvenli sorgu yazımı yazısında ele alınıyor:
$stmt = $db->prepare(
'INSERT INTO kayitlar (ad, eposta, olusturuldu) VALUES (?, ?, NOW())'
);
$stmt->execute([$ad, $eposta]);Gönderim sonrası yönlendirme
Kayıt başarılı olduğunda doğrudan çıktı üretmek yerine yönlendirme yapılır. Aksi halde kullanıcı sayfayı yenilediğinde form tekrar gönderilir ve aynı kayıt ikinci kez oluşur:
header('Location: /tesekkurler.php', true, 303);
exit;Otomatik gönderimlere karşı sınırlama
Açık bir form, kısa sürede çok sayıda isteği tetikleyen otomatik araçların hedefi olur. Gizli alan tuzağı basit ve etkili bir ilk savunmadır: forma kullanıcıya görünmeyen bir alan eklenir, doldurulmuş olarak gelirse istek reddedilir.
// tuzak alan doldurulmuşsa istek otomatiktir
if (($_POST['website'] ?? '') !== '') {
http_response_code(400);
exit;
}
// aynı oturumdan art arda gönderimi sınırla
$son = $_SESSION['son_gonderim'] ?? 0;
if (time() - $son < 10) {
$hatalar['genel'] = 'Lütfen biraz bekleyin.';
}Daha yoğun trafikte adres tabanlı sayaçlar ve dış doğrulama servisleri devreye alınır. Ancak bu önlemlerin hiçbiri sunucu tarafı doğrulamanın yerini tutmaz.
Doğrulama kurallarını tek yerde toplamak
Doğrulama kodu form işleme betiğine dağıldığında, aynı kural birden fazla yerde farklı biçimde yazılmaya başlar. Kuralların tek bir yapıda tanımlanması hem tekrarı önler hem de yeni alan eklemeyi kolaylaştırır:
$kurallar = [
'ad' => fn(string $v): bool => mb_strlen($v) >= 2,
'eposta' => fn(string $v): bool => (bool) filter_var($v, FILTER_VALIDATE_EMAIL),
'telefon' => fn(string $v): bool => preg_match('/^[0-9]{10}$/', $v) === 1,
];
$hatalar = [];
foreach ($kurallar as $alan => $kural) {
$deger = trim($_POST[$alan] ?? '');
if (!$kural($deger)) {
$hatalar[$alan] = 'Geçersiz değer';
}
}Dosya alanı içeren formlarda form etiketine enctype değeri eklenmelidir. Bu değer eksik olduğunda dosya alanı sunucuya boş gelir ve hatanın nedeni ilk bakışta görünmez.
Kontrol listesi
- Veriyi değiştiren istekler POST ile gönderilir.
- Tarayıcı doğrulaması sunucu doğrulamasının yerini almaz.
- Ekrana basılan her kullanıcı verisi kaçırılır.
- Her formda CSRF belirteci bulunur ve hash_equals ile karşılaştırılır.
- Veritabanı yazma işlemleri hazır sorgu ile yapılır.
- Başarılı gönderim sonrasında yönlendirme yapılır.
PHP eğitim serisi
Bu yazı, temel sözdiziminden üretim ortamına kadar ilerleyen 25 bölümlük serinin bir parçası. Bölümler sırayla okunacak biçimde hazırlandı, ancak her biri tek başına da kullanılabilir.
Temeller
- Kurulum ve temel sözdizimi
- Döngüler ve akış kontrolü
- Diziler
- Fonksiyonlar
- String fonksiyonları
- Süper globaller
- Form işleme (bu yazı)
- Dosya işlemleri
Dilin ayrıntıları
Nesne yönelimli PHP
- Sınıf ve nesne
- Kalıtım, arayüz ve trait
- Statik üyeler, sabitler ve enum
- Namespace, Composer ve autoload
Veri ve güvenlik
- PDO ile veritabanı işlemleri
- Oturum yönetimi ve kimlik doğrulama
- Güvenli çıktı ve XSS
- JSON ile veri değişimi
Dış dünya ve üretim
Yorumlar
İlk yorumu sen yap.
İlgili Yazılar

PHP Uygulamasını Üretime Almak: Yapılandırma ve Güvenlik
Geliştirme makinesinde çalışan kod ile üretimde güvenle çalışan kod arasındaki fark yapılandırmadır. Ayarlar, izinler, dağıtım akışı ve son kontroller.

PHP ile REST API Yazmak: Yönlendirme ve HTTP Durum Kodları
Bir API'nin kalitesi çoğunlukla ayrıntılarda belli olur: doğru durum kodu, tutarlı hata biçimi ve öngörülebilir adresler. Saf PHP ile uçtan uca kurulum.

PHPUnit ile Birim Test Yazmak: Kurulum, Sahte Nesneler ve Kapsam
Testin amacı hata bulmak değil, değişikliği güvenle yapabilmektir. Kurulum, ilk test, sahte nesneler ve test edilebilir kodun özellikleri.