Я пытаюсь придумать функцию, которая делает хорошее задание очистки определенных строк так, чтобы их было безопасно использовать в URL (как человеко-понятный урл) и также безопасный использовать в качестве имен файлов. Например, когда кто-то загружает файл, я хочу удостовериться, что я удаляю все опасные символы из имени.
До сих пор я придумал следующую функцию, которая я надеюсь, решает эту проблему и позволяет внешние данные UTF-8 также.
/**
* Convert a string to the file/URL safe "slug" form
*
* @param string $string the string to clean
* @param bool $is_filename TRUE will allow additional filename characters
* @return string
*/
function sanitize($string = '', $is_filename = FALSE)
{
// Replace all weird characters with dashes
$string = preg_replace('/[^\w\-'. ($is_filename ? '~_\.' : ''). ']+/u', '-', $string);
// Only allow one dash separator at a time (and make string lowercase)
return mb_strtolower(preg_replace('/--+/u', '-', $string), 'UTF-8');
}
У кого-либо есть какие-либо хитрые демонстрационные данные, которые я могу выполнить против этого - или знать лучшего способа охранять наши приложения с плохих имен?
$is-filename позволяет некоторые дополнительные символы как временные файлы энергии
обновление: удаленный звездообразный символ, так как я не мог думать о допустимом использовании
Некоторые наблюдения по поводу вашего решения:
Символ «слова» - это любая буква, цифра или символ подчеркивания, то есть любой символ, который может быть частью «слова» Perl. Определение букв и цифр контролируется символьными таблицами PCRE и может варьироваться, если имеет место соответствие для конкретной локали. Например, в языковом стандарте «fr» (французский) некоторые коды символов больше 128 используются для букв с диакритическими знаками, и им соответствует \ w.
Вероятно, вам не следует включать символы с диакритическими знаками и т. Д. В заголовок сообщения, поскольку технически они должны быть закодированы в процентах (согласно правилам кодирования URL), чтобы URL-адреса выглядели некрасиво.
Итак, если бы я был вами, после нижнего регистра, я бы преобразовал любые «специальные» символы в их эквиваленты (например, é -> e) и заменил символы, отличные от [az], на «-», ограничившись запусками одного '-' как вы это сделали. Здесь есть реализация преобразования специальных символов: https://web.archive.org/web/20130208144021/http://neo22s.com / slug
OWASP имеет PHP-реализацию своего Enterprise Security API, которая, среди прочего, включает методы для безопасного кодирования и декодирования ввода и вывода в вашем приложении.
Интерфейс кодировщика предоставляет:
canonicalize (string $input, [bool $strict = true])
decodeFromBase64 (string $input)
decodeFromURL (string $input)
encodeForBase64 (string $input, [bool $wrap = false])
encodeForCSS (string $input)
encodeForHTML (string $input)
encodeForHTMLAttribute (string $input)
encodeForJavaScript (string $input)
encodeForOS (Codec $codec, string $input)
encodeForSQL (Codec $codec, string $input)
encodeForURL (string $input)
encodeForVBScript (string $input)
encodeForXML (string $input)
encodeForXMLAttribute (string $input)
encodeForXPath (string $input)
https://github.com/OWASP/PHP-ESAPI https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
// CLEAN ILLEGAL CHARACTERS
function clean_filename($source_file)
{
$search[] = " ";
$search[] = "&";
$search[] = "$";
$search[] = ",";
$search[] = "!";
$search[] = "@";
$search[] = "#";
$search[] = "^";
$search[] = "(";
$search[] = ")";
$search[] = "+";
$search[] = "=";
$search[] = "[";
$search[] = "]";
$replace[] = "_";
$replace[] = "and";
$replace[] = "S";
$replace[] = "_";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
$replace[] = "";
return str_replace($search,$replace,$source_file);
}
Попробуйте следующее:
function normal_chars($string)
{
$string = htmlentities($string, ENT_QUOTES, 'UTF-8');
$string = preg_replace('~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', $string);
$string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
$string = preg_replace(array('~[^0-9a-z]~i', '~[ -]+~'), ' ', $string);
return trim($string, ' -');
}
Examples:
echo normal_chars('Álix----_Ãxel!?!?'); // Alix Axel
echo normal_chars('áéíóúÁÉÍÓÚ'); // aeiouAEIOU
echo normal_chars('üÿÄËÏÖÜŸåÅ'); // uyAEIOUYaA
На основе выбранного ответа в этой теме: URL-адрес дружественного имени пользователя в PHP?
Я нашел эту большую функцию в коде Chyrp :
/**
* Function: sanitize
* Returns a sanitized string, typically for URLs.
*
* Parameters:
* $string - The string to sanitize.
* $force_lowercase - Force the string to lowercase?
* $anal - If set to *true*, will remove all non-alphanumeric characters.
*/
function sanitize($string, $force_lowercase = true, $anal = false) {
$strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
"}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—",
"—", "–", ",", "<", ".", ">", "/", "?");
$clean = trim(str_replace($strip, "", strip_tags($string)));
$clean = preg_replace('/\s+/', "-", $clean);
$clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
return ($force_lowercase) ?
(function_exists('mb_strtolower')) ?
mb_strtolower($clean, 'UTF-8') :
strtolower($clean) :
$clean;
}
и эту в wordpress код
/**
* Sanitizes a filename replacing whitespace with dashes
*
* Removes special characters that are illegal in filenames on certain
* operating systems and special characters requiring special escaping
* to manipulate at the command line. Replaces spaces and consecutive
* dashes with a single dash. Trim period, dash and underscore from beginning
* and end of filename.
*
* @since 2.1.0
*
* @param string $filename The filename to be sanitized
* @return string The sanitized filename
*/
function sanitize_file_name( $filename ) {
$filename_raw = $filename;
$special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}");
$special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $filename_raw);
$filename = str_replace($special_chars, '', $filename);
$filename = preg_replace('/[\s-]+/', '-', $filename);
$filename = trim($filename, '.-_');
return apply_filters('sanitize_file_name', $filename, $filename_raw);
}
Аликс Аксель проделал невероятную работу в этой области. Его phunction framework включает в себя несколько отличных текстовых фильтров и преобразований.
Я не думаю, что иметь список удаляемых символов безопасно. Я бы предпочел использовать следующее:
Для имен файлов: используйте внутренний идентификатор или хэш содержимого файла. Сохраните название документа в базе данных. Таким образом, вы можете сохранить исходное имя файла и при этом найти файл.
Для параметров URL: используйте urlencode ()
для кодирования любых специальных символов.
Я всегда думал, что Кохана неплохо справился с этим .
public static function title($title, $separator = '-', $ascii_only = FALSE)
{
if ($ascii_only === TRUE)
{
// Transliterate non-ASCII characters
$title = UTF8::transliterate_to_ascii($title);
// Remove all characters that are not the separator, a-z, 0-9, or whitespace
$title = preg_replace('![^'.preg_quote($separator).'a-z0-9\s]+!', '', strtolower($title));
}
else
{
// Remove all characters that are not the separator, letters, numbers, or whitespace
$title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', UTF8::strtolower($title));
}
// Replace all separator characters and whitespace by a single separator
$title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title);
// Trim separators from the beginning and end
return trim($title, $separator);
}
Удобный UTF8 :: transliterate_to_ascii ()
будет преобразовывать такие вещи, как ñ => n.
Конечно, вы можете заменить другие UTF8 :: *
функциями mb_ *.
В зависимости от того, как вы будете его использовать, вы можете добавить длину ограничение для защиты от переполнения буфера.
Что касается загрузки файлов, безопаснее всего запретить пользователю управлять именем файла. Как уже упоминалось, сохраните канонизированное имя файла в базе данных вместе со случайно выбранным и уникальным именем, которое вы будете использовать в качестве фактического имени файла.
Используя OWASP ESAPI, эти имена могут быть сгенерированы следующим образом:
$userFilename = ESAPI::getEncoder()->canonicalize($input_string);
$safeFilename = ESAPI::getRandomizer()->getRandomFilename();
Вы можете добавить метку времени к $ safeFilename, чтобы гарантировать уникальность случайно сгенерированного имени файла, даже не проверяя существующий файл.
С точки зрения кодирования для URL и снова с использованием ESAPI:
$safeForURL = ESAPI::getEncoder()->encodeForURL($input_string);
Этот метод выполняет канонизацию перед кодированием строки и обрабатывает все кодировки символов.
почему бы просто не использовать php urlencode
? он заменяет "опасные" символы их шестнадцатеричным представлением для URL-адресов (например, % 20
вместо пробела)
Это должно сделать ваши имена файлов безопасными...
$string = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $string);
и более глубокое решение для этого:
// Remove special accented characters - ie. sí.
$clean_name = strtr($string, array('Š' => 'S','Ž' => 'Z','š' => 's','ž' => 'z','Ÿ' => 'Y','À' => 'A','Á' => 'A','Â' => 'A','Ã' => 'A','Ä' => 'A','Å' => 'A','Ç' => 'C','È' => 'E','É' => 'E','Ê' => 'E','Ë' => 'E','Ì' => 'I','Í' => 'I','Î' => 'I','Ï' => 'I','Ñ' => 'N','Ò' => 'O','Ó' => 'O','Ô' => 'O','Õ' => 'O','Ö' => 'O','Ø' => 'O','Ù' => 'U','Ú' => 'U','Û' => 'U','Ü' => 'U','Ý' => 'Y','à' => 'a','á' => 'a','â' => 'a','ã' => 'a','ä' => 'a','å' => 'a','ç' => 'c','è' => 'e','é' => 'e','ê' => 'e','ë' => 'e','ì' => 'i','í' => 'i','î' => 'i','ï' => 'i','ñ' => 'n','ò' => 'o','ó' => 'o','ô' => 'o','õ' => 'o','ö' => 'o','ø' => 'o','ù' => 'u','ú' => 'u','û' => 'u','ü' => 'u','ý' => 'y','ÿ' => 'y'));
$clean_name = strtr($clean_name, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u'));
$clean_name = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $clean_name);
Это предполагает, что вы хотите точку в имени файла. Если вы хотите перевести его в нижний регистр, просто используйте
$clean_name = strtolower($clean_name);
для последней строки.