Welcome Guest, Not a member yet? Register   Sign In
Serving an Image with HTTP Headers; white space bug. [SOLVED]
#1

[eluser]Ian Jones[/eluser]
I've spent maybe 8+ hours on this one problem, starting to not see the light at the end of the tunnel anymore! I would greatly appreciate any help.

I have an image uploads folder below PUBLIC_HTML web root, for the sake of security. I want to retrieve an image from this, to display in a view. Actually to make it even simpler I just want the browser to receive the correct HTTP headers, and the image bytes. But it doesn't work! Why? because there is a single leading whitespace at the start of the image bytes whenever I try to output from my controller. Here's my setup:

Code:
<?php
class Images extends Controller
{
    function Images()
    {
        parent::Controller();
    }
    
    function _remap()
    {
        if($filename = $this->uri->segment(2))
        {
            //$config['uri_protocol']  = "REQUEST_URI"; adjusted to remove a php problem where the filename . was being converted to a _
        
            $image = APPPATH . 'users/uploads/' . $filename;
            
            header('Content-Type: ' . get_mime_by_extension($image));
            header('Accept-Ranges: bytes');
            header('Content-Length: ' . filesize($image));
            //header('Content-Disposition: attachment; filename="'.$filename.'"');
            file_get_contents($image);
        }
    }
}
?>

I have no idea where the whitespace is coming from, but if I uncomment the 'attachment' header and download the file, I can simply remove the whitespace with TextEdit (OsX) and the image is fine!

How on earth do I track down the stray white space?
#2

[eluser]n0xie[/eluser]
Did you try removing the closing php tag?
#3

[eluser]Ian Jones[/eluser]
Thank you so much for your reply, yes I have tried that.

Sorry I should mention the solutions I've tried:

First and foremost, the path and access to the image files is verified and valid.

1) There are no whitespaces in this file
2) I have tried removing the php close tag '?>'
3) I've even looked at the default controller, no whitespaces there either
4) I turned off all logging in CodeIgniter, just incase something was echo'ing
5) I've tried using 'readfile()' instead of 'file_get_contents()'
6) I've tried using '$this->output->set_headers()' and '$this->output->set_output($data)'
7) I'm fairly sure its not a Byte Order Marker problem, because when I output the file contents to the browser I can't see the telltale characters.
#4

[eluser]n0xie[/eluser]
This is how we pass images through a controller although I doubt there is anything wrong with your code.

Code:
function img()
    {

        $img = fopen(site_url('public/img/someimage.gif'), 'r');
        if ($img)
        {
            header('Content-Type: image/gif');
            fpassthru($img);
        }
        }
#5

[eluser]Ian Jones[/eluser]
Sadly, although that also looks like it should work. I still get a single white space from the output buffer. Maybe there is a way to clear the output buffer... hmm
#6

[eluser]Ian Jones[/eluser]
Woo! Solved it!

I used: ob_clean() right before I call the headers and it works!

This means for sure that somewhere in CI or my code there was a stray whitespace being sent to the output buffer. Not sure I am worried if it's still there, but may be able to track it down.

Thanks for your help N0xie. A fresh pair of eyes helps kickstart new ideas.
#7

[eluser]Ian Jones[/eluser]
Here's the solution for reference:

Code:
<?php
class Images extends Controller
{
    function Images()
    {
        parent::Controller();
    }
    
    function _remap()
    {
        if($filename = $this->uri->segment(2))
        {
            //$config['uri_protocol' = "REQUEST_URI"; adjusted to remove a php problem where the filename . was being converted to a _
        
            $image = APPPATH . 'users/uploads/' . $filename;
            
            ob_clean();
            header('Content-Type: ' . get_mime_by_extension($image));
            header('Content-Length: ' . filesize($image));
            header('Content-Disposition: inline; filename="'."foo.jpg".'"');
            readfile($image);
        }
    }
}
?>

This works as N0xie suggested, also with fopen() and fpassthru(), although I adapted for the simpler readfile().

You can change 'inline' to 'attachment' to force download, and replace 'foo.jpg' to force a custom filename! (this is great for hiding the real image name, and making the downloadable image semantic / tagged usefully.
#8

[eluser]n0xie[/eluser]
[quote author="Ian Jones" date="1263405516"]Thanks for your help N0xie[/quote]
No problem, although I am rather curious where the whitespace comes from. I hope it didn't slip into the latest CI SVN... 8-/
#9

[eluser]Ian Jones[/eluser]
So am I, if I track it down I'll be sure to post. It is probably something I have done in my slightly unusual config.




Theme © iAndrew 2016 - Forum software by © MyBB