文字コード判定が上手く行かないケースがあったので、もう少し粘るようなアルゴリズムにした
This commit is contained in:
		@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user