تخطَّ إلى المحتوى

تشغيل compat-legacy في الإنتاج

المهايئ آمن للتشغيل في معالِجات ⁨HTTP⁩، وعمّال الطوابير، والعمليات الطويلة الأمد. وهو أكثر أمانًا من ⁨TCPDF⁩ القديم 6.2.13 لأنه يزيل خطرَين إنتاجيين يُرجَّح أن تواجههما: الإخراج المباشر إلى المخزن المؤقت، واستدعاء die() عند حدوث خطأ. استعن بهذه الصفحة لتشغيله بالشكل الصحيح.

قبل الإنتاج، أكمِل تدقيق الوضع الصارم في /⁨integrations/tcpdf-compat/migration/⁩، وانشر مع تعطيل الوضع الصارم ⁨off⁩.

معالجة المخرجات في العمّال والمعالِجات

قسم بعنوان «معالجة المخرجات في العمّال والمعالِجات»

يكتب Output() في ⁨TCPDF⁩ القديم مباشرةً إلى المخزن المؤقت النشط للمخرجات. وقد يؤدي ذلك إلى إفساد الاستجابات في أُطر عمل ⁨HTTP⁩ وتعطيل عمّال الطوابير. بدلًا من ذلك، يوجّه المهايئ المخرجات عبر جسر وجهة آمن.

اختر الوجهة التي تناسب الجهة المُستدعِية:

السياقالوجهةالسبب
عامل طابور يكتب إلى وحدة التخزينOutput($path, 'F')يكتب الملف ويُعيد سلسلة نصية فارغة، ولا يتفاعل مع المخزن المؤقت.
التوليد ثم ⁨attach/upload⁩Output($name, 'S')يُعيد بايتات تنسيق المستندات المحمول (⁨PDF⁩)، وتتحكم أنت في وجهتها.
مرفق بريد إلكترونيOutput($name, 'E')يُعيد متن امتدادات بريد الإنترنت متعددة الأغراض (⁨MIME⁩) بترميز ⁨base64⁩ مع Content-Type: application/pdf.
استجابة ⁨HTTP⁩ تتحكم فيهاOutput($name, 'S')يحصل على البايتات، ثم تضبط الرؤوس والمتن بنفسك.
examples/production-worker.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;
use NextPDF\Compat\Tcpdf\TCPDF;
/**
* Render an invoice in a queue worker. Returns the storage path.
*
* @throws \RuntimeException on a render failure (Error() throws, not die()).
*/
function renderInvoiceJob(array $invoice, string $storageDir): string
{
$pdf = new TCPDF('P', 'mm', 'A4');
$pdf->SetFont('helvetica', '', 12);
$pdf->AddPage();
$pdf->Cell(0, 10, 'Invoice ' . $invoice['number'], 0, 1);
$path = $storageDir . '/invoice-' . $invoice['number'] . '.pdf';
try {
$pdf->Output($path, 'F'); // writes file, no buffer pollution
} catch (TcpdfNotImplementedException $e) {
// Only reachable if strict mode is on — it must NOT be in production.
throw new \RuntimeException('Adapter strict-mode gap in production: ' . $e->getMessage(), 0, $e);
} catch (\RuntimeException $e) {
// Error() throws RuntimeException instead of die().
throw new \RuntimeException('PDF render failed: ' . $e->getMessage(), 0, $e);
}
return $path;
}

في معالِج ⁨HTTP⁩، فضّل 'S' واضبط الرؤوس بنفسك:

examples/production-http.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Report');
$bytes = $pdf->Output('report.pdf', 'S');
header('Content-Type: application/pdf');
header('Content-Length: ' . strlen($bytes));
header('Content-Disposition: inline; filename="report.pdf"');
echo $bytes;

يطلق Error() استثناء RuntimeException؛ ولا يستدعي die() أبدًا. هذا هو أهم تغيير تشغيلي مقارنةً بـ ⁨TCPDF⁩ القديم.

  • غلِّف كل نقطة دخول للتصيير ضمن try/catch.
  • اربط الاستثناء بعقد الأخطاء الخاص بتطبيقك، مثل ⁨HTTP 5xx⁩، أو مهمة فاشلة، أو إعادة محاولة، أو رسالة معلّقة (⁨dead-letter⁩).
  • لا تفترض أن العملية تنتهي عند فشل التصيير؛ فهي لا تنتهي.

