Salta ai contenuti

Riferimento alle API Cloudflare

Il package NextPDF\Cloudflare è un ponte per il rendering edge: il processo PHP gestisce l’HTML, mentre un Cloudflare Worker gestisce il browser headless. Il package espone un renderer HTML basato su Worker (CloudflareHtmlRenderer) e i value object che restituisce, uno strato di protezione delle richieste per mettere in sicurezza gli endpoint di rendering (ApiProtection), un servizio di archiviazione R2 per memorizzare i PDF generati (R2ArchiveManager) e helper di trasporto con pinning per l’hardening di TLS/DNS. La configurazione risiede in tre oggetti immutabili (CloudflareRendererConfig, ApiProtectionConfig, R2ArchiveConfig).

Da dove iniziare: se si usa il package per la prima volta, creare un CloudflareRendererConfig, collegarlo a CloudflareHtmlRenderer e chiamare render(). Questa singola chiamata invia l’HTML al Worker e restituisce un CloudflareRenderResult con i byte del PDF. Tutto il resto (protezione, archiviazione, pinning) ruota attorno a quella chiamata.

Gli snippet seguenti rappresentano i flussi di lavoro reali più frequenti per questo package. Ciascuno è autonomo, verificato rispetto al codice sorgente in src/Cloudflare/ e legge i segreti dall’ambiente.

Eseguire il rendering di una stringa HTML in un PDF all’edge: la sola chiamata di rendering canonica:

<?php
declare(strict_types=1);
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use NextPDF\Cloudflare\CloudflareHtmlRenderer;
use NextPDF\Cloudflare\CloudflareRendererConfig;
$httpFactory = new HttpFactory();
$renderer = new CloudflareHtmlRenderer(
config: new CloudflareRendererConfig(
workerUrl: 'https://pdf-renderer.example.workers.dev/render',
apiToken: getenv('CF_PDF_TOKEN') ?: throw new RuntimeException('CF_PDF_TOKEN not set'),
),
httpClient: new Client(),
requestFactory: $httpFactory,
streamFactory: $httpFactory,
responseFactory: $httpFactory,
);
$result = $renderer->render('<h1>Hello from the edge</h1>', widthPt: 595.28);
if ($result->isValid()) {
file_put_contents('output.pdf', $result->pdfData);
}

Cosa fa: invia l’HTML al Worker tramite HTTPS e scrive su disco i byte del PDF A4 restituito, dopo che isValid() ha confermato che si tratta di un PDF reale.

Archiviare un PDF generato in R2 e restituire un link a breve durata:

<?php
declare(strict_types=1);
use NextPDF\Cloudflare\R2ArchiveConfig;
use NextPDF\Cloudflare\R2ArchiveManager;
$archive = new R2ArchiveManager(
config: R2ArchiveConfig::fromArray([
'bucket_name' => 'pdf-archive',
'account_id' => getenv('CF_ACCOUNT_ID') ?: '',
'access_key_id' => getenv('R2_ACCESS_KEY_ID') ?: '',
'secret_access_key' => getenv('R2_SECRET_ACCESS_KEY') ?: '',
]),
httpClient: $httpClient, // PSR-18 ClientInterface
requestFactory: $requestFactory, // PSR-17 RequestFactoryInterface
streamFactory: $streamFactory, // PSR-17 StreamFactoryInterface
);
$upload = $archive->upload($result->pdfData, 'invoice-1234.pdf');
$signedUrl = $upload->isValid()
? $archive->generateSignedUrl($upload->key, expiresInSeconds: 600)
: null;

Cosa fa: carica i byte del PDF in una chiave R2 partizionata per data e, in caso di esito positivo, genera un URL prefirmato valido 10 minuti per il download temporaneo.

Proteggere un endpoint di rendering prima di eseguire operazioni Worker onerose:

