строка дезинфицирующее средство для имени файла


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

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

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

16 70

16 ответов:

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

делая небольшую поправку к решению 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);

Как насчет использования 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", '', $str);
    $str = str_replace(' ', '-', $str);
    $str = rawurlencode($str);
    $str = str_replace('%', '-', $str);
    return $str;
}

вот объяснений

  1. Strip HTML Tags
  2. Удалить Разрыв / Вкладки / Возврат Каретки
  3. удалить незаконные символы для папки и имени файла
  4. поставить строку в нижний регистр
  5. удалить иностранные акценты, такие как Éàû by преобразуйте его в объекты html, а затем удалите код и сохраните письмо.
  6. заменить пробелы на дефисы
  7. кодировать специальные символы, которые могут пройти предыдущие шаги и ввести имя файла конфликта на сервере. бывший. "中文百强网"
  8. замените " % " на тире, чтобы убедиться, что ссылка на файл не будет переписана браузером при запросе th файла.

ОК, некоторые файлы не будут releavant, но в большинстве случаев это будет работа.

ex. Оригинальное название: "საბეჭდი-და-ტიპოგრაფიული.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 и

$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
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)

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

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

Ну, tempnam() сделает это за вас.

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

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

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

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

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

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, потому что:

NotExist' onerror='alert(1).jpg

становится XSS отверстие:

<img src='<? echo $image ?>' />
// output:
<img src='NotExist' onerror='alert(1)' />

из-за этого, популярная CMS программное обеспечение Wordpress удаляет его, и они узнали год by год через трудный путь (много сообщений об ошибках), что полезно добавлять все больше и больше символов:

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

наконец-то их список включает в себя большинство символов, которые являются частью URI rerserved-символы и 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);
    // maximise 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

так что это полное юридическое имя файла и не проблема as @SequenceDigitale.com упоминается в его ответе.

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

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

превращение сегодняшние финансовые: биллинг на сегодня-s-financial-billing

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

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

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

фильтр.фильтры.санировать

Как :

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

Blockquote LoremIpsumhasbeentheindustry's

они могут быть немного тяжелыми, но они достаточно гибкие, чтобы санировать любую строку в "сейф" en имя файла стиля или имя папки (или черт возьми, даже очищенные слизняки и вещи, если вы согнете его).

1) создание полного имени файла (с резервным именем в случае, если вход полностью усечен):

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

2) или используя только фильтр util без создания полного имени файла (строгий режим 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) საბეჭდი-და-ტიპოგრაფიული

и мы хотим преобразовать его в нечто более дружелюбное, чтобы сделать смолу.gz с длиной имени файла 255 символов. Вот пример использования. Примечание: этот пример включает в себя деформированную смолу.расширение 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

лучшее, что я знаю сегодня-это статический метод строки::webalize из Nette framework.

кстати, это переводит все диакритические знаки на их основные.. š=>с у ß=>СС и т. д.

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

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

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

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

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

один из способов

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

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

}
echo sanitize($string,$bad);

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

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

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

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