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

128
demandé sur Lightness Races in Orbit 2010-04-19 19:51:44

23 réponses

quelques observations sur votre solution:

  1. ' 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?).
  2. \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.
  3. 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

56
répondu Alan Donnelly 2015-11-10 17:43:33

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.

85
répondu Xeoncross 2017-05-23 12:10:12

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.

29
répondu SoLoGHoST 2014-08-13 03:25:51

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?

21
répondu John Conde 2017-05-23 12:17:25

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.

Les fichiers

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 ...
13
répondu Alix Axel 2012-10-11 19:15:42

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

11
répondu alex 2011-09-14 01:18:50

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.

5
répondu jah 2010-04-25 20:47:26

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;
}
5
répondu John Magnolia 2016-10-13 13:14:15

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));
}
5
répondu cedric.walter 2017-03-12 13:45:48

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.

4
répondu ZeissS 2011-10-23 00:56:12

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.

3
répondu Tgr 2010-04-25 19:59:37

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;
}
3
répondu Kevin Mark 2012-11-05 03:41:01

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

3
répondu Motin 2016-07-18 09:30:15

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");
2
répondu games 2012-09-30 00:29:53

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)
2
répondu COil 2012-12-08 12:49:27

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.

2
répondu cbmtrx 2015-12-08 19:02:51

pourquoi ne pas simplement utiliser php urlencode ? il remplace les caractères " dangereux "par leur représentation hexadécimale pour les urls (i.e. %20 pour un espace)

1
répondu knittl 2010-04-27 17:05:42

Ce post semble fonctionner le mieux parmi tout ce que j'ai lié. http://gsynuh.com/php-string-filename-url-safe/205

1
répondu ktamlyn 2012-12-20 02:49:32

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;
} 
1
répondu joan16v 2015-01-15 08:16:48

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.

  1. Installer PHP Intl "1519110920 l'extension de la première. C'est la commande pour Debian (Ubuntu): sudo aptitude install php5-intl

  2. 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)

enter image description here

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.

1
répondu Jasom Dotnet 2015-12-15 14:15:16

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;
}
0
répondu Armel Larcier 2013-06-19 08:36:46

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

0
répondu newway 2017-05-23 11:46:21
// 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);

} 
-4
répondu Brant Messenger 2010-04-19 16:04:08