ข้ามไปยังเนื้อหา

ตรวจสอบความถูกต้องของค่าฟิลด์ฟอร์มและ flatten พร้อมรักษาสถานะเชิงโต้ตอบ

ไปป์ไลน์ฟอร์มระดับโปรดักชันแทบไม่ควร flatten อินพุตดิบโดยตรง ขั้นแรกให้ตรวจสอบความถูกต้องของค่าแต่ละค่า จากนั้นจึงตัดสินใจว่าฟิลด์ใดควรกลายเป็นเนื้อหาถาวร และฟิลด์ใดยังคงแก้ไขได้ NextPDF core มีองค์ประกอบพื้นฐานสองอย่างสำหรับงานนี้ ได้แก่ trait สำหรับสร้างฟอร์ม HasFormFields ซึ่งเขียนค่าฟิลด์ลงในเอกสารขณะสร้างฟิลด์ และ flattenForms() ซึ่งฝังฟิลด์ทั้งหมดลงในกราฟิกหน้าแบบคงที่และนำฟอร์มเชิงโต้ตอบออก

สูตรนี้เชื่อมองค์ประกอบทั้งสองเข้าด้วยกันด้วยขั้นตอนการตรวจสอบความถูกต้องในชั้นแอปพลิเคชันที่ core จงใจปล่อยให้เป็นหน้าที่ของคุณ คุณจะ:

  • ตรวจสอบความถูกต้องของแมปค่ากับกฎเฉพาะของแต่ละฟิลด์ก่อนสร้างฟิลด์ใดๆ เพื่อไม่ให้ค่าที่ไม่ถูกต้องไปถึงเอกสารได้
  • สร้างชุดข้อมูลที่ผ่านการตรวจสอบหนึ่งชุด แล้วส่งออกสองครั้ง — ครั้งหนึ่งเป็นแบบ flatten (สำเนาที่ล็อกและอ่านอย่างเดียว) และอีกครั้งเป็นแบบเชิงโต้ตอบ (สำเนาที่แก้ไขได้) — เพื่อให้สถานะฟิลด์เดียวกันคงอยู่ในเอาต์พุตทั้งสอง

ข้อกำหนดเบื้องต้น: ต้องมีการติดตั้ง NextPDF core ที่ใช้งานได้ (composer require nextpdf/core) และอ่าน Build and pre-fill a PDF form กับ Flatten form fields ครบถ้วนแล้ว สูตรนี้นำกลไกการสร้างฟิลด์และการ flatten มารวมกัน

ขอบเขตของเรื่อง flattenForms() ของ core ทำงานกับทั้งเอกสาร: คือจะ flatten ทุกฟิลด์หรือไม่ flatten เลย core form API ไม่มีสวิตช์สาธารณะสำหรับ flatten เฉพาะฟิลด์ และไม่มีตัวตรวจสอบความถูกต้องของค่าในตัว ดังนั้น “flatten บางฟิลด์ คงเหลือฟิลด์อื่นไว้ให้ แก้ไขได้” จึงเกิดขึ้นที่ชั้นแอปพลิเคชัน: ตรวจสอบความถูกต้องครั้งเดียว จากนั้นเรนเดอร์ ชุดข้อมูลที่ผ่านการตรวจสอบชุดเดียวกันเป็นเอกสารสองฉบับ สูตรนี้บันทึกรูปแบบดังกล่าวไว้ โดย ไม่ได้สร้างเมธอด core แบบเฉพาะฟิลด์ขึ้นมาใหม่

Terminal window
composer require nextpdf/core

ไม่จำเป็นต้องใช้ extension เพิ่มเติม ทั้ง trait สำหรับสร้างฟอร์มและตัว flattener รวมอยู่ใน core แล้ว

ฟิลด์ฟอร์ม Acrobat (AcroForm) เก็บค่าปัจจุบันไว้ในรายการ V ของพจนานุกรมฟิลด์ flattenForms() อ่านค่า V ของแต่ละฟิลด์และเรนเดอร์ลงในสตรีมเนื้อหาของหน้าที่ฟิลด์นั้นสังกัดอยู่ — ฟิลด์ข้อความกลายเป็นข้อความ BT ... Tj ... ET ช่องทำเครื่องหมายและปุ่มตัวเลือกกลายเป็นเส้นที่วาดขึ้น และฟิลด์ตัวเลือกจะเรนเดอร์รายการที่ถูกเลือก จากนั้นจะลบรายการ /AcroForm ในแคตาล็อกออก ผลลัพธ์คือฟอร์มแบบไม่เชิงโต้ตอบ: การแสดงแทนฟิลด์แบบคงที่ที่แสดงผลเหมือนกันในโปรแกรมอ่านทุกตัว โดยไม่ต้องใช้ความสามารถในการกรอกฟอร์ม (ISO 32000-2 12.7)

