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

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

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

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

Ответы [ 17 ]

1 голос
/ 27 октября 2017

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

Это дает дополнительное преимущество, заключающееся в надежности переносимости, поскольку все (я почти уверен) операционные системы будут жаловаться, если имя файла не сформировано должным образом для этой ОС.

Если - это , то возможно делать гнусные вещи с именем файла, возможно, есть меры, которые можно применить перед проверкой имени файла в резидентной операционной системе - меры менее сложные, чем полная «очистка» имя файла.

1 голос
/ 14 сентября 2016

Лучшее, что я знаю сегодня, это статический метод Strings :: webalize из фреймворка Nette.

Кстати, это переводит все диакритические знаки в их основные .. š => 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;
}
1 голос
/ 20 января 2016

Они могут быть немного тяжелыми, но они достаточно гибки, чтобы дезинфицировать любую строку в «безопасное» имя файла или папки в стиле 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

РЕДАКТИРОВАТЬ: обновлен фильтр сценариев для &nbsp; вместо пробела, обновлена ​​ссылка 3v4l

0 голосов
/ 12 мая 2019

безопасно: заменить каждую последовательность НЕ "a-zA-Z0-9_-" на тире; добавьте расширение самостоятельно.

$name = preg_replace('/[^a-zA-Z0-9_-]+/', '-', strtolower($name)).$extension;
0 голосов
/ 07 января 2010

/ и .. в предоставленном пользователем имени файла могут быть вредными. Таким образом, вы должны избавиться от них что-то вроде:

$fname = str_replace('..', '', $fname);
$fname = str_replace('/',  '', $fname);
0 голосов
/ 08 января 2010

в одну сторону

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

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

}
echo sanitize($string,$bad);
0 голосов
/ 05 апреля 2013

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

Поскольку пользователи могут использовать косую черту для разделения двух слов, лучше заменить тире вместо NULL

...