Php and microsoft excel

PHPExcel — библиотека для создания и чтения данных из файлов формата OpenXML (который используется в MS Excel 2007). С ее помощью можно считывать из файлов, записывать в файлы, форматировать содержимое, работать с формулами и т.д. Для работы PHPExcel требуется версия PHP 5.2 или выше, с установленными библиотеками Zip, XML и GD2.

Установка PHPExcel

Первым делом библиотеку необходимо скачать. Для этого переходим на официальный сайт библиотеки и скачиваем архив PHPExcel-1.7.8.zip. После распаковки мы получим несколько файлов и папок:

  • Classes
  • Documentation
  • Tests
  • changelog.txt
  • install.txt
  • license.txt

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

В папке Documentation содержится документация по библиотеке на английском языке. В папке Tests — примеры по использованию библиотеки.

Создание Excel-файла

Итак, давайте создадим файл makeexcel.php и начинаем работать с ним. Для начала нам необходимо подключить главный файл библиотеки PHPExcel.php (который находится в папке Classes) и создать объект класса PHPExcel:

require_once 'Classes/PHPExcel.php';
$pExcel = new PHPExcel();

Настройки листа книги Excel

Документ Excel состоит из книг, а каждая книга в свою очередь, состоит из листов. Далее лист состоит из набора ячеек, доступ к которым осуществляется по координатам. То есть у нас есть столбцы, которые имеют буквенные имена (А, В, С и т.д) и есть строки, которые пронумерованы. Значит, что бы получить доступ к первой ячейке нужно указать код А1. Точно также мы с помощью библиотеки будем получать доступ к каждой ячейке.

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

$pExcel->setActiveSheetIndex(0);
$aSheet = $pExcel->getActiveSheet();

С помощью метода setActiveSheetIndex(0) указываем индекс (номер) активного листа. Нумерация листов начинается с нуля. Далее с помощью метода getActiveSheet() получаем объект этого активного листа, то есть другими словами получаем доступ к нему для работы. И сохраняем этот объект в переменную $aSheet.

Если Вы захотите указать активным какой то другой лист, то вначале его необходимо создать, при помощи метода:

$pExcel->createSheet();

Затем, по аналогии, указываем индекс и получаем объект активного листа.

// Ориентация страницы и  размер листа
$aSheet->getPageSetup()
       ->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_PORTRAIT);
$aSheet->getPageSetup()
       ->SetPaperSize(PHPExcel_Worksheet_PageSetup::PAPERSIZE_A4);
// Поля документа
$aSheet->getPageMargins()->setTop(1);
$aSheet->getPageMargins()->setRight(0.75);
$aSheet->getPageMargins()->setLeft(0.75);
$aSheet->getPageMargins()->setBottom(1);
// Название листа
$aSheet->setTitle('Прайс-лист');
// Шапка и футер (при печати)
$aSheet->getHeaderFooter()
       ->setOddHeader('&CТД ТИНКО: прайс-лист');
$aSheet->getHeaderFooter()
       ->setOddFooter('&L&B'.$aSheet->getTitle().'&RСтраница &P из &N');
// Настройки шрифта
$pExcel->getDefaultStyle()->getFont()->setName('Arial');
$pExcel->getDefaultStyle()->getFont()->setSize(8);

Вначале задаем ориентацию листа при помощи метода setOrientation(), которому передаем константу класса PHPExcel_Worksheet_PageSetup:

  • ORIENTATION_PORTRAIT — книжная
  • ORIENTATION_LANDSCAPE — альбомная

Обратите внимание, что перед методом setOrientation() необходимо вызвать метод getPageSetup(), который предоставляет доступ к настройкам страницы.

Далее вызываем метод SetPaperSize(), который позволяет задать размер страницы для печати. Ему передаем параметром константу PAPERSIZE_A4 класса PHPExcel_Worksheet_PageSetup. Что означает, что размер листа страницы будет установлен А4.

Далее устанавливаем поля документа, то есть отступы от краев документа. Отступы задаются в специальных символьных единицах. Вначале, обратите внимание, вызываем у объекта $aSheet метод getPageMargins(), который вернет объект класса, отвечающего за настройки полей страницы. Затем вызываем методы setTop(), setRight(), setLeft() и setBottom().

Далее при помощи метода setTitle(‘Прайс лист’) задаем название нашего листа.

Если нужно, можно при печати выводить шапку и подвал листа:

  • setOddHeader();
  • setOddFooter();

Обратите внимание на передаваемые параметры:

  • для шапки передаем строку ‘&CТД ТИНКО: прайс-лист’; метка &C означает, что текст нужно расположить по центру.
  • для подвала передаем строку ‘&L&B’.$aSheet->getTitle().’&RСтраница &P из &N’; это означает, что нужно вывести слева и жирным шрифтом (&L&B) название листа (метод $aSheet->getTitle()), затем справа (&R) вывести номер страницы (&P) из общего количества страниц (&N).

Затем указываем настройки шрифта по умолчанию:

  • setName(‘Arial’) — задаем имя шрифта;
  • setSize(8) — задаем размер шрифта.

Наполнение документа данными

Для начала давайте зададим ширину столбцов (в символьных единицах), которые нам понадобятся:

$aSheet->getColumnDimension('A')->setWidth(3);
$aSheet->getColumnDimension('B')->setWidth(7);
$aSheet->getColumnDimension('C')->setWidth(20);
$aSheet->getColumnDimension('D')->setWidth(40);
$aSheet->getColumnDimension('E')->setWidth(10);

Теперь заполним несколько ячеек текстом:

$aSheet->mergeCells('A1:E1');
$aSheet->getRowDimension('1')->setRowHeight(20);
$aSheet->setCellValue('A1','ТД ТИНКО');
$aSheet->mergeCells('A2:E2');
$aSheet->setCellValue('A2','Поставка технических средств безопасности');
$aSheet->mergeCells('A4:C4');
$aSheet->setCellValue('A4','Дата создания прайс-листа');

Здесь мы сначала объеденяем ячейки с А1 до E1 при помощи метода mergeCells(), далее задаем высоту строки: вначале получаем доступ к строке 1 при помощи метода getRowDimension(‘1’), затем задаем высоту — setRowHeight(20). Далее при помощи метода setCellValue(‘A1′,’ТД ТИНКО’), устанавливаем значение ячейки А1.

Создание Excel средствами PHP

Далее давайте в ячейку D4 запишем текущую дату:

// Записываем данные в ячейку
$date = date('d-m-Y');
$aSheet->setCellValue('D4',$date);
// Устанавливает формат данных в ячейке (дата вида дд-мм-гггг)
$aSheet->getStyle('D4')->getNumberFormat()
->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX14);