ข้อเท็จจริงสองประการกำหนดรูปแบบระดับโปรดักชัน:

  1. core ไม่ตรวจสอบความถูกต้องของค่าฟิลด์ เมธอดการสร้างแต่ละตัว (textField(), comboBox(), checkBox() และอื่นๆ) เขียนค่าใดๆที่ส่งเข้าไปลงใน V โดยตรง รูปแบบอีเมล การเป็นสมาชิกของตัวเลือกที่อนุญาต และการมีอยู่ของฟิลด์ที่จำเป็นเป็นเรื่องของแอปพลิเคชัน ตรวจสอบความถูกต้องก่อนสร้าง และหยุดทันทีเมื่อมีการละเมิด แทนที่จะส่งออกเอกสารที่ฝังค่าไม่ถูกต้องไว้

  2. การ flatten ย้อนกลับไม่ได้และทำกับทั้งเอกสาร หลังจากเรียก flattenForms() และ save() แล้ว ฟิลด์จะกลายเป็นกราฟิกแบบคงที่ หากต้องการเก็บสำเนาที่แก้ไขได้ไว้ด้วย ไม่ต้องพยายามย้อนการ flatten — ให้เรนเดอร์ชุดข้อมูลที่ผ่านการตรวจสอบเป็นครั้งที่สองโดยไม่เรียก flattenForms() สำเนาทั้งสองเริ่มจากค่าที่ผ่านการตรวจสอบชุดเดียวกัน ดังนั้นสำเนาที่ล็อกและสำเนาที่แก้ไขได้จึงมีสถานะฟิลด์เหมือนกัน

โปรไฟล์การทำซ้ำได้คือ structural: เอกสารแต่ละฉบับมีอาร์เรย์ /ID ใน trailer ซึ่งการประมวลผลภายหลังจะปรับให้เป็นมาตรฐานก่อนเปรียบเทียบการรันสองครั้ง

NextPDF\Core\Document (ผ่าน NextPDF\Core\Concerns\HasFormFields):

  • textField(string $name, float $x, float $y, float $w, float $h, string $default = '', array $options = []): static — สร้างฟิลด์ข้อความโดยกำหนดค่าไว้ใน default
  • comboBox(string $name, float $x, float $y, float $w, float $h, array $items, string $selected = ''): static — สร้างดรอปดาวน์โดยกำหนดรายการที่ถูกเลือกไว้ใน selected
  • checkBox(string $name, float $x, float $y, float $size, bool $checked = false): static — สร้างช่องทำเครื่องหมายโดยกำหนดสถานะไว้ใน checked
  • flattenForms(): static — ฝังค่าของทุกฟิลด์ลงในเนื้อหาหน้าแบบคงที่และตัด AcroForm ออก เป็น no-op เมื่อไม่มีฟิลด์ ภายในมอบหมายงานไปยัง NextPDF\Form\FormFlattener

NextPDF\Core\Concerns\HasOutput:

  • save(string $path): void — สร้างและเขียน PDF โยน NextPDF\Exception\InvalidConfigException เมื่อพาธเอาต์พุตเป็น stream wrapper มี null byte หรือระบุไดเรกทอรีหลักที่ไม่มีอยู่

ตัวตรวจสอบความถูกต้องในตัวอย่างด้านล่างเป็นโค้ดของแอปพลิเคชันที่ต้องดูแลเอง ไม่ใช่สัญลักษณ์จาก core และ core ไม่มี API สำหรับตรวจสอบความถูกต้องของค่า จึงต้องระบุขั้นตอนการตรวจสอบไว้อย่างชัดเจนในที่นี้

