システムを作っていると、お客様からよく「このデータを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ファイルが開くようになります。