trình vệ sinh chuỗi cho tên tệp


113

Tôi đang tìm một hàm php sẽ làm sạch một chuỗi và làm cho nó sẵn sàng để sử dụng cho một tên tệp. Có ai biết về một cái tiện dụng không?

(Tôi có thể viết một cái, nhưng tôi lo rằng tôi sẽ bỏ qua một nhân vật!)

Chỉnh sửa: để lưu tệp trên hệ thống tệp Windows NTFS.


1
Bạn có thể nói cụ thể hơn: Điều gì sẽ xảy ra với Umlauts (loại bỏ hoặc chuyển đổi sang ký tự cơ bản?) Điều gì sẽ xảy ra với các ký tự đặc biệt?
Pekka

Dành cho hệ thống tập tin nào? Chúng khác nhau. Xem en.wikipedia.org/wiki/…
Gordon

Windows :) Cần 15 ký tự.
user151841

1
Tôi muốn chỉ ra rằng các giải pháp "danh sách đen" được đề xuất trong một số câu trả lời là không đủ, vì không thể kiểm tra được mọi ký tự không mong muốn có thể xảy ra (ngoài các ký tự đặc biệt, còn có các ký tự có dấu và âm sắc, toàn bộ bảng chữ cái không phải tiếng Anh / latin, ký tự điều khiển, v.v. để đối phó). Vì vậy, tôi cho rằng cách tiếp cận "danh sách trắng" luôn tốt hơn và việc chuẩn hóa chuỗi (như được gợi ý bởi nhận xét của Blair McMillan về câu trả lời của Dominic Rodger) sẽ cho phép xử lý tự nhiên bất kỳ chữ cái nào có dấu, âm sắc, v.v.
Sean the Bean

Cách tốt nhất có lẽ sử dụng biểu thức thông thường, xem kịch bản này python tôi thực hiện: github.com/gsscoder/normalize-fn
gsscoder

Câu trả lời:


42

Thay vì lo lắng về việc bỏ qua các ký tự - bạn có thể sử dụng danh sách trắng các ký tự mà bạn cảm thấy hài lòng không? Ví dụ, bạn có thể cho phép ol chỉ tốt' a-z, 0-9, _, và một trường hợp duy nhất của một giai đoạn ( .). Điều đó rõ ràng là hạn chế hơn hầu hết các hệ thống tệp, nhưng sẽ giúp bạn an toàn.


40
Không tốt cho các ngôn ngữ có Umlauts. Điều này sẽ dẫn đến Qubec cho Québec, Dsseldorf cho Düsseldorf, v.v.
Pekka

15
Đúng - nhưng như tôi đã nói: "Ví dụ".
Dominic Rodger

5
Điều này có thể hoàn toàn được OP chấp nhận. Nếu không, sử dụng giống như php.net/manual/en/class.normalizer.php
Blair McMillan

3
Đó thực sự không phải là những gì được hỏi. Op yêu cầu một chức năng để làm sạch chuỗi, không phải là một thay thế.
i.am.michiel

3
@ i.am.michiel, có lẽ, nhưng nếu OP chấp nhận nó, tôi sẽ cho rằng họ thấy nó hữu ích.
Dominic Rodger

157

Thực hiện một điều chỉnh nhỏ đối với giải pháp của Tor Valamo để khắc phục sự cố mà Dominic Rodger nhận thấy, bạn có thể sử dụng:

// 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
Tôi yêu những người nghiện regex! -_ ~
AVProgrammer

2
@ iim.hlk - vâng, nó bị thiếu dấu ngoặc đơn. Tôi đã thêm chúng ngay bây giờ. Cảm ơn!
Sean Vieira

2
có một lỗ hổng ở đó, bạn nên chia nó thành hai và chạy kiểm tra ..sau đó. Ví dụ .?.cuối cùng sẽ là ... Mặc dù vì bạn lọc, /tôi không thể biết bạn khai thác thêm điều đó như thế nào ngay bây giờ, nhưng nó cho thấy lý do tại sao việc kiểm tra ..không hiệu quả ở đây. Tốt hơn hết là không nên thay thế, chỉ từ chối nếu nó không đủ điều kiện.
falstro

2
Bởi vì không có giá trị nào trong số đó là bất hợp pháp trên hệ thống tệp Windows và tại sao lại mất nhiều thông tin hơn bạn phải làm? Bạn có thể thay đổi biểu thức chính quy thành đơn giản [^a-z0-9_-]nếu bạn muốn thực sự hạn chế - hoặc chỉ sử dụng tên được tạo và loại bỏ tên đã cho và tránh tất cả những vấn đề này. :-)
Sean Vieira