โฟลว์ขั้นต่ำนี้ตรวจสอบความถูกต้องของแมปค่า สร้างสามฟิลด์จากแมปนั้น จากนั้น flatten และบันทึกสำเนาที่ล็อกหนึ่งชุด

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
/** @var array<string, string> $input Untrusted value map (e.g. from a request). */
$input = [
'full_name' => 'Ada Lovelace',
'email' => '[email protected]',
'country' => 'Taiwan',
];
$allowedCountries = ['United Kingdom', 'Taiwan', 'Japan'];
// Validate before authoring: core writes whatever you pass, so reject early.
if (trim($input['full_name']) === '') {
throw new InvalidArgumentException('full_name must not be empty.');
}
if (filter_var($input['email'], FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidArgumentException('email is not a valid address.');
}
if (!in_array($input['country'], $allowedCountries, true)) {
throw new InvalidArgumentException('country is not an allowed option.');
}
$doc = Document::createStandalone();
$doc->setTitle('Validated Form (locked copy)');
$doc->addPage();
$doc->textField(name: 'full_name', x: 20, y: 30, w: 90, h: 8, default: $input['full_name']);
$doc->textField(name: 'email', x: 20, y: 45, w: 90, h: 8, default: $input['email']);
$doc->comboBox(
name: 'country',
x: 20, y: 60, w: 90, h: 8,
items: $allowedCountries,
selected: $input['country'],
);
// Whole-document flatten: every field becomes static graphics.
$doc->flattenForms();
$doc->save(__DIR__ . '/registration-locked.pdf');
echo "Wrote registration-locked.pdf\n";

โฟลว์ระดับโปรดักชันแยกการตรวจสอบความถูกต้องออกจากการเรนเดอร์ FieldRuleSet แบบระบุชนิดข้อมูลจะตรวจสอบความถูกต้องของแมปค่าหนึ่งครั้งและคืนชุดข้อมูลที่ผ่านการตรวจสอบ ฟังก์ชันตัวช่วย renderForm() เพียงตัวเดียวสร้างฟิลด์และรันสองครั้ง — แบบ flatten สำหรับสำเนาที่ล็อก และแบบไม่ flatten สำหรับสำเนาที่แก้ไขได้ สำเนาทั้งสองมาจากค่าที่ผ่านการตรวจสอบชุดเดียวกัน ดังนั้นสถานะเชิงโต้ตอบจึงคงอยู่ในทั้งสองสำเนา ฮาร์เนสอ่านพาธเอาต์พุตจาก NEXTPDF_COOKBOOK_LOCKED_OUTPUT และ NEXTPDF_COOKBOOK_EDITABLE_OUTPUT

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Exception\InvalidConfigException;
/**
* A single validated form record. Immutable: once constructed, every value has
* already passed the rule set, so the rendering step cannot re-introduce a bad
* value. This is the "validate once, render many" boundary.
*/
final readonly class ValidatedRegistration
{
/**
* @param non-empty-string $fullName
* @param non-empty-string $email
* @param non-empty-string $country
*/
public function __construct(
public string $fullName,
public string $email,
public string $country,
public bool $newsletter,
) {}
}
/**
* Application-layer field validation. Core performs no value validation, so the
* rules live here. Each method throws on the first violation; the caller maps
* the exception to an HTTP 422 or a user-facing message.
*/
final class FieldRuleSet
{
/** @var list<non-empty-string> */
private const array ALLOWED_COUNTRIES = ['United Kingdom', 'Taiwan', 'Japan', 'Germany'];
/**
* @param array<string, string|bool> $input Untrusted value map.
*
* @throws InvalidArgumentException When any field fails its rule.
*/
public function validate(array $input): ValidatedRegistration
{
$fullName = $this->requireNonEmpty($input, 'full_name');
$email = $this->requireEmail($input, 'email');
$country = $this->requireAllowed($input, 'country', self::ALLOWED_COUNTRIES);
$newsletter = $input['newsletter'] ?? false;
if (!is_bool($newsletter)) {
throw new InvalidArgumentException('newsletter must be a boolean.');
}
return new ValidatedRegistration(
fullName: $fullName,
email: $email,
country: $country,
newsletter: $newsletter,
);
}
/**
* @param array<string, string|bool> $input
*
* @return non-empty-string
*
* @throws InvalidArgumentException
*/
private function requireNonEmpty(array $input, string $key): string
{
$value = $input[$key] ?? '';
if (!is_string($value) || trim($value) === '') {
throw new InvalidArgumentException(sprintf('%s must not be empty.', $key));
}
return $value;
}
/**
* @param array<string, string|bool> $input
*
* @return non-empty-string
*
* @throws InvalidArgumentException
*/
private function requireEmail(array $input, string $key): string
{
$value = $input[$key] ?? '';
if (!is_string($value) || $value === '' || filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidArgumentException(sprintf('%s is not a valid email address.', $key));
}
return $value;
}
/**
* @param array<string, string|bool> $input
* @param list<non-empty-string> $allowed
*
* @return non-empty-string
*
* @throws InvalidArgumentException
*/
private function requireAllowed(array $input, string $key, array $allowed): string
{
$value = $input[$key] ?? '';
if (!is_string($value) || !in_array($value, $allowed, true)) {
throw new InvalidArgumentException(sprintf('%s is not an allowed option.', $key));
}
return $value;
}
/** @return list<non-empty-string> */
public function allowedCountries(): array
{
return self::ALLOWED_COUNTRIES;
}
}
/**
* Author the same field layout from one validated record. When $flatten is
* true, every field is baked into static page content and the AcroForm is
* dropped; when false, the fields stay interactive and editable. Both paths
* start from identical values, preserving the form's state across copies.
*/
function renderForm(ValidatedRegistration $record, FieldRuleSet $rules, bool $flatten): Document
{
$doc = Document::createStandalone();
$doc->setTitle($flatten ? 'Customer Registration (locked)' : 'Customer Registration (editable)');
$doc->addPage();
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, 'Customer Registration', newLine: true);
$doc->ln(4);
$leftMargin = 15.0;
$fieldX = 70.0;
$fieldW = 120.0;
$fieldH = 8.0;
$rowSpacing = 12.0;
$y = 40.0;
$doc->setFont('helvetica', '', 10);
$doc->setXY($leftMargin, $y);
$doc->cell(50, $fieldH, 'Full Name:');
$doc->textField(name: 'full_name', x: $fieldX, y: $y, w: $fieldW, h: $fieldH, default: $record->fullName);
$y += $rowSpacing;
$doc->setXY($leftMargin, $y);
$doc->cell(50, $fieldH, 'Email:');
$doc->textField(name: 'email', x: $fieldX, y: $y, w: $fieldW, h: $fieldH, default: $record->email);
$y += $rowSpacing;
$doc->setXY($leftMargin, $y);
$doc->cell(50, $fieldH, 'Country:');
$doc->comboBox(
name: 'country',
x: $fieldX,
y: $y,
w: $fieldW,
h: $fieldH,
items: $rules->allowedCountries(),
selected: $record->country,
);
$y += $rowSpacing;
$doc->setXY($leftMargin, $y);
$doc->cell(50, $fieldH, 'Newsletter:');
$doc->checkBox(name: 'newsletter', x: $fieldX, y: $y, size: 5, checked: $record->newsletter);
if ($flatten) {
// Whole-document flatten: locked, read-only copy.
$doc->flattenForms();
}
return $doc;
}
/** @var array<string, string|bool> $input Untrusted value map (request payload). */
$input = [
'full_name' => 'Ada Lovelace',
'email' => '[email protected]',
'country' => 'Taiwan',
'newsletter' => true,
];
$rules = new FieldRuleSet();
try {
// Validate once. A violation aborts before any document is built.
$record = $rules->validate($input);
// Render the validated dataset twice: locked, then editable.
$locked = renderForm($record, $rules, flatten: true);
$editable = renderForm($record, $rules, flatten: false);
$lockedPath = getenv('NEXTPDF_COOKBOOK_LOCKED_OUTPUT')
?: __DIR__ . '/registration-locked.pdf';
$editablePath = getenv('NEXTPDF_COOKBOOK_EDITABLE_OUTPUT')
?: __DIR__ . '/registration-editable.pdf';
$locked->save($lockedPath);
$editable->save($editablePath);
echo "Wrote locked and editable registration copies\n";
} catch (InvalidArgumentException $e) {
// Validation failure: a bad value never reached the document.
fwrite(STDERR, 'Form validation failed: ' . $e->getMessage() . "\n");
exit(1);
} catch (InvalidConfigException $e) {
// Output failure: bad path, missing directory, or stream wrapper.
fwrite(STDERR, sprintf(
'PDF save failed for key "%s": %s' . "\n",
$e->getConfigKey(),
$e->getMessage(),
));
exit(1);
}

