Pro édition
AST — Référence détaillée
En un coup d’œil
Section intitulée « En un coup d’œil »Cette page est la référence détaillée du module AST de Pro. Elle couvre les surfaces publiques de build, cache, mutation, écriture et émission, leurs contrats de comportement et leurs modes de défaillance. Le module analyse un PDF chargé en un arbre AstDocument immuable, applique des mutations en mémoire journalisées et écrit des mises à jour incrémentales basées sur des overlays. AstDocument et AstNode sont des types valeur Core dans l’espace de noms NextPDF\Ast ; ce module les produit et les consomme.
Disponibilité et licence
Section intitulée « Disponibilité et licence »Cette fonctionnalité est livrée dans NextPDF Pro (nextpdf/pro) et s’active avec une enveloppe de licence de niveau Pro. Un déploiement sans ce droit ne charge pas les classes de la fonctionnalité. Compare les éditions et obtiens une licence.
Il n’existe aucun indicateur de licence par fonctionnalité. Il s’agit d’une fonctionnalité de l’édition Pro. Le comportement du build est entièrement régi par AstBuildOptions.
Surface d’API publique
Section intitulée « Surface d’API publique »| Symbole | Paramètres | Comportement par défaut | Renvoie | Lève ou échoue avec | Notes |
|---|---|---|---|---|---|
AstBuilder::__construct | PdfReader $reader, AstBuildOptions $options, ?AstCache $cache = null | Lie un reader chargé aux options de build ; le cache est optionnel | AstBuilder | — | Un cache null signifie que chaque appel à build() reconstruit. |
AstBuilder::build | string $sourceHash (hex SHA-256 complet des octets du PDF) | Consultation du cache, rejet du chiffrement, chemin de l’arbre de structure, repli untagged, attachement des bounding boxes, stockage en cache | AstDocument | AstUnsupportedEncryptionException, AstBuildLimitException, AstBuildTimeoutException | Un hit de cache renvoie sans réanalyse. |
AstBuildOptions::__construct | ?int $pageRangeStart = null, ?int $pageRangeEnd = null, int $maxNodes = 100_000, int $maxDepth = 200, ?int $estimatedTokenBudget = null, int $maxMemoryBytes = 268435456, float $timeoutSeconds = 30.0, bool $useHeuristic = false | Objet valeur de configuration immuable | AstBuildOptions | — | estimatedTokenBudget est une indication informative ; il n’est pas appliqué. |
AstBuildOptions::pageRangeContains | int $pageIndex | Vrai lorsque l’index base 0 tombe dans la plage configurée | bool | — | Les bornes null sont ouvertes ; les deux null signifient toutes les pages. |
AstBuildOptions::hash | — | SHA-256 stable sur toutes les valeurs d’options | string | — | Des valeurs égales produisent des hachages égaux entre instances ; utilisé comme segment de la clé de cache. |
AstCache::__construct | CacheInterface $backend | Encapsule n’importe quel backend PSR-16 | AstCache | — | — |
AstCache::buildKey | string $sourceHash, AstBuildOptions $options | Clé = nextpdf_ast_v1_ + les 32 premiers hex du hash source + _ + les 16 premiers hex du hash d’options | string | — | Les changements d’options invalident automatiquement les résultats en cache. |
AstCache::get | string $cacheKey | Décode une charge JSON via une validation stricte champ par champ | ?AstDocument | Ne lève jamais ; les échecs renvoient null | Les charges malformées ou falsifiées échouent en mode fermé comme un cache miss. |
AstCache::set | string $cacheKey, AstDocument $document | Stocke du JSON avec un TTL de 24 heures, puis vérifie par relecture immédiate | void | AstWriteVerificationException (espace de noms Exception) | Un échec d’écriture du backend ou un aller-retour raté lève. |
AstCache::delete | string $cacheKey | Suppression au mieux | void | Ne lève jamais | Les échecs de suppression du backend sont ignorés. |
AstCache::has | string $cacheKey | Vérification d’existence au mieux | bool | Ne lève jamais ; les échecs renvoient false | — |
AstMutator::updateNode | AstDocument $document, string $nodeId, array $updates | Remplace text_content, enregistre une entrée Updated | AstDocument (nouvelle instance) | InvalidArgumentException | Seule la clé text_content est appliquée ; les clés inconnues sont ignorées. |
AstMutator::deleteNode | AstDocument $document, string $nodeId | Supprime le nœud de l’arbre en mémoire, enregistre une entrée Deleted | AstDocument (nouvelle instance) | InvalidArgumentException | Suppression en mémoire uniquement ; voir la mise en garde sur le caviardage ci-dessous. |
AstMutator::getMutationLog | — | Renvoie l’instance de log partagée | MutationLog | — | Passe le même log à AstWriter. |
AstMutator::resetLog | — | Rejette toutes les mutations enregistrées | void | — | Démarre un nouveau log. |
MutationLog | record, all, isEmpty, count, forNode, mutatedNodeIds | Log en mémoire en ajout seul, ordre d’insertion préservé | selon la méthode | — | forNode renvoie l’entrée la plus récente pour un nœud ; la dernière entrée l’emporte. |
MutationEntry::__construct | string $nodeId, MutationType $type, ?AstNode $originalNode, ?AstNode $mutatedNode, DateTimeImmutable $timestamp | Enregistrement immuable d’une mutation | MutationEntry | — | originalNode est null pour Inserted ; mutatedNode est null pour Deleted. |
MutationType | cas d’enum Updated, Inserted, Deleted | Classification adossée à des chaînes | — | — | Deleted sous OVERLAY masque le contenu ; il n’efface pas les octets. |
AstWriter::write | string $originalPdfBytes, MutationLog $log | Ajoute une mise à jour incrémentale dont les flux d’overlay couvrent les bounding boxes mutées | string (octets PDF modifiés) | AstWriteException | Un log vide renvoie l’entrée inchangée. Les entrées Inserted et les entrées sans bounding box sont ignorées. |
AstWriter::writeAndVerify | string $originalPdfBytes, MutationLog $log | Exécute write(), puis un contrôle structurel de la sortie | string (octets PDF vérifiés) | AstWriteException, AstWriteVerificationException (espace de noms Writer) | La vérification est structurelle, pas sémantique. |
AstPdfEmitter::emit | AstNode $root, BinaryBuffer $buffer, ObjectRegistry $registry, array $pageObjects | Écrit un StructTreeRoot, une chaîne StructElem et un ParentTree pour l’arbre fourni | EmitResult | AstEmitException | La racine doit être un nœud Document avec des enfants. Émetteur aller-retour pour la vérification de l’arbre de structure. |
EmitResult::__construct | int $structTreeRootObject, int $rootElementObject, int $parentTreeObject, int $elementObjectCount, int $parentTreeNextKey | Enregistrement immuable des identifiants d’objets émis | EmitResult | — | — |
public function build(string $sourceHash): AstDocumentpublic function updateNode(AstDocument $document, string $nodeId, array $updates): AstDocumentpublic function deleteNode(AstDocument $document, string $nodeId): AstDocumentpublic function write(string $originalPdfBytes, MutationLog $log): stringpublic function writeAndVerify(string $originalPdfBytes, MutationLog $log): stringHiérarchie des exceptions
Section intitulée « Hiérarchie des exceptions »NextPDF\Pro\Ast\Exception\AstExceptionétendRuntimeException— base de la hiérarchie de build.AstBuildLimitExceptionétendAstException— un plafond de nœuds, de profondeur ou de mémoire a été dépassé.AstBuildTimeoutExceptionétendAstBuildLimitException— le délai de build en temps réel s’est écoulé.AstNoStructTreeExceptionétendAstException— aucun arbre de structure présent.AstBuilder::build()l’attrape en interne et se replie ; les appelants debuild()ne l’observent pas.AstUnsupportedEncryptionExceptionétendAstException— le PDF d’entrée est chiffré.NextPDF\Pro\Ast\Exception\AstWriteVerificationExceptionétendAstException— la vérification d’écriture du cache a échoué.NextPDF\Pro\Ast\Writer\AstWriteExceptionétendRuntimeException— échec d’entrée ou de structure du writer.NextPDF\Pro\Ast\Writer\AstWriteVerificationExceptionétendAstWriteException— la vérification structurelle post-écriture a échoué.
Deux classes AstWriteVerificationException distinctes existent dans des espaces de noms différents. AstCache::set() lève la classe de l’espace de noms Exception ; AstWriter::writeAndVerify() lève la classe de l’espace de noms Writer. Fais correspondre l’espace de noms dans les clauses catch.
Contrat de comportement
Section intitulée « Contrat de comportement »AstBuilder::build($sourceHash) requiert le hex SHA-256 complet des octets source. Le pipeline est : consultation optionnelle du cache, rejet du chiffrement, chemin de l’arbre de structure, repli untagged, attachement des bounding boxes, stockage optionnel en cache.
La clé de cache combine le hash source avec le hash AstBuildOptions. Le hash d’options est stable entre instances aux valeurs identiques, si bien que des entrées et des options identiques renvoient le même arbre. Lorsqu’aucun cache n’est fourni, chaque appel reconstruit. Les charges en cache sont du JSON, jamais de la sérialisation PHP native : le chemin de lecture valide chaque champ et n’instancie que des types valeur AST, si bien qu’une entrée de cache empoisonnée ne peut pas déclencher d’injection d’objet et se dégrade en cache miss.
Le chemin de l’arbre de structure s’exécute lorsqu’un arbre de structure est présent. Les plafonds de ressources — nombre de nœuds, profondeur, delta de mémoire et temps réel — sont appliqués pendant la lecture de l’arbre de structure et lèvent AstBuildLimitException ou AstBuildTimeoutException. Si le reader signale l’absence d’arbre de structure, le builder bascule vers le chemin untagged : le builder heuristique quand useHeuristic vaut true, sinon le builder de repli minimal. Les bounding boxes sont attachées en analysant le flux de contenu de chaque page dans la plage ; une page dont le flux de contenu ne peut être analysé est ignorée et laisse le reste de l’arbre intact.
AstNode est immuable. Les mises à jour de l’arbre reconstruisent les nœuds affectés de bas en haut ; les sous-arbres inchangés sont renvoyés par identité. AstMutator suit le même contrat : chaque mutation renvoie un nouveau AstDocument, ne reconstruit que le chemin racine-vers-cible et enregistre une MutationEntry dans le MutationLog partagé.
AstWriter applique un MutationLog en mode OVERLAY sous forme de mise à jour incrémentale en ajout seul : nouveaux flux de contenu d’overlay, objets de page mis à jour, une section de références croisées ne couvrant que les nouveaux objets et un trailer dont /Prev pointe vers le startxref précédent. Les octets d’origine sont laissés intacts, conformément au modèle de mise à jour incrémentale d’ISO 32000-2:2020, 7.5.6. Le texte de remplacement dessiné pour les entrées Updated échappe \, ( et ) dans les chaînes littérales, conformément à ISO 32000-2:2020, 7.3.4.2.
AstPdfEmitter::emit() est l’inverse symétrique de la lecture de l’arbre de structure : les arbres produits par le reader font un aller-retour vers des arbres structurellement équivalents, à la renumérotation des node-id et aux classes de canonicalisation documentées près. Les MCID présents sur les nœuds sont réémis à l’identique, jamais réalloués.
Cas limites et modes de défaillance
Section intitulée « Cas limites et modes de défaillance »- L’entrée chiffrée est rejetée avant tout travail sur l’arbre ; il n’y a pas de résultat d’arbre partiel pour les PDF chiffrés. Déchiffre d’abord.
- Plafonds de ressources : nombre max de nœuds (100,000 par défaut), profondeur max (200 par défaut), mémoire max (256 MiB par défaut), délai en temps réel (30 s par défaut). Dépasser un plafond lève
AstBuildLimitException; le délai lèveAstBuildTimeoutException, une sous-classe. - La plage de pages est en base 0 et inclusive ; les bornes null signifient toutes les pages.
- Une page dont le flux de contenu ne peut être analysé est ignorée pendant l’attachement des bounding boxes ; le reste de l’arbre n’est pas affecté.
AstCache::get()ne lève jamais : les charges malformées, falsifiées ou non-chaîne renvoient null et forcent une reconstruction.AstCache::set()échoue bruyamment lorsque l’écriture du backend ou la relecture immédiate échoue.AstMutatorlèveInvalidArgumentExceptionlorsque l’id de nœud est introuvable. Les clés de mise à jour inconnues sont silencieusement ignorées ; seuletext_contentest appliquée.AstWriter::write()lèveAstWriteExceptionlorsque l’entrée n’a pas d’en-tête%PDF-ou destartxreflocalisable. Les entrées sans bounding box sont ignorées silencieusement. Les pages introuvables par balayage d’objets — par exemple sous des flux de références croisées compressés — sont ignorées ; si aucun overlay ne peut être appliqué, les octets d’entrée sont renvoyés inchangés.- La sortie OVERLAY n’est pas du caviardage. Le rectangle blanc et le texte redessiné sont ajoutés ; les octets de contenu d’origine restent dans le fichier et sont récupérables par extraction brute. Ne l’utilise pas pour l’effacement au titre de l’art. 17 du RGPD ni pour un caviardage légal. Un writer en mode reconstruction existe dans l’arborescence source mais est marqué interne, n’est pas prêt pour la production et se situe hors de la surface d’API prise en charge.
- La géométrie de l’overlay suppose un A4 portrait (595 x 842 pt) car le writer ne lit pas la MediaBox de la page. Sur les pages non-A4, l’overlay peut être légèrement mal aligné ; la sortie reste structurellement valide.
writeAndVerify()ne contrôle que la structure : en-tête,%%EOFfinal et croissance de la sortie. Il ne réanalyse pas sémantiquement le document muté.AstPdfEmitter::emit()lèveAstEmitExceptionlorsque la racine n’est pas un nœud Document ou n’a pas d’enfants. Les entrées associées OBJR (annotation) ne sont pas émises dans cette version.- Ce module n’effectue aucune opération cryptographique et ne définit aucun comportement spécifique à FIPS. SHA-256 n’apparaît que comme adressage par contenu pour les clés de cache.
Conformité
Section intitulée « Conformité »Le chemin de l’arbre de structure lit les fonctionnalités de structure logique du PDF tagué définies par ISO 32000-2 ; le corpus RAG disponible au moment de la rédaction n’inclut pas les clauses de structure logique, de sorte que cette affirmation est fondée sur le produit à partir des annotations source. La disposition de mise à jour incrémentale du writer suit ISO 32000-2:2020, 7.5.6 (cité ci-dessous), et son échappement de chaînes littérales suit ISO 32000-2:2020, 7.3.4.2 (cité ci-dessous).
Ces affirmations décrivent la capacité par rapport aux clauses citées. NextPDF ne détient aucune certification de conformité, et la prise en charge d’une clause n’est pas une revendication de certification.
Notes de développement
Section intitulée « Notes de développement »- Compose un
AstBuilderparPdfReaderchargé. Réutilise unAstCacheentre les builds pour amortir l’analyse ; la conception des clés rend les changements d’options auto-invalidants. - Partage un
MutationLogentre unAstMutatoret l’AstWriterpour que le writer applique exactement la session enregistrée. AppelleresetLog()entre des sessions d’édition indépendantes. - Mets
useHeuristicà true pour les documents untagged lorsqu’un regroupement dérivé de la mise en page est préférable à l’arbre de repli minimal. - Les builds sont déterministes pour des octets et des options identiques ; appuie-toi là-dessus pour des tests de type snapshot.
- Attrape les échecs de build via la hiérarchie
NextPDF\Pro\Ast\Exceptionet les échecs d’écriture via la hiérarchieNextPDF\Pro\Ast\Writer; les deux ne partagent pas de base sousRuntimeException.
Limite de publication
Section intitulée « Limite de publication »Cette page documente uniquement le comportement observable de l’extérieur et la surface d’API publique prise en charge. Les chemins d’espaces de noms internes, les classes utilitaires, les tables de mécanismes, les noms de fichiers de runbook et les préfixes de tickets sont hors périmètre.