3
Lưu ý rằng: là bất hợp pháp.
JasonXA

49

Đây là cách bạn có thể làm sạch hệ thống tệp khi được yêu cầu

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

Mọi thứ khác đều được phép trong hệ thống tệp, vì vậy câu hỏi được trả lời hoàn hảo ...

... nhưng thể nguy hiểm nếu cho phép các dấu ngoặc kép ví dụ' trong tên tệp nếu bạn sử dụng nó sau này trong ngữ cảnh HTML không an toàn vì tên tệp hoàn toàn hợp pháp này:

 ' onerror= 'alert(document.cookie).jpg

trở thành một lỗ XSS :

<img src='<? echo $image ?>' />
// output:
<img src=' ' onerror= 'alert(document.cookie)' />

Do đó, phần mềm CMS phổ biến Wordpress sẽ loại bỏ chúng, nhưng chúng chỉ bao gồm tất cả các ký tự liên quan sau một số bản cập nhật :

$special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%", "+", chr(0));
// ... a few rows later are whitespaces removed as well ...
preg_replace( '/[\r\n\t -]+/', '-', $filename )

Cuối cùng, danh sách của họ bây giờ bao gồm hầu hết các ký tự là một phần của các ký tự được khôi phục lại URI và các ký tự không an toàn cho URL danh sách.

Tất nhiên bạn có thể đơn giản mã hóa tất cả các ký tự này trên đầu ra HTML, nhưng hầu hết các nhà phát triển và tôi cũng vậy, hãy làm theo câu thành ngữ "An toàn hơn là xin lỗi" và xóa chúng trước.

Vì vậy, cuối cùng tôi đề nghị sử dụng cái này:

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

Mọi thứ khác không gây ra sự cố với hệ thống tệp phải là một phần của chức năng bổ sung:

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

Và tại thời điểm này, bạn cần tạo tên tệp nếu kết quả trống và bạn có thể quyết định xem mình có muốn mã hóa các ký tự UTF-8 hay không. Nhưng bạn không cần điều đó vì UTF-8 được phép trong tất cả các hệ thống tệp được sử dụng trong bối cảnh lưu trữ web.

Điều duy nhất bạn phải làm là sử dụng urlencode()(như bạn hy vọng sẽ làm điều đó với tất cả các URL của mình) để tên tệp საბეჭდი_მანქანა.jpgtrở thành URL này là của bạn <img src>hoặc <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 thực hiện điều đó, vì vậy tôi có thể đăng liên kết này như một người dùng sẽ làm điều đó:
http://www.maxrev.de/html/img/ საბეჭდი_მანქანა. Jpg

Vì vậy, đây là một tên tệp hợp pháp hoàn chỉnh và không phải là một vấn đề như @ SequenceDigitale.com đã đề cập trong câu trả lời của anh ấy .


3
Làm tốt lắm. Câu trả lời hữu ích nhất cho tôi. +1

Ồ ... Chức năng hoạt động tốt, nhưng vì một thời gian nó bắt đầu đặt - giữa mọi ký tự, giống như r-u-l-e-svà tôi không biết tại sao điều này lại xảy ra. Chắc chắn rằng đó không phải là lỗi của chức năng, nhưng chỉ cần hỏi - lý do của hành vi đó có thể là gì? Mã hóa sai?

1
Ồ tốt ... Chỉ cần gỡ lỗi và nó xảy ra ngay sau khi preg_replacevào filter_filename().

Sau khi xóa những bình luận này, nó bắt đầu hoạt động trở lại.

Bạn đã loại bỏ nhận xét nào? Gửi email cho tôi nếu việc này dễ dàng hơn: gutt.it/contact.htm
mgutt

43

Điều gì về việc sử dụng rawurlencode ()? http://www.php.net/manual/en/ Chức năng.rawurlencode.php

Đây là một chức năng khử trùng ngay cả các ký tự tiếng Trung:

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

Đây là lời giải thích

  1. Tách thẻ HTML
  2. Xóa Break / Tabs / Return Carriage
  3. Xóa các ký tự bất hợp pháp cho thư mục và tên tệp
  4. Đặt chuỗi bằng chữ thường
  5. Loại bỏ các dấu nước ngoài như Éàû bằng cách chuyển đổi nó thành các thực thể html và sau đó loại bỏ mã và giữ lại chữ cái.
  6. Thay thế Dấu cách bằng dấu gạch ngang
  7. Mã hóa các ký tự đặc biệt có thể vượt qua các bước trước đó và nhập vào tên tệp xung đột trên máy chủ. Ví dụ. "中文 百强 网"
  8. Thay thế "%" bằng dấu gạch ngang để đảm bảo liên kết của tệp sẽ không bị trình duyệt viết lại khi truy vấn tệp thứ.

