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

تحليل ملف PDF وفحصه لاستخراج حقائقه البنيوية

تستخدم هذه الوصفة وضع ⁨Quick⁩ الاحتياطي في فاحص ⁨Core⁩ لقراءة الحقائق البنيوية من ملف بتنسيق المستندات المحمولة (⁨PDF⁩). ستحصل على الإصدار وعدد الصفحات وعلَم التشفير وعلَم التوقيع وعلَم المرفقات وحجم الملف وأعلام المخاطر. يعمل وضع ⁨Quick⁩ بالكامل داخل العملية، من دون عربة ⁨Spectrum⁩ الجانبية ومن دون وصول إلى الشبكة. استخدمه للفرز السريع، وليس كأداة تحقّق.

Terminal window
composer require nextpdf/core:^3

يسجّل ملف ⁨PDF⁩ إصداره في ترويسة الملف (⁨ISO 32000-2⁩ §7.5.2). يحمل المُلحِق (⁨trailer⁩) مُعرّف ملف (/ID) على هيئة سلسلتي بايت (⁨ISO 32000-2⁩ §7.5.5). عند وجود توقيع، يخزّن قاموس التوقيع بنية رسالة التعمية (⁨CMS⁩) من النوع ⁨SignedData⁩، مُرمَّزة بقواعد الترميز المميِّز (⁨DER⁩)، داخل Contents (⁨ISO 32000-2⁩ §12.8.1). يستخدم وضع ⁨Quick⁩ الاحتياطي مسحًا محدودًا لبايتات المستند لاستنتاج الإصدار وتقدير عدد الصفحات وأعلام وجود التشفير والتوقيع والمرفقات.

أنشئ new Inspector()، ثم استدعِ ->inspect(string $pdfData, InspectConfig::quick()). يعيد ذلك InspectResult يحتوي على $pdfVersion، و$pageCount، و$isEncrypted، و$hasSigned، و$hasAttachments، و$fileSizeBytes، و$riskFlags، والدالة المساعِدة hasRisks().

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\InspectConfig;
use NextPDF\Inspect\Inspector;
$pdf = file_get_contents(__DIR__ . '/document.pdf');
$result = (new Inspector())->inspect($pdf, InspectConfig::quick());
printf(
"v%s, %d page(s), encrypted=%s, signed=%s\n",
$result->pdfVersion ?? '?',
$result->pageCount,
$result->isEncrypted ? 'yes' : 'no',
$result->hasSigned ? 'yes' : 'no',
);

يعمل هذا البرنامج المستقل بذاته داخل بيئة اختبار دليل الوصفات. وهو يعكس examples/39-parse-and-inspect-pdf.php: إذ يبني ملف ⁨PDF⁩ صغيرًا متعدد الصفحات في الذاكرة، ويقرأ حقائقه البنيوية باستخدام وضع ⁨Quick⁩ الاحتياطي، ثم يوجّه المعالجة بناءً على تلك الحقائق، لا بناءً على حكم بالثقة أبدًا. فرع التوجيه توضيحي. استبدله بخط المعالجة الخاص بك وطابور التحقّق والحَجْر.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Inspect\InspectConfig;
use NextPDF\Inspect\Inspector;
// A self-contained input so the program runs with no external file.
$doc = Document::createStandalone();
$doc->setTitle('Parse-and-inspect demo');
$doc->setAuthor('NextPDF Cookbook');
$doc->addPage();
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'Page one of the parse-and-inspect demonstration.', newLine: true);
$doc->addPage();
$doc->cell(0, 10, 'Page two.', newLine: true);
$pdf = $doc->getPdfData();
$result = (new Inspector())->inspect($pdf, InspectConfig::quick());
echo 'PDF version : ' . ($result->pdfVersion ?? 'unknown') . "\n";
echo 'Pages : ' . $result->pageCount . "\n";
echo 'Encrypted : ' . ($result->isEncrypted ? 'yes' : 'no') . "\n";
echo 'Signed : ' . ($result->hasSigned ? 'yes' : 'no') . "\n";
echo 'Attachments : ' . ($result->hasAttachments ? 'yes' : 'no') . "\n";
echo 'File size : ' . $result->fileSizeBytes . " bytes\n";
echo 'Risk flags : ' . ($result->hasRisks() ? count($result->riskFlags) : 0) . "\n";
// Route on structural facts, not trust verdicts. Replace these calls with
// your own pipeline / verifier queue / quarantine.
if ($result->isEncrypted) {
// $pipeline->decryptThenContinue($pdf);
echo "Route: decrypt-then-continue\n";
} elseif ($result->hasSigned) {
// $verifierQueue->enqueue($pdf); // see the signature-inspect recipe
echo "Route: enqueue for cryptographic verification\n";
} elseif ($result->hasRisks()) {
// $quarantine->hold($pdf, $result->riskFlags);
echo "Route: quarantine (risk flags present)\n";
} else {
// $pipeline->continue($pdf);
echo "Route: continue (no risks, unsigned, unencrypted)\n";
}
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script under the
// semantic profile; emit the document to the side-channel.
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
file_put_contents($out !== false && $out !== '' ? $out : __DIR__ . '/inspected.pdf', $pdf);

