İçeriğe geç

Tahmin yürütmeyi reddeden bir API

Spec: ISO/IEC 25010 Spec: ISO 32000-2 Evidence: Code-backed

NextPDF, ne yapmak istediğinizi açıkça söylemenizi zorunlu kılar. Niyet baytları değiştirdiğinde — bir imza düzeyi, bir çıktı hedefi, bir uyumluluk hedefi — bu, motorun bağlamdan çıkarsayacağı bir şey değil, zorunlu ve açık bir argümandır.

Bu sayfa, bu yaklaşımı motorun kendi kaynağında gösterir: yöntem imzaları, adlandırılmış argümanlar ve belirsiz bir girdinin herhangi bir bayt üretilmeden önce reddedildiği noktalar.

Tahmin, haberiniz olmadan sizin adınıza verilmiş bir karardır. Bir metin alanı için bu hafif rahatsız edicidir. Bir PDF söz konusu olduğunda ise gizli bir kusurdur; çünkü teslim ettiğiniz şey çoğu zaman, doğruluğu daha sonra başka biri tarafından bir doğrulayıcıyla denetlenen yasal veya arşivsel bir nesnedir.

Bir imzayı düşünün. Özeti, imza değerinin kendisini kasıtlı olarak dışarıda bırakan, bildirilmiş bir bayt aralığı üzerinden hesaplanır ( Spec: ISO 32000-2, §12.8 ). Sessizce “yardım eden” bir API — yapıyı yeniden yazan, bir düzeyi çıkarsayan, bir yer tutucuyu dolduran — yardım etmiş sayılmaz. Bir imzanın korumakla yükümlü olduğu baytları değiştirmiştir. Çağrı noktasında yardımcı gibi görünen tahmin, haftalar sonra üretim ortamındaki bir olaya dönüşür. İkisi de aynı kod satırıdır.

  • Bir seçim çıktıyı değiştiriyorsa ve güvenli bir varsayılanı yoksa, NextPDF bunu çıkarsanan bir değer değil, zorunlu bir argüman hâline getirir.
  • Belirsiz anlaşılabilecek isteğe bağlı argümanlar adlandırılır, böylece çağrı noktası niyeti belirtir (newLine: true, çıplak bir true değil).
  • Güvensiz olabilecek girdiler işlemeden önce doğrulanır ve nedenini adıyla belirten türü tanımlı bir istisnayla reddedilir.
  • Bir belge örneği tek kullanımlıktır: oluşturulur, çıktısı alınır ve atılır. reset() yoktur, dolayısıyla “bu nesne yeniden mi kullanılıyor?” tahmini de yoktur.
  • Motor, istediğiniz nesnenin yerine asla makul görünümlü bir nesne üretmez. Bunun yerine reddeder.

Mekanizma yalındır ve asıl mesele de budur. Bu; tür sistemi, adlandırılmış argümanlar, sihirli dizgeler yerine numaralandırmalar ve çıktının öncesine yerleştirilmiş az sayıda bilinçli koruma koşuludur.

Tablo, birkaç belirsiz girdiyi karşılaştırır. Her biri için, “yardım eden” bir kütüphanenin neyi çıkarsayacağını ve bunun yerine NextPDF’in ne yaptığını gösterir. NextPDF sütunundaki her davranış, bu sayfada ileride gösterilen kaynaktan alınmıştır.

