文件名的字符串消毒器

2022-08-30 06:47:34

我正在寻找一个php函数,它将清理字符串并使其准备好用于文件名。有人知道一个方便的吗?

(我可以写一个,但我担心我会忽略一个角色!

编辑:用于在Windows NTFS文件系统上保存文件。


答案 1

对Tor Valamo的解决方案进行一些小的调整,以解决Dominic Rodger注意到的问题,您可以使用

// 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);

答案 2

这是按照要求清理文件系统文件名的方法

function filter_filename($name) {
    // remove illegal file system characters https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
    $name = str_replace(array_merge(
        array_map('chr', range(0, 31)),
        array('<', '>', ':', '"', '/', '\\', '|', '?', '*')
    ), '', $name);
    // maximise filename length to 255 bytes http://serverfault.com/a/9548/44086
    $ext = pathinfo($name, PATHINFO_EXTENSION);
    $name= mb_strcut(pathinfo($name, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($name)) . ($ext ? '.' . $ext : '');
    return $name;
}

其他所有内容在文件系统中都是允许的,因此这个问题得到了完美的回答......

...但是,如果您稍后在不安全的HTML上下文中使用它,则允许在文件名中使用例如单引号可能是危险的,因为这个绝对合法的文件名:'

 ' onerror= 'alert(document.cookie).jpg

成为 XSS 孔

<img src='<? echo $image ?>' />
// output:
<img src=' ' onerror= 'alert(document.cookie)' />

因此,流行的CMS软件Wordpress删除了它们,但它们仅在一些更新后才涵盖了所有相关的字符:

$special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%", "+", chr(0));
// ... a few rows later are whitespaces removed as well ...
preg_replace( '/[\r\n\t -]+/', '-', $filename )

最后,他们的列表现在包括 URI 保留字符和 URL 不安全字符列表中的大多数字符。

当然,你可以简单地在HTML输出上编码所有这些字符,但大多数开发人员和我都遵循成语“比抱歉更安全”并提前删除它们。

所以最后我建议使用这个:

function filter_filename($filename, $beautify=true) {
    // sanitize filename
    $filename = preg_replace(
        '~
        [<>:"/\\\|?*]|            # file system reserved https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
        [\x00-\x1F]|             # control characters http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
        [\x7F\xA0\xAD]|          # non-printing characters DEL, NO-BREAK SPACE, SOFT HYPHEN
        [#\[\]@!$&\'()+,;=]|     # URI reserved https://www.rfc-editor.org/rfc/rfc3986#section-2.2
        [{}^\~`]                 # URL unsafe characters https://www.ietf.org/rfc/rfc1738.txt
        ~x',
        '-', $filename);
    // avoids ".", ".." or ".hiddenFiles"
    $filename = ltrim($filename, '.-');
    // optional beautification
    if ($beautify) $filename = beautify_filename($filename);
    // maximize filename length to 255 bytes http://serverfault.com/a/9548/44086
    $ext = pathinfo($filename, PATHINFO_EXTENSION);
    $filename = mb_strcut(pathinfo($filename, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($filename)) . ($ext ? '.' . $ext : '');
    return $filename;
}

不会导致文件系统出现问题的其他所有内容都应该是附加函数的一部分:

function beautify_filename($filename) {
    // reduce consecutive characters
    $filename = preg_replace(array(
        // "file   name.zip" becomes "file-name.zip"
        '/ +/',
        // "file___name.zip" becomes "file-name.zip"
        '/_+/',
        // "file---name.zip" becomes "file-name.zip"
        '/-+/'
    ), '-', $filename);
    $filename = preg_replace(array(
        // "file--.--.-.--name.zip" becomes "file.name.zip"
        '/-*\.-*/',
        // "file...name..zip" becomes "file.name.zip"
        '/\.{2,}/'
    ), '.', $filename);
    // lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625
    $filename = mb_strtolower($filename, mb_detect_encoding($filename));
    // ".file-name.-" becomes "file-name"
    $filename = trim($filename, '.-');
    return $filename;
}

此时,如果结果为空,则需要生成文件名,并且可以决定是否要对UTF-8字符进行编码。但是您不需要这样做,因为在 Web 托管上下文中使用的所有文件系统中都允许使用 UTF-8。

您唯一要做的就是使用(因为您希望对所有URL执行此操作),因此文件名成为您的或:http://www.maxrev.de/html/img/%E1%83%A1%E1%83%90%E1%83%91%E1%83%94%E1%83%AD%E1%83%93%E1%83%98_%E1%83%9B%E1%83%90%E1%83%9C%E1%83%A5%E1%83%90%E1%83%9C%E1%83%90.jpgurlencode()საბეჭდი_მანქანა.jpg<img src><a href>

Stackoverflow就是这样做的,所以我可以像用户一样发布这个链接:
http://www.maxrev.de/html/img/ საბეჭდი_მანქანა.jpg

因此,这是一个完整的合法文件名,而不是@SequenceDigitale.com 在他的答案中提到的问题。


推荐