72

I have an image $file ( eg ../image.jpg )

which has a mime type $type

How can I output it to the browser?

Shaiful Islam
  • 6,448
  • 12
  • 35
  • 54
steven
  • 11,401
  • 14
  • 35
  • 39

12 Answers12

144
$file = '../image.jpg';
$type = 'image/jpeg';
header('Content-Type:'.$type);
header('Content-Length: ' . filesize($file));
readfile($file);
Emre Yazici
  • 9,708
  • 6
  • 46
  • 54
  • 16
    PHP and/or the server will take care of the content-length for you. – Matthew Scharley Dec 05 '09 at 10:48
  • 1
    The content length header for convenience. – Emre Yazici Dec 05 '09 at 10:51
  • 2
    For some reason filesize failed for me when trying to access the image by absolute path, so I commented that line and the code is working fine. – kiranvj Mar 30 '13 at 12:59
  • 16
    It's better to avoid putting Content-Length especially if you have GZip enabled on your webserver, because you'll be telling the browser to expect more bytes than actually arrive, and it will wait to time out. This can have bad consequences if e.g. you have JS waiting for the event. – Coder May 23 '14 at 14:10
  • Make sure Type in "Content-Type" is capitalized. I just ran into this where it was "Content-type" and it resulted in a bunch of gibberish – AllisonC Jun 21 '17 at 12:07
32

If you have the liberty to configure your webserver yourself, tools like mod_xsendfile (for Apache) are considerably better than reading and printing the file in PHP. Your PHP code would look like this:

header("Content-type: $type");
header("X-Sendfile: $file"); # make sure $file is the full path, not relative
exit();

mod_xsendfile picks up the X-Sendfile header and sends the file to the browser itself. This can make a real difference in performance, especially for big files. Most of the proposed solutions read the whole file into memory and then print it out. That's OK for a 20kbyte image file, but if you have a 200 MByte TIFF file, you're bound to get problems.

Benjamin Wohlwend
  • 28,402
  • 10
  • 83
  • 95
  • interesting comment about file size and potential memory problems due to reading it all in – Ian Feb 08 '11 at 22:07
27
$file = '../image.jpg';

if (file_exists($file))
{
    $size = getimagesize($file);

    $fp = fopen($file, 'rb');

    if ($size and $fp)
    {
        // Optional never cache
    //  header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate');
    //  header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
    //  header('Pragma: no-cache');

        // Optional cache if not changed
    //  header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($file)).' GMT');

        // Optional send not modified
    //  if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) and 
    //      filemtime($file) == strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']))
    //  {
    //      header('HTTP/1.1 304 Not Modified');
    //  }

        header('Content-Type: '.$size['mime']);
        header('Content-Length: '.filesize($file));

        fpassthru($fp);

        exit;
    }
}

http://php.net/manual/en/function.fpassthru.php

