开发者

Setting the header to be content image in CakePHP

I am writing an action in a controller where in a certain case, I want to output raw image data directly, and want to set the header content-type appropriate. However I think the header is already being set earlier by CakePHP (I am setting render to be false).

Is there a way to get around t开发者_运维问答his? Thanks!


As said before, CakePHP does not send headers when render is false. Beware though, that any code doing an 'echo' will send headers (except you are using output-buffering). This includes messages from PHP (warnings etc.).

Sending the file can be done in numerous ways, but there are two basic ways:

Send the file using plain PHP

function send_file_using_plain_php($filename) {
    // Avoids hard to understand error-messages
    if (!file_exists($filename)) {
        throw RuntimeException("File $filename not found");
    }

    $fileinfo = new finfo(FILEINFO_MIME);
    $mime_type = $fileinfo->file($filename); 
    // The function above also returns the charset, if you don't want that:
    $mime_type = reset(explode(";", $mime_type));
    // gets last element of an array

    header("Content-Type: $mime_type");
    header("Content-Length: ".filesize($filename));
    readfile($filename);
}

Use X-Sendfile and have the Webserver serve the file

// This was only tested with nginx

function send_file_using_x_sendfile($filename) {
    // Avoids hard to understand error-messages
    if (!file_exists($filename)) {
        throw RuntimeException("File $filename not found");
    }

    $fileinfo = new finfo(FILEINFO_MIME);
    $mime_type = $fileinfo->file($filename); 
    // The function above also returns the charset, if you don't want that:
    $mime_type = reset(explode(";", $mime_type));
    // gets last element of an array

    header("Content-Type: $mime_type");
    // The slash makes it absolute (to the document root of your server)
    // For apache and lighttp use:
    header("X-Sendfile: /$filename");
    // or for nginx: header("X-Accel-Redirect: /$filename");

}

The first function occupies one PHP-process / thread while the data is being send and supports no Range-Requests or other advanced HTTP-features. This should therefore only be used with small files, or on very small sites.

Using X-Sendfile you get all that, but you need to know which webserver is running and maybe even a change to the configuration is needed. Especially when using lighttp or nginx this really pays off performance-wise, because these webservers are extremly good at serving static files from disk.

Both functions support files not in the document-root of the webserver. In nginx there are so called "internal locations" (http://wiki.nginx.org/HttpCoreModule#internal). These can be used with the X-Accel-Redirect-Header. Even rate-throtteling is possible, have a look at http://wiki.nginx.org/XSendfile.

If you use apache, there is mod_xsendfile, which implements the feature needed by the second function.


It's not $this->render(false), it's $this->autoRender=false; The header is not sent in the controller action unless you echo something out.


If render is false, cake will not send a header.

You can rely on plain ol' php here.

PNG:

header('Content-Type: image/gif');
readfile('path/to/myimage.gif');

JPEG:

header('Content-Type: image/jpeg');
readfile('path/to/myimage.jpg');

PNG:

header('Content-Type: image/png');
readfile('path/to/myimage.png');
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