Dompdf에서 NextPDF로 마이그레이션
한눈에 보기
섹션 제목: “한눈에 보기”이 가이드는 Dompdf 기반 코드베이스를 NextPDF Html 파이프라인으로 이전하는 방법을 설명합니다. Dompdf와 NextPDF는 HTML을 불러오고, 렌더링하고, PDF를 내보내는 동일한 흐름을 공유하므로 대부분의 호출 지점은 기계적으로 변환됩니다. 실제 작업의 핵심은 옵션 매핑과 CSS 지원 차이를 다루는 것입니다. NextPDF와 Dompdf는 독립적인 엔진이므로, Dompdf가 만든 레이아웃은 NextPDF 결과와 호환되는 수준이지 바이트 단위로 동일하지는 않습니다. 이 가이드는 동사 매핑, 옵션 키 매핑, 동작 차이, 그리고 안전한 마이그레이션 순서를 다룹니다.
NextPDF가 어떤 HTML/CSS 기능을 지원한다고 해서 특정 Dompdf 문서가 픽셀 단위로 동일하게 재현된다고 보장할 수는 없습니다. 어떤 기능이 검증(Verified)되었는지에 대한 권위 있는 기준은 CSS 지원 매트릭스입니다. 이 가이드는 동작을 설명하며, 시각적 동등성을 주장하지 않습니다.
composer require nextpdf/core:^3전환 기간에는 dompdf/dompdf를 설치된 상태로 유지하세요. 각 호출 지점이 전환될 때까지 두 엔진을 나란히 실행하는 방식은 안전한 마이그레이션 순서를 따르고, 전환이 완료되면 제거합니다.
개념적 개요
섹션 제목: “개념적 개요”Dompdf의 Dompdf 객체는 DOM, 스타일시트, 프레임 트리, 캔버스를 모두 소유하는 단일 파사드입니다. NextPDF는 이러한 관심사를 분리합니다. NextPDF\Core\Document는 페이지 모델과 출력을 소유하고, writeHtml() 메서드 하나가 HTML 파이프라인을 구동합니다. “렌더링 후 출력”이라는 별도의 2 단계 과정은 없습니다. writeHtml()는 콘텐츠를 작성하는 동안 레이아웃도 배치하며, save(), output(), 또는 getPdfData()로 문서를 내보냅니다.
NextPDF가 작성하는 페이지 콘텐츠는 ISO 32000-2 콘텐츠 스트림 페인팅입니다(ISO 32000-2 §8, iso32000_2_sec8#x1.x3.p14). 용지 크기 옵션이 제어하는 페이지 기하 구조는 페이지 객체의 MediaBox에 매핑됩니다(ISO 32000-2 §7, iso32000_2_sec7#x1.x104.p10). 이는 적합한 모든 작성기가 공유하는 엔진 수준의 기본 사항입니다. 그러나 CSS를 그 콘텐츠로 바꾸는 레이아웃 알고리즘은 NextPDF 고유의 것이며, Dompdf의 것과 다릅니다(동작상의 차이 참조).
API 표면
섹션 제목: “API 표면”NextPDF Html API는 Html 모듈 레퍼런스(PHPDoc에서 자동 생성)에 문서화되어 있습니다. 아래에서 사용하는 핵심 진입점은 다음과 같습니다. Document::createStandalone(), Document::writeHtml(string $html): static, Document::writeHtmlCell(...), Document::output(?string, OutputDestination), Document::save(string $path): void, Document::getPdfData(): string, 그리고 NextPDF\Core\Config 값 객체(pageSize, margins, fontsDirectory)입니다.
API 동사 매핑
섹션 제목: “API 동사 매핑”아래 Dompdf 공개 API 이름은 업스트림 공개 저장소(dompdf/dompdf, master)와 대조해 확인했습니다 — 저장소 내 _source-sidecar-upstream-api.md 출처 사이드카를 참조하세요. 업스트림 문서 텍스트는 재현하지 않았습니다.
| Dompdf | NextPDF | 참고 |
|---|---|---|
new Dompdf($options) | Document::createStandalone($config) | Dompdf는 Options 객체를 받고, NextPDF는 NextPDF\Core\Config를 받습니다. 오래 실행되는 워커의 경우 createStandalone() 대신 DocumentFactory를 사용하세요. |
$dompdf->loadHtml($html, $encoding) | $doc->writeHtml($html) | NextPDF는 입력을 UTF-8로 취급합니다. 인코딩 인자를 전달하는 대신 UTF-8이 아닌 입력은 호출 전에 변환하세요. |
$dompdf->loadHtmlFile($file) | $doc->writeHtml(file_get_contents($file)) | NextPDF에는 파일 로드 변형이 없습니다. I/O 정책이 코드에 남도록 파일을 직접 읽으세요. |
$dompdf->setPaper($size, $orientation) | ConfigpageSize(PageSize 값 객체) | 자세한 내용은 옵션 맵을 참조하세요. |
$dompdf->render() | (암묵적) | NextPDF는 writeHtml() 중에 레이아웃을 배치하므로 별도의 렌더링 단계가 없습니다. render() 호출을 제거하세요. |
$dompdf->output() | $doc->getPdfData() | PDF 바이트를 반환합니다. |
$dompdf->stream($name, $opts) | $doc->output($name, OutputDestination::Download) | NextPDF는 OutputDestination 열거형을 통해 대상을 분리합니다. |
$dompdf->setBasePath($p) / setProtocol() / setBaseHost() | (리소스 해석 방식이 다름) | NextPDF는 상대 리소스를 기본 path/protocol 삼중 구성이 아니라 문서 작업 집합을 기준으로 해석합니다 — 동작상의 차이를 참조하세요. |
$dompdf->addInfo($label, $value) | $doc->setTitle() / setAuthor() / 메타데이터 API | Dompdf의 자유 형식 정보 쌍은 타입이 지정된 메타데이터 세터에 매핑됩니다(ISO 32000-2 §14 문서 정보, iso32000_2_sec14#x1.x5.p5). |
$dompdf->setHttpContext($ctx) | (해당 없음) | NextPDF는 스트림 컨텍스트를 통해 원격 리소스를 가져오지 않습니다 — 지원되지 않음 / 직접적인 대응 없음을 참조하세요. |
코드 예제 — 빠른 시작
섹션 제목: “코드 예제 — 빠른 시작”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// Dompdf:// $dompdf = new Dompdf();// $dompdf->loadHtml('<h1>Invoice</h1>');// $dompdf->setPaper('A4', 'portrait');// $dompdf->render();// file_put_contents('out.pdf', $dompdf->output());
// NextPDF — the createStandalone() default page size is A4 portrait:$doc = Document::createStandalone();$doc->setTitle('Invoice');$doc->addPage();$doc->writeHtml('<h1>Invoice</h1>');$doc->save(__DIR__ . '/out.pdf');
echo "Wrote out.pdf\n";코드 예제 — 프로덕션
섹션 제목: “코드 예제 — 프로덕션”이 예제는 examples/08-html-basic.php(이 가이드의 실행 가능한 기반)를 반영하며, 기본값이 아닌 명시적 용지 크기와 여백을 사용합니다. 이는 Dompdf의 setPaper()에 Options 여백 구성을 더한 것과 동등합니다.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\OutputDestination;use NextPDF\Core\Config;use NextPDF\Core\Document;use NextPDF\ValueObjects\Margin;use NextPDF\ValueObjects\PageSize;
// Equivalent of: $dompdf->setPaper('letter','portrait') + margin options.// US Letter portrait = 612 x 792 pt.// Margin constructor order is (top, right, bottom, left) — all 0.5in here.$config = new Config( pageSize: new PageSize(612.0, 792.0, 'Letter'), margins: new Margin(36.0, 36.0, 36.0, 36.0), // top,right,bottom,left; 0.5in in points);
$doc = Document::createStandalone($config);$doc->setTitle('Quarterly Report');$doc->setAuthor('Finance');$doc->addPage();
$html = <<<'HTML'<h1 style="color:#1E3A8A;">Quarterly Report</h1><p>This report renders through the NextPDF Html pipeline. The CSS subset thatis <strong>Verified</strong> for production is the support-matrix authority,not this page.</p><table border="1"> <tr><th>Region</th><th>Total</th></tr> <tr><td>EMEA</td><td>1,204</td></tr></table>HTML;
$doc->writeHtml($html);
// Equivalent of $dompdf->stream('report.pdf'):$doc->output('report.pdf', OutputDestination::Download);엣지 케이스 및 주의 사항
섹션 제목: “엣지 케이스 및 주의 사항”- 2 단계 렌더링 없음.
render()와output()사이의 상태를 검사하는(예: 페이지 수 읽기) Dompdf 코드는 그 정확한 지점에 대응하는 NextPDF 대응물이 없습니다. 대신writeHtml()이후에 문서를 조회하세요. - 인코딩. NextPDF는 Dompdf의
$encoding매개변수를 제거합니다.writeHtml()전에 입력을 UTF-8로 변환하세요. Latin-1 바이트를 전달하면 오류가 아니라 깨진 문자(mojibake)가 발생합니다. render()가 그대로 남아 있음. 남아 있는$dompdf->render()형태의 호출은 대응하는 NextPDF 메서드가 없으므로 치명적인 “undefined method” 오류를 일으킵니다. 전환 중에 삭제하고, 스텁으로 두지 마세요.- 인라인 PHP. Dompdf의
enable_php는<script type="text/php">를 평가합니다. NextPDF는 설계상 문서 내 PHP 실행을 전혀 지원하지 않습니다(주입 표면이기 때문입니다). 해당 로직을writeHtml()전의 PHP 코드로 옮기세요. - 상대 리소스 해석. Dompdf는
<img src>를 기본 path/protocol/host 삼중 구성을 기준으로 해석합니다. NextPDF는 문서 작업 집합을 기준으로 해석합니다. 마이그레이션 중에는 변수를 제거하기 위해 절대 경로나 미리 해석된 데이터 URI를 전달하세요.
writeHtml()는 단일 스트리밍 패스로 레이아웃을 배치합니다(ADR-001). 레이아웃 이후 유지되는 중간 프레임 트리 객체가 없으므로, 최대 메모리는 DOM 노드 수가 아니라 문서 크기를 따릅니다. 이 가이드 예제의 성능 예산은 wall_ms: 2000, peak_mb: 128입니다. 대용량 문서에서는 수 메가바이트 크기의 단일 문자열을 만드는 대신 addPage() 경계로 HTML을 분할하세요.
보안 참고 사항
섹션 제목: “보안 참고 사항”- 스트림 컨텍스트를 통한 원격 가져오기 없음. NextPDF는 Dompdf의
setHttpContext()/enable_remote원격 가져오기 경로를 구현하지 않습니다. 원격 자산은 애플리케이션에서 해석하고 검증한 뒤, 바이트나 데이터 URI를 전달하세요. 이는enable_remote가 수반하는 SSRF 표면을 제거합니다. - 문서 내 코드 실행 없음.
enable_php대응물이 없는 것은 의도적인 강화이지 결함이 아닙니다. - 타입이 지정된 세터를 통해 설정한 문서 메타데이터는 ISO 32000-2 §14 정보 딕셔너리 / XMP에 기록됩니다(
iso32000_2_sec14#x1.x5.p5). 그 위치에 비밀 정보를 넣지 마세요.
적합성
섹션 제목: “적합성”| 진술 | 사양 | 조항 | reference_id(참조 ID) |
|---|---|---|---|
| 페이지 콘텐츠는 opaque/transparent 모델의 콘텐츠 스트림 페인팅입니다. | ISO 32000-2 | §8 | |
| 용지 크기는 페이지 객체의 경계 박스에 매핑됩니다. | ISO 32000-2 | §7 | |
| HTML 글꼴은 embedded/subset 글꼴 프로그램으로 기록됩니다. | ISO 32000-2 | §9 | |
| 공백 / 줄바꿈 처리는 엔진별로 다릅니다. | CSS Text 3 | §6.5 |
NextPDF는 ISO 32000-2 콘텐츠를 생성합니다. 마이그레이션된 Dompdf 문서가 시각적으로 동일하다고 주장하지 않습니다. 렌더러를 변경하면 항상 출력을 다시 검토해야 합니다.
상업적 맥락
섹션 제목: “상업적 맥락”해당 없음. 코어에는 여기서 설명한 HTML-to-PDF 마이그레이션 경로가 포함되어 있습니다.
함께 보기
섹션 제목: “함께 보기”마이그레이션 세부 사항(R6 필수 섹션)
섹션 제목: “마이그레이션 세부 사항(R6 필수 섹션)”대상 독자
섹션 제목: “대상 독자”서버 측 HTML-to-PDF에 dompdf/dompdf를 사용하면서 NextPDF 엔진을 원하는 팀입니다. loadHtml / setPaper / render / output만 호출한다면, 동사 매핑이 전체 호출 표면을 포괄합니다.
포함 범위: Dompdf 파사드 동사, Options 키, CSS 기능 동등성 기대치, 리소스 해석, 메타데이터. 제외 범위: Dompdf의 내부 FrameTree/Canvas/Stylesheet 객체(NextPDF에는 공개 대응물이 없으므로 — 이들에 접근하는 코드는 그대로 마이그레이션하지 말고 공개 API로 대체하세요).
호환성 맵
섹션 제목: “호환성 맵”제공 범위는 드롭인 심(shim)이 아니라 동작 호환성입니다. NextPDF에는 Dompdf 클래스 심이 없습니다(TCPDF 경로와 달리 — /migration/tcpdf-compat/ 호환 가이드 참조). 동사 매핑을 사용하여 모든 호출 지점을 다시 작성하세요. CSS 지원 매트릭스의 검증(Verified) 행이 CSS 기능 기대치를 전적으로 결정합니다. 이 가이드는 속성별 상태를 다시 기술하지 않습니다.
옵션 및 구성 맵
섹션 제목: “옵션 및 구성 맵”| Dompdf 옵션(키 / 세터) | NextPDF | 참고 |
|---|---|---|
default_paper_size / setDefaultPaperSize() ; setPaper($size,...) | Config->pageSize(PageSize VO) | 명명된 크기는 명시적 포인트 치수가 됩니다. new PageSize(595.276, 841.890, 'A4')가 createStandalone() 기본값입니다. |
default_paper_orientation / setDefaultPaperOrientation() | 교체할 PageSize width/height | NextPDF에는 방향 플래그가 없습니다. 가로 페이지는 너비 > 높이인 PageSize입니다. |
dpi / setDpi() | (전역 설정 항목이 아님) | NextPDF는 PDF 포인트(1/72 인치)로 동작합니다. 이미지 크기 지정은 문서 DPI 배율이 아니라 이미지별로 이루어집니다. 고정 픽셀 크기는 포인트로 다시 계산하세요. |
enable_remote / setIsRemoteEnabled() | (대응물 없음 — 설계상) | 원격 자산은 코드에서 해석하세요. 보안 참고 사항을 참조하세요. |
enable_html5_parser / setIsHtml5ParserEnabled() | (항상 HTML을 파싱함) | 토글 없음. 파서가 곧 파이프라인입니다. |
enable_php / setIsPhpEnabled() | (대응물 없음 — 설계상) | 문서 내 PHP는 지원되지 않습니다. 로직을 템플릿 밖으로 옮기세요. |
font_dir / setFontDir() | Config->fontsDirectory | 단일 글꼴 디렉터리 문자열입니다. |
chroot | (앱에서 해석) | NextPDF는 파일시스템 격리(jail) 옵션을 받지 않습니다. 바이트를 전달하기 전에 경로 검증을 수행하세요. |
default_font / setDefaultFont() | CSS font-family / 등록된 글꼴 | 전역 옵션이 아니라 기본 스타일시트나 글꼴 등록을 통해 기본값을 설정하세요. |
enable_font_subsetting / setIsFontSubsettingEnabled() | (항상 서브셋함) | NextPDF는 임베드된 글꼴을 항상 서브셋합니다(ISO 32000-2 §9, iso32000_2_sec9#x1.x45.p7). “끄기”는 없습니다 — 플래그를 끈 Dompdf 경로는 대응물이 없으며 필요하지도 않습니다. |
동작상의 차이
섹션 제목: “동작상의 차이”- 레이아웃 엔진. Dompdf와 NextPDF는 독립적인 CSS 레이아웃 구현입니다. 공백 축약과 줄바꿈은 사양에 정의되어 있지만 엔진의 영향을 받습니다(CSS Text 3 §6.5,
css_text_3#x1.x6.x5.p20). 밀집된 텍스트에서는 줄바꿈과 페이지 나눔 차이를 예상하세요. 마이그레이션 후 시각적 차이에 대한 기준선을 다시 설정하세요. - 렌더링 경계.
render()/output()2 단계 경계가 없습니다(엣지 케이스 참조). - 리소스 해석. 기본 경로/프로토콜/호스트와 문서 작업 집합의 차이입니다.
- DPI 모델. 포인트와 Dompdf의 DPI 배율이 대비됩니다.
- 메타데이터. 자유 형식
addInfo()쌍과 타입이 지정된 세터가 대비됩니다(ISO 32000-2 §14,iso32000_2_sec14#x1.x5.p5).
이는 문서화된 동작상의 차이이지 어느 엔진의 결함도 아닙니다.
지원되지 않음 / 직접적인 대응 없음
섹션 제목: “지원되지 않음 / 직접적인 대응 없음”enable_php(문서 내 PHP) — 의도적으로 없습니다.setHttpContext()/enable_remote원격 가져오기 — 의도적으로 없습니다.- 공개 접근:
FrameTree/Canvas/Stylesheet— 공개 대응물 없음. dpi— 문서 전역 배율로서 모델링되지 않음.
이들에 의존하는 코드는 그대로 “마이그레이션”할 수 없습니다. 위 행에 따라 제거하거나 애플리케이션 코드로 다시 표현해야 합니다.
안전한 마이그레이션 순서
섹션 제목: “안전한 마이그레이션 순서”- 새로
nextpdf/core를dompdf/dompdf와 함께 추가합니다(아직 Dompdf를 제거하지 마세요). - 위험이 낮은 문서 하나를 고릅니다. 동사 매핑으로 그 호출 지점을 다시 작성하고,
render()호출을 삭제합니다. - 동일한 입력으로 두 PDF를 생성하여 시각적으로 비교합니다. 차이는 독립적인 엔진에서 예상되는 결과로 취급하고 문서별로 수용 여부를 결정합니다.
- 옵션 사용은 옵션 맵에 따라 변환하고, DPI 기반 크기를 포인트로 다시 계산합니다.
- 해석 변수를 제거하기 위해 remote/relative 자산을 절대 경로나 데이터 URI로 미리 해석합니다.
- 위험이 가장 낮은 것부터 가장 높은 것 순으로 문서별로 반복합니다. 마지막 호출 지점이 전환될 때까지 두 엔진을 모두 설치된 상태로 유지합니다.
- 패키지
dompdf/dompdf를composer.json에서 제거하는 것은 마지막 전환이 끝난 후에만 합니다.
마이그레이션 테스트
섹션 제목: “마이그레이션 테스트”- 코드를 변경하기 전에 대표 문서들의 Dompdf 출력을 스냅샷합니다(골든 바이트가 아니라 골든 입력 — 바이트는 달라집니다).
- 마이그레이션된 각 문서에 대해 NextPDF 출력을 자체 수용 검사(시각적 비교, 텍스트 추출 단언)를 통해 실행하세요. NextPDF 자체의 HTML 파이프라인 동작은
examples/08-html-basic.php와 코어tests/Html 스위트가 다룹니다. 마이그레이션 수용 검사는 문서별로 다르며 직접 단언해야 합니다. - 향후 엔진 업데이트로 인한 변화가 포착되도록 마이그레이션된 문서마다 회귀 테스트를 추가하세요.
근거 / 추적성
섹션 제목: “근거 / 추적성”이 페이지의 모든 NextPDF 동작 진술은 저장소 내 테스트, 예제, 소스 시그니처 또는 ADR로 뒷받침됩니다 — PDF 형식 속성의 경우 RAG로 고정된 ISO 32000-2 / CSS 조항으로 뒷받침되며, 해당 근거는 프런트매터 citations:와 적합성 표에 있습니다. dompdf 동작은 “독립적인 엔진 — 문서화된 차이를 예상하라”로만 단언됩니다. 저장소 내 산출물이 증명하지 않는 동등성은 주장되지 않습니다.
| NextPDF 동작 주장 | 저장소 내 근거(경로) |
|---|---|
createStandalone() 기본 페이지는 A4 세로입니다(595.276 × 841.890 pt). | src/Core/Config.php (default PageSize(595.276, 841.890, 'A4')); tests/Unit/Core/DocumentCreateStandaloneAndConfigWithersEdgeCaseTest.php (createStandaloneWithNullConfigBuildsDocumentWithA4Defaults). |
writeHtml()는 단일 스트리밍 패스로 레이아웃을 배치하며, 레이아웃 이후 DOM을 유지하지 않습니다. | docs/architecture/adr/ADR-001-stream-based-rendering-pipeline.md; src/Core/Concerns/HasTextOutput.php (writeHtml()). |
writeHtml()는 페이지가 없을 때 첫 페이지를 자동으로 생성합니다. | tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php (writeHtmlAutoCreatesFirstPageWhenNoPagesExist). |
output() / save() / getPdfData()가 출력 동사입니다(render/output 2 단계 없음). | src/Core/Concerns/HasOutput.php (output(), save(), getPdfData()); tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php. |
출력 대상은 NextPDF\Contracts\OutputDestination 열거형입니다(Inline/Download/File/String). | src/Contracts/OutputDestination.php; tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php. |
| HTML 글꼴은 항상 embedded/subset 프로그램으로 기록됩니다. | tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php(recordUsedCharactersAffectsFontSubsetting); ISO 32000-2 §9 (프런트매터 citations:). |
타입이 지정된 메타데이터 세터(setTitle/setAuthor)가 자유 형식 addInfo()를 대체합니다. | src/Core/Concerns/HasMetadata.php (setTitle(), setAuthor()); tests/Unit/Core/Concerns/DocumentInfoMetadataSetterBaselineTest.php. |
| 엔드투엔드 HTML 파이프라인(이 가이드의 실행 가능한 기반). | examples/08-html-basic.php; 코어 tests/Unit/Html/ 스위트. |
| 공백 / 줄바꿈은 엔진별로 다릅니다(레이아웃 차이). | CSS Text 3 §6.5 (프런트매터 citations: + 적합성). |
최종 전환 전까지 두 패키지가 모두 설치된 상태로 유지되므로, 아직 변환되지 않은 호출 지점의 롤백은 그 호출 지점 하나를 Dompdf 경로로 되돌리는 것을 의미합니다. 최종 전환 후의 롤백은 dompdf/dompdf와 이전 호출 지점을 버전 관리에서 복원하는 것을 의미합니다. 데이터 마이그레이션은 관여하지 않습니다 — 코드뿐입니다.
성능 고려 사항
섹션 제목: “성능 고려 사항”자세한 내용은 성능을 참조하세요. 단일 패스 모델은 마이그레이션으로 프레임 트리 유지 비용이 새로 생기지 않음을 의미합니다. 문서당 주요 비용 변화는 자산을 사전에 다시 해석하는 작업(5 단계)이며, 이는 캐시할 수 있습니다.
흔한 함정
섹션 제목: “흔한 함정”render()호출을 그대로 남겨두기(치명적인 undefined method).- 매개변수
$encoding을 제거한 후 UTF-8이 아닌 바이트 전달하기(오류 없이 깨진 문자). - 바이트 단위 또는 픽셀 단위로 동일한 출력 기대하기(독립적인 엔진 — 이 가이드는 드롭인이나 100% 호환성을 결코 주장하지 않습니다).
enable_php옵션 템플릿에 의존하기(반드시 리팩터링하여 제거해야 함).- CSS 지원 매트릭스를 권고 사항으로 취급하기 — 이는 기대치를 정하는 검증된 기능의 권위 있는 기준입니다.