URL 및 파일 이름을 안전하게 하기 위해 문자열을 삭제하시겠습니까?
URL(포스트 슬러그 등)에서 안전하게 사용할 수 있도록, 파일명으로도 사용할 수 있도록, 특정의 문자열을 잘 소거할 수 있는 기능을 생각하고 있습니다.예를 들어, 다른 사람이 파일을 업로드할 때 이름에서 위험한 문자를 모두 제거하고 싶습니다.
지금까지 저는 이 문제를 해결하고 해외 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');
}
이에 대해 실행할 수 있는 까다로운 샘플 데이터를 가지고 있는 분이나, 악명으로부터 우리 앱을 보호할 수 있는 더 좋은 방법을 알고 있는 분 계십니까?
$is-module은 temp vim 파일과 같은 추가 문자를 허용합니다.
update: 유효한 용도가 생각나지 않아 스타 문자를 삭제했습니다.
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;
}
그리고 이건 워드프레스 코드의
/**
* 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);
}
2012년 9월 갱신
Alix Axel은 이 분야에서 놀라운 일을 해냈다.그의 기능 프레임워크에는 몇 가지 훌륭한 텍스트 필터와 변환이 포함되어 있습니다.
솔루션에 대한 몇 가지 관찰 사항:
- 패턴의 끝에 있는 'u'는 일치하는 텍스트가 아니라 패턴이 UTF-8로 해석된다는 것을 의미합니다(후자를 가정한 것 같습니다).
- \w는 밑줄 문자와 일치합니다.파일에는 특별히 포함시키므로 URL에는 포함하지 않아도 되지만 코드에는 밑줄을 포함할 수 있습니다.
- 「foreign UTF-8」의 포함은, 로케일에 의존한다고 생각됩니다.이것이 서버의 로케일인지 클라이언트의 로케일인지 명확하지 않습니다.PHP 문서에서:
"word" 문자는 모든 문자, 숫자 또는 밑줄 문자, 즉 Perl "word"의 일부가 될 수 있는 모든 문자입니다.문자와 숫자의 정의는 PCRE의 문자 테이블에 의해 제어됩니다.로케일 고유의 매칭이 이루어지는 경우 다를 수 있습니다.예를 들어 "fr"(프랑스어) 로케일에서는 악센트 문자로 128을 초과하는 문자 코드가 사용되며 \w로 일치합니다.
슬래그 생성
악센트 등의 문자는 (URL 인코딩 규칙에 따라) 퍼센트로 인코딩해야 하기 때문에 URL이 보기 흉할 수 있으므로 포스트 슬러그에 포함시키지 않는 것이 좋습니다.
따라서 저라면 소문자로 구분한 후 모든 '특수' 문자를 동등한 문자(예: e-> e)로 변환하고 [a-z] 이외의 문자를 '-'로 대체하여 단일 '-'의 실행으로 제한합니다.특수문자를 변환하는 방법은 https://web.archive.org/web/20130208144021/http://neo22s.com/slug에 있습니다.
일반적으로 소독한 상태
OWASP에는 엔터프라이즈보안 API의 PHP 구현이 있습니다.이 API에는 어플리케이션의 입출력을 안전하게 인코딩 및 디코딩하는 방법이 포함되어 있습니다.
인코더 인터페이스에는 다음이 있습니다.
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)
https://github.com/OWASP/PHP-ESAPI https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
이렇게 하면 파일명이 안전해질 겁니다...
$string = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $string);
이에 대한 보다 심층적인 솔루션은 다음과 같습니다.
// 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);
이것은, 파일명에 닷이 있는 것을 전제로 하고 있습니다.소문자로 변환하고 싶은 경우는,
$clean_name = strtolower($clean_name);
마지막 줄까지.
이것을 시험해 보세요.
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
이 스레드에서 선택한 답변에 기초합니다: PHP의 URL Friendly Username?
아직 어떤 해결책도 제시하지 않았기 때문에 정확한 답변은 아니지만, 너무 커서 코멘트에 넣을 수 없습니다.
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/
다만, 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
위키피디아에 따르면:
NTFS 에서는, 각 패스 컴퍼넌트(디렉토리 또는 파일명)의 길이는 255 문자입니다.
제가 아는 한(그리고 테스트도) 이것은 잘못된 것입니다.
를 세는 것.이러한 입니다.C:\255자가 아닌 256자를 지정합니다.탐색기를 사용하여 생성된 디렉토리는 디렉토리 이름에 사용 가능한 모든 공간을 사용하지 않도록 제한됩니다.그 이유는 8.3 파일 명명 규칙을 사용하여 파일을 만들 수 있기 때문입니다.다른 파티션에서도 같은 일이 발생합니다.
물론 파일은 8.3 light 요건을 예약할 필요는 없습니다.
(255 chars) E:\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.txt
상위 디렉토리의 절대 경로가 242자를 초과할 경우 하위 디렉토리를 더 이상 생성할 수 없습니다.256 = 242 + 1 + \ + 8 + . + 3Windows 탐색기를 사용하면 상위 디렉토리가 시스템로케일에 따라 233자를 초과하는 경우 다른 디렉토리를 만들 수 없습니다.256 = 233 + 10 + \ + 8 + . + 3; 그10여기 문자열의 길이가 있습니다.New folder.
파일 시스템 간의 상호 운용성을 확보하려면 Windows 파일시스템에 심각한 문제가 발생합니다.
3. 예약 문자 및 키워드에 주의
ASCII가 아닌 문자, 인쇄할 수 없는 문자 및 제어 문자를 삭제하는 것 외에 다음 문자를 다시(배치/이동)해야 합니다.
"*/:<>?\|
이러한 문자를 삭제하는 것은, 파일명의 의미를 일부 잃을 가능성이 있기 때문에, 최적인 방법은 아닙니다.적어도 이러한 문자가 여러 개 발생할 경우 하나의 언더스코어로 대체해야 한다고 생각합니다._또는 좀 더 대표적인 것(이는 아이디어에 불과합니다)을 참조해 주세요.
"*?->_/\|->-:->[ ]-[ ]<->(>->)
피해야 할 특별한 키워드도 있습니다(예:NUL어떻게 극복해야 할지 모르겠지만요.아마도 무작위 이름의 블랙리스트가 그것을 해결하기 위한 좋은 접근법이 될 것이다.
4. 대소문자의 구별
이것은 말할 필요도 없습니다만, 다른 operating system간에 파일의 일의성을 확보하려면 , 파일명을 정규화된 대소문자로 변환해 주세요.my_file.txt그리고.My_File.txtLinux에서는 두 가지 기능이 모두 동일하지 않습니다.my_file.txt파일을 만듭니다.
5. 독자적인 것을 확인하다
파일 이름이 이미 존재하는 경우 기본 파일 이름에 고유 식별자를 추가해야 합니다.
일반적인 고유 식별자에는 UNIX 타임스탬프, 파일 내용의 다이제스트 또는 랜덤 문자열이 포함됩니다.
6. 숨김 파일
이름을 붙일 수 있다고 해서 그렇게 해야 하는 건...
도트는 일반적으로 파일 이름에 화이트리스트로 표시되지만 Linux에서는 숨겨진 파일이 선행 점으로 표시됩니다.
7. 기타 고려사항
파일 이름에서 일부 문자를 제거해야 하는 경우 일반적으로 파일의 기본 이름보다 확장자가 더 중요합니다.파일 확장자(8-16)의 최대 글자 수를 허용하면 기본 이름에서 해당 문자를 제거해야 합니다.또, 드물게 긴 연장이 여러 번 있는 경우 등에도 주의해 주세요._.graphmlz.tag.gz-_.graphmlz.tag only만._이 경우 파일 기반 이름으로 간주해야 합니다.
8. 자원
Calibre는 파일 이름 삭제 작업을 상당히 적절하게 처리합니다.
파일 이름 망글링에 대한 위키피디아 페이지와 Samba 사용의 링크된 장.
예를 들어 규칙 1/2/3 중 하나를 위반하는 파일을 작성하려고 하면 매우 유용한 오류가 발생합니다.
Warning: touch(): Unable to create file ... because No error in ... on line ...
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);
}
한 ★★UTF8::transliterate_to_ascii()= > n = > n 과 같 、 n 과 、 n 과 、 n will will will will will will will will will will
다른 한 쪽, 즉 다른 쪽, 즉 다른 쪽, 즉 다른 쪽, '아니다'는요.UTF8::*mb_* 를 포함한 .
다른 소스에서 적응하고 몇 가지 추가했습니다. 아마도 조금 과잉일 수도 있습니다.
/**
* 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('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'IJ', 'ij', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'ſ', 'ƒ', 'Ơ', 'ơ', 'Ư', 'ư', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ', 'ǒ', 'Ǔ', 'ǔ', 'Ǖ', 'ǖ', 'Ǘ', 'ǘ', 'Ǚ', 'ǚ', 'Ǜ', 'ǜ', 'Ǻ', 'ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ');
$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;
}
파일 업로드의 경우 사용자가 파일 이름을 제어하지 않도록 하는 것이 가장 안전합니다.이미 암시한 바와 같이, 정규화된 파일명을 실제 파일명으로 사용할 랜덤으로 선택된 고유 이름과 함께 데이터베이스에 저장합니다.
OWASP ESAPI 를 사용하면, 다음의 이름을 생성할 수 있습니다.
$userFilename = ESAPI::getEncoder()->canonicalize($input_string);
$safeFilename = ESAPI::getRandomizer()->getRandomFilename();
$safeFilename에 타임스탬프를 추가하여 무작위로 생성된 파일 이름이 기존 파일을 확인하지 않고도 고유함을 확인할 수 있습니다.
URL 인코딩 및 ESAPI 사용의 관점에서:
$safeForURL = ESAPI::getEncoder()->encodeForURL($input_string);
이 메서드는 문자열을 인코딩하기 전에 정규화를 수행하여 모든 문자 인코딩을 처리합니다.
PHP의 URLify를 추천합니다* (Github에서는 480개 이상의 별) - "Django 프로젝트의 URLify.js의 PHP 포트입니다.URL에서 사용할 수 있도록 ASCII 이외의 문자를 변환합니다.
기본 사용:
URL의 slug를 생성하려면:
<?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"
?>
파일 이름의 slug를 생성하려면:
<?php
echo URLify::filter ('фото.jpg', 60, "", true);
// "foto.jpg"
?>
*제 기준에 부합하는 다른 제안은 없었습니다.
- 컴포저를 통해 설치 가능
- iconv는 시스템에 따라 동작이 다르므로 의존하지 마십시오.
- 오버라이드 및 커스텀 문자 치환을 허용하려면 확장 가능해야 합니다.
- 인기(예를 들어 Github의 많은 별)
- 테스트 있음
또한 URLify는 특정 단어를 삭제하고 번역되지 않은 모든 문자를 삭제합니다.
다음은 URLify를 사용하여 많은 외국어를 올바르게 번역한 테스트 케이스입니다.https://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f
이거는 Joomla 3.3.2 버전입니다
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));
}
사용하는 방법에 따라 버퍼 오버플로우로부터 보호하기 위해 길이 제한을 추가할 수 있습니다.
제거할 검댕 목록을 가지고 있는 것은 안전하지 않다고 생각합니다.저는 다음 것을 사용하고 싶습니다.
파일명의 경우:파일 컨텐츠의 내부 ID 또는 해시를 사용합니다.문서 이름을 데이터베이스에 저장합니다.이렇게 하면 원래 파일 이름을 유지하면서 파일을 찾을 수 있습니다.
URL 사용urlencode()이치노
업로드 파일명을 보호하는 좋은 방법은 다음과 같습니다.
$file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
/**
* Sanitize Filename
*
* @param string $str Input file name
* @param bool $relative_path Whether to preserve paths
* @return string
*/
public function sanitize_filename($str, $relative_path = FALSE)
{
$bad = array(
'../', '<!--', '-->', '<', '>',
"'", '"', '&', '$', '#',
'{', '}', '[', ']', '=',
';', '?', '%20', '%22',
'%3c', // <
'%253c', // <
'%3e', // >
'%0e', // >
'%28', // (
'%29', // )
'%2528', // (
'%26', // &
'%24', // $
'%3f', // ?
'%3b', // ;
'%3d' // =
);
if ( ! $relative_path)
{
$bad[] = './';
$bad[] = '/';
}
$str = remove_invisible_characters($str, FALSE);
return stripslashes(str_replace($bad, '', $str));
}
★★★★★★★★★★★★★★★★.remove_invisible_characters★★★★★★ 。
function remove_invisible_characters($str, $url_encoded = TRUE)
{
$non_displayables = array();
// every control character except newline (dec 10),
// carriage return (dec 13) and horizontal tab (dec 09)
if ($url_encoded)
{
$non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15
$non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31
}
$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127
do
{
$str = preg_replace($non_displayables, '', $str, -1, $count);
}
while ($count);
return $str;
}
모든 종류의 이상한 라틴 문자를 포함한 엔트리 타이틀과 편리한 대시 구분 파일 이름 형식으로 번역하기 위해 필요한 HTML 태그를 가지고 있습니다.@SoLoGHoST의 답변과 @Xeoncross의 답변 중 몇 가지를 조합하여 조금 커스터마이즈했습니다.
function sanitize($string,$force_lowercase=true) {
//Clean up titles for filenames
$clean = strip_tags($string);
$clean = strtr($clean, 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 = strtr($clean, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u','—' => '-'));
$clean = str_replace("--", "-", preg_replace("/[^a-z0-9-]/i", "", preg_replace(array('/\s/', '/[^\w-\.\-]/'), array('-', ''), $clean)));
return ($force_lowercase) ?
(function_exists('mb_strtolower')) ?
mb_strtolower($clean, 'UTF-8') :
strtolower($clean) :
$clean;
}
번역 배열에 Em Dash 문자(--)를 수동으로 추가해야 했습니다.다른 파일도 있겠지만 아직까지는 내 파일명은 괜찮아 보인다.
그래서:
1부: 아빠의 '저버츠'?-최고(아니)
다음과 같이 됩니다.
제1부-내 부하-최고가 아니다
반환된 문자열에 ".html"만 추가합니다.
왜 단순히 php's를 사용하지 않는가? 이것은 "php" 문자를 URL의 16진수 표현으로 대체한다(즉,%20 (여백에 대하여)
이 질문에는 이미 몇 가지 해결책이 준비되어 있습니다만, 저는 이 코드의 대부분을 읽고 테스트했습니다.그 결과, 여기서 배운 것을 조합한 이 솔루션이 완성되었습니다.
함수
이 함수는 여기 Symfony2 번들에 번들되어 있지만 일반 PHP로 사용하기 위해 추출할 수 있습니다. 이 함수는 에만 의존합니다.iconv「CHANGE:」(영어)
파일 시스템php:
<?php
namespace COil\Bundle\COilCoreBundle\Component\HttpKernel\Util;
use Symfony\Component\HttpKernel\Util\Filesystem as BaseFilesystem;
/**
* Extends the Symfony filesystem object.
*/
class Filesystem extends BaseFilesystem
{
/**
* Make a filename safe to use in any function. (Accents, spaces, special chars...)
* The iconv function must be activated.
*
* @param string $fileName The filename to sanitize (with or without extension)
* @param string $defaultIfEmpty The default string returned for a non valid filename (only special chars or separators)
* @param string $separator The default separator
* @param boolean $lowerCase Tells if the string must converted to lower case
*
* @author COil <https://github.com/COil>
* @see http://stackoverflow.com/questions/2668854/sanitizing-strings-to-make-them-url-and-filename-safe
*
* @return string
*/
public function sanitizeFilename($fileName, $defaultIfEmpty = 'default', $separator = '_', $lowerCase = true)
{
// Gather file informations and store its extension
$fileInfos = pathinfo($fileName);
$fileExt = array_key_exists('extension', $fileInfos) ? '.'. strtolower($fileInfos['extension']) : '';
// Removes accents
$fileName = @iconv('UTF-8', 'us-ascii//TRANSLIT', $fileInfos['filename']);
// Removes all characters that are not separators, letters, numbers, dots or whitespaces
$fileName = preg_replace("/[^ a-zA-Z". preg_quote($separator). "\d\.\s]/", '', $lowerCase ? strtolower($fileName) : $fileName);
// Replaces all successive separators into a single one
$fileName = preg_replace('!['. preg_quote($separator).'\s]+!u', $separator, $fileName);
// Trim beginning and ending seperators
$fileName = trim($fileName, $separator);
// If empty use the default string
if (empty($fileName)) {
$fileName = $defaultIfEmpty;
}
return $fileName. $fileExt;
}
}
유닛 테스트
흥미로운 점은 PHPUnit 테스트를 작성했다는 것입니다.처음에는 엣지 케이스를 테스트하기 위해서입니다.필요에 맞는지 확인할 수 있습니다(버그가 발견되면 테스트 케이스를 추가해 주세요).
FilesystemTest.php:
<?php
namespace COil\Bundle\COilCoreBundle\Tests\Unit\Helper;
use COil\Bundle\COilCoreBundle\Component\HttpKernel\Util\Filesystem;
/**
* Test the Filesystem custom class.
*/
class FilesystemTest extends \PHPUnit_Framework_TestCase
{
/**
* test sanitizeFilename()
*/
public function testFilesystem()
{
$fs = new Filesystem();
$this->assertEquals('logo_orange.gif', $fs->sanitizeFilename('--logö _ __ ___ ora@@ñ--~gé--.gif'), '::sanitizeFilename() handles complex filename with specials chars');
$this->assertEquals('coilstack', $fs->sanitizeFilename('cOiLsTaCk'), '::sanitizeFilename() converts all characters to lower case');
$this->assertEquals('cOiLsTaCk', $fs->sanitizeFilename('cOiLsTaCk', 'default', '_', false), '::sanitizeFilename() lower case can be desactivated, passing false as the 4th argument');
$this->assertEquals('coil_stack', $fs->sanitizeFilename('coil stack'), '::sanitizeFilename() convert a white space to a separator');
$this->assertEquals('coil-stack', $fs->sanitizeFilename('coil stack', 'default', '-'), '::sanitizeFilename() can use a different separator as the 3rd argument');
$this->assertEquals('coil_stack', $fs->sanitizeFilename('coil stack'), '::sanitizeFilename() removes successive white spaces to a single separator');
$this->assertEquals('coil_stack', $fs->sanitizeFilename(' coil stack'), '::sanitizeFilename() removes spaces at the beginning of the string');
$this->assertEquals('coil_stack', $fs->sanitizeFilename('coil stack '), '::sanitizeFilename() removes spaces at the end of the string');
$this->assertEquals('coilstack', $fs->sanitizeFilename('coil,,,,,,stack'), '::sanitizeFilename() removes non-ASCII characters');
$this->assertEquals('coil_stack', $fs->sanitizeFilename('coil_stack '), '::sanitizeFilename() keeps separators');
$this->assertEquals('coil_stack', $fs->sanitizeFilename(' coil________stack'), '::sanitizeFilename() converts successive separators into a single one');
$this->assertEquals('coil_stack.gif', $fs->sanitizeFilename('cOil Stack.GiF'), '::sanitizeFilename() lower case filename and extension');
$this->assertEquals('copy_of_coil.stack.exe', $fs->sanitizeFilename('Copy of coil.stack.exe'), '::sanitizeFilename() keeps dots before the extension');
$this->assertEquals('default.doc', $fs->sanitizeFilename('____________.doc'), '::sanitizeFilename() returns a default file name if filename only contains special chars');
$this->assertEquals('default.docx', $fs->sanitizeFilename(' ___ - --_ __%%%%__¨¨¨***____ .docx'), '::sanitizeFilename() returns a default file name if filename only contains special chars');
$this->assertEquals('logo_edition_1314352521.jpg', $fs->sanitizeFilename('logo_edition_1314352521.jpg'), '::sanitizeFilename() returns the filename untouched if it does not need to be modified');
$userId = rand(1, 10);
$this->assertEquals('user_doc_'. $userId. '.doc', $fs->sanitizeFilename('亐亐亐亐亐.doc', 'user_doc_'. $userId), '::sanitizeFilename() returns the default string (the 2nd argument) if it can\'t be sanitized');
}
}
테스트 결과: (PHP 5.3.2가 설치된 Ubuntu 및 PHP 5.3.17이 설치된 MacOsX에서 확인됨:
All tests pass:
phpunit -c app/ src/COil/Bundle/COilCoreBundle/Tests/Unit/Helper/FilesystemTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.
Configuration read from /var/www/strangebuzz.com/app/phpunit.xml.dist
.
Time: 0 seconds, Memory: 5.75Mb
OK (1 test, 17 assertions)
솔루션 #1: 서버에 PHP 확장을 설치할 수 있습니다(호스팅).
"지구상의 거의 모든 언어"를 ASCII 문자로 번역합니다.
먼저 PHP Intl 확장을 설치합니다.다음 명령어는 Debian(Ubuntu)용입니다.
sudo aptitude install php5-intl이것은 my fileName 함수입니다(테스트 생성).php 및 여기에 붙여넣기) :
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<?php
function pr($string) {
print '<hr>';
print '"' . fileName($string) . '"';
print '<br>';
print '"' . $string . '"';
}
function fileName($string) {
// remove html tags
$clean = strip_tags($string);
// transliterate
$clean = transliterator_transliterate('Any-Latin;Latin-ASCII;', $clean);
// remove non-number and non-letter characters
$clean = str_replace('--', '-', preg_replace('/[^a-z0-9-\_]/i', '', preg_replace(array(
'/\s/',
'/[^\w-\.\-]/'
), array(
'_',
''
), $clean)));
// replace '-' for '_'
$clean = strtr($clean, array(
'-' => '_'
));
// remove double '__'
$positionInString = stripos($clean, '__');
while ($positionInString !== false) {
$clean = str_replace('__', '_', $clean);
$positionInString = stripos($clean, '__');
}
// remove '_' from the end and beginning of the string
$clean = rtrim(ltrim($clean, '_'), '_');
// lowercase the string
return strtolower($clean);
}
pr('_replace(\'~&([a-z]{1,2})(ac134/56f4315981743 8765475[]lt7ňl2ú5äňú138yé73ťž7ýľute|');
pr(htmlspecialchars('<script>alert(\'hacked\')</script>'));
pr('Álix----_Ãxel!?!?');
pr('áéíóúÁÉÍÓÚ');
pr('üÿÄËÏÖÜ.ŸåÅ');
pr('nie4č a a§ôňäääaš');
pr('Мао Цзэдун');
pr('毛泽东');
pr('ماو تسي تونغ');
pr('مائو تسهتونگ');
pr('מאו דזה-דונג');
pr('მაო ძედუნი');
pr('Mao Trạch Đông');
pr('毛澤東');
pr('เหมา เจ๋อตง');
?>
</body>
</html>
이 행은 핵심입니다.
// transliterate
$clean = transliterator_transliterate('Any-Latin;Latin-ASCII;', $clean);
해결책 2: 서버에 PHP 확장을 설치할 수 없습니다(호스팅).
CMS Drupal의 번역 모듈에서는 꽤 좋은 작업이 이루어지고 있습니다.그것은 지구상의 거의 모든 언어를 지원합니다.완전한 솔루션 삭제 문자열을 원하는 경우 플러그인 저장소를 체크할 것을 권장합니다.
이 포스트는 제가 묶은 것 중 가장 잘 작동하는 것 같습니다.http://gsynuh.com/php-string-filename-url-safe/205
이것은 좋은 기능입니다.
public function getFriendlyURL($string) {
setlocale(LC_CTYPE, 'en_US.UTF8');
$string = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string);
$string = preg_replace('~[^\-\pL\pN\s]+~u', '-', $string);
$string = str_replace(' ', '-', $string);
$string = trim($string, "-");
$string = strtolower($string);
return $string;
}
이것은 Prestashop이 URL을 삭제하기 위해 사용하는 코드입니다.
replaceAccentedChars
에 의해 사용됩니다.
str2url
발음을 없애다
function replaceAccentedChars($str)
{
$patterns = array(
/* Lowercase */
'/[\x{0105}\x{00E0}\x{00E1}\x{00E2}\x{00E3}\x{00E4}\x{00E5}]/u',
'/[\x{00E7}\x{010D}\x{0107}]/u',
'/[\x{010F}]/u',
'/[\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{011B}\x{0119}]/u',
'/[\x{00EC}\x{00ED}\x{00EE}\x{00EF}]/u',
'/[\x{0142}\x{013E}\x{013A}]/u',
'/[\x{00F1}\x{0148}]/u',
'/[\x{00F2}\x{00F3}\x{00F4}\x{00F5}\x{00F6}\x{00F8}]/u',
'/[\x{0159}\x{0155}]/u',
'/[\x{015B}\x{0161}]/u',
'/[\x{00DF}]/u',
'/[\x{0165}]/u',
'/[\x{00F9}\x{00FA}\x{00FB}\x{00FC}\x{016F}]/u',
'/[\x{00FD}\x{00FF}]/u',
'/[\x{017C}\x{017A}\x{017E}]/u',
'/[\x{00E6}]/u',
'/[\x{0153}]/u',
/* Uppercase */
'/[\x{0104}\x{00C0}\x{00C1}\x{00C2}\x{00C3}\x{00C4}\x{00C5}]/u',
'/[\x{00C7}\x{010C}\x{0106}]/u',
'/[\x{010E}]/u',
'/[\x{00C8}\x{00C9}\x{00CA}\x{00CB}\x{011A}\x{0118}]/u',
'/[\x{0141}\x{013D}\x{0139}]/u',
'/[\x{00D1}\x{0147}]/u',
'/[\x{00D3}]/u',
'/[\x{0158}\x{0154}]/u',
'/[\x{015A}\x{0160}]/u',
'/[\x{0164}]/u',
'/[\x{00D9}\x{00DA}\x{00DB}\x{00DC}\x{016E}]/u',
'/[\x{017B}\x{0179}\x{017D}]/u',
'/[\x{00C6}]/u',
'/[\x{0152}]/u');
$replacements = array(
'a', 'c', 'd', 'e', 'i', 'l', 'n', 'o', 'r', 's', 'ss', 't', 'u', 'y', 'z', 'ae', 'oe',
'A', 'C', 'D', 'E', 'L', 'N', 'O', 'R', 'S', 'T', 'U', 'Z', 'AE', 'OE'
);
return preg_replace($patterns, $replacements, $str);
}
function str2url($str)
{
if (function_exists('mb_strtolower'))
$str = mb_strtolower($str, 'utf-8');
$str = trim($str);
if (!function_exists('mb_strtolower'))
$str = replaceAccentedChars($str);
// Remove all non-whitelist chars.
$str = preg_replace('/[^a-zA-Z0-9\s\'\:\/\[\]-\pL]/u', '', $str);
$str = preg_replace('/[\s\'\:\/\[\]-]+/', ' ', $str);
$str = str_replace(array(' ', '/'), '-', $str);
// If it was not possible to lowercase the string with mb_strtolower, we do it after the transformations.
// This way we lose fewer special chars.
if (!function_exists('mb_strtolower'))
$str = strtolower($str);
return $str;
}
데이터를 활용하려면 https://stackoverflow.com/a/7610586/971619 또는 https://stackoverflow.com/a/7610586/971619 중 두 가지 좋은 답이 있습니다.
// CLEAN ILLEGAL CHARACTERS
function clean_filename($source_file)
{
$search[] = " ";
$search[] = "&";
$search[] = "$";
$search[] = ",";
$search[] = "!";
$search[] = "@";
$search[] = "#";
$search[] = "^";
$search[] = "(";
$search[] = ")";
$search[] = "+";
$search[] = "=";
$search[] = "[";
$search[] = "]";
$replace[] = "_";
$replace[] = "and";
$replace[] = "S";
$replace[] = "_";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
return str_replace($search,$replace,$source_file);
}
언급URL : https://stackoverflow.com/questions/2668854/sanitizing-strings-to-make-them-url-and-filename-safe
'programing' 카테고리의 다른 글
| 반환값과 Promise.resolve의 차이점은 무엇입니까? (0) | 2022.12.24 |
|---|---|
| 행잉 포인터와 메모리 누수의 차이 (0) | 2022.12.24 |
| Python에서의 Bash 명령어 실행 (0) | 2022.12.24 |
| 클론 방식을 올바르게 재정의하려면 어떻게 해야 합니다. (0) | 2022.12.24 |
| str==의 차이점은 무엇입니까?C의 특수 및 str[0]=='\0'은 무엇입니까? (0) | 2022.12.24 |
