<?php
namespace Site\Lib;
enum Delimiter: int {
case COMMA = 1;
case SEMICOLON = 2;
case TAB = 3;
case PIPE = 4;
public static function default(): self {
return self::COMMA;
}
public function getChar(): string {
return match ($this) {
self::COMMA => ",",
self::SEMICOLON => ";",
self::TAB => "\t",
self::PIPE => "|",
};
}
}
/**
* CSVパーシングクラス
*/
class Csv {
// リクエスト関連のプロパティ
private bool $isHeader = false;
private int $length = 8192;
private Delimiter $delimiter;
private string $filename;
private string $enclosure = "\"";
private string $escape = "\\";
private $fp;
public function __construct(string $filename, int $length = 8192) {
$this->length = $length;
$this->filename = $filename;
$this->delimiter = Delimiter::default();
$this->fp = fopen($this->filename, 'r');
if ($this->fp === false) {
$msg = "ファイルを開けられません。";
logger(\LogType::Csv, $msg);
throw new \Exception($msg);
}
}
public function __destruct() {
if ($this->fp !== false) {
fclose($this->fp);
}
}
public function parse(?Delimiter $delimiter = null, bool $isHeader = false): array {
$res = [];
$this->isHeader = $isHeader;
$this->delimiter = $delimiter ?? $this->delimiter;
$delim = ($delimiter ?? $this->delimiter)->getChar();
rewind($this->fp);
if ($this->isHeader) {
$res = ['header' => [], 'body' => []];
$head = fgets($this->fp, $this->length);
if ($head !== false) {
$res['header'] = str_getcsv($head, $delim, $this->enclosure, $this->escape);
}
}
while (($buffer = fgets($this->fp, $this->length)) !== false) {
$row = str_getcsv($buffer, $delim, $this->enclosure, $this->escape);
if ($this->isHeader) $res['body'][] = $row;
else $res[] = $row;
}
if (!feof($this->fp)) {
$msg = "エラー:fgets()の失敗";
logger(\LogType::Csv, $msg);
throw new \Exception($msg);
}
return $res;
}
public function write(array $list, ?Delimiter $delimiter = null): bool {
$fp = fopen($this->filename, 'w');
if ($fp === false) {
$msg = "ファイルに書き込めません。";
logger(\LogType::Csv, $msg);
throw new \Exception($msg);
}
$delim = ($delimiter ?? $this->delimiter)->getChar();
foreach ($list as $l) {
if (fputcsv($fp, $l, $delim, $this->enclosure, $this->escape) === false) {
fclose($fp);
$msg = "CSVデータの書き込みに失敗";
logger(\LogType::Csv, $msg);
throw new \Exception($msg);
}
}
return fclose($fp);
}
}