Mehmet

WFN Üye
Konular
1,851
Mesajlar
1,852
Çözüm
0
Ticaret Puanı
0
Üyelik
1 Ay 6 Gün
Konum
YurtDışı
Web Sitesi
Var
Alanı
Google Adsense
1/1
Konu sahibi
Dosya adı çakışmasını önlemenin en güvenilir yolu, kullanıcının gönderdiği adı depolama adı olarak kullanmamaktır. Yüklenen dosyayı sunucu tarafında rastgele veya UUID tabanlı benzersiz bir adla kaydedin; özgün adı ise veritabanında gösterim amacıyla ayrı tutun. Kaydetme işlemi de mevcut dosyanın üzerine yazmayı reddeden bir yöntemle yapılmalıdır.

Çakışma nasıl oluşur?​


İki kullanıcı logo.png yüklediğinde uygulama dosyayı doğrudan /uploads/logo.png konumuna yazarsa ikinci yükleme birincinin üzerine yazabilir. Yalnızca “dosya mevcutsa sonuna sayı ekle” yaklaşımı da eşzamanlı isteklerde güvenilir değildir: iki istek aynı boş adı aynı anda kontrol edip aynı sonucu seçebilir.

Bu nedenle üç bilgiyi ayırın:

  • Özgün ad: Kullanıcıya gösterilecek logo.png gibi ad.
  • Depolama adı: Sunucuda kullanılacak benzersiz ad, örneğin a4f...c91.bin.
  • Kayıt kimliği: Dosyanın kullanıcıya, içeriğe veya ilgili kayda ait bağlantısı.

Uzantıyı yalnızca kullanıcı adından kopyalamayın. İzin verilen türleri uygulamanızın gereksinimine göre sınırlayın ve dosyanın gerçek içerik türünü sunucu tarafında kontrol edin. Özgün adı doğrudan yolun parçası yapmak; yol geçişi, özel karakter ve aynı ada sahip dosya sorunlarını birlikte doğurabilir.

Uygulanabilir örnek: PHP ile üzerine yazmadan kaydetme​


Aşağıdaki işlev yalnızca çakışmasız depolama adımını gösterir; tam bir HTTP yükleme uç noktası değildir. Çağrıdan önce oturum/yetki ve gerekiyorsa CSRF, UPLOAD_ERR_OK, skaler alan yapısı, boyut ve izin verilen içerik türü uygulamada doğrulanmış olmalıdır. Hedef dizini önceden, web kökü dışında ve yalnız uygulamanın yazabildiği özel bir alan olarak hazırlayın. İşlev, PHP’nin yüklediği geçici dosyayı benzersiz bir ada kopyalar. Hedef dosya, fopen(..., 'x') sayesinde zaten varsa açılmaz; böylece mevcut dosyanın üzerine yazılmaz. Özgün dosya adı depolama yolunda kullanılmaz.

PHP:
<?php
function saveUploadedWithoutOverwrite(string $tmp, string $directory): string
{
    if (!is_uploaded_file($tmp) || !is_dir($directory)
        || !is_writable($directory)) {
        throw new RuntimeException('Kaynak veya hedef uygun değil');
    }
    $source = fopen($tmp, 'rb');
    if ($source === false) {
        throw new RuntimeException('Geçici dosya açılamadı');
    }
    try {
        $stat = fstat($source);
        if ($stat === false) {
            throw new RuntimeException('Dosya boyutu okunamadı');
        }
        for ($attempt = 0; $attempt < 5; $attempt++) {
            $name = bin2hex(random_bytes(16)) . '.bin';
            $path = $directory . DIRECTORY_SEPARATOR . $name;
            $target = @fopen($path, 'x+b');
            if ($target === false) {
                continue;
            }
            $copied = stream_copy_to_stream($source, $target);
            $ok = $copied !== false && $copied === $stat['size']
                && fflush($target);
            $closed = fclose($target);
            if (!$ok || !$closed) {
                // Yalnız bu denemede oluşturduğumuz yarım dosya.
                unlink($path);
                throw new RuntimeException('Dosyanın tamamı yazılamadı');
            }
            return $name;
        }
        throw new RuntimeException('Hedef dosya ayrıcalıklı oluşturulamadı');
    } finally {
        fclose($source);
    }
}

