ข้ามไปยังเนื้อหา

เลย์เอาต์เอนจินแบบกำหนดเองและการดักจับข้อความขณะทำเลย์เอาต์

NextPDF ไม่ได้เปิดเผยอินเทอร์เฟซสำหรับเลย์เอาต์เอนจินแบบเสียบเพิ่มได้ ให้ใช้สัญญาส่วนขยายเลย์เอาต์สาธารณะ TextPreprocessorInterface เพื่อดักจับข้อความขณะทำเลย์เอาต์ อีเวนต์วงจรชีวิตของเนื้อหาช่วยให้สังเกตสิ่งที่เลย์เอาต์สร้างขึ้นได้

Terminal window
composer require nextpdf/core:^3

ไปป์ไลน์เลย์เอาต์เป็นส่วนภายใน ไปป์ไลน์นี้ครอบคลุมการจัดวางกลิฟ การสร้างชุดย่อยฟอนต์ การส่งออก ToUnicode CMap และต้นไม้โครงสร้าง NextPDF ไม่อนุญาตให้แทนที่ไปป์ไลน์นี้ ผลลัพธ์ระดับไบต์ที่เสถียรและความสอดคล้องกับ tagged-PDF ขึ้นอยู่กับบิลด์เดียวที่มีการควบคุม

NextPDF เปิดเผย จุด ก่อน เลย์เอาต์: TextPreprocessorInterface พรีโปรเซสเซอร์จะรับข้อความดิบและคืนค่าผลลัพธ์ที่แบ่งเป็นเซกเมนต์ก่อนที่ข้อความนั้นจะเข้าสู่การจัดวางกลิฟ การสร้างชุดย่อยฟอนต์ การส่งออก ToUnicode CMap หรือการสร้างต้นไม้โครงสร้าง ใช้เส้นทางที่รองรับนี้เพื่อเปลี่ยนเนื้อหาข้อความโดยไม่ต้องแตะเลย์เอาต์เอนจิน

PHPDoc ของซอร์สกำหนดกฎไว้อย่างเคร่งครัด: อิมพลีเมนต์ ต้องไม่ เปลี่ยนพฤติกรรมของเลย์เอาต์ อิมพลีเมนต์ต้องไม่เพิ่มอักขระที่ส่งผลต่อเลย์เอาต์ เช่น line feed, carriage return หรือ tab และต้องรักษาลำดับการอ่านเชิงตรรกะไว้ พรีโปรเซสเซอร์ระบุการแทนที่เนื้อหา แต่ไม่ได้ตัดสินเลย์เอาต์ ต้องปฏิบัติตามกฎนี้ มิฉะนั้นผลลัพธ์ที่เสถียรและความสามารถในการเข้าถึงจะเสียหาย

หากต้องการสังเกตผลลัพธ์ของเลย์เอาต์แทนการเปลี่ยนแปลง ให้ใช้อีเวนต์วงจรชีวิตของเนื้อหาใน ทริกเกอร์การกระทำและตัวรับฟังอีเวนต์ ContentRenderedEvent จะถูกส่งหลังจากที่เนื้อหาถูกวาดลงบนหน้า FontLoadedEvent จะถูกส่งหนึ่งครั้งต่อตระกูลฟอนต์และสไตล์

NextPDF\Contracts\TextPreprocessorInterface (เสถียรตั้งแต่ 1.9.0):

เมท็อดคืนค่าวัตถุประสงค์
process(string $text)TextPreprocessResultแปลงข้อความดิบก่อนไปป์ไลน์การเรนเดอร์ และคืนค่าผลลัพธ์ที่แบ่งเป็นเซกเมนต์พร้อมเมทาดาทาของการปกปิด

ผลลัพธ์ NextPDF\Contracts\TextPreprocessResult ที่คืนค่ามาคือวัตถุค่าแบบตรึง ลายเซ็นของคอนสตรักเตอร์และพรอเพอร์ตีสาธารณะของวัตถุนี้มีความเสถียรและจะไม่เปลี่ยนแปลงในรีลีสแบบ minor หรือ patch อาจเพิ่มเมท็อดใหม่ได้

ตัวอย่างพรีโปรเซสเซอร์ขนาดเล็กด้านล่างนี้ปิดบังโทเค็นแบบคงที่ พรีโปรเซสเซอร์นี้ไม่เพิ่มอักขระที่ส่งผลต่อเลย์เอาต์และรักษาลำดับการอ่านไว้

<?php
declare(strict_types=1);
use NextPDF\Contracts\TextPreprocessorInterface;
use NextPDF\Contracts\TextPreprocessResult;
use NextPDF\Contracts\TextSegment;
final class TokenMaskingPreprocessor implements TextPreprocessorInterface
{
public function process(string $text): TextPreprocessResult
{
$masked = \str_replace('SECRET-TOKEN', '••••••••••••', $text);
return new TextPreprocessResult([
new TextSegment($masked, redacted: $masked !== $text),
]);
}
}

