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

Pro รุ่น

Webview — การอ้างอิงเชิงลึก

หน้านี้บันทึกพื้นผิว NextPDF\Pro\Webview สาธารณะ แบบจำลองคำขอ/การตอบกลับแบบ byte-range และโหมดความล้มเหลวที่แน่ชัดที่เกินกว่าหน้าแลนดิ้งสาธารณะ

ความสามารถนี้มาพร้อมกับ NextPDF Pro (nextpdf/pro) และเปิดใช้งานด้วย license envelope ระดับ Pro การนำไปใช้งานที่ไม่มีสิทธิ์ดังกล่าวจะไม่โหลดคลาสของความสามารถนี้ เปรียบเทียบรุ่นและรับสิทธิ์การใช้งาน

ไม่มีแฟล็กสิทธิ์การใช้งานต่อฟีเจอร์ โค้ดมาพร้อมกับรุ่น Pro ส่วน PSR-17 ResponseFactoryInterface / StreamFactoryInterface และชนิดสื่อของเนื้อหาเป็นพารามิเตอร์ของ constructor ในขณะรัน ไม่ใช่กลไกควบคุมการอนุญาตสิทธิ์

Terminal window
composer require nextpdf/pro

ชนิดสาธารณะภายใต้ NextPDF\Pro\Webview:

  • LinearizedDocument — PDF ที่ผ่าน linearized ซึ่งตรวจสอบแล้วและเตรียมพร้อมสำหรับการส่งมอบ
  • ByteRangeResponder — ตัวตอบกลับ HTTP แบบ byte-range ตาม RFC 9110
  • ByteRange — ช่วงไบต์แบบ inclusive ที่ตอบสนองได้หนึ่งช่วงเหนือการแทนเอกสาร
  • FirstPageProber — การพิสูจน์เชิงโครงสร้าง “หน้าแรกก่อนดาวน์โหลดเต็ม”

ชนิดข้อยกเว้นภายใต้ NextPDF\Pro\Webview\Exception:

  • WebviewException (marker interface), UnsupportedDocumentException, RangeNotSatisfiableException

คลาส final readonly ที่มี constructor แบบ private ให้สร้างอินสแตนซ์ผ่าน named constructor

  • static fromBytes(string $bytes): self — แจงไบต์ผ่าน LinearizationView::fromPdf() ฝั่งอ่านของ Core ยก UnsupportedDocumentException เมื่อเอกสารไม่ได้ linearized เมื่อ /L ที่ประกาศไว้ไม่ตรงกับความยาวไบต์จริง หรือเมื่อออฟเซ็ตจบหน้าแรก /E ไม่ใช่ออฟเซ็ตค่าบวกภายในไฟล์
  • length(): int — ความยาวของเอกสารเป็นไบต์
  • firstPagePrefixLength(): int — prefix ส่วนต้นน้อยที่สุดที่บรรจุหน้าแรกครบถ้วน นั่นคือออฟเซ็ต /E ที่ถูกจำกัดให้ไม่เกินความยาวไฟล์
  • firstPageByteRange(): ByteRange — ช่วงแบบ inclusive [0, /E - 1] ที่ส่งมอบหน้าแรก ยก RangeNotSatisfiableException เฉพาะเมื่อ prefix ว่างเปล่าเท่านั้น (defence-in-depth โดย fromBytes() รับประกัน 0 < /E <= length ไว้แล้ว)
  • slice(int $firstByte, int $lastByte): string — การ slice เชิงโปรแกรมแบบเข้มงวดด้วยออฟเซ็ต inclusive ยก RangeNotSatisfiableException เมื่ออยู่นอกขอบเขต
  • etag(): string — strong SHA-256 entity-tag ที่กำหนดได้แน่นอนสำหรับไบต์ ถูก memoise ครั้งเดียวตอนสร้าง

คุณสมบัติสาธารณะแบบ readonly: bytes (ไบต์ PDF ดิบ) และ view (Core LinearizationView)