OK, một số tên tệp sẽ không liên quan nhưng trong hầu hết các trường hợp, nó sẽ hoạt động.

Ví dụ. Tên gốc: "საბეჭდი-და-ტიპოგრაფიული. Jpg"

Tên đầu ra: "-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 "

Nó tốt hơn như vậy hơn là lỗi 404.

Hy vọng điều đó hữu ích.

Carl.


1
Bạn không xóa các ký tự NULL và Control. Tất cả ASCII từ 0 đến 32 phải được xóa khỏi chuỗi.
Basil Musa

UTF-8 được phép trong hệ thống tệp và nó được phép trong URL, vậy tại sao nó lại tạo ra lỗi 404? Điều duy nhất bạn cần làm là mã hóa URL http://www.maxrev.de/html/img/საბეჭდი_მანქანა.jpgthành 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.jpgmã nguồn HTML như bạn hy vọng sẽ làm với tất cả các URL của mình.
mgutt

1
Một số điểm khác: Bạn xóa thẻ HTML thông qua strip_tags()và sau đó bạn xóa [<>]. Bởi điều đó strip_tags()không thực sự cần thiết chút nào. Điểm giống nhau là những câu trích dẫn. Không có dấu ngoặc kép nào còn lại khi bạn giải mã với ENT_QUOTES. Và str_replace()không loại bỏ các khoảng trắng liên tiếp và sau đó bạn sử dụng strtolower()cho chuỗi mult-byte. Và tại sao bạn chuyển đổi thành chữ thường? Và cuối cùng bạn không bắt gặp bất kỳ ký tự dành riêng nào như @BasilMusa đã đề cập. Thêm chi tiết trong câu trả lời của tôi: stackoverflow.com/a/42058764/318765
mgutt

đã yêu nó!
Yash Kumar Verma

39

GIẢI PHÁP 1 - đơn giản và hiệu quả

$file_name = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $url ) );

  • strtolower () đảm bảo tên tệp là chữ thường (vì chữ hoa không quan trọng bên trong URL, nhưng trong tên tệp NTFS)
  • [^a-z0-9]+ sẽ đảm bảo, tên tệp chỉ giữ các chữ cái và số
  • Thay thế các ký tự không hợp lệ bằng '-'giữ cho tên tệp có thể đọc được

Thí dụ:

URL:  http://stackoverflow.com/questions/2021624/string-sanitizer-for-filename
File: http-stackoverflow-com-questions-2021624-string-sanitizer-for-filename

GIẢI PHÁP 2 - cho các URL rất dài

Bạn muốn lưu nội dung URL vào bộ đệm và chỉ cần có tên tệp duy nhất. Tôi sẽ sử dụng chức năng này:

$file_name = md5( strtolower( $url ) )

điều này sẽ tạo một tên tệp có độ dài cố định. Trong hầu hết các trường hợp, băm MD5 là đủ duy nhất cho kiểu sử dụng này.

Thí dụ:

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
Có thể MD5 có thể xảy ra sự cố: Hãy cẩn thận khi sử dụng hàm băm với URL. Trong khi căn bậc hai của số skrenta.com/2007/08/md5_tutorial.html của URL vẫn lớn hơn rất nhiều thì kích thước web hiện tại nếu bạn gặp sự cố, bạn sẽ nhận được các trang về Britney Spears khi bạn đang mong đợi các trang về Bugzilla. Nó có lẽ không phải là vấn đề trong trường hợp của chúng tôi, nhưng đối với hàng tỷ trang, tôi sẽ chọn một thuật toán băm lớn hơn nhiều như SHA 256 hoặc tránh nó hoàn toàn. Nguồn: boyter.org/2013/01/code-for-a-search-engine-in-php-part-1
adilbo

15

Tốt, tempnam () sẽ làm điều đó cho bạn.

http://us2.php.net/manual/en/ Chức năng.tempnam.php

nhưng điều đó tạo ra một cái tên hoàn toàn mới.

