Xeo*_*oss 134 php url filenames sanitization
我试图想出一个功能,它可以很好地清理某些字符串,以便它们可以安全地在URL中使用(如post slug),也可以安全地用作文件名.例如,当有人上传文件时,我想确保从名称中删除所有危险字符.
到目前为止,我已经提出了以下函数,我希望能解决这个问题并允许外部UTF-8数据.
/**
* Convert a string to the file/URL safe "slug" form
*
* @param string $string the string to clean
* @param bool $is_filename TRUE will allow additional filename characters
* @return string
*/
function sanitize($string = '', $is_filename = FALSE)
{
// Replace all weird characters with dashes
$string = preg_replace('/[^\w\-'. ($is_filename ? '~_\.' : ''). ']+/u', '-', $string);
// Only allow one dash separator at a time (and make string lowercase)
return mb_strtolower(preg_replace('/--+/u', '-', $string), 'UTF-8');
}
Run Code Online (Sandbox Code Playgroud)
有没有人有任何棘手的样本数据我可以针对此运行 - 或者知道更好的方法来保护我们的应用程序免受坏名声?
$ is-filename允许一些额外的字符,如temp vim文件
更新:删除了明星字符,因为我无法想到有效用途
Xeo*_*oss 87
我在Chyrp代码中发现了这个更大的功能:
/**
* Function: sanitize
* Returns a sanitized string, typically for URLs.
*
* Parameters:
* $string - The string to sanitize.
* $force_lowercase - Force the string to lowercase?
* $anal - If set to *true*, will remove all non-alphanumeric characters.
*/
function sanitize($string, $force_lowercase = true, $anal = false) {
$strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
"}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—",
"—", "–", ",", "<", ".", ">", "/", "?");
$clean = trim(str_replace($strip, "", strip_tags($string)));
$clean = preg_replace('/\s+/', "-", $clean);
$clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
return ($force_lowercase) ?
(function_exists('mb_strtolower')) ?
mb_strtolower($clean, 'UTF-8') :
strtolower($clean) :
$clean;
}
Run Code Online (Sandbox Code Playgroud)
这个在wordpress代码中
/**
* Sanitizes a filename replacing whitespace with dashes
*
* Removes special characters that are illegal in filenames on certain
* operating systems and special characters requiring special escaping
* to manipulate at the command line. Replaces spaces and consecutive
* dashes with a single dash. Trim period, dash and underscore from beginning
* and end of filename.
*
* @since 2.1.0
*
* @param string $filename The filename to be sanitized
* @return string The sanitized filename
*/
function sanitize_file_name( $filename ) {
$filename_raw = $filename;
$special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}");
$special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $filename_raw);
$filename = str_replace($special_chars, '', $filename);
$filename = preg_replace('/[\s-]+/', '-', $filename);
$filename = trim($filename, '.-_');
return apply_filters('sanitize_file_name', $filename, $filename_raw);
}
Run Code Online (Sandbox Code Playgroud)
Alix Axel在这方面做了一些令人难以置信的工作.他的功能框架包括几个伟大的文本过滤器和转换.
Ala*_*lly 57
您对解决方案的一些观察:
"单词"字符是任何字母或数字或下划线字符,即任何可以成为Perl"单词"一部分的字符.字母和数字的定义由PCRE的字符表控制,如果发生特定于语言环境的匹配,则可能会有所不同.例如,在"fr"(法语)语言环境中,一些大于128的字符代码用于重音字母,并且这些字符代码由\ w匹配.
您可能不应该在帖子中包含重音等字符,因为从技术上讲,它们应该是百分比编码(根据URL编码规则),因此您将看到难看的URL.
所以,如果我是你,在小写之后,我将任何'特殊'字符转换为它们的等价物(例如é - > e)并用' - '替换非[az]字符,限制单个' - '的运行就像你做的那样.这里有一个转换特殊字符的实现:https://web.archive.org/web/20130208144021/http : //neo22s.com/slug
OWASP有一个企业安全API的PHP实现,其中包括在应用程序中安全编码和解码输入和输出的方法.
编码器接口提供:
canonicalize (string $input, [bool $strict = true])
decodeFromBase64 (string $input)
decodeFromURL (string $input)
encodeForBase64 (string $input, [bool $wrap = false])
encodeForCSS (string $input)
encodeForHTML (string $input)
encodeForHTMLAttribute (string $input)
encodeForJavaScript (string $input)
encodeForOS (Codec $codec, string $input)
encodeForSQL (Codec $codec, string $input)
encodeForURL (string $input)
encodeForVBScript (string $input)
encodeForXML (string $input)
encodeForXMLAttribute (string $input)
encodeForXPath (string $input)
Run Code Online (Sandbox Code Playgroud)
https://github.com/OWASP/PHP-ESAPI https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
SoL*_*oST 30
这应该使您的文件名安全...
$string = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $string);
Run Code Online (Sandbox Code Playgroud)
更深层次的解决方案是:
// Remove special accented characters - ie. sí.
$clean_name = strtr($string, array('Š' => 'S','Ž' => 'Z','š' => 's','ž' => 'z','Ÿ' => 'Y','À' => 'A','Á' => 'A','Â' => 'A','Ã' => 'A','Ä' => 'A','Å' => 'A','Ç' => 'C','È' => 'E','É' => 'E','Ê' => 'E','Ë' => 'E','Ì' => 'I','Í' => 'I','Î' => 'I','Ï' => 'I','Ñ' => 'N','Ò' => 'O','Ó' => 'O','Ô' => 'O','Õ' => 'O','Ö' => 'O','Ø' => 'O','Ù' => 'U','Ú' => 'U','Û' => 'U','Ü' => 'U','Ý' => 'Y','à' => 'a','á' => 'a','â' => 'a','ã' => 'a','ä' => 'a','å' => 'a','ç' => 'c','è' => 'e','é' => 'e','ê' => 'e','ë' => 'e','ì' => 'i','í' => 'i','î' => 'i','ï' => 'i','ñ' => 'n','ò' => 'o','ó' => 'o','ô' => 'o','õ' => 'o','ö' => 'o','ø' => 'o','ù' => 'u','ú' => 'u','û' => 'u','ü' => 'u','ý' => 'y','ÿ' => 'y'));
$clean_name = strtr($clean_name, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u'));
$clean_name = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $clean_name);
Run Code Online (Sandbox Code Playgroud)
这假定您需要文件名中的点.如果你想将它转移到小写,只需使用
$clean_name = strtolower($clean_name);
Run Code Online (Sandbox Code Playgroud)
为最后一行.
Joh*_*nde 21
试试这个:
function normal_chars($string)
{
$string = htmlentities($string, ENT_QUOTES, 'UTF-8');
$string = preg_replace('~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', $string);
$string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
$string = preg_replace(array('~[^0-9a-z]~i', '~[ -]+~'), ' ', $string);
return trim($string, ' -');
}
Examples:
echo normal_chars('Álix----_Ãxel!?!?'); // Alix Axel
echo normal_chars('áéíóúÁÉÍÓÚ'); // aeiouAEIOU
echo normal_chars('üÿÄËÏÖÜŸåÅ'); // uyAEIOUYaA
Run Code Online (Sandbox Code Playgroud)
根据此主题中选定的答案:PHP中的URL友好用户名?
Ali*_*xel 13
这不是一个答案,因为它没有提供任何解决方案(还有!),但它太大了,不适合评论......
我在Windows 7和Ubuntu 12.04上做了一些测试(关于文件名),我发现的是:
1. PHP无法处理非ASCII文件名
虽然Windows和Ubuntu都可以处理Unicode文件名(甚至看起来像RTL)但是PHP 5.3甚至要求使用普通的旧版ISO-8859-1进行处理,所以为了安全起见,最好保留ASCII文件名.
2.文件名的长度很重要(特别是在Windows上)
在Ubuntu上,文件名可以拥有的最大长度(包括扩展名)是255(不包括路径):
/var/www/uploads/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345/
Run Code Online (Sandbox Code Playgroud)
但是,在Windows 7(NTFS)上,文件名的最大长度取决于它的绝对路径:
(0 + 0 + 244 + 11 chars) C:\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\1234567.txt
(0 + 3 + 240 + 11 chars) C:\123\123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\1234567.txt
(3 + 3 + 236 + 11 chars) C:\123\456\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1234567.txt
Run Code Online (Sandbox Code Playgroud)
维基百科说:
NTFS允许每个路径组件(目录或文件名)长度为255个字符.
据我所知(和测试),这是错误的.
总共(计算斜线)所有这些示例都有259个字符,如果你去掉C:\它会产生256个字符(不是255?!).使用资源管理器创建的目录,您会注意到它限制自己使用目录名称的所有可用空间.这样做的原因是允许使用8.3文件命名约定创建文件.其他分区也会发生同样的事情.
文件当然不需要保留8.3长度要求:
(255 chars) E:\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.txt
Run Code Online (Sandbox Code Playgroud)
如果父目录的绝对路径超过242个字符,则无法再创建子目录,因为256 = 242 + 1 + \ + 8 + . + 3.如果父目录的字符数超过233个(取决于系统区域设置),则使用Windows资源管理器无法创建另一个目录,因为256 = 233 + 10 + \ + 8 + . + 3; 在10这里是字符串的长度New folder.
如果要确保文件系统之间的互操作性,Windows文件系统会带来一个令人讨厌的问题.
3.注意保留字符和关键字
除了删除非ASCII,不可打印和控制字符外,还需要重新(放置/移动):
"*/:<>?\|
Run Code Online (Sandbox Code Playgroud)
删除这些字符可能不是最好的主意,因为文件名可能会失去一些意义.我认为,至少,这些字符的多次出现应该被单个下划线(_)取代,或者更具代表性(这只是一个想法):
"*? - > _/\| - > -: - > [ ]-[ ]< - > (> - > )还有一些特殊的关键词应该避免(比如NUL),虽然我不知道如何克服这个问题.也许带有随机名称后备的黑名单是解决它的好方法.
4.案例敏感性
这不用说,但如果你想这样确保文件在不同的操作系统上的独特性,你应该转换文件名归一化的情况下,这种方式my_file.txt和My_File.txt在Linux上不会都成为相同my_file.txt的Windows文件.
5.确保它是独一无二的
如果文件名已存在,则应将唯一标识符附加到其基本文件名.
公共唯一标识符包括UNIX时间戳,文件内容的摘要或随机字符串.
6.隐藏文件
仅因为它可以被命名并不意味着它应该......
点通常在文件名中以白名单列出,但在Linux中,隐藏文件由前导点表示.
7.其他考虑因素
如果必须删除文件名的一些字符,则扩展名通常比文件的基本名称更重要.允许文件扩展名(8-16)具有相当大的最大字符数,应从基本名称中删除字符.同样重要的是要注意,在不太可能发生多个长扩展的情况下 - 例如_.graphmlz.tag.gz- 在这种情况下_.graphmlz.tag只_应被视为文件基名.
8.资源
Calibre处理文件名错误相当:
例如,如果您尝试创建违反任何规则1/2/3的文件,您将收到一个非常有用的错误:
Warning: touch(): Unable to create file ... because No error in ... on line ...
Run Code Online (Sandbox Code Playgroud)
ale*_*lex 11
我一直认为Kohana做得很好.
public static function title($title, $separator = '-', $ascii_only = FALSE)
{
if ($ascii_only === TRUE)
{
// Transliterate non-ASCII characters
$title = UTF8::transliterate_to_ascii($title);
// Remove all characters that are not the separator, a-z, 0-9, or whitespace
$title = preg_replace('![^'.preg_quote($separator).'a-z0-9\s]+!', '', strtolower($title));
}
else
{
// Remove all characters that are not the separator, letters, numbers, or whitespace
$title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', UTF8::strtolower($title));
}
// Replace all separator characters and whitespace by a single separator
$title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title);
// Trim separators from the beginning and end
return trim($title, $separator);
}
Run Code Online (Sandbox Code Playgroud)
方便的UTF8::transliterate_to_ascii()将变成ñ=> n之类的东西.
当然,你可以UTF8::*用mb_*函数替换其他东西.
在文件上传方面,最安全的做法是阻止用户控制文件名.正如已经暗示的那样,将规范化的文件名存储在数据库中,并随机选择一个唯一的名称作为实际文件名.
使用OWASP ESAPI,可以生成这些名称:
$userFilename = ESAPI::getEncoder()->canonicalize($input_string);
$safeFilename = ESAPI::getRandomizer()->getRandomFilename();
Run Code Online (Sandbox Code Playgroud)
您可以在$ safeFilename中附加时间戳,以帮助确保随机生成的文件名是唯一的,甚至不检查现有文件.
在URL编码方面,再次使用ESAPI:
$safeForURL = ESAPI::getEncoder()->encodeForURL($input_string);
Run Code Online (Sandbox Code Playgroud)
此方法在编码字符串之前执行规范化,并将处理所有字符编码.
我改编自另一个来源并增加了一些额外的,可能有点矫枉过正
/**
* Convert a string into a url safe address.
*
* @param string $unformatted
* @return string
*/
public function formatURL($unformatted) {
$url = strtolower(trim($unformatted));
//replace accent characters, forien languages
$search = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 'Œ', 'œ', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 'Š', 'š', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 'Ÿ', '?', '?', '?', '?', 'Ž', 'ž', '?', 'ƒ', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?');
$replace = array('A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 's', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'l', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U', 'u', 'A', 'a', 'I', 'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o');
$url = str_replace($search, $replace, $url);
//replace common characters
$search = array('&', '£', '$');
$replace = array('and', 'pounds', 'dollars');
$url= str_replace($search, $replace, $url);
// remove - for spaces and union characters
$find = array(' ', '&', '\r\n', '\n', '+', ',', '//');
$url = str_replace($find, '-', $url);
//delete and replace rest of special chars
$find = array('/[^a-z0-9\-<>]/', '/[\-]+/', '/<[^>]*>/');
$replace = array('', '-', '');
$uri = preg_replace($find, $replace, $url);
return $uri;
}
Run Code Online (Sandbox Code Playgroud)
小智 5
这是Joomla 3.3.2版本 JFile::makeSafe($file)
public static function makeSafe($file)
{
// Remove any trailing dots, as those aren't ever valid file names.
$file = rtrim($file, '.');
$regex = array('#(\.){2,}#', '#[^A-Za-z0-9\.\_\- ]#', '#^\.#');
return trim(preg_replace($regex, '', $file));
}
Run Code Online (Sandbox Code Playgroud)
我建议* 用于PHP的URLify(在Github上为480颗星以上) -“来自Django项目的URLify.js的PHP端口。对非ASCII字符进行音译以用于URL”。
基本用法:
要为URL生成段:
<?php
echo URLify::filter (' J\'étudie le français ');
// "jetudie-le-francais"
echo URLify::filter ('Lo siento, no hablo español.');
// "lo-siento-no-hablo-espanol"
?>
Run Code Online (Sandbox Code Playgroud)
要为文件名生成段:
<?php
echo URLify::filter ('????.jpg', 60, "", true);
// "foto.jpg"
?>
Run Code Online (Sandbox Code Playgroud)
*没有其他建议符合我的标准:
另外,URLify还会删除某些单词并去除所有未音译的字符。
这是一个测试案例,其中大量的外来字符已使用URLify正确音译:https ://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f
| 归档时间: |
|
| 查看次数: |
167764 次 |
| 最近记录: |