PHPでのCSV出力について

こんにちは、中川です。

今日は、PHPでのCSV出力について書いてみようと思います。

CSV出力といえば、カンマ区切りの1行ずつのデータで出力すれば・・・と、簡単なイメージもありますが、実はいろいろと細かい対策が必要な処理のひとつです。

■データ内の改行
データ内に改行文字がある場合、そのデータは「"」(ダブルクォーテーション)で囲う。

(例)


1,"TEST
TEST",HOGE
2,TEST,HOGE

■データ内に「"」が含まれる
「"」(ダブルクォーテーション)の前に「"」を付ける + ダブルクォーテーションでデータを囲う。

(例)


1,TEST,"あああ""いいい""ううう",aaa
2,TEST,これは引用なし,bbb

■CSVファイルの文字コード
Excelで開く場合、文字コードがUTF-8等では文字化けしてしまいます。
だったら、sjisにすればよいかと思われるかもしれませんが、
(株)などの機種依存文字などが含まれている場合に問題になりますので、
「sjis-win」として出力してあげましょう。

■ダウンロード
ダウンロードダイアログを表示させて保存できるようにヘッダーを出力


header('Content-Type', 'application/octet-stream');
header('Content-Disposition', 'attachment; filename="'.$filename.'"');

こんな感じでしょうか。(探せば色々なヘッダーが出てきますね。。。)

■数字形式のデータの扱い


1,NAKAGAWA,09012345678
2,YOSHIKI,"09012345678"

このような、電話番号などの先頭に「0」がつく数字形式のデータをそのままCSV出力してしまうと、引用符で囲わなくても囲っても、エクセルで開いた場合、以下のように先頭の「0」がなくなってしまいます。

エクセルのファイルを読み込んで開く方法などで回避もできるようですが、
こういった場合の出力側での対処には以下のような方法があります。

データとしては微妙ですが、表示の問題を解決するには以下のように「=」で対処可能です。


1,"NAKAGAWA",09012345678    #これは頭の0が消える
2,"YOSHIKI",="09012345678"  #これは頭の0が表示される

データとしての値を大事にするか、エクセルでの表示を大事にするかで対応を変えるようにしましょう。

■A1セルの内容に注意
エクセルでは、「A1」(一番左上ですね)のセルに、
「ID」や「ID_xxxx」という文字列があると、「SYLKエラー」みたいなエラーが出るようです。
エクセルで開くことを前提にしたCSV出力では「A1」に「ID」文字列は厳禁ですので注意しましょう。

参考:http://www.yamamototakashi.com/soft/d2/manual/HLP000206.html

■■■■■■■■■■■■■■■■■■■■■■■■■

このように細かい気遣いが必要なCSV処理ですが、
CakePHPフレームワークを利用されている場合には、
このような対策(一部)をし、簡単にCSV出力に行えるHelperがありますので、
利用例を簡単に紹介したいと思います。

■CSV Helper (PHP 5)
http://bakery.cakephp.org/articles/view/csv-helper-php5

上記ページの「CsvHelper Class」のコードをダウンロードして、
/PROJECT/app/views/helpers/csv.php に配置します。

■コントローラ処理


<?php
class HogeController extends AppController {
var $uses = array('User');
  var $helpers = array('Csv'); //CsvHelperを利用
  /**
   * ユーザ一覧のCSV出力
   */
  function csv() {
     Configure::write('debug', 0);
     $this->layout = false;
     $users = $this->User->find('all'); //ユーザ一覧データを取得
     $this->set('users', $users);
  }
}
?>

■ビュー処理


<?php
//ファイル名設定
$this->Csv->setFilename('users.csv');
$header = array('ユーザID', '姓', '名', 'セイ', 'メイ');
//ヘッダー行追加
$this->Csv->addRow($header);
foreach ($users as $data) {
  $user = $data['User'];
  //出力するカラムを取り出す
  $row = array(
    $user['id'],
    $user['last_name'],
    $user['first_name'],
    $user['last_name_kana'],
    $user['first_name_kana'],
  );
  //データ行追加
  $this->Csv->addRow($row);
}
//CSVファイルダウンロード出力
echo $this->Csv->render(true, 'sjis-win', 'utf-8');
?>

CsvHelperを使えば、これだけの処理で簡単にCSV出力を行うことができます。

ちなみに、このCsvHelperのコードを見てみると、
「へー、そんな方法でできるんだー」みたいなちょっとした感動がありましたので、
是非ご覧になってください。

■■■■■■■■■■■■■■■■■■■■■■■■■

■最後に
実際の業務では、「改行を消して」や、「"(ダブルクォート)で囲わないで」、
「出力文字数制限入れて」などの、ユーザの要望や連携先の要件によって、
いろいろと対策が変わってきたりしますので、
一概にご紹介したような対策を必ずするとは限りませんのでご注意ください。