Очистить строки, чтобы сделать их безопасными для URL и имени файла?

136

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

обновление: убрал символ звезды, так как я не мог придумать правильное использование

Xeoncross
источник
Вам лучше удалить все, кроме [\ w.-]
Элиас
3
Вы можете найти нормализатор и комментарии к нему полезными.
Мэтт Гибсон

Ответы:

57

Некоторые замечания по вашему решению:

  1. 'u' в конце вашего паттерна означает, что паттерн , а не текст, который ему соответствует, будет интерпретироваться как UTF-8 (я полагаю, вы предположили последний?).
  2. \ w соответствует символу подчеркивания. Вы специально включаете его для файлов, что приводит к предположению, что вы не хотите, чтобы они были в URL, но в коде, который у вас есть, URL будет разрешено включать подчеркивание.
  3. Включение «чужого UTF-8», кажется, зависит от локали. Не ясно, является ли это языковым стандартом сервера или клиента. Из документов PHP:

Символ «слово» - это любая буква или цифра или символ подчеркивания, то есть любой символ, который может быть частью «слова» Perl. Определение букв и цифр контролируется таблицами символов PCRE и может отличаться, если происходит сопоставление для конкретной локали. Например, в локали "fr" (французский) некоторые коды символов, превышающие 128, используются для букв с надстрочными знаками, и они соответствуют \ w.

Создание слизняка

Вы, вероятно, не должны включать акцентированные и т. Д. Символы в свой пост-пост, поскольку технически они должны быть закодированы в процентах (согласно правилам кодирования URL), чтобы у вас были уродливые URL.

Таким образом, на вашем месте я бы после преобразования в нижний регистр преобразовал бы любые «специальные» символы в их эквивалент (например, é -> e) и заменил бы не [az] символы на «-», ограничиваясь запусками одного «-» как ты сделал. Здесь есть реализация преобразования специальных символов: https://web.archive.org/web/20130208144021/http://neo22s.com/slug

Санитарная обработка в целом

У OWASP есть реализация PHP их Enterprise Security API на PHP, которая, среди прочего, включает методы для безопасного кодирования и декодирования ввода и вывода в вашем приложении.

Интерфейс Encoder обеспечивает:

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

Алан Доннелли
источник
Вы правы относительно моего предположения о модификаторе "u" - я думал, что это было для текста. Я также забыл о модификаторе \ w, включая подчеркивание. Я обычно конвертирую все символы с акцентом в ASCII - но я хочу, чтобы это работало и для других языков. Я предполагал, что существует какой-то безопасный способ UTF-8, что любой символ языка может быть использован в URL-адресе или имени файла, чтобы сработали даже арабские заголовки. В конце концов, linux поддерживает имена файлов UTF-8, и браузеры должны кодировать HTML-ссылки по мере необходимости. Большое спасибо за ваш вклад здесь.
Xeoncross
Если подумать, вы на самом деле правы, но проблема не только в том, что браузер правильно кодирует ссылки. Самый простой способ добиться того, чего вы хотите, - это сопоставить символы, не входящие в ASCII, с их ближайшим эквивалентом ASCII, а затем закодировать URL-адрес вашей ссылки в теле HTML. Сложный путь - обеспечить согласованную кодировку UTF-8 (или UTF-16, я думаю, для некоторых китайских диалектов) из вашего хранилища данных, через ваш веб-сервер, прикладной уровень (PHP), содержимое страницы, веб-браузер и не кодировать URL-адреса ваших URL ( но все же лишить «нежелательных» символов). Это даст вам хорошие некодированные ссылки и URL.
Алан Доннелли
Хороший совет. Я собираюсь попытаться создать чистую среду UTF-8. Затем, взяв несколько строк из языков, не относящихся к ASCII, я удалю опасные символы (./ ;: и т. Д.) И создам файлы, а затем добавлю HTML-ссылки на эти файлы, чтобы посмотреть, смогу ли я щелкнуть по ним и посмотреть, все ли это работает. Если нет, то мне, вероятно, придется вернуться к (raw)? Urlencode (), чтобы разрешить UTF-8. Я опубликую результаты здесь.
Xeoncross
3
Я создал файл с именем, สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txtа затем создал HTML-файл UTF-8 со ссылкой на него. Удивительно, но это сработало - даже на окнах! Однако у меня тогда был PHP, file_put_contents('สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txt')и он не смог создать имя файла базара из этой строки. Затем я попытался создать его fopen()и получил то же испорченное имя файла. Таким образом, очевидно, что PHP (по крайней мере для Windows) не способен создавать имена файлов UTF-8. bugs.php.net/bug.php?id=46990&thanks=6
Xeoncross
1
Я награждаю этим ответом, потому что он заставил меня задуматься больше всего, а также содержал полезную ссылку на проект, о котором я никогда не слышал, который стоит изучить Я отправлю, как только найду ответ.
Xeoncross
87

