pembersih string untuk nama file

113

Saya mencari fungsi php yang akan membersihkan string dan membuatnya siap digunakan untuk nama file. Ada yang tahu yang berguna?

(Saya bisa menulis satu, tapi saya khawatir saya akan mengabaikan karakter!)

Edit: untuk menyimpan file pada sistem file Windows NTFS.

pengguna151841
sumber
1
Bisakah Anda lebih spesifik: Apa yang akan terjadi dengan Umlauts (hapus atau ubah ke karakter dasar?) Apa yang akan terjadi dengan karakter khusus?
Pekka
Untuk Sistem File yang mana? Mereka berbeda. Lihat en.wikipedia.org/wiki/…
Gordon
Windows :) Butuh 15 karakter.
pengguna151841
1
Saya ingin menunjukkan bahwa solusi "daftar hitam" yang disarankan di beberapa jawaban tidak cukup, karena tidak mungkin untuk memeriksa setiap kemungkinan karakter yang tidak diinginkan (selain karakter khusus, ada karakter dengan aksen dan umlaut, keseluruhan alfabet non-Inggris / latin, karakter kontrol, dll. untuk ditangani). Jadi saya berpendapat bahwa pendekatan "daftar putih" selalu lebih baik, dan menormalkan string (seperti yang disarankan oleh komentar Blair McMillan tentang jawaban Dominic Rodger) akan memungkinkan penanganan alami untuk setiap huruf dengan aksen, umlaut, dll.
Sean the Bean
Cara yang baik mungkin menggunakan ekspresi reguler, lihat skrip python yang saya buat: github.com/gsscoder/normalize-fn
gsscoder

Jawaban:

42

Alih-alih mengkhawatirkan karakter yang terlewatkan - bagaimana dengan menggunakan daftar putih karakter yang ingin Anda gunakan? Misalnya, Anda dapat memungkinkan ol hanya baik' a-z, 0-9, _, dan satu contoh dari periode ( .). Itu jelas lebih membatasi daripada kebanyakan sistem file, tetapi akan membuat Anda tetap aman.

Dominic Rodger
sumber
40
Tidak bagus untuk bahasa dengan Umlauts. Ini akan menghasilkan Qubec untuk Québec, Dsseldorf untuk Düsseldorf, dan seterusnya.
Pekka
15
Benar - tapi seperti yang saya katakan: "Misalnya".
Dominic Rodger
5
Yang mungkin bisa diterima oleh OP. Jika tidak, gunakan sesuatu seperti php.net/manual/en/class.normalizer.php
Blair McMillan
3
Sebenarnya bukan itu yang diminta. Operasi meminta fungsi untuk membersihkan string, bukan alternatif.
i.am.michiel
3
@ i.am.michiel, mungkin, tetapi mengingat OP menerimanya, saya akan menganggap mereka merasa terbantu.
Dominic Rodger
157

Membuat sedikit penyesuaian pada solusi Tor Valamo untuk memperbaiki masalah yang diketahui oleh Dominic Rodger, Anda dapat menggunakan:

// 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);
Sean Vieira
sumber
43
Saya suka pecandu regex! -_ ~
AVProgrammer
2
@ iim.hlk - ya, kurung pembungkusnya tidak ada. Saya telah menambahkannya sekarang. Terima kasih!
Sean Vieira
2
ada cacat di sana, Anda harus membaginya menjadi dua dan menjalankan pemeriksaan ..setelahnya. Misalnya .?.akan berakhir menjadi ... Meskipun karena Anda memfilter, /saya tidak dapat melihat bagaimana Anda akan mengeksploitasinya lebih jauh sekarang, tetapi ini menunjukkan mengapa pemeriksaan ..tidak efektif di sini. Lebih baik lagi mungkin, jangan diganti, tolak saja jika tidak memenuhi syarat.
falstro
2
Karena tidak ada nilai tersebut yang ilegal pada sistem file Windows dan mengapa kehilangan lebih banyak informasi daripada yang Anda perlukan? Anda dapat mengubah ekspresi reguler menjadi hanya [^a-z0-9_-]jika Anda ingin benar-benar membatasi - atau cukup gunakan nama yang dihasilkan dan buang nama yang diberikan dan hindari semua masalah ini. :-)
Sean Vieira
3
Perhatikan bahwa: ilegal.
JasonXA
49