Belirsiz girdiTahmin yürüten bir kütüphanenin yaptığıNextPDF’in yaptığı
Şuna benzer bir yön dizgesi: "portait"Bir varsayılana geri döner ve yine de işleraddPage() bir dizge değil, Orientation numaralandırmasını alır — bir yazım hatası sessiz bir varsayılan değil, bir tür hatasıdır
Çıplak ve sona eklenmiş bir true’nun verildiği cell()Hangi boole konumunu kastettiğinizi varsayar ve onu seçerBoole değeri çağrı noktasında adlandırılır (newLine: true); adlandırılmamış bir değişmez, API’nin ortadan kaldırdığı kötü bir kod kokusudur
Bir php:// sarmalayıcısı veya dizin geçişi yolunun verildiği save()”Elinden gelenin en iyisini yapar” ve bir yere yazarPDF oluşturulmadan önce, anahtarı, değeri ve beklenen türü adıyla belirten türü tanımlı bir InvalidConfigException ile reddedilir
setSignature() ardından save(), üst düzey imzalayıcı bağlanmamışkenÇağıranın imzalı sandığı, imzasız bir dosya üretirBayt üretmeden önce NotImplementedException fırlatır ve desteklenen yolu adıyla belirtir
İkinci bir işleme için bir Document örneğini yeniden kullanmakArtakalan durumun hâlâ geçerli olup olmadığını tahmin ederNe reset() ne de yeniden kullanım yolu vardır — her istek için DocumentFactory aracılığıyla yeni bir örnek oluşturulur, dolayısıyla tahmin edilecek artakalan bir durum yoktur

Niyet zorunlu bir argümandır. Çekirdek sözleşme niteliğindeki PdfDocumentInterface, geometriyi ve hizalamayı gevşek ilkel türler olarak değil, türü tanımlı değer nesneleri ve numaralandırmalar olarak alır:

public function addPage(
?PageSize $size = null,
Orientation $orientation = Orientation::Portrait,
): static;
public function cell(
float $width,
float $height,
string $text = '',
bool|string $border = false,
bool $newLine = false,
Alignment $align = Alignment::Left,
bool $fill = false,
): static;

Orientation ve Alignment birer numaralandırmadır; bu nedenle çağıran "portait" geçiremez ve bunun sessizce “varsayılan” anlamına gelmesini sağlayamaz. Bir varsayılan varsa bu, ne istediğinize dair olası bir tahmin değil, güvenli bir varsayılandır (dikey, sola, kenarlıksız).

Belirsiz boole değerleri çağrı noktasında adlandırılır. Fiilî API başvurusu işlevi gören örneklerin tamamında aynı biçim yinelenir:

$document->cell(0, 15, 'Hello, NextPDF!', newLine: true);
$document->setSignature(certInfo: $certInfo, level: SignatureLevel::PAdES_B_B);
$pdf = $document->output(dest: OutputDestination::String);

newLine: true yanlış anlaşılmaya açık değildir. Sona çıplak şekilde eklenmiş bir true ise belirsiz olurdu. İmza düzeyi, motorun yorumlaması gereken bir dizge değil, bir numaralandırma durumu olan SignatureLevel::PAdES_B_B’dir. Çıktı hedefi OutputDestination::String’tir, dolayısıyla “bana baytları ver; HTTP üst bilgisi yok, dosya yok” açıkça belirtilmiştir. Bir dosya adının geçirilip geçirilmediğinden çıkarsanmaz.

Güvensiz girdi, bir bayt yazılmadan önce reddedilir. save(), hedef yolu PDF’yi oluşturmadan önce doğrular:

public function save(string $path): void
{
// Reject stream wrappers and null bytes
if (\str_contains($path, "\0") || \preg_match('#^[a-zA-Z]+://#', $path)) {
throw new InvalidConfigException(
configKey: 'output_path',
givenValue: $path,
expectedType: 'valid_path',
);
}
// Resolve the parent directory to prevent path traversal
$dir = \dirname($path);
$realDir = \realpath($dir);
if ($realDir === false) {
throw new InvalidConfigException(
configKey: 'output_path',
givenValue: $dir,
expectedType: 'existing_directory',
);
}
// ... only now is the PDF built and written atomically
}

Motor, bir php:// sarmalayıcısı veya bir dizin geçişi yolu ile “elinden gelenin en iyisini yapmaz”. Reddeder; istisna da anahtarı, değeri ve neyin beklendiğini adıyla belirtir.

Motor, yanıltıcı bir nesne üretmek yerine reddeder. Tahmin yürütmeyi reddetmenin en güçlü biçimi, çıktı gerçeği yansıtmayacaksa onu hiç üretmemektir. Üst düzey bir imza yapılandırılmışken ancak gerçek imzalamayı yapacak yazıcı bağlantısı kurulmamışken, oluşturma yolu, çağıranın imzalı sandığı imzasız bir dosya üretmek yerine bayt üretmeden önce istisna fırlatır:

if ($this->padesOrchestrator !== null) {
throw new NotImplementedException(
feature: 'Document::setSignature()->save()/output()/getPdfData()',
followUp: 'The high-level PAdES writer seam is not yet wired ... '
. 'Produce a signed PDF via the direct two-phase '
. 'PadesOrchestrator::signDocument() then finalizeSignature() '
. 'buffer API ...',
);
}

İmzalı gibi görünen imzasız bir PDF, bu ilkenin önlemek için var olduğu makul görünümlü yanlış nesne türünün ta kendisidir. Aynı yaklaşım, katı CSS yolunda da görülür. Katı CSS yolu, kayıtlı olmayan bir spesifikasyon sapmasını, yaklaşık bir işlem uygulayıp sapmayı tespit edilmeden bırakmak yerine, tespit edildiği noktada bir StrictModeViolation ile durdurur.

Tek kullanımlılık, bütün bir tahmin sınıfını ortadan kaldırır. Bir Document tek kullanımlıktır — oluşturulur, çıktısı alınır ve atılır. reset() yoktur ve yeniden kullanım yolu yoktur. Uzun süre çalışan bir worker süreci, her istek için DocumentFactory aracılığıyla yeni bir örnek oluşturur. Önceki bir belgeden kalan artakalan durumun hâlâ anlamlı olup olmadığını motorun asla tahmin etmesi gerekmez; çünkü tasarım gereği böyle bir durum yoktur.

Bu sayfa Evidence: Code-backed niteliğindedir: yukarıdaki her biçim, niyetten yola çıkılarak yorumlanmış değil, motorun kendi kaynağından ve örneklerinden alınmıştır.

  • Türü tanımlı, numaralandırma içeren yöntem imzaları, PdfDocumentInterface içindeki açık sözleşmedir. Adlandırılmış argümanlı çağrı biçimi, fiilî API başvurusu işlevi gören kanonik örneklerin tamamında tutarlı olan biçimdir.
  • Türü tanımlı InvalidConfigException ile işleme öncesi yol doğrulaması ve üretmeden önce reddeden NotImplementedException koruması, belge cephesindeki çıktı yolundan birebir alınmıştır.
  • Standart dayanağı Spec: ISO/IEC 25010, §3.32 ‘dir — kullanıcı hatasına karşı koruma, yani tahmin yürütmeyi reddeden bir API’nin çağrı noktasında karşılamak için var olduğu kalite özelliği. İkinci dayanak Spec: ISO 32000-2, §12.8 ‘dir; imzalı bir belge çevresinde tahmin yürütmenin asla zararsız olmamasının nedeni de budur. Özet, imza değerini dışarıda bırakan, bildirilmiş bir bayt aralığını kapsar, dolayısıyla herhangi bir sessiz yeniden yazma onu geçersiz kılar.

Aşağıda küçük, eksiksiz bir program yer alıyor. Belirsiz olabilecek her satır kendi niyetini belirtir. Tek güvensiz girdi, herhangi bir işlem yapılmadan önce reddedilir.

<?php
declare(strict_types=1);
use NextPDF\Contracts\OutputDestination;
use NextPDF\Core\Document;
use NextPDF\Exception\InvalidConfigException;
use NextPDF\ValueObjects\PageSize;
use NextPDF\Contracts\Orientation;
$document = Document::createStandalone();
$document->setTitle('Quarterly Report');
// Intent is explicit: a typed page size and an Orientation enum case,
// not a string the engine has to interpret.
$document->addPage(PageSize::a4(), Orientation::Landscape);
$document->setFont('helvetica', 'B', 16);
// Ambiguous boolean is named, so the call reads as intent.
$document->cell(0, 12, 'Quarterly Report', newLine: true);
try {
// Unsafe path is rejected before a byte is built.
$document->save('php://output/report.pdf');
} catch (InvalidConfigException $e) {
// "Invalid configuration for key "output_path": expected valid_path, ..."
error_log($e->getMessage());
// The String destination is explicit: bytes only, no HTTP headers,
// no file side effect. Nothing is inferred from a missing filename.
$bytes = $document->output(dest: OutputDestination::String);
}

