@@ -23,13 +23,19 @@ class Pdf
2323 // Regular expression to detect XML strings
2424 const REGEX_XML = '/<\??xml/i ' ;
2525
26+ // Regular expression to detect URL strings
27+ const REGEX_URL = '/^(https?:)?\/\//i ' ;
28+
2629 // Regular expression to detect options that expect an URL or a file name,
2730 // so we need to create a tmp file for the content.
2831 const REGEX_OPTS_TMPFILE = '/^((header|footer)-html|(xsl|user)-style-sheet)$/i ' ;
2932
30- // prefix for tmp files
33+ // Prefix for tmp files
3134 const TMP_PREFIX = 'tmp_wkhtmlto_pdf_ ' ;
3235
36+ // Maximum length of a file path if PHP_MAXPATHLEN is not defined
37+ const MAX_PATHLEN = 255 ;
38+
3339 /**
3440 * @var string the name of the `wkhtmltopdf` binary. Default is
3541 * `wkhtmltopdf`. You can also configure a full path here.
@@ -122,8 +128,8 @@ public function __construct($options = null)
122128 */
123129 public function addPage ($ input , $ options = array (), $ type = null )
124130 {
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 );
127133 return $ this ;
128134 }
129135
@@ -139,9 +145,9 @@ public function addPage($input, $options = array(), $type = null)
139145 */
140146 public function addCover ($ input , $ options = array (), $ type = null )
141147 {
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 );
145151 return $ this ;
146152 }
147153
@@ -153,8 +159,8 @@ public function addCover($input, $options = array(), $type = null)
153159 */
154160 public function addToc ($ options = array ())
155161 {
156- $ options ['input ' ] = ($ this ->version9 ? '-- ' : '' ). " toc " ;
157- $ this ->_objects [] = $ this ->processOptions ($ options );
162+ $ options ['input ' ] = ($ this ->version9 ? '-- ' : '' ) . ' toc ' ;
163+ $ this ->_objects [] = $ this ->ensureUrlOrFileOptions ($ options );
158164 return $ this ;
159165 }
160166
@@ -215,16 +221,16 @@ public function toString()
215221 */
216222 public function setOptions ($ options = array ())
217223 {
218- // #264 tmpDir must be set before calling processOptions
224+ // #264 tmpDir must be set before calling ensureUrlOrFileOptions
219225 if (isset ($ options ['tmpDir ' ])) {
220226 $ this ->tmpDir = $ options ['tmpDir ' ];
221227 unset($ options ['tmpDir ' ]);
222228 }
223- $ options = $ this ->processOptions ($ options );
229+ $ options = $ this ->ensureUrlOrFileOptions ($ options );
224230 foreach ($ options as $ key => $ val ) {
225231 if (is_int ($ key )) {
226232 $ this ->_options [] = $ val ;
227- } elseif ($ key [0 ]!=='_ ' && property_exists ($ this , $ key )) {
233+ } elseif ($ key [0 ] !== '_ ' && property_exists ($ this , $ key )) {
228234 $ this ->$ key = $ val ;
229235 } else {
230236 $ this ->_options [$ key ] = $ val ;
@@ -287,7 +293,7 @@ protected function createPdf()
287293 $ command ->addArg ($ fileName , null , true ); // Always escape filename
288294 if (!$ command ->execute ()) {
289295 $ this ->_error = $ command ->getError ();
290- if (!(file_exists ($ fileName ) && filesize ($ fileName )!==0 && $ this ->ignoreWarnings )) {
296+ if (!(file_exists ($ fileName ) && filesize ($ fileName ) !== 0 && $ this ->ignoreWarnings )) {
291297 return false ;
292298 }
293299 }
@@ -296,35 +302,58 @@ protected function createPdf()
296302 }
297303
298304 /**
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.
303315 */
304- protected function processInput ($ input , $ type = null )
316+ protected function ensureUrlOrFile ($ input , $ type = null )
305317 {
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 )) {
311322 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 ' ;
312338 }
339+ $ file = new File ($ input , $ ext , self ::TMP_PREFIX , $ this ->tmpDir );
340+ $ this ->_tmpFiles [] = $ file ;
341+ return $ file ;
313342 }
314343
315344 /**
316345 * @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
318348 */
319- protected function processOptions ($ options = array ())
349+ protected function ensureUrlOrFileOptions ($ options = array ())
320350 {
321351 foreach ($ options as $ key => $ val ) {
322352 // Some options expect a URL or a file name, so check if we need a temp file
323353 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 ;
328357 }
329358 }
330359 }
0 commit comments