
CakePHP 1.3.xで CSVファイルのエクスポート機能を作ってみた
2015/01/11
過去に CakePHP1.3 で作成したシステムにCSVファイルのエクスポート機能を追加してほしいときたので、機能追加してみました。
忘備録も兼ねたポストで次回に備えたいと思います。
『CSV Helper』でCSVを作成する
今回は CakePHPのバージョンが 1.3.22だったので、ヘルパーである『CSV Helper』を使ってみたいと思います。
ダウンロードというか、公開されているページはこちら。
CSV Helper (PHP 5) :: The Bakery: Everything CakePHP
CsvHelper
公開されているものを転載します。
最後の「?>」は要らないので、書きません。
[php]
clear();
}
function clear() {
$this->line = array();
$this->buffer = fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+');
}
function addField($value) {
$this->line[] = $value;
}
function endRow() {
$this->addRow($this->line);
$this->line = array();
}
function addRow($row) {
fputcsv($this->buffer, $row, $this->delimiter, $this->enclosure);
}
function renderHeaders() {
header("Content-type:application/vnd.ms-excel");
header("Content-disposition:attachment;filename=".$this->filename);
}
function setFilename($filename) {
$this->filename = $filename;
if (strtolower(substr($this->filename, -4)) != '.csv') {
$this->filename .= '.csv';
}
}
function render($outputHeaders = true, $to_encoding = null, $from_encoding = "auto") {
if ($outputHeaders) {
if (is_string($outputHeaders)) {
$this->setFilename($outputHeaders);
}
$this->renderHeaders();
}
rewind($this->buffer);
$output = stream_get_contents($this->buffer);
if ($to_encoding) {
$output = mb_convert_encoding($output, $to_encoding, $from_encoding);
}
return $this->output($output);
}
}
[/php]
アクションを作成
ダウンロード機能を実装するコントローラーに、ダウンロード用アクションを作成します。
そのまんま、download としてみました。
ヘルパー設定に「Csv」を記述するのを忘れずに。
サンプルのアクションは、都道府県と、欲しいデータ(ユーザ)の一覧を取得しています。
抽出したデータと、表の一行目の配列をセットしてビューに渡します。
app/controllers/users_controller.php
[php]
class UsersController extends AppController
{
// Model
var $uses = array('User');
// Helper
var $helpers = array('Html', 'Form', 'Csv');
public function download()
{
// 都道府県取得
$_prefs_master = $this->Prefecture->find( 'all',
array(
'conditions' => null,
'fields' => null,
'order' => array('Prefecture.id' => 'ASC'),
'recursive' => -1
)
);
$prefs_master = Set::combine($_prefs_master, '{n}.Prefecture.id', '{n}.Prefecture.name');
// ユーザデータ抽出
$users = $this->User->find( 'all',
array(
'conditions' => $conditions,
'fields' => null,
'order' => $order,
'recursive' => -1,
)
);
// 警告を出さない
Configure::write('debug', 0);
// レイアウトなし
$this->layout = '';
// 表の一行目を作成
$head = array('ID', '氏名', '登録日時', '電話番号', '都道府県', '市区町村', '以下住所');
// 任意のファイル名
$filename = 'UserList_' . date('Ymd_His');
// 出力
$this->set(compact('users', 'filename', 'head', 'prefs_master'));
}
}
[/php]
ビューファイル
最後にビューファイルの作成です。
app/views/download.ctp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/** * CSV書き出し用ビューファイル * */ $csv->addRow($head); // 一行目データ // controllerから渡されたデータを追加 foreach ( $users as $val ) { $csv->addRow(); $csv->addField($val['User']['id']); // ID $csv->addField($val['User']['name']); // 氏名 $csv->addField($val['User']['first_create']); // 登録日時 $csv->addField($val['User']['telephone']); // 電話番号 $csv->addField($prefs_master[$val['User']['prefecture']]); // 都道府県 $csv->addField($val['User']['city']); // 市区町村 $csv->addField($val['User']['address']); // 以下住所 $csv->endRow(); } // ファイル名設定 $csv->setFilename( $filename ); // 文字コードをUTF-8からSJISに変換して出力。 echo $csv->render(true, 'sjis', 'utf-8'); |
コントローラーから渡されたデータを foreach() でグリグリと回しているだけです。
基本的に、CakePHPで作成したアプリケーションの文字コードはUTF-8だと思いますので、csvにする時に、sjisに変換しています。
機種依存文字などが含まれる場合は、sjis-win あたりがの方が良いかと思います。
これで、http://your-domain.com/users/download にアクセスすれば、設定したファイル名のCSVファイルをダウンロードします。
余談
本当は、この機能を管理画面(/admin/users/download)で使いたかったのですが、プレフィックスルーティンで管理画面を制御していたために、コントローラー側でレイアウトを無効としても、無効にならず、管理画面用のレイアウトファイルをcsvファイルとして出力するという事態に陥ってしまい、1時間ほど「あーでもないこーでもない」とやってました。
社内に置いてあるローカルサーバでしか運用しないので、(管理画面内ではなく)フロント側のURLとしても問題なかったのですが、プレフィックスルーティンを使っている場合、(ダウンロード機能の場合だけはプレフィックスルーティンを)無効にする、といった手段を講じる必要がありそうです。
とりあえずこれは未来の私へのメッセージ。
絶対に同じことで悩んでそうなので(苦笑)
CakePHP2.x系統での場合もまた記事にしたいと思います。