Bu programın sessizce yanlış bir şey yapabileceği bir yol yoktur. Niyeti belirtip devam eder ya da sorunu adıyla bildirip durur.

Sıkça dile getirilen itiraz şudur: “bu yalnızca ayrıntıcılık”. Bu ayrıntıcılık değildir. Bu, gizli varsayılanların yokluğudur. Çıplak bir true, newLine: true ifadesinden yalnızca ortadan kaldırdığı netlik kadar daha kısadır. Motor, çağrı noktasındaki birkaç ek karakter karşılığında bir hata kategorisini ortadan kaldırır: kodun derlenip çalıştığı, dosya ürettiği ve yine de yanlış olduğu kategori.

İlgili bir yanlış anlama, hızlı başarısız olmanın “sürekli istisna fırlatmak” anlamına geldiğidir. Normal kullanımda NextPDF hiçbir istisna fırlatmaz. Geçerli girdi sorunsuz işler. Korumalar yalnızca gerçekten belirsiz veya güvensiz girdilerde devreye girer — tam da hemen haberdar olmak isteyeceğiniz, tahmin edilmesini istemeyeceğiniz girdilerde.

Tahmin yürütmeyi reddetmek, her kolaylığa değil, niyet ve güvenliğe uygulanır. NextPDF’in yine de güvenli varsayılanları vardır: dikey yön, sola hizalama, kenarlık yok. İlke şudur: bir varsayılan yalnızca güvenli ve şaşırtıcı olmadığı yerde sunulur; yanlış çıkarsamanın yanlış bir belge ürettiği yerde asla sunulmaz.

Bu sayfa, ilkeyi çekirdek genel API yüzeyinde (belge cephesi, sözleşme ve çıktı yolu) gösterir. Alt sistemlerin kendi giriş noktaları vardır ve her biri kendi doğrulama davranışını belgeler. Burada alıntılanan biçimler, bu inceleme itibarıyla günceldir. Bunlar deseni örnekler; motordaki her korumanın eksiksiz bir kataloğu değildir.

Açıklanan hızlı başarısız korumaları, doğruluk ve güvenlik korumalarıdır. Tek başlarına bir güvenlik sınırı değildirler. Girdi doğrulaması bir katmandır. tasarım felsefesi ve güvenlik belgeleri daha geniş duruşu açıklar.

  • NextPDF tasarım felsefesi — bu sayfada gösterilen ilkeyi öncelikler bağlamına yerleştirir.
  • Bir özellik olarak hatalar — bu korumaların fırlattığı türü tanımlı istisnaların size ne anlatmak için tasarlandığını açıklar.
  • Her yerde katı türler — tür sisteminin “niyetinizi belirtin” ilkesini tavsiye niteliğinde olmaktan çıkarıp zorunlu kılınabilir hâle nasıl getirdiğini gösterir.
  • Kod destekli (kanıt düzeyi) — iddiaları yalnızca açıklanmakla kalmayıp motorun kendi kaynağına veya çalıştırılabilir bir örneğe karşı denetlenip alıntılanan bir sayfa.
  • Hızlı başarısız — geçersiz bir girdiyi, devam edip daha sonra anlaşılmaz biçimde başarısız olmak yerine, en erken noktada açık bir nedenle reddetmek.
  • Adlandırılmış argüman — bir değeri bir parametreye adıyla bağlayan ve aksi hâlde belirsiz olan bir değişmezi kendini açıklayan hâle getiren bir PHP çağrı noktası sözdizimi (newLine: true).
  • Tek kullanımlık yaşam döngüsü — tek kullanımlık Document sözleşmesi: örnekle, yaz, kaydet, at. reset() yok, yeniden kullanım yok. Worker süreçleri, her istek için DocumentFactory aracılığıyla yeni bir örnek oluşturur.
  • PAdES — PDF Advanced Electronic Signatures, PDF imzalamaya yönelik ETSI profil ailesi. İlk kullanımda açılmıştır; imzalama sayfalarında ayrıntılı olarak ele alınmıştır.