С помощью констант, определенных в классе PHPExcel_Style_NumberFormat, можно задать формат ячейки: FORMAT_GENERAL (общий), FORMAT_TEXT (текст), FORMAT_NUMBER (число), FORMAT_NUMBER_00 (число с дробной частью), FORMAT_PERCENTAGE (процент), FORMAT_PERCENTAGE_00 (процент с дробной частью) и т.п.

Теперь, используя метод setCellValue(), а также цикл while() наполним данными наш прайс-лист:

mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_query('SET NAMES utf8');
mysql_select_db(DB_NAME);

// Создаем шапку таблички данных
$aSheet->setCellValue('A6','№');
$aSheet->setCellValue('B6','Код');
$aSheet->setCellValue('C6','Наименование');
$aSheet->setCellValue('D6','Описание');
$aSheet->setCellValue('E6','Цена');

$query = "SELECT `code`, `name`, `description`, `price` FROM `products` WHERE 1 LIMIT 10";
$res = mysql_query( $query );

$i = 1;
while( $prd = mysql_fetch_assoc($res) ) {
    $aSheet->setCellValue('A'.($i+6), $i);
    $aSheet->setCellValue('B'.($i+6), $prd['code']);
    $aSheet->setCellValue('C'.($i+6), $prd['name']);
    $aSheet->setCellValue('D'.($i+6), $prd['description']);
    $aSheet->setCellValue('E'.($i+6), $prd['price']);
    $i++;
}

Стилизация данных

Давайте немного украсим наш прайс-лист, то есть каждой ячейке добавим стилей. Для этого необходимо создать массив со стилями и при помощи метода applyFromArray(), применить этот массив к ячейке (или ячейкам):

// массив стилей
$style_wrap = array(
    // рамки
    'borders'=>array(
        // внешняя рамка
        'outline' => array(
            'style'=>PHPExcel_Style_Border::BORDER_THICK,
            'color' => array(
                'rgb'=>'006464'
            )
        ),
        // внутренняя
        'allborders'=>array(
            'style'=>PHPExcel_Style_Border::BORDER_THIN,
            'color' => array(
                'rgb'=>'CCCCCC'
            )
        )
    )
);

$aSheet->getStyle('A1:F'.($i+5))->applyFromArray($style_wrap);

Теперь, по аналогии, применим стили к остальным ячейкам:

// Стили для верхней надписи (первая строка)
$style_header = array(
    // Шрифт
    'font'=>array(
        'bold' => true,
        'name' => 'Times New Roman',
        'size' => 15,
        'color'=>array(
            'rgb' => '006464'
        )
    ),
    // Выравнивание
    'alignment' => array(
        'horizontal' => PHPExcel_STYLE_ALIGNMENT::HORIZONTAL_CENTER,
        'vertical' => PHPExcel_STYLE_ALIGNMENT::VERTICAL_CENTER,
    ),
    // Заполнение цветом
    'fill' => array(
        'type' => PHPExcel_STYLE_FILL::FILL_SOLID,
        'color'=>array(
            'rgb' => '99CCCC'
        )
    ),
    'borders'=>array(
        'bottom'=>array(
            'style'=>PHPExcel_Style_Border::BORDER_THIN,
            'color' => array(
                'rgb'=>'006464'
            )
        )
    )
);
$aSheet->getStyle('A1:E1')->applyFromArray($style_header);

// Стили для слогана компании (вторая строка)
$style_slogan = array(
    // шрифт
    'font'=>array(
        'bold' => true,
        'italic' => true,
        'name' => 'Times New Roman',
        'size' => 12,
        'color'=>array(
            'rgb' => '006464'
        )
    ),
    // выравнивание
    'alignment' => array(
        'horizontal' => PHPExcel_STYLE_ALIGNMENT::HORIZONTAL_CENTER,
        'vertical' => PHPExcel_STYLE_ALIGNMENT::VERTICAL_CENTER,
    ),
    // заполнение цветом
    'fill' => array(
        'type' => PHPExcel_STYLE_FILL::FILL_SOLID,
        'color'=>array(
            'rgb' => '99CCCC'
        )
    ),
    //рамки
    'borders' => array(
        'bottom' => array(
            'style'=>PHPExcel_Style_Border::BORDER_THIN,
            'color' => array(
                'rgb'=>'006464'
            )
        )
    )
);
$aSheet->getStyle('A2:E2')->applyFromArray($style_slogan);

// Стили для текта возле даты
$style_tdate = array(
    // выравнивание
    'alignment' => array(
        'horizontal' => PHPExcel_STYLE_ALIGNMENT::HORIZONTAL_RIGHT,
    ),
    // заполнение цветом
    'fill' => array(
        'type' => PHPExcel_STYLE_FILL::FILL_SOLID,
        'color'=>array(
            'rgb' => 'EEEEEE'
        )
    ),
    // рамки
    'borders' => array(
        'right' => array(
            'style'=>PHPExcel_Style_Border::BORDER_NONE
        )
    )
);
$aSheet->getStyle('A4:D4')->applyFromArray($style_tdate);
 
// Стили для даты
$style_date = array(
    // заполнение цветом
    'fill' => array(
        'type' => PHPExcel_STYLE_FILL::FILL_SOLID,
        'color'=>array(
            'rgb' => 'EEEEEE'
        )
    ),
    // рамки
    'borders' => array(
        'left' => array(
            'style'=>PHPExcel_Style_Border::BORDER_NONE
        )
    ),
);
$aSheet->getStyle('E4')->applyFromArray($style_date);
 
// Стили для шапки таблицы (шестая строка)
$style_hprice = array(
    // выравнивание
    'alignment' => array(
    'horizontal' => PHPExcel_STYLE_ALIGNMENT::HORIZONTAL_CENTER,
    ),
    // заполнение цветом
    'fill' => array(
        'type' => PHPExcel_STYLE_FILL::FILL_SOLID,
        'color'=>array(
            'rgb' => 'CFCFCF'
        )
    ),
    // шрифт
    'font'=>array(
        'bold' => true,
        /* 'italic' => true, */
        'name' => 'Times New Roman',
        'size' => 10
    ),
);
$aSheet->getStyle('A6:E6')->applyFromArray($style_hprice);

// Cтили для данных в таблице прайс-листа
$style_price = array(
    'alignment' => array(
    'horizontal' => PHPExcel_STYLE_ALIGNMENT::HORIZONTAL_LEFT,
    )
);
$aSheet->getStyle('A7:E'.($i+5))->applyFromArray($style_price);

Сохранение документа

Осталось только сохранить наш документ:

/*
$objWriter = PHPExcel_IOFactory::createWriter($pExcel, 'Excel5');
$objWriter->save('simple.xls');
*/
$objWriter = PHPExcel_IOFactory::createWriter($pExcel, 'Excel2007');
$objWriter->save('simple.xlsx');

или так

/*
$objWriter = new PHPExcel_Writer_Excel5($pExcel);
$objWriter->save('simple.xls');
*/
$objWriter = new PHPExcel_Writer_Excel2007($pExcel);
$objWriter->save('simple.xlsx');