คลาส final readonly ที่อิมพลีเมนต์เทียบกับ PSR-7 / PSR-17 เท่านั้น

  • __construct(ResponseFactoryInterface $responses, StreamFactoryInterface $streams, string $contentType = 'application/pdf') — ยก InvalidArgumentException เมื่อ $contentType มีอักขระควบคุม (เนื่องจากมันถูกแทรกเข้าไปในเฮดเดอร์ของการตอบกลับและของ multipart part จึงปฏิเสธ CR/LF และไบต์ควบคุมอื่น ๆ เพื่อป้องกัน header injection)
  • respond(LinearizedDocument $document, ServerRequestInterface $request): ResponseInterface — ตอบคำขอช่วงสำหรับเอกสาร linearized โดยใช้ ETag ของเอกสารเอง
  • respondToBytes(string $bytes, ServerRequestInterface $request, ?string $etag = null): ResponseInterface — ตอบคำขอช่วงสำหรับไบต์ใด ๆ (การแทนเอกสารที่ควรรองรับช่วงโดยไม่ต้องผ่าน linearized) ETag จะถูกอนุมานจากไบต์เมื่อเป็น null
  • firstPageResponse(LinearizedDocument $document): ResponseInterface — สร้าง 206 ที่บรรจุช่วงไบต์ของหน้าแรกพอดี ซึ่งเป็นรูปแบบ server-push ของ “หน้าแรกก่อนดาวน์โหลดเต็ม”

ออบเจกต์ค่า final readonly สำหรับช่วงไบต์แบบ inclusive ที่ตอบสนองได้หนึ่งช่วง (RFC 9110 §14.1.2)

  • __construct(int $firstByte, int $lastByte, int $contentLength) — บังคับใช้ความสามารถในการตอบสนอง 0 <= firstByte <= lastByte <= contentLength - 1 มิฉะนั้นยก RangeNotSatisfiableException
  • length(): int — ช่วงแบบ inclusive (lastByte - firstByte + 1) มีค่า >= 1 เสมอ
  • contentRange(): string — ค่าฟิลด์ Content-Range ตาม RFC 9110 §14.4 คือ bytes first-last/length

คุณสมบัติสาธารณะแบบ readonly: firstByte, lastByte, contentLength

คลาส final readonly ที่สร้างจาก LinearizedDocument

  • prefixLength(): int — จำนวนไบต์ส่วนต้นน้อยที่สุดที่จำเป็นต่อการเรนเดอร์หน้าแรก
  • prefixFraction(): float — สัดส่วนของไฟล์ทั้งไฟล์ (0.0–1.0) ที่ prefix แทน คืนค่า 1.0 สำหรับไฟล์ที่มีความยาวเป็นศูนย์
  • hintStreamWithinPrefix(): bool — ว่าออบเจกต์ hint stream หลักอยู่ภายใน prefix ของหน้าแรกครบถ้วนหรือไม่ (เพื่อให้ prefix เพียงอย่างเดียวให้โปรแกรมอ่านระบุตำแหน่งออบเจกต์ของหน้าที่ 1 ได้) hint stream ต้องมีความยาวเป็นค่าบวก
  • isFirstPageSelfContained(): bool — การพิสูจน์เชิงโครงสร้างแบบรวม นั่นคือ prefix ค่าบวกที่พอดีภายในไฟล์และบรรจุ hint stream ครบถ้วน

ByteRangeResponder เป็นไปตาม RFC 9110 §14 หลังจากคำนวณความยาวและ strong SHA-256 ETag แล้ว มันอ่านเฮดเดอร์ Range และ If-Range แล้วตัดสินใจดังนี้:

