@dhesaw

Как объединить файлы xlsx/xls в один через phpSpreadSheet?

Пытаюсь объединить excel файлы в один, вытаскивая из файлов листы и добавляя их в общий файл.
В переменной $files у меня хранятся ссылки на excel файлы на сервере.
$spreadsheetMain=new Spreadsheet();
                $spreadsheetMain->removeSheetByIndex(0);
                foreach ($files as $key => $links) {
                    try {
                    $spreadsheet=(new \PhpOffice\PhpSpreadsheet\Reader\Xlsx)
                    ->load($links)
                    ->getActiveSheet()
                    ->setTitle("Worksheet_".rand(1,1000));
                    } catch(\Exception $e){
                        $spreadsheet=(new \PhpOffice\PhpSpreadsheet\Reader\Xls)
                        ->load($links)
                        ->getActiveSheet()
                        ->setTitle("Worksheet_".rand(1,1000));
                    }
                    $spreadsheetMain->addExternalSheet($spreadsheet);
                }
                $file=new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheetMain); // пока нет проверки на xls (у меня пока 
                их все равно нет)
                $folderName=self::createFolder(); //создание папки на сервере, работает нормально.
                $file->save(
                    "{$_SERVER['DOCUMENT_ROOT']}/upload/tmp/{$folderName}/mergedFilesDoc.xlsx"
                );

при сохранении у меня вылетает ошибка:

PhpOffice\PhpSpreadsheet\Cell\Cell::setXfIndex(): Argument #1 ($indexValue) must be of type int, null given, called in /home/bitrix/www/local/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Spreadsheet.php on line 1405 (0)
/home/bitrix/www/local/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Cell.php:763
#0: PhpOffice\PhpSpreadsheet\Cell\Cell->setXfIndex
/home/bitrix/www/local/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Spreadsheet.php:1405
#1: PhpOffice\PhpSpreadsheet\Spreadsheet->garbageCollect
/home/bitrix/www/local/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx.php:306
#2: PhpOffice\PhpSpreadsheet\Writer\Xlsx->save
/home/bitrix/www/local/warehouses/class/FileBuilder.php:83

я зашел в метод save у Spreadsheet.php и попробовал проскочить ошибку
$test=$cell->getXfIndex();
if ($test!=null && $test<count($map))
$cell->setXfIndex($map[$cell->getXfIndex()]);

файл создается, но почему-то пропали стили с файлов (бордерды ячеек, бг колор ячеек, выравнивание текста в ячейках) , а еще при открытии файла он говорит, что файл поврежден и восстанавливает его.

Я пробовал через эту библиотеку самописную еще делать https://github.com/infostreams/excel-merge но она работает через раз и не все файлы открывает.
  • Вопрос задан
  • 161 просмотр
Пригласить эксперта
Ответы на вопрос 1
@dhesaw Автор вопроса
Переписал метод мерджа на
$mergedWorkbook=new Spreadsheet();
                foreach ($files as $file) {
                    $spreadsheet = IOFactory::load($file);
                    $worksheets = $spreadsheet->getAllSheets();
                    foreach ($worksheets as $worksheet) {
                        if ($mergedWorkbook->sheetNameExists($worksheet->getTitle())) {
                            $worksheet->setTitle($worksheet->getTitle() . rand(1,40));
                        }
                        $mergedWorkbook->addExternalSheet($worksheet);
                    }
                }
                $mergedWorkbook->removeSheetByIndex(0);
                $writer = IOFactory::createWriter($mergedWorkbook, 'Xlsx');
                $folderName=self::createFolder();
                $writer->save(
                    "{$_SERVER['DOCUMENT_ROOT']}/upload/tmp/{$folderName}/mergedFilesDoc.xlsx"
                );


Но ошибка с некорректным форматированием ячеек все равно осталась, пришлось изменить метод garbageCollect класса Spreadsheet библиотеки phpOffice.
// other_code before 1399 line
 foreach ($this->getWorksheetIterator() as $sheet) {
            // for all cells
            foreach ($sheet->getCoordinates(false) as $coordinate) {
                $cell = $sheet->getCell($coordinate);
                $cell->setXfIndex($map[$cell->getXfIndex()]?$map[$cell->getXfIndex()]:0); // code modification
            }

            // for all row dimensions
            foreach ($sheet->getRowDimensions() as $rowDimension) {
                if ($rowDimension->getXfIndex() !== null) {
                    $rowDimension->setXfIndex($map[$rowDimension->getXfIndex()]?$map[$rowDimension->getXfIndex()]:0); // code modification
                }
            }

            // for all column dimensions
            foreach ($sheet->getColumnDimensions() as $columnDimension) {
                $columnDimension->setXfIndex($map[$columnDimension->getXfIndex()]?$map[$columnDimension->getXfIndex()]:0); // code modification
            }

            // also do garbage collection for all the sheets
            $sheet->garbageCollect();
        }
// other_code after 1420 line

Понимаю, что это неправильно, но так файл начал создаваться (как для xls, так и для xlsx) и все стили подтянулись. Ну и не пишет, что файл поврежден.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы