파일 이름에 대한 문자열 새니 타이 저


113

문자열을 삭제하고 파일 이름에 사용할 수 있도록 준비하는 PHP 함수를 찾고 있습니다. 누구나 편리한 것을 알고 있습니까?

(하나 쓸 수 있지만 캐릭터를 놓칠 까 봐 걱정!)

편집 : Windows NTFS 파일 시스템에 파일을 저장합니다.


1
좀 더 구체적으로 말씀해 주시겠습니까? 움라우트에는 어떤 일이 발생합니까 (기본 문자를 제거하거나 변환합니까?) 특수 문자는 어떻게됩니까?
Pekka

어떤 파일 시스템에 사용됩니까? 그들은 다릅니다. en.wikipedia.org/wiki/…
Gordon

Windows :) 15 자 필요.
user151841

1
가능한 모든 바람직하지 않은 문자를 확인하는 것이 불가능하기 때문에 일부 답변에서 제안 된 "블랙리스트"솔루션으로는 충분하지 않다는 점을 지적하고 싶습니다 (특수 문자 외에도 악센트 및 움라우트가있는 문자가 있습니다. 비 영어 / 라틴 알파벳, 제어 문자 등). 따라서 "화이트리스트"접근 방식이 항상 더 좋으며 문자열을 정규화 (Dominic Rodger의 답변에 대한 Blair McMillan의 의견에서 제안한대로)하면 악센트, 움라우트 등이있는 모든 문자를 자연스럽게 처리 할 수 ​​있습니다.
Sean the Bean

정규 표현식을 사용하는 좋은 방법은 내가 만든이 파이썬 스크립트를 참조하십시오. github.com/gsscoder/normalize-fn
gsscoder

답변:


42

캐릭터를 간과하는 것에 대해 걱정하는 대신-기꺼이 사용되는 캐릭터의 화이트리스트를 사용하는 것은 어떻습니까? 예를 들어, 당신은 그냥 좋은 팔자을 허용 할 수있는 a-z, 0-9, _, 및 기간의 단일 인스턴스 ( .). 이는 대부분의 파일 시스템보다 분명히 더 제한적이지만 안전을 유지해야합니다.


40
움라우트가있는 언어에는 좋지 않습니다. 결과적으로 Québec의 경우 Qubec, Düsseldorf의 경우 Dsseldorf 등이됩니다.
Pekka

15
사실-하지만 내가 말했듯이 : "예를 들어".
Dominic Rodger

5
OP에 완벽하게 수용 될 수 있습니다. 그렇지 않으면 php.net/manual/en/class.normalizer.php
Blair McMillan

3
그것은 실제로 요청 된 것이 아닙니다. op는 대안이 아닌 문자열을 삭제하는 함수를 요청합니다.
i.am.michiel 2013

3
@ i.am.michiel, 아마도 OP가 그것을 받아 들였다면 도움이되었다고 가정합니다.
Dominic Rodger 2013

157

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

43
나는 정규식 중독자를 좋아합니다! -_ ~
AVProgrammer 2012-08-13

2
@ iim.hlk-네, 래핑 괄호가 누락되었습니다. 지금 추가했습니다. 감사!
Sean Vieira 2013 년

2
거기에 결함이 있습니다. 두 개로 나누고 ..나중에 검사를 실행해야합니다 . 예를 들어 .?.복지를 끝낼 것이다 ... 당신이 필터링했기 때문에 /나는 당신이 그것을 더 이상 악용하는 방법을 볼 수 없지만 ..여기 에서 검사 가 왜 비효율적 인지 보여줍니다 . 더 나은 방법은 대체하지 말고 자격이 없으면 거부하는 것입니다.
falstro 2014

2
이러한 값은 Windows 파일 시스템에서 불법아니며 필요한 것보다 더 많은 정보를 잃어 버리는 이유는 무엇입니까? [^a-z0-9_-]정말 제한적 이길 원한다면 정규식을 간단히 변경 하거나 생성 된 이름을 사용하고 주어진 이름을 버리고 이러한 모든 문제를 피할 수 있습니다. :-)
Sean Vieira 2015