Я нашел эту большую функцию в коде 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);
}

Обновление сентябрь 2012

Аликс Аксель проделал невероятную работу в этой области. Его функциональная структура включает в себя несколько отличных текстовых фильтров и преобразований.

Xeoncross
источник
23
Код WordPress не является переносимым, поскольку он используетapply_filters
Кевин Марк
1
Обратите внимание , что WordPress версия заменяет /[\s-]+/с -которой лучше , чем первая версия (которая заменяет только /\s+/) , что может привести к несколько тире подряд
Yotam Omer
Просто для справки WordPress apply_filters можно найти здесь и sanitize_file_name здесь .
Эрик
как насчет нескольких пробелов? Заменить
Джеффри Жираф
8
Переменная $ anal звучит очень пугающе для меня с опцией force.
Вильюн
30

Это должно сделать ваши имена файлов безопасными ...

$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);

для последней строки.

SoLoGHoST
источник
1
Все еще отсутствуют некоторые чешские и словацкие символы:'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
Ясом Дотнет
22

Попробуй это:

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 Friendly Username в PHP?

Джон Конде
источник
Очень хорошо - я никогда не видел, чтобы это делалось без таблицы перевода (как в WordPress). Однако я не думаю, что этой функции достаточно как есть, поскольку она переводит только специальные символы, но не удаляет опасные символы. Возможно это может быть добавлено к одному выше ...
Xeoncross
4
Ха! Хак с кодировкой сущностей сладок! Хотя на первый взгляд не совсем понятно, как этот метод делает то, что делает. Хотя есть проблема. Не превратится ли «Frédéric & Éric» в «Frederic amp Eric»?
Алан Доннелли
@AlanDonnelly: Действительно, я обновил функцию в своем исходном ответе (проверьте ссылку), также trim()должно быть trim($string, '-').
Аликс Аксель
@Xeoncross: последний preg_replace()должен удалить все опасные символы.
Аликс Аксель
@AlixAxel, ты просто везде не так. Я просто читал над PHP AWS SDK, и у них был какой-то ваш код для UUID. Удивительный код функции просто трудно победить.
Xeoncross
13

Это не совсем ответ, так как он не дает никаких решений (пока!), Но он слишком велик, чтобы поместиться в комментарии ...


Я провел некоторое тестирование (относительно имен файлов) на Windows 7 и Ubuntu 12.04, и выяснил, что:

1. PHP не может обрабатывать не-ASCII имена файлов

Хотя и Windows, и Ubuntu могут обрабатывать имена файлов Unicode (даже RTL, как кажется), PHP 5.3 требует хаков, чтобы иметь дело даже с простым старым ISO-8859-1, поэтому лучше сохранить его в ASCII только для безопасности.

2. Длина имени файла имеет значение (особенно в Windows)

В Ubuntu максимальная длина имени файла (включая расширение) составляет 255 (без пути):

/var/www/uploads/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345/

Однако в Windows 7 (NTFS) максимальная длина имени файла зависит от его абсолютного пути:

(0 + 0 + 244 + 11 chars) C:\1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\1234567.txt
(0 + 3 + 240 + 11 chars) C:\123\123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\1234567.txt
(3 + 3 + 236 + 11 chars) C:\123\456\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1234567.txt

Википедия говорит, что:

NTFS позволяет каждому компоненту пути (каталог или имя файла) иметь длину 255 символов.

Насколько мне известно (и тестирование), это неправильно.

В целом (с учетом слеша) все эти примеры имеют 259 символов, если вы C:\удалите символ, который дает 256 символов (не 255 ?!). Каталоги были созданы с помощью Проводника, и вы заметите, что он ограничивает себя в использовании всего доступного пространства для имени каталога. Причина этого заключается в том, чтобы разрешить создание файлов с использованием соглашения о присвоении имен 8.3 . То же самое происходит с другими разделами.

Файлы не должны резервировать требования 8,3 длины, конечно:

