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-filename은 temp vim 파일과 같은 추가 문자를 허용합니다
업데이트 : 유효한 사용을 생각할 수 없으므로 별표 문자를 제거했습니다.
솔루션에 대한 몇 가지 관찰 사항 :
- 패턴의 끝에서 'u'는 일치하는 텍스트가 아닌 패턴이 UTF-8로 해석 됨을 의미합니다 (후자를 가정한다고 가정합니까?).
- \ w는 밑줄 문자와 일치합니다. URL에 원하지 않는 것으로 가정하는 파일에 대해 구체적으로 포함 시키지만 코드에는 URL에 밑줄을 포함 할 수 있습니다.
- "외부 UTF-8"의 포함은 로케일에 따라 다릅니다. 이것이 서버 또는 클라이언트의 로캘인지는 확실하지 않습니다. PHP 문서에서 :
"단어"문자는 문자 또는 숫자 또는 밑줄 문자, 즉 Perl "단어"의 일부가 될 수있는 문자입니다. 문자 및 숫자의 정의는 PCRE의 문자표로 제어되며 로케일 별 일치가 발생하는 경우 달라질 수 있습니다. 예를 들어 "fr"(프랑스어) 로캘에서 128보다 큰 일부 문자 코드는 악센트 부호 문자에 사용되며 \ w와 일치합니다.
슬러그 생성
기술적으로, URL 인코딩 규칙에 따라 백분율로 인코딩되어 못생긴 URL을 볼 수 있기 때문에 포스트 슬러그에 악센트 부호 등을 포함해서는 안됩니다.
따라서 내가 당신이라면 소문자를 뺀 후 '특수'문자를 동등한 것으로 변환하고 (예를 들어 e-> e) 비 [az] 문자를 '-'로 바꾸면 단일 '-'의 실행으로 제한됩니다 당신이 한대로. 여기에 특수 문자를 변환하는 구현이 있습니다 : https://web.archive.org/web/20130208144021/http://neo22s.com/slug
일반적으로 위생
OWASP에는 Enterprise Security 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)
https://github.com/OWASP/PHP-ESAPI https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
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 은이 분야에서 놀라운 일을했습니다. 그의 문장 구조에는 몇 가지 훌륭한 텍스트 필터와 변형이 포함됩니다.
이것은 파일 이름을 안전하게 만들어야합니다 ...
$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는 유니 코드 파일 이름 (RTL 파일도 포함)을 처리 할 수 있지만 PHP 5.3에서는 오래된 ISO-8859-1을 처리하기 위해 해킹이 필요하므로 안전을 위해서만 ASCII를 유지하는 것이 좋습니다.
2. 파일 이름의 길이 (특히 Windows의 경우)
우분투에서 파일 이름의 최대 길이 (확장명 포함)는 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
Wikipedia 는 다음과 같이 말합니다.
NTFS를 사용하면 각 경로 구성 요소 (디렉토리 또는 파일 이름)의 길이가 255 자일 수 있습니다.
내가 아는 한 (그리고 테스트) 이것은 잘못되었습니다.
C:\
256 자 (255가 아닙니까!)를 제공하는 문자열 을 제거하면이 모든 예제에 총 259 개의 문자가 포함됩니다 . 탐색기를 사용하여 생성 된 디렉토리는 디렉토리 이름에 사용 가능한 모든 공간을 사용하지 못하도록합니다. 그 이유는 8.3 파일 명명 규칙을 사용하여 파일을 만들 수 있기 때문입니다 . 다른 파티션에서도 마찬가지입니다.
파일은 물론 8.3 길이 요구 사항을 예약 할 필요가 없습니다.
(255 chars) E:\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.txt
부모 디렉토리의 절대 경로가 242자를 초과하면 하위 디렉토리를 더 이상 만들 수 없습니다 256 = 242 + 1 + \ + 8 + . + 3
. Windows 탐색기를 사용하면 상위 디렉토리의 시스템 로케일에 따라 233 자 이상인 경우 다른 디렉토리를 작성할 수 없습니다 256 = 233 + 10 + \ + 8 + . + 3
. 는 10
여기 문자열의 길이입니다 New folder
.
파일 시스템간에 상호 운용성을 보장하려는 경우 Windows 파일 시스템에 심각한 문제가 발생합니다.
3. 예약 된 문자 및 키워드주의
비 ASCII, 인쇄 불가능 및 제어 문자 를 제거하는 것 외에도 다음 을 다시 배치해야합니다.
"*/:<>?\|
파일 이름이 의미를 잃을 수 있으므로 이러한 문자를 제거하는 것이 가장 좋은 방법은 아닙니다. 최소한 이러한 문자의 여러 발생은 단일 밑줄 ( _
) 또는 더 대표적인 것으로 대체되어야한다고 생각합니다 (이것은 단지 아이디어 일뿐입니다).
"*?
->_
/\|
->-
:
->[ ]-[ ]
<
->(
>
->)
을 피하는NUL
방법은 확실하지 않지만 피해야 할 특수 키워드 도 있습니다 (예 :). 임의 이름 대체가있는 블랙리스트가이를 해결하는 좋은 방법 일 수 있습니다.
4. 대소 문자 구분
이 말도없이 가야하지만, 당신이 이렇게 서로 다른 운영 체제에서 파일 고유성을 보장하려는 경우, 정규화 된 경우에 그런 식으로 파일 이름을 변환해야 my_file.txt
하고 My_File.txt
리눅스에서 모두 같은이되지 않습니다 my_file.txt
Windows에서 파일을.
5. 고유한지 확인
파일 이름이 이미 존재하는 경우 고유 한 식별자를 기본 파일 이름에 추가해야합니다 .
일반적인 고유 식별자로는 UNIX 타임 스탬프, 파일 내용 요약 또는 임의 문자열이 있습니다.
6. 숨겨진 파일
이름을 지정할 수 있다고해서 반드시 그렇게해야하는 것은 아닙니다.
점은 일반적으로 파일 이름에 화이트리스트로 표시되지만 Linux에서는 숨겨진 파일이 선행 점으로 표시됩니다.
7. 기타 고려 사항
파일 이름의 일부 문자를 제거해야하는 경우 확장명은 일반적으로 파일의 기본 이름보다 중요합니다. 파일 확장자 (8-16)에 대해 최대 문자 수를 허용하면 기본 이름에서 문자를 제거해야합니다. 같은 - 그것은 하나 이상의 긴 확장자를 갖는 드문 경우에 점에 유의하는 것도 중요합니다 _.graphmlz.tag.gz
- _.graphmlz.tag
단지 _
이 경우 파일 기본 이름으로 고려되어야한다.
자원
Calibre 는 파일 이름이 꽤 깔끔하게 처리되도록 처리합니다.
파일 이름 맹 글링에 위키 백과 페이지 와 링크 된 삼바를 사용하는 장 .
예를 들어, 1/2/3 규칙을 위반하는 파일을 만들려고하면 매우 유용한 오류가 발생합니다.
Warning: touch(): Unable to create file ... because No error in ... on line ...
나는 항상 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);
}
핸디 UTF8::transliterate_to_ascii()
는 ñ => n과 같은 것을 돌립니다.
물론 다른 UTF8::*
것들을 mb_ * 함수로 바꿀 수도 있습니다.
파일 업로드 측면에서 사용자가 파일 이름을 제어하지 못하게하는 것이 가장 안전합니다. 이미 암시 한 것처럼 정규화 된 파일 이름을 실제 파일 이름으로 사용할 무작위로 선택되고 고유 한 이름과 함께 데이터베이스에 저장하십시오.
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+ 별) - "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"
?>
파일 이름에 대한 슬러그를 생성하려면
<?php
echo URLify::filter ('фото.jpg', 60, "", true);
// "foto.jpg"
?>
* 다른 제안들 중 어느 것도 나의 기준과 일치하지 않습니다 :
- 작곡가를 통해 설치 가능
- iconv는 다른 시스템에서 다르게 작동하기 때문에 의존해서는 안됩니다
- 재정의 및 사용자 지정 문자 교체를 허용하도록 확장 가능해야합니다.
- 인기 (예 : Github의 많은 별)
- 테스트가 있습니다
또한 URLify는 특정 단어를 제거하고 음역하지 않은 모든 문자를 제거합니다.
다음은 URLify를 사용하여 많은 외국 문자가 올바르게 음역되는 테스트 사례입니다. https://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f
나는 다른 출처에서 적응하고 몇 가지를 추가했습니다.
/**
* 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;
}
그리고 이것은 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));
}
제거 할 문자 목록이 안전하지 않다고 생각합니다. 차라리 다음을 사용합니다.
파일 이름의 경우 : 내부 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;
}
왜 단순히 PHP를 사용하지 urlencode
않습니까? "위험한"문자를 URL의 16 진수 표현으로 대체합니다 (예 : %20
공백).
이 질문에 대해 이미 여러 가지 솔루션이 제공되었지만 여기에서 대부분의 코드를 읽고 테스트했으며 여기에서 배운 내용이 혼합 된이 솔루션으로 끝났습니다.
함수
이 함수는 Symfony2 번들로 번들로 제공되지만 일반 PHP 로 사용하기 위해 추출 iconv
될 수 있으며 활성화해야하는 함수 와의 종속성 만 있습니다.
Filesystem.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)
유용한 모든 종류의 라틴 문자와 유용한 대시 구분 파일 이름 형식으로 변환하는 데 필요한 일부 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 대시 문자 (—)를 수동으로 추가해야했습니다. 다른 사람이있을 수 있지만 지금까지 내 파일 이름이 좋아 보입니다.
그래서:
제 1 부 : 아빠의“지 버트”? — 그들은 최고입니다!
된다 :
1 부-아빠-셔 버트-그들은 최고가 아닙니다
반환 된 문자열에 ".html"을 추가합니다.
해결 방법 # 1 : 서버에 PHP 확장을 설치하는 기능이 있습니다 (호스팅)
"지구상의 거의 모든 단일 언어"를 ASCII 문자로 음역합니다.
PHP Intl 확장을 먼저 설치하십시오 . 이것은 데비안 (우분투) 명령입니다 :
sudo aptitude install php5-intl
이것은 내 fileName 함수입니다 (test.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;
}
데이터를 slugfy하는이 좋은 답변이 사용이 그 https://stackoverflow.com/a/3987966/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 tip' 카테고리의 다른 글
같은 클래스의 다른 생성자에서 생성자 호출 (0) | 2020.06.26 |
---|---|
numpy 배열이 비어 있는지 여부를 어떻게 확인할 수 있습니까? (0) | 2020.06.26 |
CSV에서 큰 따옴표를 올바르게 이스케이프 처리 (0) | 2020.06.26 |
Java에 경로 결합 방법이 있습니까? (0) | 2020.06.26 |
Node.js에서 cURL이 동일합니까? (0) | 2020.06.26 |