string净化器的文件名

我正在寻找一个PHP函数,将净化一个string,并准备使用一个文件名。 任何人都知道一个方便的吗?

(我可以写一个,但是我担心我会忽略一个字符!)

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

不要担心忽略字符 – 如何使用白名单的字符,你很乐意使用? 例如,你可以只允许好的az0-9_和句点( . )的单个实例。 这显然比大多数文件系统更有限制,但应该保证你的安全。

为了解决Dominic Rodger注意到的问题,对Tor Valamo的解决scheme做一些小的调整,你可以使用:

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

那么使用rawurlencode()怎么样? http://www.php.net/manual/en/function.rawurlencode.php

这是一个function,即使中国的字符消毒:

 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("/(&)([az])([az]+;)/i", '$2', $str); $str = str_replace(' ', '-', $str); $str = rawurlencode($str); $str = str_replace('%', '-', $str); return $str; } 

这是解释

  1. 去除HTML标签
  2. 删除rest/标签/回车
  3. 删除文件夹和文件名的非法字符
  4. 把string放在小写字母中
  5. 通过将其转换为html实体,去除诸如Éàû等外国口音,然后删除代码并保留该字母。
  6. 用破折号replace空格
  7. 编码特殊字符,可以通过前面的步骤,并在服务器上input冲突文件名。 恩。 “中文百强网”
  8. 用破折号replace“%”,以确保在查询文件时文件的链接不会被浏览器重写。

好的,有些文件名不会相关,但在大多数情况下,它将起作用。

恩。 原始名称:“საბეჭდი-და-ტგრაფიული。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错误更好。

希望有帮助。

卡尔。

 preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file) 

根据系统允许的内容添加/删除更多有效的字符。

或者,你可以尝试创build文件,然后返回一个错误,如果它不好。

那么,tempnam()会为你做。

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

但是这创造了一个全新的名字。

清理现有的string只是限制用户可以input的字母,数字,句号,连字符和下划线,然后用一个简单的正则expression式进行消毒。 检查哪些字符需要转义或者可能会导致误报。

 $sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename); 

按照要求,你可以如何清理文件系统

 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上下文中使用它,那么允许在文件名中使用单引号' 是危险的,因为:

 NotExist' onerror='alert(1).jpg 

成为XSS洞 :

 <img src='<? echo $image ?>' /> // output: <img src='NotExist' onerror='alert(1)' /> 

正因为如此,受欢迎的CMS软件Wordpress将其删除,他们通过艰苦的方式(许多错误报告) 逐年学习,添加越来越多的字符是有用的:

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

最后,他们的列performance在包括大部分属于URI rerserved-字符和URL不安全字符列表的字符 。

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

所以最后我会build议使用这个:

 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://tools.ietf.org/html/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); // maximise 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的一部分:

 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字符。 但是你并不需要这样做,因为在虚拟主机上下文中使用的所有文件系统都允许使用UTF-8。

你唯一需要做的就是使用urlencode() (因为你希望对所有的URL都这么做),这样文件名საბეჭდი_მანქანა.jpg成为你的<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

这样做,所以我可以张贴这个链接作为用户会做到这一点:
http://www.maxrev.de/html/img/საბეჭდი_მანქანა。JPG

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

下面的expression式创build一个漂亮,干净,可用的string:

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

今天的财务:计费转变为今天的财务计费

对肖恩·维埃拉(Sean Vieira)的解决scheme做一个小的调整以允许单点,你可以使用:

 preg_replace("([^\w\s\d\.\-_~,;:\[\]\(\)]|[\.]{2,})", '', $file) 

PHP提供了一个将文本清理为不同格式的函数

filter.filters.sanitize

如何 :

 echo filter_var( "Lorem Ipsum has been the industry's",FILTER_SANITIZE_URL ); 

Blockquote LoremIpsumhasbeentheindustry's

解决scheme1 – 简单而有效