เอาต์พุตที่คาดหวัง:

Wrote locked and editable registration copies

สำเนาที่ล็อกจะเปิดขึ้นโดยไม่มีฟิลด์เชิงโต้ตอบ — ค่าต่างๆเป็นกราฟิกแบบคงที่ สำเนาที่แก้ไขได้จะเปิดขึ้นโดยมีค่าเดียวกันกรอกไว้ล่วงหน้า และทุกฟิลด์ยังคงแก้ไขได้ ทั้งสองสำเนาสะท้อนชุดข้อมูลที่ผ่านการตรวจสอบชุดเดียว

  • ตรวจสอบความถูกต้องก่อนสร้าง ไม่ใช่หลังจากนั้น เมธอดการสร้างเขียนค่าของคุณลงใน V แบบตรงตามตัวอักษร ไม่มี hook ของ core ที่ปฏิเสธค่ารูปแบบผิดในเวลา save() ดังนั้นค่าที่ข้ามการตรวจสอบความถูกต้องจะถูกฝังลงในสำเนาที่ flatten แล้วโดยไม่มีทางกู้คืน
  • flattenForms() ทำทั้งหมดหรือไม่ทำเลย โดยจะ flatten ทุกฟิลด์ในเอกสาร หากต้องการให้บางฟิลด์ยังแก้ไขได้ ให้เรนเดอร์เอกสารฉบับที่สองโดยไม่เรียกการ flatten ตามที่ตัวอย่างระดับโปรดักชันทำ — ไม่ควรคาดหวังว่าจะมีสวิตช์แบบเฉพาะฟิลด์ใน core API
  • ลำดับการเรียก สร้างทุกฟิลด์ก่อน จากนั้นเรียก flattenForms() แล้วจึง save() การเรียก flattenForms() เมื่อไม่มีฟิลด์เป็น no-op ที่ปลอดภัย ส่วนการเรียกหลัง save() ไม่มีผลต่อไบต์ที่เขียนไปแล้ว
  • ชื่อฟิลด์ต้องไม่ซ้ำกัน ฟิลด์สองตัวที่ใช้ชื่อเดียวกันจะกลายเป็นฟิลด์เชิงตรรกะหนึ่งตัวที่มีค่าร่วมกันในโปรแกรมอ่านที่ทำตามมาตรฐาน ตรวจสอบความไม่ซ้ำกันของชื่อเมื่อชื่อถูกกำหนดจากข้อมูล
  • ค่าความจริงของช่องทำเครื่องหมายขณะ flatten ช่องทำเครื่องหมายที่ flatten แล้วจะวาดเครื่องหมายถูกเมื่อค่าเป็น Yes, On, 1 หรือ true ส่วนค่าว่างหรือ Off จะวาดเฉพาะกล่อง ส่งค่า boolean จริงไปยัง checkBox() เพื่อให้สถานะที่เรนเดอร์ตรงกับค่าที่ผ่านการตรวจสอบ
  • ฟิลด์ลายเซ็นจะไม่ถูก flatten ลักษณะที่ปรากฏของฟิลด์ /Sig สร้างจากเพย์โหลดลายเซ็น ไม่ใช่ค่าที่เรนเดอร์ใหม่ได้ ตัว flattener จึงข้ามฟิลด์นี้ ให้ flatten ก่อนลงนาม และห้าม flatten หลังลงนามเด็ดขาด
  • สำเนาที่แก้ไขได้ยังคงแก้ไขได้ การรักษาสถานะไว้ในสำเนาที่แก้ไขได้หมายความว่าผู้รับสามารถเปลี่ยนแปลงได้ ให้ถือว่าสำเนาที่ล็อกเป็นบันทึกอย่างเป็นทางการ และสำเนาที่แก้ไขได้เป็นฉบับร่างสำหรับใช้งาน

