Müzakirə

PHP Upload Sistemi Yapımı

Başladan Celal · 09 iyl 2026 15:10 · 34 Baxış · 0 Cavablar
Mövzunu Açan #0
Dosya yükleme sistemleri, web uygulamalarının olmazsa olmazı diyebiliriz; profil resimlerinden belge paylaşımlarına, her yerde karşımıza çıkıyorlar. Ama işin aslı, bu basit görünen mekanizma, güvenlik açısından en çok dikkat etmemiz gereken yerlerden biri... Genelde "bir
CODE
1move_uploaded_file()
ile hallederiz" diye düşünülür, ancak o kadar basit değil, inanın bana.

Öncelikle, işin HTML kısmını doğru kurmakla başlayalım. Bir dosya yükleme formu oluştururken, sıradan formlardan biraz farklı bir
CODE
1enctype
kullanmamız gerekiyor. Eğer bunu unutursanız, PHP tarafında
CODE
1$_FILES
süperglobali bomboş kalır, dosya falan göremezsiniz. İşte temel bir HTML formu:
CODE
123456

    Yüklenecek Dosyayı Seçin:
    
    


Buradaki
CODE
1name="fileToUpload"
kısmı çok önemli, çünkü PHP tarafında bu isimle dosyaya erişeceğiz. Bir de
CODE
1method="post"
ve
CODE
1enctype="multipart/form-data"
olmazsa olmazlar arasında, aksi halde tarayıcı dosyayı server'a düzgün bir şekilde göndermez. Bu detaylar atlandığında çok vakit kaybedilebilir, tecrübeyle sabit...

Şimdi gelelim PHP tarafına, yani
CODE
1upload.php
dosyamıza. Dosya yüklendiğinde, tüm bilgiler
CODE
1$_FILES
süperglobal dizisinde toplanır. Bu dizi, formda verdiğiniz
CODE
1name
attribute'u ile erişilebilir. Örneğin, yukarıdaki form için
CODE
1$_FILES['fileToUpload']
şeklinde erişiriz. İçinde neler mi var?
  • CODE
    1name
    : Dosyanın orijinal adı. Kullanıcının bilgisayarındaki adı neyse o.
  • CODE
    1type
    : Dosyanın MIME tipi (örn:
    CODE
    1image/jpeg
    ,
    CODE
    1application/pdf
    ). Bu, güvenlik için çok kritik bir bilgi.
  • CODE
    1tmp_name
    : Sunucuya geçici olarak kaydedilen dosyanın yolu ve adı. Asıl işimiz bununla.
  • CODE
    1error
    : Yükleme sırasında oluşan hata kodu. Eğer
    CODE
    10
    ise her şey yolunda demektir.
  • CODE
    1size
    : Dosyanın boyutu (bayt cinsinden).
Bu bilgilerle dosya üzerinde birçok kontrol yapabiliriz, ki yapmalıyız da... Güvenlik burada başlıyor.

Dosya yükleme sistemlerinin en hassas noktası, güvenlik. Bir kere, kullanıcıların ne yükleyebileceğini kısıtlamamız şart. Sadece resim bekliyorsanız, birisi gelip .exe veya .php dosyası yüklemeye çalışmamalı. İşte burada MIME tipi ve dosya uzantısı kontrolü devreye giriyor. Ben genellikle ikisini birlikte kontrol etmeyi tercih ederim, çünkü MIME tipi bazen kolayca taklit edilebilir. Örneğin:
CODE
12


Bu kod bloğu, temel kontrolleri içeriyor.
CODE
1getimagesize()
fonksiyonu, özellikle resim dosyaları için harika bir güvenlik katmanı sağlar; dosyanın gerçekten bir resim olup olmadığını, sadece uzantısına bakarak değil, içeriğine bakarak anlarız. Eğer geçersiz bir resim dosyasıysa,
CODE
1false
döner.

Peki ya dosya adları? Kullanıcının yüklediği dosyanın adını olduğu gibi kaydetmek, ciddi riskler barındırır. Diyelim ki bir kullanıcı
CODE
1../../../../../etc/passwd
gibi bir isimle dosya yüklemeye çalıştı veya
CODE
1index.php
adında kötü niyetli bir script yükledi... İşte bu yüzden, yüklenen her dosyaya benzersiz, rastgele bir isim vermek en sağlıklısıdır. Şöyle bir şey düşünebiliriz:
CODE
123
$newFileName = uniqid() . "." . $imageFileType; // örn: 5f7b4c9a3d2e1.jpg
$target_file = $target_dir . $newFileName;

Böylece hem çakışmaların önüne geçeriz hem de potansiyel yol geçişi (path traversal) saldırılarını engelleriz. Orijinal dosya adını kaydetmek isterseniz, onu veritabanına ayrı bir sütun olarak saklayabilirsiniz, ama asla sunucuda dosya adı olarak kullanmayın.

Bir de hedef dizinin yazma izinleri konusu var, yani
CODE
1uploads/
klasörümüzün. PHP'nin bu klasöre dosya yazabilmesi için gerekli izinlere sahip olması gerekir. Genellikle
CODE
1chmod 755
veya
CODE
1chmod 775
(sunucu yapılandırmasına göre değişebilir) yeterli olur. Eğer izinler yanlışsa,
CODE
1move_uploaded_file()
fonksiyonu her zaman hata verir ve "Permission denied" gibi bir mesajla karşılaşırsınız. Bu durumla çok sık karşılaşılır, özellikle yeni başlayanlar için tam bir baş belasıdır.