$file_name = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $url ) );

  • strtolower()保证文件名是小写的(因为大小写在URL内部并不重要,但在NTFS文件名中)
  • [^a-z0-9]+将确保文件名只保留字母和数字
  • '-'代替无效字符保持文件名可读

例:

 URL: http://stackoverflow.com/questions/2021624/string-sanitizer-for-filename File: http-stackoverflow-com-questions-2021624-string-sanitizer-for-filename 

解决scheme2 – 对于很长的URL

您想要cachingURL内容,只需要有唯一的文件名。 我会使用这个function:

$file_name = md5( strtolower( $url ) )

这将创build一个固定长度的文件名。 在大多数情况下,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 

这些可能有点沉重,但是它们足够灵活,可以将任何string清理成“安全”的样式文件名或文件夹名称(或者,如果弯曲的话,甚至是擦洗过的slu and和东西)。

1)build立一个完整的文件名(在input被完全截断的情况下使用备用名称):

 str_file($raw_string, $word_separator, $file_extension, $fallback_name, $length); 

2)或者只使用filter util而不build立完整的文件名(严格模式true将不允许在文件名中使用[]或()):

 str_file_filter($string, $separator, $strict, $length); 

3)这里有这些function:

 // Returns filesystem-safe string after cleaning, filtering, and trimming input function str_file_filter( $str, $sep = '_', $strict = false, $trim = 248) { $str = strip_tags(htmlspecialchars_decode(strtolower($str))); // lowercase -> decode -> strip tags $str = str_replace("%20", ' ', $str); // convert rogue %20s into spaces $str = preg_replace("/%[a-z0-9]{1,2}/i", '', $str); // remove hexy things $str = str_replace("&nbsp;", ' ', $str); // convert all nbsp into space $str = preg_replace("/&#?[a-z0-9]{2,8};/i", '', $str); // remove the other non-tag things $str = preg_replace("/\s+/", $sep, $str); // filter multiple spaces $str = preg_replace("/\.+/", '.', $str); // filter multiple periods $str = preg_replace("/^\.+/", '', $str); // trim leading period if ($strict) { $str = preg_replace("/([^\w\d\\" . $sep . ".])/", '', $str); // only allow words and digits } else { $str = preg_replace("/([^\w\d\\" . $sep . "\[\]\(\).])/", '', $str); // allow words, digits, [], and () } $str = preg_replace("/\\" . $sep . "+/", $sep, $str); // filter multiple separators $str = substr($str, 0, $trim); // trim filename to desired length, note 255 char limit on windows return $str; } // Returns full file name including fallback and extension function str_file( $str, $sep = '_', $ext = '', $default = '', $trim = 248) { // Run $str and/or $ext through filters to clean up strings $str = str_file_filter($str, $sep); $ext = '.' . str_file_filter($ext, '', true); // Default file name in case all chars are trimmed from $str, then ensure there is an id at tail if (empty($str) && empty($default)) { $str = 'no_name__' . date('Ym-d_H-m_A') . '__' . uniqid(); } elseif (empty($str)) { $str = $default; } // Return completed string if (!empty($ext)) { return $str . $ext; } else { return $str; } } 

所以我们假设一些用户input是: .....&lt;div&gt;&lt;/div&gt;<script></script>&amp; Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor \/. /. . z \... y \...... x ./ “This name” is & 462^^ not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული .....&lt;div&gt;&lt;/div&gt;<script></script>&amp; Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor \/. /. . z \... y \...... x ./ “This name” is & 462^^ not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული

我们想把它转换成友好的东西来做一个文件名长度为255个字符的tar.gz。 这是一个示例使用。 注意:这个例子包含一个格式错误的tar.gz扩展名作为概念validation,你应该在对白名单build立string之后过滤ext。

 $raw_str = '.....&lt;div&gt;&lt;/div&gt;<script></script>&amp; Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor \/. /. . z \... y \...... x ./ “This name” is & 462^^ not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული'; $fallback_str = 'generated_' . date('Ym-d_H-m_A'); $bad_extension = '....t&+++a()r.gz[]'; echo str_file($raw_str, '_', $bad_extension, $fallback_str); 

