إرجاع ملف PDF مُولَّد من وحدة تحكم
لمحة سريعة
قسم بعنوان «لمحة سريعة»أنشئ ملف PDF داخل إجراء وحدة تحكم، ثم أرجِعه كاستجابة HTTP. يتضمن كل تكامل لإطار عمل مساعد PdfResponse يبني كائن الاستجابة، ويضبط Content-Type: application/pdf، ويرفق ترويسات الأمان، وينقِّح اسم الملف. يشرح هذا الدليل أوضاع التسليم الثلاثة في Laravel وSymfony وCodeIgniter 4: المعاينة المضمَّنة، وتنزيل الملف، والتسليم المتدفِّق.
تحقق من هذه المتطلبات المسبقة أولًا، حتى يكون مسار وحدة التحكم جاهزًا قبل البدء:
- نواة NextPDF مثبَّتة.
- تكامل واحد لإطار العمل مثبَّت، وقد اكتُشف مزوِّد الخدمة أو الحزمة أو الخدمة الخاصة به. تحقق من الاكتشاف في صفحة التثبيت الخاصة بإطار عملك قبل البدء.
- لا يحتاج الوضع المتدفِّق إلى أي حزم إضافية. يوفر كل تكامل المتغيِّر المتدفِّق إلى جانب المتغيِّر المُخزَّن مؤقتًا.
هذا دليل إرشادي يفترض أنك تعرف بالفعل كيفية توجيه طلب إلى وحدة تحكم في إطار عملك. للحصول على أول مثال قابل للتشغيل في كل إطار عمل، اقرأ دليل البدء السريع المرتبط ضمن انظر أيضًا.
التثبيت
قسم بعنوان «التثبيت»ثبِّت التكامل الخاص بإطار عملك. نفِّذ أحد الأوامر التالية:
composer require nextpdf/laravelcomposer require nextpdf/symfonycomposer require nextpdf/codeigniterبالنسبة إلى Laravel، انشر الإعداد بعد التثبيت:
php artisan vendor:publish --tag=nextpdf-configيسجِّل Symfony الحزمة عبر Flex، ويكتشف CodeIgniter الخدمة تلقائيًا. أكِّد الاكتشاف في صفحة تثبيت إطار عملك قبل المتابعة.
نظرة عامة مفاهيمية
قسم بعنوان «نظرة عامة مفاهيمية»يتبع كل تكامل لإطار عمل النمط نفسه المكوَّن من ثلاثة أجزاء: احصل على مستند جديد، واكتب المحتوى في ذلك المستند، ثم مرِّره إلى مصنع PdfResponse الذي يُرجِع استجابة HTTP. واجهة برمجة تطبيقات المستند (addPage() وcell() وsetFont()) هي سطح محرك النواة، وهي متطابقة عبر الإطارات. يختلف مصنع الاستجابة فقط في فئة الاستجابة التي يُرجِعها، لأن لكل إطار عمل نوع استجابة HTTP خاصًا به.
يوفِّر PdfResponse ثلاثة أوضاع للتسليم. المعاينة المضمَّنة تضبط ترويسة Content-Disposition: inline، بحيث يعرض المتصفح ملف PDF في علامة تبويب عارض. التنزيل يضبط Content-Disposition: attachment، بحيث يحفظ المتصفح الملف. التدفُّق يُصدِر متن ملف PDF في كتل ثابتة بدلًا من تخزين المستند بأكمله مؤقتًا في الذاكرة. اختره للمستندات الكبيرة عندما تكون ذروة استخدام الذاكرة أهم من معرفة Content-Length.
احصل على المستند عبر مسار التحليل المعتاد لإطار عملك:
- Laravel — حلِّل
NextPDF\Contracts\DocumentFactoryInterfaceمن الحاوية باستخدامapp(...)واستدعِcreate()، الذي يُرجِعNextPDF\Core\Documentجديدًا، وهو النوع الملموس الذي تقبله مصانعPdfResponse. - Symfony — احقن
NextPDF\Symfony\Service\PdfFactoryواستدعِcreate()، الذي يُرجِعNextPDF\Core\Documentجديدًا مع تطبيق الإعدادات الافتراضية المُهيَّأة للمستند مسبقًا. - CodeIgniter 4 — حلِّل مكتبة
PdfعبرServices::pdf()(أو المساعدpdf())، أو احصل على مستند مجرَّد عبرpdf_document().
سطح واجهة برمجة التطبيقات
قسم بعنوان «سطح واجهة برمجة التطبيقات»| الجانب المعني | Laravel | Symfony | CodeIgniter 4 |
|---|---|---|---|
| مستند جديد | app(DocumentFactoryInterface::class)->create() | PdfFactory::create() | pdf_document() / Services::pdf()->document() |
| استجابة مضمَّنة | PdfResponse::inline($doc, $name) | PdfResponse::inline($doc, $name) | $pdf->inline($name) / PdfResponse::inline($doc, $name) |
| استجابة تنزيل | PdfResponse::download($doc, $name) | PdfResponse::download($doc, $name) | $pdf->download($name) / PdfResponse::download($doc, $name) |
| مضمَّن متدفِّق | PdfResponse::streamInline($doc, $name) | PdfResponse::streamInline($doc, $name) | PdfResponse::streamInline($doc, $name) |
| تنزيل متدفِّق | PdfResponse::streamDownload($doc, $name) | PdfResponse::streamDownload($doc, $name) | PdfResponse::streamDownload($doc, $name) |
| النوع المُرجَع | Illuminate\Http\Response (متدفِّق: StreamedResponse) | Symfony\Component\HttpFoundation\Response (متدفِّق: StreamedResponse) | CodeIgniter\HTTP\DownloadResponse |
يوجد PdfResponse الخاص بـ Laravel في NextPDF\Laravel\Http\PdfResponse، والخاص بـ Symfony في NextPDF\Symfony\Http\PdfResponse، والخاص بـ CodeIgniter في NextPDF\CodeIgniter\Http\PdfResponse. توثِّق صفحة الأمان والعمليات الخاصة بكل تكامل سلوك الاستجابة الكامل لتلك الحزمة: مجموعة الترويسات، وقواعد الترتيب، وتنقيح اسم الملف. تجد هذه الصفحات مرتبطة ضمن انظر أيضًا.
عينة شفرة — البدء السريع
قسم بعنوان «عينة شفرة — البدء السريع»فيما يلي الحد الأدنى لإجراء التنزيل في كل إطار عمل. تستخدم استدعاءات المستند سطح النواة نفسه، ولا يتغير إلا قالب وحدة التحكم.
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\Response;use NextPDF\Contracts\DocumentFactoryInterface;use NextPDF\Laravel\Http\PdfResponse;
final class ReportController extends Controller{ public function download(): Response { $document = app(DocumentFactoryInterface::class)->create(); $document->addPage(); $document->cell(0, 10, 'Monthly report', newLine: true);
return PdfResponse::download($document, 'report.pdf'); }}<?php
declare(strict_types=1);
namespace App\Controller;
use NextPDF\Symfony\Http\PdfResponse;use NextPDF\Symfony\Service\PdfFactory;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Routing\Attribute\Route;
final class ReportController{ #[Route('/report', name: 'report_pdf')] public function download(PdfFactory $pdf): Response { $document = $pdf->create(); $document->addPage(); $document->cell(0, 10, 'Monthly report', newLine: true);
return PdfResponse::download($document, 'report.pdf'); }}<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\DownloadResponse;use NextPDF\CodeIgniter\Config\Services;
final class ReportController extends BaseController{ public function download(): DownloadResponse { $pdf = Services::pdf(); $pdf->document()->addPage(); $pdf->document()->cell(0, 10, 'Monthly report');
return $pdf->download('report.pdf'); }}للمعاينة في المتصفح بدلًا من التنزيل، استبدل استدعاء download(...) بـ inline(...) في Laravel وSymfony، أو بـ $pdf->inline('report.pdf') في CodeIgniter. يتغير الترتيب إلى inline، وتبقى كل ترويسة أخرى كما هي.
عينة شفرة — الإنتاج
قسم بعنوان «عينة شفرة — الإنتاج»يحقن إجراء الإنتاج تبعياته، ويلتقط أكثر الاستثناءات تحديدًا مما يوثِّقه التكامل، ويسجِّل فئة الفشل دون تسريب أثر التتبع، ويُرجِع خطأ HTTP محدَّدًا. يستخدم المثال أدناه حقن المُنشئ في Laravel. تتبع المكافِئات في Symfony وCodeIgniter النمط نفسه وتظهر في صفحة الاستخدام الإنتاجي الخاصة بكل تكامل.
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\Response;use NextPDF\Contracts\DocumentFactoryInterface;use NextPDF\Laravel\Http\PdfResponse;use Psr\Log\LoggerInterface;use Throwable;
final class InvoiceController extends Controller{ public function __construct( private readonly DocumentFactoryInterface $documents, private readonly LoggerInterface $logger, ) {}
public function show(int $invoiceId): Response { try { $document = $this->documents->create(); $document->addPage(); $document->cell(0, 10, "Invoice #{$invoiceId}", newLine: true);
return PdfResponse::download( $document, "invoice-{$invoiceId}.pdf", ); } catch (Throwable $exception) { // Log the exception class, never the message or a stack trace, // so internal detail does not leak into the log sink. $this->logger->error('Invoice PDF generation failed', [ 'invoice_id' => $invoiceId, 'exception' => $exception::class, ]);
return new Response('Could not generate the invoice PDF.', 500); } }}احقن DocumentFactoryInterface واستدعِ create() في كل إجراء. يُرجِع هذا NextPDF\Core\Document جديدًا، وهو النوع الملموس الذي تقبله مصانع PdfResponse الخاصة بـ Laravel. تحليل مستند جديد لكل طلب يبقي المصنع قابلًا للاستبدال في الاختبارات. لا تُعِد استخدام مثيل وحدة تحكم واحد لمستندَين غير مرتبطَين داخل عملية عامل واحدة طويلة التشغيل.
بالنسبة إلى المستندات الكبيرة جدًا، استبدل المصنع المُخزَّن مؤقتًا بمصنع متدفِّق لتقييد ذروة استخدام الذاكرة. يُرجِع المتغيِّر المتدفِّق StreamedResponse (في Laravel وSymfony) ويُصدِر المتن في كتل ثابتة. ويحذف Content-Length عمدًا، لذلك لا ترى أشرطة تقدُّم التنزيل ولا الوكلاء الحساسون للطول حجمًا معروفًا. فضِّل download() / inline() المُخزَّنَين مؤقتًا للاستجابات الصغيرة الحساسة لزمن الوصول.
$document = $this->documents->create();// ... emit content onto $document ...return PdfResponse::streamDownload($document, 'annual-report.pdf');الحالات الحدية والمزالق
قسم بعنوان «الحالات الحدية والمزالق»- مستند جديد لكل استدعاء. في التكاملات الثلاثة جميعها، المستند هو ناتج مصنع جديد لكل عملية تحليل. لا تخزِّن مستندًا مُحلَّلًا مؤقتًا بين مستندات منطقية مختلفة، أو بين الطلبات في عامل طويل التشغيل. وإلا فستنتقل حالة المحتوى القديمة إلى ما يليها.
- اسم ملف فارغ. يؤدي اسم الملف الفارغ المُمرَّر إلى مصنع
PdfResponseإلى الرجوع إلى اسم افتراضي (document.pdf) بدلًا من إنتاج ترتيب فارغ. مرِّر اسم ملف صريحًا وذا معنى. - أسماء الملفات غير ASCII. تضيف استجابة Laravel معلَمة RFC 5987
filename*=تلقائيًا للأسماء غير ASCII، وتستخدم معلَمة اسم الملف العادية لأسماء ASCII. لا تُرمِّز اسم الملف يدويًا بنفسك. - الاستجابات المتدفِّقة خلف وكيل يُخزِّن مؤقتًا. الوكيل الذي يخزِّن المتن الكامل مؤقتًا يلغي فائدة الذاكرة من التدفُّق. هيِّئ الوكيل لتدفُّق استجابات PDF، أو استخدم استجابة مُخزَّنة مؤقتًا في ذلك المسار.
- رد نداء Symfony المتدفِّق. يُرجِع متغيِّر Symfony المتدفِّق
StreamedResponse، ويفرغ رد ندائه المخرجات. لا تكتب إلى متن الاستجابة بنفسك بعد إعادته.
الأداء
قسم بعنوان «الأداء»يحجب التوليد المتزامن داخل وحدة التحكم الطلب طوال مدة بناء ملف PDF بالكامل. يبقى المستند المؤلَّف من صفحة واحدة عادةً ضمن ميزانية الطلب المعتادة بهامش جيد. بالنسبة إلى المخرجات متعددة الصفحات أو الدُّفعية، انقل التوليد بعيدًا عن مؤشر ترابط الطلب باستخدام مهمة في الطابور — انظر توليد ملف PDF في مهمة بالطابور. تقلِّل المتغيِّرات المتدفِّقة ذروة استخدام الذاكرة للمستندات الكبيرة على حساب عدم معرفة Content-Length. اخترها عندما تكون الذاكرة هي القيد ولا يكون شريط التقدُّم مطلوبًا.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»- تطبِّق مصانع
PdfResponseمجموعة ثابتة من ترويسات تقوية الاستجابة وتنقِّح اسم ملف التنزيل في كل تكامل. لا تضِف هذه الترويسات بنفسك. - لا تُدرِج أبدًا مدخلات المستخدم غير المُتحقَّق منها مباشرةً في اسم ملف تمرِّره إلى المصنع. مرِّر قيمة تتحكم فيها، ودَع المصنع ينقِّحها كطبقة ثانية.
- في كتلة catch، سجِّل فئة الاستثناء ومُعرِّف الارتباط، لا رسالة الاستثناء ولا أثر التتبع. أثر التتبع الخام في مَصرِف السجلات يُعد تسريبًا للمعلومات.
- لا تكتب أبدًا كتلة
catchفارغة. كل مثال هنا يسجِّل ويُرجِع استجابة خطأ محدَّدة.
توثِّق صفحة الأمان والعمليات الخاصة بكل تكامل نموذج التهديد لذلك التكامل: مجموعة الترويسات، وقواعد تنقيح اسم الملف، ومدة ربط المستند.
المطابقة
قسم بعنوان «المطابقة»لا يقدِّم هذا الدليل أي ادعاء معياري بشأن المعايير. كل استدعاء لواجهة برمجة التطبيقات معروض هنا هو السطح العام المُتحقَّق منه للتكامل المُسمَّى، وقد تم التحقق منه مقابل صفحات البدء السريع والاستخدام الإنتاجي لكل حزمة. توثِّق صفحات الاستخدام الإنتاجي الأصلية المرتبطة ضمن انظر أيضًا دلالات الترويسة وسلوك ربط الحاوية اللذَين تعتمد عليهما التكاملات، إلى جانب استشهادات PSR الخاصة بها. تعيد صفحة كتاب الطبخ هذه ذكر الاستخدام وتؤجِّل الاستشهادات المعيارية إلى تلك الصفحات.
انظر أيضًا
قسم بعنوان «انظر أيضًا»- توليد ملف PDF في مهمة بالطابور — انقل هذا العمل بعيدًا عن مؤشر ترابط الطلب.
- الاستخدام الإنتاجي في Laravel — وحدة تحكم مرتبطة بحقن التبعيات، ومجموعة الترويسات، وعقد ربط PSR-11.
- دليل البدء السريع لـ Symfony — وحدة التحكم، والمضمَّن، والمتدفِّق، ونموذج الاستجابة.
- دليل البدء السريع لـ CodeIgniter —
Services::pdf()، والمساعدpdf()، وPdfResponse. - اختيار تكامل — اختر حزمة إطار العمل المناسبة.