Küçük bir PHP uygulamasında profil resmi kabul ederken yalnızca dosya uzantısına güvenmek yeterli değildir. İstemci tarafındaki `accept` özelliği kullanıcıya kolaylık sağlar; güvenlik kontrolü sunucuda yapılmalıdır.
Formda `multipart/form-data` kullanın:
<form method="post" enctype="multipart/form-data">
<label for="avatar">Profil resmi</label>
<input id="avatar" name="avatar" type="file" accept="image/jpeg,image/png,image/webp" required>
<button type="submit">Yükle</button>
</form>
PHP tarafında boyutu, yükleme hatasını ve gerçek MIME türünü kontrol edin. Dosya adını kullanıcıdan gelen değerle oluşturmamak, çalıştırılabilir dosyaların yüklenmesini önlemek ve rastgele bir ad kullanmak önemlidir.
Sunucu tarafı doğrulama
Aşağıdaki örnek JPEG, PNG ve WebP dosyalarını kabul eder; dosyayı doğrudan web köküne değil, uygulamanın erişim dışı yükleme dizinine taşır:
<?php
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit('Yalnızca POST kabul edilir.');
}
if (!isset($_FILES['avatar']) || $_FILES['avatar']['error'] !== UPLOAD_ERR_OK) {
exit('Dosya yüklenemedi.');
}
$file = $_FILES['avatar'];
$maxBytes = 2 * 1024 * 1024;
if ($file['size'] <= 0 || $file['size'] > $maxBytes) {
exit('Dosya 2 MB sınırını aşmamalıdır.');
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);
$allowed = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/webp' => 'webp',
];
if (!isset($allowed[$mime])) {
exit('Desteklenmeyen dosya türü.');
}
if (@getimagesize($file['tmp_name']) === false) {
exit('Geçerli bir görsel yükleyin.');
}
$uploadDir = __DIR__ . '/../private-uploads/avatars';
if (!is_dir($uploadDir) && !mkdir($uploadDir, 0750, true)) {
exit('Yükleme dizini oluşturulamadı.');
}
$filename = bin2hex(random_bytes(16)) . '.' . $allowed[$mime];
$destination = $uploadDir . DIRECTORY_SEPARATOR . $filename;
if (!move_uploaded_file($file['tmp_name'], $destination)) {
exit('Dosya kaydedilemedi.');
}
echo 'Profil resmi yüklendi.';
`finfo` ve `getimagesize()` birlikte kullanıldığında yalnızca uzantıya dayalı yanıltma ihtimali azalır. Yine de bu örnekte oturumdaki kullanıcıyla dosyanın ilişkilendirilmesi, eski dosyanın silinmesi ve veritabanına yalnızca rastgele dosya adının yazılması ayrıca uygulanmalıdır.
Test ve dağıtım kontrolü
Şu durumları tek tek deneyin:
- 2 MB’tan büyük bir görsel gönderin; istek reddedilmelidir.
- Uzantısı `.jpg` olan metin dosyası gönderin; MIME kontrolü geçmemelidir.
- Geçerli JPEG, PNG ve WebP dosyalarını yükleyin.
- Dosya adında boşluk, Türkçe karakter veya `../` bulunan bir ad kullanın; kaydedilen ad yine rastgele olmalıdır.
- Yükleme dizinindeki dosyanın tarayıcıdan doğrudan çalıştırılamadığını doğrulayın.