<?php
declare(strict_types=1);
use NextPDF\Cloudflare\ApiKeyValidator;
use NextPDF\Cloudflare\ApiProtection;
use NextPDF\Cloudflare\ApiProtectionConfig;
$protection = new ApiProtection(
config: new ApiProtectionConfig(maxRequestsPerMinute: 30),
keyValidator: new ApiKeyValidator([getenv('RENDER_API_KEY') ?: '']),
);
$decision = $protection->checkRequest(
clientId: $clientIp,
payloadSize: strlen($html),
apiKey: $presentedApiKey,
);
if (!$decision->allowed) {
// Reject with 429 and rate-limit headers before any render call.
return [429, $decision->toHeaders(), $decision->denialReason];
}

Cosa fa: convalida la chiave API, la dimensione del payload e poi il limite di frequenza per client, restituendo una singola decisione insieme alle intestazioni di risposta da allegare quando la richiesta viene rifiutata.

La tabella Renderer descrive la superficie principale. Usarla quando si costruisce la configurazione, si crea il renderer o si eseguono chiamate di rendering e di raggiungibilità.

SimboloParametriComportamento predefinitoValore restituitoEccezioni o erroriNote
new CloudflareRendererConfig(string $workerUrl, string $apiToken, int $renderTimeout = 30, string $defaultCss = '', int $maxHtmlSize = 5000000, ?string $r2FontBucket = null, bool $fallbackToLocal = true, array $pinnedPublicKeys = [], array $backupPublicKeys = [])URL del Worker, bearer token, timeout, CSS, limite di dimensione, bucket di font R2 facoltativo, flag di fallback, set di pin.Il fallback locale è abilitato; il pinning è disabilitato quando gli array di pin sono vuoti.CloudflareRendererConfignessuna prevista.Mantenere segreto il token API; preferire URL HTTPS del Worker.
CloudflareRendererConfig::fromArray(array $config)worker_url, api_token, render_timeout, default_css, max_html_size, r2_font_bucket, fallback_to_local, array di pin.Le chiavi facoltative mancanti usano i valori predefiniti del costruttore.CloudflareRendererConfignessuna prevista.Corrisponde agli array di configurazione in stile framework.
CloudflareRendererConfig::isValid()nessuna.Richiede un URL del Worker e un token API non vuoti.boolnessuna prevista.Una configurazione non valida attiva il fallback o un errore nel renderer.
CloudflareRendererConfig::allPublicKeyPins()nessuna.Combina i pin della chiave pubblica primaria e di backup.list<string>nessuna prevista.Un elenco vuoto disabilita il pinning.
new CloudflareHtmlRenderer(CloudflareRendererConfig $config, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory, ?LoggerInterface $logger = null, ?LocalRendererFactoryInterface $localRendererFactory = null, ?HtmlSecurityPolicyInterface $htmlSecurityPolicy = null, ?ResponseFactoryInterface $responseFactory = null)Configurazione, dipendenze HTTP PSR, logger facoltativo, factory di fallback locale facoltativa, policy HTML facoltativa, factory di risposta facoltativa.Usa DefaultHtmlSecurityPolicy quando non viene fornita alcuna policy HTML.CloudflareHtmlRendererErrori di wiring del container.La factory di risposta abilita il trasporto cURL con pinning quando richiesto.
CloudflareHtmlRenderer::render(string $html, float $widthPt = 595.28, float $heightPt = 0, array $fontFiles = [])HTML, larghezza pagina, altezza pagina, file di font in R2.Larghezza A4; altezza automatica; nessun file di font.CloudflareRenderResultCloudflareNotAvailableException, CloudflareRenderException, validation failures.Convalida la dimensione dell’HTML e l’URL del Worker prima dell’I/O di rete.
CloudflareHtmlRenderer::getHtmlSecurityPolicy()nessuna.Restituisce la policy configurata a livello di parsing.HtmlSecurityPolicyInterfacenessuna prevista.Usare insieme alla protezione degli endpoint e alla convalida dell’URL del Worker.
CloudflareHtmlRenderer::isAvailable()nessuna.Richiesta HEAD al Worker quando la configurazione è valida.boolRestituisce false in caso di errori.Usare per i controlli di prontezza, non come unica protezione a runtime.

