Pro الإصدار
Webview
لمحة سريعة
قسم بعنوان «لمحة سريعة»تُقدِّم Webview ملفّ PDF مُخطَّطًا خطّيًا (Fast Web View) عبر HTTP فيستطيع العميل بدءَ تصيير الصفحة 1 من بادئة أمامية صغيرة بينما بقيّة الملفّ ما زالت في الطريق. وهي تلفّ البايتات الخام بوصفها LinearizedDocument، وتجيب على طلبات Range باستجابات محتوى جزئي وفق RFC 9110 عبر ByteRangeResponder بنمط PSR-7، وتستطيع البرهنة (عبر FirstPageProber) على أنّ الصفحة الأولى مكتفية ذاتيًا داخل البادئة.
التوفّر والترخيص
قسم بعنوان «التوفّر والترخيص»تُشحَن هذه الإمكانية في NextPDF Pro (nextpdf/pro) وتُفعَّل بمظروف ترخيص من فئة Pro. ولا يُحمِّل أيُّ نشرٍ يفتقر إلى ذلك الاستحقاق أصنافَ هذه الإمكانية. قارِن الإصدارات واحصل على ترخيص.
ولا توجد علامة ترخيص منفصلة لكلّ ميزة. ويُوصَل المُجيب بمصانع PSR-17 الخاصّة بك في وقت التشغيل — ResponseFactoryInterface وStreamFactoryInterface — ونوعُ الوسيط يكون افتراضيًا application/pdf كوسيطٍ للبنّاء، لا مفتاحَ ترخيص.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/proتعيش الشيفرة ضمن النطاق الاسمي NextPDF\Pro\Webview.
نظرة مفاهيمية عامة
قسم بعنوان «نظرة مفاهيمية عامة»يُخطَّط ملفّ PDF خطّيًا بحيث تستقرّ الصفحة الأولى من المستند — قاموس معامِلات التخطيط الخطّي، وتدفّق التلميح الأساسي، وكائنات الصفحة 1 — في قسم أمامي ينتهي عند إزاحة /E. وتحوّل Webview ذلك التخطيط إلى تسليم تدريجي.
يحلّل LinearizedDocument::fromBytes() البايتات عبر LinearizationView القرائية في النواة (لا تعيد Pro أبدًا تنفيذ تحليل التخطيط الخطّي) ويرفض أيَّ شيء ليس مستندًا مُخطَّطًا خطّيًا قابلًا للاستخدام: غير مُخطَّط خطّيًا أصلًا، أو طول /L مُعلَن لا يطابق طول البايتات الحقيقي، أو إزاحة نهاية الصفحة الأولى /E ليست إزاحة موجبة داخل الملفّ. ولذلك يكون الإنشاء كلّيًّا — بمجرّد أن تمسك بـLinearizedDocument، تكون كلُّ إزاحة يكشفها موثوقة.
ثمّ يجيب ByteRangeResponder على طلب HTTP. وهو مُنفَّذ مقابل PSR-7 / PSR-17 فقط، من دون اقتران بأي إطار عمل. وهو يُعلِن دائمًا Accept-Ranges: bytes وETag قويًّا حتميًّا بصيغة SHA-256، ويحلّل ترويسة Range من العميل وفق RFC 9110 §14، ويُرجِع إمّا 200 OK كاملًا، أو نطاقًا واحدًا 206 Partial Content، أو استجابة 206 بنوع multipart/byteranges لعدّة نطاقات، أو 416 Range Not Satisfiable.
وFirstPageProber هو جانب البرهان البنيوي: فهو يُحدِّد كمّيًّا بادئة الصفحة الأولى، والكسر الذي تمثّله تلك البادئة من الملفّ كاملًا، وما إذا كان تدفّق التلميح الأساسي يقع بالكامل داخلها — وهي الخاصّية التي تتيح للقارئ تحديد موقع كائنات الصفحة 1 من البادئة وحدها.
لماذا يعمل بهذه الطريقة
قسم بعنوان «لماذا يعمل بهذه الطريقة»لا تعيد Webview أبدًا تحليلَ التخطيط الخطّي بنفسها. بل تستعير LinearizationView القرائية من النواة، فترث طبقةُ التسليم محلِّلًا واحدًا مُدقَّقًا بدلًا من نسخة ثانية آخذة في الانحراف. والإنشاء كلّيّ عن قصد. ويرفض LinearizedDocument::fromBytes() التخطيطَ المشوَّه مقدَّمًا، فكلُّ إزاحة تثق بها استجابةُ Range قد جرى التحقّق منها أوّلًا. ولا يتكلّم المُجيب سوى PSR-7 وPSR-17، فتُقدِّم الشيفرةُ نفسُها ملفَّ PDF مُخطَّطًا خطّيًا من أيّ مكدّس HTTP. وهذا الانضباط هو ما يجعل التسليم التدريجي بالنطاقات آمنًا لعرضه على عملاء غير موثوقين بكمّيات كبيرة.
خلفية التصميم: توليد المستندات عالي الحجم.
كيف يعمل التقديم التدريجي بنطاق البايتات
قسم بعنوان «كيف يعمل التقديم التدريجي بنطاق البايتات»- ابنِ
LinearizedDocument من بايتات PDF المُصيَّرة. ويُثير الإدخال غير الصالح UnsupportedDocumentException مقدَّمًا. - سلِّم المستندَ وطلبَ PSR-7 الوارد
ServerRequestInterface إلى ByteRangeResponder::respond(). ويقرأ المُجيب Range (والشرطَ المسبق الاختياري If-Range)، ويُنتِج ResponseInterface الصحيح بنمط PSR-7. - يطلب العميل البادئة الأمامية أوّلًا (أو تدفعها أنت بـ
firstPageResponse())، ويُصيِّر الصفحة 1، ثمّ يطلب النطاقات المتبقّية مع تمرير المستخدم.
يستخدم نموذج نطاق البايتات إزاحات شاملة وفق RFC 9110 §14.1.2: فـByteRange هو firstByte–lastByte على تمثيل لـcontentLength، وحقله Content-Range هو bytes first-last/length.
عقد السلوك
قسم بعنوان «عقد السلوك»-
LinearizedDocument::fromBytes() كلّيّ: مستندٌ غير مُخطَّط خطّيًا، أو عدمُ تطابق /L، أو إزاحة /E غير موجبة / خارج الملفّ، كلُّ واحدة منها تُثير UnsupportedDocumentException بدلًا من إنتاج مستند غير آمن. -
ETag هو وسم كيان SHA-256 قويّ على البايتات بالضبط، يُحفَظ مرّةً واحدةً عند الإنشاء. ويُنتِج إدخالُ تصييرٍ متطابق بايتاتٍ متطابقة وبالتالي ETag متطابقًا، فتتصرّف الذواكر المؤقّتة وIf-Range على نحو متوقَّع. - طلبٌ بلا
Range منطبق يُرجِع 200 OK بالجسم الكامل. وIf-Range لا يطابق ETag القويّ الحالي يتسبّب بتجاهل Range وإرجاع 200 كامل (RFC 9110 §13.1.5). ولا يُكرَّم إلّا شكلُ If-Range بوسم الكيان القويّ؛ ويُعامَل If-Range بتاريخ HTTP كعدم تطابق. - وحدة نطاق غير معروفة أو
Range غير صالح نحويًا يُتجاهَل ويُرجَع 200 كامل (RFC 9110 §14.2). - نطاق واحد قابل للإرضاء يُرجِع
206 Partial Content مع Content-Range؛ ونطاقات متعدّدة قابلة للإرضاء تُرجِع 206 بنوع multipart/byteranges. ونطاقات بايتات صالحة لا يُرضى أيٌّ منها تُرجِع 416 مع Content-Range: bytes */length (RFC 9110 §15.3.7). - يُصدِر
firstPageResponse() استجابة 206 تحمل بالضبط نطاق بايتات الصفحة الأولى [0, /E - 1] — وهو شكل الدفع من الخادم لـ«الصفحة الأولى قبل التنزيل الكامل».
مثال شيفرة — بداية سريعة
قسم بعنوان «مثال شيفرة — بداية سريعة»ما يلي يعكس واجهة برمجة التطبيقات العامة المُوثَّقة. ولا يشحن المستودع مثالًا قابلًا للتشغيل لهذه الوحدة.
use NextPDF\Pro\Webview\LinearizedDocument;use NextPDF\Pro\Webview\ByteRangeResponder;
$document = LinearizedDocument::fromBytes($pdfBytes);$responder = new ByteRangeResponder($responseFactory, $streamFactory);
$response = $responder->respond($document, $request);مثال شيفرة — دفع الصفحة الأولى والتحرّي
قسم بعنوان «مثال شيفرة — دفع الصفحة الأولى والتحرّي»use NextPDF\Pro\Webview\LinearizedDocument;use NextPDF\Pro\Webview\ByteRangeResponder;use NextPDF\Pro\Webview\FirstPageProber;use NextPDF\Pro\Webview\Exception\UnsupportedDocumentException;
try { $document = LinearizedDocument::fromBytes($pdfBytes);} catch (UnsupportedDocumentException $e) { // Not a usable linearized document — fall back to plain full delivery. // ... return;}
$prober = new FirstPageProber($document);if ($prober->isFirstPageSelfContained()) { // Push exactly the first page's bytes for an instant render. $response = (new ByteRangeResponder($responseFactory, $streamFactory)) ->firstPageResponse($document);}الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»- تتطلّب Webview ملفّ PDF مُخطَّطًا خطّيًا بالفعل. وإن لم يكن المستند المُصيَّر مُخطَّطًا خطّيًا، فعِّل التخطيط الخطّي وقت التصيير، أو قدِّمه بتسليم كامل بسيط — إذ يستطيع
respondToBytes() ما زال تقديمَ نطاقات على بايتات اعتباطية (غير مُخطَّطة خطّيًا) حين تحتاج دعمَ النطاقات فقط، لا دلالات الصفحة الأولى. - التحديثات التزايدية مهمّة: مستندٌ أُلحِق به بما يتجاوز طول
/L المُعلَن يُرفَض كعدم تطابق طول، لأنّ إزاحات نطاق البايتات لن تعود موثوقة. - يحدّ المُجيب عددَ النطاقات المتمايزة التي يكرّمها لكلّ طلب. وطلبٌ يطلب نطاقات مدموجة أكثر من الحدّ، أو بايتات إجمالية أكثر من التمثيل كاملًا، يُتجاهَل
Range الخاصّ به ويُقدَّم 200 كامل.
الأداء
قسم بعنوان «الأداء»بادئة الصفحة الأولى هي إزاحة نهاية الصفحة الأولى /E مُثبَّتة عند طول الملفّ، فيُبلِّغ FirstPageProber::prefixFraction() عن مدى صغر الجلب الأوّلي نسبةً إلى الملفّ كاملًا — ولمستند متعدّد الصفحات هذا هو المغزى كلُّه من Fast Web View. ويقطّع بناءُ الاستجابة سلسلةَ البايتات في الذاكرة؛ والكلفة متناسبة مع البايتات المُنتقاة. ويُحسَب ETag مرّةً واحدةً لكلّ مستند. قِس بمستندات تمثيلية.
ملاحظات الأمان
قسم بعنوان «ملاحظات الأمان»عامِل الإدخال على أنّه غير موثوق. ويتحقّق LinearizedDocument::fromBytes() من ثوابت التخطيط الخطّي قبل استخدام أي إزاحة. ويرفض المُجيب contentType يحتوي على محارف تحكُّم لمنع حقن الترويسات، ويشتقّ حدًّا فاصلًا متعدّد الأجزاء مضمونًا ألّا يظهر داخل الجسم، ويدمج النطاقات المتداخلة ويحدّ عددها وحجمها الإجمالي للدفاع عن صنف حرمان الخدمة بتضخيم النطاق متعدّد الأجزاء (Apache HTTPD CVE-2011-3192). ولا تُسجِّل هذه الوحدة أيَّ محتوى مستند.
المطابقة
قسم بعنوان «المطابقة»يتبع تسليم نطاق البايتات RFC 9110 (HTTP Semantics) — §14 لطلبات النطاق، و§13.1.5 لـIf-Range، و§15.3.7 لـ416. ونموذج المستند المُخطَّط خطّيًا هو تخطيط Fast Web View الموصوف في ISO 32000-2 Annex F. ولا تؤكّد الوحدة أي مُعرِّفات بنود خارجية إضافية تتجاوز السلوك الذي تتحقّق منه اختباراتها.
ملاحظة حدّ Enterprise
قسم بعنوان «ملاحظة حدّ Enterprise»لا يُغيِّر Enterprise سلوك Webview. ويضيف Enterprise ميزات مطابقة وأرشفة أعلى طبقةً موثَّقة بصورة منفصلة؛ وهي ليست مطلوبة لتقديم ملفّ PDF مُخطَّط خطّيًا عبر نطاقات بايتات.
حدّ النشر
قسم بعنوان «حدّ النشر»توثِّق هذه الصفحة السلوكَ القابل للرصد خارجيًا وسطحَ واجهة برمجة التطبيقات العامة المدعوم فقط. أمّا مسارات النطاقات الاسمية الداخلية، والأصناف المساعِدة، وجداول الآليات، وأسماء ملفّات كتيّبات التشغيل، وبادئات التذاكر فخارجة عن النطاق.