3
:는 불법입니다.
JasonXA

49

요청에 따라 파일 시스템을 삭제하는 방법입니다.

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 소프트웨어 인 Wordpress 는이를 제거하지만 일부 업데이트 후에 만 모든 관련 문자를 다루었습니다 .

$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 .


3
잘 했어. 저에게 가장 도움이되는 답변입니다. +1

오 ...이 기능은 잘 작동하지만 얼마 후부터 모든 캐릭터 사이에 r-u-l-e-s이런 일이 발생하는 이유를 모르겠습니다. 확실히 그것은 기능의 결함이 아니라 단지 묻는 것입니다. 그러한 행동의 이유는 무엇일까요? 잘못된 인코딩?

1
아 글쎄 ... 방금 디버그를했고 preg_replacein 직후에 발생합니다 filter_filename().

이 주석을 제거한 후 다시 작동하기 시작했습니다.

어떤 댓글을 삭제 했습니까? 이것이 더 쉬운 경우 저에게 이메일을 보내십시오 : gutt.it/contact.htm
mgutt

43

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;
}

여기에 설명이 있습니다

  1. HTML 태그 제거
  2. 브레이크 / 탭 / 반환 캐리지 제거
  3. 폴더 및 파일 이름에 대한 잘못된 문자 제거
  4. 문자열을 소문자로 입력
  5. Éàû와 같은 외국 악센트를 html 엔터티로 변환하여 제거한 다음 코드를 제거하고 문자를 유지합니다.
  6. 공백을 대시로 바꾸기
  7. 이전 단계를 통과 할 수있는 특수 문자를 인코딩하고 서버에서 충돌 파일 이름을 입력합니다. 전의. "中文 百强 网"
  8. 파일을 쿼리 할 때 브라우저가 파일 링크를 다시 쓰지 않도록 "%"를 대시로 바꿉니다.

좋아, 일부 파일 이름은 릴리스되지 않지만 대부분의 경우 작동합니다.

전의. 원래 이름 : "საბეჭდი-და-ტიპოგრაფიული. 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
NULL 및 제어 문자를 제거하지 않습니다. 0에서 32까지의 ASCII는 모두 문자열에서 제거되어야합니다.
Basil Musa 2015

UTF-8은 파일 시스템에서 허용되고 URL에서도 허용되는데 404 오류가 발생하는 이유는 무엇입니까? 당신이해야 할 유일한 일은 당신이 원하는 모든 URL http://www.maxrev.de/html/img/საბეჭდი_მანქანა.jpg을 가지고 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.jpgHTML 소스 코드에서 URL을 인코딩하는 것입니다.
mgutt

1
몇 가지 기타 사항 :을 제거하는 동안 strip_tags()과 그 후에 HTML 태그를 제거 [<>]합니다. 그것은 strip_tags()전혀 필요하지 않습니다. 같은 요점은 따옴표입니다. 로 디코딩 할 때 남은 따옴표가 없습니다 ENT_QUOTES. 그리고 str_replace()연속 공백을 제거하지 않고 strtolower()다중 바이트 문자열에 사용 합니다. 그리고 왜 소문자로 변환합니까? 그리고 마지막으로 @BasilMusa가 언급 한 예약 문자를 잡지 못했습니다. 내 답변에 대한 자세한 내용 : stackoverflow.com/a/42058764/318765
mgutt

그것과 사랑에 빠졌다!
Yash Kumar Verma

39

솔루션 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

4
MD5는 문제가있을 수 있습니다. URL에 해시를 사용할 때주의하십시오. URL의 skrenta.com/2007/08/md5_tutorial.html 숫자의 제곱근 은 여전히 ​​현재 웹 크기보다 훨씬 큽니다. 충돌이 발생하면 페이지를 예상했을 때 Britney Spears에 대한 페이지가 표시됩니다. Bugzilla에 대해. 우리의 경우에는 아마도 문제가되지 않지만 수십억 페이지에 대해 SHA 256과 같은 훨씬 더 큰 해싱 알고리즘을 선택하거나 완전히 피할 것입니다. 출처 : boyter.org/2013/01/code-for-a-search-engine-in-php-part-1
adilbo

