Her seferinde aynı byte'lar: yeniden üretilebilir PDF'ler
Spec: ISO 32000-2, §14.4ISO 32000-2 §14.4Spec: ISO 32000-2, §14.3.3ISO 32000-2 §14.3.3
Bir bakışta
“Bir bakışta” başlıklı bölümAynı girdilerden bir PDF’yi iki kez kurun ve aynı dosyayı beklersiniz. Çoğu PDF kütüphanesi bunu vaat edemez — yeniden kurun ve diff’leyin, byte’lar sürüklenir. NextPDF, hareket eden iki şeyi sabitleyebilir; böylece aynı girdiler her seferinde aynı byte’ları üretir.
Bunun önemi nedir
“Bunun önemi nedir” başlıklı bölümByte-özdeş çıktı bir gösteriş metriği değildir. Ekiplerin gerçekten istediği üç şeyin altındaki temeldir.
Birincisi önbelleğe almadır. Bir kurulum, girdilerinin saf bir işleviyse, çıktısının özeti bir önbellek anahtarıdır. Aynı girdiler, aynı özet, işi atla ve saklanan dosyayı sun. Byte’lar gezindiğinde, özet de gezinir ve önbellek asla isabet etmez.
İkincisi kurcalama-kanıtıdır. Gönderdiği dosyayı tam olarak yeniden üretebilen bir hat, sonradan, arşivlenmiş bir belgenin değiştirilmediğini kanıtlayabilir: yeniden kur, ikisinin de özetini al, karşılaştır. Gömülü bir saat yüzünden tek bir byte bile farklıysa, kanıt gitmiştir ve “bana güven”e geri dönmüşsünüzdür.
Üçüncüsü güvenilir CI’dır. Bir golden-file testi, bilinen-iyi bir çıktıyı kaydeder ve bir değişiklik onu değiştirdiğinde başarısız olur. O sinyal yalnızca, değişmemiş bir motor değişmemiş bir dosyayı yeniden ürettiğinde anlamlıdır. Her çalıştırma bir zaman damgasında farklılaşırsa, golden file gürültüdür ve ekip kırmızı bir kurulumu yok saymayı öğrenir — testteki en pahalı alışkanlık.
Kısa açıklama
“Kısa açıklama” başlıklı bölümNextPDF’nin deterministik profilinde, aynı kurulumlar arasında aksi takdirde sürüklenecek
olan, motor tarafından kontrol edilen iki alan, tarihler ve /ID’dir. Bu, hattın geri
kalanının zaten kararlı olduğunu varsayar — aynı girdiler ve kendiliğinden değişmeyen bir
serileştirme (bununla ilgili daha fazlası aşağıda):
- Gömülü tarihler. Document information sözlüğü
CreationDateveModDate’i taşır (Spec: ISO 32000-2, §14.3.3ISO 32000-2 §14.3.3) ve XMP meta verisi onları yansıtır. Kurulum zamanında “şimdi”yi yakalayın ve her yeniden kurulum farklılaşır. - Dosya tanımlayıcısı.
/IDdizisi, dosyayı tanımlayan bir çift byte dizgesidir (Spec: ISO 32000-2, §14.4ISO 32000-2 §14.4), trailer sözlüğünde saklanır (Spec: ISO 32000-2, §7.5.5ISO 32000-2 §7.5.5). Kütüphaneler onu genellikle güncel zamandan artı rastgele byte’lardan türetir; bu yüzden tasarım gereği her çalıştırmada farklıdır.
İkisini de sabitleyin — sabit bir zaman damgası ve /ID için sabit bir tohum — ve çıktı,
içeriğinin deterministik bir işlevi hâline gelir. İçeriği rahat bırakın ve dosya byte byte
özdeş olur. Bu, Reproducible Builds projesinin derlenmiş yazılım için kurduğu, belge
katmanına uygulanan aynı disiplindir.
NextPDF’nin yaklaşımı
“NextPDF’nin yaklaşımı” başlıklı bölümNextPDF’de determinizm bir test hilesi değil, bir yapılandırma nesnesidir. Motor,
NextPDF\Core ad alanında bir DeterministicSettings değer nesnesi sunar. final readonly, değişmezdir ve yukarıda adı geçen, saat ve rastgeleden türeyen tam iki
sürüklenme kaynağını sabitler: tarihler ve /ID. Onları sabitlemek, en yaygın iki
sürüklenme kaynağını ortadan kaldırır, ama tek başına byte-özdeş çıktıyı garanti etmez.
Motorun diğer serileştirme davranışı — nesne sıralaması, font alt kümeleme ve sıkıştırma
ayarları — de çıktının yeniden üretilebilmesi için deterministik olmalıdır ve NextPDF
bunları tasarım gereği kararlı tutar.
Kurucusu iki bağımsız değişken alır:
public function __construct( public DateTimeImmutable $timestamp, public string $fileIdSeed,) { // ...}$timestamp, her tarih alanına yazılan tek sabit andır — CreationDate, ModDate ve
onların XMP yansıması. Tek bir DateTimeImmutable geçirin ve belge, duvar saatine kaçta
olduğunu sormayı bırakır. $fileIdSeed, trailer /ID’sini sabitleyen girdidir:
32 karakterlik bir on altılık (hexadecimal) dizge. Aynı tohumu verin ve motor, saati ve
bir rastgele kaynağı örneklemek yerine aynı dosya tanımlayıcısını türetir.
Nesne kendi girdisini doğrular. Tohum tam olarak 32 on altılık karakter olmalıdır; başka
herhangi bir şey, farklı görünen bir /ID sessizce üretmek yerine kurulumda bir
InvalidConfigException ile reddedilir. Bu, motorun geri kalanının benimsediği aynı
tahmin-etmeyi-reddet duruşudur — belirsiz bir girdi, byte’ları sessizce değiştirmek yerine
yüksek sesle başarısız olur.
İkisi de sabitlenmiş hâlde, tarif, Reproducible Builds projesinin tanıdık kıldığıdır: yeniden kur, diff’le ve diff boştur.
- Fix the inputsThe same content, fonts, and settings that produced the original document.
- Pin the timestampOne DateTimeImmutable feeds CreationDate, ModDate, and the XMP dates — no wall clock.
- Pin the /ID seedA 32-character hex seed derives the trailer /ID instead of a clock-plus-random value.
- BuildThe output is now a pure function of content; the two moving parts are held still.
- Rebuild and diffRegenerate from the same inputs and compare bytes — an empty diff is the proof.
Pratik örnek
“Pratik örnek” başlıklı bölümKüçük, eksiksiz bir şekil. Ayarlar bir kez kurulur ve yeniden kullanılır; böylece aynı programın iki çalıştırması aynı dosyayı üretir.
<?php
declare(strict_types=1);
use NextPDF\Core\DeterministicSettings;use NextPDF\Exception\InvalidConfigException;
// One fixed instant for every date field — never the wall clock.$timestamp = new DateTimeImmutable('2026-01-01T00:00:00+00:00');
// A 32-character hex seed pins the trailer /ID. Same seed, same /ID.$fileIdSeed = '0123456789abcdef0123456789abcdef';
try { $deterministic = new DeterministicSettings( timestamp: $timestamp, fileIdSeed: $fileIdSeed, );} catch (InvalidConfigException $e) { // A malformed seed (not exactly 32 hex chars) is refused here, // before any document is built — not silently coerced. error_log($e->getMessage());
throw $e;}
// Hand $deterministic to the document configuration. With both moving// parts pinned, building the same content twice yields identical bytes://// sha256(build_one) === sha256(build_two)Tohum, kontrol ettiğiniz bir kurulum girdisidir, bir sır değil. Onu kurulum yapılandırmanızın geri kalanının yanında saklayın. Asıl mesele, onun sabit olmasıdır; böylece ürettiği dosya tanımlayıcısı da sabittir.
Yaygın yanlış kanı
“Yaygın yanlış kanı” başlıklı bölümİlk tuzak, “Zaman damgasını kaldırdım, yani kurulumum artık yeniden üretilebilir”dir.
Genellikle değildir; çünkü /ID dizisi, iki kaynağın daha sessiz olanıdır. Tarihler bir
meta veri panelinde görünür ve hatırlaması kolaydır; trailer /ID ise çoğu okuyucuya
görünmezdir ve her çalıştırmada saatten ve bir rastgele kaynaktan yeniden üretilir.
Yalnızca tarihleri sabitleyen bir kurulum, yine de her seferinde farklı bir dosya üretir.
İkisini birden sabit tutmalısınız.
İkinci tuzak, determinizmi tek başına bir güvenlik özelliği olarak ele almaktır.
Sabitlenmiş bir /ID, bir dosyayı yeniden üretilebilir kılar; onu imzalı kılmaz ve
tek başına iki kurulumun eşleştiğini kanıtlamaz. Byte byte bir karşılaştırma ya da bir
özet, kurulumların eşleştiğini kanıtlar; /ID’yi sabitlemek yalnızca yanıltıcı bir fark
kaynağını ortadan kaldırır. Ve bunların hiçbiri, bir üçüncü tarafın dosyaya kefil olduğunu
kanıtlamaz. Yeniden üretilebilirlik ve imzalama, ikamesi olmayan, tamamlayıcı
katmanlardır.
Sınırlar ve hudutlar
“Sınırlar ve hudutlar” başlıklı bölümDeterminizm, motorun kendi hareket eden parçalarını sabitler. Sizin girdilerinizi
sabitlemez. İçeriğiniz canlı bir zaman damgası gömüyorsa, diskte değişmiş bir font
çekiyorsa ya da güncel tarihe bağlı bir değer oluşturuyorsa, çıktı değişir; çünkü girdi
değişti — ve bu doğrudur. DeterministicSettings, motorun belirlenimsizliğini kaldırır,
sizinkini değil. Yeniden üretilebilir bir kurulum, yine de yeniden üretilebilir girdiler
gerektirir.
| Edition | Availability |
|---|---|
| Core | Full support. |
| Pro | Not in this edition |
| Enterprise | Not in this edition |
İlgili belgeler
“İlgili belgeler” başlıklı bölüm- Golden-file testi — byte-özdeş çıktıya bağlı olan CI tekniği ve deterministik bir motorun neden onun ön koşulu olduğu.
- Artımlı güncellemeler — bir PDF’nin ekleyerek
nasıl büyüdüğü; bir dosyayı önceki sürümleriyle ilişkilendirmek için
/IDdizisinin yeniden önem kazandığı yer. - Meta veri ve XMP paketi — gömülü tarihlerin nerede yaşadığı ve XMP paketinin document information sözlüğünü nasıl yansıttığı.
- Bir PDF dosyasının anatomisi — trailer,
cross-reference table ve
/IDdizisinin dosya yapısında nerede oturduğu.
Sözlük
“Sözlük” başlıklı bölüm- Byte-özdeş (byte-identical) — tam olarak, byte byte eşleşen iki dosya. “Aynı”nın en güçlü biçimi ve bir özetin ya da bir diff’in doğrulayabileceği biçim.
/ID(dosya tanımlayıcısı) — bir PDF’yi ve sürümlerini tanımlayan iki byte dizgesinden oluşan dizi (ISO 32000-2 §14.4), trailer sözlüğünde saklanır (§7.5.5). Genellikle saatten artı rastgele byte’lardan türetilir; bu yüzden her sabitlenmemiş kurulumda değişir.- Document information sözlüğü —
CreationDateveModDate’i taşıyan yapı (ISO 32000-2 §14.3.3). Deterministik bir kurulumun sabitlemesi gereken iki belirlenimsizlik kaynağından biri. - Golden file — bir testin karşı karşılaştırdığı, kaydedilmiş, bilinen-iyi bir çıktı; yalnızca değişmemiş bir motor değişmemiş bir dosyayı yeniden ürettiğinde anlamlıdır.
- Yeniden üretilebilir kurulum (reproducible build) — çıktısı, girdilerinin deterministik bir işlevi olan bir kurulum; böylece aynı girdilerden yeniden kurmak aynı byte’ları verir. Terim, derlenmiş yazılım için Reproducible Builds projesinden gelir.