Если нужно вывести документ в браузер

/*
header('Content-Type:application/vnd.ms-excel');
header('Content-Disposition:attachment;filename="simple.xls"');
$objWriter = new PHPExcel_Writer_Excel5($pExcel);
*/
header('Content-Type:xlsx:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition:attachment;filename="simple.xlsx"');
$objWriter = new PHPExcel_Writer_Excel2007($pExcel);
$objWriter->save('php://output');

Первый заголовок указывает браузеру тип открываемого контента — это документ формата Excel. Второй — говорит браузеру, что документ необходимо отдать пользователю на скачивание под именем simple.xlsx.

Добавление формул

Формула Excel — это математическое выражение, которое создается для вычисления результата и которое может зависеть от содержимого других ячеек. Формула в ячейке Excel может содержать данные, ссылки на другие ячейки, а также обозначение действий, которые необходимо выполнить.

Использование ссылок на ячейки позволяет пересчитывать результат по формулам, когда происходят изменения содержимого ячеек, включенных в формулы. Формулы Excel начинаются со знака =. Скобки ( ) могут использоваться для определения порядка математических операции.

Примеры формул Excel: =27+36, =А1+А2-АЗ, =SUM(А1:А5), =MAX(АЗ:А5), =(А1+А2)/АЗ.

PHPExcel тоже поддерживает добавление формул в ячейки. Установить формулу можно так:

// формула для вычисления суммы
$formula = '=SUM(D2:D4)';
$aSheet->setCellValue('D5', $formula);

Добавление формул

Чтение Excel-файла

Самый простой вариант — считать все таблицы (на всех листах) и записать данные в трехмерный массив:

// Подключаем библиотеку
require_once 'Classes/PHPExcel.php';
$pExcel = PHPExcel_IOFactory::load('simple.xlsx');

// Цикл по листам Excel-файла
foreach ($pExcel->getWorksheetIterator() as $worksheet) {
    // выгружаем данные из объекта в массив
    $tables[] = $worksheet->toArray();
}

Теперь можно вывести массив:

// Цикл по листам Excel-файла
foreach( $tables as $table ) {
    echo '<table border="1">';
    // Цикл по строкам
    foreach($table as $row) {
        echo '<tr>';
        // Цикл по колонкам
        foreach( $row as $col ) {
            echo '<td>'.$col.'</td>';
        }
        echo '</tr>';
    }
    echo '</table>';
}

Для получения значения отдельной ячейки:

// выбираем лист, с которым будем работать
$pExcel->setActiveSheetIndex(0);
$aSheet = $pExcel->getActiveSheet();
// получаем доступ к ячейке по номеру строки 
// (нумерация с единицы) и столбца (нумерация с нуля) 
$cell = $aSheet->getCellByColumnAndRow($col, $row);
// читаем значение ячейки
$value = $cell->getValue()

или так:

$value = $pExcel->getActiveSheet()->getCellValue('B2')

Еще два примера:

// Цикл по листам Excel-файла
foreach( $pExcel->getWorksheetIterator() as $worksheet ) {
    echo '<h2>Лист «'.$worksheet->getTitle().'»</h2>';
    echo '<table border="1">';
    // Цикл по строкам
    foreach( $worksheet->getRowIterator() as $row ) {
        echo '<tr>';
        // Цикл по колонкам
        foreach( $row->getCellIterator() as $cell ) {
            $value = $cell->getValue();
            // $calcValue = $cell->getCalculatedValue()
            // $dataType = PHPExcel_Cell_DataType::dataTypeForValue($value);
            echo '<td>'.$value.'</td>';
        }
        echo '</tr>';
    }
    echo '</table>';
}
// Цикл по листам Excel-файла
foreach ($pExcel->getWorksheetIterator() as $worksheet) {
    $worksheetTitle     = $worksheet->getTitle();
    $highestRow         = $worksheet->getHighestRow(); // например, 10
    $highestColumn      = $worksheet->getHighestColumn(); // например, 'E'
    $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn);
    $nrColumns = ord($highestColumn) - 64;
    echo '<h2>Лист «'.$worksheetTitle.'» ';
    echo $nrColumns . ' колонок (A-' . $highestColumn . ') ';
    echo ' и ' . $highestRow . ' строк.</h2>';
    echo '<table border="1">';
    // Цикл по строкам
    for ($row = 1; $row <= $highestRow; $row++) {
        echo '<tr>';
        // Цикл по колонкам
        for ($col = 0; $col < $highestColumnIndex; $col++) {
            $cell = $worksheet->getCellByColumnAndRow($col, $row);
            echo '<td>'.$cell->getValue().'</td>';
        }
        echo '</tr>';
    }
    echo '</table>';
}

Дополнительно

  • Документация разработчика PHPExcel на русском
  • Блог на Laravel 7, часть 17. Временная зона для пользователей, деплой на хостинг TimeWeb
  • Блог на Laravel 7, часть 16. Роль нового пользователя, сообщение админу о новом посте
  • Блог на Laravel 7, часть 15. Восстановление постов, slug для категории, поста и страницы
  • Блог на Laravel 7, часть 14. Валидация данных и права доступа при загрузке изображений
  • Блог на Laravel 7, часть 13. Загрузка и ресайз изображений для категорий и постов блога
  • Блог на Laravel 7, часть 12. Доп.страницы сайта в панели управления и в публичной части
  • Блог на Laravel 7, часть 11. Панель управления — назначение ролей и прав для пользователей

Поиск:
Excel • MS • PHP • Web-разработка

Каталог оборудования

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Производители

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Функциональные группы

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

К сожалению разработчики прекратили поддержку и разработку проекта, но PHPExcel все равно остается популярной библиотекой которая выполняет свои задачи, последняя версия нормально работает на PHP 7.

Проект на GitHub.

1

Создание документа

require_once __DIR__ . '/PHPExcel-1.8/Classes/PHPExcel.php';
require_once __DIR__ . '/PHPExcel-1.8/Classes/PHPExcel/Writer/Excel2007.php';

$xls = new PHPExcel();

PHP

Если нужно открыть существующий файл:

require_once __DIR__ . '/PHPExcel-1.8/Classes/PHPExcel.php';
require_once __DIR__ . '/PHPExcel-1.8/Classes/PHPExcel/Writer/Excel2007.php';
require_once __DIR__ . '/PHPExcel-1.8/Classes/PHPExcel/IOFactory.php';

$xls = PHPExcel_IOFactory::load(__DIR__ . '/file.xlsx');

PHP

Установка сводки документа:

$xls->getProperties()->setTitle("Название");
$xls->getProperties()->setSubject("Тема");
$xls->getProperties()->setCreator("Автор");
$xls->getProperties()->setManager("Руководитель");
$xls->getProperties()->setCompany("Организация");
$xls->getProperties()->setCategory("Группа");
$xls->getProperties()->setKeywords("Ключевые слова");
$xls->getProperties()->setDescription("Примечания");
$xls->getProperties()->setLastModifiedBy("Автор изменений");
$xls->getProperties()->setCreated("25.03.2019");