Để khử trùng một chuỗi hiện có, chỉ cần hạn chế những gì người dùng của bạn có thể nhập và đặt nó thành các chữ cái, số, dấu chấm, dấu gạch ngang và dấu gạch dưới sau đó khử trùng bằng dấu regex đơn giản. Kiểm tra những ký tự nào cần được thoát nếu không bạn có thể nhận được kết quả dương tính giả.

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

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

Thêm / bớt các ký tự hợp lệ hơn tùy thuộc vào những gì được phép cho hệ thống của bạn.

Ngoài ra, bạn có thể thử tạo tệp và sau đó trả lại lỗi nếu nó bị lỗi.


5
Điều đó sẽ cho phép thông qua các tên tệp như .., có thể là một vấn đề.
Dominic Rodger

@Dom - chỉ cần kiểm tra điều đó một cách riêng biệt, vì nó là một giá trị cố định.
Tor Valamo

10

PHP cung cấp một chức năng để làm sạch văn bản sang định dạng khác

filter.filters.sanifying

Làm thế nào để :

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

Blockquote LoremIpsumhasbeentheindustry's


1
Tốt, nhưng nó sẽ không loại bỏ dấu gạch chéo, đó có thể là một vấn đề: Duyệt qua thư mục.
func0der

7

safe: thay thế mọi chuỗi NOT "a-zA-Z0-9_-" thành dấu gạch ngang; tự thêm tiện ích mở rộng.

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

1
Bạn cần thêm phần mở rộng tệp được phân tách bằng dấu ".": $ Name = preg_replace ('/ [^ a-zA-Z0-9 _-] + /', '-', strtolower ($ name)). '.' . $ phần mở rộng;
Smith

6

Biểu thức sau tạo một chuỗi đẹp, sạch sẽ và có thể sử dụng được:

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

Chuyển tài chính ngày nay: thanh toán thành thanh toán tài chính hôm nay


vì vậy tên tệp không được có dấu chấm hoặc dấu gạch dưới, hoặc bất cứ điều gì tương tự?
Tor Valamo

2
@Jonathan - chữ in nghiêng là gì?
Dominic Rodger

@Tor, vâng, xin lỗi. Đã cập nhật. @Dominic, chỉ vẽ điểm nhấn vào văn bản.
Sampson

Gism là gì? Tôi nhận được "Cảnh báo: preg_replace () [function.preg-thay thế]: modifier Unknown 'g'"
user151841

1
@ user151841 Đối với preg_replacecờ toàn cầu là ẩn. Vì vậy, không cần g nếu preg_replace đang được sử dụng. Khi chúng ta muốn kiểm soát số lượng thay thế thì preg_replace có một limittham số cho điều đó. Đọc tài liệu về preg_replace để biết thêm.
rineez

6

Thực hiện một điều chỉnh nhỏ đối với giải pháp của Sean Vieira để cho phép các chấm đơn, bạn có thể sử dụng:

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

2

Những thứ này có thể hơi nặng, nhưng chúng đủ linh hoạt để làm sạch bất kỳ chuỗi nào thành "két" en tên tệp hoặc tên thư mục theo kiểu (hoặc thật tệ, thậm chí là những con sên được làm sạch và những thứ nếu bạn bẻ cong nó).

1) Xây dựng một tên tệp đầy đủ (với tên dự phòng trong trường hợp đầu vào hoàn toàn bị cắt ngắn):

str_file($raw_string, $word_separator, $file_extension, $fallback_name, $length);

2) Hoặc chỉ sử dụng bộ lọc mà không tạo tên tệp đầy đủ (chế độ nghiêm ngặt truesẽ không cho phép [] hoặc () trong tên tệp):

str_file_filter($string, $separator, $strict, $length);

3) Và đây là những chức năng:

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

Vì vậy, giả sử một số đầu vào của người dùng là: .....&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) საბეჭდი-და-ტიპოგრაფიული

Và chúng tôi muốn chuyển đổi nó thành thứ gì đó thân thiện hơn để tạo tar.gz với độ dài tên tệp là 255 ký tự. Đây là một ví dụ sử dụng. Lưu ý: ví dụ này bao gồm phần mở rộng tar.gz không đúng định dạng như một bằng chứng về khái niệm, bạn vẫn nên lọc phần mở rộng sau khi chuỗi được tạo dựa trên (các) danh sách trắng của bạn.

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

Đầu ra sẽ là: _wei_gbel_file_name_dcor_._._._z_._y_._x_._this_name_is_462_not_that_grrrreat_][09]()1234747)_.tar.gz

Bạn có thể chơi với nó ở đây: https://3v4l.org/iSgi8

