Download Processing

Download Processing#

Namespace: Infocyph\Pathwise\StreamHandler

Where it fits:

  • Use this module when you need secure download metadata and controlled stream delivery for local or mounted filesystems.

DownloadProcessor supports:

  • Download metadata generation with headers suitable for HTTP adapters.

  • Safe download filename handling for Content-Disposition.

  • Extension allowlist/blocklist controls.

  • Allowed-root restrictions to prevent serving files outside trusted paths.

  • Hidden-file blocking.

  • Optional max download size enforcement.

  • Optional range requests with byte-range parsing and partial metadata.

  • Stream copy to caller-provided output resource.

  • Mounted/default filesystem paths (e.g. s3://...) via Flysystem routing.

Security controls#

DownloadProcessor exposes explicit hardening options:

  • setAllowedRoots(array $roots)

  • setExtensionPolicy(array $allowedExtensions = [], array $blockedExtensions = [])

  • setBlockHiddenFiles(bool $block = true)

  • setMaxDownloadSize(int $maxDownloadSize = 0)

  • setRangeRequestsEnabled(bool $enabled = true)

  • setForceAttachment(bool $enabled = true)

  • setDefaultDownloadName(string $name)

  • setChunkSize(int $chunkSize)

Examples#

Prepare secure metadata:

use Infocyph\Pathwise\StreamHandler\DownloadProcessor;

$downloads = new DownloadProcessor();
$downloads->setAllowedRoots(['/srv/app/downloads']);
$downloads->setExtensionPolicy(['pdf', 'zip'], ['php', 'phar', 'exe']);

$manifest = $downloads->prepareDownload(
    path: '/srv/app/downloads/report.pdf',
    downloadName: 'monthly-report.pdf',
    rangeHeader: null,
);

// Use $manifest['status'] and $manifest['headers'] in your framework response.

Stream output with range support:

$output = fopen('php://output', 'wb');

$manifest = $downloads->streamDownload(
    path: '/srv/app/downloads/video.mp4',
    outputStream: $output,
    downloadName: 'video.mp4',
    rangeHeader: $_SERVER['HTTP_RANGE'] ?? null,
);

// $manifest includes status, headers, rangeStart/rangeEnd and bytesSent.

Mounted storage example:

use Infocyph\Pathwise\Storage\StorageFactory;
use Infocyph\Pathwise\StreamHandler\DownloadProcessor;

StorageFactory::mount('s3', ['adapter' => $myS3Adapter]);

$downloads = new DownloadProcessor();
$downloads->setAllowedRoots(['s3://downloads']);

$manifest = $downloads->prepareDownload('s3://downloads/report.pdf');