string sanitizer for filename

Viewed 188767

I'm looking for a php function that will sanitize a string and make it ready to use for a filename. Anyone know of a handy one?

( I could write one, but I'm worried that I'll overlook a character! )

Edit: for saving files on a Windows NTFS filesystem.

18 Answers

Making a small adjustment to Tor Valamo's solution to fix the problem noticed by Dominic Rodger, you could use:

// Remove anything which isn't a word, whitespace, number
// or any of the following caracters -_~,;[]().
// If you don't need to handle multi-byte characters
// you can use preg_replace rather than mb_ereg_replace
// Thanks @Łukasz Rysiak!
$file = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $file);
// Remove any runs of periods (thanks falstro!)
$file = mb_ereg_replace("([\.]{2,})", '', $file);

Instead of worrying about overlooking characters - how about using a whitelist of characters you are happy to be used? For example, you could allow just good ol' a-z, 0-9, _, and a single instance of a period (.). That's obviously more limiting than most filesystems, but should keep you safe.

Well, tempnam() will do it for you.

http://us2.php.net/manual/en/function.tempnam.php

but that creates an entirely new name.

To sanitize an existing string just restrict what your users can enter and make it letters, numbers, period, hyphen and underscore then sanitize with a simple regex. Check what characters need to be escaped or you could get false positives.

$sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename);
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)

Add/remove more valid characters depending on what is allowed for your system.

Alternatively you can try to create the file and then return an error if it's bad.

safe: replace every sequence of NOT "a-zA-Z0-9_-" to a dash; add an extension yourself.

$name = preg_replace('/[^a-zA-Z0-9_-]+/', '-', strtolower($name)).'.'.$extension;

so a PDF called

"This is a grüte test_service +/-30 thing"

becomes

"This-is-a-gr-te-test_service-30-thing.pdf"

The following expression creates a nice, clean, and usable string:

/[^a-z0-9\._-]+/gi

Turning today's financial: billing into today-s-financial-billing

It seems this all hinges on the question, is it possible to create a filename that can be used to hack into a server (or do some-such other damage). If not, then it seems the simple answer to is try creating the file wherever it will, ultimately, be used (since that will be the operating system of choice, no doubt). Let the operating system sort it out. If it complains, port that complaint back to the User as a Validation Error.

This has the added benefit of being reliably portable, since all (I'm pretty sure) operating systems will complain if the filename is not properly formed for that OS.

If it is possible to do nefarious things with a filename, perhaps there are measures that can be applied before testing the filename on the resident operating system -- measures less complicated than a full "sanitation" of the filename.

function sanitize_file_name($file_name) { 
 // case of multiple dots
  $explode_file_name =explode('.', $file_name);
  $extension =array_pop($explode_file_name);
  $file_name_without_ext=substr($file_name, 0, strrpos( $file_name, '.') );    
  // replace special characters
  $file_name_without_ext = preg_quote($file_name_without_ext);
  $file_name_without_ext = preg_replace('/[^a-zA-Z0-9\\_]/', '_', $file_name_without_ext);
  $file_name=$file_name_without_ext . '.' . $extension;    
  return $file_name;
}

/ and .. in the user provided file name can be harmful. So you should get rid of these by something like:

$fname = str_replace('..', '', $fname);
$fname = str_replace('/',  '', $fname);

one way

$bad='/[\/:*?"<>|]/';
$string = 'fi?le*';

function sanitize($str,$pat)
{
    return preg_replace($pat,"",$str);

}
echo sanitize($string,$bad);
Related