15

음, tempnam ()이 당신을 위해 그것을 할 것입니다.

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

그러나 그것은 완전히 새로운 이름을 만듭니다.

기존 문자열을 삭제하려면 사용자가 입력 할 수있는 항목을 제한하고 문자, 숫자, 마침표, 하이픈 및 밑줄로 만든 다음 간단한 정규식으로 삭제하면됩니다. 이스케이프해야하는 문자를 확인하십시오. 그렇지 않으면 오 탐지가 발생할 수 있습니다.

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

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

시스템에 허용되는 항목에 따라 더 많은 유효한 문자를 추가 / 제거합니다.

또는 파일 생성을 시도한 다음 문제가있는 경우 오류를 반환 할 수 있습니다.


5
그것은 ..문제가 될 수도 있고 아닐 수도있는 같은 파일 이름을 허용 할 것 입니다.
Dominic Rodger

@Dom-고정 값이므로 별도로 확인하십시오.
Tor Valamo 2010 년

10

PHP는 텍스트를 다른 형식으로 삭제하는 기능을 제공합니다.

filter.filters.sanitize

어떻게 :

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

인용구 LoremIpsumhasbeentheindustry's


1
좋지만 슬래시가 제거되지는 않습니다. 문제가 될 수 있습니다. 디렉토리 탐색.
func0der 2011-06-11

7

안전 : NOT "a-zA-Z0-9_-"의 모든 시퀀스를 대시로 바꿉니다. 확장을 직접 추가하십시오.

$name = preg_replace('/[^a-zA-Z0-9_-]+/', '-', strtolower($name)).'.'.$extension;

1
"."로 구분 된 파일 확장자를 추가해야합니다. $ name = preg_replace ( '/ [^ a-zA-Z0-9 _-] + /', '-', strtolower ($ name)). '.' . $ extension;
Smith

6

다음 표현식은 멋지고 깔끔하며 사용 가능한 문자열을 만듭니다.

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

선반 오늘날의 금융 : 대금 청구오늘날의 금융-청구


그래서 파일 이름에는 마침표 나 밑줄 또는 그와 비슷한 것을 가질 수 없습니까?
Tor Valamo 2010 년

2
@Jonathan-이탤릭체는 무엇입니까?
Dominic Rodger

@ 토르, 네, 죄송합니다. 업데이트되었습니다. @Dominic, 텍스트에 중점을 둡니다.
Sampson

Gism이란 무엇입니까? "경고 : preg_replace () [function.preg-replace] : Unknown modifier 'g'"
user151841

1
@ user151841 preg_replace전역 플래그는 암시 적입니다. 따라서 preg_replace를 사용하는 경우 g가 필요하지 않습니다. 교체 횟수를 제어하고 싶을 때 preg_replace에는 이에 대한 limit매개 변수가 있습니다. 자세한 내용은 preg_replace 문서를 읽어보십시오.
rineez 2014 년

6

단일 점을 허용하도록 Sean Vieira의 솔루션을 약간 조정하면 다음을 사용할 수 있습니다.

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

2

이것들은 약간 무거울 수 있지만 어떤 문자열이든 "안전한" 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("&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('Y-m-d_H-m_A') . '__' . uniqid();
    } elseif (empty($str)) {
        $str = $default;
    }

    // Return completed string
    if (!empty($ext)) {
        return $str . $ext;
    } else {
        return $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) საბეჭდი-და-ტიპოგრაფიული

그리고 파일 이름 길이가 255자인 tar.gz를 만들기 위해 더 친숙한 것으로 변환하고 싶습니다. 다음은 사용 예입니다. 참고 :이 예제에는 개념 증명으로 잘못된 형식의 tar.gz 확장이 포함되어 있습니다. 화이트리스트에 대해 문자열이 빌드 된 후에도 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('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

여기에서 재생할 수 있습니다 : https://3v4l.org/iSgi8

또는 요점 : https://gist.github.com/dhaupin/b109d3a8464239b7754a

편집 :&nbsp; 공백 대신에 대한 스크립트 필터 업데이트, 3v4l 링크 업데이트


1

오늘 내가 아는 가장 좋은 방법 은 Nette 프레임 워크의 정적 메서드 Strings :: webalize 입니다.

BTW, 이것은 모든 분음 부호를 기본으로 변환합니다. š => 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;
}

