@@ -68,23 +68,28 @@ public function getPdfFile(): string
6868
6969 /**
7070 * Renders the raw roadbook page to PDF, either through the WeasyPrint
71- * HTTP sidecar (dev/Docker) or the standalone `weasyprint` binary
72- * (production, when $weasyprintUrl is "cli").
71+ * HTTP sidecar (dev/Docker) or the standalone `weasyprint` binary reading
72+ * the rendered HTML straight off disk (production, when $weasyprintUrl
73+ * is "cli" — no network hop, so $internalBaseUrl/DNS don't matter there).
7374 *
7475 * @throws \RuntimeException when the conversion fails
7576 */
76- public function exportPdf (string $ internalBaseUrl , string $ weasyprintUrl , string $ weasyprintBin = 'weasyprint ' ): void
77+ public function exportPdf (string $ internalBaseUrl , string $ weasyprintUrl , string $ weasyprintBin = 'weasyprint ' , ? string $ publicDir = null ): void
7778 {
7879 $ pdfDir = dirname ($ this ->getPdfFile ());
7980 if (!is_dir ($ pdfDir )) {
8081 mkdir ($ pdfDir , 0775 , true );
8182 }
8283
83- $ url = rtrim ($ internalBaseUrl , '/ ' ) . '/roadbook/ ' . $ this ->id . '/raw ' ;
84-
85- $ body = $ weasyprintUrl === 'cli '
86- ? $ this ->convertPdfViaCli ($ url , $ weasyprintBin )
87- : $ this ->convertPdfViaHttp ($ url , $ weasyprintUrl );
84+ if ($ weasyprintUrl === 'cli ' ) {
85+ if ($ publicDir === null ) {
86+ throw new \RuntimeException ('publicDir is required for CLI-mode PDF export. ' );
87+ }
88+ $ body = $ this ->convertPdfViaCli ($ publicDir , $ weasyprintBin );
89+ } else {
90+ $ url = rtrim ($ internalBaseUrl , '/ ' ) . '/roadbook/ ' . $ this ->id . '/raw ' ;
91+ $ body = $ this ->convertPdfViaHttp ($ url , $ weasyprintUrl );
92+ }
8893
8994 if (!$ this ->saveFile ($ this ->getPdfFile (), $ body )) {
9095 throw new \RuntimeException ('Unable to write the PDF file. ' );
@@ -107,7 +112,7 @@ private function convertPdfViaHttp(string $url, string $weasyprintUrl): string
107112
108113 $ body = @file_get_contents ($ convertUrl , false , $ context );
109114 $ status = 0 ;
110- foreach (http_get_last_response_headers () as $ header ) {
115+ foreach (http_get_last_response_headers () ?? [] as $ header ) {
111116 if (preg_match ('#^HTTP/\S+\s+(\d{3})# ' , $ header , $ m )) {
112117 $ status = (int ) $ m [1 ];
113118 }
@@ -129,25 +134,39 @@ private function convertPdfViaHttp(string $url, string $weasyprintUrl): string
129134 return $ body ;
130135 }
131136
132- private function convertPdfViaCli (string $ url , string $ weasyprintBin ): string
137+ private function convertPdfViaCli (string $ publicDir , string $ weasyprintBin ): string
133138 {
134- $ outputFile = tempnam (sys_get_temp_dir (), 'weasyprint_ ' );
139+ $ html = $ this ->twig ->render ('raw.twig.html ' , [
140+ 'suffix_css_js ' => '' ,
141+ 'style ' => $ this ->getCustomCss (),
142+ 'content ' => (string ) file_get_contents ($ this ->getHtmlFile ()),
143+ ]);
144+
145+ $ htmlFile = tempnam (sys_get_temp_dir (), 'weasyprint_src_ ' ) . '.html ' ;
146+ $ outputFile = tempnam (sys_get_temp_dir (), 'weasyprint_out_ ' );
135147
136148 try {
137- $ process = new Process ([$ weasyprintBin , $ url , $ outputFile ], timeout: 120 );
149+ file_put_contents ($ htmlFile , $ html );
150+
151+ // Rendered from disk directly: relative/absolute asset paths (/design,
152+ // /img, /images) resolve against the local filesystem, no HTTP round-trip.
153+ $ baseUrl = 'file:// ' . rtrim ($ publicDir , '/ ' ) . '/ ' ;
154+
155+ $ process = new Process ([$ weasyprintBin , $ htmlFile , $ outputFile , '--base-url ' , $ baseUrl ], timeout: 120 );
138156 $ process ->run ();
139157
140158 if (!$ process ->isSuccessful ()) {
141- throw new \RuntimeException (sprintf ('PDF conversion failed (weasyprint_bin=%s, raw_url =%s): %s ' , $ weasyprintBin , $ url , trim ($ process ->getErrorOutput ()) !== '' ? trim ($ process ->getErrorOutput ()) : trim ($ process ->getOutput ())), previous: new ProcessFailedException ($ process ));
159+ throw new \RuntimeException (sprintf ('PDF conversion failed (weasyprint_bin=%s, roadbook_id =%s): %s ' , $ weasyprintBin , $ this -> id , trim ($ process ->getErrorOutput ()) !== '' ? trim ($ process ->getErrorOutput ()) : trim ($ process ->getOutput ())), previous: new ProcessFailedException ($ process ));
142160 }
143161
144162 $ body = file_get_contents ($ outputFile );
145163 if ($ body === false || $ body === '' ) {
146- throw new \RuntimeException (sprintf ('PDF conversion produced an empty file (weasyprint_bin=%s, raw_url =%s) ' , $ weasyprintBin , $ url ));
164+ throw new \RuntimeException (sprintf ('PDF conversion produced an empty file (weasyprint_bin=%s, roadbook_id =%s) ' , $ weasyprintBin , $ this -> id ));
147165 }
148166
149167 return $ body ;
150168 } finally {
169+ @unlink ($ htmlFile );
151170 @unlink ($ outputFile );
152171 }
153172 }
0 commit comments