PHP

Защита книги паролем:

$xls->getActiveSheet()->getProtection()->setSheet(true);
$xls->getActiveSheet()->getProtection()->setSort(true);
$xls->getActiveSheet()->getProtection()->setInsertRows(true);
$xls->getActiveSheet()->getProtection()->setFormatCells(true);
$xls->getActiveSheet()->getProtection()->setPassword('123456');

PHP

Создаем новый лист, далее работаем с ним через переменную $sheet.

$xls->setActiveSheetIndex(0);
$sheet = $xls->getActiveSheet();
$sheet->setTitle('Название листа');

PHP

Параметры печати

// Формат
$sheet->getPageSetup()->SetPaperSize(PHPExcel_Worksheet_PageSetup::PAPERSIZE_A4);

// Ориентация
// ORIENTATION_PORTRAIT — книжная
// ORIENTATION_LANDSCAPE — альбомная
$sheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_PORTRAIT);

// Поля
$sheet->getPageMargins()->setTop(1);
$sheet->getPageMargins()->setRight(0.75);
$sheet->getPageMargins()->setLeft(0.75);
$sheet->getPageMargins()->setBottom(1);

// Верхний колонтитул
$sheet->getHeaderFooter()->setOddHeader("Название листа");

// Нижний колонтитул
$sheet->getHeaderFooter()->setOddFooter('&L&B Название листа &R Страница &P из &N');

PHP

Запись в ячейку и ее формат

$sheet->setCellValue("A1", "Значение");

PHP

Формат ячеек определяется автоматически, иногда это вызывает проблемы. Например, значения 1., 10.0, 0.1 выведутся как 1, 10, 0,1. Чтобы это исправить нужно использовать метод setCellValueExplicit() в место setCellValue().

$sheet->setCellValueExplicit("A1", '1.', PHPExcel_Cell_DataType::TYPE_STRING);
$sheet->setCellValueExplicit("A2", '10.0', PHPExcel_Cell_DataType::TYPE_STRING);
$sheet->setCellValueExplicit("A3", '0.1', PHPExcel_Cell_DataType::TYPE_STRING);

PHP

2

Размеры ячеек

Ширина столбцов

// Ширина столбца A 
$sheet->getColumnDimension("A")->setWidth(100);

// Авто ширина колонки по содержимому
$sheet->getColumnDimensionByColumn("A")->setAutoSize(true);

PHP

Высота строк

// Высота 1-й строки
$sheet->getRowDimension("1")->setRowHeight(50);

PHP

Вставленный в ячейку длинный текст будет выходить за ее пределы, переносы rn работать не будут.

$sheet->setCellValue("A1", "Excel — программа rn для работы с электронными таблицами");

PHP

Метод setWrapText(true) включает переносы строк и авто высоту.

$sheet->setCellValue("A1", "Excel — программа rn для работы с электронными таблицами");
$sheet->getStyle("A1")->getAlignment()->setWrapText(true);

PHP

3

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

// Объединение ячеек в колонке
$sheet->mergeCells("A1:A6");
$sheet->setCellValue("A1", "A1:A6");

// Объединение ячеек в строке
$sheet->mergeCells("C2:I2");
$sheet->setCellValue("C2", "C2:I2");

// Объединение ячеек по диапазону
$sheet->mergeCells("C4:I6");
$sheet->setCellValue("C4", "C4:I6");

PHP

Объединение ячеек PHPExcel

4

Стили текста

// Шрифт Times New Roman
$sheet->getStyle('A1')->getFont()->setName('Times New Roman');

// Размер шрифта 18
$sheet->getStyle("A2")->getFont()->setSize(18);

// Цвет шрифта
$sheet->getStyle("A3")->getFont()->getColor()->setRGB('ff0000');

// Жирный
$sheet->getStyle("A4")->getFont()->setBold(true);

// Курсив
$sheet->getStyle("A5")->getFont()->setItalic(true);

// Подчеркнутый текст
$sheet->getStyle("A6")->getFont()->setUnderline(true);

// Зачеркнутый текст
$sheet->getStyle("A7")->getFont()->setStrikethrough(true);

PHP

Стили текста PHPExcel

Также можно задать сразу несколько стилей для ячейки, массивом:

$style = array(
	'font' => array(
		'name'      => 'Times New Roman',
		'size'      => 18,   
		'color'     => array('rgb' => 'FF0000'),              
		'bold'      => true,
		'italic'    => true,
		'underline' => true,
		'strike'    => true,
	)
);

$sheet->getStyle('A1')->applyFromArray($style);

PHP

Установить стили шрифта для всего документа:

$sheet->getDefaultStyle()->getFont()->setName('Times New Roman');
$sheet->getDefaultStyle()->getFont()->setSize(18);

PHP

Или:

$style = array(
	'font' => array(
		'name' => 'Times New Roman',
		'size' => 18,  
	)
);

$sheet->getDefaultStyle()->applyFromArray($style);

PHP

5

Выравнивание в ячейке

По горизонтали:

// По левому краю
$sheet->getStyle("A1")->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);

// По центру
$sheet->getStyle("A1")->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);

// По правому краю
$sheet->getStyle("A1")->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);

PHP

По вертикали:

// Сверху
$sheet->getStyle("A1")->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_TOP);

// По центру
$sheet->getStyle("A1")->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);

// Снизу
$sheet->getStyle("A1")->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_BOTTOM);

PHP

6

Фон ячейки

Стили фона устанавливаются массивом значений, type – определяет стиль заливки, далее в зависимости от выбранного стиля задаются его настройки в параметрах color, startcolor, endcolor, rotation.

PHPExcel_Style_Fill::FILL_SOLID

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_SOLID,
		'color' => array('rgb' => '01B050')
	)
);
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_SOLID

PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
		'rotation' => 90
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR

PHPExcel_Style_Fill::FILL_GRADIENT_PATH

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_GRADIENT_PATH,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_GRADIENT_PATH

PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN

PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY

PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID

PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL

PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS

PHPExcel_Style_Fill::FILL_PATTERN_DARKUP

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_DARKUP,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_DARKUP

PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL

PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625

PHPExcel_Style_Fill::FILL_PATTERN_GRAY125

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_GRAY125,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_GRAY125

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL

PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY

$bg = array(
	'fill' => array(
		'type' => PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY,
		'startcolor' => array('rgb' => '01B050'),
		'endcolor' => array('rgb' => 'f1ee3b'),
	)
);                 
$sheet->getStyle("B2")->applyFromArray($bg);

PHP

PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY

7

Границы

Стили линий задаются костантами:

