CSVをPHPでオブジェクト配列として扱う、CSVのActiveRecord的な何かを書いた。
だいぶ前にもあったけど、CSVを読み込んだり書き出したり、うにゃうにゃすることがよくあるので、簡単に扱えるものでも書こうかと思って書きました。
ただ、ここで扱うCSVは1行目にfieldName(半角英数)が入ることを前提としています。
利用方法は以下のような感じ。
//ライブラリを読み込む require_once("csv_active_record.php"); //オブジェクト生成 //第1引数はCSVファイルヘのパス、第2引数は文字コード(省略した場合、デフォルトでUTF-8) $object=new CSVActiveRecord("test.csv", "UTF-8");
オブジェクトを生成した時点で、CSVがオブジェクト配列として返されます。
◆CSV
"id","name","price","comment" "1","梅おにぎり","105","梅干し入りのおにぎり" "2","お〜い、お茶","120","喉が渇いたときはやっぱりお茶" "4","大根サラダ","180","野菜もちゃんと食べないとね" "5","プリン","88","デザートはやっぱりプリンでしょ"
◆返されたオブジェクト配列
var_dump($object->csvObject); ↓ array(4) { [0]=> object(stdClass)#2 (4) { ["id"]=> string(1) "1" ["name"]=> string(15) "梅おにぎり" ["price"]=> string(3) "105" ["comment"]=> string(30) "梅干し入りのおにぎり" } [1]=> object(stdClass)#3 (4) { ["id"]=> string(1) "2" ["name"]=> string(18) "お〜い、お茶" ["price"]=> string(3) "120" ["comment"]=> string(42) "喉が渇いたときはやっぱりお茶" } [2]=> object(stdClass)#4 (4) { ["id"]=> string(1) "4" ["name"]=> string(15) "大根サラダ" ["price"]=> string(3) "180" ["comment"]=> string(39) "野菜もちゃんと食べないとね" } [3]=> object(stdClass)#5 (4) { ["id"]=> string(1) "5" ["name"]=> string(9) "プリン" ["price"]=> string(2) "88" ["comment"]=> string(45) "デザートはやっぱりプリンでしょ" } } var_dump($object->fieldNameArray); ↓ array(4) { [0]=> string(2) "id" [1]=> string(4) "name" [2]=> string(5) "price" [3]=> string(7) "comment" }
CSVのアップデート・行の追加・削除
csvObjectを変更して、$object->save()関数を呼び出すことでCSVファイルに保存することができます。
(CSVファイルはSJISで書き出すようにしています)
$object->csvObject[2]->["name"]="NewName"; $object->save();
また、$object->update()関数でもアップデートできます。
この場合、第1引数はレコードの行番号で、第2引数はアップデートするパラメータの連想配列です。
$object->update(1, array( "name"=>"NewName" ));
行の追加をするときは$object->insert()でできます。
このとき、insertするパラメータは連想配列で与えてください。
$object->insert(array( "id"=>"5", "name"=>"プリン", "price"=>"88", "comment"=>"デザートはやっぱりプリンでしょ" ));
行の削除もできます。もちろん$object->delete()です。引数には行番号を与えてください。
$object->delete(2);
CSVを条件付きでSELECTする
insert, update, deleteときたら「select」だ。
おまけ的に$object->select()も作ってみた。
第1引数にfieldName、第2引数に条件を与えると、条件にあったオブジェクト配列を返してくれます。
$selectedRecords=$object->select("price", ">110");
ライブラリのソース
<?php class CSVActiveRecord { private $fileURL; private $charset; public $csvRecords; public $fieldNameArray; public $csvObject; public $selectObject; function __construct($fileURL, $charset="UTF-8"){ $this->fileURL=$fileURL; $this->charset=$charset; mb_regex_encoding($this->charset); $result=$this->read(); return $result; } //CSVの読み込み(オブジェクト配列を返す) public function read(){ $this->csvRecords=array(); $fp = @fopen($this->fileURL, "r+"); while(($line = @fgets($fp))){ $line = mb_convert_encoding($line, $this->charset, "SJIS"); $line = mb_ereg_replace("\"", "", $line); $line = mb_ereg_replace("\n", "", $line); if(mb_substr_count($line, ",") > 1){ $this->csvRecords[] = mb_split(",", $line); } } @fclose($fp); $result=$this->mapping(); return $result; } //オブジェクトにマッピングする public function mapping(){ if(!$this->csvRecords){ return false; } $this->csvObject=null; $this->fieldNameArray=$this->csvRecords[0]; foreach($this->csvRecords as $key => $csvRecord){ if($key!="0"){ $objectArray[]=$this->transformArray($this->fieldNameArray, $csvRecord); } } return $this->csvObject=$objectArray; } //CSVを書き出す・保存 public function save(){ if(!$this->csvObject){ return false; } $csv=""; //フィールドネームレコード foreach($this->fieldNameArray as $fieldName){ $csv.="\"".$fieldName."\","; } $csv.="\n"; foreach($this->csvObject as $record){ foreach($record as $value){ $csv.="\"".$value."\","; } $csv.="\n"; } $csv = mb_ereg_replace(",\n", "\n", $csv); $csv = mb_convert_encoding($csv, "SJIS", $this->charset); // CSVファイルを呼び出す(※なければ新たに作成) $fp = @fopen($this->fileURL, "w+"); // CSVファイルに$dataを追加挿入 @fputs($fp, $csv); // CSVファイルを閉じる @fclose($fp); chmod($this->fileURL, 0666); $result=$this->read(); return $result; } //新たな行を追加する public function insert($param=array()){ if(!is_array($param) || !count($param)){ return false; } foreach($this->fieldNameArray as $NameArray){ $record[$NameArray]=$param[$NameArray]; } $this->csvObject[]=$record; $result=$this->save(); return $result; } //特定の行をアップデート public function update($recordNum, $param=array()){ if(!is_array($param) || !count($param)){ return false; } foreach($param as $fieldName => $value){ $this->csvObject[$recordNum]->$fieldName=$value; } $result=$this->save(); return $result; } //特定の行を削除 public function delete($recordNum){ unset($this->csvObject[$recordNum]); $result=$this->save(); return $result; } //条件付きでrecordをselect public function select($fieldName, $condition){ $selectRecords=array(); $newfunc = create_function('$a', 'if($a'.$condition.') return true; else return false'); foreach($this->csvObject as $record){ if($newfunc($record[$fieldName])){ $selectRecords[]=$record; } } return $this->selectObject=$selectRecords; } //配列をobjectに変換 private function transformArray($fieldNameArray, $array){ foreach($array as $key => $value){ $fieldName=$fieldNameArray[$key]; $object->$fieldName=$value; } return $object; } } ?>
と、ここまで書いたけど、少し気に入らない部分が出てきた。
時間があったら書き直そう。
タイトルにはActiveRedord的な何かと書いたけど違うよなーたぶん。