ConditionStatusNotes
ไม่มี Range ที่ใช้ได้ หรือ If-Range ไม่ตรงกับ strong ETag ปัจจุบัน200 OKเนื้อหาเต็ม เฉพาะรูปแบบ strong entity-tag ของ If-Range เท่านั้นที่ได้รับการยอมรับ (RFC 9110 §13.1.5)
หน่วยช่วงที่ไม่รู้จัก หรือ Range ที่ไม่ถูกต้องตามไวยากรณ์200 OKเฮดเดอร์ถูกเพิกเฉย (RFC 9110 §14.2)
ช่วงเดียวที่ตอบสนองได้206 Partial Contentบรรจุ Content-Range
หลายช่วงที่ตอบสนองได้206 Partial Contentmultipart/byteranges พร้อม boundary ที่อนุมานขึ้น
ช่วงไบต์ที่ถูกต้อง แต่ไม่มีช่วงใดตอบสนองได้416 Range Not Satisfiableบรรจุ Content-Range: bytes */length (RFC 9110 §15.3.7)

ทุกการตอบกลับจะประกาศ Accept-Ranges: bytes และ strong ETag การตอบกลับ 200 และ 206 ยังตั้งค่า Content-Type และ Content-Length ด้วย

การแจงช่วงรับเฉพาะหน่วย bytes= เท่านั้น มันรองรับ first-last แบบชัดเจน, first- แบบปลายเปิด (ถูกจำกัดให้สิ้นสุดที่ปลายไฟล์) และ suffix -N (N ไบต์สุดท้าย โดย suffix ที่ใหญ่อย่างน้อยเท่ากับการแทนเอกสารจะเลือกทั้งหมด) - เปล่า ๆ (หรือสเปกที่ผิดรูปแบบในลักษณะอื่น) ทำให้เฮดเดอร์ Range ทั้งหมดไม่ถูกต้องตามไวยากรณ์ เฮดเดอร์จึงถูกเพิกเฉยและคืนค่าการแทนเอกสารแบบ 200 OK เต็ม suffix -0 หรือสเปกใดที่ออฟเซ็ตแรกอยู่ที่ปลายไฟล์หรือเลยไป เป็นสเปกที่ตอบสนองไม่ได้และถูกทิ้ง หากไม่มีสเปกใดในเฮดเดอร์ที่ตอบสนองได้ การตอบกลับคือ 416 Range Not Satisfiable ออฟเซ็ตทศนิยมขนาดใหญ่ถูกเปรียบเทียบโดยไม่พึ่งพา integer-overflow saturation ดังนั้นค่า Range 30 หลักจึงถูกจัดการแบบไม่ขึ้นกับแพลตฟอร์ม ช่วงที่ตอบสนองได้และทับซ้อนกันจะถูกรวมก่อนที่จะสร้างเนื้อหาใด ๆ ส่วนช่วงที่แตกต่างกันอย่างแท้จริง (ไม่ทับซ้อน) จะถูกรักษาไว้เป็น multipart part แยกกัน

WebviewException เป็น marker interface ที่ขยายจาก Throwable ให้ catch มันเพื่อจัดการทั้งระบบย่อยอย่างเป็นเอกภาพ ข้อยกเว้นรูปธรรมทั้งสองอิมพลีเมนต์มัน

  • UnsupportedDocumentException (ขยายจาก InvalidArgumentException) — ยกโดย LinearizedDocument::fromBytes() เมื่อไบต์ไม่ใช่เอกสาร linearized ที่ใช้งานได้ named constructor ได้แก่ notLinearized() (ไม่มีพจนานุกรมพารามิเตอร์ /Linearized), lengthMismatch($declaredLength, $actualLength) (/L ที่ประกาศไว้ไม่ตรงกับความยาวจริง ไม่ว่าจะถูกตัดทอน ถูกผนวกเกิน /L ผ่านการอัปเดตแบบ incremental หรือไม่เป็นไปตามข้อกำหนด) และ malformedFirstPageOffset($firstPageEndOffset, $length) (ออฟเซ็ต /E ไม่ใช่ออฟเซ็ตค่าบวกภายในไฟล์)
  • RangeNotSatisfiableException (ขยายจาก OutOfRangeException) — ข้อผิดพลาดของการ slice เชิงโปรแกรม ยกโดย ByteRange::__construct() และ LinearizedDocument::slice() / firstPageByteRange() เมื่อช่วงแบบ inclusive ตกอยู่นอกเอกสาร named constructor: outOfBounds($firstByte, $lastByte, $length)

