İçeriğe geç
getnextpdf.com

Bir PDF, bir kaptır: gömülü dosyalar ve ilişkili veriler

Spec: ISO 32000-2, §7.11.4Spec: ISO 32000-2, §14.13Spec: ISO 19005-3, PDF/A-3

Çoğu insan bir PDF’yi bir sayfa yığını olarak hayal eder. Gördüğünüz kısım odur. Ama bir PDF aynı zamanda bir kaptır ve içinde bütün başka dosyalar taşıyabilir — bir elektronik tablo, bir XML yükü, özgün kaynak belge — hepsi, başkasına verdiğiniz aynı tek dosyada paketlenmiş hâlde.

Bu sayfa bunun nasıl çalıştığını açıklar: byte’ları saklayan gömülü-dosya akışını, onları listeleyen ad ağacını ve bir ekin orada öylece durup durmadığına yoksa gerçekten bir şey ifade edip etmediğine karar veren tek anahtarı.

Tipsiz bir ek ile tipli bir ek, bir insana özdeş görünür. İkisi de bir PDF’nin içinde yolculuk eden bir dosyadır ve — bu motorda — ikisi de belgeyle ilişkilendirilmiştir. Aradaki fark, birinin bir makineye ne işe yaradığını söylemesi, diğerininse ilişkiyi makinenin tahmin etmesi için boş bırakmasıdır.

Bu fark, bir hibrit e-fatura için işin tamamıdır. Bir vergi platformu sizin fatura sayfanızı okumaz; gömdüğünüz XML’i okur. O XML, görünür belge için fatura verisi olarak değil de ayrımsız bir yığın olarak eklenmişse, uyumlu bir okuyucunun onun işlenecek yük olduğunu güvenilir biçimde bilmesinin bir yolu yoktur. Sayfa kusursuz görünür. Fatura reddedilir. Başarısızlık, ardında bekletilmiş bir ödemeyle birlikte, günler sonra gelir.

İlişkiyi, dosyayı üreten katmanda doğru kurmak, onu bir defada bir reddedilmiş fatura üzerinden keşfetmekten çok daha ucuzdur.

  • Bir PDF, herhangi bir dosyanın byte’larını bir gömülü dosya akışı olarak gömebilir (Spec: ISO 32000-2, §7.11.4). Akış, veriye ek olarak küçük bir parametreler sözlüğü taşır: özgün boyut, tarihler ve bir sağlama toplamı.
  • Gömülü dosyalar EmbeddedFiles ad ağacında kataloglanır; böylece bir okuyucu, tüm belgeyi taramadan onları ada göre listeleyebilir.
  • Bir ilişkili dosya bir adım daha ileri gider: bir AFRelationship beyan eder (Spec: ISO 32000-2, §7.11.3) — sekiz standart değerden biri (Source, Data, Alternative, Supplement, EncryptedPayload, FormData, Schema, Unspecified) ya da özel bir değer — dosyanın, eklendiği içerikle nasıl ilişkili olduğunu söyleyerek.
  • Bu tipli ilişki, hibrit e-faturaların (ZUGFeRD / Factur-X) ve PDF/A-3 eklerinin arkasındaki mekanizmadır (Spec: ISO 19005-3, PDF/A-3).
  • NextPDF, ham kap ilkellerini çekirdekte destekler: açık bir ilişkiyle birlikte embedFile() ve embedFileFromString(). Gelişmiş sürümler, bu ilkellerin üzerine özel EN 16931 / ZUGFeRD / Factur-X e-fatura gömücüsünü ekler.

Bunu, üst üste yığılmış iki katman olarak düşünün.

Alt katman depolamadır. Bir gömülü dosya akışı (Spec: ISO 32000-2, §7.11.4), özgün dosyanın byte’larının bir PDF akış nesnesine sarılmış hâlidir; özgün boyutu, değişiklik tarihini ve sıkıştırılmamış verinin bir sağlama toplamını kaydeden bir parametreler sözlüğüyle birlikte. Akışa, /EF sözlüğü gömülü dosya akışına işaret eden bir dosya belirtimi (file specification) sözlüğü üzerinden ulaşılır — akışın kendisi /EF taşımaz. Bir okuyucu, dosyayı byte byte geri çekebilir. Bu dosyaları bulunabilir kılmak için belge kataloğu bir EmbeddedFiles ad ağacı tutar — bir addan her dosya belirtimine giden sıralı bir eşleme — böylece bir görüntüleyici her sayfayı dolaşmadan “bu PDF’nin içinde 3 dosya var” diye listeleyebilir.