Doğrulamalar tamamlandıktan sonra işlevi geçerli geçici yükleme yolu ve hazırladığınız özel dizinle çağırın. Dönen değer depolama adıdır; veritabanındaki dosya kaydına bunu ve doğrulanmış içerik türünü yazın. Aynı özgün adla iki yükleme farklı depolama adları üretmelidir. İşlev mevcut bir hedefi açmaz; rastgele çakışma durumunda başka aday dener. Tekrarlanan açma başarısızlığı izin, kota veya disk problemi de olabilir; bunu her zaman rastgele çakışma sanmayın.

Örnekte .bin uzantısı kullanılması dosyayı güvenli ilan etmez. İndirme, yetki kontrolü yapan uç noktadan ve doğrulanmış içerik türüyle sunulmalı; özgün ad çıktı bağlamına uygun kaçışlanmalıdır. Kopyalanan bayt sayısı ve tampon yazımı kontrol edilir; hata durumunda yalnız o denemede oluşturulan yarım hedef kaldırılır. Üretimde beklenmeyen süreç kesintileri için dosya/veritabanı tutarlılığını ayrıca izleyin.

Hangi yöntemi ne zaman seçmeli?​


Dosya sisteminde güvenli bir depolama adı üretmek tek başına yeterli değildir. Dosyanın veritabanı kaydı da tutarlı olmalı ve aynı iş kaydı için aynı dosyanın iki kez oluşturulmaması gerekiyorsa ilgili iş anahtarına benzersizlik kuralı eklenmelidir.

YöntemUygun kullanımDikkat edilmesi gereken
Rastgele adGenel dosya yüklemeleriÖzgün ad ayrıca saklanmalı
UUIDKayıt kimliğiyle ilişkilendirilen dosyalarUUID üretimi sunucu tarafında yapılmalı
İsim sonuna sayı eklemeYalnızca kullanıcı arayüzünde görünen adlarEşzamanlı kaydetmede tek başına güvenli değil

Sık yapılan hatalar​


  • Dosya adını basename() ile temizleyip yine de doğrudan kaydetmek: Bu, çakışmayı çözmez; yalnızca yolu kısmen düzenler.
  • Önce file_exists() kontrol edip sonra yazmak: Kontrol ile yazma arasında başka bir istek dosyayı oluşturabilir. Hedefi özel açma veya veritabanı benzersizlik kuralı kullanın.
  • Özgün adı veritabanında benzersiz sanmak: İki farklı kullanıcı aynı adı seçebilir; özgün ad gösterim bilgisidir.
  • Başarısız kopyadan sonra yarım dosya bırakmak: Hata durumunda hedefi silin ve veritabanı kaydını ancak dosya başarıyla yazıldıktan sonra oluşturun.
  • Kullanıcıya gösterilen adı URL yolu yapmak: Depolama adını, indirme yetkilendirmesinden ve gösterim adından ayrı tutun.
[/LIST]

Kaynaklar​



Sık sorulan sorular​


Aynı dosya tekrar yüklenirse içeriği karşılaştırıp tek kopya mı tutulmalı?​


Bu, çakışma önleme değil, tekilleştirme kararıdır. İçeriğin özetini sunucu tarafında hesaplayıp aynı özet için tek fiziksel dosya tutabilirsiniz; ancak silme ve erişim kayıtlarının birden fazla kaydı destekleyecek şekilde tasarlanması gerekir.

Özgün dosya adını kullanıcıya göstermek güvenli mi?​


Genellikle gösterilebilir; fakat HTML çıktısında uygun şekilde kaçışlayın ve bu adı dosya yolu, komut veya sorgu parçası olarak kullanmayın. Depolama adı her durumda ayrı kalmalıdır.
 

Sende şimdi bize katılmak ister misin?

Kayıt ol

Bize katılım kolay ve ücretsizdir!

Konuyu görüntüleyenler

Bu konuyu şu anda görüntüleyen üye bulunmuyor.