detectDelimiter($filePath); $enclosure = $options['enclosure'] ?? '"'; $encoding = $options['encoding'] ?? $this->detectEncoding($filePath); $data = []; $headers = []; $rowIndex = 0; $handle = fopen($filePath, 'r'); if ($handle === false) { throw new \RuntimeException("Could not open file: $filePath"); } while (($row = fgetcsv($handle, 0, $delimiter, $enclosure)) !== false) { // Converter encoding se necessário if ($encoding !== 'UTF-8') { $row = array_map(function ($value) use ($encoding) { return mb_convert_encoding($value, 'UTF-8', $encoding); }, $row); } if ($rowIndex === $headerRow) { $headers = $row; $rowIndex++; continue; } if ($rowIndex < $dataStartRow) { $rowIndex++; continue; } // Verificar se não está vazia $nonEmpty = array_filter($row, fn($v) => $v !== null && $v !== ''); if (!empty($nonEmpty)) { $data[] = $row; } $rowIndex++; } fclose($handle); return [ 'headers' => $headers, 'data' => $data, 'total_rows' => count($data), 'detected_delimiter' => $delimiter, 'detected_encoding' => $encoding, ]; } /** * Get headers from CSV file */ public function getHeaders(string $filePath, array $options = []): array { $headerRow = $options['header_row'] ?? 0; $delimiter = $options['delimiter'] ?? $this->detectDelimiter($filePath); $enclosure = $options['enclosure'] ?? '"'; $encoding = $options['encoding'] ?? $this->detectEncoding($filePath); $handle = fopen($filePath, 'r'); if ($handle === false) { throw new \RuntimeException("Could not open file: $filePath"); } $rowIndex = 0; $headers = []; while (($row = fgetcsv($handle, 0, $delimiter, $enclosure)) !== false) { if ($rowIndex === $headerRow) { $headers = $row; break; } $rowIndex++; } fclose($handle); // Converter encoding se necessário if ($encoding !== 'UTF-8') { $headers = array_map(function ($value) use ($encoding) { return mb_convert_encoding($value, 'UTF-8', $encoding); }, $headers); } return $headers; } /** * Get preview data */ public function getPreview(string $filePath, int $rows = 10, array $options = []): array { $delimiter = $options['delimiter'] ?? $this->detectDelimiter($filePath); $enclosure = $options['enclosure'] ?? '"'; $encoding = $options['encoding'] ?? $this->detectEncoding($filePath); $preview = []; $rowCount = 0; $totalRows = 0; $handle = fopen($filePath, 'r'); if ($handle === false) { throw new \RuntimeException("Could not open file: $filePath"); } // Primeiro, contar todas as linhas while (fgets($handle) !== false) { $totalRows++; } // Voltar ao início rewind($handle); // Ler preview while (($row = fgetcsv($handle, 0, $delimiter, $enclosure)) !== false) { if ($rowCount >= $rows) { break; } // Converter encoding se necessário if ($encoding !== 'UTF-8') { $row = array_map(function ($value) use ($encoding) { return mb_convert_encoding($value, 'UTF-8', $encoding); }, $row); } $preview[] = [ 'row_index' => $rowCount, 'data' => $row, ]; $rowCount++; } fclose($handle); return [ 'preview' => $preview, 'total_rows' => $totalRows, 'columns_count' => !empty($preview) ? count($preview[0]['data']) : 0, 'detected_delimiter' => $delimiter, 'detected_encoding' => $encoding, ]; } /** * Detect CSV delimiter */ protected function detectDelimiter(string $filePath): string { $delimiters = [',', ';', "\t", '|']; $counts = array_fill_keys($delimiters, 0); $handle = fopen($filePath, 'r'); if ($handle === false) { return ','; } // Ler primeiras 5 linhas $lines = 0; while (($line = fgets($handle)) !== false && $lines < 5) { foreach ($delimiters as $d) { $counts[$d] += substr_count($line, $d); } $lines++; } fclose($handle); // Retornar o delimitador mais frequente arsort($counts); return array_key_first($counts); } /** * Detect file encoding */ protected function detectEncoding(string $filePath): string { $content = file_get_contents($filePath, false, null, 0, 10000); // Verificar BOM UTF-8 if (substr($content, 0, 3) === "\xEF\xBB\xBF") { return 'UTF-8'; } // Tentar detectar encoding $encoding = mb_detect_encoding($content, ['UTF-8', 'ISO-8859-1', 'Windows-1252', 'ASCII'], true); return $encoding ?: 'UTF-8'; } /** * Check if parser supports the extension */ public static function supports(string $extension): bool { return in_array(strtolower($extension), self::$supportedExtensions); } }