Mengonversi dokumen Office ke PDF dengan Gotenberg
Gambaran singkat
Bagian berjudul “Gambaran singkat”Jembatan Gotenberg mengonversi dokumen Office ke PDF. Jembatan ini mengirim dokumen ke microservice Gotenberg melalui HTTPS, lalu mengembalikan byte PDF. Anda mendeskripsikan layanan dengan GotenbergConfig yang imutabel, menghubungkan klien PSR-18 dan factory PSR-17 ke GotenbergBridge, memeriksa kesehatan layanan, lalu mengonversi berkas dari disk atau byte di memori. Panduan ini membahas deteksi format berbasis ekstensi, probe kesehatan, kontrak kegagalan bertipe, dan penyerahan hasil ke pasca-pemrosesan NextPDF.
Prasyaratnya dinyatakan sejak awal:
- Inti NextPDF dan
nextpdf/gotenbergsudah terpasang. - Layanan Gotenberg dapat dijangkau melalui HTTPS. Jembatan menolak URL
http://biasa sebelum permintaan apa pun meninggalkan proses. - Klien PSR-18 serta factory request dan stream PSR-17 sudah terpasang. Untuk penyematan DNS dan TLS, Anda juga perlu menyediakan response factory PSR-17.
- Input adalah salah satu dari enam format Office yang dikenali:
.docx,.xlsx,.pptx,.odt,.ods, atau.odp. Jembatan menolak ekstensi apa pun selain itu denganValueError.
Ini adalah panduan praktis. Untuk program lengkap yang dapat dijalankan, lihat panduan ringkas Gotenberg.
Pemasangan
Bagian berjudul “Pemasangan”Pasang jembatan, klien PSR-18, dan factory PSR-17.
composer require nextpdf/gotenberg guzzlehttp/guzzleJalankan layanan Gotenberg yang dapat dijangkau melalui HTTPS. Ambil token bearer dari secrets manager atau nilai environment yang disuntikkan. Jembatan tidak pernah membaca variabel environment dan tidak pernah membuat klien HTTP; Andalah yang menyediakan keduanya.
Gambaran umum konseptual
Bagian berjudul “Gambaran umum konseptual”GotenbergBridge::convertFile() menerima path di disk. Jembatan melakukan kanonisasi path untuk memblokir traversal, memetakan ekstensi berkas ke format yang didukung, memeriksa ukuran dan nama berkas, lalu mengirim permintaan multipart ke <apiUrl>/forms/libreoffice/convert. convertString() mengikuti alur yang sama untuk byte yang sudah Anda miliki; metode ini menggunakan nama berkas asli agar ekstensi dapat dideteksi.
Deteksi format didasarkan pada ekstensi. Jembatan memetakan .docx, .xlsx, .pptx, .odt, .ods, dan .odp ke formatnya masing-masing dan menolak yang lain dengan ValueError sebelum ada lalu lintas jaringan. Objek hasil mengekspos format sumber yang terdeteksi sebagai nilai enum.
Jembatan melakukan satu siklus request-response HTTP sinkron yang dibungkus dengan validasi. Jembatan tidak melakukan coba ulang, antrean, cache, atau pembatasan laju; kontrol tersebut menjadi tanggung jawab aplikasi di sekitar jembatan. Perlakukan setiap konversi sebagai panggilan jarak jauh ke layanan yang Anda operasikan tetapi tidak Anda kendalikan di dalam proses, lalu rancang aplikasi untuk latensi serta mode kegagalannya.
Jembatan melaporkan kegagalan sebagai exception bertipe dan tidak pernah mengembalikan hasil yang parsial atau belum tervalidasi:
- Status non-
200,Content-Typetanpaapplication/pdf, atau body yang tidak diawali dengan%PDFakan memunculkanGotenbergConvertException. Jembatan hanya mengembalikan hasil ketika ketiga pemeriksaan lolos. - Kegagalan klien PSR-18, termasuk kegagalan jaringan atau timeout, dibungkus sebagai
GotenbergConvertExceptiondengan exception asli sebagai penyebabnya. - Kegagalan validasi (URL non-HTTPS, alamat privat atau dicadangkan, input berukuran berlebih, nama berkas tidak aman) memunculkan
RuntimeExceptionsebelum ada lalu lintas jaringan. - Ekstensi berkas yang tidak dikenali memunculkan
ValueErrorsebelum ada lalu lintas jaringan.
Permukaan API
Bagian berjudul “Permukaan 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): GotenbergConvertResultObjek hasil mengekspos pdfData, enum sourceFormat, isValid() (true ketika body tidak kosong dan diawali dengan %PDF), dan size(). Untuk referensi field lengkap, peta kunci fromArray(), dan aturan pemilihan transport, lihat halaman konfigurasi Gotenberg yang ditautkan di bagian Lihat juga.
Contoh kode — Mulai cepat
Bagian berjudul “Contoh kode — Mulai cepat”Deskripsikan layanan, hubungkan jembatan, lakukan probe layanan, lalu konversi satu berkas.
<?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);Kelas yang digunakan adalah NextPDF\Gotenberg\GotenbergConfig (baris di atas menggunakan namespace persis yang harus diimpor oleh kode Anda). isAvailable() mengembalikan false dan tidak pernah melempar exception untuk URL yang kosong, non-HTTPS, atau beralamat privat, maupun untuk kesalahan jaringan apa pun; status di bawah 500 dari /health berarti layanan tersedia.
Contoh kode — Produksi
Bagian berjudul “Contoh kode — Produksi”Konversi produksi menangkap setiap jenis kegagalan secara terpisah, melakukan coba ulang hanya ketika kondisinya tepat, dan membatasi konkurensi di sisi pemanggil. Urutan catch di bawah ini mencakup seluruh kasus.
<?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; }}Lakukan coba ulang hanya pada GotenbergConvertException tingkat transport (exception klien PSR-18 yang dibungkus) dan pada kesalahan server yang idempoten (502, 503, 504). Respons kelas 400 biasanya berarti input salah, sehingga coba ulang akan gagal dengan cara yang sama. Batasi total percobaan dan total waktu aktual. Batasi jumlah konversi yang sedang berjalan sesuai kapasitas yang dapat ditopang oleh deployment Gotenberg Anda. Jembatan itu sendiri bersifat stateless dan aman digunakan dari banyak worker, tetapi layanan memiliki kapasitas konversi yang terbatas.
Kasus tepi & jebakan
Bagian berjudul “Kasus tepi & jebakan”- Deteksi format berdasarkan ekstensi. Berkas
.docxyang diganti namanya menjadi.txtditolak denganValueError; berkas.txtyang diganti namanya menjadi.docxdikirim ke Gotenberg dan gagal di sana. Saat menerima unggahan, percayai format yang sebenarnya, bukan sekadar namanya. fromArray()dirancang untuk bersikap toleran. Metode ini secara diam-diam mengganti input yang cacat dengan nilai standar. Validasi array sumber di jalur boot Anda agar URL yang hilang muncul lebih awal sebagai kesalahan konfigurasi, bukan sebagai exception pada setiap konversi.- Batas ukuran diberlakukan dalam proses.
maxFileSize(standar 50 MiB) diperiksa sebelum permintaan dikirim, sehingga berkas berukuran berlebih tidak pernah menghabiskan kapasitas layanan. Turunkan batas agar sesuai dengan kebutuhan dokumen Anda; batas yang lebih kecil adalah kontrol denial-of-service yang lebih murah. - Probe tidak gratis. Panggil
isAvailable()dari endpoint readiness atau kesehatan, bukan sebelum setiap konversi. Menjalankannya pada setiap konversi melipatgandakan laju permintaan Anda ke layanan tanpa manfaat apa pun. - Tidak ada cache dalam proses. Jika dokumen yang sama dikonversi berulang kali, cache PDF hasilnya di aplikasi Anda, dengan kunci berupa hash konten dari input.
renderTimeMsadalah milik Anda untuk diatur. Field waktu pada hasil bernilai0.0kecuali integrasi Anda mengukur dan menetapkannya. Ukur sendiri durasi panggilan jika Anda membutuhkan angka tersebut.
Kinerja
Bagian berjudul “Kinerja”Selama permintaan berlangsung, satu konversi menahan satu koneksi dan satu worker LibreOffice di sisi Gotenberg, dan konversi Office memang membutuhkan waktu. Atur timeout berdasarkan latensi konversi terukur untuk dokumen nyata Anda, dengan margin cadangan. Jaga agar nilainya di bawah gateway upstream mana pun atau max_execution_time PHP, sehingga jembatan mengalami timeout lebih dahulu dan Anda mendapatkan exception bertipe alih-alih proses yang dihentikan paksa. Batasi konkurensi dengan antrean, semaphore, atau worker pool yang diukur sesuai kapasitas layanan. Tidak ada cache dalam proses; tambahkan cache di aplikasi Anda jika Anda mengonversi input yang sama berulang kali.
Catatan keamanan
Bagian berjudul “Catatan keamanan”- Penyaringan HTTPS dan alamat sebelum pengiriman. Jembatan menolak URL non-HTTPS dan tujuan yang teresolusi ke ruang alamat privat atau dicadangkan sebelum permintaan apa pun meninggalkan proses. Setiap panggilan yang dicoba ulang menjalankan kembali validasi tersebut, sehingga coba ulang tidak dapat melewati penjaga SSRF.
- Transport tersemat sesuai permintaan. Ketika Anda menyediakan response factory dan pin (atau terdapat kumpulan IP yang teresolusi), jembatan mengikat koneksi ke alamat yang teresolusi, memberlakukan penyematan SPKI, memverifikasi peer dan host, menerapkan timeout, dan menonaktifkan pengikutan pengalihan. Konfigurasikan pin cadangan sebelum rotasi sertifikat.
- Jangan percayai jenis konten yang dideklarasikan dari sebuah unggahan. Saat menerima unggahan pengguna, validasi sendiri jenis berkas yang sebenarnya; peta ekstensi-ke-format adalah keputusan perutean, bukan pemeriksaan keaslian.
- Rahasia diredaksi dan imutabel.
apiKeymembawa#[SensitiveParameter], dan konfigurasinya bersifatfinal readonly. Ambil token dari secrets manager; jangan pernah meng-commit-nya. Entri konversi yang dicatat membawa URL, nama berkas, format, dan panjang konten — tidak pernah isi berkas atau token. - Jangan pernah menulis blok
catchyang kosong. Setiap contoh menangkap jenis yang spesifik dan mencatat log dengan konteks.
Untuk model keamanan dan deployment lengkap, lihat halaman keamanan dan operasi Gotenberg. Kontrak transport PSR-18 dan panduan jangan-percayai-content-type disematkan ke klausulnya masing-masing pada halaman penggunaan produksi upstream.
Kesesuaian
Bagian berjudul “Kesesuaian”Panduan ini tidak membuat klaim standar normatifnya sendiri. Perilaku transport PSR-18 jembatan (klien hanya melempar exception ketika tidak dapat mengirim atau mengurai respons; 4xx/5xx adalah nilai kembalian yang normal), panduan validasi unggahan berkas, dan model penyematan TLS disematkan ke PSR-18, OWASP, dan RFC 7469 pada halaman penggunaan produksi dan konfigurasi Gotenberg upstream. Halaman cookbook ini menyatakan kembali penggunaannya dan menyerahkan kutipan tersebut ke halaman-halaman itu. Jembatan menghasilkan byte PDF lalu berhenti. Penandatanganan, profil PDF/A, dan penambahan tanda air adalah urusan pasca-pemrosesan NextPDF serta kapabilitas edisi komersial, bukan bagian dari jembatan ini.
Lihat juga
Bagian berjudul “Lihat juga”- Mengembalikan PDF yang dihasilkan dari sebuah controller — mengembalikan PDF hasil konversi sebagai respons HTTP.
- Panduan ringkas Gotenberg — program konversi lengkap yang dapat dijalankan.
- Konfigurasi Gotenberg — setiap field, peta
fromArray(), dan pemilihan transport. - Penggunaan produksi Gotenberg — rahasia, timeout, coba ulang, konkurensi, dan batas pasca-pemrosesan.