إن ظهور TcpdfNotImplementedException في مهمة تكامل مستمر (⁨CI⁩) دورية بالوضع الصارم (موصى بها) يُعد نتيجة حقيقية. فهو يعني أن مسار شيفرة يعتمد على معامِل ⁨TCPDF⁩ غير مدعوم. تعامل معه بوصفه بند عمل في الترحيل، لا اختبارًا متقلبًا.

دورة الحياة وإدارة الموارد

قسم بعنوان «دورة الحياة وإدارة الموارد»
  • يبني المستند بايتات ⁨PDF⁩ الخاصة به على نحو كسول عند أول استدعاء للإخراج. Close() اختياري؛ واستدعاؤه يخزّن البايتات مؤقتًا. Open() عملية لاغية آمنة.
  • endPage() لا يفعل شيئًا لأن ⁨NextPDF⁩ يدير دورة حياة الصفحة. أزِله من الحلقات كثيفة التنفيذ؛ فهو لا يضيف أي قيمة.
  • دع ⁨PHP⁩ يجمع المهايئ ضمن عملية كنس المهملات بين المهام. _destroy() يعيد ضبط البيانات المخزّنة مؤقتًا في المهايئ، لكنك لست بحاجة إلى استدعائه صراحةً في حلقات العمّال العادية.
  • أنشئ مهايئًا جديدًا لكل مستند. لا تُعِد استخدام نسخة مهايئ واحدة عبر مستندات غير مترابطة في عامل طويل الأمد؛ فحالة المستند خاصة بكل نسخة.
  • المهايئ طبقة تفويض رفيعة؛ والمحرك هو المهيمن على التكلفة، لا المهايئ.
  • عرّف الثوابت القديمة مرة واحدة عند الإقلاع. LegacyDefaults::register() وLegacyBootstrap::enableAliases() دالّتان مُتساويتا القوة ومحميّتان، لذلك تكون الاستدعاءات المتكررة قليلة الكلفة. تعريف الثوابت لكل طلب يهدر الجهد.
  • فضّل Output(..., 'S') أو 'F' على 'I'/'D' في السياقات غير المتصفِّحة. يُنتج مسارا ⁨inline/download⁩ مخرجات مستقلة عن إطار العمل، وهي مخرجات لا ترغب فيها عادةً داخل عامل.
  • للتوليد بكميات كبيرة، حلِّل أداء المحرك، لا المهايئ. فميزانية الحِمل الإضافي الخاص بالمهايئ لكل صفحة صغيرة مقارنةً بالتصيير.
  • كل نسخة من المهايئ مستقلة وتحتفظ بحالة المستند الخاصة بها. التزامن على مستوى العملية أو العامل آمن عندما تستخدم كل وحدة عمل نسخة المهايئ الخاصة بها.
  • تستخدم حواجز تساوي القوة في LegacyBootstrap وLegacyDefaults حالة ساكنة محلية للعملية؛ وهي آمنة ضمن نماذج ⁨PHP⁩ المعتادة ⁨per-request/per-worker.⁩ لكنها ليست مصممة لمشاركة حالة قابلة للتغيير عبر الخيوط.

قائمة تحقُّق ما قبل الإنتاج

قسم بعنوان «قائمة تحقُّق ما قبل الإنتاج»
  • اكتمل تدقيق الوضع الصارم، والإنتاج يعمل مع تعطيل الوضع الصارم.
  • جميع نقاط دخول التصيير مُغلَّفة ضمن try/catch من أجل RuntimeException (دون الاعتماد على die()).
  • العمّال يستخدمون Output(..., 'F') أو 'S'، وليس مسار ⁨inline⁩ أبدًا.
  • الثوابت القديمة مُعرَّفة مرة واحدة عند الإقلاع، قبل أول إنشاء.
  • توجد مهمة تكامل مستمر (⁨CI⁩) دورية بالوضع الصارم لالتقاط حالات التراجع.
  • تأكيدات الاختبار على مستوى البايت أُعيد ضبط خطها الأساسي (راجع /⁨integrations/tcpdf-compat/migration/⁩).
  • /⁨integrations/tcpdf-compat/security-and-operations/⁩ — التشفير، ووضعية التوقيع، والتقوية
  • /⁨integrations/tcpdf-compat/troubleshooting/⁩ — أنماط فشل الإنتاج وإصلاحاتها
  • /⁨integrations/tcpdf-compat/configuration/⁩ — الوضع الصارم ونظافة الثوابت
  • /⁨integrations/tcpdf-compat/migration/⁩ — التدقيق الذي يجب أن يسبق الإنتاج