(255 chars) E:\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.txt

Вы не можете создавать больше подкаталогов, если абсолютный путь родительского каталога содержит более 242 символов, потому что 256 = 242 + 1 + \ + 8 + . + 3. Используя Windows Explorer, вы не можете создать другой каталог, если родительский каталог содержит более 233 символов (в зависимости от локали системы), потому что 256 = 233 + 10 + \ + 8 + . + 3; 10здесь длина строки New folder.

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

3. Остерегайтесь зарезервированных символов и ключевых слов.

Помимо удаления не ASCII, непечатных и управляющих символов , вам также необходимо повторно (поместить / переместить):

"*/:<>?\|

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

  • "*? -> _
  • /\| -> -
  • : -> [ ]-[ ]
  • < -> (
  • > -> )

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

4. Чувствительность к регистру

Это должно быть само собой разумеющимся, но если вы хотите обеспечить уникальность файлов в разных операционных системах, вам следует преобразовать имена файлов в нормализованный регистр, таким образом my_file.txtи My_File.txtв Linux оба не станут одним и тем же my_file.txtфайлом в Windows.

5. Убедитесь, что это уникально

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

Общие уникальные идентификаторы включают метку времени UNIX, дайджест содержимого файла или случайную строку.

6. Скрытые файлы

То, что его можно назвать, не значит, что оно должно ...

Точки, как правило, заносятся в белый список в именах файлов, но в Linux скрытый файл представлен лидирующей точкой.

7. Другие соображения

Если вам нужно удалить несколько символов имени файла, расширение обычно более важно, чем базовое имя файла. Допуская значительное максимальное количество символов для расширения файла (8-16), следует удалить символы из базового имени. Важно также отметить , что в маловероятном случае наличия более чем один длинное расширения - такие , как _.graphmlz.tag.gz- _.graphmlz.tagтолько _следует рассматривать в качестве базового имени файла в этом случае.

8. Ресурсы

Калибр обрабатывает искажение имени файла довольно прилично:

Страница Википедии по искажению имени файла и связанная с ним глава из Использование Samba .


Например, если вы попытаетесь создать файл, который нарушает любое из правил 1/2/3, вы получите очень полезную ошибку:

Warning: touch(): Unable to create file ... because No error in ... on line ...
Аликс Аксель
источник
11

Я всегда думал, что Кохана справилась с этим довольно хорошо .

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_ *.

Алекс
источник
5

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

Используя OWASP ESAPI, эти имена могут быть сгенерированы следующим образом:

$userFilename   = ESAPI::getEncoder()->canonicalize($input_string);
$safeFilename   = ESAPI::getRandomizer()->getRandomFilename();

Вы можете добавить метку времени к $ safeFilename, чтобы убедиться, что случайно сгенерированное имя файла уникально, даже не проверяя существующий файл.

С точки зрения кодирования для URL, и снова с помощью ESAPI:

$safeForURL     = ESAPI::getEncoder()->encodeForURL($input_string);

Этот метод выполняет канонизацию перед кодированием строки и будет обрабатывать все кодировки символов.

Джа
источник
Определенно - кроме того, отказ от управления именами файлов у пользователей предотвратит возможность двух загрузок с одинаковым именем.
CodeVirtuoso
5

Я рекомендую * URLify для PHP (480+ звезд на Github) - «PHP-порт URLify.js из проекта Django. Транслитерирует не-ascii символы для использования в URL».

Основное использование:

Чтобы создать слаг для URL:

<?php

echo URLify::filter (' J\'étudie le français ');
// "jetudie-le-francais"

echo URLify::filter ('Lo siento, no hablo español.');
// "lo-siento-no-hablo-espanol"

?>

Чтобы создать слаг для имен файлов:

<?php

echo URLify::filter ('фото.jpg', 60, "", true);
// "foto.jpg"

?>

* Ни одно из других предложений не соответствовало моим критериям:

  • Должен быть установлен через композитор
  • Не должен зависеть от iconv, так как он ведет себя по-разному в разных системах
  • Должен быть расширяемым, чтобы разрешать переопределения и замены пользовательских символов
  • Популярные (например, много звезд на Github)
  • Есть тесты

В качестве бонуса URLify также удаляет определенные слова и удаляет все символы, не транслитерированные.

Вот тестовый пример с тоннами иностранных символов, которые правильно транслитерируются с помощью URLify: https://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f