Hoặc Gist: https://gist.github.com/dhaupin/b109d3a8464239b7754a

CHỈNH SỬA: cập nhật bộ lọc tập lệnh &nbsp;thay vì không gian, liên kết 3v4l được cập nhật


1

Phương thức tốt nhất mà tôi biết hiện nay là phương thức tĩnh Strings :: webalize từ Nette framework.

BTW, điều này chuyển tất cả các dấu phụ thành cơ bản .. š => s ü => u ß => ss, v.v.

Đối với tên tệp, bạn phải thêm dấu chấm "." thành tham số ký tự được phép.

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

Tại sao bạn muốn thay dấu phụ? Chỉ cần sử dụng urlencode()trước khi bạn sử dụng tên tệp là srchoặc href. Hệ thống tệp được sử dụng duy nhất hiện có vấn đề với UTF-8 là FATx (được sử dụng bởi XBOX): en.wikipedia.org/wiki/Comparison_of_file_systems#Limits Và tôi không nghĩ điều này được sử dụng bởi máy chủ web
mgutt

1

Có vẻ như tất cả điều này phụ thuộc vào câu hỏi, liệu có thể tạo một tên tệp có thể được sử dụng để xâm nhập vào máy chủ (hoặc gây ra một số thiệt hại khác). Nếu không, thì có vẻ như câu trả lời đơn giản là thử tạo tệp ở bất cứ đâu, cuối cùng, tệp sẽ được sử dụng (vì đó sẽ là hệ điều hành được lựa chọn, không nghi ngờ gì nữa). Hãy để hệ điều hành sắp xếp nó. Nếu khiếu nại, hãy chuyển khiếu nại đó trở lại Người dùng dưới dạng Lỗi xác thực.

Điều này có thêm lợi ích là khả năng di động đáng tin cậy, vì tất cả (tôi khá chắc chắn) hệ điều hành sẽ phàn nàn nếu tên tệp không được định dạng đúng cho hệ điều hành đó.

Nếu nó có thể làm những việc bất chính với một tên tập tin, có lẽ có biện pháp có thể được áp dụng trước khi thử nghiệm các tên tập tin trên hệ điều hành thường trú - biện pháp ít phức tạp hơn so với một "vệ sinh" đầy đủ của tên tập tin.


0

một chiều

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

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

}
echo sanitize($string,$bad);

Còn những ký tự không in được thì sao? Tốt hơn là sử dụng cách tiếp cận danh sách trắng hơn là cách tiếp cận danh sách đen trong trường hợp này. Về cơ bản, chỉ cho phép các tên tệp ASCII có thể in được, ngoại trừ các chữ cái đặc biệt. Nhưng đối với các ngôn ngữ không phải tiếng Anh, đó là một vấn đề khác.
TheRealChx101

0

/..trong tên tệp do người dùng cung cấp có thể có hại. Vì vậy, bạn nên loại bỏ những điều này bằng cách như:

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

Điều này là không đủ! Ví dụ: tên tệp "./.name" sẽ vẫn thoát ra khỏi thư mục hiện tại. (Loại bỏ .. không có gì ở đây, nhưng loại bỏ / sẽ biến ./ vào .. và do đó thoát ra khỏi thư mục đích..)
cemper93

3
@ cemper93 Không, câu trả lời này sẽ chỉ biến chuỗi thành ..namemà sẽ không thoát ra khỏi bất kỳ điều gì. Việc loại bỏ tất cả các ký tự phân cách đường dẫn là đủ để ngăn chặn bất kỳ sự chuyển tải thư mục nào. (Việc loại bỏ ..là không cần thiết về mặt kỹ thuật.)
cdhowie

@cdhowie Có, nhưng tên tệp ./.trở thành ... Và cuối cùng câu trả lời này bỏ lỡ tất cả các ký tự dành riêng cho hệ thống tệp khác như NULL. Thêm câu trả lời của tôi: stackoverflow.com/a/42058764/318765
mgutt

-4

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

Vì người dùng có thể sử dụng dấu gạch chéo để phân tách hai từ, tốt hơn nên thay thế bằng dấu gạch ngang thay vì NULL


Nơi nào nói rằng anh ấy sẽ thay thế bằng NULL? Ngoài ra, điều này không xử lý tất cả các ký tự đặc biệt.
Travis Pessetto

Đúng - có những ký tự đặc biệt khác cũng cần xử lý. str_replace dù sao cũng không phải là giá thầu tốt nhất ở đây.
Martin Kovachev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.