0

I have one .xlsx file containing several worksheets. This .xlsx is generated using the php library phpoffice / phpspreadsheet. What I need to do is extract a specific worksheet from this file and create a new one - a separate .xlsx file.

My PHP code look like this:

<?php
// autoload of phpoffice library
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

// load .xlsx file from html form
$reader = IOFactory::createReader('Xlsx');
$spreadsheet = $reader->load($_FILES['in_file']['tmp_name']);

// setting the required sheet
$sheet = $spreadsheet->getSheetByName('required sheet');

// instance of the Worksheet object
$ws = new Worksheet($sheet);

// creating a new spreadsheet
$newSpreadsheet = new Spreadsheet();

// adding a worksheet to a new spreadsheet
$newSpreadsheet->addSheet($ws, 1);

// remove the worksheet in the first position
$newSpreadsheet->removeSheetByIndex(0);

// save the new .xlsx file
$writer = IOFactory::createWritter($newSpreadsheet, 'Xlsx');
$writer->save('new_xlsx.xlsx');

A new .xlsx file is generated, the worksheet name of this new file is set, but this worksheet is not populated with data. Why? What's missing me? Did I forget something?

Petr Fořt Fru-Fru
  • 858
  • 2
  • 8
  • 23

1 Answers1

2

You were close to getting the solution! PhpSpreadsheet allows you to use the clone keyword on sheet objects and then add them to other spreadsheets. I see you're getting this from an uploaded form so a simple check of the MIME Type is probably a good idea.

$required_sheet = 'Test3';
$input_file = 'test.xlsx';

$mime_type = mime_content_type($input_file);
if ($mime_type !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    die('Not an Xlsx file');

$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx;
$reader->setReadDataOnly(true);

$original = $reader->load($input_file);

$cloned_worksheet = clone $original->getSheetByName($required_sheet);

$new = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$new->addSheet($cloned_worksheet);
$sheetIndex = $new->getIndex(
    $new->getSheetByName('Worksheet')
);
$new->removeSheetByIndex($sheetIndex);

$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($new, "Xlsx");
$writer->save($required_sheet . '.xlsx');
Jacob Mulquin
  • 3,458
  • 1
  • 19
  • 22
  • 1
    I've tested using `clone` with a random `xlsx` file I've found online and the issue I've found is that adding the cloned worksheet failed on save due to unresolved references (formatting, I think) from the worksheet into the parent spreadsheet. Definitely worth trying this approach, just be aware that this might blow up on arbitrary files. – msbit Apr 15 '22 at 02:31
  • 1
    Actually, nevermind, I think the secret sauce here to avoid the issue I was having is `$reader->setReadDataOnly(true);` ✌️ – msbit Apr 15 '22 at 02:37
  • 1
    And one final wrinkle to using `setReadDataOnly(true)` is that nice-to-haves like date formatting is also removed, leaving dates like `44012` for `30/6/2020`. – msbit Apr 15 '22 at 03:32
  • 1
    Thank you very much for your efforts to help me. Your answer helped me. Otherwise, my php code looks a little different. The PHP code used here in my question is just an abbreviated snippet of my official code. @Jacob Mulquin – Petr Fořt Fru-Fru Apr 15 '22 at 13:21