Unzip with PHP on Shared Hosting: A Safer Way to Extract ZIP Files

Illustrated infographic summarizing: Unzip with PHP on Shared Hosting: A Safer Way to Extract ZIP Files

By Greg Nowak. Updated 7 September 2026.

Uploading one ZIP archive can save time when a website release contains thousands of small files. If your shared hosting has no SSH access and its file manager cannot extract archives, PHP can handle the job.

The extraction itself is only one step. For a business website, the useful outcome is a complete release, a checked customer journey and a clear way back if something fails. Here is how to organise that work without overwriting the live site halfway through an update.

Choose the simplest available route

Check the hosting panel before adding a script. Its extraction feature may be sufficient, provided you can choose a separate destination. For an agency handover, record who uploads the package, who activates it and who checks the result.

Hosting situation Practical approach Before proceeding
File manager supports ZIP extraction Use the hosting panel Select a fresh release directory
No SSH or panel extraction; PHP ZIP is available Use a temporary PHP helper Protect access and staging files
PHP ZIP is missing Ask the host to enable it or extract the package Confirm support for the site's PHP runtime
Large archives or repeated timeouts Ask for a host-managed or command-line operation Check disk quota and execution limits
Choose the extraction method around the hosting account's actual capabilities.

Check PHP, space and access first

With shell access, check ZIP support using:

php -m | grep -i zip

The command-line runtime may differ from the website's PHP configuration. For a browser helper, check the hosting panel or temporarily run var_dump(class_exists('ZipArchive')); behind access protection, then delete it. The PHP installation documentation explains the extension requirements; shared-hosting changes usually belong with the host.

Use a supported PHP branch with current patches. On 7 September 2026, PHP 8.2–8.5 remain supported; 8.2 and 8.3 receive security fixes only. PHP 8.2 support ends on 31 December 2026, according to the official support schedule.

Allow space for the ZIP, expanded release and previous release, plus working headroom. Check the account's file-count quota too. A small compressed file can contain many entries.

Before uploading the helper, protect its URL with hosting-panel authentication over HTTPS or an appropriate IP restriction. An obscure filename is insufficient. Keep the archive and staging directory outside the public document root where possible; otherwise block web access to both. Filesystem permissions alone do not stop the web server serving files it can read.

A bounded ZipArchive helper for trusted releases

This example is for a team-produced, reviewed archive on Linux shared hosting. Place it in the protected maintenance workspace described above. It uses fixed paths, rejects questionable entry names and requires a new destination. Adjust the example limits to the expected package.

<?php
$archive = __DIR__ . '/site-release.zip';
$target = __DIR__ . '/release-2026-09-07';
$maxEntries = 2000;
$maxBytes = 200 * 1024 * 1024; // 200 MiB, declared size

if (!class_exists('ZipArchive')) {
    exit('ZIP support is unavailable.');
}
if (!is_file($archive)) {
    exit('Archive not found.');
}
if (file_exists($target) || is_link($target)) {
    exit('Use a new release directory.');
}

$zip = new ZipArchive();
$result = $zip->open(
    $archive,
    ZipArchive::RDONLY | ZipArchive::CHECKCONS
);
if ($result !== true) {
    exit('Could not open archive. Error code: ' . $result);
}

$oldUmask = umask(0077);
try {
    if ($zip->numFiles > $maxEntries) {
        throw new RuntimeException('Too many archive entries.');
    }
    $total = 0;
    for ($i = 0; $i < $zip->numFiles; $i++) {
        $stat = $zip->statIndex($i);
        if ($stat === false) {
            throw new RuntimeException('Cannot inspect entry.');
        }
        $path = $stat['name'];
        if ($path === '' || $path[0] === '/'
            || str_contains($path, '\\')
            || str_contains($path, ':')
            || preg_match('/[\x00-\x1F\x7F]/', $path)
            || preg_match('#(^|/)\.{1,2}(/|$)#', $path)) {
            throw new RuntimeException('Unsupported archive path.');
        }
        $size = $stat['size'];
        if (!is_int($size) || $size < 0
            || $size > $maxBytes - $total) {
            throw new RuntimeException('Declared size exceeds limit.');
        }
        $total += $size;
    }
    if (!mkdir($target, 0700)) {
        throw new RuntimeException('Cannot create release directory.');
    }
    if (!$zip->extractTo($target)) {
        throw new RuntimeException('Extraction failed; inspect partial release.');
    }
    echo 'Extracted. Validate before activation.';
} catch (RuntimeException $e) {
    http_response_code(500);
    echo htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
} finally {
    umask($oldUmask);
    $zip->close();
}

