PHPでCSVファイル出力
CSVファイル出力(open、close、write、download、UTF-16LE、BOM付き、ダブルコーテーション)をclassにまとめてみました
CSVファイル出力機能をいくつか作成したことがありますが、仕様が微妙に違っていたりして統一感がなかったので、1つのファイルにまとめてみました。
使い方(1)
ファイル名:sample1.csv、ファイル文字コード:SJIS-win、区切り文字:,(カンマ)、改行コード:\r\n、ダブルコーテーション:あり
require_once('csv.class.php'); $csv = new csv(); // 初期値設定(ファイル文字コード:SJIS-win、区切り文字:,(カンマ)、改行コード:\r\n、ダブルコーテーション:あり) $csv->init(); // ファイルオープン(ファイル名:sample1.csv) $csv->open('sample1.csv'); // ヘッダー項目出力 $csv->write(array('郵便番号','所在地','名称')); // データ出力 $csv->write(array('zip' => '〒102-8688', 'address' => '東京都千代田区九段南1-2-1', 'name' => '千代田区役所')); $csv->write(array('zip' => '〒104-8404', 'address' => '東京都中央区築地一丁目1番1号', 'name' => '中央区役所')); // ファイルクローズ $csv->close(); // ファイルダウンロード $csv->download(); // ファイル削除 $csv->unlink(); // 結果 sample1.csv // "郵便番号","所在地","名称" // "〒102-8688","東京都千代田区九段南1-2-1","千代田区役所" // "〒104-8404","東京都中央区築地一丁目1番1号","中央区役所"
使い方(2)
ファイル名:/home/work/sample2.csv、ファイル文字コード:UTF-16LE(BOM付き)、区切り文字:TAB(タブ)、改行コード:\n、ダブルコーテーション:なし
require_once('csv.class.php'); $csv = new csv(); try { // ファイル文字コード=UTF-16LE(BOM付き) if ($csv->setEncode('UTF-16LE', true) === false) { throw new Exception('setEncode'); } // 区切り文字=TAB(タブ) if ($csv->setDelimiter("\t") === false) { throw new Exception('setDelimiter'); } // 改行コード=\n if ($csv->setNewLine("\n") === false) { throw new Exception('setNewLine'); } // ダブルコーテーション=なし if ($csv->setQuote(false) === false) { throw new Exception('setQuote'); } // ファイルオープン ファイル名=/home/work/sample2.csv if ($csv->open('/home/work/sample2.csv') === false) { throw new Exception('open'); } // ヘッダー項目出力 if ($csv->write(array('郵便番号','所在地','名称')) === false) { throw new Exception('write'); } $arr = array( array( 'zip' => '〒102-8688', 'address' => '東京都千代田区九段南1-2-1', 'name' => '千代田区役所', ), array( 'zip' => '〒104-8404', 'address' => '東京都中央区築地一丁目1番1号', 'name' => '中央区役所', ), ); // データ出力 foreach ($arr as $key=>$row) { //1行づつ出力 if ($csv->write($row) === false) { throw new Exception('write'); } } // ファイルクローズ if ($csv->close() === false) { throw new Exception('close'); } // ファイルダウンロード if ($csv->download() === false) { throw new Exception('download'); } // ファイル削除 if ($csv->unlink() === false) { throw new Exception('unlink'); } } catch (Exception $e) { echo sprintf('ERROR=%s', $e->getMessage()); } // 結果 sample2.csv // 郵便番号 所在地 名称 // 〒102-8688 東京都千代田区九段南1-2-1 千代田区役所 // 〒104-8404 東京都中央区築地一丁目1番1号 中央区役所
設定
■初期値設定 init() ・下記内容を一括設定します 文字コード = SJIS-win BOM = なし 区切り文字 = ,(カンマ) 改行コード = \r\n ダブルコーテーション= あり ■ファイル文字コード設定 setEncode(文字コード, BOM) ・文字コード = SJIS SJIS-win EUC-JP eucJP-win UTF-8 UTF-16BE UTF-16LE UTF-32BE UTF-32LE ・BOM = false:BOMなし true:BOM付き 文字コード と BOM の組み合わせ SJIS BOMなし SJIS-win BOMなし EUC-JP BOMなし eucJP-win BOMなし UTF-8 BOM付き or BOMなし UTF-16BE BOM付き or BOMなし UTF-16LE BOM付き or BOMなし UTF-32BE BOM付き or BOMなし UTF-32LE BOM付き or BOMなし ■ 区切り文字設定 setDelimiter(区切り文字) ・区切り文字 = ,(カンマ) \t(タブ) :(コロン) ;(セミコロン) |(パイプライン) 半角スペース ■改行コード設定 setNewLine(改行コード) ・改行コード = \r\n(Windows系) \n(UNIX系) \r(MacOS9以前) ■ダブルコーテーション設定 setQuote(ダブルコーテーション) ・ダブルコーテーション = false(設定なし) true(設定あり)
csv出力
csv.class.php
<?php /** * csv出力 * csv.class.php ver1.00 **/ class csv { /** * 変数 */ protected $m_sCharSet = 'UTF-8';//文字コード protected $m_sEncode = 'SJIS-win';//ファイル出力の文字エンコーディング protected $m_sDelimiter = ',';//区切り文字 protected $m_sNewLine = "\r\n";//改行コード protected $m_bQuote = true;//ダブルクォーテーション protected $m_sBom = null;//BOM protected $m_arrFile = array();//ファイル(path=絶対パス、directory=ディレクトリ、file=ファイル名) protected $m_clsHdl = null;//ファイルポインタ public function __construct() { $this->init(); } public function __destruct() { } /** * 初期値設定 * 引数:なし * 戻値:結果 */ public function init() { if ($this->m_clsHdl !== null) { return false; } $this->m_sEncode = 'SJIS-win';//ファイル出力の文字エンコーディング $this->m_sDelimiter = ',';//区切り文字 $this->m_sNewLine = "\r\n";//改行コード $this->m_bQuote = true;//ダブルクォーテーション $this->m_sBom = null;//BOM $this->m_arrFile = array();//ファイル(path=絶対パス、directory=ディレクトリ、file=ファイル名) $this->m_clsHdl = null;//ファイルポインタ return true; } /** * オープン * 引数:ファイル名 * 戻値:結果 */ public function open($p_sValue='') { if ($this->m_clsHdl !== null) { return false; } //ファイル名・ディレクトリ取得 $this->m_arrFile = $this->_parseFile($p_sValue); if ($this->m_arrFile === false) { return false; } //書き込みでファイルをオープン $this->m_clsHdl = fopen($this->m_arrFile['path'], 'w'); if ($this->m_clsHdl === false) { $this->m_arrFile = array(); $this->m_clsHdl = null; return false; } //BOM付きはファイルの先頭にBOM (Byte Order Mark) を付加 if ($this->m_sBom !== null) { $bResult = fwrite($this->m_clsHdl, $this->m_sBom); if ($bResult === false) { $this->close(); $this->m_arrFile = array(); $this->m_clsHdl = null; return false; } } return true; } /** * クローズ * 引数:なし * 戻値:結果 */ public function close() { if ($this->m_clsHdl === null) { return false; } //ファイルをクローズ $bResult = fclose($this->m_clsHdl); if ($bResult === false) { return false; } $this->m_clsHdl = null; return true; } /** * 出力 * 引数:出力データ(1行単位) * 戻値:結果 */ public function write($p_arrValue) { if ($this->m_clsHdl === null) { return false; } //配列を文字列に変換 $arrWork = array(); $sCsv = ''; if (is_array($p_arrValue) === true) { foreach ($p_arrValue as $key=>$row) { $arrWork[] = $this->_value($row); } } else { $arrWork[] = $this->_quote($p_arrValue); } $sCsv = implode($this->m_sDelimiter, $arrWork).$this->m_sNewLine; //文字エンコーディングを変換 if ($this->m_sCharSet !== $this->m_sEncode) { $sCsv = mb_convert_encoding($sCsv, $this->m_sEncode, $this->m_sCharSet); } //ファイルへ出力 $bResult = fwrite($this->m_clsHdl, $sCsv); if ($bResult === false) { return false; } return true; } /** * ダウンロード * 引数:なし * 戻値:結果 */ public function download() { if (is_file($this->m_arrFile['path']) === false) { return false; } header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.$this->m_arrFile['file'].'"'); header('Content-Length: '.filesize($this->m_arrFile['path'])); ob_end_clean(); readfile($this->m_arrFile['path']); return true; } /** * 削除 * 引数:なし * 戻値:結果 */ public function unlink() { if ($this->m_clsHdl !== null) { return false; } if (is_file($this->m_arrFile['path']) === false) { return false; } //ファイルの削除 $bResult = @unlink($this->m_arrFile['path']); if ($bResult === false) { return false; } return true; } /** * ファイル名・ディレクトリパスを取得 * 引数:ファイル名 * 戻値:結果 */ protected function _parseFile($p_sValue='') { if ((strpos($p_sValue, '/') !== false) && (strpos($p_sValue, '\\') !== false)) { return false; } $sDirName = ''; $sFileName = ''; if (strlen($p_sValue) > 0) { $sFileName = $p_sValue; $nPos = strrpos($p_sValue, '\\'); if ($nPos !== false) { $sDirName = substr($p_sValue, 0, $nPos + 1); $sFileName = substr($p_sValue, $nPos + 1); } else { $nPos = strrpos($p_sValue, '/'); if ($nPos !== false) { $sDirName = substr($p_sValue, 0, $nPos + 1); $sFileName = substr($p_sValue, $nPos + 1); } }// if ($nPos !== false) }// if (strlen($p_sValue) > 0) if (strlen($sDirName) === 0) { $sDirName = dirname(__FILE__).DIRECTORY_SEPARATOR; } if (strlen($sFileName) === 0) { $sFileName = sprintf('%s.csv', date('YmdHis')); } if ((is_dir($sDirName) === false) || ($this->_chkFileName($sFileName) === false)) { return false; } return array( 'path' => $sDirName.$sFileName, 'directory' => $sDirName, 'file' => $sFileName ); } /** * ファイル名チェック * 引数:ファイル名 * 戻値:結果 */ protected function _chkFileName($p_sValue) { //2バイト文字はエラーとする if (strlen($p_sValue) !== mb_strlen($p_sValue, $this->m_sCharSet)) { return false; } //50文字以内に制限 if ((strlen($p_sValue) < 1) || (50 < strlen($p_sValue))) { return false; } //先頭・末尾がスペースはエラー $sPattern = "#^ | $#"; if (preg_match($sPattern, $p_sValue) === 1) { return false; } //制御文字は使用不可 $sPattern = '#[\x00-\x1f\x7f]#'; if (preg_match($sPattern, $p_sValue) === 1) { return false; } //ハードウェア名は使用不可 $sPattern = '#^(AUX|COM[0-9]|CON|LPT[0-9]|NUL|PRN)(\.|$)#i'; if (preg_match($sPattern, $p_sValue) === 1) { return false; } // \ / : * ? " < > | は使用不可 $sPattern = '#[\\\/:*?"<>|]#'; if (preg_match($sPattern, $p_sValue) === 1) { return false; } // 「.」「..」 又は、先頭・末尾が「.」 はエラー if (($p_sValue === '.') || ($p_sValue === '..') || (substr($p_sValue, 0, 1) === '.') || (substr($p_sValue, -1) === '.')) { return false; } return true; } /** * ダブルクォーテーション * 引数:文字列 * 戻値:変換後文字列 */ protected function _quote($p_sValue) { if ($this->m_bQuote === true) { $p_sValue = '"'.preg_replace('#(?<!\\\\)\"#', '""', $p_sValue).'"'; } return $p_sValue; } /** * 多次元配列を文字列に変換 * 引数:配列 * 戻値:文字列 */ protected function _value($arrValue) { $arrWork = array(); if (is_array($arrValue) === true) { foreach ($arrValue as $key=>$row) { if (is_array($row) === true) { $arrWork[] = $this->_value($row); } else { $arrWork[] = $this->_quote($row); } } } else { $arrWork[] = $this->_quote($arrValue); } return implode($this->m_sDelimiter, $arrWork); } /** * 変換後の文字エンコーディング設定 * 引数:エンコーディング * 引数:BOMの設定(false:BOMなし true:BOM付き) * 戻値:結果 */ public function setEncode($p_sValue, $p_bBom=false) { if ($this->m_clsHdl !== null) { return false; } $arrEncoding = array( array('encode' => 'SJIS', 'bom' => null), array('encode' => 'SJIS-win', 'bom' => null), array('encode' => 'EUC-JP', 'bom' => null), array('encode' => 'eucJP-win', 'bom' => null), array('encode' => 'UTF-8', 'bom' => pack('C*', 0xEF, 0xBB, 0xBF)), array('encode' => 'UTF-16BE', 'bom' => pack('C*', 0xFE, 0xFF)), array('encode' => 'UTF-16LE', 'bom' => pack('C*', 0xFF, 0xFE)), array('encode' => 'UTF-32BE', 'bom' => pack('C*', 0x00, 0x00, 0xFE, 0xFF)), array('encode' => 'UTF-32LE', 'bom' => pack('C*', 0xFF, 0xFE, 0x00, 0x00)), ); $bChk = false; foreach ($arrEncoding as $key=>$row) { if (strtolower($row['encode']) === strtolower($p_sValue)) { $bChk = true; $this->m_sEncode = $row['encode']; if ($p_bBom === true) { if ($row['bom'] !== null) { $this->m_sBom = $row['bom']; } else { $bChk = false; } } else if ($p_bBom === false) { $this->m_sBom = null; } else { $this->m_sBom = null; $bChk = false; } break; }// if (strtolower($row['encode']) === }// foreach ($arrEncoding as $key=>$row) return $bChk; } /** * 区切り文字設定 * 引数:区切り文字 * 戻値:結果 */ public function setDelimiter($p_sValue) { if ($this->m_clsHdl !== null) { return false; } $arrDelimiter = array(',', "\t", ':', ';', '|', ' '); $bChk = false; foreach ($arrDelimiter as $key=>$row) { if ($row === $p_sValue) { $bChk = true; $this->m_sDelimiter = $row; break; } } return $bChk; } /** * 改行コード設定 * 引数:改行コード * 戻値:結果 */ public function setNewLine($p_sValue) { if ($this->m_clsHdl !== null) { return false; } $arrNewLine = array("\r\n", "\n", "\r"); $bChk = false; foreach ($arrNewLine as $key=>$row) { if ($row === $p_sValue) { $bChk = true; $this->m_sNewLine = $row; break; } } return $bChk; } /** * ダブルクォーテーション設定 * 引数:ダブルクォーテーションの設定(false:なし true:あり) */ public function setQuote($p_bQuote) { $bChk = false; if ($p_bQuote === true) { $bChk = true; $this->m_bQuote = true; } else if ($p_bQuote === false) { $bChk = true; $this->m_bQuote = false; } return $bChk; } } ?>