Mike
  • 1,597
  • 3
  • 21
  • 16
  • @Michael [via php.net](http://php.net/manual/de/function.getimagesize.php) _The getimagesize() function will determine the size of any given image file and return the dimensions along with the file type and a height/width text string to be used inside a normal HTML IMG tag and the correspondent HTTP content type._ – ReynekeVosz Mar 22 '16 at 08:20
4

Try this:

<?php
  header("Content-type: image/jpeg");
  readfile("/path/to/image.jpg");
  exit(0);
?>
Carlos Lima
  • 4,012
  • 27
  • 31
3
header('Content-type: image/jpeg');
readfile($image);
code_burgar
  • 11,153
  • 4
  • 32
  • 52
3

For the next guy or gal hitting this problem, here's what worked for me:

ob_start();
header('Content-Type: '.$mimetype);
ob_end_clean();
$fp = fopen($fullyQualifiedFilepath, 'rb');
fpassthru($fp);
exit;

You need all of that, and only that. If your mimetype varies, have a look at PHP's mime_content_type($filepath)

Hans
  • 51
  • 3
2

(Expanding on the accepted answer...)

I needed to:

  1. log views of a jpg image and an animated gif, and,
  2. ensure that the images are never cached (so every view is logged), and,
  3. also retain the original file extensions.

I accomplished this by creating a "secondary" .htaccess file in the sub-folder where the images are located.
The file contains only one line:

AddHandler application/x-httpd-lsphp .jpg .jpeg .gif

In the same folder, I placed the two 'original' image files (we'll call them orig.jpg and orig.gif), as well as two variations of the [simplified] script below (saved as myimage.jpg and myimage.gif)...

<?php 
  error_reporting(0); //hide errors (displaying one would break the image)

  //get user IP and the pseudo-image's URL
  if(isset($_SERVER['REMOTE_ADDR'])) {$ip =$_SERVER['REMOTE_ADDR'];}else{$ip= '(unknown)';}
  if(isset($_SERVER['REQUEST_URI'])) {$url=$_SERVER['REQUEST_URI'];}else{$url='(unknown)';}

  //log the visit
  require_once('connect.php');            //file with db connection info
  $conn = new mysqli($servername, $username, $password, $dbname);
  if (!$conn->connect_error) {         //if connected then save mySQL record
   $conn->query("INSERT INTO imageclicks (image, ip) VALUES ('$url', '$ip');");
     $conn->close();  //(datetime is auto-added to table with default of 'now')
  } 

  //display the image
  $imgfile='orig.jpg';                             // or 'orig.gif'
  header('Content-Type: image/jpeg');              // or 'image/gif'
  header('Content-Length: '.filesize($imgfile));
  header('Cache-Control: no-cache');
  readfile($imgfile);
?>

The images render (or animate) normally and can be called in any of the normal ways for images (like an <img> tag), and will save a record of the visiting IP, while invisible to the user.

ashleedawg
  • 17,207
  • 5
  • 53
  • 80
1
    $file = '../image.jpg';
    $type = 'image/jpeg';
    header('Content-Type:'.$type);
    header('Content-Length: ' . filesize($file));
    $img = file_get_contents($file);
    echo $img;

This is works for me! I have test it on code igniter. if i use readfile, the image won't display. Sometimes only display jpg, sometimes only big file. But after i changed it to "file_get_contents" , I get the flavour, and works!! this is the screenshoot: Screenshot of "secure image" from database

0
<?php

header("Content-Type: $type");
readfile($file);

That's the short version. There's a few extra little things you can do to make things nicer, but that'll work for you.

Matthew Scharley
  • 115,776
  • 51
  • 189
  • 215
0

You can use header to send the right Content-type :

header('Content-Type: ' . $type);

And readfile to output the content of the image :

readfile($file);


And maybe (probably not necessary, but, just in case) you'll have to send the Content-Length header too :

header('Content-Length: ' . filesize($file));


Note : make sure you don't output anything else than your image data (no white space, for instance), or it will no longer be a valid image.

Pascal MARTIN
  • 374,560
  • 73
  • 631
  • 650
0

You can use finfo (PHP 5.3+) to get the right MIME type.

$filePath = 'YOUR_FILE.XYZ';
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$contentType = finfo_file($finfo, $filePath);
finfo_close($finfo);

header('Content-Type: ' . $contentType);
readfile($filePath);

PS: You don't have to specify Content-Length, Apache will do it for you.

Fabien Sa
  • 7,626
  • 2
  • 35
  • 40
0
header("Content-type: image/png"); 
echo file_get_contents(".../image.png");

The first step is retrieve the image from a particular location and then store it on to a variable for that purpose we use the function file_get_contents() with the destination as the parameter. Next we set the content type of the output page as image type using the header file. Finally we print the retrieved file using echo.

Community
  • 1
  • 1
Randomhex
  • 11
  • 1
  • 4
    Hi there and welcome to Stack Overflow! Would you mind updating your answer with some explanation of why your solution works? Could you also remove the quotes from around your answer, as that's making the syntax-highlighter treat it all as a string literal. Thanks! – Michael Cordingley Apr 30 '19 at 18:41
  • Please share some explanation. For example, why did you set `Content-type: image/png` for outputting a JPG image? Also, why read the whole file into a variable? Shouldn't `readfile` have a much better memory performance? – Nico Haase Nov 17 '20 at 13:49