From 45eba305285af363c49f73b81af8f5801780dad3 Mon Sep 17 00:00:00 2001 From: shibafu Date: Sun, 16 Feb 2020 17:01:16 +0900 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E5=AD=97=E3=82=B3=E3=83=BC=E3=83=89?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E3=81=8C=E4=B8=8A=E6=89=8B=E3=81=8F=E8=A1=8C?= =?UTF-8?q?=E3=81=8B=E3=81=AA=E3=81=84=E3=82=B1=E3=83=BC=E3=82=B9=E3=81=8C?= =?UTF-8?q?=E3=81=82=E3=81=A3=E3=81=9F=E3=81=AE=E3=81=A7=E3=80=81=E3=82=82?= =?UTF-8?q?=E3=81=86=E5=B0=91=E3=81=97=E7=B2=98=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AA=E3=82=A2=E3=83=AB=E3=82=B4=E3=83=AA=E3=82=BA=E3=83=A0?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Io/CheckinCsvImporter.php | 53 +++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/app/Io/CheckinCsvImporter.php b/app/Io/CheckinCsvImporter.php index 6445f79..f91a063 100644 --- a/app/Io/CheckinCsvImporter.php +++ b/app/Io/CheckinCsvImporter.php @@ -28,11 +28,7 @@ class CheckinCsvImporter public function execute() { // Guess charset - $head = file_get_contents($this->filename, false, null, 0, 1024); - $charset = mb_detect_encoding($head, ['ASCII', 'UTF-8', 'SJIS-win'], true); - if (array_search($charset, ['UTF-8', 'SJIS-win'], true) === false) { - throw new CsvImportException(['文字コード判定に失敗しました。UTF-8 (BOM無し) または Shift_JIS をお使いください。']); - } + $charset = $this->guessCharset($this->filename); // Open CSV $csv = Reader::createFromPath($this->filename, 'r'); @@ -101,4 +97,51 @@ class CheckinCsvImporter } }); } + + /** + * 指定されたファイルを読み込み、文字コードの判定を行います。 + * @param string $filename CSVファイル名 + * @param int $samplingLength ファイルの先頭から何バイトを判定に使用するかを指定 + * @return string 検出した文字コード (UTF-8, SJIS-win, ...) + * @throws CsvImportException ファイルの読み込みに失敗した、文字コードを判定できなかった、または非対応文字コードを検出した場合にスロー + */ + private function guessCharset(string $filename, int $samplingLength = 1024): string + { + $fp = fopen($filename, 'rb'); + if (!$fp) { + throw new CsvImportException(['CSVファイルの読み込み中にエラーが発生しました。']); + } + + try { + $head = fread($fp, $samplingLength); + if ($head === false) { + throw new CsvImportException(['CSVファイルの読み込み中にエラーが発生しました。']); + } + + for ($addition = 0; $addition < 4; $addition++) { + $charset = mb_detect_encoding($head, ['ASCII', 'UTF-8', 'SJIS-win'], true); + if ($charset) { + if (array_search($charset, ['UTF-8', 'SJIS-win'], true) === false) { + throw new CsvImportException(['文字コード判定に失敗しました。UTF-8 (BOM無し) または Shift_JIS をお使いください。']); + } else { + return $charset; + } + } + + // 1バイト追加で読み込んだら、文字境界に到達して上手く判定できるかもしれない + if (feof($fp)) { + break; + } + $next = fread($fp, 1); + if ($next === false) { + throw new CsvImportException(['CSVファイルの読み込み中にエラーが発生しました。']); + } + $head .= $next; + } + + throw new CsvImportException(['文字コード判定に失敗しました。UTF-8 (BOM無し) または Shift_JIS をお使いください。']); + } finally { + fclose($fp); + } + } }