function file_munge_filename

Same name in other branches
  1. 7.x includes/file.inc \file_munge_filename()
  2. 8.9.x core/includes/file.inc \file_munge_filename()

Modifies a filename as needed for security purposes.

Munging a file name prevents unknown file extensions from masking exploit files. When web servers such as Apache decide how to process a URL request, they use the file extension. If the extension is not recognized, Apache skips that extension and uses the previous file extension. For example, if the file being requested is exploit.php.pps, and Apache does not recognize the '.pps' extension, it treats the file as PHP and executes it. To make this file name safe for Apache and prevent it from executing as PHP, the .php extension is "munged" into .php_, making the safe file name exploit.php_.pps.

Specifically, this function adds an underscore to all extensions that are between 2 and 5 characters in length, internal to the file name, and either included in the list of unsafe extensions, or not included in $extensions.

Function behavior is also controlled by the configuration 'system.file:allow_insecure_uploads'. If it evaluates to TRUE, no alterations will be made, if it evaluates to FALSE, the filename is 'munged'. *

Parameters

$filename: File name to modify.

$extensions: A space-separated list of extensions that should not be altered. Note that extensions that are unsafe will be altered regardless of this parameter.

$alerts: If TRUE, \Drupal::messenger()->addStatus() will be called to display a message if the file name was changed.

Return value

string The potentially modified $filename.

Deprecated

in drupal:9.2.0 and is removed from drupal:10.0.0. Dispatch a \Drupal\Core\File\Event\FileUploadSanitizeNameEvent event instead.

See also

https://www.drupal.org/node/3032541

Related topics

6 calls to file_munge_filename()
NameMungingTest::testMungeIgnoreAllowedExtensions in core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php
Tests that allowed extensions are ignored by file_munge_filename().
NameMungingTest::testMungeIgnoreInsecure in core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php
Test munging with system.file.allow_insecure_uploads set to true.
NameMungingTest::testMungeNullByte in core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php
Tests munging with a null byte in the filename.
NameMungingTest::testMungeUnsafe in core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php
Tests unsafe extensions are always munged by file_munge_filename().
NameMungingTest::testMunging in core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php
Create a file and munge/unmunge the name.

... See full list

File

core/includes/file.inc, line 158

Code

function file_munge_filename($filename, $extensions, $alerts = TRUE) {
    @trigger_error('file_munge_filename() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. Dispatch a \\Drupal\\Core\\File\\Event\\FileUploadSanitizeNameEvent event instead. See https://www.drupal.org/node/3032541', E_USER_DEPRECATED);
    $original = $filename;
    // Allow potentially insecure uploads for very savvy users and admin
    if (!\Drupal::config('system.file')->get('allow_insecure_uploads')) {
        // Remove any null bytes. See
        // http://php.net/manual/security.filesystem.nullbytes.php
        $filename = str_replace(chr(0), '', $filename);
        $allowed_extensions = array_unique(explode(' ', strtolower(trim($extensions))));
        // Remove unsafe extensions from the allowed list of extensions.
        $allowed_extensions = array_diff($allowed_extensions, FileSystemInterface::INSECURE_EXTENSIONS);
        // Split the filename up by periods. The first part becomes the basename
        // the last part the final extension.
        $filename_parts = explode('.', $filename);
        // Remove file basename.
        $new_filename = array_shift($filename_parts);
        // Remove final extension.
        $final_extension = array_pop($filename_parts);
        // Loop through the middle parts of the name and add an underscore to the
        // end of each section that could be a file extension but isn't in the list
        // of allowed extensions.
        foreach ($filename_parts as $filename_part) {
            $new_filename .= '.' . $filename_part;
            if (!in_array(strtolower($filename_part), $allowed_extensions) && preg_match("/^[a-zA-Z]{2,5}\\d?\$/", $filename_part)) {
                $new_filename .= '_';
            }
        }
        $filename = $new_filename . '.' . $final_extension;
        if ($alerts && $original != $filename) {
            \Drupal::messenger()->addStatus(t('For security reasons, your upload has been renamed to %filename.', [
                '%filename' => $filename,
            ]));
        }
    }
    return $filename;
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.