พรีโปรเซสเซอร์ระดับโปรดักชันเก็บกฎการจับคู่ไว้ที่เดียว พรีโปรเซสเซอร์นี้จะล้มเหลวแบบปิด (fail closed) เมื่อพบแพตเทิร์นที่ไม่ถูกต้อง และไม่บันทึกข้อความต้นฉบับลงล็อกโดยเด็ดขาด

<?php
declare(strict_types=1);
use NextPDF\Contracts\TextPreprocessorInterface;
use NextPDF\Contracts\TextPreprocessResult;
use NextPDF\Contracts\TextSegment;
use Psr\Log\LoggerInterface;
final class PatternRedactionPreprocessor implements TextPreprocessorInterface
{
/**
* @param non-empty-string $pattern A valid PCRE pattern for sensitive spans
*/
public function __construct(
private readonly string $pattern,
private readonly LoggerInterface $logger,
) {}
public function process(string $text): TextPreprocessResult
{
$result = \preg_replace($this->pattern, '[REDACTED]', $text);
if ($result === null) {
// Fail closed: never emit unredacted text on a pattern error.
$this->logger->error('Redaction pattern failed; substituting empty text');
return new TextPreprocessResult([new TextSegment('', redacted: true)]);
}
return new TextPreprocessResult([
new TextSegment($result, redacted: $result !== $text),
]);
}
}
  • ไม่มีการแทนที่เลย์เอาต์ ไม่สามารถแทนที่การจัดวางกล่อง การตัดบรรทัด หรือการแบ่งหน้าผ่านสัญญานี้ การเสียบเลย์เอาต์เอนจินของผู้พัฒนาภายนอกถูกออกแบบให้อยู่นอกขอบเขต
  • การบังคับใช้กฎ หากเพิ่ม \n \r หรือ \t ใน process() จะทำให้เลย์เอาต์เสียหายและทำลายผลลัพธ์ที่เสถียร เอนจินเชื่อถือตามกฎนี้และจะไม่ตรวจสอบผลลัพธ์ซ้ำเพื่อหาอักขระที่ส่งผลต่อเลย์เอาต์
  • ลำดับการอ่าน หากจัดเรียงเซกเมนต์ใหม่ จะทำลายลำดับการอ่านของ tagged-PDF และความสอดคล้องกับ PDF/UA
  • ความรับผิดชอบเดียว พรีโปรเซสเซอร์มีหน้าที่ระบุการแทนที่เนื้อหา ใช้อีเวนต์วงจรชีวิตเพื่อเฝ้าสังเกต และอย่าส่งผลข้างเคียงผ่าน process()

process() ทำงานหนึ่งครั้งต่อหนึ่ง text run บน hot path ของเลย์เอาต์ ควบคุมการใช้หน่วยความจำให้ต่ำ คอมไพล์แพตเทิร์นหนึ่งครั้งในคอนสตรักเตอร์ ไม่ใช่ในการเรียกแต่ละครั้ง อีเวนต์วงจรชีวิตของเนื้อหาไม่มีต้นทุนใด ๆ เมื่อไม่มีตัวรับฟังผูกไว้

ใช้ TextPreprocessorInterface เพื่อลบเนื้อหาอ่อนไหวออก ก่อน ที่เนื้อหานั้นจะไปถึงสตรีมเนื้อหา ชุดย่อยฟอนต์ หรือเมทาดาทา เนื่องจากทำงานก่อนการสร้างชุดย่อยและ ToUnicode CMap กลิฟที่ถูกปกปิดจึงไม่ถูกใส่ลงในไฟล์เลย จัดการความล้มเหลวของพรีโปรเซสเซอร์แบบ fail-closed และส่งออกข้อความว่างหรือข้อความที่ปิดบังแล้วแทนข้อความต้นฉบับ

หน้านี้ไม่ได้ระบุการอ้างอิงเชิงบรรทัดฐานเกี่ยวกับการลงนามหรือการจัดเก็บถาวร กฎลำดับการอ่านทำให้สัญญาสอดคล้องกับข้อกำหนดของ tagged-PDF เอกสารอ้างอิงด้านความสามารถในการเข้าถึงครอบคลุมความสอดคล้องในระดับแท็ก

NextPDF Pro มีกลยุทธ์การประมวลผลข้อความเบื้องต้นระดับโปรดักชัน รวมถึงการปกปิดข้อมูลที่ระบุตัวบุคคลได้ (PII) ที่ปรับแต่งสำหรับประเภทเอกสารทั่วไป ใน Core ผู้พัฒนาเขียน TextPreprocessorInterface ด้วยตัวเอง หรือใช้บิลด์แบบชำระเงินที่ผ่านการตรวจสอบแล้วผ่านสัญญาสาธารณะเดียวกัน

อภิธานศัพท์ให้คำนิยามของ text preprocessor และ extension point โปรดดูอภิธานศัพท์ที่เผยแพร่สำหรับคำนิยามมาตรฐานของแต่ละคำ