Usare questa tabella quando servono i value object request/result (CloudflareRenderResult, CloudflareRenderPayload) o i controlli statici a livello di trasporto che convalidano l’HTML, l’URL del Worker e i pin DNS prima di qualsiasi I/O di rete.

SimboloParametriComportamento predefinitoValore restituitoEccezioni o erroriNote
new CloudflareRenderResult(string $pdfData, float $widthPt, float $heightPt, float $contentHeightPx = 0.0, string $renderLocation = '', float $renderTimeMs = 0.0)Byte del PDF, larghezza, altezza, altezza del contenuto misurata, posizione edge, tempo di rendering.Metadati vuoti quando il Worker non li riporta.CloudflareRenderResultnessuna prevista.Solitamente restituito da CloudflareResponseParser::parse().
CloudflareRenderResult::isValid()nessuna.Verifica la presenza di byte PDF non vuoti che iniziano con un’intestazione PDF.boolnessuna prevista.Usare prima di archiviare o passare i byte a un altro livello.
CloudflareRenderResult::size()nessuna.Conta i byte del PDF generato.intnessuna prevista.Inserire questo valore nella logica di quota e audit.
new CloudflareRenderPayload(string $html, float $widthPt, float $heightPt = 0, string $defaultCss = '', ?string $r2FontBucket = null, array $fontFiles = [])HTML, dimensione, CSS, bucket di font R2 facoltativo, elenco di file di font.Altezza automatica, nessun CSS predefinito, nessun bucket di font R2, nessun file di font.CloudflareRenderPayloadnessuna prevista.Value object del payload di richiesta.
CloudflareRenderPayload::toJson()nessuna.Serializza HTML, dimensione, CSS e riferimenti ai font per il Worker.stringErrori di codifica JSON.API di basso livello per il payload di richiesta.
CloudflareResponseParser::parse(ResponseInterface $response, float $requestedWidthPt)Risposta del Worker e larghezza richiesta.Accetta risposte PDF binarie e risposte JSON strutturate.CloudflareRenderResultCloudflareRenderException per output del Worker non riuscito o non valido.Parser centrale utilizzato dal renderer.
CloudflareSecurityPolicy::validate(string $html, int $maxSize)Input HTML e limite di dimensione.Applica la policy di input HTML del package.voidEccezione di convalida.Mantenere i controlli sull’input non attendibile fuori dal confine del Worker.
CloudflareSecurityPolicy::validateWorkerUrl(string $url)URL del Worker.Analizza e convalida la destinazione.arrayEccezione di convalida.Blocca le forme di endpoint non sicure prima dell’I/O di rete.
CloudflareSecurityPolicy::assertPinsStillValid(string $host, array $pinnedIps)Host ed elenco di IP con pinning.Verifica le aspettative dei pin DNS.voidEccezione di convalida quando i pin sono obsoleti o non validi.Usare durante i controlli operativi per i deployment con pinning.

Usare questa tabella per proteggere un endpoint di rendering: convalida della chiave API, controlli sulla dimensione del payload e sul limite di frequenza, e gli oggetti result/header prodotti.

