ContentStream: مُصدِر دفق محتوى PDF
لمحة سريعة
قسم بعنوان «لمحة سريعة»تُصدِر وحدة ContentStream معاملات المحتوى المُعلَّم في تنسيق Portable Document Format (PDF). فهي تفتح وسوم البنية والأثريات وتغلقها، وتتعقّب عمق التداخل، وتُرجع المخزن المؤقت للمعاملات.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/core:^3نظرة مفاهيمية
قسم بعنوان «نظرة مفاهيمية»ContentStreamBuilder هو الصنف الوحيد في الوحدة. يبني هذا الصنف طبقة المحتوى المُعلَّم من دفق محتوى الصفحة. يُرمِّز دفق المحتوى محتوى الصفحة على هيئة سلسلة من المعاملات — ISO 32000-2 §8. ثم يُصدِر الباني معاملات المحتوى المُعلَّم حول ذلك المحتوى.
append() يُضيف بايتات المعاملات الخام حرفيًّا. ولا يهرّب الباني هذا المُدخَل؛ فأنت المسؤول عن صحّته. استخدم هذا الحدّ عندما يحتاج خط معالجة HTML ووحدة Graphics إلى تداخل معاملاتهما الخاصة.
beginTag() يفتح تسلسلًا مُعلَّمًا بوسم بنية. وهو يُصدِر معامل BDC مع قائمة خصائص MCID، وفقًا لـ ISO 32000-2 §14.6. ويُصدِر endTag() معامل EMC المُطابِق. كما يَعدّ الباني عمق التداخل. إذا استدعيتَ endTag() دون تسلسل مفتوح، فإنه يطرح PageLayoutException بدلًا من كتابة EMC غير متوازن.
beginArtifact() يفتح تسلسلًا أثريًّا. استخدم الأثريات لعناصر الترقيم الزخرفية — الترويسات والتذييلات وأرقام الصفحات والخطوط — التي يجب أن تبقى خارج شجرة البنية، وفقًا لـ ISO 32000-2 §14.8.2.2. النوع الفرعي إحدى أربع قيم في ISO: Pagination، أو Layout، أو Page، أو Background. فضِّل التعداد ArtifactSubtype المُحدَّد النوع. ويُتحقَّق من الحِمل الزائد النصّي مقابل التعداد، لذلك تفشل أي قيمة غير معيارية فورًا.
relabelTag() يُعيد كتابة وسم سبق إصداره في موضعه. finish() يُرجع المخزن المؤقت الكامل ويطرح استثناءً إذا كان المحتوى المُعلَّم غير متوازن. drain() يُرجع المخزن المؤقت حتى الآن دون فحص التوازن، من أجل البث التدريجي. peek() يُرجع المخزن المؤقت دون استهلاكه. reset() يمسح الحالة.
واجهة API
قسم بعنوان «واجهة API»| الطريقة | التوقيع | الدور |
|---|---|---|
append() | append(string $raw): void | يُضيف بايتات المعاملات الخام حرفيًّا (دون تهريب) |
beginTag() | beginTag(string $structType, int $mcid): void | يفتح تسلسل بنية BDC |
endTag() | endTag(): void | يُغلق التسلسل الأعمق بـ EMC |
beginArtifact() | beginArtifact(ArtifactSubtype|string $type): void | يفتح تسلسلًا أثريًّا |
endArtifact() | endArtifact(): void | يُغلق الأثري الأعمق |
getMarkedContentDepth() | getMarkedContentDepth(): int | يُرجع عمق التداخل الحالي |
relabelTag() | relabelTag(string $old, string $new, int $mcid): void | يُعيد كتابة وسم مُصدَر في موضعه |
finish() | finish(): string | يُرجع المخزن المؤقت الكامل؛ ويطرح استثناءً إذا كان غير متوازن |
drain() | drain(): string | يُرجع المخزن المؤقت دون فحص التوازن |
peek() | peek(): string | يُرجع المخزن المؤقت دون استهلاكه |
reset() | reset(): void | يمسح كل الحالة |
شغّل composer docs:generate-api-php -- --module=ContentStream لتوليد جدول PHPDoc الكامل.
مثال برمجي — بداية سريعة
قسم بعنوان «مثال برمجي — بداية سريعة»<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\ContentStream\ContentStreamBuilder;
$builder = new ContentStreamBuilder();
$builder->beginTag('P', mcid: 0);$builder->append("BT /F1 12 Tf 72 720 Td (Hello) Tj ET\n");$builder->endTag();
$pageContent = $builder->finish();مثال برمجي — للإنتاج
قسم بعنوان «مثال برمجي — للإنتاج»استخدم هذا النمط لتغليف فقرة بوسم بنية وتذييل بأثري. يبثّ النمط المخزن المؤقت تدريجيًّا عبر drain().
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Accessibility\ArtifactSubtype;use NextPDF\ContentStream\ContentStreamBuilder;
$builder = new ContentStreamBuilder();
$builder->beginTag('H1', mcid: 0);$builder->append($titleOperators);$builder->endTag();
$builder->beginArtifact(ArtifactSubtype::Pagination);$builder->append($footerOperators);$builder->endArtifact();
if ($builder->getMarkedContentDepth() !== 0) { throw new RuntimeException('Unbalanced marked content before flush.');}
$chunk = $builder->drain();الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»append()لا يهرّب المُدخَل. مرّر بايتات معاملات صالحة فقط؛ فالباني يثق بالمستدعي.endTag()وendArtifact()يطرحان استثناءً عند الجريان السفلي. لا تُغلق أبدًا تسلسلًا غير مفتوح.finish()يفحص التوازن ويطرح استثناءً عندما لا يكون العمق صفرًا.drain()لا يفحص. استخدمdrain()للبث التدريجي فقط.- عدّاد العمق لا يميّز الوسوم عن الأثريات.
EMCيُغلق التسلسل الأعمق من أيّ من النوعين. أدخِل التسلسلات بترتيب صارم. - يُتحقَّق من الحِمل الزائد النصّي لـ
beginArtifact()مقابل التعداد. النوع الفرعي غير المعياري يفشل عند الاستدعاء، لا في المُخرَج. relabelTag()يُعيد كتابة وسم مُصدَر. استخدم نفسmcidالذي استخدمته لإصداره.
الأداء
قسم بعنوان «الأداء»كل عملية هي إلحاق سلسلة بكلفة O(1)، باستثناء relabelTag()، الذي يُجري إعادة كتابة بكلفة O(buffer). تحتفظ الوحدة بمخزن سلاسل مؤقت واحد وعدّاد عمق صحيح واحد. وهي لا تُجري أي تحليل، ولا تُخصّص سوى المخزن المؤقت. ميزانية حِمل العمل المرجعي هي 1500 ms زمنًا و64 MB ذروةً. وتبقى هذه الوحدة أدنى من هذه الميزانية بكثير.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»append() هو حدّ الثقة. يكتب الباني البايتات حرفيًّا، لذا يجب على الكود الأعلى أن يهرّب أي سلسلة تصل إلى معامل سلسلة حرفية. المُهرِّب القياسي هو PdfStringEscaper::escapeLiteral() (ADR-015). لا تمرّر أبدًا نصًّا غير مُهرَّب من المستخدم عبر append(). تمنع فحوص التوازن في endTag() وendArtifact() وfinish() وصول شجرة محتوى مُعلَّم مشوّهة إلى Writer. راجع /modules/core/security/ للاطلاع على نموذج تهديد المستند.
المطابقة
قسم بعنوان «المطابقة»تُصدِر الوحدة emits بُنى معاملات محتوى مُعلَّم متوافقة مع ISO 32000-2: أزواج BDC/EMC مع قائمة خصائص MCID وفقًا لـ §14.6، وتسلسلات أثرية وفقًا لـ §14.8.2.2. هذه حقائق تنفيذية. الدليل هو src/ContentStream/ContentStreamBuilder.php، والتعداد src/Accessibility/ArtifactSubtype.php، وtests/Unit/ContentStream/ContentStreamBuilderMarkedContentBalanceCoverageTest إضافةً إلى ContentStreamBuilderRelabelTagInvariantTest. وهي ليست ادّعاءً بالمطابقة الشاملة من طرف إلى طرف لـ PDF/UA-2 أو PDF 2.0. يتحقق وسيط خارجي من بنية PDF الموسومة التي تشارك فيها هذه المعاملات: tests/Integration/Accessibility/VeraPdfUa2GoldenTest يفحص مُلحَقًا مُولَّدًا مقابل veraPDF لمواصفة PDF/UA-2. يتخطّى اختبار الوسيط ذاك skips when the veraPDF binary is absent، لذا فهو بوابة اختيارية. اذكر أن هذه الوحدة “produces marked-content structures; PDF/UA-2 conformance is validated by veraPDF” بدلًا من تأكيد مطابقة غير مشروطة.