Мотин
источник
1
Спасибо - это выглядит идеально для моих целей.
Дэвид Гудвин
5

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

/**
 * Convert a string into a url safe address.
 *
 * @param string $unformatted
 * @return string
 */
public function formatURL($unformatted) {

    $url = strtolower(trim($unformatted));

    //replace accent characters, forien languages
    $search = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'IJ', 'ij', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'ſ', 'ƒ', 'Ơ', 'ơ', 'Ư', 'ư', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ', 'ǒ', 'Ǔ', 'ǔ', 'Ǖ', 'ǖ', 'Ǘ', 'ǘ', 'Ǚ', 'ǚ', 'Ǜ', 'ǜ', 'Ǻ', 'ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ'); 
    $replace = array('A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 's', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'l', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U', 'u', 'A', 'a', 'I', 'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o'); 
    $url = str_replace($search, $replace, $url);

    //replace common characters
    $search = array('&', '£', '$'); 
    $replace = array('and', 'pounds', 'dollars'); 
    $url= str_replace($search, $replace, $url);

    // remove - for spaces and union characters
    $find = array(' ', '&', '\r\n', '\n', '+', ',', '//');
    $url = str_replace($find, '-', $url);

    //delete and replace rest of special chars
    $find = array('/[^a-z0-9\-<>]/', '/[\-]+/', '/<[^>]*>/');
    $replace = array('', '-', '');
    $uri = preg_replace($find, $replace, $url);

    return $uri;
}
Джон Магнолия
источник
5

и это версия Joomla 3.3.2 из JFile::makeSafe($file)

public static function makeSafe($file)
{
    // Remove any trailing dots, as those aren't ever valid file names.
    $file = rtrim($file, '.');

    $regex = array('#(\.){2,}#', '#[^A-Za-z0-9\.\_\- ]#', '#^\.#');

    return trim(preg_replace($regex, '', $file));
}
cedric.walter
источник
4

Я не думаю, что иметь список символов для удаления безопасно. Я бы предпочел использовать следующее:

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

Для параметров URL: используйте urlencode()для кодирования любых специальных символов.

ZeissS
источник
1
Я согласен, большинство методов, перечисленных здесь, удаляют известные опасные символы - мой метод удаляет все, что не является известным безопасным символом. Так как большинство системных слагов кодируют почтовые URL, я бы посоветовал нам продолжать следовать этому проверенному методу, а не использовать документированный небезопасный urlencode () UTF-8 .
Xeoncross
3

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

Tgr
источник
Да, тестирование для mb_strlen () всегда важно!
Xeoncross
3

Это хороший способ обеспечить загрузку имени файла:

$file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
игры
источник
Я не уверен в этом, потому что один .\x00..\x20может быть уменьшен до .\x00\x20.
Xeoncross
@Xeoncross: я думаю, что .\x00..\x20удаляет точки и каждый символ между \x00и \x20, тогда как .\x00\x20следует удалять только эти 3 байта.
Аликс Аксель
Этот ответ требует более подробного объяснения для его безопасного использования. Не так много информации о точном синтаксисе для чарлиста в сети.
Мануэль Арвед Шмидт
3

Вот реализация CodeIgniter.

/**
 * Sanitize Filename
 *
 * @param   string  $str        Input file name
 * @param   bool    $relative_path  Whether to preserve paths
 * @return  string
 */
public function sanitize_filename($str, $relative_path = FALSE)
{
    $bad = array(
        '../', '<!--', '-->', '<', '>',
        "'", '"', '&', '$', '#',
        '{', '}', '[', ']', '=',
        ';', '?', '%20', '%22',
        '%3c',      // <
        '%253c',    // <
        '%3e',      // >
        '%0e',      // >
        '%28',      // (
        '%29',      // )
        '%2528',    // (
        '%26',      // &
        '%24',      // $
        '%3f',      // ?
        '%3b',      // ;
        '%3d'       // =
    );

    if ( ! $relative_path)
    {
        $bad[] = './';
        $bad[] = '/';
    }

    $str = remove_invisible_characters($str, FALSE);
    return stripslashes(str_replace($bad, '', $str));
}

И remove_invisible_charactersзависимость.

