(我可以自己写一个,但是我担心会忽略某个字符!)
编辑:用于在Windows NTFS文件系统上保存文件。
对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);
[^a-z0-9_-]
,如果你想要更加严格 - 或者只需使用生成的名称,丢弃给定的名称,避免所有这些问题。 :-) - Sean Vieiratrim()
函数来去除前后的空格,这样复制粘贴的 filename.txt
就会被清理成 filename.txt
。 - Slavafunction 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)' />
$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;
}
您需要做的唯一一件事就是使用urlencode()
(希望您对所有URL都这样做),以便文件名საბეჭდი_მანქანა.jpg
变成此URL作为您的<img src>
或<a href>
:
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.jpg
filter_filename()
函数中的preg_replace
之后。 - user5147563preg_replace('~[<>:"/\\|?*]~x','-', $filename)
会允许 Hello\World.txt
正常通过!将 [<>:"/\\|?*]
改为 [<>:"/\\\|?*]
即可修复该问题。 - spackmat解决方案1 - 简单而有效
$file_name = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $url ) );
[^a-z0-9]+
将确保文件名仅包含字母和数字'-'
替换无效字符可使文件名可读性更好示例:
URL: https://dev59.com/eHI-5IYBdhLWcg3wFkOO
File: http-stackoverflow-com-questions-2021624-string-sanitizer-for-filename
解决方案2 - 适用于非常长的URL
您希望缓存URL内容并且只需要具有唯一文件名。 我建议使用以下函数:
$file_name = md5( strtolower( $url ) )
这将创建一个固定长度的文件名。在大多数情况下,MD5哈希对这种用途是足够独特的。
示例:
URL: https://www.amazon.com/Interstellar-Matthew-McConaughey/dp/B00TU9UFTS/ref=s9_nwrsa_gw_g318_i10_r?_encoding=UTF8&fpl=fresh&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=desktop-1&pf_rd_r=BS5M1H560SMAR2JDKYX3&pf_rd_r=BS5M1H560SMAR2JDKYX3&pf_rd_t=36701&pf_rd_p=6822bacc-d4f0-466d-83a8-2c5e1d703f8e&pf_rd_p=6822bacc-d4f0-466d-83a8-2c5e1d703f8e&pf_rd_i=desktop
File: 51301f3edb513f6543779c3a5433b01c
使用rawurlencode()怎么样?http://www.php.net/manual/en/function.rawurlencode.php
这里有一个可以过滤中文字符的函数:
public static function normalizeString ($str = '')
{
$str = strip_tags($str);
$str = preg_replace('/[\r\n\t ]+/', ' ', $str);
$str = preg_replace('/[\"\*\/\:\<\>\?\'\|]+/', ' ', $str);
$str = strtolower($str);
$str = html_entity_decode( $str, ENT_QUOTES, "utf-8" );
$str = htmlentities($str, ENT_QUOTES, "utf-8");
$str = preg_replace("/(&)([a-z])([a-z]+;)/i", '$2', $str);
$str = str_replace(' ', '-', $str);
$str = rawurlencode($str);
$str = str_replace('%', '-', $str);
return $str;
}
有些文件名可能不相关,但在大多数情况下它将起作用。
例如:
原始文件名:“საბეჭდი-და-ტიპოგრაფიული.jpg”
输出文件名:“-E1-83-A1-E1-83-90-E1-83-91-E1-83-94-E1-83-AD-E1-83-93-E1-83-98--E1-83-93-E1-83-90--E1-83-A2-E1-83-98-E1-83-9E-E1-83-9D-E1-83-92-E1-83-A0-E1-83-90-E1-83-A4-E1-83-98-E1-83-A3-E1-83-9A-E1-83-98.jpg”
这样比404错误更好。
希望对您有所帮助。
卡尔。
http://www.maxrev.de/html/img/საბეჭდი_მანქანა.jpg
编码为 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.jpg
,就像你希望对所有URL进行的那样,在HTML源代码中。 - mguttstrip_tags()
去除 HTML 标签,然后再去除 [<>]
。这样 strip_tags()
实际上就不是必需的了。同样的道理也适用于引号。当你使用 ENT_QUOTES
解码时,就没有引号了。而且 str_replace()
不会删除连续的空格,然后你又使用 strtolower()
处理多字节字符串。为什么你要转换成小写呢?最后,你没有像 @BasilMusa 提到的那样捕获任何保留字符。更多细节请参见我的答案:https://dev59.com/eHI-5IYBdhLWcg3wFkOO#42058764。 - mgutt\s
替换[\r\n\t ]
?在[\"\*\/\:\<\>\?\'\|]
中有太多不必要的转义。 - mickmackusa不必担心遗漏字符 - 为什么不使用一个白名单来限制可以使用的字符呢?例如,您可以只允许使用a-z
、0-9
、_
和一个点(.
)的实例。这显然比大多数文件系统更具限制性,但可以保障您的安全。
https://www.php.net/manual/en/function.tempnam.php
但这会创建一个全新的名称。$sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename);
安全性:将每个非 "a-zA-Z0-9_-" 字符序列替换为破折号;自行添加扩展名。
$name = preg_replace('/[^a-zA-Z0-9_-]+/', '-', strtolower($name)).'.'.$extension;
所以有一个名为PDF的文件
"This is a grüte test_service +/-30 thing"
变成
"This-is-a-gr-te-test_service-30-thing.pdf"
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)
根据你的系统允许的内容,添加/删除更多有效字符。
或者,您可以尝试创建文件,如果文件不正确则返回错误。
..
这样的文件名通过,这可能是一个问题也可能不是。 - Dominic Rodger\d
和_
写在同一字符类中的答案都表明缺乏正则表达式模式基础。 - mickmackusaPHP提供了一个函数来将文本转换为不同的格式
filter_var()
与第二个参数FILTER_SANITIZE_URL
一起使用
echo filter_var(
"Lorem Ipsum has been the industry's", FILTER_SANITIZE_URL
);
LoremIpsum已成为该行业的
\ / : * ? " < > |
。 然而,这些字符在使用FILTER_SANITIZE_URL
规则时都是被允许的。 - thelrFILTER_SANITIZE_EMAIL
。删除除字母、数字和 !#$%&'*+-=?^_\
{|}~@.[]` 之外的所有字符。 - dobspreg_replace("([^\w\s\d\.\-_~,;:\[\]\(\)]|[\.]{2,})", '', $file)