10

the same work can be done by follow code:

header('Content-Type:image/jpeg');
readfile('a.jpg');

but now I really confused by Yii2's \yii\web\Response.


What I confused is like that:

  1. create a controller and action to provide picture

    See below

    class ServerController extends \yii\web\Controller
    {
        public function actionIndex($name)
        {
            // how to response
        }
    }
    
  2. access http://example.com/index.php?r=server/index&name=foo.jpg

thanks for the answer!

Muhammad Omer Aslam
  • 22,976
  • 9
  • 42
  • 68
haoliang
  • 655
  • 2
  • 8
  • 21

5 Answers5

20

Finally, I did it by follow codes:

$response = Yii::$app->getResponse();
$response->headers->set('Content-Type', 'image/jpeg');
$response->format = Response::FORMAT_RAW;
if ( !is_resource($response->stream = fopen($imgFullPath, 'r')) ) {
   throw new \yii\web\ServerErrorHttpException('file access failed: permission deny');
}
return $response->send();
haoliang
  • 655
  • 2
  • 8
  • 21
  • I've tried your solution. Seems to work! Shoudn't the resource gets closed somehow? – robsch Feb 06 '15 at 11:40
  • I have no idea about closing resource connection. Could you tell me the way if you already found it ? – haoliang Mar 04 '15 at 02:02
  • 1
    Usually, one should call fclose() to release a resource. But I think this is done automatically (http://stackoverflow.com/questions/12143343/does-php-close-the-file-after-the-file-handler-is-garbage-collected). So your solution seems to be okay, I guess. – robsch Mar 04 '15 at 07:13
  • This should be the accepted answer. When I was wondering the same question, the fact I was looking for was $response->format = Response::FORMAT_RAW. – Navarr Jul 22 '15 at 13:13
9

Yii2 already has built-in function for sending files. This way you do not need to set response format and content type will be detected automatically (you can override it if you wish):

function actionDownload()
{
    $imgFullPath = 'picture.jpg';
    return Yii::$app->response->sendFile($imgFullPath);
}

..

If the file is only temporary created for current download action you can use AFTER_SEND event to delete the file:

function actionDownload()
{
    $imgFullPath = 'picture.jpg';
    return Yii::$app->response
        ->sendFile($imgFullPath)
        ->on(\yii\web\Response::EVENT_AFTER_SEND, function($event) {
            unlink($event->data);
        }, $imgFullPath);
}
Igor Jerosimić
  • 13,621
  • 6
  • 44
  • 53
6

in yii2 you can return a response object from class yii\web\Response in action. so you can return a own response.

for example display image in yii2 :

public function actionIndex() {
    \Yii::$app->response->format = yii\web\Response::FORMAT_RAW;
    \Yii::$app->response->headers->add('content-type','image/png');
    \Yii::$app->response->data = file_get_contents('file.png');
    return \Yii::$app->response;
}

FORMAT_RAW: the data will be treated as the response content without any conversion. No extra HTTP header will be added.

Max Maximov
  • 123
  • 2
  • 12
Think Big
  • 1,021
  • 14
  • 24
4

I do it like this. I have added another function just for setting the headers. You can move this function in a helper too:

$this->setHttpHeaders('csv', 'filename', 'text/plain');

/**
 * Sets the HTTP headers needed by file download action.
 */
protected function setHttpHeaders($type, $name, $mime, $encoding = 'utf-8')
{
    Yii::$app->response->format = Response::FORMAT_RAW;
    if (strstr($_SERVER["HTTP_USER_AGENT"], "MSIE") == false) {
        header("Cache-Control: no-cache");
        header("Pragma: no-cache");
    } else {
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Pragma: public");
    }
    header("Expires: Sat, 26 Jul 1979 05:00:00 GMT");
    header("Content-Encoding: {$encoding}");
    header("Content-Type: {$mime}; charset={$encoding}");
    header("Content-Disposition: attachment; filename={$name}.{$type}");
    header("Cache-Control: max-age=0");
}

I also found how yii2 does it, take a look here (scroll to the bottom) https://github.com/yiisoft/yii2/blob/48ec791e4aca792435ef1fdce80ee7f6ef365c5c/framework/captcha/CaptchaAction.php

Mihai P.
  • 9,307
  • 3
  • 38
  • 49
3

The Yii2 way:

Yii::$app->response->setDownloadHeaders($filename);
Latikov Dmitry
  • 956
  • 5
  • 8