Ini adalah bagaimana Anda dapat membersihkan sistem file seperti yang diminta

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

Segala sesuatu yang lain diperbolehkan dalam filesystem, jadi pertanyaannya terjawab dengan sempurna ...

... tetapi bisa berbahaya untuk mengizinkan, misalnya tanda kutip tunggal 'dalam nama file jika Anda menggunakannya nanti dalam konteks HTML yang tidak aman karena nama file ini benar-benar legal:

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

menjadi lubang XSS :

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

Karena itu, perangkat lunak CMS Wordpress yang populer menghapusnya, tetapi mereka menutupi semua karakter yang relevan hanya setelah beberapa pembaruan :

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

Terakhir, daftar mereka sekarang menyertakan sebagian besar karakter yang merupakan bagian dari karakter yang dilindungi URI dan daftar karakter URL yang tidak aman .

Tentu saja Anda dapat dengan mudah menyandikan semua karakter ini pada keluaran HTML, tetapi sebagian besar pengembang dan saya juga, mengikuti ungkapan "Lebih baik aman daripada menyesal" dan menghapusnya terlebih dahulu.

Jadi akhirnya saya menyarankan untuk menggunakan ini:

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

Segala sesuatu yang lain yang tidak menyebabkan masalah dengan sistem file harus menjadi bagian dari fungsi tambahan:

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

Dan pada titik ini Anda perlu membuat nama file jika hasilnya kosong dan Anda dapat memutuskan apakah Anda ingin menyandikan karakter UTF-8. Tetapi Anda tidak membutuhkannya karena UTF-8 diizinkan di semua sistem file yang digunakan dalam konteks hosting web.

Satu-satunya hal yang harus Anda lakukan adalah menggunakan urlencode()(seperti yang Anda harapkan dengan semua URL Anda) sehingga nama file საბეჭდი_მანქანა.jpgmenjadi URL ini sebagai Anda <img src>atau <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 melakukan itu, jadi saya dapat memposting tautan ini seperti yang dilakukan pengguna:
http://www.maxrev.de/html/img/ საბეჭდი_მანქანა. Jpg

Jadi ini adalah nama file resmi yang lengkap dan bukan masalah seperti yang disebutkan @ SequenceDigitale.com dalam jawabannya .

mgutt
sumber
3
Kerja bagus. Jawaban yang paling membantu saya. +1
Oh ... Fungsinya bekerja dengan baik, tetapi sejak beberapa waktu mulai ditempatkan - di antara setiap karakter, seperti r-u-l-e-sdan saya tidak tahu mengapa ini terjadi. Tentu itu bukan kesalahan fungsi, tetapi hanya bertanya - apa yang mungkin menjadi alasan perilaku seperti itu? Pengodean salah?
1
Oh well ... Baru saja melakukan debug dan itu terjadi tepat setelah preg_replacemasuk filter_filename().
Setelah menghapus komentar ini, ini mulai berfungsi kembali.
Komentar mana yang Anda hapus? Kirimi saya email jika ini lebih mudah: gutt.it/contact.htm
mgutt
43

Bagaimana dengan menggunakan rawurlencode ()? http://www.php.net/manual/en/function.rawurlencode.php

Ini adalah fungsi yang membersihkan bahkan Karakter Cina:

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

Berikut penjelasannya

  1. Hapus Tag HTML
  2. Hapus Break / Tabs / Return Carriage
  3. Hapus Illegal Chars untuk folder dan nama file
  4. Masukkan string dalam huruf kecil
  5. Hapus aksen asing seperti Éàû dengan mengubahnya menjadi entitas html lalu hapus kode dan simpan hurufnya.
  6. Ganti Spasi dengan tanda hubung
  7. Enkode karakter khusus yang bisa melewati langkah sebelumnya dan masukkan nama file konflik di server. ex. "中文 百强 网"
  8. Ganti "%" dengan tanda hubung untuk memastikan link file tidak akan ditulis ulang oleh browser saat menanyakan file th.

