파일 이름에 대한 문자열 살균기
문자열을 삭제하고 파일 이름에 사용할 수 있도록 준비하는 PHP 함수를 찾고 있습니다. 누구나 편리한 것을 알고 있습니까?
(하나 쓸 수 있지만 캐릭터를 놓칠 까 봐 걱정!)
편집 : Windows NTFS 파일 시스템에 파일을 저장합니다.
캐릭터를 간과하는 것에 대해 걱정하는 대신-기꺼이 사용되는 캐릭터의 화이트리스트를 사용하는 것은 어떻습니까? 예를 들어, 당신은 그냥 좋은 팔자을 허용 할 수있는 a-z
, 0-9
, _
, 및 기간의 단일 인스턴스 ( .
). 이는 대부분의 파일 시스템보다 분명히 더 제한적이지만 안전을 유지해야합니다.
Dominic Rodger가 발견 한 문제를 해결하기 위해 Tor Valamo의 솔루션을 약간 조정하면 다음 을 사용할 수 있습니다.
// 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
다음은 중국어 문자도 삭제하는 기능입니다.
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;
}
여기에 설명이 있습니다
- HTML 태그 제거
- 브레이크 / 탭 / 반환 캐리지 제거
- 폴더 및 파일 이름에 대한 잘못된 문자 제거
- 문자열을 소문자로 입력
- Éàû와 같은 외국 악센트를 html 엔터티로 변환하여 제거한 다음 코드를 제거하고 문자를 유지합니다.
- 공백을 대시로 바꾸기
- 이전 단계를 통과 할 수있는 특수 문자를 인코딩하고 서버에서 충돌 파일 이름을 입력합니다. 전의. "中文 百强 网"
- 파일을 쿼리 할 때 브라우저가 파일 링크를 다시 쓰지 않도록 "%"를 대시로 바꿉니다.
좋아, 일부 파일 이름은 릴리스되지 않지만 대부분의 경우 작동합니다.
전의. 원래 이름 : "საბეჭდი-და-ტიპოგრაფიული. 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 오류보다 낫습니다.
도움이 되었기를 바랍니다.
칼.
솔루션 1- 간단하고 효과적
$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
솔루션 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
요청에 따라 파일 시스템을 삭제하는 방법입니다.
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 소프트웨어 워드 프레스는 그것을 제거하고 그들이 배운 년 으로 올해 는 더 많은 문자를 추가하는 데 유용하는 어려운 방법 (많은 버그 리포트)를 통해 :
$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://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);
// 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 문자를 인코딩할지 여부를 결정할 수 있습니다. 그러나 웹 호스팅 컨텍스트에서 사용되는 모든 파일 시스템에서 UTF-8이 허용되므로 필요하지 않습니다.
당신이해야 할 유일한 것은 사용하는 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
Stackoverflow가 그렇게하므로 사용자가하는 것처럼이 링크를 게시 할 수 있습니다.
http://www.maxrev.de/html/img/ საბეჭდი_მანქანა. jpg
이것은 완전한 법적 파일 이름이고 그래서 문제가되지 않습니다 로서 그의 대답에 언급 @ SequenceDigitale.com .
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)
시스템에 허용되는 항목에 따라 더 많은 유효한 문자를 추가 / 제거합니다.
또는 파일 생성을 시도한 다음 문제가있는 경우 오류를 반환 할 수 있습니다.
음, tempnam ()이 당신을 위해 그것을 할 것입니다.
http://us2.php.net/manual/en/function.tempnam.php
그러나 그것은 완전히 새로운 이름을 만듭니다.
기존 문자열을 삭제하려면 사용자가 입력 할 수있는 항목을 제한하고 문자, 숫자, 마침표, 하이픈 및 밑줄로 만든 다음 간단한 정규식으로 삭제하면됩니다. 이스케이프해야하는 문자를 확인하십시오. 그렇지 않으면 오 탐지가 발생할 수 있습니다.
$sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename);
PHP는 텍스트를 다른 형식으로 삭제하는 기능을 제공합니다.
어떻게 :
echo filter_var(
"Lorem Ipsum has been the industry's",FILTER_SANITIZE_URL
);
인용구
LoremIpsumhasbeentheindustry's
다음 표현식은 멋지고 깔끔하며 사용 가능한 문자열을 만듭니다.
/[^a-z0-9\._-]+/gi
선반 오늘날의 금융 : 대금 청구 에 오늘날의 금융-청구
단일 점을 허용하도록 Sean Vieira의 솔루션을 약간 조정하면 다음을 사용할 수 있습니다.
preg_replace("([^\w\s\d\.\-_~,;:\[\]\(\)]|[\.]{2,})", '', $file)
이것들은 약간 무거울 수 있지만 어떤 문자열이든 "안전한" en
스타일의 파일 이름이나 폴더 이름 으로 정리할 수있을만큼 유연 합니다.
1) 전체 파일 이름 빌드 (입력이 완전히 잘린 경우 대체 이름 포함) :
str_file($raw_string, $word_separator, $file_extension, $fallback_name, $length);
2) 또는 전체 파일 이름을 만들지 않고 필터 유틸리티 만 사용합니다 (엄격 모드 true
는 파일 이름에 [] 또는 ()를 허용하지 않음).
str_file_filter($string, $separator, $strict, $length);
3) 그 기능은 다음과 같습니다.
// 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(" ", ' ', $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('Y-m-d_H-m_A') . '__' . uniqid();
} elseif (empty($str)) {
$str = $default;
}
// Return completed string
if (!empty($ext)) {
return $str . $ext;
} else {
return $str;
}
}
따라서 사용자 입력이 다음과 같다고 가정 해 보겠습니다. .....<div></div><script></script>& Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor \/. /. . z \... y \...... x ./ “This name” is & 462^^ not = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული
그리고 파일 이름 길이가 255자인 tar.gz를 만들기 위해 더 친숙한 것으로 변환하고 싶습니다. 다음은 사용 예입니다. 참고 :이 예제에는 개념 증명으로 잘못된 tar.gz 확장이 포함되어 있습니다. 화이트리스트에 대해 문자열이 빌드 된 후에도 ext를 필터링해야합니다.
$raw_str = '.....<div></div><script></script>& Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor \/. /. . z \... y \...... x ./ “This name” is & 462^^ not = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული';
$fallback_str = 'generated_' . date('Y-m-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
You can play with it here: https://3v4l.org/iSgi8
Or a Gist: https://gist.github.com/dhaupin/b109d3a8464239b7754a
EDIT: updated script filter for
instead of space, updated 3v4l link
The best I know today is static method Strings::webalize from Nette framework.
BTW, this translates all diacritic signs to their basic.. š=>s ü=>u ß=>ss etc.
For filenames you have to add dot "." to allowed characters parameter.
/**
* 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;
}
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.
one way
$bad='/[\/:*?"<>|]/';
$string = 'fi?le*';
function sanitize($str,$pat)
{
return preg_replace($pat,"",$str);
}
echo sanitize($string,$bad);
/
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);
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;
$fname = str_replace('/','',$fname);
Since users might use the slash to separate two words it would be better to replace with a dash instead of NULL
참고URL : https://stackoverflow.com/questions/2021624/string-sanitizer-for-filename
'programing' 카테고리의 다른 글
양식 제출시 PHP $ _POST 배열이 비어 있음 (0) | 2020.09.04 |
---|---|
NSDate 시작일과 종료일 (0) | 2020.09.04 |
한 자리 정수에서 두 자리 문자열 만들기 (0) | 2020.09.04 |
iOS 고유 사용자 식별자 (0) | 2020.09.04 |
$ _POST 존재 여부 확인 (0) | 2020.09.04 |