المخرَج القياسي المتوقَّع (⁨STDOUT⁩) (يعتمد الإصدار والحجم على البنية؛ وملف ⁨PDF⁩ التوضيحي غير مشفَّر وغير موقَّع وخالٍ من المخاطر):

PDF version : <version>
Pages : 2
Encrypted : no
Signed : no
Attachments : no
File size : <n> bytes
Risk flags : 0
Route: continue (no risks, unsigned, unencrypted)
  • وضع ⁨Quick⁩ أداة فرز، لا أداة تحقّق. فهو يبلّغ عمّا هو موجود وعمّا هو غائب. ولا يتحقّق من التواقيع، ولا يفكّ تشفير المحتوى، ولا يؤكّد المطابقة. تعامل مع النتيجة بوصفها مُدخلًا للتوجيه.
  • عدد الصفحات تقدير. يحسب وضع ⁨Quick⁩ الاحتياطي علامات كائنات الصفحات. يمكن لرسم بياني للكائنات مُشوَّه عمدًا أن يغيّر العدّ. استخدم الأعماق المدعومة بـ ⁨Spectrum⁩ عندما تحتاج إلى عدّ دقيق.
  • يحتاج العمقان ⁨Standard/Full⁩ إلى العربة الجانبية. يتطلّب new InspectConfig() (العمق Standard) وInspectConfig::full() العربة الجانبية ⁨Spectrum.⁩ وهما يطلقان INSPECT-SIDECAR-001 عند عدم توفّرها، ولا يتراجعان بصمت إلى وضع ⁨Quick.⁩
  • المُدخل الفارغ. يؤدي تمرير سلسلة فارغة إلى إطلاق استثناء فحص نصّه “⁨PDF data must not be empty⁩”.
  • نطاق علَم التشفير. يعكس العلَم وجود مُدخَل /Encrypt في المُلحِق (⁨trailer⁩). لا يفكّ الفاحص تشفير الملف المُعلَّم.

يستخدم وضع ⁨Quick⁩ الاحتياطي مسحًا محدودًا، لا تحليلًا كاملًا. استخدمه لتوجيه كميات كبيرة من الملفات الواردة مسبقًا قبل المعالجة الأثقل.

يعمل الفاحص داخل العملية ويقرأ العلامات البنيوية فقط. لا تغادر أي بايتات من المستند المُضيف، ولا يُستخرَج أي نص من المستند. علَم المخاطر، مثل ⁨JavaScript⁩ المضمَّنة، إشارة توجيهية استرشادية، وليس تأكيدًا بأن الملف آمن أو غير آمن.

العبارةالمواصفةالبند⁨reference_id⁩
تسجّل ترويسة الملف إصدار ⁨PDF.⁩⁨ISO 32000-2⁩§7.5.2
المُلحِق (⁨trailer⁩) /ID مُعرّف ملف مكوَّن من سلسلتي بايت.⁨ISO 32000-2⁩§7.5.5
يحمل Contents في قاموس التوقيع بنية ⁨SignedData⁩ من نوع ⁨CMS⁩ مُرمَّزة بـ ⁨DER.⁩⁨ISO 32000-2⁩§12.8.1

تبلّغ هذه الوصفة عن الحقائق البنيوية فقط. ولا تؤكّد أن الملف صالح أو آمن أو مطابق.

يعمل عمقا الفحص ⁨Standard⁩ و⁨Full⁩ عبر العربة الجانبية ⁨Spectrum.⁩ ويضيفان تحليلًا أغنى للكائنات والخطوط والصور. وضع ⁨Quick⁩ الاحتياطي الموثَّق هنا هو ⁨Core⁩ ويعمل دون اتصال.