@@ -23,13 +23,19 @@ class Pdf
23
23
// Regular expression to detect XML strings
24
24
const REGEX_XML = '/<\??xml/i ' ;
25
25
26
+ // Regular expression to detect URL strings
27
+ const REGEX_URL = '/^(https?:)?\/\//i ' ;
28
+
26
29
// Regular expression to detect options that expect an URL or a file name,
27
30
// so we need to create a tmp file for the content.
28
31
const REGEX_OPTS_TMPFILE = '/^((header|footer)-html|(xsl|user)-style-sheet)$/i ' ;
29
32
30
- // prefix for tmp files
33
+ // Prefix for tmp files
31
34
const TMP_PREFIX = 'tmp_wkhtmlto_pdf_ ' ;
32
35
36
+ // Maximum length of a file path if PHP_MAXPATHLEN is not defined
37
+ const MAX_PATHLEN = 255 ;
38
+
33
39
/**
34
40
* @var string the name of the `wkhtmltopdf` binary. Default is
35
41
* `wkhtmltopdf`. You can also configure a full path here.
@@ -122,8 +128,8 @@ public function __construct($options = null)
122
128
*/
123
129
public function addPage ($ input , $ options = array (), $ type = null )
124
130
{
125
- $ options ['inputArg ' ] = $ this ->processInput ($ input , $ type );
126
- $ this ->_objects [] = $ this ->processOptions ($ options );
131
+ $ options ['inputArg ' ] = $ this ->ensureUrlOrFile ($ input , $ type );
132
+ $ this ->_objects [] = $ this ->ensureUrlOrFileOptions ($ options );
127
133
return $ this ;
128
134
}
129
135
@@ -139,9 +145,9 @@ public function addPage($input, $options = array(), $type = null)
139
145
*/
140
146
public function addCover ($ input , $ options = array (), $ type = null )
141
147
{
142
- $ options ['input ' ] = ($ this ->version9 ? '-- ' : '' ). 'cover ' ;
143
- $ options ['inputArg ' ] = $ this ->processInput ($ input , $ type );
144
- $ this ->_objects [] = $ this ->processOptions ($ options );
148
+ $ options ['input ' ] = ($ this ->version9 ? '-- ' : '' ) . 'cover ' ;
149
+ $ options ['inputArg ' ] = $ this ->ensureUrlOrFile ($ input , $ type );
150
+ $ this ->_objects [] = $ this ->ensureUrlOrFileOptions ($ options );
145
151
return $ this ;
146
152
}
147
153
@@ -153,8 +159,8 @@ public function addCover($input, $options = array(), $type = null)
153
159
*/
154
160
public function addToc ($ options = array ())
155
161
{
156
- $ options ['input ' ] = ($ this ->version9 ? '-- ' : '' ). " toc " ;
157
- $ this ->_objects [] = $ this ->processOptions ($ options );
162
+ $ options ['input ' ] = ($ this ->version9 ? '-- ' : '' ) . ' toc ' ;
163
+ $ this ->_objects [] = $ this ->ensureUrlOrFileOptions ($ options );
158
164
return $ this ;
159
165
}
160
166
@@ -215,16 +221,16 @@ public function toString()
215
221
*/
216
222
public function setOptions ($ options = array ())
217
223
{
218
- // #264 tmpDir must be set before calling processOptions
224
+ // #264 tmpDir must be set before calling ensureUrlOrFileOptions
219
225
if (isset ($ options ['tmpDir ' ])) {
220
226
$ this ->tmpDir = $ options ['tmpDir ' ];
221
227
unset($ options ['tmpDir ' ]);
222
228
}
223
- $ options = $ this ->processOptions ($ options );
229
+ $ options = $ this ->ensureUrlOrFileOptions ($ options );
224
230
foreach ($ options as $ key => $ val ) {
225
231
if (is_int ($ key )) {
226
232
$ this ->_options [] = $ val ;
227
- } elseif ($ key [0 ]!=='_ ' && property_exists ($ this , $ key )) {
233
+ } elseif ($ key [0 ] !== '_ ' && property_exists ($ this , $ key )) {
228
234
$ this ->$ key = $ val ;
229
235
} else {
230
236
$ this ->_options [$ key ] = $ val ;
@@ -287,7 +293,7 @@ protected function createPdf()
287
293
$ command ->addArg ($ fileName , null , true ); // Always escape filename
288
294
if (!$ command ->execute ()) {
289
295
$ this ->_error = $ command ->getError ();
290
- if (!(file_exists ($ fileName ) && filesize ($ fileName )!==0 && $ this ->ignoreWarnings )) {
296
+ if (!(file_exists ($ fileName ) && filesize ($ fileName ) !== 0 && $ this ->ignoreWarnings )) {
291
297
return false ;
292
298
}
293
299
}
@@ -296,35 +302,58 @@ protected function createPdf()
296
302
}
297
303
298
304
/**
299
- * @param string $input
300
- * @param string|null $type a type hint if the input is a string of known type. This can either be
301
- * `TYPE_HTML` or `TYPE_XML`. If `null` (default) the type is auto detected from the string content.
302
- * @return \mikehaertl\tmp\File|string a File object if the input is a HTML or XML string. The unchanged input otherwhise.
305
+ * This method creates a temporary file if the passed argument is neither a
306
+ * File instance or URL nor contains XML or HTML and is also not a valid
307
+ * file name.
308
+ *
309
+ * @param string|File $input the input argument File to check
310
+ * @param string|null $type a type hint if the input is a string of known
311
+ * type. This can either be `TYPE_HTML` or `TYPE_XML`. If `null` (default)
312
+ * the type is auto detected from the string content.
313
+ * @return \mikehaertl\tmp\File|string a File object if the input is a HTML
314
+ * or XML string. The unchanged input otherwhise.
303
315
*/
304
- protected function processInput ($ input , $ type = null )
316
+ protected function ensureUrlOrFile ($ input , $ type = null )
305
317
{
306
- if ($ type === self ::TYPE_HTML || $ type === null && preg_match (self ::REGEX_HTML , $ input )) {
307
- return $ this ->_tmpFiles [] = new File ($ input , '.html ' , self ::TMP_PREFIX , $ this ->tmpDir );
308
- } elseif ($ type === self ::TYPE_XML || preg_match (self ::REGEX_XML , $ input )) {
309
- return $ this ->_tmpFiles [] = new File ($ input , '.xml ' , self ::TMP_PREFIX , $ this ->tmpDir );
310
- } else {
318
+ if ($ input instanceof File) {
319
+ $ this ->_tmpFiles [] = $ input ;
320
+ return $ input ;
321
+ } elseif (preg_match (self ::REGEX_URL , $ input )) {
311
322
return $ input ;
323
+ } elseif ($ type === self ::TYPE_XML || $ type === null && preg_match (self ::REGEX_XML , $ input )) {
324
+ $ ext = '.xml ' ;
325
+ } else {
326
+ // First check for obvious HTML content to avoid is_file() as much
327
+ // as possible as it can trigger open_basedir restriction warnings
328
+ // with long strings.
329
+ $ isHtml = $ type === self ::TYPE_HTML || preg_match (self ::REGEX_HTML , $ input );
330
+ if (!$ isHtml ) {
331
+ $ maxPathLen = defined ('PHP_MAXPATHLEN ' ) ?
332
+ constant ('PHP_MAXPATHLEN ' ) : self ::MAX_PATHLEN ;
333
+ if (strlen ($ input ) <= $ maxPathLen && is_file ($ input )) {
334
+ return $ input ;
335
+ }
336
+ }
337
+ $ ext = '.html ' ;
312
338
}
339
+ $ file = new File ($ input , $ ext , self ::TMP_PREFIX , $ this ->tmpDir );
340
+ $ this ->_tmpFiles [] = $ file ;
341
+ return $ file ;
313
342
}
314
343
315
344
/**
316
345
* @param array $options list of options as name/value pairs
317
- * @return array options with raw content converted to tmp files where neccessary
346
+ * @return array options with raw HTML/XML/String content converted to tmp
347
+ * files where neccessary
318
348
*/
319
- protected function processOptions ($ options = array ())
349
+ protected function ensureUrlOrFileOptions ($ options = array ())
320
350
{
321
351
foreach ($ options as $ key => $ val ) {
322
352
// Some options expect a URL or a file name, so check if we need a temp file
323
353
if (is_string ($ val ) && preg_match (self ::REGEX_OPTS_TMPFILE , $ key ) ) {
324
- defined ('PHP_MAXPATHLEN ' ) || define ('PHP_MAXPATHLEN ' , 255 );
325
- $ isFile = (strlen ($ val ) <= PHP_MAXPATHLEN ) ? is_file ($ val ) : false ;
326
- if (!($ isFile || preg_match ('/^(https?:)?\/\//i ' ,$ val ) || $ val === strip_tags ($ val ))) {
327
- $ options [$ key ] = new File ($ val , '.html ' , self ::TMP_PREFIX , $ this ->tmpDir );
354
+ $ file = $ this ->ensureUrlOrFile ($ val );
355
+ if ($ file instanceof File) {
356
+ $ options [$ key ] = $ file ;
328
357
}
329
358
}
330
359
}
0 commit comments