Oke, beberapa nama file tidak akan relevan tetapi dalam banyak kasus itu akan berhasil.

ex. Nama Asli: "საბეჭდი-და-ტიპოგრაფიული. Jpg"

Nama Output: "-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 "

Lebih baik seperti itu daripada kesalahan 404.

Semoga bermanfaat.

Carl.

SequenceDigitale.com
sumber
1
Anda tidak menghapus karakter NULL dan Control. ASCII dari 0 hingga 32 semuanya harus dihapus dari string.
Basil Musa
UTF-8 diizinkan dalam sistem file dan diizinkan di URL, jadi mengapa harus menghasilkan kesalahan 404? Satu-satunya hal yang perlu Anda lakukan adalah menyandikan URL http://www.maxrev.de/html/img/საბეჭდი_მანქანა.jpgke 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.jpgdalam kode sumber HTML seperti yang diharapkan Anda lakukan dengan semua URL Anda.
mgutt
1
Beberapa poin lainnya: Anda menghapus tag HTML melalui strip_tags()dan setelah itu Anda menghapus [<>]. Oleh karena strip_tags()itu tidak terlalu dibutuhkan sama sekali. Poin yang sama adalah kutipannya. Tidak ada tanda kutip tersisa saat Anda mendekode dengan ENT_QUOTES. Dan str_replace()tidak menghapus spasi putih berturut-turut dan kemudian Anda gunakan strtolower()untuk string multi-byte. Dan mengapa Anda mengubahnya menjadi huruf kecil? Dan akhirnya Anda tidak menemukan karakter yang dilindungi undang-undang seperti yang disebutkan @BasilMusa. Detail lebih lanjut dalam jawaban saya: stackoverflow.com/a/42058764/318765
mgutt
jatuh cinta padanya!
Yash Kumar Verma
39

SOLUSI 1 - sederhana dan efektif

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

  • strtolower () menjamin nama file adalah huruf kecil (karena case tidak masalah di dalam URL, tetapi di nama file NTFS)
  • [^a-z0-9]+ akan memastikan, nama file hanya menyimpan huruf dan angka
  • Gantikan karakter yang tidak valid dengan '-'membuat nama file tetap terbaca

Contoh:

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

SOLUSI 2 - untuk URL yang sangat panjang

Anda ingin menyimpan konten URL dan hanya perlu memiliki nama file yang unik. Saya akan menggunakan fungsi ini:

$file_name = md5( strtolower( $url ) )

ini akan membuat nama file dengan panjang tetap. Hash MD5 dalam banyak kasus cukup unik untuk penggunaan semacam ini.

Contoh:

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
Philipp
sumber
4
Mungkin MD5 bisa dengan Masalah: Hati-hati saat menggunakan hash dengan URL. Sementara akar kuadrat dari nomor skrenta.com/2007/08/md5_tutorial.html URL masih jauh lebih besar daripada ukuran web saat ini jika Anda mengalami benturan, Anda akan mendapatkan halaman tentang Britney Spears ketika Anda mengharapkan halaman tentang Bugzilla. Ini mungkin bukan masalah dalam kasus kami, tetapi untuk miliaran halaman saya akan memilih algoritma hashing yang jauh lebih besar seperti SHA 256 atau menghindarinya sama sekali. Sumber: boyter.org/2013/01/code-for-a-search-engine-in-php-part-1
adilbo
15

Nah, tempnam () akan melakukannya untuk Anda.

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

tapi itu menciptakan nama yang sama sekali baru.

Untuk membersihkan string yang ada, cukup batasi apa yang dapat dimasukkan pengguna dan buat menjadi huruf, angka, titik, tanda hubung, dan garis bawah, lalu bersihkan dengan regex sederhana. Periksa karakter apa yang perlu dihilangkan atau Anda bisa mendapatkan positif palsu.

$sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename);
Mark Moline
sumber
13
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)

Tambahkan / hapus lebih banyak karakter yang valid tergantung pada apa yang diizinkan untuk sistem Anda.

Atau Anda dapat mencoba membuat file dan kemudian mengembalikan kesalahan jika buruk.

Tor Valamo
sumber
5
Itu akan memungkinkan melalui nama file seperti .., yang mungkin atau mungkin tidak menjadi masalah.
Dominic Rodger
@Dom - cukup periksa secara terpisah, karena ini adalah nilai tetap.
Tor Valamo
10

PHP menyediakan fungsi untuk membersihkan teks ke format yang berbeda

filter.filters.sanitize

Cara:

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

Blockquote LoremIpsumhasbeentheindustry's

120DEV
sumber
1
Bagus, tetapi tidak akan menghapus garis miring, yang bisa menjadi masalah: Direktori traverse.
func0der
7

aman: ganti setiap urutan NOT "a-zA-Z0-9_-" menjadi tanda hubung; tambahkan ekstensi sendiri.

$name = preg_replace('/[^a-zA-Z0-9_-]+/', '-', strtolower($name)).'.'.$extension;
commonpike
sumber
1
Anda perlu menambahkan ekstensi file yang dipisahkan oleh ".": $ Name = preg_replace ('/ [^ a-zA-Z0-9 _-] + /', '-', strtolower ($ name)). '.' . $ extension;
Smith
6

Ekspresi berikut membuat string yang bagus, bersih, dan dapat digunakan:

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

Mengubah keuangan hari ini: penagihan menjadi tagihan -keuangan-hari ini

Sampson
sumber
jadi nama file tidak boleh memiliki titik atau garis bawah, atau semacamnya?
Tor Valamo
2
@Jonathan - ada apa dengan huruf miring?
Dominic Rodger
@Tor, ya, maaf. Diperbarui. @Dominic, hanya menekankan pada teks.
Sampson
Apa itu gism? Saya mendapatkan "Peringatan: preg_replace () [function.preg-replace]: Pengubah tak dikenal 'g'"
user151841
1
@ user151841 Untuk preg_replacebendera global implisit. Jadi tidak perlu g jika preg_replace sedang digunakan. Saat kita ingin mengontrol jumlah penggantian, preg_replace memiliki limitparameter untuk itu. Baca dokumentasi preg_replace untuk lebih lanjut.
rineez
6

Membuat sedikit penyesuaian pada solusi Sean Vieira untuk memungkinkan adanya titik tunggal, Anda dapat menggunakan:

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

Ini mungkin agak berat, tetapi cukup fleksibel untuk membersihkan string apa pun menjadi ennama file atau nama folder bergaya "aman" (atau heck, bahkan siput dan benda-benda yang digosok jika Anda menekuknya).

1) Membangun nama file lengkap (dengan nama cadangan jika masukan benar-benar terpotong):

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

2) Atau hanya menggunakan util filter tanpa membuat nama file lengkap (mode ketat truetidak akan mengizinkan [] atau () dalam nama file):

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

3) Dan inilah fungsinya:

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

Jadi katakanlah beberapa masukan pengguna adalah: .....&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) საბეჭდი-და-ტიპოგრაფიული

Dan kami ingin mengubahnya menjadi sesuatu yang lebih ramah untuk membuat tar.gz dengan panjang nama file 255 karakter. Berikut adalah contoh penggunaan. Catatan: contoh ini menyertakan format ekstensi tar.gz yang salah sebagai bukti konsep, Anda masih harus memfilter ext setelah string dibuat sesuai dengan daftar putih Anda.

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

Outputnya adalah: _wei_gbel_file_name_dcor_._._._z_._y_._x_._this_name_is_462_not_that_grrrreat_][09]()1234747)_.tar.gz

Anda dapat bermain dengannya di sini: https://3v4l.org/iSgi8

Atau Intinya: https://gist.github.com/dhaupin/b109d3a8464239b7754a

EDIT: filter skrip yang diperbarui untuk &nbsp;menggantikan ruang, tautan 3v4l yang diperbarui