ตัวตอบกลับ HTTP จะ ไม่ ยก RangeNotSatisfiableException สำหรับเฮดเดอร์ Range ของไคลเอนต์ ช่วง HTTP ที่ตอบสนองไม่ได้คือ การตอบกลับ 416 (RFC 9110 §15.3.7) ไม่ใช่ข้อยกเว้น ข้อยกเว้นนั้นถูกสงวนไว้สำหรับการ slice เชิงโปรแกรมโดยตรง ซึ่งคำขอที่อยู่นอกขอบเขตเป็นความผิดพลาดของผู้เรียกใช้ ByteRangeResponder::__construct() ยก InvalidArgumentException ธรรมดา (ไม่ใช่ WebviewException) เมื่อ contentType ที่กำหนดค่าไว้มีอักขระควบคุม

ตัวตอบกลับจำกัดจำนวนช่วงที่ถูกรวมและแตกต่างกันที่ยอมรับต่อคำขอ (ประเภท multipart range-amplification คือ Apache HTTPD CVE-2011-3192) เมื่อคำขอขอช่วงที่รวมกันแล้วมากกว่าเพดาน หรือขอจำนวนไบต์รวมมากกว่าการแทนเอกสารทั้งหมด Range จะถูกเพิกเฉยและคืนค่า 200 แบบเต็ม multipart boundary ถูกอนุมานแบบกำหนดได้แน่นอนและถูกอนุมานใหม่จนกว่าจะรับประกันได้ว่าจะไม่ปรากฏภายในเนื้อหา ซึ่งรักษาเอาต์พุตที่ทำซ้ำได้ในขณะที่ตัดความเป็นไปได้ของการชนกันของ boundary ออกไป

พฤติกรรมแบบ byte-range เป็นไปตาม RFC 9110 (HTTP Semantics) ได้แก่ §14 (คำขอช่วง), §13.1.5 (If-Range), §14.4 (Content-Range) และ §15.3.7 (416) การจัดวางเอกสาร linearized คือแบบจำลอง Fast Web View ของ ISO 32000-2 Annex F โมดูลนี้ไม่ยืนยันตัวระบุข้อกำหนดภายนอกเพิ่มเติมใดนอกเหนือจากพฤติกรรมที่การทดสอบของมันตรวจสอบยืนยันแล้ว

  • respondToBytes() ให้บริการช่วงเหนือไบต์ใด ๆ เมื่อไม่ต้องการความหมายเชิงหน้าแรก
  • ตัวตรวจสอบความถูกต้อง If-Range แบบ HTTP-date จะถูกถือว่าไม่ตรงกัน → 200 แบบเต็ม (ไคลเอนต์เพียงดึงข้อมูลใหม่)
  • ETag เป็นแฮช SHA-256 ที่ใช้เป็นตัวตรวจสอบความถูกต้องของแคชแบบ strong ล้วน ๆ โมดูลนี้ไม่ทำการลงลายเซ็นหรือการดำเนินการเข้ารหัสลับอื่นใด และไม่นิยามพฤติกรรมเฉพาะของ FIPS

หน้านี้บันทึกเฉพาะพฤติกรรมที่สังเกตได้จากภายนอกและพื้นผิว API สาธารณะที่รองรับเท่านั้น เส้นทาง namespace ภายใน คลาสตัวช่วย ตารางกลไก ชื่อไฟล์ runbook และคำนำหน้า ticket อยู่นอกขอบเขต