data types and standard library

Fileinfo and MIME Detection

Fileinfo helps PHP inspect a file's contents and guess its MIME type. That matters when users upload files, admins import documents, or an application decides how a stored file should be served.

Do not trust the browser-provided filename, file extension, or Content-Type header on its own. They are useful hints, but they can be wrong or deliberately misleading.

Detect a file's MIME type

Use finfo with FILEINFO_MIME_TYPE when you need the detected media type.

PHP example
<?php

declare(strict_types=1);

$path = tempnam(sys_get_temp_dir(), 'mime_');
file_put_contents($path, "Plain text upload\n");

$info = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $info->file($path);

echo $mimeType . PHP_EOL;

unlink($path);

// Prints:
// text/plain

The detected MIME type comes from the file data, not from the name report.txt.

Use an allowlist

File validation should usually ask, "is this one of the types we accept?" rather than "is this not obviously dangerous?"

PHP example
<?php

declare(strict_types=1);

function assertAllowedMimeType(string $path, array $allowedMimeTypes): string
{
    $info = new finfo(FILEINFO_MIME_TYPE);
    $mimeType = $info->file($path);

    if (!is_string($mimeType) || !in_array($mimeType, $allowedMimeTypes, true)) {
        throw new InvalidArgumentException('File type is not allowed.');
    }

    return $mimeType;
}

$path = tempnam(sys_get_temp_dir(), 'mime_');
file_put_contents($path, "Name,Email\nNia,nia@example.com\n");

echo assertAllowedMimeType($path, ['text/plain', 'text/csv']) . PHP_EOL;

unlink($path);

// Prints:
// text/plain

Different systems may detect small text-like files as text/plain even when the extension is .csv. Allowlists sometimes need to account for that.

Extensions are still useful

MIME detection and extension checks answer different questions. MIME detection tells you what the content appears to be. The extension affects user expectations, storage names, and download behaviour.

PHP example
<?php

declare(strict_types=1);

function extensionFromOriginalName(string $filename): string
{
    return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
}

echo extensionFromOriginalName('Quarterly-Report.PDF') . PHP_EOL;

// Prints:
// pdf

Use the extension as part of a policy, not as proof that the file is safe.

Validate image uploads beyond MIME type

For images, MIME detection is useful but not the whole story. You may also need dimensions, file size, and image decoding checks.

PHP example
<?php

declare(strict_types=1);

function assertImageSize(array $size): void
{
    [$width, $height] = $size;

    if ($width < 1 || $height < 1 || $width > 4000 || $height > 4000) {
        throw new InvalidArgumentException('Image dimensions are not allowed.');
    }
}

assertImageSize([1200, 800]);

echo 'Image size accepted' . PHP_EOL;

// Prints:
// Image size accepted

In a real upload handler, the size array might come from getimagesize() after the file has passed basic upload and MIME checks.

Keep uploaded files out of public execution paths

Validation is only one part of file safety. Store uploads outside directories where PHP can execute scripts, generate a safe storage name, and serve downloads through controlled application code or static storage with the correct headers.

PHP example
<?php

declare(strict_types=1);

function storageName(string $extension): string
{
    $safeExtension = strtolower($extension);

    if (!preg_match('/^[a-z0-9]+$/', $safeExtension)) {
        throw new InvalidArgumentException('Invalid extension.');
    }

    return bin2hex(random_bytes(16)) . '.' . $safeExtension;
}

$name = storageName('pdf');

echo strlen($name) > 4 ? 'generated' : 'invalid';
echo PHP_EOL;

// Prints:
// generated

Do not keep the user's original filename as the storage path. Store it as metadata if you need it for display.

What to remember

Fileinfo is a boundary tool. Use it with an allowlist, combine it with extension and size checks where appropriate, avoid public executable upload paths, and keep useful validation errors without exposing sensitive server paths.

Practice

Task: Validate an uploaded document type

Write a small validator for a document upload represented by a temporary file path and an original filename.

Requirements

  • Use declare(strict_types=1);.
  • Create a temporary file containing plain text.
  • Detect the MIME type with finfo.
  • Allow only text/plain and text/csv.
  • Extract and normalise the original filename extension.
  • Allow only txt and csv extensions.
  • Return the detected MIME type and extension.
  • Show one accepted example and one rejected example.
  • Include the expected output as comments in the same PHP code block.

The example should not trust the original filename alone.

Show solution
PHP example
<?php

declare(strict_types=1);

function validateDocumentUpload(string $path, string $originalName): array
{
    $info = new finfo(FILEINFO_MIME_TYPE);
    $mimeType = $info->file($path);

    if (!is_string($mimeType) || !in_array($mimeType, ['text/plain', 'text/csv'], true)) {
        throw new InvalidArgumentException('Document MIME type is not allowed.');
    }

    $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));

    if (!in_array($extension, ['txt', 'csv'], true)) {
        throw new InvalidArgumentException('Document extension is not allowed.');
    }

    return [
        'mimeType' => $mimeType,
        'extension' => $extension,
    ];
}

$path = tempnam(sys_get_temp_dir(), 'upload_');
file_put_contents($path, "sku,name\nKB-101,Keyboard\n");

$accepted = validateDocumentUpload($path, 'products.csv');

echo $accepted['mimeType'] . ' / ' . $accepted['extension'] . PHP_EOL;

try {
    validateDocumentUpload($path, 'products.php');
} catch (InvalidArgumentException $exception) {
    echo $exception->getMessage() . PHP_EOL;
}

unlink($path);

// Prints:
// text/plain / csv
// Document extension is not allowed.

The validator checks the detected content type and the user-facing extension. In a real upload flow, this would sit alongside upload error handling, file size limits, safe storage names, and storage outside executable public paths.