Konwersja dokumentów Office do PDF przy użyciu Gotenberg
W skrócie
Dział zatytułowany „W skrócie”Mostek Gotenberg konwertuje dokument Office do PDF. Wysyła dokument do mikrousługi Gotenberg przez HTTPS i zwraca bajty PDF. Usługę opisujesz niezmienną konfiguracją GotenbergConfig, podłączasz klienta PSR-18 oraz fabryki PSR-17 do GotenbergBridge, sprawdzasz stan usługi i konwertujesz plik z dysku albo bajty z pamięci. Przewodnik omawia wykrywanie formatu po rozszerzeniu, sondę stanu, kontrakt typowanych błędów oraz przekazanie wyniku do przetwarzania końcowego w NextPDF.
Wymagania wstępne, od razu na początku:
- Rdzeń NextPDF oraz pakiet
nextpdf/gotenbergsą zainstalowane. - Usługa Gotenberg jest dostępna przez HTTPS. Mostek odrzuca zwykły adres URL z
http://, zanim z procesu wyjdzie jakiekolwiek żądanie. - Klient PSR-18 oraz fabryki żądań i strumieni PSR-17 są zainstalowane. Aby używać przypinania DNS i TLS, dostarczasz dodatkowo fabrykę odpowiedzi PSR-17.
- Dane wejściowe to jeden z sześciu rozpoznawanych formatów Office:
.docx,.xlsx,.pptx,.odt,.odslub.odp. Mostek odrzuca każde inne rozszerzenie, zgłaszającValueError.
To przewodnik praktyczny. Kompletny, gotowy do uruchomienia program znajdziesz w przewodniku Gotenberg quickstart.
Instalacja
Dział zatytułowany „Instalacja”Zainstaluj mostek, klienta PSR-18 oraz fabryki PSR-17.
composer require nextpdf/gotenberg guzzlehttp/guzzleUruchom usługę Gotenberg dostępną przez HTTPS. Tokeny bearer pobieraj z menedżera sekretów lub ze wstrzykniętej wartości środowiskowej. Mostek nigdy nie odczytuje zmiennych środowiskowych ani nie tworzy klienta HTTP; jedno i drugie dostarczasz samodzielnie.
Przegląd koncepcyjny
Dział zatytułowany „Przegląd koncepcyjny”Metoda GotenbergBridge::convertFile() przyjmuje ścieżkę do pliku na dysku. Sprowadza ścieżkę do postaci kanonicznej, aby zablokować przechodzenie po katalogach, mapuje rozszerzenie pliku na obsługiwany format, sprawdza rozmiar i nazwę pliku oraz wysyła żądanie multipart na adres <apiUrl>/forms/libreoffice/convert. Metoda convertString() działa tak samo dla bajtów, które już masz; używa oryginalnej nazwy pliku, aby można było wykryć rozszerzenie.
Wykrywanie formatu opiera się na rozszerzeniu. Mostek mapuje .docx, .xlsx, .pptx, .odt, .ods oraz .odp na odpowiednie formaty, a wszystko inne odrzuca, zgłaszając ValueError, zanim pojawi się jakikolwiek ruch sieciowy. Obiekt wyniku udostępnia wykryty format źródłowy jako wartość wyliczenia.
Mostek wykonuje jedno synchroniczne wywołanie HTTP, objęte walidacją. Nie ponawia prób, nie kolejkuje, nie buforuje ani nie ogranicza tempa żądań; te mechanizmy należą do aplikacji otaczającej mostek. Traktuj każdą konwersję jak zdalne wywołanie usługi, którą obsługujesz, ale której nie kontrolujesz w obrębie procesu, i projektuj z uwzględnieniem jej opóźnień oraz trybów awarii.
Mostek zgłasza błędy jako typowane wyjątki i nigdy nie zwraca częściowego ani niezweryfikowanego wyniku:
- Status inny niż
200, nagłówekContent-Typebezapplication/pdfalbo treść, która nie zaczyna się od%PDF, powodują zgłoszenieGotenbergConvertException. Mostek zwraca wynik tylko wtedy, gdy wszystkie trzy kontrole zakończą się powodzeniem. - Błąd klienta PSR-18, w tym awaria sieci lub przekroczenie limitu czasu, jest opakowywany w
GotenbergConvertException, z oryginalnym wyjątkiem jako przyczyną. - Błędy walidacji (adres URL inny niż HTTPS, adres prywatny lub zarezerwowany, zbyt duże dane wejściowe, niebezpieczna nazwa pliku) powodują zgłoszenie
RuntimeException, zanim pojawi się jakikolwiek ruch sieciowy. - Nierozpoznane rozszerzenie pliku powoduje zgłoszenie
ValueError, zanim pojawi się jakikolwiek ruch sieciowy.
Powierzchnia API
Dział zatytułowany „Powierzchnia API”// 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): GotenbergConvertResultObiekt wyniku udostępnia pdfData, wyliczenie sourceFormat, metodę isValid() (zwraca true, gdy treść jest niepusta i zaczyna się od %PDF) oraz size(). Pełny opis pól, mapę kluczy fromArray() oraz reguły wyboru transportu znajdziesz na stronie konfiguracji Gotenberg linkowanej w sekcji Zobacz też.
Przykład kodu — szybki start
Dział zatytułowany „Przykład kodu — szybki start”Skonfiguruj usługę, podłącz mostek, wykonaj sondę i przekonwertuj jeden plik.
<?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);To klasa NextPDF\Gotenberg\GotenbergConfig (powyższy wiersz używa dokładnej przestrzeni nazw, którą musi zaimportować kod). Metoda isAvailable() zwraca false i nigdy nie zgłasza wyjątku w przypadku pustego adresu URL, adresu innego niż HTTPS, adresu prywatnego ani żadnego błędu sieci; status poniżej 500 zwrócony z /health oznacza dostępność.
Przykład kodu — produkcja
Dział zatytułowany „Przykład kodu — produkcja”Konwersja produkcyjna przechwytuje każdy typ błędu osobno, ponawia próbę tylko wtedy, gdy spełnione są właściwe warunki, i ogranicza współbieżność po stronie wywołującego. Poniższa kolejność bloków catch jest wyczerpująca.
<?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; }}Ponawiaj próbę tylko przy GotenbergConvertException na poziomie transportu (opakowanym wyjątku klienta PSR-18) oraz dla idempotentnych błędów serwera (502, 503, 504). Odpowiedź z klasy 400 zwykle oznacza, że dane wejściowe są nieprawidłowe, więc ponowienie zakończy się tak samo. Ogranicz łączną liczbę prób oraz całkowity czas rzeczywisty. Ogranicz liczbę równolegle wykonywanych konwersji do przepustowości, którą wytrzymuje wdrożenie Gotenberg. Sam mostek jest bezstanowy i bezpieczny w użyciu z wielu procesów roboczych, ale usługa ma skończoną przepustowość konwersji.
Przypadki brzegowe i pułapki
Dział zatytułowany „Przypadki brzegowe i pułapki”- Wykrywanie formatu odbywa się na podstawie rozszerzenia. Plik
.docxprzemianowany na.txtjest odrzucany z błędemValueError; plik.txtprzemianowany na.docxjest wysyłany do Gotenberg i tam kończy się niepowodzeniem. Przy przyjmowaniu przesyłanych plików opieraj się na rzeczywistym formacie, a nie na nazwie. - Metoda
fromArray()jest z założenia pobłażliwa. Po cichu podstawia wartości domyślne w miejsce nieprawidłowych danych wejściowych. Sprawdzaj tablicę źródłową na ścieżce rozruchu, aby brakujący adres URL ujawnił się wcześnie jako błąd konfiguracji, a nie jako wyjątek przy każdej konwersji. - Limit rozmiaru jest egzekwowany w obrębie procesu. Parametr
maxFileSize(domyślnie 50 MiB) jest sprawdzany przed wysłaniem żądania, więc zbyt duży plik nigdy nie zużywa przepustowości usługi. Obniż limit, aby odpowiadał potrzebom Twoich dokumentów; mniejszy limit to tańszy mechanizm ochrony przed odmową usługi. - Sonda nie jest bezkosztowa. Wywołuj
isAvailable()z punktu końcowego gotowości lub kontroli stanu, a nie przed każdą konwersją. Uruchamianie jej przy każdej konwersji podwaja liczbę żądań kierowanych do usługi bez żadnej korzyści. - Brak buforowania w obrębie procesu. Jeśli ten sam dokument jest konwertowany wielokrotnie, buforuj powstały plik PDF w aplikacji, kluczując go skrótem treści danych wejściowych.
- Pole
renderTimeMsustawiasz samodzielnie. Pole czasu w wyniku wynosi0.0, chyba że integracja je zmierzy i ustawi. Zmierz czas wywołania samodzielnie, jeśli potrzebujesz tej wartości.
Wydajność
Dział zatytułowany „Wydajność”Przez cały czas trwania żądania zajęte są jedno połączenie i jeden proces roboczy LibreOffice po stronie Gotenberg, a sama konwersja Office wymaga czasu. Ustaw timeout na podstawie zmierzonego opóźnienia konwersji dla rzeczywistych dokumentów, z zapasem. Utrzymuj go poniżej limitu dowolnej nadrzędnej bramy lub PHP max_execution_time, aby mostek przekroczył limit czasu jako pierwszy i abyś otrzymał typowany wyjątek zamiast wymuszonego zakończenia procesu. Ogranicz współbieżność za pomocą kolejki, semafora lub puli procesów roboczych dobranej do przepustowości usługi. Mostek nie ma bufora w obrębie procesu; dodaj go w aplikacji, jeśli wielokrotnie konwertujesz te same dane wejściowe.
Uwagi dotyczące bezpieczeństwa
Dział zatytułowany „Uwagi dotyczące bezpieczeństwa”- HTTPS i weryfikacja adresu przed wysłaniem. Mostek odrzuca adres URL inny niż HTTPS oraz miejsce docelowe, które rozwiązuje się na prywatną lub zarezerwowaną przestrzeń adresową, zanim z procesu wyjdzie jakiekolwiek żądanie. Każde ponowne wywołanie ponownie wykonuje tę walidację, więc ponowienie nie może obejść zabezpieczenia przed SSRF.
- Transport z przypinaniem na żądanie. Gdy dostarczysz fabrykę odpowiedzi oraz przypięcia (lub gdy istnieje rozwiązany zbiór adresów IP), mostek wiąże połączenie z rozwiązanymi adresami, wymusza przypinanie SPKI, weryfikuje peera i hosta, stosuje limit czasu oraz wyłącza podążanie za przekierowaniami. Skonfiguruj zapasowe przypięcie przed rotacją certyfikatu.
- Nie ufaj deklarowanemu typowi treści przesyłanego pliku. Przyjmując pliki przesyłane przez użytkowników, sam zweryfikuj rzeczywisty typ pliku; mapa rozszerzenie–format to decyzja o routingu, a nie kontrola autentyczności.
- Sekrety są maskowane i niezmienne. Parametr
apiKeyma atrybut#[SensitiveParameter], a konfiguracja jestfinal readonly. Pobieraj token z menedżera sekretów; nigdy nie umieszczaj go w repozytorium. Zapisany w dzienniku wpis konwersji zawiera adres URL, nazwę pliku, format oraz długość treści — nigdy zawartość pliku ani tokenu. - Nigdy nie pisz pustego bloku
catch. Każdy przykład przechwytuje konkretny typ i zapisuje w dzienniku wraz z kontekstem.
Pełny model bezpieczeństwa i wdrożenia znajdziesz na stronie bezpieczeństwa i operacji Gotenberg. Kontrakt transportu PSR-18 oraz wskazówka, by nie ufać typowi treści, są powiązane z odpowiednimi klauzulami na nadrzędnej stronie użycia produkcyjnego.
Zgodność
Dział zatytułowany „Zgodność”Ten przewodnik nie formułuje własnych normatywnych deklaracji zgodności ze standardami. Zachowanie transportu PSR-18 w mostku (klient zgłasza wyjątek tylko wtedy, gdy nie może wysłać żądania ani sparsować odpowiedzi; odpowiedź 4xx/5xx to normalna wartość zwracana), wskazówki dotyczące walidacji przesyłanych plików oraz model przypinania TLS są przypisane do PSR-18, OWASP i RFC 7469 na nadrzędnych stronach użycia produkcyjnego i konfiguracji Gotenberg. Ta strona poradnika powtarza sposób użycia i odsyła po te cytowania do tamtych stron. Mostek wytwarza bajty pliku PDF i na tym kończy. Podpisywanie, profile PDF/A oraz znaki wodne należą do zadań przetwarzania końcowego w NextPDF oraz funkcji edycji komercyjnej, a nie do tego mostka.
Zobacz też
Dział zatytułowany „Zobacz też”- Zwracanie wygenerowanego pliku PDF z kontrolera — zwróć przekonwertowany plik PDF jako odpowiedź HTTP.
- Gotenberg quickstart — kompletny, gotowy do uruchomienia program konwersji.
- Konfiguracja Gotenberg — wszystkie pola, mapa
fromArray()oraz wybór transportu. - Użycie produkcyjne Gotenberg — sekrety, limity czasu, ponawianie prób, współbieżność oraz granica przetwarzania końcowego.