NextPDF Cloudflare 브리지 구성
한눈에 보기
섹션 제목: “한눈에 보기”세 개의 불변 구성 객체가 패키지 동작을 제어합니다. 이 페이지의 모든 기본값은 src/Cloudflare/의 해당 생성자 시그니처에서 가져온 것이며, 명세나 추정값을 기준으로 하지 않습니다. 이 페이지에서 최댓값을 명시하는 경우, 그 최댓값은 이 패키지가 적용하는 제한입니다. Cloudflare 플랫폼 용량에 대한 진술이 아닙니다.
CloudflareRendererConfig
섹션 제목: “CloudflareRendererConfig”렌더러 구성입니다. final readonly이며, 직접 생성하거나 CloudflareRendererConfig::fromArray()로 생성합니다.
| 필드 | 타입 | 기본값 | 의미 |
|---|---|---|---|
workerUrl | string | — (필수) | Worker 엔드포인트 URL입니다. HTTPS여야 합니다. |
apiToken | string | — (필수) | Bearer 토큰입니다. #[SensitiveParameter]로 표시됩니다. |
renderTimeout | int | 30 | 고정된 cURL 전송에서 적용하는 전송 타임아웃(초)입니다. |
defaultCss | string | '' | 페이로드에서 HTML 앞에 주입되는 CSS입니다. |
maxHtmlSize | int | 5000000 | 요청 전송 전에 적용되는 최대 HTML 입력 크기(바이트)입니다. |
r2FontBucket | ?string | null | 사용자 정의 폰트 패키지용 R2 버킷 이름입니다. |
fallbackToLocal | bool | true | 연결할 수 없는 Worker가 로컬 렌더러로 폴백할지 여부입니다. |
pinnedPublicKeys | list<string> | [] | SHA-256 SPKI 지문이며, 형식은 sha256/<base64>입니다. |
backupPublicKeys | list<string> | [] | 백업 SPKI 핀이며, 회전이 독립적으로 검증되도록 별도로 유지됩니다. |
isValid()은 workerUrl !== ''이고 apiToken !== ''일 때만 true를 반환합니다. allPublicKeyPins()은 pinnedPublicKeys와 backupPublicKeys의 중복 제거된 합집합을 반환합니다. TLS 계층은 인증서의 SPKI 해시가 그 합집합의 구성원 중 하나와 일치할 때 인증서를 수락합니다. 이는 제시된 SPKI 지문 집합이 고정된 집합과 교차할 때 고정된 연결을 검증하는 RFC 7469 §2.6과 일치합니다. RFC 7469 §2.5는 의도하지 않은 핀 검증 실패에 대비한 주요 복구 메커니즘으로 백업 핀을 설명합니다. 인증서 회전으로 엔드포인트가 중단되지 않도록 백업 핀을 하나 이상 유지하십시오. 자세한 내용은 /integrations/cloudflare/security-and-operations/을 참조하십시오.
fromArray() 키 맵
섹션 제목: “fromArray() 키 맵”CloudflareRendererConfig::fromArray()은 snake_case 키를 읽으며, 키가 없거나 타입이 맞지 않으면 동일한 기본값을 적용합니다:
| 배열 키 | 매핑 대상 |
|---|---|
worker_url | workerUrl |
api_token | apiToken |
render_timeout | renderTimeout (기본값 30) |
default_css | defaultCss |
max_html_size | maxHtmlSize (기본값 5000000) |
r2_font_bucket | r2FontBucket |
fallback_to_local | fallbackToLocal (기본값 true) |
pinned_public_keys | pinnedPublicKeys (문자열이 아닌 구성원은 제거됨) |
backup_public_keys | backupPublicKeys (문자열이 아닌 구성원은 제거됨) |
<?php
declare(strict_types=1);
use NextPDF\Cloudflare\CloudflareRendererConfig;
$config = CloudflareRendererConfig::fromArray([ 'worker_url' => 'https://pdf-renderer.example.workers.dev/render', 'api_token' => getenv('CF_PDF_TOKEN') ?: '', 'render_timeout' => 60, 'r2_font_bucket' => 'pdf-fonts', 'pinned_public_keys' => ['sha256/YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg='], 'backup_public_keys' => ['sha256/Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys='],]);패키지가 적용하는 입력 크기 제한
섹션 제목: “패키지가 적용하는 입력 크기 제한”다음 제한은 요청이 프로세스 밖으로 나가기 전에 CloudflareSecurityPolicy::validate()에 의해 적용됩니다. 이 수치는 소스에서 가져왔습니다:
| 제한 | 값 | 위치 |
|---|---|---|
| 최대 HTML 입력 | maxHtmlSize (기본값 5000000 바이트) | CloudflareSecurityPolicy::validate() |
| 최대 디코딩된 base64 데이터 URI 크기 | 13631488 바이트 (≈13 MB) | CloudflareSecurityPolicy::MAX_DATA_URI_BYTES |
둘 중 하나라도 초과하면 위반한 크기와 제한을 명시하는 메시지와 함께 RuntimeException이 발생합니다. base64 상한은 압축 폭탄 방어 장치입니다. 정책은 base64 길이로부터 디코딩된 크기를 추정하여 상한 이상이면 거부합니다. <meta http-equiv="refresh"> 태그도 대소문자를 구분하지 않고 거부되는데, 렌더링된 페이지 안에서 리디렉션을 유발할 수 있기 때문입니다.
패키지는 자신이 직접 적용하는 제한만 명시합니다. Worker 자체의 요청, CPU, 메모리 상한에 대해서는 어떤 주장도 하지 않습니다. 해당 내용은 Cloudflare 공식 문서와 사용자의 Worker 구현을 참조하십시오.
ApiProtectionConfig
섹션 제목: “ApiProtectionConfig”Worker 또는 그 앞단의 PHP 게이트웨이가 인바운드 렌더 요청에 적용하는 선택적 요청 보호 계층 구성입니다. final readonly.
| 필드 | 타입 | 기본값 | 의미 |
|---|---|---|---|
maxRequestsPerMinute | int | 60 | 클라이언트별 분당 요청 상한입니다. |
maxRequestsPerHour | int | 1000 | 클라이언트별 시간당 요청 상한입니다. |
maxPayloadSizeBytes | int | 10485760 | 최대 인바운드 페이로드(≈10 MB)입니다. |
allowedOrigins | list<string> | [] | CORS 허용 목록입니다. 비어 있으면 여기서는 출처 제한을 표현하지 않습니다. |
requireApiKey | bool | true | API 키가 필요한지 여부입니다. |
apiKeyHeader | string | 'X-Api-Key' | API 키를 전달하는 헤더입니다. |
rateLimitWindowSeconds | int | 60 | 분 단위 윈도우 길이(초)입니다. |
fromArray()은 max_requests_per_minute, max_requests_per_hour, max_payload_size_bytes, allowed_origins, require_api_key, api_key_header, rate_limit_window_seconds를 읽습니다. isValid()은 모든 숫자 필드가 양수이고 apiKeyHeader가 비어 있지 않아야 합니다.
R2ArchiveConfig
섹션 제목: “R2ArchiveConfig”S3 호환 API를 통해 렌더링된 PDF를 Cloudflare R2에 아카이브하기 위한 구성입니다. final readonly.
| 필드 | 타입 | 기본값 | 의미 |
|---|---|---|---|
bucketName | string | — (필수) | R2 버킷입니다. S3 명명 규칙에 대해 검증됩니다. |
accountId | string | — (필수) | 기본 엔드포인트를 구성하는 데 사용되는 Cloudflare 계정 ID입니다. |
accessKeyId | string | — (필수) | R2 액세스 키 ID입니다. #[SensitiveParameter]. |
secretAccessKey | string | — (필수) | R2 비밀 액세스 키입니다. #[SensitiveParameter]. |
endpoint | string | '' | 사용자 정의 S3 엔드포인트입니다. 비어 있으면 accountId로부터 기본값을 구성합니다. |
pathPrefix | string | 'pdfs/' | 업로드된 객체의 키 접두사입니다. |
maxFileSizeBytes | int | 104857600 | 업로드 전에 적용되는 최대 업로드 크기(≈100 MB)입니다. |
생성자는 비어 있지 않지만 S3 호환 규칙에 맞지 않는 bucketName을 거부합니다. 그 규칙은 다음과 같습니다: 3–63 자, 소문자 영숫자와 하이픈만 사용할 수 있으며, 영숫자로 시작하고 끝나야 합니다. 위반 시 InvalidArgumentException이 발생합니다. isValid()은 bucketName, accountId, accessKeyId, secretAccessKey가 비어 있지 않아야 합니다. endpoint가 비어 있으면 getEndpoint()은 https://<accountId>.r2.cloudflarestorage.com을 반환합니다.
비밀 정보 처리
섹션 제목: “비밀 정보 처리”apiToken, accessKeyId, secretAccessKey에는 #[SensitiveParameter] 어트리뷰트가 지정되어 있어 PHP가 스택 트레이스에서 이를 가립니다. 환경 변수나 비밀 관리자에서 값을 공급하십시오. 절대 커밋하지 마십시오. 구성 객체는 불변이므로 생성 후에는 한 번 설정된 값을 변경할 수 없습니다.
함께 보기
섹션 제목: “함께 보기”- /integrations/cloudflare/quickstart/ — 첫 번째 렌더에서 이 구성을 적용합니다.
- /integrations/cloudflare/production-usage/ — 폴백, R2 아카이브, API 보호를 함께 구성합니다.
- /integrations/cloudflare/security-and-operations/ — 핀 고정, SSRF 방어, 비밀 정보 회전.