дезинфицирующее средство для строк - PullRequest
85 голосов
/ 07 января 2010

Я ищу функцию php, которая очистит строку и подготовит ее к использованию для имени файла. Кто-нибудь знает удобный?

(я мог бы написать один, но я боюсь, что пропущу персонажа!)

Редактировать: для сохранения файлов в файловой системе Windows NTFS.

Ответы [ 17 ]

136 голосов
/ 07 января 2010

Небольшая корректировка решения 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);
36 голосов
/ 26 сентября 2013

Как насчет использования 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.

Надеюсь, это было полезно.

Карл.

32 голосов
/ 07 января 2010

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

28 голосов
/ 20 марта 2017

РЕШЕНИЕ 1 - просто и эффективно

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

  • strtolower () гарантирует, что имя файла в нижнем регистре (поскольку регистр не имеет значения внутри URL, но в имени файла NTFS)
  • [^a-z0-9]+ обеспечит, имя файла содержит только буквы и цифры
  • Замена недопустимых символов на '-' делает имя файла читаемым

Пример:

URL:  /1602744/dezinfitsiruyschee-sredstvo-dlya-strok
File: http-stackoverflow-com-questions-2021624-string-sanitizer-for-filename

РЕШЕНИЕ 2 - для очень длинных URL

Вы хотите кешировать содержимое URL-адреса и просто должны иметь уникальные имена файлов. Я бы использовал эту функцию:

$file_name = md5( strtolower( $url ) )

это создаст имя файла с фиксированной длиной. Хеш MD5 в большинстве случаев достаточно уникален для такого использования.

* +1032 * Пример: * 1 033 *
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
22 голосов
/ 06 февраля 2017

Вот как вы можете выполнить санитарную обработку файловой системы в соответствии с запросом

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 упоминается в его ответе .

13 голосов
/ 07 января 2010
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)

Добавить / удалить больше допустимых символов в зависимости от того, что разрешено для вашей системы.

В качестве альтернативы вы можете попытаться создать файл и вернуть ошибку, если она плохая.

13 голосов
/ 07 января 2010

Хорошо, tempnam () сделает это за вас.

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

но это создает совершенно новое имя.

Чтобы очистить существующую строку, просто ограничьте то, что ваши пользователи могут вводить, и введите буквы, цифры, точку, дефис и подчеркивание, а затем очистите с помощью простого регулярного выражения. Проверьте, какие символы нужно экранировать, иначе вы можете получить ложные срабатывания.

$sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename);
8 голосов
/ 16 марта 2017

PHP предоставляет функцию для очистки текста в другой формат

filter.filters.sanitize

Как:

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

Цитата LoremIpsumhasbeentheindustry's

6 голосов
/ 13 июля 2013

Сделав небольшую корректировку решения Шона Виейры, чтобы учесть одиночные точки, вы можете использовать:

preg_replace("([^\w\s\d\.\-_~,;:\[\]\(\)]|[\.]{2,})", '', $file)
6 голосов
/ 07 января 2010

Следующее выражение создает красивую, чистую и пригодную для использования строку:

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

Превращение сегодняшнего финансового: выставление счетов в сегодня-финансовый-выставление счетов

...