SpreadSheet-Coding.com

PHPSpreadsheet · Google Sheets API · Excel

Spreadsheets, driven by code.

Hands-on PHP tutorials for working with Excel and Google Sheets — read and write .xlsx, convert files to JSON, stream downloads in the browser, and insert images, formulas, and styling. Every guide ships with code you can copy, run, and adapt.

download-zip.php View article
<?php

require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

// One workbook per region. In a real app this is whatever your query returns.
$reports = [
    'north' => [
        ['Rep', 'Units', 'Revenue'],
        ['Alice', 120, 4800],
        ['Bob', 90, 3600],
    ],
    'south' => [
        ['Rep', 'Units', 'Revenue'],
        ['Carol', 150, 6000],
        ['Dan', 70, 2800],
    ],
    'east' => [
        ['Rep', 'Units', 'Revenue'],
        ['Erin', 200, 8000],
    ],
];

// 1. A scratch directory used by this request and nobody else.
$workDir = sys_get_temp_dir() . '/reports-' . bin2hex(random_bytes(8));

if (!mkdir($workDir) && !is_dir($workDir)) {
    exit('Could not create a working directory.');
}

$zipPath = $workDir . '/reports.zip';
$zip = new ZipArchive();

if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
    exit('Could not create the archive.');
}

// 2. Build each workbook, save it, then add it to the archive.
foreach ($reports as $region => $rows) {
    $spreadsheet = new Spreadsheet();
    $worksheet = $spreadsheet->getActiveSheet();
    $worksheet->setTitle(ucfirst($region));
    $worksheet->fromArray($rows, null, 'A1');

    $memberName = $region . '-sales.xlsx';
    $filePath = $workDir . '/' . $memberName;

    (new Xlsx($spreadsheet))->save($filePath);

    // addFile() records a path, it does not copy the bytes yet. The file must
    // still exist when close() runs.
    $zip->addFile($filePath, $memberName);

    // Release the workbook before building the next one.
    $spreadsheet->disconnectWorksheets();
    unset($spreadsheet, $worksheet);
}

// 3. close() is what actually writes the archive. Before this line reports.zip
//    is incomplete, so nothing may stream it yet.
$zip->close();

// 4. Send it. The archive is a real file, so its size is known up front and the
//    browser can show a true progress bar.
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="reports.zip"');
header('Content-Length: ' . filesize($zipPath));
header('Cache-Control: max-age=0');

while (ob_get_level() > 0) {
    ob_end_clean();
}

readfile($zipPath);

// 5. Clean up. Nothing is left behind in the temp directory.
foreach (glob($workDir . '/*') as $leftover) {
    unlink($leftover);
}
rmdir($workDir);

exit;

The full script from Download Several Excel Files As One ZIP In PHP Using PHPSpreadSheet — copy, run, adapt.

IOFactory::load() PhpSpreadsheet
Open any spreadsheet file
getActiveSheet() PhpSpreadsheet
Select the worksheet to fill
fromArray() PhpSpreadsheet
Write many rows at once
getCalculatedValue() PhpSpreadsheet
Read a formula result
save('php://output') PhpSpreadsheet
Stream the file as a download
spreadsheets_values->get() Google Sheets
Read a range of cells
spreadsheets_values->update() Google Sheets
Write a range of cells
spreadsheets->create() Google Sheets
Create a new spreadsheet
json_encode() PHP
Serialize rows to JSON
header() PHP
Send the download headers