file->setCsvControl($this->delimiter); $this->file->setFlags(\SplFileObject::READ_CSV); $this->file->setFlags(\SplFileObject::SKIP_EMPTY); if ($this->auto_detect_first_line) { $this->shiftToFirstValuableLine(); } $this->setupConverter(); } /** * устанавливает конвертер значений согласно конфигурационным настройкам */ public function setupConverter() { if (!count($this->converter_conf)) { $this->converter = new Converter(); if ($this->hasHeaderRow) { // если у файла есть заголовок, то в результате имеем ассоциативный массив $this->converter_conf['hasKey'] = 1; } //$this->converter->configuration = $this->converter_conf; } } /** * определяет первую значимую строку, * считывается файл пока в нем не встретится строка с непустыми колонками * в количестве указанном в атрибуте min_column_quantity * в результате выполнения курсор ресурса будет находится на последней незначимой строке */ protected function shiftToFirstValuableLine() { $finish = false; while (!$finish) { $this->current_line ++; $j = 0; $row = $this->file->fgetcsv();; if ($row === false) { continue; } for ($i = 1; $i <= count($row); $i++) { // CustomVarDamp::dump($row[$i]); if ($row[$i - 1] <> '') { $j++; } if ($j >= $this->min_column_quantity) { break 2; } } } die(); // $this->current_line --; $this->file->seek( $this->current_line ); } /** * @return array - итоговый двумерный массив с результатом парсинга * метод считывает с открытого файла данные построчно */ public function read() { $return = []; // будем считать количество пустых строк подряд - при трех подряд - считаем что это конец файла и выходим $empty_lines = 0; while ( $empty_lines < 3 ) { // прочтем строку из файла. Если там есть значения - то в ней массив, иначе - false $row = $this->readRow( ); if ($row === false) { //счетчик пустых строк $empty_lines++; continue; } // строка не пустая, имеем прочитанный массив значений $this->current_line++; if ($this->hasHeaderRow) { // в файле есть заголовок, но он еще не назначен, назначим if ($this->keys === NULL) { $this->keys = array_values($row); } } // если у нас установлен лимит, при его достижении прекращаем парсинг if (($this->last_line) && ($this->current_line > $this->last_line)) { break; } // обнуляем счетчик, так как считаюся пустые строки ПОДРЯД $empty_lines = 0; $return[] = $row; } $this->closeHandler(); return $return; } protected function closeHandler() { $this->file = NULL; } /** * @return array - одномерный массив результата парсинга строки */ protected function readRow( ) { $row = $this->file->fgetcsv(); // уберем нулевые колонки $row = array_filter($row, function($val){ return $val <> ''; }); if (is_array($row)) { // если есть заголовок, то перед конвертацией его нужно назначить if ($this->hasHeaderRow && $this->keys !== NULL) { if (count($this->keys) !== count($row)) { throw new \ErrorException("Ошибка парсинга файла в строке # {$this->current_line}. Не соответсвие числа ключевых колонок (заголовка) - числу колонок с данными", 0, 1, $this->file->getBasename(), $this->current_line); } $row = array_combine($this->keys, $row); } // попытаемся конвертировать прочитанные значения согласно конфигурации котнвертера значений $row = $this->convert($row); // обрежем массив к первой значимой колонке if ( $this->first_column ) { $row = array_slice($row, $this->first_column); } } if (is_null($row)) $row = false; return $row; } /** * @param $arr * @return mixed * преобразовует значения прочитанного массива в нужные типы, согласно конфигурации конвертера */ protected function convert($arr) { $result = $arr; $converter = $this->converter; if (!is_null($converter)) { $result = $converter->convertByConfiguration( $arr, $this->converter_conf ); } return $result; } }