Office-documenten converteren naar PDF met Gotenberg
In het kort
Sectie met titel “In het kort”De Gotenberg-bridge converteert een Office-document naar PDF. De bridge stuurt het document via HTTPS naar een Gotenberg-microservice en geeft de PDF-bytes terug. U beschrijft de service met een onveranderlijke GotenbergConfig, koppelt een PSR-18-client en PSR-17-factory’s aan GotenbergBridge, controleert de health status van de service en converteert een bestand vanaf schijf of bytes in het geheugen. Deze handleiding behandelt extensiegebaseerde formaatdetectie, de health probe, het getypeerde foutcontract en de overdracht naar NextPDF-nabewerking.
Voorafgaande vereisten:
- NextPDF-core en
nextpdf/gotenbergzijn geïnstalleerd. - Een Gotenberg-service is bereikbaar via HTTPS. De bridge weigert een gewone
http://-URL voordat een verzoek het proces verlaat. - Een PSR-18-client en PSR-17 request- en stream-factory’s zijn geïnstalleerd. Voor DNS- en TLS-pinning levert u daarnaast een PSR-17 response-factory mee.
- De invoer is een van de zes herkende Office-formaten:
.docx,.xlsx,.pptx,.odt,.odsof.odp. De bridge weigert elke andere extensie met eenValueError.
Dit is een how-to-handleiding. Lees voor een volledig, uitvoerbaar programma de Gotenberg-quickstart.
Installeren
Sectie met titel “Installeren”Installeer de bridge, een PSR-18-client en PSR-17-factory’s.
composer require nextpdf/gotenberg guzzlehttp/guzzleZorg voor een Gotenberg-service die bereikbaar is via HTTPS. Haal een eventueel bearer-token op uit een secrets manager of een geïnjecteerde omgevingswaarde. De bridge leest nooit omgevingsvariabelen en bouwt nooit een HTTP-client; u levert beide zelf aan.
Conceptueel overzicht
Sectie met titel “Conceptueel overzicht”GotenbergBridge::convertFile() neemt een pad op schijf. De bridge canonicaliseert het pad om traversal te blokkeren, koppelt de bestandsextensie aan een ondersteund formaat, controleert de grootte en de bestandsnaam en stuurt een multipart-verzoek naar <apiUrl>/forms/libreoffice/convert. convertString() volgt hetzelfde pad voor bytes die u al beschikbaar hebt; de methode gebruikt de oorspronkelijke bestandsnaam zodat de extensie kan worden gedetecteerd.
Formaatdetectie gebruikt de extensie. De bridge koppelt .docx, .xlsx, .pptx, .odt, .ods en .odp aan hun formaten en weigert al het andere met een ValueError vóór enig netwerkverkeer. Het resultaatobject stelt het gedetecteerde bronformaat beschikbaar als een enum-waarde.
De bridge voert één synchrone HTTP-round-trip uit, met validatie eromheen. De bridge doet geen nieuwe pogingen, plaatst niets in een wachtrij, cachet niet en beperkt het aantal aanvragen niet; die controles horen thuis in de applicatie rond de bridge. Behandel elke conversie als een remote aanroep naar een service die u beheert maar niet in-process bestuurt, en ontwerp voor de bijbehorende latency en foutmodi.
De bridge meldt fouten als getypeerde excepties en retourneert nooit een gedeeltelijk of ongevalideerd resultaat:
- Een statuscode anders dan
200, eenContent-Typezonderapplication/pdf, of een body die niet begint met%PDFveroorzaaktGotenbergConvertException. De bridge retourneert alleen een resultaat wanneer alle drie de controles slagen. - Een PSR-18-clientfout, waaronder een netwerkfout of timeout, wordt verpakt als
GotenbergConvertExceptionmet de oorspronkelijke exceptie als oorzaak. - Validatiefouten (niet-HTTPS-URL, privé- of gereserveerd adres, te grote invoer, onveilige bestandsnaam) veroorzaken
RuntimeExceptionvóór enig netwerkverkeer. - Een niet-herkende bestandsextensie veroorzaakt
ValueErrorvóór enig netwerkverkeer.
API-overzicht
Sectie met titel “API-overzicht”// Configuration (final readonly):new GotenbergConfig( string $apiUrl, // required, must be HTTPS int $timeout = 30, // hard transfer timeout, seconds int $maxFileSize = 52_428_800, // 50 MiB string $apiKey = '', // #[SensitiveParameter]; Bearer when non-empty list<string> $pinnedPublicKeys = [], // sha256/<base64> list<string> $backupPublicKeys = [],)GotenbergConfig::fromArray(array $config): selfGotenbergConfig::isValid(): bool
// The bridge:new GotenbergBridge( GotenbergConfig $config, ClientInterface $httpClient, // PSR-18 RequestFactoryInterface $requestFactory, // PSR-17 StreamFactoryInterface $streamFactory, // PSR-17 ?LoggerInterface $logger = null, // PSR-3 ?HtmlSecurityPolicyInterface $htmlSecurityPolicy = null, ?ResponseFactoryInterface $responseFactory = null, // enables pinned transport)GotenbergBridge::isAvailable(): boolGotenbergBridge::convertFile(string $path): GotenbergConvertResultGotenbergBridge::convertString(string $bytes, string $originalFilename): GotenbergConvertResultHet resultaatobject stelt pdfData, de sourceFormat-enum, isValid() (true wanneer de body niet leeg is en begint met %PDF) en size() beschikbaar. Raadpleeg de Gotenberg-configuratiepagina onder Zie ook voor de volledige veldreferentie, de sleutelmap van fromArray() en de regels voor transportselectie.
Codevoorbeeld — Snelstart
Sectie met titel “Codevoorbeeld — Snelstart”Configureer de service, koppel de bridge, voer de probe uit en converteer één bestand.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Gotenberg\GotenbergBridge;use NextPDF\Gotenberg\GotenbergConfig;use NextPDF\Gotenberg\GotenbergConvertException;
$config = new GotenbergConfig( apiUrl: 'https://gotenberg.example.com', timeout: 60, apiKey: getenv('GOTENBERG_TOKEN') ?: '',);
$bridge = new GotenbergBridge( config: $config, httpClient: $httpClient, // your PSR-18 client requestFactory: $requestFactory, // your PSR-17 factory streamFactory: $streamFactory, // your PSR-17 factory responseFactory: $responseFactory, // enables the pinned transport);
// Probe before converting. The probe validates the URL with no network// traffic, then sends a HEAD to <apiUrl>/health.if (!$bridge->isAvailable()) { throw new RuntimeException('Gotenberg is not reachable.');}
try { $result = $bridge->convertFile('/path/to/report.docx');} catch (GotenbergConvertException $exception) { // Bad config, HTTP failure, non-200, wrong Content-Type, or non-PDF body. throw $exception;}
if (!$result->isValid()) { throw new RuntimeException('Result is not a valid PDF.');}
file_put_contents('/path/to/report.pdf', $result->pdfData);De klasse is NextPDF\Gotenberg\GotenbergConfig (de regel hierboven gebruikt exact de namespace die uw code moet importeren). isAvailable() retourneert false en gooit nooit een exceptie bij een lege, niet-HTTPS- of privéadres-URL, of bij een netwerkfout; een statuscode lager dan 500 van /health betekent beschikbaar.
Codevoorbeeld — Productie
Sectie met titel “Codevoorbeeld — Productie”Een productieconversie vangt elk fouttype apart op, doet alleen nieuwe pogingen wanneer de omstandigheden daarvoor kloppen en begrenst de gelijktijdigheid aan de kant van de aanroeper. De volgorde van de catch-blokken hieronder is uitputtend.
<?php
declare(strict_types=1);
use NextPDF\Gotenberg\GotenbergBridge;use NextPDF\Gotenberg\GotenbergConvertException;use Psr\Log\LoggerInterface;use RuntimeException;use ValueError;
final readonly class OfficeConverter{ public function __construct( private GotenbergBridge $bridge, private LoggerInterface $logger, ) {}
public function convert(string $path): string { try { $result = $this->bridge->convertFile($path); } catch (GotenbergConvertException $exception) { // Transport, non-200, wrong Content-Type, or non-PDF body. // Retry only on transport-level or 502/503/504 causes, with // bounded exponential backoff and jitter — never blind retries. $this->logger->error('gotenberg.convert.failed', [ 'path' => basename($path), 'exception' => $exception::class, ]); throw $exception; } catch (ValueError $exception) { // Extension is not one of the six recognized Office formats. $this->logger->warning('gotenberg.convert.unsupported_format', [ 'path' => basename($path), ]); throw $exception; } catch (RuntimeException $exception) { // Non-HTTPS URL, private address, oversized input, or unsafe name. $this->logger->error('gotenberg.convert.rejected', [ 'path' => basename($path), 'exception' => $exception::class, ]); throw $exception; }
if (!$result->isValid()) { throw new RuntimeException('Gotenberg returned an invalid PDF body.'); }
return $result->pdfData; }}Doe alleen een nieuwe poging bij een GotenbergConvertException op transportniveau (een verpakte PSR-18-clientexceptie) en bij idempotente serverfouten (502, 503, 504). Een respons van de 400-klasse betekent meestal dat de invoer onjuist is, dus een nieuwe poging mislukt op dezelfde manier. Begrens het totale aantal pogingen en de totale doorlooptijd. Begrens het aantal lopende conversies tot de capaciteit die uw Gotenberg-deployment aankan. De bridge zelf is stateless en veilig te gebruiken vanuit veel workers, maar de service heeft een eindige conversiecapaciteit.
Randgevallen en valkuilen
Sectie met titel “Randgevallen en valkuilen”- Formaatdetectie gebeurt op basis van de extensie. Een
.docxdie hernoemd is naar.txtwordt geweigerd metValueError; een.txtdie hernoemd is naar.docxwordt naar Gotenberg gestuurd en mislukt daar. Vertrouw bij het accepteren van uploads op het werkelijke formaat, niet op de naam. fromArray()is opzettelijk vergevingsgezind. De methode vervangt onjuist gevormde invoer stilzwijgend door standaardwaarden. Valideer de bronarray tijdens het opstarten, zodat een ontbrekende URL vroeg naar voren komt als configuratiefout en niet als een exceptie per conversie.- De groottelimiet wordt in-process afgedwongen.
maxFileSize(standaard 50 MiB) wordt gecontroleerd voordat het verzoek wordt verzonden, zodat een te groot bestand nooit servicecapaciteit verbruikt. Verlaag de limiet tot wat uw documenten nodig hebben; een kleinere limiet is een goedkopere denial-of-service-maatregel. - De probe is niet gratis. Roep
isAvailable()aan vanaf een readiness- of health-endpoint, niet vóór elke conversie. De probe per conversie uitvoeren verdubbelt zonder voordeel uw aanvraagsnelheid naar de service. - Geen in-process caching. Als hetzelfde document herhaaldelijk wordt geconverteerd, cachet u de resulterende PDF in uw applicatie, met een content-hash van de invoer als sleutel.
renderTimeMsstelt u zelf in. Het timingveld van het resultaat is0.0tenzij uw integratie het meet en instelt. Meet de aanroep zelf als u het getal nodig hebt.
Prestaties
Sectie met titel “Prestaties”Gedurende het verzoek bezet een conversie één verbinding en één LibreOffice-worker aan de Gotenberg-kant, en Office-conversie kost tijd. Stel timeout in op basis van de gemeten conversielatency voor uw echte documenten, met marge. Houd deze onder elke upstream-gateway of PHP max_execution_time, zodat de bridge als eerste een timeout krijgt en u een getypeerde exceptie ontvangt in plaats van een afgebroken proces. Begrens de gelijktijdigheid met een wachtrij, semafoor of worker pool die is afgestemd op de servicecapaciteit. Er is geen in-process cache; voeg er een toe in uw applicatie als u dezelfde invoer herhaaldelijk converteert.
Beveiligingsnotities
Sectie met titel “Beveiligingsnotities”- HTTPS- en adrescontrole vóór verzending. De bridge weigert een niet-HTTPS-URL en een bestemming die naar privé- of gereserveerde adresruimte resolvet voordat een verzoek het proces verlaat. Bij elke nieuwe poging voert de bridge die validatie opnieuw uit, zodat die poging de SSRF-bescherming niet kan omzeilen.
- Pinned transport op aanvraag. Wanneer u een response-factory en pins levert (of er een geresolvde IP-set is), bindt de bridge de verbinding aan de geresolvde adressen, dwingt SPKI-pinning af, verifieert peer en host, past de timeout toe en schakelt het volgen van redirects uit. Configureer een back-uppin vóór een certificaatrotatie.
- Vertrouw het opgegeven content type van een upload niet. Valideer bij het accepteren van uploads van gebruikers zelf het werkelijke bestandstype; de extensie-naar-formaat-koppeling is een routeringsbeslissing, geen authenticiteitscontrole.
- Secrets worden gemaskeerd en zijn onveranderlijk.
apiKeydraagt#[SensitiveParameter], en de config isfinal readonly. Haal het token uit een secrets manager; commit het nooit. De logvermelding voor de conversie bevat de URL, bestandsnaam, formaat en content-lengte — nooit de bestandsinhoud of het token. - Schrijf nooit een leeg
catch-blok. Elk voorbeeld vangt het specifieke type op en logt met context.
Raadpleeg voor het volledige beveiligings- en deploymentmodel de Gotenberg-pagina over beveiliging en operations. Het PSR-18-transportcontract en de richtlijn om het content type niet te vertrouwen zijn gekoppeld aan hun clausules op de upstream-pagina over productiegebruik.
Conformiteit
Sectie met titel “Conformiteit”Deze handleiding doet zelf geen normatieve standaardclaim. Het PSR-18-transportgedrag van de bridge (een client gooit alleen een exceptie wanneer hij een respons niet kan verzenden of parseren; een 4xx/5xx is een normale retourwaarde), de richtlijn voor validatie van bestandsuploads en het TLS-pinning-model zijn gekoppeld aan PSR-18, OWASP en RFC 7469 op de upstream Gotenberg-pagina’s over productiegebruik en configuratie. Deze cookbook-pagina herhaalt het gebruik en verwijst voor die citaten naar die pagina’s. De bridge produceert PDF-bytes en stopt. Ondertekening, PDF/A-profielen en watermerken zijn NextPDF-nabewerkingstaken en een functie van de commerciële editie, geen onderdeel van deze bridge.
Zie ook
Sectie met titel “Zie ook”- Een gegenereerde PDF retourneren vanuit een controller — retourneer een geconverteerde PDF als HTTP-respons.
- Gotenberg-quickstart — het volledige, uitvoerbare conversieprogramma.
- Gotenberg-configuratie — elk veld, de
fromArray()-map en transportselectie. - Gotenberg-productiegebruik — secrets, timeouts, nieuwe pogingen, gelijktijdigheid en de grens van de nabewerking.