+7 (495) 229-0436   shopadmin@itshop.ru 119334, г. Москва, ул. Бардина, д. 4, корп. 3
 
 
Вход
 
 
Каталог
 
 
Подписка на новости
Новости ITShop
Windows 7 и Office: Новости и советы
Обучение и сертификация Microsoft
Вопросы и ответы по MSSQLServer
Delphi - проблемы и решения
Adobe Photoshop: алхимия дизайна
 
Ваш отзыв
Оцените качество магазина ITShop.ru на Яндекс.Маркете. Если вам нравится наш магазин - скажите об этом Google!
 
 
Способы оплаты
 
Курс расчета
 
 1 у.е. = 91.78 руб.
 
 Цены показывать:
 
 
 
 
  
Новости, статьи, акции
 

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

07.02.2012 11:44

Мне по работе часто приходится импортировать Excel-документы средствами PHP.

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

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

Адресовать ячейки при работе с excel можно разными способами:

  • колонка и ряд в виде строки: "A1"
  • колонка буквой, ряд числом: ("A", 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;
}

 Сразу оговорюсь, что в приводимых мной примерах кода есть ссылки на $this, т.к. это методы моего класса-обертки над PHPExcel. В этом кусочке реализуются все три способа получения объекта ячейки.

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

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

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

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

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

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

$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->getValue() корректно обрабатывает формулы и возвращает рассчитанное значение. Но бывают ситуации, когда формула ссылается на несуществующий лист или другой файл, который локально хранится у того, кто отправил вам excel-документ. Тогда getValue() возвратит ошибку, хотя визуально в экселе вы можете увидеть верное значение, если не было пересчета листа. Дело в том, что Excel сохраняет oldCalculatedValue, которое и используется, если не пересчитывать лист. На рисунке выше я показал это в ячейке B4 - она отображает старое значение, хотя ссылка в ней нерабочая.

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

$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;
    }


Тест

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

 Тест #1:

Тест #2:

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

Ложка дегтя

 Важно отметить, что использование пунктов 2, 3 и 4 работает только в режиме ReadDataOnly = false. Это режим PHPExcel по умолчанию, когда он считывает всю мета-информацию о книге. Подходит для стандартных небольших документов, например счета, накладные и.т.д.

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

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

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

 Спасибо за внимание!

Ссылки по теме

  
Помощь
Задать вопрос
 программы
 обучение
 экзамены
 компьютеры
Бесплатный звонок
ICQ-консультанты
Skype-консультанты

Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 
Бестселлеры
Курсы обучения "Atlassian JIRA - система управления проектами и задачами на предприятии"
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2019. Все языки. Электронный ключ
Курс "Oracle. Программирование на SQL и PL/SQL"
Курс "Основы TOGAF® 9"
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Курс "Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации"
 

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.



 

О нас

 
Главная
Каталог
Новинки
Акции
Вакансии
 

Помощь

 
Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 

Способы оплаты

 

Проекты Interface Ltd.

 
Interface.ru   ITShop.ru   Interface.ru/training   Olap.ru   ITnews.ru  
 

119334, г. Москва, ул. Бардина, д. 4, корп. 3
+7 (495) 229-0436   shopadmin@itshop.ru
Проверить аттестат
© ООО "Interface Ltd."
Продаем программное обеспечение с 1990 года