Posted on

PHPExcelをCakePHPで使ってみる

 システムを作っていると、お客様からよく「このデータをExcelで使いたい」ということをお聞きします。
 大抵の場合CSV形式のファイルを出力して、それをExcelで読み込んで好きに加工して戴くのですが、やはりExcelの形式ではないので使い辛いと言われることがあります。
 そこで、Excelファイルを出力するようにしようということになり、PHPExcelというライブラリをCakePHPに組み込んで使うことにしました。


 出力するExcelのバージョンはExcel95(拡張子 .xls)とし、PHPExcelはVendorライクに使います。
 なるべくMVCモデルになるように、コントローラで必要なデータを取得して、ビューでファイル出力を行います。
 まず、PHPExcelライブラリ一式をVendor用のフォルダに配置します。

  \cakephp\app\vendors/phpexcel\PHPExcel.php
  \cakephp\app\vendors\phpexcel\PHPExcel\ (その他のファイル全部)

 コントローラで、PDF 出力ボタンを押したアクションを記述し、そこで必要なデータを取得・保存し、それ以外にシート名とファイル名を決めてビューに渡せるようにします。

class ExcelsController extends AppController {
var $name = 'Excels';
var $uses = array( 'Fruit' );
var $layout = 'default';
function fruits_view() {
$this->layout = false;			// レイアウトは使わない
// 送信データ
$data = $this->Fruit->getFruitAll();
$this->set( "data", $data );
// シート名
$this->set( "sheet_name", "Fruits" );
// 保存ファイル名
$filename = "fruits.xls";
$this->set( "filename", $filename );
}

 コントローラのアクションと同じ名前のビューを作ります。
 コントローラ名が excels_controller.php で、アクション名が fruits_view なので、ビューファイルは
\cakephp\app\views\excels\fruits_view.php
 です。

PHPExcelのライブラリを読み込みます。

// Excel出力用ライブラリ
App::import( 'Vendor', 'PHPExcel', array('file'=>'phpexcel' . DS . 'PHPExcel.php') );
App::import( 'Vendor', 'PHPExcel_IOFactory', array('file'=>'phpexcel' . DS . 'PHPExcel' . DS . 'IOFactory.php') );
App::import( 'Vendor', 'PHPExcel_Cell_AdvancedValueBinder', array('file'=>'phpexcel' . DS . 'PHPExcel' . DS . 'Cell' . DS . 'AdvancedValueBinder.php') );
// Excel95用ライブラリ
App::import( 'Vendor', 'PHPExcel_Writer_Excel5', array('file'=>'phpexcel' . DS . 'PHPExcel' . DS . 'Writer' . DS . 'Excel5.php') );
App::import( 'Vendor', 'PHPExcel_Reader_Excel5', array('file'=>'phpexcel' . DS . 'PHPExcel' . DS . 'Reader' . DS . 'Excel5.php') );

