Универсальное Чтение Ячеек В Phpexcel

Привет, Хабр! На работе мне часто приходится импортировать документы Excel с помощью PHP. Для этого я использую библиотеку PHPExcel , что на сегодняшний день является очень удобным инструментом.

Но есть несколько «скользких» вопросов, связанных со чтением данных из ячеек, о которых я хочу рассказать читателям хабра, а также проанализировать функцию, решающую эти проблемы.



1. Адресация ячеек

Существуют разные способы обращения к ячейкам при работе с Excel:
  • столбец и строка в виде строки: «A1»
  • столбец по букве, ряд по номеру: («А», 1)
  • столбец и строка по номеру: (1, 1)
Первый способ удобнее для статических ячеек, а второй и третий — для циклов.

Но в PHPExcel нет универсальной функции получения ячейки любым из этих способов, есть только отдельные функции.

Что ж, исправим это упущение:

  
  
  
  
  
   

public function getCellValue($cellOrCol, $row = null) { //column set by index if(is_numeric($cellOrCol)) { $cell = $this->activeSheet->getCellByColumnAndRow($cellOrCol, $row); } else { $lastChar = substr($cellOrCol, -1, 1); if(!is_numeric($lastChar)) { //column contains only letter, e.g. "A" $cellOrCol .

= $row; } $cell = $this->activeSheet->getCell($cellOrCol); } $val = $cell->getValue(); return $val; }

Сразу оговорюсь, что в приведённых мной примерах кода есть ссылки на $это , т.к.

это методы моего класса-обертки над PHPExcel. В этом фрагменте реализованы все три способа получения объекта ячейки.



2. Объединение ячеек

При чтении объединенных ячеек PHPExcel возвращает пустое значение для всех, кроме первого .

Те.

для картинки ниже значения B3 и C3 будут пустыми строками:

Универсальное чтение ячеек в PHPExcel

Мне всегда было неприятно такое поведение.

Гораздо удобнее (и логичнее!), чтобы любая объединенная ячейка возвращала для них общее значение.

«объединенное значение» .

Для этого при запросе значения нужно пройтись по всем объединенным диапазонам листа, и если указанная ячейка попадает в диапазон, то вернуть первый:

$this->mergedCellsRange = $this->activeSheet->getMergeCells(); foreach($this->mergedCellsRange as $currMergedRange) { if($cell->isInRange($currMergedRange)) { $currMergedCellsArray = PHPExcel_Cell::splitRange($currMergedRange); $cell = $this->activeSheet->getCell($currMergedCellsArray[0][0]); break; } }



3. Даты

Как известно, Excel хранит даты как количество дней с 1 января 1900 года.

Поэтому при чтении ячейки B2 на скриншоте выше мы получим бесполезное число 41044. Но есть и хорошая новость — в PHPExcel есть удобная функция PHPExcel_Shared_Date::ExcelToPHP() , который преобразует дату в формат php. Остается только применить эту функцию в нужный момент:

$val = $cell->getValue(); if(PHPExcel_Shared_Date::isDateTime($cell)) { $val = date($format, PHPExcel_Shared_Date::ExcelToPHP($val)); }



4. Формулы

В большинстве случаев стандартная функция $cell-> получить значение() правильно обрабатывает формулы и возвращает рассчитанное значение.

Но бывают ситуации, когда формула ссылается на несуществующий лист или другой файл, хранящийся локально у человека, отправившего вам документ Excel. Затем getValue() вернет ошибку, хотя визуально в Excel можно увидеть правильное значение, если лист не был пересчитан.

Дело в том, что Excel сохраняет OldCalculatedValue , который используется, если лист не пересчитывается.

На картинке выше я показал это в ячейке B4 — там отображается старое значение, хотя ссылка в ней битая.

PHPExcel, к счастью, тоже умеет хранить старое значение формулы.

Это удобно использовать, когда получить значение() не смог сработать и вернул не значение, а саму формулу (первый символ "="):

$val = $cell->getValue(); if((substr($val,0,1) === '=' ) && (strlen($val) > 1)){ $val = $cell->getOldCalculatedValue(); }



Результат

В результате мы получили функцию, позволяющую универсально читать значения ячеек:

public function getCellValue($cellOrCol, $row = null, $format = 'd.m.Y') { //column set by index if(is_numeric($cellOrCol)) { $cell = $this->activeSheet->getCellByColumnAndRow($cellOrCol, $row); } else { $lastChar = substr($cellOrCol, -1, 1); if(!is_numeric($lastChar)) { //column contains only letter, e.g. "A" $cellOrCol .

= $row; } $cell = $this->activeSheet->getCell($cellOrCol); } //try to find current coordinate in all merged cells ranges //if find -> get value from head cell foreach($this->mergedCellsRange as $currMergedRange){ if($cell->isInRange($currMergedRange)) { $currMergedCellsArray = PHPExcel_Cell::splitRange($currMergedRange); $cell = $this->activeSheet->getCell($currMergedCellsArray[0][0]); break; } } //simple value $val = $cell->getValue(); //date if(PHPExcel_Shared_Date::isDateTime($cell)) { $val = date($format, PHPExcel_Shared_Date::ExcelToPHP($val)); } //for incorrect formulas take old value if((substr($val,0,1) === '=' ) && (strlen($val) > 1)){ $val = $cell->getOldCalculatedValue(); } return $val; }



Тест

Для проверки прочитаем Excel со скриншота двумя способами: стандартным getValue( #1 ) и используя указанную выше функцию ( #2 ):

Универсальное чтение ячеек в PHPExcel

Тест №1:

Универсальное чтение ячеек в PHPExcel

Тест №2:

Универсальное чтение ячеек в PHPExcel

Как видите, во втором случае все было признано правильным.



Ложка дегтя

Важно отметить, что использование пунктов 2, 3 и 4 работает только в режиме Реаддатаонли = ложь .

Это режим PHPExcel по умолчанию, в котором он считывает всю метаинформацию о книге.

Подходит для стандартных небольших документов, таких как счета-фактуры, счета-фактуры и т. д. Включение Реаддатаонли = истина может потребоваться для объемных файлов, когда это необходимо только значения ячеек .

На моей практике такие файлы содержат отформатированные таблицы и такой функционал там не нужен.

Установка режима чтения в PHPExcel делается так:

$objReader = PHPExcel_IOFactory::createReaderForFile($filename); $objReader->setReadDataOnly(false); $this->PHPExcel = $objReader->load($filename);

Спасибо за внимание! Теги: #phpexcel #php #php

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.