SimboloParametriComportamento predefinitoValore restituitoEccezioni o erroriNote
new ApiProtection(ApiProtectionConfig $config, ?ApiKeyValidator $keyValidator = null, ?Closure $clock = null)Configurazione di protezione, validatore di chiavi facoltativo, clock facoltativo.Utilizza l’ora di sistema quando non viene fornito alcun clock.ApiProtectionnessuna prevista.Iniettare un clock deterministico nei test.
ApiProtection::checkRequest(string $clientId, int $payloadSize, string $apiKey = '')Identificatore client, dimensione del payload, chiave API facoltativa.Una chiave API vuota è consentita solo quando la configurazione non richiede chiavi.ApiProtectionResultnessuna prevista.Controlla la chiave API, la dimensione e quindi i limiti di frequenza.
ApiProtection::getRateLimit(string $clientId)Identificatore client.Non registra una richiesta.RateLimitResultnessuna prevista.Usare per aggiungere le intestazioni del limite di frequenza.
new ApiKeyValidator(array $validKeys = [])Elenco di chiavi valide in testo non cifrato.Un elenco vuoto rifiuta tutte le chiavi.ApiKeyValidatornessuna prevista.Memorizzare i segreti al di fuori del codice e idratarli tramite la configurazione.
ApiKeyValidator::validate(string $key)Chiave non elaborata.Confronto timing-safe rispetto alle chiavi in testo non cifrato configurate.boolnessuna prevista.Parametro sensibile; non registrare chiavi non elaborate.
ApiKeyValidator::addKey(string $key)Chiave non elaborata.Aggiunge una chiave con hash a una nuova istanza del validatore.selfnessuna prevista.Considerare l’istanza restituita come il validatore aggiornato.
ApiKeyValidator::revokeKey(string $key)Chiave non elaborata.Rimuove l’hash corrispondente da una nuova istanza del validatore.selfnessuna prevista.Considerare l’istanza restituita come il validatore aggiornato.
ApiKeyValidator::hashKey(string $key)Chiave non elaborata.Produce la rappresentazione hash memorizzata.stringnessuna prevista.Non esporre gli hash nei log o nelle risposte al client.
ApiKeyValidator::validateHashed(string $key, array $hashedKeys)Chiave non elaborata e hash candidati.Confronto a tempo costante rispetto agli hash forniti.boolnessuna prevista.Helper di basso livello per archivi di chiavi personalizzati.
new ApiProtectionConfig(int $maxRequestsPerMinute = 60, int $maxRequestsPerHour = 1000, int $maxPayloadSizeBytes = 10485760, array $allowedOrigins = [], bool $requireApiKey = true, string $apiKeyHeader = 'X-Api-Key', int $rateLimitWindowSeconds = 60)Limiti di richieste, limite del payload, origini consentite, requisito della chiave API, nome dell’intestazione, lunghezza della finestra.60/minute, 1000/hour, payload da 10 MiB, chiave API richiesta.ApiProtectionConfignessuna prevista.Costruire direttamente nei test o idratare tramite fromArray().
ApiProtectionConfig::fromArray(array $data)max_requests_per_minute, max_requests_per_hour, max_payload_size_bytes, allowed_origins, require_api_key, api_key_header, rate_limit_window_seconds.Le chiavi mancanti usano i valori predefiniti del costruttore.ApiProtectionConfignessuna prevista.Usare per idratare la configurazione del framework.
ApiProtectionConfig::isValid()nessuna.Richiede limiti positivi e valori size/window coerenti.boolnessuna prevista.Convalidare prima di esporre un endpoint.
new ApiProtectionResult(bool $allowed, string $denialReason = '', ?RateLimitResult $rateLimit = null)Decisione, motivo del rifiuto, risultato del limite di frequenza facoltativo.Motivo del rifiuto vuoto e nessun risultato del limite di frequenza.ApiProtectionResultnessuna prevista.Restituito da ApiProtection::checkRequest().
ApiProtectionResult::toHeaders()nessuna.Emette le intestazioni del limite di frequenza quando sono presenti dati sulla frequenza.array<string, string>nessuna prevista.Allegare alle risposte del Worker o del framework.
new RateLimitResult(bool $allowed, int $remainingRequests, int $retryAfterSeconds, string $clientId)Decisione, conteggio rimanente, ritardo per il nuovo tentativo, ID client.Nessun valore predefinito.RateLimitResultnessuna prevista.Risultato immutabile per un singolo controllo.
RateLimitResult::toHeaders()nessuna.Emette le intestazioni del limite rimanente e di reset.array<string, string>nessuna prevista.Usare per l’osservabilità e il backoff del client.
new RateLimitEntry(string $clientId, int $requestCount = 0, int $windowStart = 0, int $hourlyCount = 0, int $hourlyWindowStart = 0)ID client e contatori modificabili.I contatori iniziano da zero.RateLimitEntrynessuna prevista.Oggetto di tracciamento in memoria.
RateLimitEntry::increment()nessuna.Incrementa il contatore in memoria per un singolo client/window.voidnessuna prevista.Helper di basso livello usato da ApiProtection.
RateLimitEntry::isExpired(int $windowSeconds)Lunghezza della finestra in secondi.Confronta rispetto all’ora corrente.boolnessuna prevista.Helper di scadenza a runtime.
RateLimitEntry::isExpiredAt(int $now, int $windowSeconds)Valore del clock e lunghezza della finestra.Confronta rispetto al valore del clock fornito.boolnessuna prevista.Helper di test deterministico.
RateLimitEntry::reset()nessuna.Reimposta il conteggio e l’ora di inizio della finestra.voidnessuna prevista.Usato all’inizio di una nuova finestra.