Üst katman anlamdır. Tek başına, gömülü bir dosya yalnızca mevcuttur. İlişkili-dosyalar mekanizması (Spec: ISO 32000-2, §14.13) bir dosyayı bir şeye — tüm belgeye, bir sayfaya, bir grafik nesnesine — bağlar ve onu bir AFRelationship ile damgalar. ISO 32000-2, sekiz standart değerden oluşan küçük bir sözcük dağarı tanımlar (Spec: ISO 32000-2, §7.11.3) ve özel değerlere de izin verir; her standart değer kesin bir soruya yanıt verir:

AFRelationshipDosya hakkında ne iddia ettiği
SourceBu, görünür içeriğin üretildiği kaynak malzemedir (örneğin, özgün kelime işlemci belgesi).
DataBu, görünür içeriğe bağlı yapılandırılmış veridir — kanonik durum, oluşturulmuş bir fatura sayfasının arkasındaki fatura XML’idir.
AlternativeBu, aynı içeriğin alternatif bir gösterimidir (örneğin, bir ses ya da video sürümü).
SupplementBu, içeriği genişleten ama onun bir parçası olmayan tamamlayıcı malzemedir.
EncryptedPayloadGömülü dosya, PDF’nin opak bir yığın olarak sardığı şifrelenmiş bir yüktür.
FormDataDosya, form verisidir (FDF, XFDF ya da bir XML form yükü).
SchemaDosya, bir Data dosyasının yapısını tanımlayan bir şemadır (örneğin, XML verisi için bir XSD ya da bir JSON Schema).
Unspecifiedİlişki kasıtlı olarak belirtilmemiştir. Dürüsttür, ama bir makineye hiçbir şey söylemez.

Bu sekizin ötesinde, standart uygulamaya özgü özel ilişki değerlerine de izin verir; böylece sözcük dağarı sabit değil, genişletilebilirdir.

Bir ilişkili dosya, tek bir anahtarla değil, birlikte çalışan iki şeyle tanımlanır. /AF ilişkilendirmesi, dosya belirtimini belgenin bir parçasına bağlar; dosya belirtimindeki AFRelationship anahtarı ise anlamsal ilişkiyi belirtir. İlişkilendirme noktasındaki (belge kataloğu, bir sayfa ya da bir nesne) /AF girdisi bir dizidir — bu dizi, genellikle dolaylı referanslar olarak, bir veya daha fazla dosya belirtimi sözlüğü içerir; /AF tek bir referans değildir. Belge düzeyinde bir ilişkili dosya, belge kataloğunun /AF dizisinde listelenen ve kendi AFRelationship değerini taşıyan dosya belirtimidir. O elektronik tabloyu Unspecified olarak işaretlerseniz, onu belgeyle ilişkilendirmiş ama bir makineye neden olduğu hakkında hiçbir şey söylememiş olursunuz. Aynı elektronik tabloyu Data olarak işaretlerseniz, her uyumlu okuyucuya onun ne olduğunu ve ne işe yaradığını söylemiş olursunuz. Byte’lar aynıdır. Anlambilim değildir.

İşte bu yüzden e-fatura durumu “bir XML dosyası ekle” değildir. “Bu XML’i, bu belge için Data ilişkili dosyası olarak, uyumlu bir PDF/A-3 taşıyıcısının içine göm”dür — fatura geçerliliği ve hukuki kabul ise taşıyıcının gerçekleştirmediği ayrı denetimler olarak kalır. Akış dört aşamadan oluşur ve onu doğru tutan şey, sıradır.

  1. Store the bytesThe file is wrapped in an embedded file stream with its size, dates, and a checksum (ISO 32000-2 §7.11.4).
  2. Register it by nameThe file specification is added to the EmbeddedFiles name tree so a reader can enumerate attachments without scanning the document.
  3. Declare the relationshipAn AFRelationship value (one of the eight standard values such as Source or Data) marks how the file relates to the content, associated at the document level (ISO 32000-2 §14.13.3).
  4. Make it archivalA PDF/A-3 carrier permits the embedded payload to ride inside one conforming archival PDF/A document; invoice validity and legal acceptance remain separate checks (ISO 19005-3).
How a typed attachment becomes a hybrid file end to end: the engine stores the bytes, registers the file by name, declares the relationship, and the archival profile permits it all to ride inside one conforming archival document.