 Excelのオブジェクトを生成し、最初のシートをアクティブにしてデータを出力します。
サンプルとしていろいろなメソッドを使ったコードを載せておきますので、詳しくはPHPExcelのマニュアルをご参照ください。
 但し、全部英語です。

// Excelファイルの生成 ------------------------------------------
// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
// Set active sheet index to the first sheet, so Excel opens this as the first sheet
$objPHPExcel->setActiveSheetIndex( 0 );
$sheet = $objPHPExcel->getActiveSheet();
// Rename sheet
// シート名をつける
$sheet->setTitle( $sheet_name );
// デフォルトのフォント
$sheet->getDefaultStyle()->getFont()->setName('MS Pゴシック');
// デフォルトのフォントサイズ
$sheet->getDefaultStyle()->getFont()->setSize(11);
// デフォルトの列幅指定
$sheet->getDefaultColumnDimension()->setWidth(12);
// デフォルトの行の高さ指定
$sheet->getDefaultRowDimension()->setRowHeight(18);
// 列の幅指定
$sheet->getColumnDimension( 'A' )->setWidth(12);
$sheet->getColumnDimension( 'B' )->setWidth(30);
$sheet->getColumnDimension( 'C' )->setWidth(12);
// 列名
$row_cnt = 1;
//	$sheet->setCellValueByColumnAndRow( 0, $row_cnt, "ID" );
$cell_pos = 'A' . $row_cnt;
// セルの値を入力
$sheet->setCellValue( $cell_pos, "ID" );
// 周りを罫線で囲む
$sheet->getStyle( $cell_pos )->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
// 文字色を指定(赤)
$sheet->getStyle( $cell_pos )->getFont()->getColor()->setARGB(PHPExcel_Style_Color::COLOR_RED);
// ボールド指定
$sheet->getStyle( $cell_pos )->getFont()->setBold(true);
// フォントサイズの指定
$sheet->getStyle( $cell_pos )->getFont()->setSize(15);
// 背景色の指定(塗りつぶし)
$sheet->getStyle( $cell_pos )->getFill()->setFillType( PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('FF0000FF');
// 縦方向の位置指定(中央)
$sheet->getStyle( $cell_pos )->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
// 横方向の位置指定(中央)
$sheet->getStyle( $cell_pos )->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
//	$sheet->setCellValueByColumnAndRow( 1, $row_cnt, "名前" );
$cell_pos = 'B' . $row_cnt;
$sheet->setCellValue( $cell_pos, "名前" );
$sheet->getStyle( $cell_pos )->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
$sheet->getStyle( $cell_pos )->getFont()->getColor()->setARGB(PHPExcel_Style_Color::COLOR_BLUE);
$sheet->getStyle( $cell_pos )->getFont()->setBold(true);
$sheet->getStyle( $cell_pos )->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
$cell_pos = 'C' . $row_cnt;
$sheet->setCellValue( $cell_pos, "数量" );
$sheet->getStyle( $cell_pos )->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
$sheet->getStyle( $cell_pos )->getFont()->getColor()->setARGB(PHPExcel_Style_Color::COLOR_GREEN);
$sheet->getStyle( $cell_pos )->getFont()->setBold(true);
$sheet->getStyle( $cell_pos )->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
// PHPの日時出力
$cell_pos = 'E' . $row_cnt;
$time = time();					// 現在日時(Unix Timestamp)
$sheet->setCellValue( $cell_pos, PHPExcel_Shared_Date::PHPToExcel( $time ) );
$sheet->getStyle( $cell_pos )->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDDSLASH);
// DBから取ってきたような日付の文字列(年月日のみ)
$cell_pos = 'E2';
PHPExcel_Cell::setValueBinder( new PHPExcel_Cell_AdvancedValueBinder() );
$sheet->setCellValue( $cell_pos, '2010/5/10' );
$sheet->getStyle( $cell_pos )->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDDSLASH);
// 行の高さを指定
$sheet->getRowDimension( $row_cnt )->setRowHeight( 50 );
// データ
$row_cnt = 2;
foreach( $data as $id => $name ){
// 行の高さ指定
$sheet->getRowDimension( $row_cnt )->setRowHeight( 20 );
// ID
$cell_pos = 'A' . $row_cnt;
$sheet->setCellValue( $cell_pos, $id );
$sheet->getStyle( $cell_pos )->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
$sheet->getStyle( $cell_pos )->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
/*
// セルを( x, y )で指定した場合の例は下記
$sheet->setCellValueByColumnAndRow( 0, $row_cnt, $id );
$sheet->getStyleByColumnAndRow( 0, $row_cnt )->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
$sheet->getStyleByColumnAndRow( 0, $row_cnt )->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
*/
// 名前
$cell_pos = 'B' . $row_cnt;
$sheet->setCellValue( $cell_pos, $name );
$sheet->getStyle( $cell_pos )->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
// 数量
$cell_pos = 'C' . $row_cnt;
$sheet->setCellValue( $cell_pos, 1000 );
$sheet->getStyle( $cell_pos )->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
// 数字のフォーマット指定
if( $row_cnt % 2 == 0 ){
// カンマ区切り
$sheet->getStyle( $cell_pos )->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1);
} else {
// 小数点以下の桁数指定
$sheet->getStyle( $cell_pos )->getNumberFormat()->setFormatCode( "#,##0.00" );
}
$row_cnt++;
}
// 全体を太い線で囲む
$start_cell = "A1";
$end_cell = "C" . ($row_cnt-1);
$cell_range = "{$start_cell}:{$end_cell}";			// セルの範囲指定
$sheet->getStyle( $cell_range )->getBorders()->getOutline()->setBorderStyle(PHPExcel_Style_Border::BORDER_MEDIUM);

 ファイルを一時フォルダに出力し、内容をクライアントに送信します。

// Excelファイルの保存 ------------------------------------------
// 保存ファイルフルパス
$uploadDir = realpath( TMP );
$uploadDir .= DS . 'excels' . DS;
$path = $uploadDir . $filename;
$objWriter = new PHPExcel_Writer_Excel5( $objPHPExcel );
$objWriter->save( $path );
// Excelファイルをクライアントに出力 ----------------------------
Configure::write('debug', 0); 		// debugコードを非表示
header("Content-disposition: attachment; filename={$filename}");
header("Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; name={$filename}");
$result = file_get_contents( $path );	// ダウンロードするデータの取得
print( $result ); 						// 出力

 これで、「Excel出力」ボタンを押して、ブラウザの別タブ(または別ウィンドウ)で生成したExcelファイルが開くようになります。