CODE
1$_FILES['fileToUpload']['error']
kısmına da değinmek lazım. Bu, yükleme işlemi sırasında PHP'nin otomatik olarak oluşturduğu hata kodlarını içerir.
  • CODE
    1UPLOAD_ERR_OK (0)
    : Dosya başarıyla yüklendi.
  • CODE
    1UPLOAD_ERR_INI_SIZE (1)
    : Yüklenen dosya boyutu,
    CODE
    1php.ini
    'deki
    CODE
    1upload_max_filesize
    değerini aşıyor.
  • CODE
    1UPLOAD_ERR_FORM_SIZE (2)
    : Yüklenen dosya boyutu, HTML formundaki
    CODE
    1MAX_FILE_SIZE
    değerini aşıyor.
  • CODE
    1UPLOAD_ERR_PARTIAL (3)
    : Dosya kısmen yüklendi.
  • CODE
    1UPLOAD_ERR_NO_FILE (4)
    : Hiçbir dosya yüklenmedi.
  • CODE
    1UPLOAD_ERR_NO_TMP_DIR (6)
    : Geçici bir klasör eksik.
  • CODE
    1UPLOAD_ERR_CANT_WRITE (7)
    : Diske yazılamadı.
  • CODE
    1UPLOAD_ERR_EXTENSION (8)
    : Bir PHP uzantısı dosya yüklemesini durdurdu.
Bu hata kodlarını kontrol ederek kullanıcıya daha anlamlı geri bildirimler verebiliriz. Örneğin, "Dosyanız çok büyük, lütfen daha küçük bir dosya yükleyin." demek, "Hata kodu 1" demekten çok daha açıklayıcıdır, değil mi?

Dosyayı sunucuya taşıma işlemi için
CODE
1move_uploaded_file()
fonksiyonunu kullanıyoruz. Bu fonksiyon, PHP'nin güvenlik mekanizmalarıyla birlikte çalıştığı için, doğrudan
CODE
1copy()
veya
CODE
1rename()
kullanmaktan çok daha güvenlidir. Yüklenen dosyanın gerçekten bir HTTP POST yüklemesi olup olmadığını kontrol eder. İlk parametre geçici dosya yolu, ikincisi ise hedef yol ve dosya adıdır.
CODE
123456
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
    echo "Dosya " . htmlspecialchars($newFileName) . " başarıyla yüklendi.";
} else {
    echo "Dosyayı yüklerken bir hata oluştu.";
}

Buradaki
CODE
1htmlspecialchars()
kullanımı da çok ince bir detaydır. Yüklenen dosya adını (veya yeni adını) ekrana bastırırken olası XSS (Cross-Site Scripting) saldırılarına karşı önlem almış oluruz. Küçük bir dokunuş gibi görünse de, güvenlik zincirinin önemli bir halkasıdır.

Peki, yüklenen dosyalarla ilgili bilgileri veritabanına kaydetmeli miyiz? Kesinlikle evet! Dosyanın orijinal adı, yeni adı, boyutu, MIME tipi, yüklenme tarihi ve kim tarafından yüklendiği gibi bilgileri veritabanında tutmak, hem daha düzenli bir yapı sağlar hem de ileride raporlama veya dosya yönetimi açısından işimizi çok kolaylaştırır. Örneğin, bir kullanıcının yüklediği tüm resimleri listelemek istediğinizde, veritabanındaki bilgilere dayanarak bunu çok rahat yapabilirsiniz. Bir örnek tablo yapısı şöyle olabilir:
CODE
1234567891011
CREATE TABLE [icode]uploads[/icode] (
  [icode]id[/icode] INT AUTO_INCREMENT PRIMARY KEY,
  [icode]original_name[/icode] VARCHAR(255) NOT NULL,
  [icode]stored_name[/icode] VARCHAR(255) NOT NULL,
  [icode]file_path[/icode] VARCHAR(255) NOT NULL,
  [icode]file_type[/icode] VARCHAR(100) NOT NULL,
  [icode]file_size[/icode] INT NOT NULL,
  [icode]uploaded_by[/icode] INT,
  [icode]uploaded_at[/icode] DATETIME DEFAULT CURRENT_TIMESTAMP
);

Bu sayede, dosya sisteminde sadece benzersiz isimli dosyalar dururken, tüm meta verileri düzenli bir şekilde yönetmiş oluruz.

Çoklu dosya yükleme konusu da var elbette. Bu durumda HTML formunda
CODE
1input type="file"
etiketine
CODE
1multiple
attribute'unu ekleriz ve
CODE
1name
attribute'unu bir dizi olarak tanımlarız, örneğin
CODE
1name="filesToUpload[]"
. PHP tarafında ise
CODE
1$_FILES['filesToUpload']
dizisi, her bir dosya için ayrı ayrı bilgiler içeren iç içe bir dizi haline gelir. Her dosyayı bir döngü içinde tek tek işlemek gerekir. Bu da biraz daha kod kalabalığı demek ama mantık aynıdır.

Sonuç olarak, PHP ile dosya yükleme sistemi geliştirmek, sadece
CODE
1move_uploaded_file()
fonksiyonunu kullanmaktan çok daha fazlasını gerektirir. Güvenlik kontrolleri, dosya adı yönetimi, veritabanı entegrasyonu ve kullanıcıya doğru geri bildirimler sunmak, sağlam ve güvenilir bir sistemin temel taşlarıdır. Bu adımların her biri atlanmaması gereken kritik öneme sahiptir.

Peki sizler, dosya yükleme sistemleri geliştirirken en çok hangi güvenlik önlemlerine dikkat ediyorsunuz? Ya da başınıza gelen en ilginç dosya yükleme hatası senaryosu neydi? Tecrübelerinizi ve görüşlerinizi merak ediyorum...

Cavab vermək üçün daxil olmalısınız.

0 sitat seçildi