Skip to content
← Back to Functions
Code

Download Header Builder

Builds safe headers for attachment or inline file downloads.

Function signature

ogBuildDownloadHeaders(filename, content_type = 'application/octet-stream', size_bytes = 0, disposition = 'attachment')

Categories

  • Security

Parameters

filenameCaller-supplied value used for filename processing.content_typeString value for content type processing.size_bytesInteger value controlling size bytes.dispositionString value for disposition processing.

Return value

Public-safe status string returned by the function.

  • success
  • message
  • data

Compatibility

Existing function name, slug, path, and call order preserved; advertised metadata corrected to the actual source behavior.

Minimum PHP version: 7.4

Security notes

Use caller-owned allowlists and procedural mysqli prepared execution where SQL plans are returned; validate file paths, MIME policies, and permissions before file or download workflows.

Code

<?php

/*
 * Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
 * Free for personal and internal use. Paid project use requires visible credit
 * to Jeffery L. Paris. Corporate use requires a paid license fee unless a
 * separate written license states otherwise.
 */

/**
 * Builds safe headers for attachment or inline file downloads.
 *
 * Primary use case: Digital products and exports.
 * Typical inputs: filename, content type, size, disposition.
 * Typical output: header list.
 *
 * Implementation note: Sanitize filenames and avoid header injection.
 *
 * @return array Structured result data with success, message, and data keys.
 */
function ogBuildDownloadHeaders($filename, $content_type = 'application/octet-stream', $size_bytes = 0, $disposition = 'attachment') {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	$filename = basename((string)$filename);
	$content_type = trim((string)$content_type);
	$size_bytes = (int)$size_bytes;
	$disposition = strtolower(trim((string)$disposition));

	if (empty($filename)) {
		$result['message'] = 'Filename is required.';
		return $result;
	}
	$filename = preg_replace('/[^a-zA-Z0-9._-]+/', '-', $filename);
	$filename = trim($filename, '.-');
	if (empty($filename)) {
		$result['message'] = 'Filename is not safe after cleaning.';
		return $result;
	}
	if (!preg_match('/^[a-z0-9.+-]+\/[a-z0-9.+-]+$/i', $content_type)) {
		$content_type = 'application/octet-stream';
	}
	if ($disposition != 'attachment' && $disposition != 'inline') {
		$disposition = 'attachment';
	}

	$headers = array();
	$headers[] = 'Content-Type: ' . $content_type;
	$headers[] = 'Content-Disposition: ' . $disposition . '; filename="' . $filename . '"';
	$headers[] = 'X-Content-Type-Options: nosniff';
	if ($size_bytes > 0) {
		$headers[] = 'Content-Length: ' . $size_bytes;
	}

	$result['success'] = true;
	$result['message'] = 'Download headers built.';
	$result['data'] = array(
		'filename' => $filename,
		'content_type' => $content_type,
		'disposition' => $disposition,
		'headers' => $headers
	);

	return $result;
}