O dördüncü aşama, PDF/A-3’ün neden ayrı bir profil olarak var olduğudur. Daha eski arşivleme profilleri neyin gömülebileceğini kısıtlıyordu; PDF/A-3 (Spec: ISO 19005-3, PDF/A-3), herhangi bir biçimdeki dosyaların uyumlu bir arşivleme belgesinin içinde yolculuk etmesine izin veren kısımdır. Gömülü yüke izin verir — o yükü doğrulamaz ya da ona hukuki statü kazandırmaz. Onsuz, hibrit fatura — bir kişinin okuduğu sayfa ve bir vergi sisteminin ayrıştırdığı verinin ikisi birden olan tek dosya — hiç de uyumlu bir arşivleme PDF/A belgesi olamazdı; faturanın geçerli ve hukuken kabul edilip edilmediği ise ayrı bir soru olarak kalır. Gelişmiş sürümlerin eklediği özel e-fatura gömücüsü, tam da bunun üzerindeki kolaylık dikişidir: yükü gömer, ilişkiyi Data olarak ayarlar ve onu doğru biçimde kaydeder; böylece kap tesisatını elle kurmazsınız. Daha derin faturalama ve arşivleme mekanikleri, aşağıda bağlantısı verilen iki komşu sayfada yaşar; bu sayfa, ikisinin de üzerinde durduğu kabı konu alır.

Küçük, eksiksiz bir program. Önemli olan iki çağrı, tipsiz bir ilişkili dosya ile tipli bir ilişkili dosya arasındaki farktır — ve ilişki, ayarlamanız gereken açık bir bağımsız değişkendir. Bu motorda, her iki çağrı da bir ilişkili dosya üretir: embedFile() ve embedFileFromString(), dosya belirtimini her zaman belge kataloğunun /AF dizisine kaydeder; dolayısıyla ilişkinin değiştirdiği tek şey, ilişkilendirmenin ne anlama geldiğidir. Varsayılanı Unspecified’dır; bu da dosyayı ilişkilendirir ama bir makineye nedeni hakkında hiçbir şey söylemez; bir e-fatura yükü için onu Data olarak ayarlarsınız ki bir okuyucu onu bulabilsin.

<?php
declare(strict_types=1);
use NextPDF\Core\Document;
use NextPDF\Navigation\AFRelationship;
$document = Document::createStandalone();
$document->addPage();
$document->setFont('helvetica', 'B', 16);
$document->cell(0, 12, 'Invoice INV-2026-0042', newLine: true);
// An UNTYPED associated file: the bytes are embedded AND the file spec is
// added to the document catalog's /AF array, but the relationship says
// nothing about why. A reader can open it; a machine cannot tell its role.
// The relationship is left Unspecified (its default); the second argument is
// the human-readable description. embedFile accepts the AFRelationship enum.
$document->embedFile(
'/srv/invoices/INV-2026-0042-source.docx',
'Original source document',
AFRelationship::Unspecified,
);
// A TYPED associated file: the invoice XML is declared as the DATA behind
// the visible page. This is the relationship a hybrid e-invoice reader
// looks for — the same intent the dedicated e-invoice embedder sets.
// embedFileFromString takes the data, a filename, a description, and a
// relationship as a PDF-name string ('/Data').
$invoiceXml = $generateCiiXml(); // your ERP authors this; the engine never does
$document->embedFileFromString(
$invoiceXml,
'factur-x.xml',
'Factur-X invoice data',
'/Data',
);
$bytes = $document->getPdfData();

'/Data' ilişkisi yanılmaya yer bırakmaz. İlk ek — Unspecified bırakılmış olan — yine de, yalnızca belirtilmiş bir anlam olmadan, ilişkilendirilmiştir. Her iki çağrı için de motor, gömülü dosya akışını yazar, dosyayı EmbeddedFiles ad ağacına ekler, dosya belirtimini belge kataloğunun /AF dizisinde listeler ve belirttiğiniz ilişkiyi kaydeder — sizin yerinize bir tane seçmez. Bu motorda yalnızca-ad-ağacı kipi yoktur: bu yolla gömdüğünüz her dosya belgeyle ilişkilendirilmiş bir dosyadır; bu nedenle kontrol ettiğiniz tek kol ilişkidir.

Sık görülen varsayım, “gömülü” ve “ilişkili”nin aynı şeyin iki sözcüğü olduğudur. Değiller. Gömülü, depolamayla ilgilidir — byte’lar PDF’nin içindedir. İlişkili, bağlamayla ilgilidir — dosya belirtimi, belgenin bir parçasındaki bir /AF dizisinde listelenir ve bir AFRelationship taşır. Soyut PDF modelinde bir dosya, hiç ilişkilendirilmeden ad ağacına gömülebilir; NextPDF’nin embedFile() yolu onu öyle bırakmaz — /AF ilişkilendirmesini her zaman yazar — dolayısıyla bu motor için açık soru asla bir dosyanın ilişkilendirilip ilişkilendirilmediği değil, ilişkinin ne söylediğidir.