function remove_invisible_characters($str, $url_encoded = TRUE)
{
    $non_displayables = array();

    // every control character except newline (dec 10),
    // carriage return (dec 13) and horizontal tab (dec 09)
    if ($url_encoded)
    {
        $non_displayables[] = '/%0[0-8bcef]/';  // url encoded 00-08, 11, 12, 14, 15
        $non_displayables[] = '/%1[0-9a-f]/';   // url encoded 16-31
    }

    $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';   // 00-08, 11, 12, 14-31, 127

    do
    {
        $str = preg_replace($non_displayables, '', $str, -1, $count);
    }
    while ($count);

    return $str;
}
Кевин Марк
источник
2

почему бы просто не использовать php urlencode? он заменяет «опасные» символы их шестнадцатеричным представлением для URL (то есть %20для пробела)

knittl
источник
2
Символ% не рекомендуется для имен файлов, а шестнадцатеричные символы не выглядят так хорошо в URL. Браузеры могут поддерживать строки UTF-8, которые намного приятнее и проще для языков, отличных от ascii.
Xeoncross
Вы могли бы сделать urlencode и ТОГДА str_replace ('% 20', '-', url)?
Франческо
2

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

Функция

Здесь функция упакована в пакет Symfony2, но ее можно извлечь для использования в качестве простого PHP , она зависит только отiconv функции, которая должна быть включена:

Filesystem.php :

<?php

namespace COil\Bundle\COilCoreBundle\Component\HttpKernel\Util;

use Symfony\Component\HttpKernel\Util\Filesystem as BaseFilesystem;

/**
 * Extends the Symfony filesystem object.
 */
class Filesystem extends BaseFilesystem
{
    /**
     * Make a filename safe to use in any function. (Accents, spaces, special chars...)
     * The iconv function must be activated.
     *
     * @param string  $fileName       The filename to sanitize (with or without extension)
     * @param string  $defaultIfEmpty The default string returned for a non valid filename (only special chars or separators)
     * @param string  $separator      The default separator
     * @param boolean $lowerCase      Tells if the string must converted to lower case
     *
     * @author COil <https://github.com/COil>
     * @see    http://stackoverflow.com/questions/2668854/sanitizing-strings-to-make-them-url-and-filename-safe
     *
     * @return string
     */
    public function sanitizeFilename($fileName, $defaultIfEmpty = 'default', $separator = '_', $lowerCase = true)
    {
    // Gather file informations and store its extension
    $fileInfos = pathinfo($fileName);
    $fileExt   = array_key_exists('extension', $fileInfos) ? '.'. strtolower($fileInfos['extension']) : '';

    // Removes accents
    $fileName = @iconv('UTF-8', 'us-ascii//TRANSLIT', $fileInfos['filename']);

    // Removes all characters that are not separators, letters, numbers, dots or whitespaces
    $fileName = preg_replace("/[^ a-zA-Z". preg_quote($separator). "\d\.\s]/", '', $lowerCase ? strtolower($fileName) : $fileName);

    // Replaces all successive separators into a single one
    $fileName = preg_replace('!['. preg_quote($separator).'\s]+!u', $separator, $fileName);

    // Trim beginning and ending seperators
    $fileName = trim($fileName, $separator);

    // If empty use the default string
    if (empty($fileName)) {
        $fileName = $defaultIfEmpty;
    }

    return $fileName. $fileExt;
    }
}

Юнит тесты

Что интересно, я создал тесты PHPUnit, сначала для тестирования крайних случаев, и поэтому вы можете проверить, соответствует ли он вашим потребностям: (Если вы обнаружите ошибку, не стесняйтесь добавлять тестовый пример)

FilesystemTest.php :

<?php

namespace COil\Bundle\COilCoreBundle\Tests\Unit\Helper;

use COil\Bundle\COilCoreBundle\Component\HttpKernel\Util\Filesystem;

/**
 * Test the Filesystem custom class.
 */
