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

Enterprise الإصدار

البدء السريع مع NextPDF Enterprise

يأخذك هذا الدرس من مشروع فارغ إلى نتيجتين عمليتين من Enterprise. أولاً تتحقق من ملف ⁨PDF⁩ موقّع موجود وتقرأ ⁨MainIndication⁩ الخاص به. ثم ترفع مستنداً موقّعاً إلى مستوى ⁨PAdES⁩ B-LT باستخدام المُنتِج طويل الأمد. تُظهر كل خطوة المخرجات أو الاستثناء الدقيق الذي ينبغي أن تتوقعه. يوثّق ⁨NextPDF⁩ القدرة، لا الاعتماد: فهو لا يحمل أي اعتماد ⁨PAdES⁩ أو eIDAS ولا يمنح أياً منه.

تُشحن هذه القدرة ضمن ⁨NextPDF⁩ Enterprise (⁨nextpdf/enterprise⁩) وتُفعَّل بمغلّف ترخيص من فئة Enterprise. لا يُحمّل أي نشر بلا ذلك الاستحقاق أصناف القدرة. قارن الإصدارات واحصل على ترخيص.

  • تمّت تهيئة Composer لمستودع ⁨NextPDF⁩ الخاص. اتّبع التثبيت والمصادقة أولاً.
  • لديك مغلّف ترخيص Enterprise، مُنزّلاً من حسابك على ⁨app.getnextpdf.com⁩. يشرح الترخيص والتفعيل ما هو المغلّف وأين يوضع.
  • من أجل الخطوة 3 تحتاج إلى ملف ⁨PDF⁩ موقّع للتحقق منه. ومن أجل جزء B-LT تحتاج أيضاً إلى شهادة الموقّع ووصول شبكي إلى مستجيبي OCSP/CRL.

اطلب حزمة Enterprise. إنها تعتمد على ⁨nextpdf/core⁩ و⁨nextpdf/pro⁩، لذا يجلب Composer الحزمة الكاملة:

Terminal window
composer require nextpdf/enterprise
composer show nextpdf/enterprise

إذا طبع ⁨composer show⁩ الحزمة وإصدارها، فقد نجح التثبيت. ضع الآن مغلّف الترخيص الموقّع حيث يُحمّله نشرك، تماماً كما يصف الترخيص والتفعيل. تثبيت الحزمة وحده لا يمنح قدرات Enterprise؛ الترخيص المُفعَّل هو ما يختار الإصدار.

اسأل مُقيّم الاستحقاق عمّا يمنحه ترخيصك. يحصل مُهيّئك على ⁨NextPDF\Enterprise\Licensing\LicenseKey⁩ الموثّق أثناء التفعيل؛ مرّره:

<?php
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Licensing\EntitlementEvaluator;
use NextPDF\Enterprise\Licensing\LicenseKey;
/** @var LicenseKey|null $license The verified license from activation. */
$result = (new EntitlementEvaluator())->evaluate($license);
echo 'status: ' . $result->status->value . PHP_EOL;
echo 'edition: ' . ($result->edition?->value ?? 'none') . PHP_EOL;
echo 'runtime: ' . ($result->runtimeAllowed ? 'allowed' : 'disabled') . PHP_EOL;

مع ترخيص Enterprise نشط ترى:

status: active
edition: enterprise
runtime: allowed

الطريقة الكامنة وراء هذه الخطوة:

public function evaluate(?LicenseKey $license, ?DateTimeImmutable $now = null): EntitlementResult

يرمي أو يفشل بـ: إنه لا يرمي أبداً. يُرجِع الترخيص المفقود ⁨EntitlementResult⁩ يفشل بالإغلاق مع ⁨EntitlementStatus::NoLicense⁩ و⁨runtimeAllowed⁩ بقيمة false (انظر الخطوة 4).

تحقّق من ملف ⁨PDF⁩ موقّع موجود

قسم بعنوان «تحقّق من ملف ⁨PDF⁩ موقّع موجود»

استخرج التوقيع من ملف ⁨PDF⁩ موقّع، ثم شغّل تحققاً أساسياً من AdES. يطبّق المحرّك مستويات التحقق في ETSI EN 319 102-1؛ ⁨validateBasic()⁩ هو تدفّق البند ⁨5.2⁩ — البنية، والملخّص، وتعمية التوقيع، وسلسلة الشهادات:

<?php
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Validation\AdESValidationEngine;
use NextPDF\Enterprise\Security\Validation\CmsSignatureDataExtractor;
use NextPDF\Enterprise\Signature\SignatureExtractor;
$pdf = file_get_contents(__DIR__ . '/contract-signed.pdf');
if ($pdf === false) {
throw new RuntimeException('Could not read contract-signed.pdf');
}
$signatures = (new SignatureExtractor())->extract($pdf);
if ($signatures === []) {
throw new RuntimeException('The PDF carries no signature dictionary.');
}
$engine = new AdESValidationEngine(extractor: new CmsSignatureDataExtractor());
$report = $engine->validateBasic(
$signatures[0]['signedBytes'], // the exact /ByteRange-covered bytes
$signatures[0]['contents'], // the DER CMS SignedData from /Contents
);
echo $report->mainIndication->name . PHP_EOL;
echo ($report->subIndication?->name ?? '(none)') . PHP_EOL;

من أجل توقيع جيّد التكوين يجتاز الفحوص الأساسية البنيوية، وفحوص الملخّص، والتعمية، والسلسلة المُهيّأة في هذا المثال، ترى:

TOTAL_PASSED
(none)

