50
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

【CakePHP】ファイルダウンロード

ファイルを作成してダウンロードする方法と、ファイルを作成せずにダウンロードする方法がある。

「ファイル作成してダウンロード」は、既に用意されているファイルをダウンロードする場合や、PDFやエクセルなどを一旦編集してダウンロードする場合に適していると思う。

「ファイルを作成せずにダウンロード」は、CSVなどテキスト系のファイルのダウンロードに適していると思う。

※CakePHPのバージョン2.3以降

ファイルを作成してダウンロード

$this->autoRender = false;

$this->response->file(
  //ファイルパス
  APP.'webroot/files/foo.csv',
  [
    //ダウンロードしたときのファイル名。省略すれば元のファイル名。
    'name'=>'bar.csv',
    //これは必須
    'download'=>true,
  ]
);

ファイルを作成せずにダウンロード(Viewを使う)

//レイアウトを使用しない
$this->layout = false;

//ファイルの種類によってContent-Typeを指定 後述するFirefoxのため。
$this->response->type('csv');

//ダウンロードするファイル名を指定
//downloadメソッドの中で、「Content-Disposition: attachment; filename=ファイル名」を設定している。
$this->response->download('bar.csv');

//Viewでファイル内容をレンダリングする
$this->set(['data'=>$data]);

ファイルを作成せずにダウンロード(Viewを使わない)

//Viewを使用しない
$this->autoRender = false;

//ファイルの種類によってContent-Typeを指定 後述するFirefoxのため。
$this->response->type('csv');

//ダウンロードするファイル名を指定
//downloadメソッドの中で、「Content-Disposition: attachment; filename=ファイル名」を設定している。
$this->response->download('bar.csv');

//レスポンスに設定
$this->response->body('ファイルの内容');

ついでにダウンロードの基礎知識

間違いや補足などありましたらご指摘いただけるとありがたいです。

ブラウザでダウンロードさせたい場合、HTTPヘッダのContent-Dispositionをattachmentとすれば良い。inlineとすれば、画面に表示される。PHPで書くと以下のようになる。

php
header('Content-Disposition: attachment; filename=bar.csv');

参考
既知の MIME タイプに対し [ファイルのダウンロード] ダイアログ ボックスを開く

Chrome、IE、Firefox、Operaの最新版で試したところContent-Dispositionのみでjpgファイルをダウンロードできた。

ただし、IEの過去バージョン(IE 6など)ではContent-Dispositionのみではダウンロードされない場合があるとのこと。
cakeの$this->response->fileの中を読むと、Operaの場合Content-typeに「application/octet-stream」を、IEの場合Content-typeに「application/force-download」を設定している。
もしもブラウザのバージョンによって、「ファイルを作成せずにダウンロード」のやり方でダウンロードされない場合はこのあたりが怪しいかもしれない。

また、Firefoxではダウンロード時に表示も選択することができるが、その際にContent-Typeを参照しているので、Content-Typeも設定したほうが良いかもしれない。そのため、「ファイルを作成せずにダウンロード」ではContent-Typeを設定している。

多くのPHPのダウンロードのサンプルでは、Content-Typeに「application/octet-stream」もしくは、「application/force-download」を設定すればダウンロードされるとあり実際うまくいくが、これはブラウザが想定しないMIMEのためダウンロードされる仕組みを利用したもので、Content-Disposition: attachmentを使うのがいいのではないかと思う。(このあたりは自信ないのでご指摘頂けるとありがたいです。)

※さらについでにContent-Typeの説明

Content-Type: text/html; charset=UTF-8

Content-Typeはファイルの種類をブラウザに示すもの。
Content-Typeは、サーバ側で設定することも可能。例えばPHPでは以下のようにする。

php
header('Content-Type: image/png');

また、Apacheの設定で拡張子を見てContent-Typeを設定することも可能。
例)pdf拡張子の場合、Content-Typeをapplication/pdfにする。

apache
AddType application/pdf .pdf

Content-Typeの代表的なもので以下がある。
text/html(HTMLテキスト)
image/jpeg(jpeg画像)

また、charset=UTF-8で文字コードを表している。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
50
Help us understand the problem. What are the problem?