dhaupin
sumber
1

Yang terbaik yang saya tahu hari ini adalah metode statis Strings :: webalize dari kerangka Nette.

BTW, ini menerjemahkan semua tanda diakritik ke dasarnya .. š => s ü => u ß => ss dll.

Untuk nama file Anda harus menambahkan titik "." ke parameter karakter yang diizinkan.

/**
 * 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;
}
DnD
sumber
Mengapa Anda ingin mengganti diakritik? Cukup gunakan urlencode()sebelum Anda menggunakan nama file sebagai srcatau href. Satu-satunya sistem file yang saat ini digunakan yang bermasalah dengan UTF-8 adalah FATx (digunakan oleh XBOX): en.wikipedia.org/wiki/Comparison_of_file_systems#Limits Dan saya rasa ini tidak digunakan oleh server web
mgutt
1

Tampaknya ini semua bergantung pada pertanyaan, apakah mungkin untuk membuat nama file yang dapat digunakan untuk meretas ke server (atau melakukan beberapa kerusakan lainnya). Jika tidak, maka tampaknya jawaban sederhana untuk mencoba membuat file di mana pun itu akan, pada akhirnya, digunakan (karena itu akan menjadi sistem operasi pilihan, tidak diragukan lagi). Biarkan sistem operasi menyelesaikannya. Jika ada keluhan, kirim kembali keluhan itu ke Pengguna sebagai Kesalahan Validasi.

Ini memiliki keuntungan tambahan karena portabel yang andal, karena semua (saya cukup yakin) sistem operasi akan mengeluh jika nama file tidak dibentuk dengan benar untuk OS itu.

Jika adalah mungkin untuk melakukan hal-hal jahat dengan nama file, mungkin ada langkah-langkah yang dapat diterapkan sebelum menguji nama file pada sistem operasi penduduk - tindakan kurang rumit daripada penuh "sanitasi" dari nama file.

ReverseEMF
sumber
0

satu arah

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

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

}
echo sanitize($string,$bad);
anjing hantu74
sumber
Bagaimana dengan karakter yang tidak dapat dicetak? Dalam kasus ini, pendekatan daftar putih lebih baik digunakan daripada pendekatan daftar hitam. Pada dasarnya hanya mengizinkan nama file ASCII yang dapat dicetak tidak termasuk huruf khusus tentunya. Tetapi untuk lokal non-Inggris, itu masalah lain.
TheRealChx101
0

/dan ..nama file yang diberikan pengguna bisa berbahaya. Jadi Anda harus menyingkirkan ini dengan sesuatu seperti:

$fname = str_replace('..', '', $fname);
$fname = str_replace('/',  '', $fname);
tamat
sumber
Ini tidak cukup! Misalnya, nama file "./.name" akan tetap keluar dari direktori saat ini. (Menghapus .. tidak melakukan apa-apa di sini, tetapi menghapus / akan mengubah ./. Menjadi .. dan karenanya keluar dari direktori target.)
cemper93
3
@ cemper93 Tidak, jawaban ini hanya akan mengubah string ..nameyang tidak akan keluar dari apapun. Menghapus semua karakter pemisah jalur seharusnya cukup untuk mencegah traversal direktori. (Penghapusan ..secara teknis tidak perlu.)
cdhowie
@cdhowie Ya, tapi nama file ./.menjadi ... Dan akhirnya jawaban ini merindukan semua karakter khusus sistem file lainnya seperti NULL. Selengkapnya di jawaban saya: stackoverflow.com/a/42058764/318765
mgutt
-4

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

Karena pengguna mungkin menggunakan garis miring untuk memisahkan dua kata, akan lebih baik untuk mengganti dengan tanda hubung daripada NULL

pengguna2246924
sumber
Di mana dikatakan dia akan mengganti dengan NULL? Juga, ini tidak menangani semua karakter khusus.
Travis Pessetto
Ya - ada karakter khusus lain yang perlu ditangani juga. str_replace tidak akan menjadi tawaran terbaik di sini.
Martin Kovachev