لدى ⁨MainIndication⁩ ثلاث حالات بالضبط: ⁨TOTAL_PASSED⁩ و⁨TOTAL_FAILED⁩ و⁨INDETERMINATE⁩. المحرّك يفشل بالإغلاق: فحص لا يستطيع إثباته إيجابياً يُنتِج ⁨INDETERMINATE⁩، لا اجتيازاً صامتاً أبداً. الاجتياز هنا هو نتيجة تحقق ضمن فحوص هذا المحرّك، لا بيان ثقة أو اعتماد — تنتمي مراسي الثقة والأدلة طويلة الأمد إلى المستويات الأعمق في صفحة التحقق.

public function extract(string $pdfData): array

يرمي أو يفشل بـ: ⁨InvalidArgumentException⁩ إذا لم يكن الدخل ملف ⁨PDF⁩ صالحاً. يُنتِج ⁨/ByteRange⁩ أو ⁨/Contents⁩ مشوّه سلاسل فارغة (فشل بالإغلاق)، لا نتيجة إيجابية أبداً.

public function validateBasic(string $signedData, string $signature): ValidationReport

يرمي أو يفشل بـ: إنه لا يرمي أبداً عند فشل التحقق. يُعيَّن كل عيب إلى دلالة ⁨ValidationReport⁩، مثل ⁨HASH_FAILURE⁩ أو ⁨SIG_CRYPTO_FAILURE⁩.

ارفع الآن مستنداً حديث التوقيع إلى B-LT. يجمع المُنتِج طويل الأمد سلسلة الشهادات إضافةً إلى أدلة OCSP/CRL ويكتب مخزن أمان المستند (DSS). إنه يُكمل تمريرة التوقيع الموصوفة في صفحة التوقيع، التي تمنحك مخزن الإخراج، وسجلّ الكائنات، وسداسي ⁨/Contents⁩ الخاص بالتوقيع:

use NextPDF\Enterprise\Security\Ltv\LtvManager;
use NextPDF\Security\Signature\CertificateInfo;
use NextPDF\Security\Signature\SignatureLevel;
$certInfo = CertificateInfo::fromPkcs12('/secure/signer.p12', $p12Password);
// $httpClient is any PSR-18 client; it fetches OCSP responses and CRLs.
$ltv = new LtvManager($certInfo, $httpClient, level: SignatureLevel::PAdES_B_LT);
// $buffer, $registry, and $signatureContentsHex come from the signing pass.
$dssObjectNumber = $ltv->enableLtv($buffer, $registry, $signatureContentsHex);

القيمة المُرجَعة هي رقم كائن DSS الخاص بمُدخل ⁨/DSS⁩ في كتالوج المستند. يفترض المُنتِج تلقائياً إنفاذ إبطال صارم: مادة الإبطال المفقودة ترفع استثناءً بدلاً من أن تُصدِر بصمت ملف “B-LT” أجوف.

public function enableLtv(BinaryBuffer $buffer, ObjectRegistry $registry, string $signatureContentsHex): int

يرمي أو يفشل بـ: ⁨NextPDF\Enterprise\Security\Ltv\LtvException⁩ عندما يفشل التحقق من السلسلة، أو عندما تكون الشهادة مُبطَلة، أو عندما تكون مادة الإبطال مفقودة تحت الافتراض الصارم.

status: no_license — المغلّف غير مُحمَّل

قسم بعنوان «status: no_license — المغلّف غير مُحمَّل»

تطبع الخطوة 2 ⁨status: no_license⁩ و⁨runtime: disabled⁩، وتحمل النتيجة التحذير ⁨No license configured. Enterprise runtime is disabled. Install a license or purchase one at https://nextpdf.dev/pricing⁩. عندئذٍ يرمي استدعاء مُقيَّد بالاستحقاق ⁨NextPDF\Accelerator\Exception\SpectrumAuthenticationException⁩ برمز ⁨SPEC-LIC-001⁩، مثل ⁨Capability '...' requires a valid license.⁩ الحل: ضع المغلّف وفعّله وفق الترخيص والتفعيل، ثم أعد تشغيل الخطوة 2.

InvalidArgumentException: Input does not start with %PDF header

قسم بعنوان «InvalidArgumentException: Input does not start with %PDF header»

تلقّى ⁨SignatureExtractor::extract()⁩ شيئاً ليس ملف ⁨PDF⁩ — مساراً خاطئاً، أو قراءة فارغة، أو تنزيلاً مضغوطاً. تفقّد الملف الذي حمّلته. قائمة ⁨$signatures⁩ فارغة أمر مختلف: الملف ملف ⁨PDF⁩، لكنه لا يحمل قاموس ⁨/Type /Sig⁩، فليس هناك ما يُتحقَّق منه.

LtvException: Strict revocation: LTV warning: no revocation data for certificate at chain position 0

قسم بعنوان «LtvException: Strict revocation: LTV warning: no revocation data for certificate at chain position 0»

لم يستطع ⁨enableLtv()⁩ الحصول على استجابة OCSP أو CRL لشهادة في السلسلة، والافتراض الصارم يرفض كتابة ادّعاء B-LT بلا دليل. تفقّد إمكانية الوصول إلى المستجيب من المضيف، أو مرّر ⁨enforcementMode: RevocationEnforcementMode::PERMISSIVE⁩ فقط إذا كنت تقبل صراحةً تشغيلاً بالتحذير فحسب — لا تصنّف أبداً مثل هذا الإخراج على أنه B-LT لسير عمل إنتاجي أو امتثالي ما لم يُقبَل دليل الإبطال المفقود ويُوثَّق صراحةً. ذو صلة: طلب B-LTA بلا عميل TSA يفشل بـ ⁨LtvException: TSA client required for document timestamps⁩.