การตรวจสอบความถูกต้องมีความซับซ้อนเชิงเส้นตามจำนวนฟิลด์และรันหนึ่งครั้งต่อชุดข้อมูล การเรนเดอร์แต่ละครั้งสร้างคำอธิบายประกอบ widget หนึ่งรายการพร้อมลักษณะที่ปรากฏต่อหนึ่งฟิลด์ ขั้นตอน flatten เพิ่มบล็อกเนื้อหาที่มีขอบเขตจำกัดต่อหนึ่งฟิลด์ การเรนเดอร์ชุดข้อมูลสองครั้งทำให้ต้นทุนต่อเอกสารเพิ่มขึ้นราวสองเท่า ซึ่งยังคงอยู่ภายในงบประมาณ 1500 ms / 64 MB ได้อย่างเหลือเฟือสำหรับฟอร์มที่มีฟิลด์ไม่กี่ร้อยฟิลด์ หากต้องการเอาต์พุตเพียงชุดเดียว ให้เรนเดอร์ครั้งเดียวและข้ามรอบที่สองไป

  • ตรวจสอบความถูกต้องของอินพุตที่ไม่น่าเชื่อถือที่ขอบเขต รูปแบบอีเมล การเป็นสมาชิกของตัวเลือกที่อนุญาต และการมีอยู่ของฟิลด์ที่จำเป็นถูกบังคับใช้ในโค้ดแอปพลิเคชัน เพราะ core ไม่ได้บังคับใช้สิ่งเหล่านี้ ให้ escape หรือปรับค่าใดๆที่มาจากอินพุตที่ไม่น่าเชื่อถือให้เป็นมาตรฐานก่อนที่ค่านั้นจะไปถึงฟิลด์ เพราะ core เขียนค่านั้นลงในเอกสารแบบตรงตามตัวอักษร
  • การ flatten ไม่ใช่การควบคุมการเข้าถึง ค่าที่ flatten แล้วไม่สามารถแก้ไขได้ในโปรแกรมอ่านทั่วไป แต่ยังคงมองเห็นได้ในเนื้อหาของหน้าและสามารถดึงออกมาได้ด้วยเครื่องมือข้อความใดๆ อย่าถือว่าการ flatten เป็น redaction หรือเป็นการปกป้องค่าที่ละเอียดอ่อน
  • สำเนาที่แก้ไขได้มีข้อมูลเดียวกัน แจกจ่ายให้เฉพาะฝ่ายที่ได้รับอนุญาตให้เห็นและเปลี่ยนแปลงค่าเหล่านั้นเท่านั้น เมื่อเนื้อหามีความละเอียดอ่อน ให้ผนวกสำเนาฉบับใดก็ได้เข้ากับ Encrypt with permissions และสังเกตข้อควรระวังที่อาศัยความร่วมมือของโปรแกรมอ่านตามที่อธิบายไว้ในนั้น: บิตสิทธิ์ไม่ได้บังคับใช้ข้อจำกัดในการอ่าน
  • ล้มเหลวแบบปิด ตัวอย่างระดับโปรดักชันออกด้วยค่าที่ไม่ใช่ศูนย์เมื่อการตรวจสอบความถูกต้องหรือเอาต์พุตล้มเหลว แทนที่จะเขียนเอกสารที่ไม่สมบูรณ์หรือไม่ถูกต้อง ห้ามกลืน exception เหล่านี้เด็ดขาด
