11

I was wondering if there was a way for a controller to, instead of returning a string, or a view, return an image (be it JPG, PNG etc). For example, instead of ending with a $this->load->view('folder/special_view.php), I'd like to do something like $this->load->image('images/gorilla.png'), and have it so if my user were to go to that controller they would see an image as if they'd gone to a normal .png or jpeg. Can I set the headers so it expects a different MIME? Example code of this would be fantastic.

It would take forever for me to explain why I need this, but it involves bringing a premade CMS into codeigniter, and having it need certian things to be true. Thank you so much!

Ethan
  • 5,660
  • 9
  • 44
  • 51

7 Answers7

27

sure you can, use this instead of $this->load->view()

$filename="/path/to/file.jpg"; //<-- specify the image  file
if(file_exists($filename)){ 
  $mime = mime_content_type($filename); //<-- detect file type
  header('Content-Length: '.filesize($filename)); //<-- sends filesize header
  header("Content-Type: $mime"); //<-- send mime-type header
  header('Content-Disposition: inline; filename="'.$filename.'";'); //<-- sends filename header
  readfile($filename); //<--reads and outputs the file onto the output buffer
  exit(); // or die()
}
Lajos Mészáros
  • 3,756
  • 2
  • 20
  • 26
ekhaled
  • 2,930
  • 20
  • 24
12

This is not intended as One-upmanship, but pǝlɐɥʞ's suggestion is a pure PHP implementation that is not all that re-usable. You wanted to use the syntax $this->load->image('images/gorilla.png') so here is how you can.

Create /application/libraries/MY_Loader.php

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Loader Class
 *
 * Loads views and files
 *
 * @package     CodeIgniter
 * @subpackage  Libraries
 * @author      Phil Sturgeon
 * @category    Loader
 * @link        http://codeigniter.com/user_guide/libraries/loader.html
 */
class MY_Loader extends CI_Loader {

    function image($file_path, $mime_type_or_return = 'image/png')
    {
        $this->helper('file');

        $image_content = read_file($file_path);

        // Image was not found
        if($image_content === FALSE)
        {
            show_error('Image "'.$file_path.'" could not be found.');
            return FALSE;
        }

        // Return the image or output it?
        if($mime_type_or_return === TRUE)
        {
            return $image_content;
        }

        header('Content-Length: '.strlen($image_content)); // sends filesize header
        header('Content-Type: '.$mime_type_or_return); // send mime-type header
        header('Content-Disposition: inline; filename="'.basename($file_path).'";'); // sends filename header
        exit($image_content); // reads and outputs the file onto the output buffer
    }

There are a few ways you can use this:

Basic output (default is jpeg)

$this->load->image('/path/to/images/gorilla.png');

Send mime-type to use other image types

$this->load->image('/path/to/images/gorilla.jpg', 'image/jpeg');

Return the image

$image = $this->load->image('/path/to/images/gorilla.php', TRUE);

Just like $this->load->view, the 3rd parameter being set to TRUE means it will return instead of directly outputting.

Hope this helps :-)

Phil Sturgeon
  • 30,637
  • 12
  • 78
  • 117
11

An easier way with automatic mime-type.

$this->load->helper('file');

$image_path = '/path/to/image/file';

$this->output->set_content_type(get_mime_by_extension($image_path));
$this->output->set_output(file_get_contents($image_path));
Shiva127
  • 2,413
  • 1
  • 23
  • 27
1

I would do a

$computedImage = 'path/to/the/image.ext';
$this->load->helper('file');
$this->output->set_content_type(get_mime_by_extension($computedImage))->set_output(file_get_contents($computedImage));

If this helps. Cheers!

foxybagga
  • 4,184
  • 2
  • 34
  • 31
1

About the Phil's code:

In CodeIgniter 2.0, today, there are a one change that have to be made in order to make it work:

  • The library has to be in /application/core/MY_Loader.php

I like to remark a small typo about the library's explanation:

  • There is a mistake in the header "Basic output (default is jpeg)" because in fact the default is .png

Another solutions to the problem are:

I've made a small code to make it work with the core codeIgniter libraries:

    $this->output->set_header("Content-Type: image/png");
    $this->load->file('../images/example.png');

Or using the Image Manipulation Library

    $config['image_library'] = "GD2";
    $config['source_image'] = "../images/example.png";
    $config['maintain_ratio'] = TRUE;
    $config['dynamic_output'] = TRUE;

    $this->load->library('image_lib', $config);
    $image = $this->image_lib->resize();

In both cases you get the same image you get from the source but in the output.

But for me, I liked more the extension to the core library :-)

Thank you very much Phil.

  • I never noticed the generic file loader. I was going through the code of CodeIgniter... Thanks for pointing this out.. Using the best of codeigniter... :) –  Sep 24 '11 at 23:20
  • Well one more thing which I noted was internally the load function calls the include function... as per the php manual one should use include if its used for processing... instead readfile function should be used... so we can use the readfile function provided in File helper! –  Sep 25 '11 at 03:11
1

This method works even if you have $config['compress_output'] set to TRUE

$filename="/path/to/file.jpg"; //<-- specify the image  file
if(file_exists($filename)){ 
  header('Content-Length: '.filesize($filename])); //<-- sends filesize header
  header('Content-Type: image/jpg'); //<-- send mime-type header
  header('Content-Disposition: inline; filename="'.$filename.'";'); //<-- sends filename     header
  $jpg = file_get_contents($filename); 
  $this->output->set_output($jpg);
}
JohnWright
  • 248
  • 1
  • 7
1

If it fits your use case, simply redirecting to it is just fine. For example, tracking using images would be like:

// Do your logic here

redirect($image_path); // Or PHP's header location function

No need to change headers. Your use case may not fit this, but someone might find this useful ^_^

Ryan Thompson
  • 458
  • 5
  • 15