class FilesystemTest extends \PHPUnit_Framework_TestCase
{
    /**
     * test sanitizeFilename()
     */
    public function testFilesystem()
    {
    $fs = new Filesystem();

    $this->assertEquals('logo_orange.gif', $fs->sanitizeFilename('--logö  _  __   ___   ora@@ñ--~gé--.gif'), '::sanitizeFilename() handles complex filename with specials chars');
    $this->assertEquals('coilstack', $fs->sanitizeFilename('cOiLsTaCk'), '::sanitizeFilename() converts all characters to lower case');
    $this->assertEquals('cOiLsTaCk', $fs->sanitizeFilename('cOiLsTaCk', 'default', '_', false), '::sanitizeFilename() lower case can be desactivated, passing false as the 4th argument');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('coil stack'), '::sanitizeFilename() convert a white space to a separator');
    $this->assertEquals('coil-stack', $fs->sanitizeFilename('coil stack', 'default', '-'), '::sanitizeFilename() can use a different separator as the 3rd argument');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('coil          stack'), '::sanitizeFilename() removes successive white spaces to a single separator');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('       coil stack'), '::sanitizeFilename() removes spaces at the beginning of the string');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('coil   stack         '), '::sanitizeFilename() removes spaces at the end of the string');
    $this->assertEquals('coilstack', $fs->sanitizeFilename('coil,,,,,,stack'), '::sanitizeFilename() removes non-ASCII characters');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename('coil_stack  '), '::sanitizeFilename() keeps separators');
    $this->assertEquals('coil_stack', $fs->sanitizeFilename(' coil________stack'), '::sanitizeFilename() converts successive separators into a single one');
    $this->assertEquals('coil_stack.gif', $fs->sanitizeFilename('cOil Stack.GiF'), '::sanitizeFilename() lower case filename and extension');
    $this->assertEquals('copy_of_coil.stack.exe', $fs->sanitizeFilename('Copy of coil.stack.exe'), '::sanitizeFilename() keeps dots before the extension');
    $this->assertEquals('default.doc', $fs->sanitizeFilename('____________.doc'), '::sanitizeFilename() returns a default file name if filename only contains special chars');
    $this->assertEquals('default.docx', $fs->sanitizeFilename('     ___ -  --_     __%%%%__¨¨¨***____      .docx'), '::sanitizeFilename() returns a default file name if filename only contains special chars');
    $this->assertEquals('logo_edition_1314352521.jpg', $fs->sanitizeFilename('logo_edition_1314352521.jpg'), '::sanitizeFilename() returns the filename untouched if it does not need to be modified');
    $userId = rand(1, 10);
    $this->assertEquals('user_doc_'. $userId. '.doc', $fs->sanitizeFilename('亐亐亐亐亐.doc', 'user_doc_'. $userId), '::sanitizeFilename() returns the default string (the 2nd argument) if it can\'t be sanitized');
    }
}