Вид Константа
PHPExcel_Style_Border::BORDER_NONE
PHPExcel_Style_Border::BORDER_THIN
PHPExcel_Style_Border::BORDER_MEDIUM
PHPExcel_Style_Border::BORDER_THICK
PHPExcel_Style_Border::BORDER_DOUBLE
PHPExcel_Style_Border::BORDER_HAIR
PHPExcel_Style_Border::BORDER_DOTTED
PHPExcel_Style_Border::BORDER_DASHED
PHPExcel_Style_Border::BORDER_DASHDOT
PHPExcel_Style_Border::BORDER_DASHDOTDOT
PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT
PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT
PHPExcel_Style_Border::BORDER_MEDIUMDASHED
PHPExcel_Style_Border::BORDER_SLANTDASHDOT

Внешняя рамка у ячеек

$border = array(
	'borders'=>array(
		'outline' => array(
			'style' => PHPExcel_Style_Border::BORDER_THIN,
			'color' => array('rgb' => '000000')
		),
	)
);

$sheet->getStyle("B2:J5")->applyFromArray($border);

PHP

Внешняя рамка у ячеек

Внутриния рамка у ячеек

$border = array(
	'borders'=>array(
		'inside' => array(
			'style' => PHPExcel_Style_Border::BORDER_THIN,
			'color' => array('rgb' => '000000')
		),
	)
);

$sheet->getStyle("B2:J5")->applyFromArray($border);

PHP

Внутриния рамка у ечеек

Таблица

$border = array(
	'borders'=>array(
		'allborders' => array(
			'style' => PHPExcel_Style_Border::BORDER_THIN,
			'color' => array('rgb' => '000000')
		)
	)
);

$sheet->getStyle("B2:J5")->applyFromArray($border);

PHP

Таблица

Таблица с жирной рамкой

$border = array(
	'borders'=>array(
		'outline' => array(
			'style' => PHPExcel_Style_Border::BORDER_THICK,
			'color' => array('rgb' => '000000')
		),
		'allborders' => array(
			'style' => PHPExcel_Style_Border::BORDER_THIN,
			'color' => array('rgb' => '000000')
		)
	)
);

$sheet->getStyle("B2:J5")->applyFromArray($border);

PHP

Таблица с жирной рамкой

Отдельные линии

            case '':
			case 'bottom':
			case 'diagonal':
			case 'horizontal':
			case '':
			case 'left':
			case '':
			case 'right':
			case 'top':
			case 'vertical':

Сверху:

$border = array(
	'borders'=>array(
		'top' => array(
			'style' => PHPExcel_Style_Border::BORDER_THIN,
			'color' => array('rgb' => '000000')
		)
	)
);
$sheet->getStyle("B2")->applyFromArray($border);

PHP

Снизу:

$border = array(
	'borders'=>array(
		'bottom' => array(
			'style' => PHPExcel_Style_Border::BORDER_THIN,
			'color' => array('rgb' => '000000')
		)
	)
);
$sheet->getStyle("B4")->applyFromArray($border);

PHP

Слева:

$border = array(
	'borders'=>array(
		'left' => array(
			'style' => PHPExcel_Style_Border::BORDER_THIN,
			'color' => array('rgb' => '000000')
		)
	)
);
$sheet->getStyle("B6")->applyFromArray($border);

PHP

Справа:

$border = array(
	'borders'=>array(
		'right' => array(
			'style' => PHPExcel_Style_Border::BORDER_THIN,
			'color' => array('rgb' => '000000')
		)
	)
);
$sheet->getStyle("B8")->applyFromArray($border);

PHP

Отдельные линии

8

Изображения

$objDrawing = new PHPExcel_Worksheet_Drawing();
$objDrawing->setResizeProportional(false);  
$objDrawing->setName('Название картинки');
$objDrawing->setDescription('Описание картинки');
$objDrawing->setPath(__DIR__ . '/logo.png');
$objDrawing->setCoordinates('B2');                      
$objDrawing->setOffsetX(10); 
$objDrawing->setOffsetY(10);                
$objDrawing->setWidth(163); 
$objDrawing->setHeight(50); 
$objDrawing->setWorksheet($sheet);

PHP

Изображения в PHPExcel

9

$sheet->setCellValue("A1", "Ссылка на example.com");
$sheet->getCell("A1")->getHyperlink()->setUrl("http://example.com");
$sheet->getCell("A1")->getHyperlink()->setTooltip('Подсказка');

// У текста нужно сделать синий цвет и подчеркивание
$sheet->getStyle("A1")->applyFromArray(
	array(
		'font' => array(
			'color' => array(
				'rgb' => '0000FF'
			), 
			'underline' => 'single'
		)
	)
);

PHP

Гиперссылка в PHPExcel

10

Формулы

Русские названия функций не поддерживаются, придется использовать латинские аналоги.

$sheet->setCellValue("A3", "=SUM(A1:A2)");

PHP

СУММ SUM Cуммирование значений в ячейках
ЕСЛИ IF Условие
ПРОСМОТР LOOKUP Поиск по значению
ВПР VLOOKUP Поиск значения по диапазону
ПОИСКПОЗ MATCH Поиск положенияв диапазоне ячеек
ВЫБОР CHOOSE Выбор одного значения из списка
ДАТА DATE Возвращает порядковый номер определенной даты
ДНИ DAYS Возвращает число дней между двумя датами
НАЙТИ, НАЙТИБ FIND, FINDB Поиск вхождения одной строки в другую
ИНДЕКС INDEX Возвращает значение или ссылку на него из таблицы или диапазона

11

Сохранение

XLSX

Отдача на скачивание:

header("Expires: Mon, 1 Apr 1974 05:00:00 GMT");
header("Last-Modified: " . gmdate("D,d M YH:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
header("Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Disposition: attachment; filename=file.xlsx");

$objWriter = new PHPExcel_Writer_Excel2007($xls);
$objWriter->save('php://output'); 
exit();	

PHP

Если возникает ошибка – «Uncaught exception 'PHPExcel_Writer_Exception' with message 'Could not close zip file php://output.'», то следует сделать скачивание через временный файл:

header("Expires: Mon, 1 Apr 1974 05:00:00 GMT");
header("Last-Modified: " . gmdate("D,d M YH:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
header("Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Disposition: attachment; filename=file.xlsx");

$file_path = __DIR__ . "/xlsx.tmp";
$objWriter = new PHPExcel_Writer_Excel2007($xls);
$objWriter->save($file_path);
readfile($file_path);
unlink($file_path);
exit();

PHP

Сохранение в файл:

$objWriter = new PHPExcel_Writer_Excel2007($xls);
$objWriter->save(__DIR__ . '/file.xlsx');

PHP

XLS (Excel 97-2004)

Отдача на скачивание:

header("Expires: Mon, 1 Apr 1974 05:00:00 GMT");
header("Last-Modified: " . gmdate("D,d M YH:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
header("Content-type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=file.xls");
	
$objWriter = new PHPExcel_Writer_Excel5($xls);
$objWriter->save('php://output'); 
exit();	

PHP

Сохранение в файл:

$objWriter = new PHPExcel_Writer_Excel5($xls);
$objWriter->save(__DIR__ . '/file.xls');

PHP

PhpSpreadsheet

Build Status
Code Quality
Code Coverage
Total Downloads
Latest Stable Version
License
Join the chat at https://gitter.im/PHPOffice/PhpSpreadsheet

PhpSpreadsheet is a library written in pure PHP and offers a set of classes that
allow you to read and write various spreadsheet file formats such as Excel and LibreOffice Calc.

PHP Version Support

LTS: Support for PHP versions will only be maintained for a period of six months beyond the
end of life of that PHP version.

Currently the required PHP minimum version is PHP 7.4, and we will support that version until 28th June 2023.

See the composer.json for other requirements.

Installation

Use composer to install PhpSpreadsheet into your project:

composer require phpoffice/phpspreadsheet

If you are building your installation on a development machine that is on a different PHP version to the server where it will be deployed, or if your PHP CLI version is not the same as your run-time such as php-fpm or Apache’s mod_php, then you might want to add the following to your composer.json before installing:

{
    "require": {
        "phpoffice/phpspreadsheet": "^1.28"
    },
    "config": {
        "platform": {
            "php": "7.4"
        }
    }
}

and then run

to ensure that the correct dependencies are retrieved to match your deployment environment.

See CLI vs Application run-time for more details.

Additional Installation Options

If you want to write to PDF, or to include Charts when you write to HTML or PDF, then you will need to install additional libraries:

PDF

For PDF Generation, you can install any of the following, and then configure PhpSpreadsheet to indicate which library you are going to use:

  • mpdf/mpdf
  • dompdf/dompdf
  • tecnickcom/tcpdf

and configure PhpSpreadsheet using:

// Dompdf, Mpdf or Tcpdf (as appropriate)
$className = PhpOfficePhpSpreadsheetWriterPdfDompdf::class;
IOFactory::registerWriter('Pdf', $className);

or the appropriate PDF Writer wrapper for the library that you have chosen to install.

Chart Export

For Chart export, we support following packages, which you will also need to install yourself using composer require

  • jpgraph/jpgraph (this package was abandoned at version 4.0.
    You can manually download the latest version that supports PHP 8 and above from jpgraph.net)
  • mitoteam/jpgraph (fork with php 8.1 support)

and then configure PhpSpreadsheet using:

// to use jpgraph/jpgraph
Settings::setChartRenderer(PhpOfficePhpSpreadsheetChartRendererJpGraph::class);
//or
// to use mitoteam/jpgraph
Settings::setChartRenderer(PhpOfficePhpSpreadsheetChartRendererMtJpGraphRenderer::class);

One or the other of these libraries is necessary if you want to generate HTML or PDF files that include charts; or to render a Chart to an Image format from within your code.
They are not necessary to define charts for writing to Xlsx files.
Other file formats don’t support writing Charts.

Documentation

Read more about it, including install instructions, in the official documentation. Or check out the API documentation.

Please ask your support questions on StackOverflow, or have a quick chat on Gitter.

Patreon

I am now running a Patreon to support the work that I do on PhpSpreadsheet.

Supporters will receive access to articles about working with PhpSpreadsheet, and how to use some of its more advanced features.

Posts already available to Patreon supporters:

  • The Dating Game
    • A look at how MS Excel (and PhpSpreadsheet) handle date and time values.
  • Looping the Loop
    • Advice on Iterating through the rows and cells in a worksheet.

And for Patrons at levels actively using PhpSpreadsheet:

  • Behind the Mask
    • A look at Number Format Masks.

The Next Article (currently Work in Progress):

  • Formula for Success
    • How to debug formulae that don’t produce the expected result.

My aim is to post at least one article each month, taking a detailed look at some feature of MS Excel and how to use that feature in PhpSpreadsheet, or on how to perform different activities in PhpSpreadsheet.

Planned posts for the future include topics like:

  • Tables
  • Structured References
  • AutoFiltering
  • Array Formulae
  • Conditional Formatting
  • Data Validation
  • Value Binders
  • Images
  • Charts

After a period of six months exclusive to Patreon supporters, articles will be incorporated into the public documentation for the library.

PHPExcel vs PhpSpreadsheet ?

PhpSpreadsheet is the next version of PHPExcel. It breaks compatibility to dramatically improve the code base quality (namespaces, PSR compliance, use of latest PHP language features, etc.).

Because all efforts have shifted to PhpSpreadsheet, PHPExcel will no longer be maintained. All contributions for PHPExcel, patches and new features, should target PhpSpreadsheet master branch.

Do you need to migrate? There is an automated tool for that.

License

PhpSpreadsheet is licensed under MIT.

Программирование, Разработка под Windows, Ненормальное программирование, PHP, ООП


Рекомендация: подборка платных и бесплатных курсов таргетированной рекламе — https://katalog-kursov.ru/

Не секрет, что зачастую PHP-программистам приходится решать задачи, весьма далёкие от бытового представления о «веб-разработке». Развитие языка в последние годы привело к тому, что PHP всё чаще считают языком общего назначения, пригодным не только для сайтов, но и для других задач.

Одну из таких «других» задач мне с коллективом пришлось решать совсем недавно. Мы решили поделиться «картой граблей» с теми, кто, возможно, пойдет по этому же пути.

Дано

  • Многие наши партнёры (скажем прямо — это крупные банки) любят считать что-то в Excel. Причем «любят» — это очень нежно сказано. Сложнейшие скоринговые модели могут быть «запрограммированы» в Excel, в файле из сотни листов с десятками макросов
  • Перевести «программы», написанные в Excel на какой-либо язык программирования — практически нереально. Это займет уйму времени, а проблема постоянного обновления и проверки корректности делает такую задачу и вовсе нерешаемой

Требуется

  • Основная информационная система нашей компании написана на PHP. Она содержит в себе как веб-интерфейсы, так и множество консольных сервисов и воркеров.
  • С этими «программами» в Excel нужно как-то взаимодействовать из консольных приложений на PHP — передавать в них данные, обсчитывать, получать результаты

Некоторое время нам хватало возможностей популярной библиотеки PHPExcel. Но когда от бизнеса поступило очередное требование «нужно, чтобы работали макросы, и еще бы хорошо всё это сохранять в PDF», стало понятно, что выбранный путь — тупиковый. Нужно не парсить файлы xlsx, не имитировать просчёт, и даже не использовать Open Office, а научиться взаимодействовать с «настоящим» Microsoft Excel.

В результате недолгих изысканий было решено создать внутренний микро-веб-сервис, который умел бы принять данные, открыть указанный файл Excel, вставить в него принятые данные, просчитать результат и выдать его в качестве ответа клиенту. Заинтересованность в таком веб-сервисе выразили несколько внутренних проектов и работа закипела.

Сервер под Windows? А почему бы нет!

Первым под удар попал отдел dev-ops. Им предстояло подготовить сервер для будущего сервиса. Дело было необычным, поскольку актуального опыта работы с Windows ни у кого нет…

В качестве серверной платформы был выбран Windows Server 2012 R2 standart. Нужно сразу отметить, что «из коробки» Windows совершенно не приспособлена к хостингу приложений на PHP. Требовалось доведение системы до нужного уровня.

Для начала был установлен PowerShellServer. Это позволило нам подключаться к windows-серверу по привычному всем протоколу ssh, не изобретая велосипедов. Поддерживается авторизация по ключам, работает rsync (это важно). Жаль, что в Personal Edition ограничение только на одно одновременное подключение, но для нас это некритично.

Nginx был установлен штатным образом. Взят со страницы nginx.org/ru/download.html Имейте в виду — под windows есть существенные ограничения: только один рабочий процесс, который держит не более 1024 соединений. Впрочем, это опять же было некритично для внутреннего микро-сервиса.

PHP 7.0.9 взят с windows.php.net/download, установлен штатным образом.

Для упрощения перезапуска всего этого «добра» был написан несложный cmd-файл:

cd C:nginx
taskkill /f /IM nginx.exe
taskkill /f /IM php-cgi.exe
 
rm C:nginxlogs*
start nginx
start -WindowStyle Hidden phpphp-cgi -A "-b 0.0.0.0:9000 -c C:serverphpphp.ini"

Первоначальная настройка сервера закончилась успешным выводом страницы с phpinfo(). Однако это было еще только самое начало…

Настраиваем сборку на Windows или Как наступить на все подводные камни?

Мы внутри компании используем Continuous Integration. Всегда. Для любого, сколь угодно малого проекта. Примерный план развертывания выглядит так:

  • Сервер Teamcity следит за изменениями в нужных ветках репозитория (в данном конкретном случае workflow был упрощен до предела и ветка была фактически одна — master)
  • Он же запускает сборку проекта при появлении изменений:
    • Содержимое репозитория с сервера TeamCity с помощью rsync доставляется на целевой сервер, во временную папку (это даёт нам возможность сэкономить на агентах TeamCity)
    • Там же, с помощью ssh, запускается билд-скрипт на phing, который и делает основную работу:
      • Переносит код в постоянное место
      • Устанавливает зависимости через composer
      • Раскладывает конфиги
      • Применяет миграции и так далее…
      • И, наконец, переключает симлинк current (это у нас wwwroot), на новую папку

Что потребовалось далее? ssh-сервер уже установлен, rsync выполняется корректно. Установим phing:

  • Исполняемый файл (phing.phar) берем с www.phing.info/trac/wiki/Users/Installation
  • Аккуратный и красивый bat-ник можно взять на www.phing.info/trac/browser/bin/phing.bat
  • Не забываем добавить путь до phing в PATH, чтобы получить system-wide команду

Git for Windows берем с git-scm.com, устанавливаем, проверяем корректную работу.

Точно по такой же схеме поступаем с composer, только bat-файл пишем сами и он будет значительно проще:

@echo off
if "%PHPBIN%" == "" set PHPBIN=C:serverphpphp.exe
"%PHPBIN%" "C:nginxphpcomposer.phar" %*

Вроде бы всё готово. Запускаем сборку… fail!

Причина 1. Нужно установить расширение php_openssl.dll, иначе Phing не сможет работать с репозиториями через SSL. Проблем не доставило.

Причина 2. Более серьезная. В нашем сценарии сборки используется техника переключения симлинка на папку со свежей сборкой на последнем шаге. Примерно так:

<symlink target="${current.dir}" link="${home.dir}/${build.branch}/current" overwrite="true" />

В результате получается что-то вроде
symlink: "c:serverdomainsthis.servicemastercurrent" => "c:serverdomainsthis.servicemaster2016-04-01-12-34-56"

Оказалось, что создать символическую ссылку на NTFS — не проблема. Проблема ее удалить… Отчего-то операция удаления симлинка требует прав администратора, которых у обычного PHP нет и быть не может.

Нам помогла утилита junction ( technet.microsoft.com/en-us/sysinternals/bb896768 ). С ней вышеуказанный кусок сценария стал выглядеть примерно так:

<exec command="junction -d  ${home.dir}/${build.branch}/current" checkreturn="true" passthru="true" />
<symlink target="${current.dir}" link="${home.dir}/${build.branch}/current" overwrite="true" />

Итак, всё встало на свои места, сборка заработала, как ей и положено. Настала пора писать код!

COM-объекты в PHP

Надо отметить, что собственно код сервиса не доставил никаких проблем.

Как запустить приложение Microsoft Excel и загрузить в приложение существующий файл?

namespace AppComponents;

class Excel
{

    protected $xls;
    
    public function __construct($filename = null)
    {
        $this->xls = new COM("Excel.Application");
        // @todo: выключить, если не требуется видеть работу приложения
        $this->xls->Application->Visible = 1;
        $this->xls->DisplayAlerts = 0;
        if (empty($filename)) {
            $this->xls->Workbooks->Add();
        } else {
            $this->xls->Workbooks->Open($filename);
        }
        $this->xls->Workbooks[1]->Activate();
    }
}

Как закрыть приложение после окончания работы скрипта?

    public function __destruct()
    {
        $this->xls->Workbooks[1]->Close(false);
        $this->xls->Quit();
    }

Получить список всех именованных диапазонов?

    public function getNames()
    {
        $names = $this->xls->Names;
        if ($names->Count == 0) {
            return [];
        } else {
            $ret = [];
            foreach ($names as $name) {
                $ret[$name->Name] = $name->Value;
            }
            return $ret;
        }
    }

Установить значение ячейки или диапазона?

    public function setValue($range, $value)
    {
        $this->xls->Range($range)->Value = iconv('UTF-8', 'Windows-1251', $value);
    }

Прочесть значение из ячейки или диапазона?
Возвращается либо скалярное значение из одной ячейки, либо массив значений, если мы запрашиваем диапазон.

    public function getValue($range)
    {
        $range = $this->xls->Range($range);
        if ($range->Count == 1) {
            $val = $range->Value;
            return is_string($val) ? iconv('Windows-1251', 'UTF-8', $val) : $val;
        } else {
            $ret = [];
            foreach ($range as $cell) {
                $val = $cell->Value;
                $ret[$cell->Address] = is_string($val) ? iconv('Windows-1251', 'UTF-8', $val) : $val;
            }
            return $ret;
        }
    }

Экспортировать книгу в PDF?

    const FORMATS = [
        'PDF' => 0
    ];

    public function saveAs($filename, $format = self::FORMATS['PDF'])
    {
        // Будь проклят тот день, когда разработчики MS-DOS придумали обратные слэши!
        $this->xls->Workbooks[1]->ExportAsFixedFormat($format, str_replace('/', '\', $filename));
    }

Что надо сделать, чтобы вся эта безумная магия заработала?
Добавить расширение php_com_dotnet.dll

Вместо заключения

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

Удачи и не наступайте на те же грабли!

Литература

  1. php.net/manual/en/book.com.php
  2. msdn.microsoft.com/ru-ru/library/wss56bz7.aspx
  3. geektimes.ru/post/50878

P.S.

По итогам обсуждения в комментариях я решил добавить к статье несколько важных дополнений.

1. Нет, задача не сводится к тому, чтобы какой-то библиотекой для PHP уметь писать в файлы формата Excel или читать данные из них. Статья не об этом. Задача — запускать расчеты, алгоритм которых задан извне в виде файлов Excel (и нет никакой возможности алгоритм преобразовать во что-то другое), подавать на вход данные, получать ответы, формировать отчет. Для этой цели нет другого решения, кроме как запустить файл в «родном» приложении Microsoft Excel.

2. Файлов — сотни. Запросов на расчеты (то есть на запуск таких файлов) — тысячи в день. Это приводит нас к невозможности решения «а пусть кто-то сам вручную запускает эти файлы». Требуется полная и надежная автоматизация.

3. См. предыдущий пункт. Перевод алгоритмов на какой-либо язык программирования невозможен, поскольку затраты на верификацию и QA превысят затраты на windows-сервер на три порядка.

4. Веб-сервис написан для использования другими сервисами, а не клиентами-людьми.

5. Немного изменил метод public function getValue($range), чтобы показать, как прочесть диапазон ячеек, как одно целое. Добавил метод получения списка всех именованных диапазонов.

Author: Viewers: 2,443Last month viewers: 135Categories: PHP Tutorials

Microsoft Excel is the most popular spreadsheet program in the world. This is why many Web applications need to provide means to export or import files in Microsoft format.

In general reading and writing Excel files is not a trivial task. However Ignatius Teo had a brilliant idea of using PHP streams to read and write Excel files just and simple and reading and writing arrays of data.

Read this article to learn how to use the MS-Excel Stream Handler class to read and write Excel files from the xls:// stream.

Loaded Article

Contents

Read and Write Microsoft Excel Spreadsheet Files

Introduction to MS Excel XLS files

PHP support for Stream Handling

Read Data from a XLS Stream

Conclusion

Read and Write Microsoft Excel Spreadsheet Files

Spreadsheets are an interactive computer application programs for organization, analysis and storage of data in tabular form.

One of the most popular ones is Microsoft Excel. It used the XLS binary file format as a default one until 2007 version. Even though it was 8 years ago when Microsoft moved to XML based technology, a lot of people still use the old version. So this will show you how to benefit from PHP’s power of reading xls stream.

This article is split in two parts. The first part will talk a little bit about the theory and then show how to read and download data from XLS. The second part will show how to write data to an XLS file on the server.

Microsoft Excel 2013 Default Screen Small

Introduction to MS Excel XLS files

XLS is a file extension for a spreadsheet file format created by Microsoft for use with Microsoft Excel. XLS stands for eXceL Spreadsheet and has a Binary File Format structure, so it is very hard to read and edit like plain texts as XML or text files. XLS files can be read by Microsoft Excel, Microsoft Excel Viewer and OpenOffice.

Binary Files like XLS file format are stored in a simple stream file. That is why we will use PHP stream capabilities to read and write XLS’s.

PHP support for Stream Handling

As it is stated in PHP.net website: «Streams were introduced with PHP 4.3.0 as a way of generalizing file, network, data compression, and other operations which share a common set of functions and uses.». That opened a new way to manipulate with data files.

A stream is referenced as: scheme://target, for example (file://path-to-file, http://path-to-url, https://path-to-url, ftp://path-to-server, ftps://path-to-server). And of course what we will use for this example «xlsfile://path-to-file».

Let’s now take a look how to use PHP to read and write XLS files.

Read Data from a XLS Stream

First you will need to download Ignatius Teo’s class. Now create a file named example.php and paste this code in it:

<?php
 require_once "excel.php";
 $export_file = "xlsfile://example.xls";
 header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
 header ("Last-Modified: " . gmdate("D,d M YH:i:s") . " GMT");
 header ("Cache-Control: no-cache, must-revalidate");
 header ("Pragma: no-cache");
 header ("Content-type: application/x-msexcel");
 header ("Content-Disposition: attachment; filename="" . basename($export_file) . """ );
 header ("Content-Description: PHP/INTERBASE Generated Data" );
 readfile($export_file);
 exit;
?>

Let me explain what we have done. First we downloaded the class excel.php and put it in the same folder where example.php is. We also need an xls file. I have named it as example.xls. It is a simple spreadsheet file I have created with OpenOffice.

First we include the class and define the export file schema and path. Next we send a raw HTTP header, that will help us download the file. The HTTP header contains expiration date set to the past to prevent caching, a last modification date as current time and date and no cache directives. We do not want browsers to cache our file we are reading.

To guide the browser how to open or download the file we include the Content-type, we provide the file name in Content-Disposition and the Content-Description. And Finally we read the file in buffer with readfile function.

Spreadsheet example image

Conclusion

In this part of the article we learned how read and serve for download Excel files from PHP using the XLS stream handler.

In the next part I will go more detailed on how to write to an XLS file. I will create an array with sample data, and then write it into the stream. The resulting file will be then downloaded as Microsoft Excel file.

If you liked this article so far or you have questions about the XLS stream handler class, post a comment.

You need to be a registered user or login to post a comment

1,602,182 PHP developers registered to the PHP Classes site.
Be One of Us!

Login Immediately with your account on:

Facebook

Facebook

Gmail

Gmail

Hotmail

Hotmail

StackOverflow

StackOverflow

GitHub

GitHub

Yahoo

Yahoo

Comments:

5. php and excel — Ian Onvlee (2015-10-25 19:31)
php and excel part 1… — 1 reply
Read the whole comment and replies

4. Embed image — tim mason (2015-10-25 19:31)
How would i embed an image from a URL… — 1 reply
Read the whole comment and replies

3. Multiple worksheet handling — sathish kannan (2015-10-25 19:31)
Writing HTML tables into Multiple excel worksheet… — 1 reply
Read the whole comment and replies

2. Great ! — Ariel Rivera (2015-10-25 19:31)
Simple and neat…. — 1 reply
Read the whole comment and replies

1. Can we get data into PHP array? — Adwait Pande (2015-10-25 19:30)
Need code to get excel data into PHP array… — 1 reply
Read the whole comment and replies

Понравилась статья? Поделить с друзьями:
  • Php and excel spreadsheet
  • Php and excel files
  • Php and excel file
  • Photos of the word thank you
  • Photos of the word love