The strict !== true check matters because ZipArchive::open() can return an integer error code. Consistency checking does not establish that the contents are trustworthy.

The size check is preflight validation, not a hard extraction quota. statIndex() supplies archive metadata; this helper does not count bytes as they are written. It is unsuitable for processing arbitrary customer uploads or defending against hostile archives.

The restrictive umask keeps staging permissions narrow. PHP documents that extractTo() does not restore original permissions. Before activation, apply the host's required file and directory permissions, including any executable scripts. Avoid blanket chmod 777 fixes.

Validate the release before switching traffic

Check the directory layout: an extra parent folder can put index.php one level below where the site expects it. Confirm dependencies, environment configuration and writable directories. Keep uploads, secrets and generated content outside the replaceable package wherever practical.

Agree the activation method before starting. Some hosts allow a document-root change; others require a maintenance window and directory changes. Do not assume switching will be instantaneous. Keep the previous release and test the homepage, a key enquiry or purchase journey, and the error log after activation.

If the release changes the database, restoring old files may not restore the application. Plan compatible migrations or a tested database recovery procedure, accounting for orders and submissions received since the backup.

Close the maintenance job properly

A timeout or failed extraction can leave a partial directory. Inspect it, remove the failed release and retry into a fresh destination. Delete the temporary helper and uploaded ZIP after the job; record the release, checks and rollback location.

If these deployments depend on one person's memory, Greg can help document and coordinate a repeatable release workflow that fits your hosting, team and budget.

Related on GrN.dk

Need help with this kind of work?

Discuss your website deployment workflow Get in touch with Greg.

Sources

Seneste artikler

Når en ingrediens ændres, kan menukortet kræve rettelser, selv om opskriftsdatoen står stille. Sådan kan AI hjælpe med gennemgang og godkendelse i WordPress.

Når checkout fejler, skal driftspartneren have noget konkret at arbejde med. Se, hvordan AI, dmesg og journalctl kan samle sporene i en brugbar driftssag.

Brug oktober til at afprøve daglige AI-forslag til genbestilling før Black Friday. Få styr på Shopify-data, leveringstid og budget, før forslagene bliver til indkøb.

Jeg lærte serverdrift ved at ødelægge mine egne servere. Jeg søger en, der vil stå ved siden af mig, mens jeg gør det, og så gøre det selv ugen efter.

Jeg er god til at bygge og dårlig til at ringe. Her er, hvem jeg vil have ved siden af mig, hvad der er lettest at sælge, og hvordan vi deler det.

AI kan samle onboardingopgaverne før første arbejdsdag. Se, hvordan lederen godkender konkret adgang, og hvordan åbne opgaver bliver fulgt til dørs.

En AI-assistent kan svare på spørgsmål og føre kunder til booking. Her er de konkrete grænser for pris, levering, personoplysninger og kontakt med en medarbejder.

Et sikkert AI-workflow kan omsætte Meet- og Teams-transskripter til godkendte beslutninger og opgaver i Jira eller Asana – uden at slippe kontrollen.

AI kan finde opsigelsesfrister og prisreguleringer i leverandørkontrakter, sende usikre fund til godkendelse og oprette de rette påmindelser.

Sådan automatiserer danske virksomheder Gmail og Microsoft 365 med hurtig sortering, begrænsede rettigheder og menneskelig godkendelse.