İkinci bir tuzak: bir görüntüleyicinin hangi ekin fatura olduğunu “çözeceğini” varsaymak. Uyumlu bir okuyucunun tahmin etmesi beklenmez. İlişkisi Data diyen dosyayı arar. İlişkiyi Unspecified bırakırsanız, yükü ilişkilendirmiş ama makineye onun rolü hakkında yararlı hiçbir şey söylememiş olursunuz.

Kap mekanizması, dürüst olmaya değer bir biçimde güçlüdür: embedFile(), PHP sürecinin okuyabildiği herhangi bir yolu okur. Özellik budur — ve hudut da budur. Motor, kendisine verilen byte’ları ekler; bir yolun amaçladığınız bir yol olup olmadığına sizin yerinize karar vermez ve karar veremez.

Embedding a file from a caller-supplied path — edition availability
EditionAvailability
Core

embedFile() reads any path the PHP process has access to and embeds its bytes verbatim. Validating that the path is safe and intended — not a user-controlled value, a traversal, or a secret outside the document’s scope — is the integrator’s responsibility. This is a documented security contract, not an oversight: the engine will not silently guess which paths are legitimate, because that guess belongs to your application, which knows the trust boundary the engine cannot see. Pass attacker-influenced bytes through a string with embedFileFromString() so the path layer is never in play.

ProNot in this edition
EnterpriseNot in this edition

Açıkça belirtmeye değer iki sınır daha:

  • Gömmek, doğrulamak değildir. Motor, kendisine verdiğiniz byte’ları taşır. Gömülü XML’in uyumlu bir fatura yükü olup olmadığı, bir doğrulayıcı tarafından yanıtlanan ayrı bir sorudur — faturalama sayfasına bakın.
  • Tipli bir ek, tek başına uyumlu bir arşivleme dosyası değildir. Hibrit dosyayı hukuki bir PDF/A-3 belgesi yapmak, arşivleme kipini ve bağımsız bir uygunluk denetimini gerektirir — arşivleme sayfasına bakın.
  • Faturalar ve e-faturalama — bu mekanizmanın olanaklı kıldığı kullanım durumu: makine okuyabilir bir faturayı Data ilişkili dosyası olarak taşıyan hibrit bir PDF.
  • Arşivleme ve PDF/A — taşıyıcının neden bir PDF/A-3 dosyası olduğu ve uygunluğun neyi vaat edip neyi etmediği.
  • Bir PDF dosyasının anatomisi — ad ağacının ve belge kataloğunun dosya yapısında nerede durduğu.
  • Akışlar ve filtreler — gömülü bir dosyanın byte’larının bir akış nesnesinin içinde nasıl saklanıp sıkıştırıldığı.
  • Gömülü dosya akışı (embedded file stream) — özgün boyutunu, tarihlerini ve bir sağlama toplamını kaydeden bir parametreler sözlüğüyle birlikte, harici bir dosyanın byte’larını tutan bir PDF akış nesnesi (ISO 32000-2 §7.11.4).
  • EmbeddedFiles ad ağacı — belge kataloğundaki, gömülü dosyaları ada göre listeleyen sıralı eşleme; böylece bir okuyucu tüm belgeyi taramadan ekleri listeleyebilir.
  • İlişkili dosya (associated file) — bir /AF ilişkilendirmesiyle (belge kataloğu, bir sayfa ya da bir nesne üzerinde) belgenin bir parçasına bağlanan ve o içerikle nasıl ilişkili olduğunu belirten bir AFRelationship taşıyan gömülü bir dosya; bu sayfanın merkeze aldığı, belge düzeyindeki durumdur — kataloğun /AF dizisindeki dosya belirtimi (ISO 32000-2 §14.13.3).
  • AFRelationship — değeri ilişkiyi adlandıran dosya-belirtimi anahtarı (ISO 32000-2 §7.11.3). Sekiz standart değerden birini (Source, Data, Alternative, Supplement, EncryptedPayload, FormData, Schema, Unspecified) ya da özel bir değer alır; Data, bir hibrit e-fatura yükünün kullandığı değerdir.
  • PDF/A-3 — herhangi bir biçimdeki dosyaların gömülmesine izin vererek uyumlu bir hibrit belgeyi olanaklı kılan ISO 19005-3 arşivleme profili.
  • Hibrit fatura — hem insan okuyabilir bir sayfa hem de makine okuyabilir gömülü bir fatura yükü olan tek bir PDF dosyası.