PDF 파싱 및 검사로 구조적 사실 얻기
한눈에 보기
섹션 제목: “한눈에 보기”이 레시피는 Core inspector의 Quick 폴백을 사용해 PDF에서 구조적 사실을 읽습니다. 여기에는 버전, 페이지 수, 암호화 플래그, 서명 플래그, 첨부 플래그, 파일 크기, 위험 플래그가 포함됩니다. Quick은 Spectrum 사이드카나 네트워크 없이 완전히 인프로세스로 실행됩니다. 검증기로 사용하지 말고 빠른 분류 용도로 사용하십시오.
composer require nextpdf/core:^3개념 개요
섹션 제목: “개념 개요”PDF는 파일 헤더에 버전을 기록합니다(ISO 32000-2 §7.5.2). 트레일러에는 두 개의 바이트 문자열로 구성된 파일 식별자(/ID)가 들어 있습니다(ISO 32000-2 §7.5.5). 서명이 존재하는 경우 이는 서명 딕셔너리로 표현되며, 그 Contents에는 DER CMS SignedData가 들어 있습니다(ISO 32000-2 §12.8.1). Quick 폴백은 문서 바이트를 제한적으로 스캔해 버전, 페이지 수 추정치, 그리고 암호화·서명·첨부 존재 플래그를 도출합니다.
API 표면
섹션 제목: “API 표면”먼저 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 : 2Encrypted : noSigned : noAttachments : noFile size : <n> bytesRisk flags : 0Route: 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”라는 메시지와 함께 inspect 예외를 던집니다.
- 암호화 플래그의 범위. 이 플래그는
/Encrypt트레일러 항목을 반영합니다. 플래그가 설정된 파일은 inspector가 복호화하지 않습니다.
Quick 폴백은 전체 파싱이 아닌 제한된 스캔입니다. 더 무거운 처리 전에 대량으로 유입되는 파일을 사전 라우팅하는 데 적합합니다.
보안 참고 사항
섹션 제목: “보안 참고 사항”inspector는 인프로세스로 동작하며 구조적 마커만 읽습니다. 문서 바이트는 호스트를 벗어나지 않으며, 문서 텍스트도 추출되지 않습니다. 예를 들어 임베디드 JavaScript와 같은 위험 플래그는 라우팅을 위한 권고 신호입니다. 이는 파일이 안전하거나 안전하지 않다고 단언하는 것이 아닙니다.
적합성
섹션 제목: “적합성”| 진술 | 사양 | 조항 | 참조 ID |
|---|---|---|---|
| 파일 헤더는 PDF 버전을 기록합니다. | ISO 32000-2 | §7.5.2 | |
트레일러 /ID는 두 개의 바이트 문자열로 구성된 파일 식별자입니다. | ISO 32000-2 | §7.5.5 | |
서명 딕셔너리 Contents는 DER CMS SignedData를 담습니다. | ISO 32000-2 | §12.8.1 |
이 레시피는 구조적 사실을 보고합니다. 파일이 유효하거나 안전하거나 적합하다고 단언하지 않습니다.
상업적 맥락
섹션 제목: “상업적 맥락”Standard 및 Full 검사 깊이는 Spectrum 사이드카를 통해 실행됩니다. 두 깊이에서는 더 풍부한 객체, 글꼴, 이미지 분석이 추가됩니다. 여기서 문서화한 Quick 폴백은 Core이며 오프라인으로 동작합니다.