프로덕션에서 compat-legacy 실행하기
한눈에 보기
섹션 제목: “한눈에 보기”이 어댑터는 HTTP 핸들러, 큐 워커, 장기 실행 프로세스에서 안전하게 실행할 수 있습니다. 레거시 TCPDF 6.2.13보다 더 안전한 이유는 프로덕션에서 흔히 문제가 되는 두 가지 위험 요소, 즉 버퍼로 직접 출력하는 동작과 오류 시 die()를 호출하는 동작을 제거했기 때문입니다. 이 페이지에서는 어댑터를 올바르게 운영하는 방법을 설명합니다.
전제 조건: /integrations/tcpdf-compat/migration/에서 엄격 모드 감사를 완료하고, 프로덕션에는 엄격 모드를 끈 상태로 배포합니다.
워커와 핸들러의 출력 처리
섹션 제목: “워커와 핸들러의 출력 처리”레거시 TCPDF의 Output()은 활성 출력 버퍼로 직접 출력합니다. 이 동작은 HTTP 프레임워크의 응답을 손상시키고 큐 워커의 동작을 망가뜨릴 수 있습니다. 대신 이 어댑터는 안전한 대상 브리지를 통해 출력을 라우팅합니다.
호출자에 맞는 출력 대상을 사용합니다:
| 상황 | 대상 | 이유 |
|---|---|---|
| 스토리지에 기록하는 큐 워커 | Output($path, 'F') | 파일에 쓰고 빈 문자열을 반환합니다. 버퍼와 상호작용하지 않습니다. |
| 생성 후 attach/upload | Output($name, 'S') | PDF 바이트를 반환하며, 보낼 위치는 사용자가 제어합니다. |
| 이메일 첨부 파일 | Output($name, 'E') | Content-Type: application/pdf를 포함한 base64 MIME 본문을 반환합니다. |
| 직접 제어하는 HTTP 응답 | Output($name, 'S') | 바이트를 받은 다음 헤더와 본문을 직접 설정합니다. |
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;use NextPDF\Compat\Tcpdf\TCPDF;
/** * Render an invoice in a queue worker. Returns the storage path. * * @throws \RuntimeException on a render failure (Error() throws, not die()). */function renderInvoiceJob(array $invoice, string $storageDir): string{ $pdf = new TCPDF('P', 'mm', 'A4'); $pdf->SetFont('helvetica', '', 12); $pdf->AddPage(); $pdf->Cell(0, 10, 'Invoice ' . $invoice['number'], 0, 1);
$path = $storageDir . '/invoice-' . $invoice['number'] . '.pdf';
try { $pdf->Output($path, 'F'); // writes file, no buffer pollution } catch (TcpdfNotImplementedException $e) { // Only reachable if strict mode is on — it must NOT be in production. throw new \RuntimeException('Adapter strict-mode gap in production: ' . $e->getMessage(), 0, $e); } catch (\RuntimeException $e) { // Error() throws RuntimeException instead of die(). throw new \RuntimeException('PDF render failed: ' . $e->getMessage(), 0, $e); }
return $path;}HTTP 핸들러에서는 'S'를 우선 사용하고 헤더를 직접 설정합니다:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();$pdf->AddPage();$pdf->SetFont('helvetica', '', 12);$pdf->Cell(0, 10, 'Report');
$bytes = $pdf->Output('report.pdf', 'S');
header('Content-Type: application/pdf');header('Content-Length: ' . strlen($bytes));header('Content-Disposition: inline; filename="report.pdf"');echo $bytes;실패 처리
섹션 제목: “실패 처리”Error()는 RuntimeException을 던지며, die()를 절대 호출하지 않습니다. 이는 레거시 TCPDF에서 운영상 가장 큰 단일 변경 사항입니다.
- 모든 렌더링 진입점을
try/catch로 감쌉니다. - 예외를 애플리케이션의 오류 계약(HTTP 5xx, 작업 실패, 재시도, 데드 레터)에 매핑합니다.
- 렌더링 실패 시 프로세스가 종료된다고 가정하지 마십시오 — 종료되지 않습니다.
주기적인 엄격 모드 CI 작업(권장)을 실행한다면, 그 과정에서 발생하는 TcpdfNotImplementedException은 실제 발견 사항입니다: 코드 경로가 지원되지 않는 TCPDF 매개변수에 의존하고 있다는 뜻입니다. 이를 불안정한 테스트가 아니라 마이그레이션 작업 항목으로 다루십시오.
수명 주기와 리소스 처리
섹션 제목: “수명 주기와 리소스 처리”- 문서는 첫 번째 출력 호출 시 PDF 바이트를 지연 생성합니다.
Close()는 선택 사항이며, 호출하면 바이트를 캐시합니다.Open()은 안전한 무동작(no-op)으로 처리됩니다. endPage()는 아무 동작도 하지 않습니다 — NextPDF가 페이지 수명 주기를 관리합니다. 핫 루프에서 제거하십시오. 별도의 가치를 더하지 않습니다.- 작업 사이에는 PHP가 어댑터를 가비지 컬렉션하도록 두십시오.
_destroy()는 어댑터의 캐시된 데이터를 재설정하지만, 일반적인 워커 루프에서는 명시적으로 호출할 필요가 없습니다. - 문서마다 새 어댑터를 생성하십시오. 장기 실행 워커에서 서로 관련 없는 문서에 동일한 어댑터 인스턴스를 재사용하지 마십시오. 문서 상태는 인스턴스별로 관리됩니다.
성능 지침
섹션 제목: “성능 지침”- 이 어댑터는 얇은 위임 계층입니다. 비용을 좌우하는 것은 어댑터가 아니라 엔진입니다.
- 레거시 상수는 부팅 시 한 번 정의하십시오.
LegacyDefaults::register()와LegacyBootstrap::enableAliases()는 모두 멱등하고 가드가 적용되어 있으므로 반복 호출 비용이 낮습니다. 요청마다 상수를 정의하는 것은 낭비입니다. - 브라우저가 아닌 환경에서는
'I'/'D'보다Output(..., 'S')또는'F'를 선호하십시오. inline/download 경로는 프레임워크와 무관한 출력을 생성하므로, 워커에서는 보통 원하지 않는 결과입니다. - 대량 생성 시에는 어댑터가 아니라 엔진을 프로파일링하십시오. 렌더링에 비하면 어댑터 자체 오버헤드의 페이지당 예산은 작습니다.
동시성
섹션 제목: “동시성”- 각 어댑터 인스턴스는 독립적이며 자체 문서 상태를 보유합니다. 각 작업 단위가 자체 어댑터 인스턴스를 사용한다면, 프로세스 또는 워커 수준의 동시성은 안전합니다.
LegacyBootstrap과LegacyDefaults의 멱등성 가드는 프로세스 로컬 정적 상태를 사용하며, 일반적인 PHP per-request/per-worker 모델에서는 안전합니다. 이들은 스레드 간에 변경 가능한 상태를 공유하도록 설계되지 않았습니다.
프로덕션 전 체크리스트
섹션 제목: “프로덕션 전 체크리스트”- 엄격 모드 감사 완료. 프로덕션은 엄격 모드를 끈 상태로 실행됩니다.
- 모든 렌더링 진입점이
RuntimeException에 대해try/catch로 감싸져 있음(die()에 의존하지 않음). - 워커는 인라인 경로가 아닌
Output(..., 'F')또는'S'를 사용함. - 레거시 상수가 첫 번째 생성 전에, 부팅 시 한 번 정의됨.
- 회귀를 잡기 위한 주기적인 엄격 모드 CI 작업이 마련되어 있음.
- 바이트 수준 테스트 어서션이 다시 기준선에 맞춰짐(/integrations/tcpdf-compat/migration/ 참고).
관련 문서
섹션 제목: “관련 문서”- /integrations/tcpdf-compat/security-and-operations/ — 암호화, 서명 태세, 강화
- /integrations/tcpdf-compat/troubleshooting/ — 프로덕션 실패 패턴과 해결 방법
- /integrations/tcpdf-compat/configuration/ — 엄격 모드와 상수 위생
- /integrations/tcpdf-compat/migration/ — 프로덕션에 앞서 반드시 수행해야 하는 감사