Результаты теста: (проверено на Ubuntu с PHP 5.3.2 и MacOsX с PHP 5.3.17:

All tests pass:

phpunit -c app/ src/COil/Bundle/COilCoreBundle/Tests/Unit/Helper/FilesystemTest.php
PHPUnit 3.6.10 by Sebastian Bergmann.

Configuration read from /var/www/strangebuzz.com/app/phpunit.xml.dist

.

Time: 0 seconds, Memory: 5.75Mb

OK (1 test, 17 assertions)
змеевик
источник
1
Это предполагает в основном латиницу. Добавьте больше символов UTF-8 из других языков, чтобы увидеть, где у вас будут проблемы.
Xeoncross
@Xeoncross Я согласен, как сказал Кристиан, нужно сохранить Id или хэш и оригинальное имя файла. Но эта функция предоставляет альтернативу, поскольку вы можете указать строку по умолчанию, когда процесс очистки завершится неудачно. Я добавил юнит-тест для этого случая. Спасибо за сообщение об ошибке.
Катушка
2

У меня есть заголовки со всеми видами странных латинских символов, а также некоторые теги HTML, которые мне нужно было перевести в полезный формат имени файла с разделителями-тире. Я объединил ответ @ SoLoGHoST с парой пунктов из ответа @ Xeoncross и немного настроил его.

    function sanitize($string,$force_lowercase=true) {
    //Clean up titles for filenames
    $clean = strip_tags($string);
    $clean = strtr($clean, 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 = strtr($clean, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u','—' => '-'));
    $clean = str_replace("--", "-", preg_replace("/[^a-z0-9-]/i", "", preg_replace(array('/\s/', '/[^\w-\.\-]/'), array('-', ''), $clean)));

    return ($force_lowercase) ?
        (function_exists('mb_strtolower')) ?
            mb_strtolower($clean, 'UTF-8') :
            strtolower($clean) :
        $clean;
}

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

Так:

Часть 1: «Žurburts» моего отца? - они (не) лучшие!

будет выглядеть так:

часть-1-мой-пап-zurburts-Theyre-не-лучший

Я просто добавляю ".html" в возвращаемую строку.

cbmtrx
источник
1
Все еще отсутствуют некоторые чешские и словацкие символы:'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
Ясом Дотнет
1
И, несомненно, еще много. Я на самом деле пытаюсь выяснить, существует ли набор ISO, который включает в себя комбинации символов. Как «выбрать» один набор, если контент требует символов от всех из них? UTF-8 я предполагаю ...
cbmtrx
Я узнал, как транслитерировать любую строку, используя одну строку PHP : $string = transliterator_transliterate('Any-Latin;Latin-ASCII;', $string);см. Мой ответ ниже или прочитайте связанный пост в блоге.
Джасом Дотнет
1
Нет, вы неправильно прочитали: ЕСЛИ вы можете установить расширения PHP на свой сервер (или хостинг) :-) Вот пост .
Джасом Дотнет
1
Ах, понял. Спасибо @JasomDotnet - мое текущее решение работает, но это ограниченный набор символов, поэтому расширение стоит проверить.
cbmtrx
2

Решение № 1: У вас есть возможность установить расширения PHP на сервере (хостинг)

Для транслитерации «почти каждого языка на планете Земля» в символы ASCII.

  1. Сначала установите расширение PHP Intl . Это команда для Debian (Ubuntu):sudo aptitude install php5-intl

  2. Это моя функция fileName (создайте test.php и вставьте туда следующий код):

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<?php

function pr($string) {
  print '<hr>';
  print '"' . fileName($string) . '"';
  print '<br>';
  print '"' . $string . '"';
}

function fileName($string) {
  // remove html tags
  $clean = strip_tags($string);
  // transliterate
  $clean = transliterator_transliterate('Any-Latin;Latin-ASCII;', $clean);
  // remove non-number and non-letter characters
  $clean = str_replace('--', '-', preg_replace('/[^a-z0-9-\_]/i', '', preg_replace(array(
    '/\s/', 
    '/[^\w-\.\-]/'
  ), array(
    '_', 
    ''
  ), $clean)));
  // replace '-' for '_'
  $clean = strtr($clean, array(
    '-' => '_'
  ));
  // remove double '__'
  $positionInString = stripos($clean, '__');
  while ($positionInString !== false) {
    $clean = str_replace('__', '_', $clean);
    $positionInString = stripos($clean, '__');
  }
  // remove '_' from the end and beginning of the string
  $clean = rtrim(ltrim($clean, '_'), '_');
  // lowercase the string
  return strtolower($clean);
}
pr('_replace(\'~&([a-z]{1,2})(ac134/56f4315981743 8765475[]lt7ňl2ú5äňú138yé73ťž7ýľute|');
pr(htmlspecialchars('<script>alert(\'hacked\')</script>'));
pr('Álix----_Ãxel!?!?');
pr('áéíóúÁÉÍÓÚ');
pr('üÿÄËÏÖÜ.ŸåÅ');
pr('nie4č a a§ôňäääaš');
pr('Мао Цзэдун');
pr('毛泽东');
pr('ماو تسي تونغ');
pr('مائو تسه‌تونگ');
pr('מאו דזה-דונג');
pr('მაო ძედუნი');
pr('Mao Trạch Đông');
pr('毛澤東');
pr('เหมา เจ๋อตง');
?>
</body>
</html>

Эта строка является основной:

  // transliterate
  $clean = transliterator_transliterate('Any-Latin;Latin-ASCII;', $clean);

Ответ основан на этом посте .

Решение № 2: У вас нет возможности установить расширения PHP на сервере (хостинг)

введите описание изображения здесь

Довольно хорошая работа проделана в модуле транслитерации для CMS Drupal. Он поддерживает почти каждый язык на планете Земля. Я предлагаю проверить хранилище плагинов, если вы хотите иметь действительно законченное решение для очистки строк.

Джасом Дотнет
источник
1

Этот пост, кажется, работает лучше всего из всех, что я связал. http://gsynuh.com/php-string-filename-url-safe/205

ktamlyn
источник
1
Этот пост очень коротко вздохнул и предполагает, что все на английском.
Xeoncross
1

Это хорошая функция:

public function getFriendlyURL($string) {
    setlocale(LC_CTYPE, 'en_US.UTF8');
    $string = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string);
    $string = preg_replace('~[^\-\pL\pN\s]+~u', '-', $string);
    $string = str_replace(' ', '-', $string);
    $string = trim($string, "-");
    $string = strtolower($string);
    return $string;
} 
joan16v
источник
Это выглядит плохо. \\s+означает обратную косую черту, за которой следует один или несколько пробелов. О чем это? Кроме того, он использует черный список, а не белый, игнорируя такие вещи, как CMD, ноль или BEL.
Xeoncross
Все еще плохо. Теперь строки вроде /blog/2014-02/just-in-timeне допускаются. Пожалуйста, используйте проверенный код выше или используйте phunctionкод фреймворка PHP.
Xeoncross
Это правильно. Эта функция предназначена только для части «точно в срок». Может быть полезно для некоторых людей.
joan16v
1
Вы можете изменить регулярное выражениеpreg_replace('~[^\-\pL\pN\s]+~u', '-', $string)
Xeoncross
Потрясающие! Я также добавил: string = trim ($ string, "-");
joan16v
0

Это код, используемый Prestashop для очистки URL:

replaceAccentedChars

используется

str2url

убрать диакритические знаки

function replaceAccentedChars($str)
{
    $patterns = array(
        /* Lowercase */
        '/[\x{0105}\x{00E0}\x{00E1}\x{00E2}\x{00E3}\x{00E4}\x{00E5}]/u',
        '/[\x{00E7}\x{010D}\x{0107}]/u',
        '/[\x{010F}]/u',
        '/[\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{011B}\x{0119}]/u',
        '/[\x{00EC}\x{00ED}\x{00EE}\x{00EF}]/u',
        '/[\x{0142}\x{013E}\x{013A}]/u',
        '/[\x{00F1}\x{0148}]/u',
        '/[\x{00F2}\x{00F3}\x{00F4}\x{00F5}\x{00F6}\x{00F8}]/u',
        '/[\x{0159}\x{0155}]/u',
        '/[\x{015B}\x{0161}]/u',
        '/[\x{00DF}]/u',
        '/[\x{0165}]/u',
        '/[\x{00F9}\x{00FA}\x{00FB}\x{00FC}\x{016F}]/u',
        '/[\x{00FD}\x{00FF}]/u',
        '/[\x{017C}\x{017A}\x{017E}]/u',
        '/[\x{00E6}]/u',
        '/[\x{0153}]/u',

        /* Uppercase */
        '/[\x{0104}\x{00C0}\x{00C1}\x{00C2}\x{00C3}\x{00C4}\x{00C5}]/u',
        '/[\x{00C7}\x{010C}\x{0106}]/u',
        '/[\x{010E}]/u',
        '/[\x{00C8}\x{00C9}\x{00CA}\x{00CB}\x{011A}\x{0118}]/u',
        '/[\x{0141}\x{013D}\x{0139}]/u',
        '/[\x{00D1}\x{0147}]/u',
        '/[\x{00D3}]/u',
        '/[\x{0158}\x{0154}]/u',
        '/[\x{015A}\x{0160}]/u',
        '/[\x{0164}]/u',
        '/[\x{00D9}\x{00DA}\x{00DB}\x{00DC}\x{016E}]/u',
        '/[\x{017B}\x{0179}\x{017D}]/u',
        '/[\x{00C6}]/u',
        '/[\x{0152}]/u');

    $replacements = array(
            'a', 'c', 'd', 'e', 'i', 'l', 'n', 'o', 'r', 's', 'ss', 't', 'u', 'y', 'z', 'ae', 'oe',
            'A', 'C', 'D', 'E', 'L', 'N', 'O', 'R', 'S', 'T', 'U', 'Z', 'AE', 'OE'
        );

    return preg_replace($patterns, $replacements, $str);
}

function str2url($str)
{
    if (function_exists('mb_strtolower'))
        $str = mb_strtolower($str, 'utf-8');

    $str = trim($str);
    if (!function_exists('mb_strtolower'))
        $str = replaceAccentedChars($str);

    // Remove all non-whitelist chars.
    $str = preg_replace('/[^a-zA-Z0-9\s\'\:\/\[\]-\pL]/u', '', $str);
    $str = preg_replace('/[\s\'\:\/\[\]-]+/', ' ', $str);
    $str = str_replace(array(' ', '/'), '-', $str);

    // If it was not possible to lowercase the string with mb_strtolower, we do it after the transformations.
    // This way we lose fewer special chars.
    if (!function_exists('mb_strtolower'))
        $str = strtolower($str);

    return $str;
}
Армель Ларсье
источник
-4
// 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);

} 
Брант Мессенджер
источник