احتوِ تطبيق NextPDF في حاوية
لمحة سريعة
قسم بعنوان «لمحة سريعة»تريد صورة Docker صغيرة قابلة لإعادة الإنتاج تشغّل محرّك نواة NextPDF الأصلي العامل
داخل العملية — composer require nextpdf/core، تولّد ملفات PDF داخل عملية PHP لديك.
تبني هذه الصفحة ذلك بالضبط: صورة php:8.4 بالامتدادات التي يحتاجها المحرّك فعلًا فقط،
بلا تبعيات تطوير في الطبقة النهائية، وخطوط مجمَّعة، ومستخدم تشغيل غير جذر، وopcache
مضبوط للإنتاج، وخطوة تحقّق تُفشِل البناء إن نقص أي شيء.
هذه الصفحة فقط للمحرّك الأصلي. فجسر Chrome (writeHtmlChrome عبر nextpdf/artisan)
وخادم Connect بيئتا تشغيل منفصلتان لهما صورهما الأثقل الخاصة — تثبيت Chromium بلا
واجهة للجسر، وخدمة طويلة العمر لـConnect. لا تضف متصفّحًا أو خادمًا إلى هذه الصورة؛
فالمحرّك الأصلي لا يحتاج أيًّا منهما.
قبل أن تبدأ، أكّد أن هذه العناصر في مكانها:
- لتطبيقك ملفّا
composer.jsonوcomposer.lockمُودَعان، معnextpdf/coreبوصفه تبعية. - لديك ملفات الخطوط التي تنوي تضمينها، وأنت مرخّص لتضمينها.
- يمكنك تشغيل
docker buildعلى دليل تطبيقك.
هذا دليل عمليّ تشغيليّ. لا شيفرة PHP هنا تقريبًا؛ والعمل في ملف Dockerfile وبضع إعدادات بيئة.
ما يتطلّبه المحرّك فعلًا
قسم بعنوان «ما يتطلّبه المحرّك فعلًا»يجب أن تفي الصورة بقيود منصّة المحرّك الحقيقية، لا أكثر. وبقراءتها مباشرةً من الحزمة،
يتطلّب nextpdf/core php: >=8.4 <9.0 وامتدادات PHP هذه:
| الامتداد | لماذا يحتاجه المحرّك |
|---|---|
ext-mbstring | معالجة سلاسل متعدّدة البايتات للنصّ والترميزات |
ext-intl | دعم Unicode والمحليّة والتدويل |
ext-gd | فكّ ترميز الصور النقطية ومعالجتها |
ext-openssl | التعمية للتوقيع والتجزئة الآمنة |
ext-zlib | ضغط المجرى (Flate) لكائنات PDF |
ext-curl | عميل HTTP للنداءات الصادرة للمحرّك |
طابِق تلك بصورة php:8.4 الرسمية. فـopenssl وcurl وzlib مُجمَّعة أصلًا في صورة
PHP الرسمية، فلا تُجري لها docker-php-ext-install. أما mbstring وgd وintl
فـليست مجمَّعة ويجب تثبيتها، ويحتاج كلٌّ منها ترويسات تطوير نظامه حاضرةً أولًا —
ويحتاج mbstring إضافةً إلى تبعية بناء libonig-dev (Oniguruma). لا تُضِف امتدادات
محرّك لا تُدرجها الحزمة — فكل docker-php-ext-install زائد وقت بناء وسطح هجوم لا
تحتاجه. والامتداد غير المتعلّق بالمحرّك الوحيد الذي تثبّته هذه الصورة هو opcache:
فهو امتداد أداء وقت تشغيل، غير مجمَّع مُمكَّنًا في الصورة الرسمية، ويعتمد ضبط opcache
أدناه على وجوده (انظر “opcache للإنتاج”).
ملف Dockerfile الإنتاجيّ
قسم بعنوان «ملف Dockerfile الإنتاجيّ»هذا بناء ثنائيّ المراحل. تثبّت المرحلة الأولى تبعيات Composer باستثناء حزم التطوير؛ والمرحلة الثانية هي صورة وقت التشغيل النحيلة التي تُشحن.
أضف أولًا ملف .dockerignore بجوار ملف Dockerfile. ومهمّته الأساسية إبقاء بيئة المضيف
— vendor/ مبنيّ على المضيف، وملفات أسرار محليّة، وخبائث بناء — خارج سياق البناء كليًّا،
فيشحن COPY . /var/www/app ما تقصده فقط: بناءات أصغر وأسرع وأأمن لا تستطيع تسريب أسرار
.env المحليّة أو حمل ميغابايتات من vendor/ المضيف إلى الصورة.
ويهمّ استثناء vendor/ أيضًا لأن COPY دليلٍ دمج، لا استبدال. يشغّل ملف Dockerfile
أدناه RUN rm -rf /var/www/app/vendor قبل COPY --from=vendor ... /var/www/app/vendor،
فلا يستطيع vendor/ مضيف في هذه الصورة النجاة أبدًا تحت شجرة التبعيات النظيفة. لكن لو
أزلت يومًا حارسة rm -rf تلك، فإن vendor/ مبنيًّا على المضيف في السياق سيهبط أولًا
ولن يكتب نسخ مرحلة vendor إلا المسارات التي تحتويها الشجرة النظيفة — فأي ملفات مضيف
إضافية (حزمة قديمة أو مثبّتة للتطوير، صنف يتيم) ستنجو تحتها. وإبقاء vendor/ خارج
السياق يسدّ تلك الثغرة بصرف النظر عن rm -rf.
# .dockerignore — keep the host environment out of the build context.vendor/.git/.env.env.local.env.*.localvar/cache/storage/node_modules/*.logاستثنِ ملفات الأسرار المحليّة الحقيقية (.env و.env.local و.env.*.local)، لا
.env.* شاملًا — فذلك المحرف البديل يسقط أيضًا قوالب غير سرّية مثل .env.example التي
تريد شحنها فتحمل الصورة خطّ أساس تهيئة موثَّقًا. أبقِ أي قالب بيئة مُودَع غير سرّيّ في
السياق؛ واستثنِ فقط الملفات التي تحمل أسرارًا محليّة فعلًا.
# syntax=docker/dockerfile:1
# ---- Stage 1: dependencies (no dev) ---------------------------------------FROM composer:2 AS vendor
WORKDIR /appCOPY composer.json composer.lock ./
# Install production dependencies only. --no-dev excludes phpunit, phpstan,# infection, and the other require-dev tooling from the shipped image.# --optimize-autoloader builds a class map for the *vendor* tree here; the# application's own classes are not present in this stage yet, so they are# optimized after the source copy in the runtime stage (see below).RUN composer install \ --no-dev \ --no-interaction \ --no-progress \ --prefer-dist \ --optimize-autoloader \ --no-scripts
# ---- Stage 2: runtime ------------------------------------------------------FROM php:8.4-cli AS runtime
# System headers for the gd, intl, and mbstring extensions that need compiling.# The PHP image already provides openssl, curl, and zlib, so those are NOT# listed; gd, intl, and mbstring are installed below. opcache has no system# headers and is installed in the same step. mbstring is built against# Oniguruma, so libonig-dev is in the *-dev set and its runtime lib (libonig5)# is preserved by the same detection below.## Build the *-dev headers (which pull in the runtime libs), compile the# extensions, then mark only the runtime shared libraries the extensions# actually link against so they survive the --auto-remove purge of the headers.# Removing libicu / libpng / libjpeg / libfreetype / libonig here would unlink# intl.so, gd.so, or mbstring.so at runtime ("undefined symbol" / "cannot open# shared object file").RUN set -eux; \ savedAptMark="$(apt-mark showmanual)"; \ apt-get update; \ apt-get install -y --no-install-recommends \ libicu-dev \ libpng-dev \ libjpeg62-turbo-dev \ libfreetype6-dev \ libonig-dev; \ docker-php-ext-configure gd --with-freetype --with-jpeg; \ docker-php-ext-install -j"$(nproc)" gd intl mbstring opcache; \ # Detect the runtime .so dependencies of the just-built extensions and # mark them manual so --auto-remove keeps them while dropping the headers. apt-mark auto '.*' > /dev/null; \ apt-mark manual $savedAptMark > /dev/null; \ find /usr/local/lib/php/extensions -type f -name '*.so' -exec \ sh -c 'ldd "$1" 2>/dev/null \ | awk "/=>/ { print \$3 }" \ | grep -E "^/" \ | xargs -r dpkg-query -S 2>/dev/null \ | cut -d: -f1 \ | sort -u \ | xargs -r apt-mark manual' _ {} \; ; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ rm -rf /var/lib/apt/lists/*
# Production opcache settings (see the opcache section below). The opcache# extension is installed above (docker-php-ext-install opcache); this file only# tunes it.COPY docker/opcache.ini /usr/local/etc/php/conf.d/opcache.ini
# A static Composer binary for the one optimized-autoloader rebuild below. It is# copied into the build but the final stage runs no Composer at request time.COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/app
# Application code, then the vendor tree from the dependency stage. The .dockerignore# should already keep a host vendor/ out of the context; the rm here is a second line# of defense so a stale host-built vendor/ can never merge under the clean one (a# directory COPY merges, it does not replace).COPY . /var/www/appRUN rm -rf /var/www/app/vendorCOPY --from=vendor /app/vendor /var/www/app/vendor
# Now that the application source is present, regenerate the optimized class map# so the APP's own classes are in the optimized autoloader, not just the vendor# packages. --no-dev keeps require-dev out; --no-scripts avoids running# application hooks during the image build.RUN composer dump-autoload \ --optimize \ --no-dev \ --no-interaction \ --no-scripts \ && rm -f /usr/bin/composer
# The bundled fonts live at /var/www/app/resources/fonts. The native engine does# NOT read any font-path environment variable — the entrypoint registers that# directory in PHP (see "Bundle fonts into the image" below). There is no ENV# line for fonts here.
# Run as a non-root user (see the non-root section below).RUN useradd --system --no-create-home --uid 10001 appuser \ && chown -R appuser:appuser /var/www/appUSER appuser
CMD ["php", "bin/generate.php"]تشغّل مرحلة التبعيات مع --no-scripts فلا يعمل أي خطّاف ما بعد التثبيت للتطبيق على شجرة
ناقصة؛ شغّل أي خطوة بناء تطبيق (تصريف الأصول، تسخين الخبيئة) في مرحلة لاحقة بعد نسخ
الشيفرة.
تثبيت Composer متعدّد المراحل (بلا تبعيات تطوير)
قسم بعنوان «تثبيت Composer متعدّد المراحل (بلا تبعيات تطوير)»يجب ألا تحتوي الصورة المشحونة أدوات تطوير. وعَلَم --no-dev في composer install هو
السطر الحامل للحمل: فهو يتخطّى كل ما تحت require-dev في nextpdf/core وتطبيقك —
مُشغِّل الاختبارات والمحلّل الساكن وأدوات الطفرة — ولا مكان لأيٍّ منها في الإنتاج. اقرنه
بـ--optimize-autoloader فيكون المُحمِّل التلقائيّ خريطة أصناف مولَّدة بدلًا من مسح نظام
ملفات في كل طلب.
انسخ composer.json وcomposer.lock قبل بقية الشيفرة فيخبّئ Docker طبقة التبعيات
ولا يعيد الحلّ إلا حين يتغيّر ملف القفل. ولأن ذلك التثبيت الأول يعمل على ملف القفل وحده —
دون شيفرة التطبيق — فإن --optimize-autoloader هناك يبني خريطة أصناف لشجرة vendor
فقط؛ فأصناف تطبيقك الخاصة غير موجودة بعد. ولهذا تشغّل مرحلة وقت التشغيل
composer dump-autoload --optimize --no-dev --no-scripts مرة بعد نسخ الشيفرة: فهو
يطوي أصناف التطبيق في خريطة الأصناف المُحسَّنة نفسها. لا تشغّل composer dump-autoload
منفصلًا في شجرة عمل تطوّر فيها أيضًا (سيُودِع خريطة أصناف إنتاجية في شجرة تطوير)؛ إعادة
البناء مكانها في الصورة، بعد نسخ الشيفرة، كما هو موضّح أعلاه.
جمّع الخطوط في الصورة
قسم بعنوان «جمّع الخطوط في الصورة»يحلّ المحرّك الأصلي الخطوط من ملفات خطوط يستطيع قراءتها، لا من خطوط نظام التشغيل
المثبّتة. لا يفعل تثبيت حزم fonts-* أو تشغيل fc-cache شيئًا يراه المسار الأصلي، فهذه
الصورة لا تثبّت خطوط نظام. جمّع ملفات .ttf / .otf لديك تحت resources/fonts/؛
ويحملها COPY . /var/www/app أعلاه إلى الصورة أصلًا.
إيصال الملفات إلى الصورة نصف العمل فقط. فالمحرّك الأصلي المجرّد لا يقرأ أي متغيّر
بيئة لبحث الخطوط — NEXTPDF_FONTS_PATH هو القيمة الافتراضية لمفتاح تهيئة fonts_path
في حزمة nextpdf/laravel (env('NEXTPDF_FONTS_PATH', resource_path('fonts')))
ويستهلكه ذلك التكامل الإطاريّ فقط، لا nextpdf/core. فنقطة دخول php bin/generate.php
عادية مع ضبط ذلك المتغيّر وحده لا تسجّل خطوطًا وتعرض التوفو نفسه الذي وُجدت هذه الصورة
لمنعه. يجب أن تسجّل نقطة الدخول الدليل المجمَّع في PHP:
use NextPDF\Typography\FontRegistry;use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;
// Register the directory the Dockerfile bundled the fonts into.$registry = new FontRegistry('/var/www/app/resources/fonts');// (equivalently, $registry->addFontDirectory('/var/www/app/resources/fonts');)
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));$doc = $factory->create();ذلك كامل شأن Docker بالخطوط. أما قواعد تسمية الملفات وواجهة السجلّ ونمط التسخين والقفل ومعالجة نظام الملفات للقراءة فقط فتقيم كلها في الصفحة المخصَّصة — لا تكرّرها هنا. اقرأ وفّر الخطوط للمحرّك الأصلي في الإنتاج للنمط الكامل، وسجّل الدليل نفسه الذي جمّعته.
شغّل بمستخدم غير جذر
قسم بعنوان «شغّل بمستخدم غير جذر»تشغّل صور PHP الرسمية بصفتها root افتراضيًا. ومولّد PDF لا يحتاج الجذر، فأنشئ مستخدمًا
غير ممتاز وانتقل إليه. يضيف ملف Dockerfile أعلاه مستخدم نظام appuser بـUID عالٍ ثابت
(10001)، ويمنحه ملكية شجرة التطبيق، وينتهي بـUSER appuser فتكون كل عملية تبدؤها
الحاوية غير ممتازة.
أبقِ التطبيق للقراءة فقط في وقت التشغيل حيثما استطعت. يقرأ المحرّك ملفات خطوطه ويكتب خرجه
وخبيئة خطوط مُحلّلة اختيارية فقط، فحاوية readOnlyRootFilesystem تعمل ما دام مسار الخرج
وأي دليل خبيئة مَركبَين قابلين للكتابة. اقرن هذا بقدرات Linux مُسقَطة وعَلَم
no-new-privileges في منسّقك دفاعًا في العمق.
opcache للإنتاج
قسم بعنوان «opcache للإنتاج»يؤتي opcache ثماره لـعمّال PHP طويلي العمر — تجمّع FPM أو عملية Apache
mod_php تخدم طلبات كثيرة من عملية واحدة دافئة. تصرّف تلك العمليات أصنافك مرة ثم لا
تستعلم عن ملفات المصدر في مسار ساخن أبدًا، وهو بالضبط ما يشتريه لك
opcache.validate_timestamps=0. وopcache ليس ممكَّنًا جاهزًا في صورة php:8.4
الرسمية، فملف Dockerfile أعلاه يثبّته بـdocker-php-ext-install opcache (يمكنك مكافئًا
docker-php-ext-enable opcache إن كان الامتداد مُجمَّعًا أصلًا). وملف conf.d أدناه
ضبط، لا خطوة التمكين — فهو لا يفعل شيئًا حتى يُحمَّل الامتداد. اشحنه بوصفه تضمين conf.d
(docker/opcache.ini، منسوخًا في ملف Dockerfile):
opcache.enable=1opcache.enable_cli=0opcache.memory_consumption=192opcache.interned_strings_buffer=16opcache.max_accelerated_files=20000opcache.validate_timestamps=0يعني opcache.validate_timestamps=0 أن الخبيئة لا تعيد فحص ملفات المصدر أبدًا — وهو
صحيح لصورة غير قابلة للتغيير، إذ إن السبيل الوحيد لتغيّر الشيفرة صورة جديدة. اضبط
memory_consumption وmax_accelerated_files على عدد أصناف تطبيقك.
CMD المعروض مولّد CLI لمرة واحدة، وopcache.enable_cli=0 صحيح له. فعملية
php bin/generate.php قصيرة العمر تبدأ وتصرّف وتعرض مرة وتخرج، فخبيئة أكواد تشغيل لا
تستطيع مشاركتها مع طلب تالٍ لا تعطي فائدة — اترك opcache في CLI مطفأً ولا تدفع شيئًا من
كلفة ذاكرته. ولا يكسب opcache قوته إلا حيث تُعاد العملية: SAPI من FPM/Apache، أو
عامل CLI طويل العمر حقًّا (مستهلك طوابير أو خادم بنمط RoadRunner). ولن يضبط
opcache.enable_cli=1 إلا ذلك النوع من عمّال CLI المقيمين؛ أما لمولّد لمرة واحدة هنا
فأبقِه 0.
إذا شغّلت إعدادًا يستخدم التحميل المسبق لـopcache (عامل FPM طويل العمر بسكربت
opcache.preload)، فاضبط opcache.preload=/path/to/preload.php وأضف
opcache.preload_user=appuser فيعمل التحميل المسبق بصفته المستخدم غير الممتاز. ودون
سكربت opcache.preload فعليّ، لا يفعل opcache.preload_user شيئًا، ولهذا ليس في تهيئة
خطّ الأساس أعلاه — لا تضفه ما لم تضبط opcache.preload أيضًا.
تحقّق من الصورة
قسم بعنوان «تحقّق من الصورة»أضف خطوة تحقّق فتفشل صورة مبنيّة خطأً بصوت عالٍ بدلًا من إنتاج توفو أو خطأ مميت عند أول
طلب. يشحن NextPDF CLI يفحص أمره doctor بيئة PHP العاملة ويبلّغ عن الامتدادات التي
يبالي بها المحرّك بالضبط — openssl وzlib وmbstring وgd وcurl وintl. وتُعلن
الحزمة "bin": ["bin/nextpdf"]، فيثبّت Composer في تطبيق مستهلك الملف التنفيذيّ عند
vendor/bin/nextpdf (لا bin/nextpdf، وهو المسار داخل حزمة nextpdf/core نفسها).
شغّله داخل الصورة المبنيّة:
docker run --rm your-app:latest php vendor/bin/nextpdf doctorتؤكد نتيجة سليمة PHP 8.4 وتحميل كل امتداد مطلوب. اربط الاستدعاء نفسه في البناء (أو في وظيفة دخان CI) فيوقف امتداد مفقود خط الأنابيب:
# Fail the pipeline if the engine's environment is not healthy.docker run --rm your-app:latest php vendor/bin/nextpdf doctor || exit 1لفحص من طرف إلى طرف، اعرض صفحة واحدة عبر نقطة دخولك الخاصة وأكّد على الخرج، كما تصف صفحة الخطوط لفحص دخان خط.
الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»-
php:8.4-fpmأو-apacheبدلًا من-cli. استخدم SAPI الذي يخدم تطبيقك تحته فعلًا. قائمة الامتدادات متطابقة؛ ويختلف وسم الأساس وCMD/نقطة الدخول فقط. ولعامل طوابير أو وظيفة دفعة CLI، -cliصحيح. - Alpine (
php:8.4-alpine) يحتاج أسماء حزم مختلفة. أسطرapt-getأعلاه لصورة Debian الافتراضية. على Alpine، ثبّت ترويسات*-devبوصفها مجموعة بناء افتراضية (apk add --no-cache --virtual .build-deps icu-dev libpng-dev freetype-dev libjpeg-turbo-dev oniguruma-dev) وبعد خطوةdocker-php-ext-install gd intl mbstring opcache، apk del .build-deps— لكن أولًاapk add --no-cacheللمكتبات وقت التشغيل التي ترتبط بها الامتدادات (icu-libsوlibpngوfreetypeوlibjpeg-turboوoniguruma) حتى لا يفكّ حذف مجموعة البناء ربطintl.so/gd.so/mbstring.so. هذه قاعدة إبقاء مكتبات وقت التشغيل نفسها التي تفرضها كتلة Debian بـapt-mark. - لا تثبّت حزم
fonts-*. فهي غير مرئية للمحرّك الأصلي. جمّع ملفات الخطوط بدلًا منها — انظر صفحة الخطوط المرتبطة أعلاه. - Premium وionCube شأن صورة مختلف. تحتاج بنى NextPDF Pro / Enterprise المُرمَّزة بـionCube مُحمِّل ionCube مثبّتًا في الصورة ومطابقًا لبناء PHP الدقيق للحاوية (8.4، NTS مقابل ZTS). وذلك خارج نطاق صورة نواة؛ إن نشرت premium، فاتبع قسم Docker في إعداد مُحمِّل ionCube.
- أبقِ
vendor/مضيف خارج سياق البناء. يُبقي.dockerignore(مستثنيًاvendor/و.git/والخبائث المحليّة) شجرة المضيف خارج السياق كليًّا — وهو ما يجعل البناء صغيرًا وسريعًا وخاليًا من الأسرار المحليّة المسرَّبة. وهو يحرس أيضًا حالة دمج الدليل: COPYدليلٍ دمج، لا استبدال، فـvendor/مبنيًّا على المضيف بلغ السياق سيهبط أولًا ولن يكتبCOPY --from=vendor /app/vendor /var/www/app/vendorإلا المسارات التي تحتويها شجرة التبعيات النظيفة. وفي ملف Dockerfile هذا يزيلRUN rm -rf /var/www/app/vendorقبل نسخ vendor أي دليل كهذا أصلًا، فلا يمكن أن تحدث تلك البقايا هنا؛ ولا يعود خطر الدمج إلا إذا أسقطت حارسةrm -rfتلك، ولهذا فإن استثناء.dockerignoreهو الإصلاح الدائم.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»- لا تشحن تبعيات تطوير. يُبقي
--no-devأدوات الاختبار والتحليل وحزمها المنقولة خارج صورة وقت التشغيل وسطح هجومها. - شغّل غير ممتاز. يضمن
USER appuserالنهائيّ ألا تشغّل أي عملية حاوية بصفتها جذرًا. اقرنه بنظام ملفات جذر للقراءة فقط وقدرات مُسقَطة في منسّقك. - ثبّت صورة الأساس. ثبّت
php:8.4بمُلخَّص في الإنتاج فلا يستطيع بناء جديد سحب أساس متغيّر بصمت، وأعد البناء على وتيرة لالتقاط رُقع الأمان عمدًا. - أبقِ الخطوط والتراخيص خارج الطبقات العامة. جمّع فقط خطوطًا أنت مرخّص لتضمينها، ولا تطهُ ملف ترخيص premium في صورة تُدفع علنًا — بل مَركِبه في وقت التشغيل.
المطابقة
قسم بعنوان «المطابقة»لا يدّعي هذا الدليل أي ادعاء معياري. وتُقرأ حقائق المنصّة مباشرةً من حزمة nextpdf/core:
قيد php: >=8.4 <9.0 والامتدادات المطلوبة ext-mbstring وext-intl وext-gd و
ext-openssl وext-zlib وext-curl. وأمر التحقّق هو معالج doctor لـCLI nextpdf
الحقيقيّ — المُعلَن بوصفه "bin": ["bin/nextpdf"] في nextpdf/core ولذا المثبَّت عند
vendor/bin/nextpdf في تطبيق مستهلك — الذي يبلّغ عن مجموعة الامتدادات نفسها. ويسجّل
المحرّك الأصلي الخطوط عبر NextPDF\Typography\FontRegistry (وسيط مُنشئ الدليل /
addFontDirectory()) مربوطًا عبر NextPDF\Core\DocumentFactory؛ وNEXTPDF_FONTS_PATH
هو مفتاح تهيئة fonts_path لحزمة nextpdf/laravel (env('NEXTPDF_FONTS_PATH', resource_path('fonts')))، لا متغيّر يقرأه nextpdf/core. وسلوك السجلّ موثّق في صفحة
الخطوط المرتبطة تحت “انظر أيضًا”.
انظر أيضًا
قسم بعنوان «انظر أيضًا»- وفّر الخطوط للمحرّك الأصلي في الإنتاج: تسمية ملفات الخطوط وواجهة السجلّ ونمط التسخين والقفل الذي تعتمده هذه الصورة.
- بثّ ملف PDF كبير مُولَّد بوصفه استجابة HTTP: نموذج الذاكرة لخدمة مستند مبنيّ من متحكّم إطار.
- اعرض عند الحافة بـCloudflare: حين لا تكون حاوية داخل العملية بيئة التشغيل الصحيحة.
- إعداد مُحمِّل ionCube: شأن الصورة المنفصل لبنى premium المُرمَّزة بـionCube.