输出将是: _wei_gbel_file_name_dcor_._._._z_._y_._x_._this_name_is_462_not_that_grrrreat_][09]()1234747)_.tar.gz

你可以在这里玩它: https : //3v4l.org/iSgi8

或一个要点: https : //gist.github.com/dhaupin/b109d3a8464239b7754a

编辑:更新的脚本filter&nbsp; 而不是空间,更新3v4l链接

单程

 $bad='/[\/:*?"<>|]/'; $string = 'fi?le*'; function sanitize($str,$pat) { return preg_replace($pat,"",$str); } echo sanitize($string,$bad); 

/..在用户提供的文件名可以是有害的。 所以你应该通过这样的东西摆脱这些:

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

今天我所知道的最好的是来自Nette框架的静态方法Strings :: webalize 。

顺便说一句,这将所有的变音符号转换为它们的基本forms。š=> sü=> uß=> ss等

对于文件名,你必须添加点“。” 给允许的字符参数。

 /** * Converts to ASCII. * @param string UTF-8 encoding * @return string ASCII */ public static function toAscii($s) { static $transliterator = NULL; if ($transliterator === NULL && class_exists('Transliterator', FALSE)) { $transliterator = \Transliterator::create('Any-Latin; Latin-ASCII'); } $s = preg_replace('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{2FF}\x{370}-\x{10FFFF}]#u', '', $s); $s = strtr($s, '`\'"^~?', "\x01\x02\x03\x04\x05\x06"); $s = str_replace( array("\xE2\x80\x9E", "\xE2\x80\x9C", "\xE2\x80\x9D", "\xE2\x80\x9A", "\xE2\x80\x98", "\xE2\x80\x99", "\xC2\xB0"), array("\x03", "\x03", "\x03", "\x02", "\x02", "\x02", "\x04"), $s ); if ($transliterator !== NULL) { $s = $transliterator->transliterate($s); } if (ICONV_IMPL === 'glibc') { $s = str_replace( array("\xC2\xBB", "\xC2\xAB", "\xE2\x80\xA6", "\xE2\x84\xA2", "\xC2\xA9", "\xC2\xAE"), array('>>', '<<', '...', 'TM', '(c)', '(R)'), $s ); $s = @iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s); // intentionally @ $s = strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e" . "\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3" . "\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" . "\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe" . "\x96\xa0\x8b\x97\x9b\xa6\xad\xb7", 'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.'); $s = preg_replace('#[^\x00-\x7F]++#', '', $s); } else { $s = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); // intentionally @ } $s = str_replace(array('`', "'", '"', '^', '~', '?'), '', $s); return strtr($s, "\x01\x02\x03\x04\x05\x06", '`\'"^~?'); } /** * Converts to web safe characters [a-z0-9-] text. * @param string UTF-8 encoding * @param string allowed characters * @param bool * @return string */ public static function webalize($s, $charlist = NULL, $lower = TRUE) { $s = self::toAscii($s); if ($lower) { $s = strtolower($s); } $s = preg_replace('#[^a-z0-9' . preg_quote($charlist, '#') . ']+#i', '-', $s); $s = trim($s, '-'); return $s; } 

看来这一切都取决于这个问题,是否有可能创build一个文件名,可以用来入侵服务器(或做一些这样的其他损害)。 如果没有,那么看起来简单的答案是尝试创build文件,最终将被使用(因为这将是所select的操作系统,毫无疑问)。 让操作系统把它整理出来。 如果投诉,将该投诉移交给用户作为validation错误。

这有可移植性的额外好处,因为所有(我非常确定)的操作系统会抱怨,如果文件名不正确形成该操作系统。

如果可能用文件名来做恶意的事情,那么在testing驻留操作系统上的文件名之前,可能有一些措施可以应用 – 比文件名的完整“卫生”要复杂得多。

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

由于用户可能会使用斜线来分隔两个单词,所以最好用短划线而不是NULL来replace