ข้อความระบุข้อกำหนดข้อรหัสอ้างอิง (reference_id)
ฟอร์มที่ flatten แล้วคือการแสดงแทนฟิลด์แบบไม่เชิงโต้ตอบ (คงที่)ISO 32000-212.7

NextPDF สร้างโครงสร้างแบบคงที่ตามที่อธิบายไว้ในข้อที่อ้างถึง แต่ไม่ได้ยืนยันความสอดคล้องตาม ISO 32000-2 แบบครอบคลุมทั้งหมด กฎการตรวจสอบความถูกต้องในสูตรนี้เป็นนโยบายของแอปพลิเคชัน ไม่ใช่ข้อกำหนดด้านความสอดคล้องของมาตรฐาน

  • Build and pre-fill a PDF form — สร้างฟิลด์และกำหนดค่าเริ่มต้นให้ฟิลด์
  • Flatten form fields — การ flatten ทั้งเอกสารที่สูตรนี้ต่อยอดมา
  • Handle errors with the NextPDF exception hierarchy — ดักจับความล้มเหลวในระดับความละเอียดที่เหมาะสม
  • Encrypt with permissions — เพิ่มการรักษาความลับเมื่อข้อมูลฟอร์มมีความละเอียดอ่อน
  • Form module — เอกสารอ้างอิงของฟิลด์ฟอร์ม