рядок дезінфікуючого засобу для імені файлу


113

Я шукаю функцію php, яка буде санітувати рядок і зробить його готовим до використання для імені файлу. Хтось знає про зручну?

(Я міг би написати один, але я переживаю, що я не помічу персонажа!)

Редагувати: для збереження файлів у файловій системі Windows NTFS.


1
Чи можете ви бути більш конкретними: що трапиться з Umlauts (видалити або перетворити на базовий символ?) Що має відбуватися зі спеціальними символами?
Пекка

Для якої файлової системи? Вони відрізняються. Дивіться en.wikipedia.org/wiki/…
Гордон

Windows :) Потрібно 15 символів.
користувач151841

1
Я хотів би зазначити, що рішення "чорного списку", запропоновані в деяких відповідях, є недостатніми, оскільки неможливо перевірити наявність усіх можливих небажаних символів (крім спеціальних символів, є символи з наголосами та умлаутами, цілими неанглійські / латинські алфавіти, контрольні символи тощо, з якими потрібно мати справу). Тому я б заперечував, що "білий" підхід завжди кращий, а нормалізація рядка (як це запропонував коментар Блера Макміллана на відповідь Домініка Роджера) дозволить природним чином обробляти будь-які листи з наголосами, умлаутами тощо.
Шон Бін

Хороший спосіб, можливо, використовуючи регулярні вирази, дивіться цей сценарій python, який я створив: github.com/gsscoder/normalize-fn
gsscoder

Відповіді:


42

Замість того, щоб турбуватися про вигляд символів - як щодо використання білого списку символів, яким ви раді використовувати? Наприклад, ви могли б дозволити тільки старий добрий a-z, 0-9, _і єдиний екземпляр періоду ( .). Це, очевидно, є більш обмежуючим, ніж більшість файлових систем, але має захищати вас.


40
Немає користі для мов з Umlauts. Це призвело б до Квебеку для Квебека, Дюссельдорфа для Дюссельдорфа тощо.
Pekka

15
Щоправда - але так, як я сказав: "Наприклад".
Домінік Роджер

5
Що може бути цілком прийнятним для ОП. В іншому випадку використовуйте щось на зразок php.net/manual/en/class.normalizer.php
Блер Макміллан

3
Це насправді не те, що просили. Оп просить функцію санітизувати рядок, а не альтернативу.
i.am.michiel

3
@ i.am.michiel, можливо, але, враховуючи, що ОП прийняла це, я вважаю, що вони вважають це корисним.
Домінік Роджер

157

Зробивши невелике коригування рішення 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

2
@ iim.hlk - так, не було пропущено круглих дужок. Я додав їх зараз. Дякую!
Шон Віейра

2
там є недолік, вам слід розділити його на два і запустити чек на ..потім. Наприклад .?., в кінцевому підсумку ... Хоча, оскільки ви фільтруєте, /я не бачу, як би ви скористалися цим шляхом прямо зараз, але це показує, чому перевірка на ..це неефективна. Ще краще, мабуть, не замінюйте, а просто відхиляйте, якщо це не відповідає вимогам.
falstro

2
Тому що жодне з цих значень не є незаконним у файловій системі Windows і чому втрачаєш більше інформації, ніж потрібно? Ви можете змінити регулярний вираз на просто, [^a-z0-9_-]якщо хочете бути дійсно обмежуючим, - або просто скористайтеся створеним ім'ям та викиньте вказане ім’я та уникайте всіх цих проблем. :-)
Шон Віейра

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_replaceвходу 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 та Control. ASCII від 0 до 32 слід видалити з рядка.
Василь Муса

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.jpgу вихідному HTML коду , як ви , сподіваюся , робити з усією своєю URL.
mgutt

1
Деякі інші моменти: Ви видаляєте теги HTML через strip_tags()та після цього [<>]. Для цього strip_tags()зовсім не потрібно. Цей же пункт є цитатами. При декодуванні не залишається жодних лапок ENT_QUOTES. І str_replace()не видаляє послідовні пробіли, а потім ви використовуєте strtolower()для багатобайтового рядка. І чому ви взагалі перетворюєтесь на малі регістри? І нарешті ви не зловили жодного зарезервованого персонажа, як згадував @BasilMusa. Детальніше в моїй обороні: stackoverflow.com/a/42058764/318765
mgutt

