Assainir les chaînes pour les rendre URL et nom de fichier sûrs?
j'essaie de trouver une fonction qui nettoie bien certaines chaînes de façon à ce qu'elles soient sûres à utiliser dans L'URL (comme une balle de poteau) et aussi sûres à utiliser comme noms de fichiers. Par exemple, quand quelqu'un télécharge un fichier, je veux m'assurer que j'ai supprimer tous les caractères du nom.
Jusqu'à présent, j'ai trouvé la fonction suivante qui, je l'espère, résout ce problème et permet aussi les données étrangères 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');
}
est - ce que quelqu'un a des données d'échantillon délicates que je peux exécuter contre ceci-ou connaissez une meilleure façon de protéger nos applications de mauvais noms?
$est-nom de fichier permet à certains personnages supplémentaires comme temp vim fichiers
mise à jour: suppression de l'étoile personnage puisque je ne pouvais pas penser à une utilisation valide
23 réponses
quelques observations sur votre solution:
- ' u 'à la fin de votre motif signifie que le motif , et non le texte qu'il correspond sera interprété comme UTF-8 (je présume que vous avez supposé ce dernier?).
- \W correspond au caractère underscore. Vous l'incluez spécifiquement pour les fichiers qui conduisent à l'hypothèse que vous ne voulez pas d'eux dans les URLs, mais dans le code que vous avez URLs sera autorisé à inclure souligner.
- l'inclusion de L'étranger "UTF-8" semble être dépendant de paramètres régionaux. Il n'est pas clair si c'est la localisation du serveur ou du client. De la PHP docs:
Un "mot" de caractère est une lettre ou un chiffre ou le caractère de soulignement, c'est-à-dire un caractère qui peut être partie d'un Perl "mot". La définition des lettres et des chiffres est contrôlée par les tables de caractères du PCRE, et peut varier si des correspondances locales spécifiques ont lieu. Par exemple, dans la locale" fr", certains codes de caractères supérieurs à 128 sont utilisés pour les lettres accentuées, et ceux-ci sont assortis par \W.
la Création de la limace
vous ne devriez probablement pas inclure accentué, etc. les caractères dans votre post slug puisque, techniquement, ils devraient être codés en pourcentage (par les règles d'encodage D'URL) de sorte que vous aurez des URL moches à la recherche.
Donc, si j'étais vous, après avoir diminué, Je convertirais tous les caractères "spéciaux" à leur équivalent (par exemple é -> e) et remplacerais les caractères non [A-z] par" -", en limitant aux passages d'un seul " - " comme vous l'avez fait. Il y a une implémentation de conversion des caractères spéciaux ici: https://web.archive.org/web/20130208144021/http://neo22s.com/slug
assainissement en général
OWASP ont une mise en œuvre PHP de leur entreprise API de sécurité qui inclut entre autres des méthodes pour encoder et décoder en toute sécurité les entrées et les sorties dans votre application.
L'interface de L'encodeur fournit:
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
j'ai trouvé cette plus grande fonction dans le Chyrp code:
/**
* 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;
}
et celui-ci dans le wordpress code
/**
* 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);
}
Mise À Jour Septembre 2012
Alix Axel a fait un travail incroyable dans ce domaine. Son cadre de fonction comprend plusieurs grands filtres et transformations de texte.
cela devrait sécuriser vos noms de fichiers...
$string = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $string);
et une solution plus profonde est:
// 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);
cela suppose que vous voulez un point dans le nom du fichier. si vous le souhaitez transféré en minuscules, il suffit d'utiliser
$clean_name = strtolower($clean_name);
pour la dernière ligne.
essayez ceci:
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', '', $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
basé sur la réponse sélectionnée dans ce thread: URL Friendly Username in PHP?
Ce n'est pas exactement la réponse qu'il ne propose pas de solutions (pour l'instant!), mais il est trop gros pour tenir sur un commentaire...
j'ai fait quelques tests (concernant les noms de fichiers) sur Windows 7 et Ubuntu 12.04 et ce que j'ai découvert était que:
1. PHP ne peut pas Gérer les noms de fichiers non-ASCII
bien que Windows et Ubuntu peuvent gérer Unicode les noms de fichiers (même ceux de RTL comme il semble) PHP 5.3 exige des hacks pour traiter même avec le simple Vieux ISO-8859-1, Il est donc préférable de le garder ASCII que pour la sécurité.
2. La longueur du nom de fichier importe (spécialement sur Windows)
sur Ubuntu, la longueur maximale qu'un nom de fichier peut avoir (extension incluse) est de 255 (chemin exclu):
/var/www/uploads/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345/
cependant, sur Windows 7 (NTFS) la longueur maximale nom de fichier peut avoir dépend du chemin d'accès absolu:
(0 + 0 + 244 + 11 chars) C:3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123434567.txt
(0 + 3 + 240 + 11 chars) C:3345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789034567.txt
(3 + 3 + 236 + 11 chars) C:3634567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345634567.txt
Wikipedia dit que:
NTFS permet chaque composant de chemin (répertoire ou nom de fichier) d'être 255 les caractères de long.
à ma connaissance (et les tests), ce n'est pas bien.
au total (décompte) tous ces les exemples ont 259 caractères, si vous supprimez le C:\
qui donne 256 caractères (pas 255?!). Les répertoires ont été créés en utilisant L'explorateur et vous remarquerez qu'il se retient d'utiliser toute l'espace disponible pour le nom du répertoire. La raison en est de permettre la création de fichiers en utilisant la 8.3 convention de nommage de fichier . La même chose se produit pour les autres cloisons.
n'ont pas besoin de réserver les 8.3 cours:
(255 chars) E:345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.txt
vous ne pouvez pas créer plus de sous-répertoires si le chemin absolu du répertoire parent a plus de 242 caractères, parce que 256 = 242 + 1 + \ + 8 + . + 3
. En utilisant Windows Explorer, vous ne pouvez pas créer un autre répertoire si le répertoire parent a plus de 233 caractères (selon la locale du système), parce que 256 = 233 + 10 + \ + 8 + . + 3
; le 10
ici est la longueur de la chaîne de caractères New folder
.
fichier système de Windows qui pose un méchant problème si vous voulez assurer l'interopérabilité entre les systèmes de fichiers.
3. Attention aux caractères réservés et aux mots-clés
en plus de supprimer caractères non-ASCII, non-imprimables et de contrôle , vous devez également re (place/move):
"*/:<>?\|
simplement enlever ces caractères pourrait ne pas être la meilleure idée parce que le nom de fichier pourrait perdre certains de ses sens. Je pense que, à tout le moins, les occurences multiples de ces caractères devraient être remplacées par un simple underscore ( _
), ou peut-être quelque chose de plus représentatif (ce n'est qu'une idée):
-
"*?
->_
-
/\|
->-
-
:
->[ ]-[ ]
-
<
->(
-
>
->)
Il ya aussi mots clés spéciaux qui devraient être évités (comme NUL
), bien que je ne suis pas sûr comment surmonter que. Peut-être qu'une liste noire avec un nom de repli aléatoire serait une bonne approche pour la résoudre.
4. Sensibilité À La Casse
cela devrait aller de soi, mais si vous le souhaitez, assurez-vous que l'unicité des fichiers à travers différents systèmes d'exploitation, vous devez transformer les noms de fichiers à un cas normalisé, de cette façon my_file.txt
et My_File.txt
sur Linux ne deviendra pas à la fois le même fichier my_file.txt
sur Windows.
5. Assurez-vous Qu'il est Unique
si le nom du fichier existe déjà, un" identificateur unique 15191330920 "doit être ajouté au nom du fichier de base.
les identificateurs uniques communs incluent le timestamp UNIX, un condensé du contenu du fichier ou une chaîne de caractères aléatoire.
6. Fichiers Cachés
juste parce qu'il peut être nommé ne signifie pas il le devrait...
les points sont habituellement blancs-listés dans les noms de fichiers mais dans Linux un fichier caché est représenté par un point principal.
7. Autres Considérations
si vous devez supprimer quelques caractères du nom du fichier, l'extension est généralement plus importante que le nom de base du fichier. Permettant un nombre maximum considérable de caractères pour l'extension de fichier (8-16) un doit supprimer les caractères du nom de base. Il est également important de noter que dans le cas peu probable d'avoir plus d'une extension longue - comme _.graphmlz.tag.gz
- _.graphmlz.tag
seulement _
doit être considéré comme le nom de base du fichier dans ce cas.
8. Ressources
Calibre poignées de nom de fichier mangling assez décemment:
page Wikipedia sur le nom de fichier mangling et lié au chapitre de l'Aide de Samba .
si par exemple, vous essayez de créer un fichier qui viole l'une des règles 1/2/3, vous obtiendrez une erreur très utile:
Warning: touch(): Unable to create file ... because No error in ... on line ...
j'ai toujours pensé Kohana a fait un assez bon travail de lui .
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);
}
La pratique UTF8::transliterate_to_ascii()
fera tourner des trucs comme - = > n.
bien sûr, vous pouvez remplacer l'autre UTF8::*
par des fonctions mb_*.
en termes de téléchargement de fichiers, vous seriez plus sûr d'empêcher l'utilisateur de contrôler le nom du fichier. Comme cela a déjà été suggéré, stockez le nom de fichier canonisé dans une base de données avec un nom choisi au hasard et unique que vous utiliserez comme nom de fichier réel.
en utilisant OWASP ESAPI, ces noms pourraient être générés ainsi:
$userFilename = ESAPI::getEncoder()->canonicalize($input_string);
$safeFilename = ESAPI::getRandomizer()->getRandomFilename();
vous pouvez ajouter un timestamp au $safeFilename pour vous assurer que les filename est unique sans même vérifier un fichier existant.
en termes D'encodage pour URL, et encore en utilisant ESAPI:
$safeForURL = ESAPI::getEncoder()->encodeForURL($input_string);
cette méthode effectue la canonisation avant d'encoder la chaîne et gère tous les encodages de caractères.
je me suis adapté à partir d'une autre source et j'ai ajouté un peu plus, peut-être un peu trop
/**
* 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;
}
Et voici Joomla 3.3.2 version de 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));
}
Je ne pense pas qu'avoir une liste de caractères à supprimer soit sûr. Je préférerais utiliser ce qui suit:
pour les noms de fichiers: utilisez un identifiant interne ou un hachage du contenu du fichier. Enregistrez le nom du document dans une base de données. De cette façon, vous pouvez garder le nom de fichier original et trouver toujours le fichier.
pour les paramètres d'url: utiliser urlencode()
pour coder des caractères spéciaux.
Selon la façon dont vous allez l'utiliser, vous pouvez ajouter une limite de longueur pour protéger contre les dépassements de tampon.
voici L'implémentation de 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));
}
Et le remove_invisible_characters
la dépendance.
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;
}
je recommande* URLify pour PHP (480+ étoiles sur Github) - "le PHP port de URLify.js du projet Django. Translittère des caractères non-ascii pour une utilisation dans les Url".
usage de base:
pour générer des slugs pour les URLs:
<?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"
?>
pour générer des limaces pour les noms de fichiers:
<?php
echo URLify::filter ('фото.jpg', 60, "", true);
// "foto.jpg"
?>
* aucune des autres suggestions correspond à mes critères:
- devrait être installable via composer
- ne devrait pas dépendre d'iconv car il se comporte différemment sur des systèmes différents
- devrait être extensible pour permettre des dérogations et des remplacements de caractères personnalisés
- Populaire (par exemple, de nombreuses stars sur Github)
- A des tests
en bonus, URLify supprime également certains les mots et les bandes éloignent tous les caractères non translittérés.
voici un cas d'essai avec des tonnes de caractères étrangers étant translittérés correctement en utilisant URLify: https://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f
c'est une bonne façon de sécuriser un nom de fichier de téléchargement:
$file_name = trim(basename(stripslashes($name)), ".\x00..\x20");
Il existe déjà plusieurs solutions pour cette question mais j'ai lu et testé la plupart du code ici et j'ai fini avec cette solution, qui est un mélange de ce que j'ai appris ici:
la fonction
la fonction est regroupée ici dans un Symfony2 faisceau mais il peut être extrait pour être utilisé comme simple PHP , il a seulement une dépendance avec la iconv
fonction qui doit être activée:
système de fichiers.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 /q/sanitizing-strings-to-make-them-url-and-filename-safe-27405/"/[^ 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;
}
}
les essais unitaires
ce qui est intéressant, c'est que J'ai créé des tests PHPUnit, d'abord pour tester les cas de bordures et donc vous pouvez vérifier si cela correspond à vos besoins: (Si vous trouvez un bug, n'hésitez pas à ajouter un cas de test)
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');
}
}
les résultats des tests: (vérifié sur Ubuntu avec PHP 5.3.2 et MacOsX avec 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)
j'ai des titres d'entrée avec toutes sortes de caractères latins bizarres ainsi que quelques balises HTML que j'ai eu besoin de traduire dans un format utile de nom de fichier délimité par un tiret. J'ai combiné la réponse de @SoLoGHoST avec quelques éléments de la réponse de @Xeoncross et j'ai un peu personnalisé.
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;
}
j'ai dû ajouter manuellement le caractère em dash (-) au tableau de traduction. Il y en a peut-être d'autres, mais jusqu'à présent, les noms de mes fichiers semblent bons.
So:
Partie 1: Les "Žurburts"de mon père?-ils sont (pas) le meilleur!
devient:
partie-1-de-ma-dads-zurburts-theyre-pas-le-meilleur
je viens de l'ajouter ".code html" à la chaîne renvoyée.
Ce post semble fonctionner le mieux parmi tout ce que j'ai lié. http://gsynuh.com/php-string-filename-url-safe/205
C'est une bonne fonction:
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;
}
Solution #1: vous avez la possibilité d'installer des extensions PHP sur le serveur (hébergement)
pour translittération de "presque toutes les langues de la planète Terre" en caractères ASCII.
-
C'est ma fonction fileName (create test.php et coller code suivant):
<!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>
cette ligne est core:
// transliterate
$clean = transliterator_transliterate('Any-Latin;Latin-ASCII;', $clean);
Réponse repose sur ce post .
Solution #2: vous n'avez pas la possibilité d'installer des extensions PHP sur le serveur (hébergement)
assez bon travail est fait dans module de translittération pour CMS Drupal. Il soutient presque chaque langue simple sur la planète Terre. Je suggère de vérifier le plugin de dépôt si vous voulez avoir des chaînes d'assainissement de solution vraiment complète.
c'est le code utilisé par Prestashop pour épurer les urls:
replaceAccentedChars
est utilisé par
str2url
pour supprimer les diacritiques
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;
}
Il ya 2 bonnes réponses à slugfy vos données, utilisez-le https://stackoverflow.com/a/3987966/971619 ou it https://stackoverflow.com/a/7610586/971619
// 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);
}