Usare questa tabella per memorizzare i PDF generati in Cloudflare R2: il servizio di archiviazione, i relativi tipi di configurazione e chiave dell’oggetto, e il risultato del caricamento da esaminare prima di esporre un URL.

SimboloParametriComportamento predefinitoValore restituitoEccezioni o erroriNote
new R2ArchiveManager(R2ArchiveConfig $config, ClientInterface $httpClient, RequestFactoryInterface $requestFactory, StreamFactoryInterface $streamFactory)Configurazione R2 e factory/client HTTP PSR.Nessuna chiamata di rete durante la costruzione.R2ArchiveManagerErrori di wiring del container.Servizio di archiviazione principale.
R2ArchiveManager::upload(string $pdfData, string $filename, array $metadata = [])Byte del PDF non elaborati, nome file originale, metadati stringa.Metadati vuoti; chiave partizionata per data.R2UploadResultRestituisce un risultato non riuscito in caso di errore di configurazione, dimensione, HTTP o trasporto.Non genera eccezioni per un normale errore di caricamento.
R2ArchiveManager::generateSignedUrl(string $key, int $expiresInSeconds = 3600)Chiave dell’oggetto e TTL dell’URL.URL firmato di un’ora.stringErrori di firma derivanti da una configurazione non valida.Mantenere TTL brevi per i PDF sensibili.
R2ArchiveManager::buildObjectKey(string $filename)Nome file originale.Usa il prefisso del percorso configurato e la data corrente.R2ObjectKeynessuna prevista.Usare per un partizionamento prevedibile dell’archivio.
R2ArchiveManager::createPutRequest(R2ObjectKey $key, string $data, array $metadata = [])Chiave dell’oggetto, byte non elaborati, metadati.Firma una richiesta PUT.RequestInterfaceErrori di costruzione della richiesta.API di basso livello per trasporti personalizzati.
new R2ArchiveConfig(string $bucketName, string $accountId, string $accessKeyId, string $secretAccessKey, string $endpoint = '', string $pathPrefix = 'pdfs/', int $maxFileSizeBytes = 104857600)Bucket, ID account, credenziali, override dell’endpoint, prefisso della chiave, dimensione massima dell’oggetto.Endpoint derivato, prefisso pdfs/, dimensione massima dell’oggetto di 100 MiB.R2ArchiveConfigInvalidArgumentException per nomi di bucket non validi.Considerare le credenziali come configurazione contenente segreti.
R2ArchiveConfig::fromArray(array $data)ID account, bucket, credenziali, prefisso del percorso, override dell’endpoint, dimensione massima.I valori mancanti usano i valori predefiniti del costruttore.R2ArchiveConfigNome di bucket non valido quando fornito.Usare per idratare la configurazione dell’applicazione.
R2ArchiveConfig::isValid()nessuna.Richiede account, bucket, access key e secret key non vuoti.boolnessuna prevista.Una configurazione non valida fa fallire i caricamenti con risultati strutturati.
R2ArchiveConfig::getEndpoint()nessuna.Usa l’endpoint esplicito o deriva l’endpoint Cloudflare R2 dall’ID account.stringnessuna prevista.Usato per costruire le richieste firmate.
new R2ObjectKey(string $key, string $bucket)Chiave completa dell’oggetto e bucket.Nessuna normalizzazione.R2ObjectKeynessuna prevista.Solitamente creato da R2ObjectKey::generate().
R2ObjectKey::generate(string $prefix, string $filename, ?DateTimeInterface $date = null)Prefisso, nome file originale, data facoltativa.Chiave dell’oggetto partizionata per data e sanificata.R2ObjectKeynessuna prevista.Iniettare la data nei test per ottenere chiavi deterministiche.
R2ObjectKey::fullPath()nessuna.Unisce il percorso di partizione e il nome file dell’oggetto.stringnessuna prevista.Memorizzare questo valore come chiave dell’oggetto.
new R2UploadResult(bool $success, string $key, string $etag = '', int $size = 0, string $error = '')Flag di esito positivo, chiave dell’oggetto, ETag, dimensione in byte, messaggio di errore.ETag vuoto, dimensione zero, errore vuoto.R2UploadResultnessuna prevista.Restituito da R2ArchiveManager::upload().
R2UploadResult::isValid()nessuna.Valido quando il caricamento è riuscito e sono presenti sia la chiave sia l’ETag.boolnessuna prevista.Verificare prima di esporre URL.
R2UploadResult::publicUrl(string $customDomain = '')Dominio pubblico personalizzato facoltativo.Restituisce la sola chiave dell’oggetto quando non viene fornito alcun dominio personalizzato.stringnessuna prevista.Evitare URL pubblici per i documenti sensibili, a meno che la policy non lo consenta.