분음 부호를 대체하려는 이유는 무엇입니까? urlencode()파일 이름을 src또는 으로 사용 하기 전에 사용하십시오 href. 현재 UTF-8에 문제가있는 유일한 파일 시스템은 FATx입니다 (XBOX에서 사용) : en.wikipedia.org/wiki/Comparison_of_file_systems#Limits 그리고 이것이 웹 서버에서 사용되지 않는다고 생각합니다
mgutt

1

이 모든 것이 질문에 달려있는 것 같습니다. 서버를 해킹하는 데 사용할 수있는 파일 이름을 만들 수 있습니까 (또는 다른 손상을 입힐 수 있는지). 그렇지 않은 경우에 대한 간단한 대답은 궁극적으로 사용할 위치에 관계없이 파일을 생성하는 것입니다 (확실히 선택하는 운영 체제가 될 것이기 때문에). 운영 체제에서 분류하도록하십시오. 불만 사항이있는 경우 해당 불만 사항을 유효성 검사 오류로 사용자에게 다시 포팅합니다.

이것은 파일 이름이 해당 OS에 대해 적절하게 형성되지 않으면 모든 운영 체제가 불평하기 때문에 안정적으로 이식 할 수 있다는 추가 이점이 있습니다.

이 경우 입니다 적은 파일 이름의 전체 "위생"보다 복잡한 방법 - 파일 이름으로 사악한 일을 할 수 아마도 상주 운영 체제에서 파일 이름을 테스트하기 전에 적용 할 수있는 방법이있다.


0

일방 통행

$bad='/[\/:*?"<>|]/';
$string = 'fi?le*';

function sanitize($str,$pat)
{
    return preg_replace($pat,"",$str);

}
echo sanitize($string,$bad);

인쇄 할 수없는 문자는 어떻습니까? 이 경우 블랙리스트 접근 방식보다 화이트리스트 접근 방식을 사용하는 것이 좋습니다. 물론 특수 문자를 제외한 인쇄 가능한 ASCII 파일 이름 만 기본적으로 허용합니다. 그러나 영어가 아닌 로케일의 경우 이는 또 다른 문제입니다.
TheRealChx101

0

/그리고 ..사용자가 제공 한 파일 이름에 해가 될 수 있습니다. 따라서 다음과 같이 제거해야합니다.

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

이것은 충분하지 않습니다! 예를 들어, 파일 이름 "./.name"은 여전히 ​​현재 디렉토리에서 분리됩니다. (.. 제거는 여기에서 아무 작업도 수행하지 않지만 / 제거하면 ./.가 ..로 바뀌므로 대상 디렉터리
벗어나게

3
@ cemper93 아니요,이 대답은 문자열을 ..name아무것도 벗어나지 않는 문자열로 바꿉니다 . 모든 경로 분리 문자를 제거하면 디렉토리 순회를 방지 할 수 있습니다. (의 제거는 ..기술적으로 필요하지 않습니다.)
cdhowie

@cdhowie 예,하지만 파일 이름 ./.... 마지막 으로이 대답은 NULL과 같은 다른 모든 파일 시스템 예약 문자를 놓칩니다. 내 대답에 더 많은 것 : stackoverflow.com/a/42058764/318765
mgutt

-4

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

사용자는 슬래시를 사용하여 두 단어를 구분할 수 있으므로 NULL 대신 대시로 바꾸는 것이 좋습니다.


그가 NULL로 대체 할 것이라고 말한 곳은 어디입니까? 또한 이것은 모든 특수 문자를 처리하지 않습니다.
Travis Pessetto 2013

예-처리가 필요한 다른 특수 문자도 있습니다. 어쨌든 str_replace는 여기에서 가장 좋은 입찰이 아닙니다.
Martin Kovachev
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.