Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Archive Tar Laravel Package

pear/archive_tar

Archive_Tar is a PHP package for creating, listing, extracting, and adding to tar files, with optional gzip, bz2, and Lzma2/xz compression support when the corresponding PHP extensions are loaded.

View on GitHub
Deep Wiki
Context7

Getting Started

pear/archive_tar is a single-class, no-framework tar library. Despite its PEAR heritage it is installable through Composer (composer require pear/archive_tar), which is how you'll actually meet it in a Laravel app — either directly or as a transitive dependency (Drupal and various backup/export packages pull it in). There is no service provider, no config file, no facade: you new Archive_Tar(...) and call methods.

Pin at least ^1.4.14 — that is the release that fixed the symlink path-traversal CVE (CVE-2021-32610), and ^1.6.0 if you need to write archives containing single files larger than 8 GB.

Minimal first use case — extract an uploaded .tar.gz safely:

use Archive_Tar;

$upload  = $request->file('bundle');                 // bundle.tar.gz
$archive = storage_path('app/imports/'.$upload->hashName());
$upload->move(dirname($archive), basename($archive));

$tar = new Archive_Tar($archive, 'gz');              // 'gz' must be explicit
$tar->setErrorHandling(PEAR_ERROR_RETURN);           // silence PEAR's print-to-output

$dest = storage_path('app/imports/'.Str::uuid());
if (! $tar->extract($dest)) {
    throw new RuntimeException($tar->errorInfo());
}

Where to look first: the source is a single file, Archive/Tar.php (~2 000 lines). The public surface you will actually use is create(), add(), addString(), listContent(), extract(), extractList(), extractModify(), setPrefix(), setRemovePath(), setIgnoreList(), setErrorHandling(), errorInfo().

Implementation Patterns

Wrap it in one small service class. You will call it from jobs, commands and controllers, so put setErrorHandling and error translation in one place:

final class TarService
{
    public function make(string $path, ?string $compression = null): Archive_Tar
    {
        $tar = new Archive_Tar($path, $compression);
        $tar->setErrorHandling(PEAR_ERROR_RETURN);
        return $tar;
    }
}

Bind it as a singleton in a service provider only if you must; it holds no state worth sharing, so app(TarService::class) on demand is enough.

Building release/backup bundles from disk. add() stores the path exactly as you pass it, so chdir() or setRemovePath() to keep absolute paths out of the archive:

$tar = $svc->make(storage_path('app/backups/app-'.now()->timestamp.'.tar.gz'), 'gz');

$tar->setRemovePath(base_path());          // strip /var/www/app from stored names
$tar->setIgnoreList(['#/node_modules/#', '#/\.git/#', '#/vendor/#']);

if (! $tar->create(['storage/app', 'public/uploads', '.env.example'])) {
    Log::error('tar create failed', ['err' => $tar->errorInfo()]);
}

Note the ignore list takes PCRE patterns with delimiters, matched against the full path — not globs.

Selective extraction before trusting an upload. Combine listContent() with extractList() instead of calling extract() blind:

$entries = $tar->listContent();                     // headers only — cheap

foreach ($entries as $e) {
    if (str_starts_with($e['name'], '/') || str_contains($e['name'], '..')
        || ($e['typeflag'] ?? '') === '5' && $e['name'] === '') {
        abort(422, 'Unsafe archive');
    }
}

$tar->extractList(['package.json', 'src/'], $tmp);  // extract a subset only

Strip a wrapper directory on extract (extractModify($dest, $removePath)) is the clean way to turn myplugin-1.2.3/src/... into src/... — no shelling out to tar --strip-components.

Generating archives in memory / streaming downloads. addString($contents, $nameInsideArchive) plus create() on a temp path is far simpler than trying to stream out of the class; then use response()->streamDownload() or Storage::put() on the result. Avoid holding a multi-hundred-MB archive string in PHP memory.

Queue anything large. extract() and create() are synchronous and CPU/IO bound. Put them in a job, write to a Str::uuid()-named temp directory under storage/app/tmp, and move the result into place on success.

Gotchas and Tips

  • Failures are not exceptions. Every method returns bool. try/catch catches nothing. Check the return value and call errorInfo().
  • PEAR's default error mode prints to output. The constructor sets PEAR_ERROR_PRINT, so a failed extract() can emit * Error extracting... into your HTTP response, corrupting JSON or a streamed download. Always call setErrorHandling(PEAR_ERROR_RETURN) first.
  • Compression is not auto-detected. new Archive_Tar('foo.tar.gz') without the second argument opens the file raw and parsing fails. Pass 'gz', 'bz2' or 'lzma2' (or true to infer from the extension, but explicit is safer). Each also needs ext-zlib / ext-bz2 / ext-xz present in the runtime — verify in your Docker image before shipping.
  • Absolute paths leak into archives. add() stores the argument verbatim. Use setRemovePath() or chdir(); otherwise your backup contains /var/www/html/..., which makes extraction on another host a mess.
  • Partial extraction on failure. A mid-extract error leaves half-written files behind. Always extract into a fresh temp directory and promote it only on success; never extract directly over live storage.
  • Symlinks and phar:// names. Hardening landed progressively (1.4.4 blocked phar://, 1.4.9 added a symlink restriction, 1.4.14 fixed the traversal CVE). Older versions in a transitive composer.lock are a real risk — check composer why pear/archive_tar and bump it.
  • Temp-file collisions. Writes stage through a .tmp sibling; two queued jobs writing the same target name will clobber each other. Use per-job unique filenames.
  • Permissions. Directories are created 775 (since 1.5.0); extracted files attempt to restore the archived mode but umask and the filesystem can override it. Don't rely on it for executable bits.
  • Long names / Unicode. Names over 100 characters go through GNU longlink headers, which some Windows tools won't read; non-ASCII names work only if the archive was written with matching encoding. Test with real-world uploads, not ASCII fixtures.
  • Memory. listContent() reads headers only and is safe for big archives; addString() and in-memory creation are not. 1.6.0 improved large-file writes, but the class still buffers blocks — cap upload sizes at the validation layer.
  • Testing. There are no Laravel fakes or assertions; verify by round-tripping — create an archive from a Storage fake, re-open it, and assert on listContent() names/sizes.
  • When to skip it. For simple .tar/.tar.gz work inside a Laravel app, PHP's built-in PharData handles list/extract/write with zero extra dependencies, and the tar binary via Symfony\Component\Process is faster and more forgiving. Reach for Archive_Tar when you specifically need its extractList()/extractModify()/setRemovePath() conveniences or you're already carrying it transitively — not as a first choice.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console