Usare questa tabella solo per il wiring di basso livello: pinning IP/SPKI a livello di cURL e contratti del renderer locale usati come percorso di fallback quando il Worker non è raggiungibile.

SimboloParametriComportamento predefinitoValore restituitoEccezioni o erroriNote
new PinnedCurlTransport(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory, array $pinnedIps = [], array $pinnedPublicKeys = [], int $timeoutSeconds = 30)Factory PSR-17, IP con pinning, chiavi pubbliche con pinning, timeout.Nessun pin e timeout di 30 secondi.PinnedCurlTransportnessuna prevista.Utilizzare solo quando è richiesto il pinning a livello di cURL.
PinnedCurlTransport::sendRequest(RequestInterface $request)Richiesta PSR-7.Invia tramite cURL con il timeout configurato e i controlli di pinning.ResponseInterfaceEccezioni di trasporto PSR-18.Usare solo quando i client HTTP del framework non possono applicare la stessa policy di pinning.
PinnedCurlTransport::buildCurlOptions(RequestInterface $request, string $host, int $port)Richiesta, host di destinazione, porta di destinazione.Costruisce l’array di opzioni cURL utilizzato da sendRequest().arrayErrori di richiesta non valida o di configurazione dei pin.Hook di basso livello per test e diagnostica.
LocalRendererInterface::render(string $html, array $options = [])HTML e opzioni del renderer.Solo contratto; l’implementazione decide i valori predefiniti.stringErrori di rendering specifici dell’implementazione.Usato come fallback locale quando il rendering del Worker non è disponibile.
LocalRendererFactoryInterface::create()nessuna.Crea un’implementazione del renderer locale.LocalRendererInterfaceErrori di factory o di dipendenza.Mantiene la costruzione del renderer di fallback al di fuori di CloudflareHtmlRenderer.
  • Considerare l’URL del Worker come un confine di rete. Convalidare destinazione, dimensione e autenticazione prima del rendering.
  • Usare i risultati della protezione API come output di policy, non come flusso di controllo delle eccezioni.
  • I caricamenti R2 restituiscono risultati strutturati di esito positivo o di errore; gestire entrambi i percorsi.