Skip to main content
GrN.dk

Main navigation

  • Articles
  • Contact
  • Your Digital Project Manager
  • About Greg Nowak
  • Services
  • Portfolio
  • Container
    • Excel Freelancer
    • Kubuntu - tips and tricks
    • Linux Apache MySQL and PHP
    • News
    • Image Gallery
User account menu
  • Log in

Breadcrumb

  1. Home

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

By Greg Nowak. Last updated 2026-07-06.

Shared hosting still creates awkward deployment moments. A site build is ready, FTP is slow, there is no SSH access, and the hosting panel either has no file manager or one that times out on larger uploads. In that situation, uploading one ZIP archive and extracting it on the server can be the least bad option.

The trick is to treat this as a controlled maintenance task, not as a casual shortcut. For most PHP hosts, the right starting point is PHP's built-in ZipArchive. A browser-based unzipper can still help on restricted hosts, but it should be temporary, removed afterwards, and never become the standard release process for a business-critical site.

Use ZipArchive first

ZipArchive is the cleanest default because it is part of PHP's ZIP extension, is documented by PHP, and keeps the deployment helper small enough to review. Put the ZIP and script in a non-public maintenance folder if your host allows it. If not, use an obscure temporary filename, run it once, and delete it immediately.

<?php
$archive = __DIR__ . '/site-release.zip';
$target = __DIR__ . '/release';

if (!class_exists('ZipArchive')) {
    exit('ZIP support is not enabled on this host.');
}

if (!is_file($archive)) {
    exit('Archive not found.');
}

if (!is_dir($target) && !mkdir($target, 0755, true)) {
    exit('Could not create target folder.');
}

$zip = new ZipArchive();
$result = $zip->open($archive);

if ($result !== true) {
    exit('Could not open ZIP archive. Error code: ' . $result);
}

for ($i = 0; $i < $zip->numFiles; $i++) {
    $name = $zip->getNameIndex($i);
    $unsafe = $name === false
        || $name === ''
        || $name[0] === '/'
        || preg_match('#(^|[\\/])\.\.([\\/]|$)#', $name)
        || preg_match('#^[A-Za-z]:[\\/]#', $name);

    if ($unsafe) {
        $zip->close();
        exit('Unsafe path in archive.');
    }
}

umask(0022);

if ($zip->extractTo($target)) {
    echo 'Archive extracted to release folder.';
} else {
    echo 'Extraction failed.';
}

$zip->close();

The extra path check is deliberate. On a real client host, you want boring failure modes: if the ZIP contains unexpected absolute paths, Windows drive paths, or parent-directory references, stop and inspect the archive locally. The umask(0022) call is also worth keeping because PHP's own manual notes that extracted files and directories otherwise use very broad default permissions unless the current umask restricts them.

Check ZIP support before rewriting the script

If the script fails before opening the archive, the issue may be the host, not your code. With SSH, run:

php -m | grep -i zip

Without SSH, look in the hosting panel's PHP extension list or run a tiny temporary check with class_exists('ZipArchive'). On Linux, PHP must be built with ZIP support. On Windows hosts, current PHP documentation says php_zip.dll must be enabled in php.ini as of PHP 8.2.0.

For an agency or operations team, that distinction matters. If ZIP support is missing, the next action is a hosting change, extension request, or different deployment method. Spending another hour changing syntax will not fix a disabled extension.

Situation Best move Why it matters
ZIP extension is enabled Use ZipArchive into a dedicated release folder Small, reviewable script with fewer moving parts
No SSH, but PHP works Use a browser helper only for the one task Useful on restricted hosts, risky if left behind
Host runs old or unsupported PHP Plan a host or PHP upgrade before normalizing the workflow Deployment fixes should not hide platform risk
Uploads happen every week Create a simple release and rollback process Repeated ZIP uploads are a process smell, not a strategy
A practical decision matrix for extracting ZIP files on shared hosting.

Use browser-based unzippers carefully

The older recommendation to use ndeet/unzipper still has a place, but the framing should be more cautious now. The project is built for the no-shell scenario: upload unzipper.php, place it near the archive, open it in a browser, choose the archive, and extract it. Its README describes it as handy when you do not have shell access.

That said, its repository also describes the project as beta and says to use it at your own risk. The latest GitHub release shown for the project is version 0.1.1 from January 5, 2018. That does not automatically make it unusable, but it does make it a one-off utility rather than something to leave installed on a live website.

Run the task like a small deployment

Before extracting, confirm that the archive was created from the correct folder. A common mistake is packaging the parent directory and ending up with /release/site-release/index.php instead of /release/index.php. Extract into a staging or release folder first, inspect the result, then switch files into place according to the host's constraints.

After extraction, delete the ZIP, delete the helper script, and keep a copy of the previous working version until the new one is checked. If the site has writable upload folders, cache folders, or local configuration files, make sure the release does not overwrite them blindly.

When to stop doing this manually

Unzipping with PHP is useful for constrained handoffs, emergency fixes, small static exports, and hosts that do not justify a larger build pipeline. It is not a healthy long-term deployment model for a site that changes often or has revenue attached to uptime.

If this task keeps returning, the useful next step is modest: a repeatable package structure, a clear release folder, permission checks, cleanup rules, and a rollback path. Greg can help turn ad hoc shared-hosting uploads into a safer website maintenance workflow without overengineering the setup.

Related on GrN.dk

  • Cloudflare Page Rules Debt: The Quiet Way Business Websites Break
  • Drupal CMS 2.0 Speeds Marketing Site Rebuilds, but It Is Not Autopilot
  • Drush: The Drupal Shell for Practical Site Operations

Need help with this kind of work?

Need a safer deployment handoff? Get in touch with Greg.

Sources

  • PHP Manual: ZipArchive::open
  • PHP Manual: ZipArchive::extractTo
  • PHP Manual: ZIP Extension Installation
  • PHP Supported Versions
  • ndeet/unzipper on GitHub
Last modified
2026-07-06

Tags

  • php
  • ZIP Archives
  • Shared Hosting
  • FTP Deployment
  • Website Operations
  • Log in to post comments

Review Greg on Google

Greg Nowak Google Reviews

 

  • Let's Encrypt Profiles Put Renewal Assumptions Under the Microscope
  • Moving Drupal Blocks on Mobile: CSS, Regions, and Safer Tradeoffs
  • Unzip with PHP on Shared Hosting: A Safer Way to Extract ZIP Files
  • Tidy Up composer.json with Composer Normalize
  • Before OpenAI agents touch the CRM, map the boring boundaries
RSS feed

GrN.dk web platforms, web optimization, data analysis, data handling and logistics.