79

I am trying to read a image file (.jpeg to be exact), and 'echo' it back to the page output, but have is display an image...

my index.php has an image link like this:

<img src='test.php?image=1234.jpeg' />

and my php script does basically this:

1) read 1234.jpeg 2) echo file contents... 3) I have a feeling I need to return the output back with a mime-type, but this is where I get lost

Once I figure this out, I will be removing the file name input all together and replace it with an image id.

If I am unclear, or you need more information, please reply.

Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
Kladskull
  • 10,332
  • 20
  • 69
  • 111

6 Answers6

135

The PHP Manual has this example:

<?php
// open the file in a binary mode
$name = './img/ok.png';
$fp = fopen($name, 'rb');

// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));

// dump the picture and stop the script
fpassthru($fp);
exit;
?>

The important points is that you must send a Content-Type header. Also, you must be careful not include any extra white space (like newlines) in your file before or after the <?php ... ?> tags.

As suggested in the comments, you can avoid the danger of extra white space at the end of your script by omitting the ?> tag:

<?php
$name = './img/ok.png';
$fp = fopen($name, 'rb');

header("Content-Type: image/png");
header("Content-Length: " . filesize($name));

fpassthru($fp);

You still need to carefully avoid white space at the top of the script. One particularly tricky form of white space is a UTF-8 BOM. To avoid that, make sure to save your script as "ANSI" (Notepad) or "ASCII" or "UTF-8 without signature" (Emacs) or similar.

Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
  • 17
    To that end, some (including Zend, PEAR, or both -- I forget) recommend omitting the closing ?>. It's perfectly syntactically valid, and guarantees no issues with trailing whitespace. – Frank Farmer May 22 '09 at 22:20
  • 15
    But, but... it's weird not to close what one open's :-) – Martin Geisler May 22 '09 at 22:46
  • 2
    Don't omit the ?>. "Easier" doesn't mean "better". – Jared Farrish May 22 '09 at 23:24
  • 3
    Totaly agree with Frank Farmer, a code without the ending ?> will be easier to debug. It's just a really useful tip. And to answer to Jared Farrish, easier here do mean better, it's right, and it should be used everywhere, since your code should not be bugged or anything, if you don't put it, it will advert you if there are some errors. It saves a lot of debugging times. – Boris Guéry May 22 '09 at 23:30
  • agreed, omit it. Technically it's more correct, because we don't want the PHP parsing to ever end on the script in question. – William Denniss May 30 '10 at 13:03
  • instead of hardcoding your header, you could just add: $size = getimagesize($filename); header("Content-type: {$size['mime']}"); – Sauleil Apr 09 '11 at 12:40
  • 2
    Agreed, omit the closing `?>`. @Jared Farrish; why do you think it is better not to? – MikeSchinkel May 15 '11 at 18:09
  • 2
    I just consider it to be a better practice, "close your tags". I don't have any fancy answer, but it's two letters and semantically, I just think it's more complete. That's just my opinion. :) – Jared Farrish May 15 '11 at 22:46
  • Eliminating bugs and potential bugs is the best practice by far. This case is a clear counter-example to "close your tags". Give your head a shake. – DaveWalley Oct 02 '13 at 21:58
  • WARNING : `filesize($name)` will break the script if your $name is a url. – Ulad Kasach Sep 20 '15 at 15:13
  • Good example from the docs, but the page says "If you just want to dump the contents of a file to the output buffer, without first modifying it or seeking to a particular offset, you may want to use the readfile(), which saves you the fopen() call." so [`readfile`](http://php.net/manual/en/function.readfile.php) is better and more efficient in this case. – Edward May 08 '16 at 08:25
  • Thank you for the White Space warning. – Tim Seed Sep 08 '17 at 14:14
  • Ommitting the closing ?> tag seems very "experienced knowledge only" type stuff. Maybe the practice should be documented (i.e. wherever you omit the closing tag, put a line at the end of the code that explains why it isn't present). – gth Apr 11 '22 at 08:31
31

I feel like we can make this code a little bit easier by just getting the mime type from $image_info:

$file_out = "myDirectory/myImage.gif"; // The image to return

if (file_exists($file_out)) {

   $image_info = getimagesize($file_out);

   //Set the content-type header as appropriate
   header('Content-Type: ' . $image_info['mime']);

   //Set the content-length header
   header('Content-Length: ' . filesize($file_out));

   //Write the image bytes to the client
   readfile($file_out);
}
else { // Image file not found

    header($_SERVER["SERVER_PROTOCOL"] . " 404 Not Found");

}

With this solution any type of image can be processed but it is just another option. Thanks ban-geoengineering for your contribution.

ban-geoengineering
  • 18,324
  • 27
  • 171
  • 253
  • 1
    The `fpassthru` docs page says "If you just want to dump the contents of a file to the output buffer, without first modifying it or seeking to a particular offset, you may want to use the readfile(), which saves you the fopen() call." so [`readfile`](http://php.net/manual/en/function.readfile.php) is better than `fpassthru` as it is more efficient in this case. – Edward May 08 '16 at 08:28
  • 2
    The code `header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");` can be used if the file does not exist and a notification of this in the response is required. – Edward May 08 '16 at 09:06
  • 1
    The variable `$fileOut` should contain the file name: `$fileOut = "your_file_name.png";` – metatron Nov 29 '17 at 18:27
  • @Edward and metatron, thanks for your responses. I've now updated my answer and code accordingly. – ban-geoengineering May 11 '18 at 18:20
  • Note that this requires PHP being compiled with GD (because of `getimagesize()`). – Gwyneth Llewelyn Jan 01 '19 at 18:33
  • @GwynethLlewelyn Do you know of an alternative to `getimagesize()` that doesn't require GD? – ban-geoengineering May 03 '20 at 22:04
  • 1
    @ban-geoengineering — no, I don't, and it seems that there are no viable alternatives out there on the 'net (or, if there are, Google can't find them...). It was not a 'complaint', mind you, just a note — although these days I'd guess that most PHP installations will have GD built-in, some won't, thus my note. – Gwyneth Llewelyn May 31 '20 at 22:14
4

I worked without Content-Length . maybe reason work for remote image files

// open the file in a binary mode
$name = 'https://www.example.com/image_file.jpg';
$fp = fopen($name, 'rb');

// send the right headers
header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate');
header('Expires: January 01, 2013'); // Date in the past
header('Pragma: no-cache');
header("Content-Type: image/jpg");
/* header("Content-Length: " . filesize($name)); */

// dump the picture and stop the script
fpassthru($fp);
exit;
Berk
  • 55
  • 1
  • 9
4

Very, very easy.

<?php

//could be image/jpeg or image/gif or whatever
header('Content-Type: image/png')
readfile('image.png')
?>
Blaze612 YT
  • 594
  • 7
  • 13
3

This should work. It may be slower.

$img = imagecreatefromjpeg($filename);
header("Content-Type: image/jpg");
imagejpeg($img);
imagedestroy($img);
Drew LeSueur
  • 19,185
  • 29
  • 89
  • 106
-7

Another easy Option (not any better, just different) if you aren't reading from a database is to just use a function to output all the code for you... Note: If you also wanted php to read the image dimensions and give that to the client for faster rendering, you could easily do that too with this method.

<?php
  Function insertImage( $fileName ) {
    echo '<img src="path/to/your/images/',$fileName,'">';    
  }
?>

<html>
  <body>
    This is my awesome website.<br>
    <?php insertImage( '1234.jpg' ); ?><br>
    Like my nice picture above?
  </body>
</html>
Joe Bubna
  • 296
  • 1
  • 2
  • 7
  • 1
    This "answer" would work, but **does not address this page's question stated above. Answers should always answer the original question.** – Edward May 08 '16 at 10:24
  • Imho if you want hide location of picture, put base64 encrypted source into img tag. **But this is not what he asked.** `src="data:image/png;base64,[...]"` – 3ED Feb 16 '19 at 18:06