Перейти к содержимому

Пользовательские движки макета и перехват текста на этапе макета

NextPDF не предоставляет подключаемый интерфейс движка макета. Используйте публичный контракт расширения макета — TextPreprocessorInterface, — чтобы работать с текстом на этапе макета. События жизненного цикла содержимого позволяют наблюдать за тем, из чего формируется макет.

Окно терминала
composer require nextpdf/core:^3

Pipeline макета является внутренним. Он охватывает раскладку глифов, формирование подмножества шрифта, вывод ToUnicode CMap и дерево структуры. NextPDF не позволяет заменить его. Стабильный побайтовый вывод и соответствие требованиям tagged-PDF зависят от единой контролируемой сборки.

NextPDF всё же предоставляет точку перед макетом: TextPreprocessorInterface. Реализация получает необработанный текст и возвращает сегментированный результат до того, как текст попадает в раскладку глифов, формирование подмножества шрифта, ToUnicode CMap или дерево структуры. Используйте этот поддерживаемый путь, чтобы менять текстовое содержимое, не затрагивая движок макета.

Исходный PHPDoc задаёт жёсткое правило: реализация не должна менять работу макета. Она не должна добавлять символы, влияющие на макет, такие как перевод строки, возврат каретки или табуляция, и должна сохранять логический порядок чтения. Препроцессор заявляет подмену содержимого; он не принимает решений о макете. Соблюдайте это правило, иначе стабильность вывода и доступность будут нарушены.

Чтобы наблюдать за результатом макета, а не менять его, используйте события жизненного цикла содержимого из раздела “Триггеры действий и обработчики событий”. ContentRenderedEvent срабатывает после отрисовки содержимого на странице. FontLoadedEvent срабатывает один раз для каждого семейства и начертания шрифта.

NextPDF\Contracts\TextPreprocessorInterface (стабильный, начиная с 1.9.0):

МетодВозвращаетНазначение
process(string $text)TextPreprocessResultПреобразует необработанный текст перед pipeline отрисовки и возвращает сегментированный результат с метаданными редактирования.

Возвращаемый NextPDF\Contracts\TextPreprocessResult — замороженный объект-значение. Сигнатура его конструктора и публичные свойства стабильны и не меняются в минорных или патч-выпусках. Новые методы могут добавляться.

Небольшой препроцессор ниже маскирует фиксированный токен. Он не добавляет символов, влияющих на макет, и сохраняет порядок чтения.

<?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),
]);
}
}

Production-препроцессор хранит правила сопоставления в одном месте. При некорректном шаблоне он отказывает безопасно и никогда не записывает исходный текст в журнал.

<?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() выполняется один раз для каждого текстового фрагмента на горячем пути макета. Держите потребление памяти низким. Компилируйте шаблоны один раз в конструкторе, а не при каждом вызове. События жизненного цикла содержимого ничего не стоят, когда к ним не привязан ни один обработчик.

Используйте TextPreprocessorInterface, чтобы удалять конфиденциальное содержимое до того, как оно попадёт в поток содержимого, подмножества шрифтов или метаданные. Поскольку он выполняется до формирования подмножества и ToUnicode CMap, отредактированные глифы никогда не попадают в файл. Считайте сбой препроцессора отказом в безопасную сторону и возвращайте пустой или маскированный текст вместо исходного.

Эта страница не содержит нормативных заявлений о подписании или архивировании. Правило порядка чтения согласует контракт с требованиями tagged-PDF. Справочник по доступности охватывает соответствие на уровне тегов.

NextPDF Pro предоставляет production-ready стратегии предобработки текста, включая редактирование персональных данных (PII), настроенное под распространённые типы документов. В Core вы пишете TextPreprocessorInterface самостоятельно или используете проверенную сборку платной редакции через тот же публичный контракт.

Глоссарий определяет термины препроцессор текста и точка расширения; канонические определения приведены в опубликованном глоссарии.