закохався в нього!
Яш Кумар Верма

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-адресами. Хоча квадратний корінь числа skrenta.com/2007/08/md5_tutorial.html URL-адрес все ще набагато більший, ніж поточний розмір веб-сторінки, якщо ви зіткнетесь, ви збираєтеся отримати сторінки про Брітні Спірс, коли ви очікували сторінки про 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
Це дозволить отримати такі назви файлів, як ..це може бути, а може і не бути проблемою.
Домінік Роджер

@Dom - просто перевірте це окремо, оскільки це фіксоване значення.
Tor Valamo

10

PHP забезпечує функцію очищення тексту в інший формат

filter.filters.sanitize

Як :

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

Блок-котирування LoremIpsumhasbeentheindustry's


1
Добре, але це не прибирає косої риси, що може бути проблемою: проходження каталогів.
func0der

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)). '.' . $ розширення;
Сміт

6

Наступний вираз створює хороший, чистий та корисний рядок:

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

Перетворення сьогоднішнього фінансового: виставлення рахунків на сьогоднішнє фінансово-рахункове


значить, у імені файлу не може бути періоду чи підкреслення, або щось подібне?
Tor Valamo

2
@Jonathan - що з курсивом?
Домінік Роджер

@Tor, так, вибачте. Оновлено. @Dominic, просто малюючи наголос на тексті.
Сампсон

Що таке гізм? Я отримую "Попередження: preg_replace () [function.preg-
zame

1
@ user151841 preg_replaceГлобальний прапор неявний. Тому немає потреби в g, якщо використовується preg_replace. Коли ми хочемо контролювати кількість замін, preg_replace має limitдля цього параметр. Докладніше прочитайте документацію preg_replace.
rineez

6

Зробивши невелике коригування рішення Шона Вієйри, щоб дозволити поодинокі точки, ви можете використовувати:

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) საბეჭდი-და-ტიპოგრაფიული

І ми хочемо перетворити його на щось дружніше, щоб зробити tar.gz з назвою файлу довжиною 255 символів. Ось приклад використання. Примітка. Цей приклад включає неправильне розширення 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

EDIT: оновлений фільтр сценаріїв &nbsp;замість місця, оновлене посилання 3v4l


1

Найкраще, що я знаю сьогодні, - це статичний метод Strings :: webalize з Nette Framework.

До речі, це переводить всі діакритичні знаки на їх основні .. š => 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/Comppare_of_file_systems#Limits І я не думаю, що це використовується веб-серверами
mgutt

1

Здається, це все залежить від питання, чи можна створити ім’я файлу, яке можна використовувати для взлому на сервер (або зробити якийсь такий подібний збиток). Якщо ні, то, здається, простою відповіддю є спробувати створити файл там, де він, в кінцевому рахунку, буде використовуватися (оскільки це буде операційна система вибору, без сумніву). Нехай операційна система розбереться. Якщо він скаржиться, відправте цю скаргу Користувачеві як помилку перевірки.

Це має додаткову перевагу надійності переносу, оскільки всі (я впевнений) операційні системи будуть скаржитися, якщо ім'я файлу неправильно сформовано для цієї ОС.

Якщо це можливо зробити мерзенні речі з ім'ям файлу, можливо , існують заходи , які можуть бути застосовані перед тестуванням файлу на скільки-небудь операційної системи - заходи , менш складні , ніж повний «санітарія» в імені файлу.


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" все одно не буде вибиватися з поточного каталогу. (Видалення .. тут нічого не робить, але видалення / перетворить ./ на .. і, отже, вирветься з цільового каталогу.)
cemper93

3
@ cemper93 Ні, ця відповідь просто перетворить рядок, у ..nameякий би нічого не вирвалося . Видалення всіх символів роздільника шляхів повинно бути достатнім для запобігання будь-якому проходженню каталогу. (Видалення ..технічно непотрібне.)
cdhowie

@cdhowie Так, але ім'я файлу ./.стає ... І, нарешті, ця відповідь не вистачає всіх інших зарезервованих символів файлової системи, таких як NULL. Більше в моєму відповідь: stackoverflow.com/a/42058764/318765
mgutt

-4

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

Оскільки користувачі можуть використовувати косу рису для розділення двох слів, краще замінити тире замість NULL


Де сказано, що він замінить NULL? Також це стосується не всіх спеціальних символів.
Травіс Пессетто

Так - є й інші спеціальні символи, які теж потребують обробки. str_replace не буде найкращою ставкою тут все одно.
Мартін Ковачев
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.