Document: DPart'lar, bölme / birleştirme ve satıcı uzantıları
Bir bakışta
“Bir bakışta” başlıklı bölümDocument modülü, sayfa içeriğiyle değil, Portable Document Format (PDF) dosyalarının bütünüyle çalışır. Düzenlemeye tabi iş akışlarının meta veri eklemek için kullandığı Document Part hiyerarşisini oluşturur. Bir PDF’yi sayfa aralıklarına göre parçalara ayırır, birkaç PDF’yi tek bir dosyada birleştirir ve geliştirici uzantılarını belge kataloğuna kaydeder.
Kurulum
“Kurulum” başlıklı bölümcomposer require nextpdf/core:^3Kavramsal genel bakış
“Kavramsal genel bakış” başlıklı bölümBu modül, sayfa içeriği katmanının üzerinde yer alır. Graphics ve Content operatör yayarken, Document yapısal düzeyde çalışır: sayfa ağaçları, belge kataloğu ve Document Part ağacı.
Bir Document Part (DPart), bir PDF’nin mantıksal bölümüdür. ISO 32000-2, düğümleri Document Part Metadata (DPM) taşıyan bir DPart hiyerarşisi tanımlar. İlaç, hukuk veya arşivleme iş akışı gibi düzenlemeye tabi bir iş akışı, meta veriyi dosyanın tamamı yerine sayfaların bir alt aralığıyla ilişkilendirebilir — §14.12. DPart, değişmez bir readonly düğümdür: yaprak düğüm, ardışık sayfa dizinlerinden oluşan bir diziye başvurur; ara düğüm ise alt DPart düğümlerini bir ağaçta gruplar. DPartRoot, Writer’ın serileştirdiği ağaç köküdür. Yaprak düğümün /Start ve /End girişleri, sayfa dizini tam sayıları değil, sayfa nesnelerine dolaylı başvurulardır — §14.12. DPart::resolveWithPageObjects(), bu girişleri writer tarafından sağlanan sayfa dizini→nesne numarası eşlemesini kullanarak çözer ve /Start (ve isteğe bağlı /End) başvuru biçimini döndürür. Yalnızca eşlemenin kullanılamadığı test yollarında tam sayı biçimine geri döner.
PdfMerger ve PdfSplitter, belge oluşturma yüzeyidir. PdfMerger, birden çok girdi PDF’sindeki sayfa nesnelerini birleştirir, çakışmaları önlemek için nesneleri yeniden numaralandırır ve tek bir sayfa ağacı ile çapraz başvuru tablosunu yeniden oluşturur. Ürettiği sayfa ağacı, dengeli bir Pages düğümüdür; Kids ile Count girişlerini ve PDF’nin sayfa ağacı düğümleri için tanımladığı kalıtsal nitelik modelini taşır — §7.7.3. PdfSplitter bunun tersini yapar: sayfa aralıklarını bağımsız SplitDocument nesnelerine çıkarır. PageRange, her iki sınıfın da kullandığı değer nesnesidir. 1 tabanlıdır, sınırlarını doğrular ve contains(), count() ile toArray() yanıtlarını verir.
VendorExtensionRegistry, ExtensionsDictionary ve DeveloperExtensionEntry, belge kataloğundaki geliştirici uzantıları sözlüğünü modeller. Bir motor, temel belirtimin ötesinde bir satıcı uzantı düzeyi bildirmek için bu sözlüğü kullanır. Kayıt defteri, aynı satıcı önekinin çakışacak biçimde yeniden kaydedilmesini VendorExtensionRegistryConflictException ile reddeder. CollectionDictionary ve CollectionSort, bir PDF koleksiyonu (taşınabilir koleksiyon veya portföy) katalog girişini modeller.
API yüzeyi
“API yüzeyi” başlıklı bölüm| Sınıf | Temel yöntemler | Rol |
|---|---|---|
DPart | isLeaf(), hasMetadata(), resolveWithPageObjects(), write() | Değişmez Document Part düğümü (@since 1.12.0) |
DPartRoot | isEmpty(), write() | Writer’ın serileştirdiği DPart ağaç kökü (@since 1.12.0) |
PdfMerger | merge(array $pdfFiles, int $maxFiles = 100, int $maxTotalBytes = 200_000_000), append() | Nesne yeniden numaralandırmalı çoklu PDF birleştirme (@since 1.9.0) |
PdfSplitter | split(), splitEvery(), extractPages() | Sayfa aralığını SplitDocument öğelerine bölme (@since 1.9.0) |
PageRange | contains(int $page), count(), toArray() | 1 tabanlı sayfa aralığı değer nesnesi |
MergeResult / SplitResult | isValid(), count(), document(), totalOutputSize() | Oluşturma sonucu nesneleri |
VendorExtensionRegistry | uzantı kaydı | Geliştirici uzantıları kayıt defteri (@since 2.2.0) |
ExtensionsDictionary | withEntry(), entries(), isEmpty(), toPdfDictionary() | Değişmez uzantılar sözlüğü oluşturucusu (@since 2.0.0) |
CollectionDictionary | toPdfDictionary() | Taşınabilir koleksiyon katalog girişi (@since 2.0.0) |
Tam PHPDoc tablosunu oluşturmak için composer docs:generate-api-php -- --module=Document komutunu çalıştırın.
Kod örneği — hızlı başlangıç
“Kod örneği — hızlı başlangıç” başlıklı bölümBir PDF’yi tek sayfalık belgelere ayırın, ardından sonucu inceleyin.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Document\PageRange;use NextPDF\Document\PdfSplitter;
$splitter = new PdfSplitter();$result = $splitter->splitEvery(file_get_contents('/srv/in/report.pdf'), 1);
foreach (range(0, $result->count() - 1) as $index) { $segment = $result->document($index); file_put_contents("/srv/out/page-{$index}.pdf", $segment->pdfData);}
$singlePage = $splitter->extractPages( file_get_contents('/srv/in/report.pdf'), new PageRange(2, 4),);Kod örneği — üretim
“Kod örneği — üretim” başlıklı bölümBirkaç PDF’yi tanımlı bir girdi bütçesiyle birleştirin, ardından birleştirilmiş çıktıyı yazmadan önce sonucu doğrulayın.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Document\PdfMerger;use NextPDF\Exception\PageLayoutException;
/** @var list<string> $sources Raw PDF byte strings to combine. */$sources = array_map( static fn (string $path): string => file_get_contents($path), glob('/srv/batch/*.pdf') ?: [],);
$merger = new PdfMerger();
try { // Bound the merge: at most 50 files, 100 MB total. $merged = $merger->merge($sources, maxFiles: 50, maxTotalBytes: 100_000_000);} catch (PageLayoutException $e) { throw new \RuntimeException('Merge rejected: empty or invalid input set.', previous: $e);}
if (!$merged->isValid()) { throw new \RuntimeException('Merged document failed structural validation.');}
file_put_contents('/srv/out/combined.pdf', $merged->pdfData);Uç durumlar ve tuzaklar
“Uç durumlar ve tuzaklar” başlıklı bölümPdfMerger::merge()vePdfSplitter::split(), girdi sınırlarınıResourceGuardaracılığıyla uygular. Çok fazla dosya veya çok fazla bayt içeren girdiler, sessizce kırpmak yerine bir istisna oluşturur.maxFiles/maxTotalBytesdeğerlerini iş yükünüze göre bilinçli olarak ayarlayın.- Boş dosya listesi veya boş aralık listesi
PageLayoutExceptionoluşturur. Bunları boş sonuçlar olarak değil, yapılandırma hataları olarak değerlendirin. PageRange1 tabanlıdır ve uç değerleri kapsar. YaprakDPart’ınpageslistesi 0 tabanlı sayfa dizinleridir. İki soyutlama farklı dizin tabanları kullanır. Bunlar arasında geçiş yaparken açıkça dönüştürün.DPartreadonlytüründedir. Farklı bir ağaç oluşturmak için, var olanı değiştirmek yerine yeni düğümler oluşturun.resolveWithPageObjects(), tam sayı dizinli geri dönüş biçimini yalnızca sayfa nesnesi eşlemesi boş olduğunda döndürür. Üretim çıktısında bu yola güvenmeyin.VendorExtensionRegistry, yinelenen bir satıcı öneki içinVendorExtensionRegistryConflictExceptionoluşturur. Her öneki yalnızca bir kez kaydedin.
Performans
“Performans” başlıklı bölümBölme ve birleştirme, sayfa sayısıyla doğrusal olarak ölçeklenir; modülün kendi kayıt tutma yükünden çok, ayrıştırma ve nesne yeniden numaralandırması tarafından belirlenir. Varsayılan referans iş yükü, 1500 ms duvar saati / 64 MB tepe bütçesine sığar. Büyük birleştirmeler, esas olarak toplam girdi baytlarıyla sınırlanır. maxTotalBytes koruması, tepe bellek kullanımını sınırlı tutar. Yeniden üretilebilirlik profili structural’dir: birleştirilmiş veya bölünmüş bir PDF yeni bir fragman ve /ID taşır; bu nedenle iki çalıştırma yapısal olarak eşittir ancak bayt düzeyinde özdeş değildir.
Güvenlik notları
“Güvenlik notları” başlıklı bölümPdfMerger::merge() ve PdfSplitter::split(), güvenilmeyen PDF baytlarını kullanır. Ayrıştırmadan önce, her ikisi de girdiyi ResourceGuard::assertSize() / assertCount() üzerinden geçirir; bu da sıkıştırma açma veya nesne sayısını artırma kaynaklı hizmet reddi saldırısını sınırlar. Varsayılanlara güvenmek yerine, dağıtım için maxFiles, maxTotalBytes ve maxBytes argümanlarını sıkı tutun. Her girdi PDF’sini potansiyel olarak kötü niyetli kabul edin. Kaynaklar kullanıcı tarafından sağlandığında, toplu oluşturmayı kısıtlanmış bir işçide çalıştırın. Güven sınırı için /modules/core/security/ bölümündeki motor tehdit modeline bakın.
Uyumluluk
“Uyumluluk” başlıklı bölümBu modülün oluşturduğu DPart ağacı, ISO 32000-2 §14.12’deki Document Part modelini izler; yaprak /Start ve /End girişleri aynı madde kapsamında sayfa nesnelerine dolaylı başvurular olarak yayımlanır. Birleştirilmiş çıktı, §7.7.3’te tanımlanan sayfa ağacı düğüm yapısını kullanır. Bunlar, src/Document/ tarafından üretilen ve tests/Unit/Document/ (DPartTest, DPartRootTest, DPartPageRefTest, DocumentPdfMergerDeepTest, DocumentPageRangeParseDeepTest) tarafından test edilen uygulama davranışlarıdır. Bunlar, uçtan uca PDF 2.0 uyumluluğunun bir beyanı değildir. Tam belge uyumluluğu, /modules/core/conformance/ bölümünde açıklanan oracle ve golden paketleri tarafından doğrulanır.
Ayrıca bakınız
“Ayrıca bakınız” başlıklı bölüm- Core modülü
- Writer modülü — DPart ağacını ve sayfa ağacını serileştirir.
- Metadata modülü — DPM ile eşleşen Extensible Metadata Platform (XMP).
- Navigation modülü
- Uyumluluk genel bakışı
- Motor güvenlik modeli