Ders 06 / 20
Yol İşlemleri
Yol parçalarını birleştirme ve çözme, platform kurallarının ayrı sunulması, betiğin kendi konumundan dayanak kurma ve kök dizin dışına çıkışı engelleme.
İçindekiler
Önceki derste bütün dosya adları çıplak yazıldı: olcumler.ndjson, veri/2024-02-07.
Bu adlar çalışma dizinine göre çözülür, dolayısıyla aynı program başka bir dizinden
çağrıldığında dosyayı bulamaz. Ayrıca ayırıcı karakteri elle yazmak, aracı tek bir
platformun yol kurallarına bağlar.
Bu ders yolları veri olarak ele alan yerleşik modülü tanıtır ve iki soruyu yanıtlar: program kendi dosyalarını nereye göre arayacak, dışarıdan gelen bir yol parçası nereye kadar gitmesine izin verilecek?
Birleştirme ve Çözme
node:path modülünün iki temel fonksiyonu vardır ve aralarındaki fark sık karıştırılır.
join, verilen parçaları platformun ayırıcısıyla birbirine ekler ve sonucu
normalleştirir; sonuç göreli verilmişse göreli kalır. resolve ise sağdan sola
yürüyerek mutlak bir yol üretir; hiçbir parça mutlak değilse çalışma dizinini başa
ekler.
// yol.mjs import path from 'node:path'; console.log('join :', path.join('veri', '2024-02-07', 'olcumler.ndjson')); console.log('join + .. :', path.join('veri', '2024-02-07', '..', 'ozet.json')); console.log('sep :', JSON.stringify(path.sep)); console.log(); const yol = 'veri/2024-02-07/olcumler.ndjson'; console.log('dirname :', path.dirname(yol)); console.log('basename :', path.basename(yol)); console.log('uzantisiz :', path.basename(yol, path.extname(yol))); console.log('extname :', path.extname(yol)); console.log('parse :', path.parse(yol));
node yol.mjs
join : veri/2024-02-07/olcumler.ndjson
join + .. : veri/ozet.json
sep : "/"
dirname : veri/2024-02-07
basename : olcumler.ndjson
uzantisiz : olcumler
extname : .ndjson
parse : {
root: '',
dir: 'veri/2024-02-07',
base: 'olcumler.ndjson',
ext: '.ndjson',
name: 'olcumler'
}
İkinci satır normalleştirmeyi gösteriyor: .. parçası bir üst dizine çıkma anlamına
gelir ve sonuçta kaybolur. sep değeri çalıştığınız platforma göre değişir; örnekteki
eğik çizgi bir Unix türevinde alınmıştır.
Bu fonksiyonların hiçbiri dosya sistemine bakmaz. extname bir dosyanın gerçekten JSON
olduğunu söylemez, adının nasıl bittiğini söyler; dirname o dizinin var olduğunu
söylemez. Yol işlemleri saf dizgi işlemleridir — Programlama Temelleri kursundaki
saf fonksiyon tanımına uyarlar ve bu yüzden sınanmaları kolaydır.
Platform Kuralları Ayrı Sunulur
Modül, çalıştığı platformun kurallarını varsayılan olarak uygular, ama iki kural kümesini de ayrı ayrı erişilebilir tutar.
// yol-platform.mjs import path from 'node:path'; console.log('bu platform :', path.join('veri', '2024-02-07', 'ozet.json')); console.log('posix :', path.posix.join('veri', '2024-02-07', 'ozet.json')); console.log('win32 :', path.win32.join('veri', '2024-02-07', 'ozet.json')); console.log(); console.log('win32 kurallariyla "C:\\veri" mutlak mi:', path.win32.isAbsolute('C:\\veri')); console.log('posix kurallariyla "C:\\veri" mutlak mi:', path.posix.isAbsolute('C:\\veri')); console.log('posix kurallariyla "/veri" mutlak mi:', path.posix.isAbsolute('/veri'));
node yol-platform.mjs
bu platform : veri/2024-02-07/ozet.json posix : veri/2024-02-07/ozet.json win32 : veri\2024-02-07\ozet.json win32 kurallariyla "C:\veri" mutlak mi: true posix kurallariyla "C:\veri" mutlak mi: false posix kurallariyla "/veri" mutlak mi: true
İlk satır, örneğin çalıştırıldığı platformun kurallarını yansıtır; bir Windows
makinesinde ters eğik çizgili biçim yazardı. Ayrı kural kümelerinin varlığı, yerel
dosya yollarıyla ilgisi olmayan işler için önemlidir: bir arşiv girdisinin veya bir
HTTP yolunun ayrıştırılması her platformda aynı sonucu vermelidir; bunun için
path.posix doğrudan seçilir.
Adres yolları için ayrıca URL nesnesi vardır ve iki alan karıştırılmamalıdır. Bir
istek yolundaki karakter kaçışları path fonksiyonlarının bilmediği kurallara uyar;
sunucu tarafında yol ayrıştırması adres nesnesiyle yapılır.
Bir Yoldan Başka Bir Yol Türetmek
Ölçüm toplayıcının sık yaptığı iş, bir girdi dosyasının adından çıktı dosyasının adını
üretmektir: olcumler.ndjson okunur, yanına olcumler-ozet.json yazılır. Dizgi
birleştirmesiyle yapıldığında bu iş uzantının kaç karakter olduğu varsayımına dayanır
ve .ndjson ile .json arasında bozulur.
parse bir yolu alanlarına ayırır, format alanlardan yol kurar. İkisi birlikte
kullanıldığında türetme, karakter saymadan yapılır — ancak format çağrısının bir
önceliği vardır:
// yol-turetme.mjs import path from 'node:path'; const kaynak = 'veri/2024-02-07/olcumler.ndjson'; const parcalar = path.parse(kaynak); // base alani varsa ext ve name yok sayilir; turetmek icin base silinir const hedef = path.format({ dir: parcalar.dir, name: `${parcalar.name}-ozet`, ext: '.json' }); const yanlis = path.format({ ...parcalar, name: `${parcalar.name}-ozet`, ext: '.json' }); console.log('kaynak :', kaynak); console.log('hedef :', hedef); console.log('base kalinca:', yanlis); console.log(); console.log('relative (komsu) :', path.relative('veri/2024-02-07', 'veri/2024-02-08/olcumler.ndjson')); console.log('relative (ayni) :', JSON.stringify(path.relative('veri', 'veri'))); console.log('relative (disari) :', path.relative('veri', 'gizli.txt'));
node yol-turetme.mjs
kaynak : veri/2024-02-07/olcumler.ndjson hedef : veri/2024-02-07/olcumler-ozet.json base kalinca: veri/2024-02-07/olcumler.ndjson
relative (komsu) : ../2024-02-08/olcumler.ndjson relative (ayni) : "" relative (disari) : ../gizli.txt
Üçüncü satır tuzağı gösteriyor. format, verilen nesnede base alanı varsa name ve
ext alanlarını yok sayar; parse çıktısı base alanını taşıdığı için doğrudan
yayılan bir nesne hiç değişmemiş yolu geri verir. Türetme yapılırken base ya
verilmez ya da yenisi hesaplanır.
Çıktının ikinci öbeği relative fonksiyonunu tanıtıyor: iki yol arasında, birinciden
ikinciye gitmek için izlenecek göreli adımı verir. Üç davranış ayrı ayrı anlamlıdır.
Komşu bir dizine giden yol bir üst düzeye çıkıp iner. İki yol aynıysa sonuç boş
dizgidir — bir alt öğe değil, yolun kendisi kastedilmiştir. Hedef, tabanın dışında
kalıyorsa sonuç .. ile başlar.
Son davranış, bir sonraki bölümdeki kök denetiminin ikinci yazım biçimidir:
path.relative(kok, tam) sonucu .. ile başlamıyorsa hedef kökün altındadır. Bu
biçim ayırıcı eklemeyi gerektirmez, ancak yol ayrımı büyük–küçük harf duyarsız bir
dosya sisteminde her iki biçim de aynı sınırla karşılaşır: dizgi karşılaştırması,
dosya sisteminin ad eşleme kuralını bilmez.
Betiğin Kendi Konumu
Bir programın kendi yanındaki dosyaları bulması, çalışma dizinine bağlı kalmamalıdır.
ES modüllerinde dayanak import.meta.url değeridir; bu bir dosya adresidir ve dosya
sistemi yoluna çevrilmesi gerekir.
// yol-guvenlik.mjs import path from 'node:path'; import { fileURLToPath } from 'node:url'; // Betiğin kendi konumu: çalışma dizininden bağımsız sabit dayanak const buDosya = fileURLToPath(import.meta.url); const buDizin = path.dirname(buDosya); console.log('betigin dizini (son parca):', path.basename(buDizin)); const kok = path.resolve(buDizin, 'veri'); function guvenliCoz(kullaniciYolu) { const tam = path.resolve(kok, kullaniciYolu); if (tam !== kok && !tam.startsWith(kok + path.sep)) { throw new Error(`kok dizin disi: ${kullaniciYolu}`); } return path.relative(kok, tam); } for (const istek of ['2024-02-07/olcumler.ndjson', './a/../b.json', '../gizli.txt']) { try { console.log(`${istek.padEnd(28)} -> ${guvenliCoz(istek)}`); } catch (hata) { console.log(`${istek.padEnd(28)} -> RED: ${hata.message}`); } }
Aynı betik iki farklı dizinden çağrıldığında aynı sonucu verir:
node yol-guvenlik.mjs
betigin dizini (son parca): lab 2024-02-07/olcumler.ndjson -> 2024-02-07/olcumler.ndjson ./a/../b.json -> b.json ../gizli.txt -> RED: kok dizin disi: ../gizli.txt
İlk satırdaki dizin adı, betiği hangi dizine kaydettiğinize göre değişir; örnekte
lab adlı bir dizinden alınmıştır. Önemli olan, komutu kök dizinden veya başka bir
yerden çağırdığınızda bu değerin değişmemesidir.
Adresten yola çevirme işi elle yapılamaz. Dosya adresinde boşluk %20 ile kodlanır
ve Windows’ta sürücü harfi ek bir kurala uyar; fileURLToPath bu ayrıntıları
üstlenir. Ters yönde, bir yolu adrese çevirmek için aynı modüldeki pathToFileURL
kullanılır.
Kök Dizin Dışına Çıkmayı Engellemek
Yukarıdaki guvenliCoz fonksiyonu, ölçüm toplayıcının ileride karşılaşacağı bir sorunu
şimdiden çözer. Hizmet, istek yolundan gelen bir ad ile dosya açacaksa, o adın
belirlenen kök dizinin altında kaldığı doğrulanmalıdır. Doğrulanmazsa ../ dizisi
içeren bir istek, kökün dışındaki dosyalara erişebilir.
Doğrulamanın üç adımı vardır ve sırası önemlidir:
- Kök dizini mutlak yola çevir.
- Kullanıcı yolunu kökün altına çöz.
resolvebu adımda..parçalarını uygular. - Sonucun kök dizine eşit olduğunu veya kök artı ayırıcı ile başladığını doğrula.
Üçüncü adımdaki ayırıcı ayrıntısı gereksiz görünür ama değildir. Yalnızca
tam.startsWith(kok) denetlenirse, veri kökü için veri-yedek adlı komşu dizin
de denetimi geçer; ayırıcının eklenmesi bu sızıntıyı kapatır.
Bu denetim, dizgi düzeyinde bir denetimdir ve sembolik bağları hesaba katmaz. Kök
dizinin içinde dışarıyı gösteren bir sembolik bağ varsa, çözülen yol kökün altında
görünürken açılan dosya dışarıda olabilir. Linux’a Giriş kursunda tanıtılan sembolik
bağ davranışı burada devreye girer; gerçek yolu almak için dosya sistemine soran
realpath çağrısı kullanılır ve denetim onun sonucu üzerinde yinelenir.
Özet
joinparçaları birleştirip normalleştirir ve göreliliği korur;resolvesağdan sola yürüyerek mutlak yol üretir.- Yol fonksiyonları dosya sistemine bakmaz; adın biçimi hakkında konuşurlar, dosyanın varlığı hakkında değil.
- Modül, iki platformun kurallarını ayrı ayrı sunar; yerel dosya dışındaki yollar için kural kümesi açıkça seçilir.
parseveformatile bir yoldan başkası karakter saymadan türetilir;format, nesnedebasealanı varsanameveextalanlarını yok sayar.- ES modülünde betiğin kendi konumu
import.meta.urladresindenfileURLToPathile elde edilir; bu dayanak çalışma dizininden bağımsızdır. - Dışarıdan gelen yol, mutlak köke çözülüp kök artı ayırıcı önekiyle sınanarak denetlenir; sembolik bağlar için gerçek yol ayrıca sorulur.
Sonraki Adım
Buraya kadar dosyalar bir kerede belleğe alındı. On iki satırlık bir dosyada bu sorunsuzdur; günlerce biriken bir ölçüm dosyasında değildir. Sonraki ders veriyi parça parça taşıyan akış soyutlamasını kurar: okunabilir, yazılabilir ve dönüştürücü akışları, bunları birbirine bağlamanın doğru yolunu ve üreticinin tüketiciden hızlı olduğunda devreye giren geri basıncı ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.