disinfettante per stringhe per nome file


113

Sto cercando una funzione php che disinfetti una stringa e la renda pronta per l'uso per un nome di file. Qualcuno ne conosce uno pratico?

(Potrei scriverne uno, ma sono preoccupato di trascurare un personaggio!)

Modifica: per salvare i file su un file system Windows NTFS.


1
Puoi essere più specifico: cosa succederà con gli Umlauts (rimuovi o converti in carattere di base?) Cosa succederà con i caratteri speciali?
Pekka

Per quale filesystem? Sono diversi. Vedi en.wikipedia.org/wiki/…
Gordon

Windows :) Occorrono 15 caratteri.
user151841

1
Ci tengo a precisare che le soluzioni "blacklist" suggerite in alcune risposte non sono sufficienti, in quanto non è possibile controllare ogni possibile carattere indesiderato (oltre ai caratteri speciali, ci sono caratteri con accenti e dieresi, interi alfabeti non inglesi / latini, caratteri di controllo, ecc. da trattare). Quindi direi che un approccio "whitelist" è sempre migliore, e normalizzare la stringa (come suggerito dal commento di Blair McMillan sulla risposta di Dominic Rodger) consentirà una gestione naturale di qualsiasi lettera con accenti, dieresi, ecc.
Sean the Bean

Un buon modo forse usando espressioni regolari, guarda questo script python che ho creato: github.com/gsscoder/normalize-fn
gsscoder

Risposte:


42

Invece di preoccuparti di trascurare i personaggi, che ne dici di utilizzare una whitelist di personaggi che sei felice di essere utilizzato? Ad esempio, è possibile consentire solo buon vecchio' a-z, 0-9, _, e una singola istanza di un punto ( .). Questo è ovviamente più limitante della maggior parte dei filesystem, ma dovrebbe tenerti al sicuro.


40
Non va bene per le lingue con dieresi. Ciò si tradurrebbe in Qubec per il Québec, Dsseldorf per Düsseldorf e così via.
Pekka

15
Vero, ma come ho detto: "Ad esempio".
Dominic Rodger

5
Che può essere perfettamente accettabile per l'OP. Altrimenti, usa qualcosa come php.net/manual/en/class.normalizer.php
Blair McMillan

3
In realtà non è ciò che è stato chiesto. L'op richiede una funzione per disinfettare la stringa, non un'alternativa.
i.am.michiel

3
@ i.am.michiel, forse, ma dato che l'OP lo ha accettato, presumo che lo abbiano trovato utile.
Dominic Rodger

157

Fare un piccolo aggiustamento per la soluzione di Tor Valamo per risolvere il problema notato da Dominic Rodger, si potrebbe usare:

// Remove anything which isn't a word, whitespace, number
// or any of the following caracters -_~,;[]().
// If you don't need to handle multi-byte characters
// you can use preg_replace rather than mb_ereg_replace
// Thanks @Łukasz Rysiak!
$file = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $file);
// Remove any runs of periods (thanks falstro!)
$file = mb_ereg_replace("([\.]{2,})", '', $file);

43
Adoro i drogati di regex! -_ ~
AVProgrammer

2
@ iim.hlk - sì, mancava la parentesi di avvolgimento. Li ho aggiunti adesso. Grazie!
Sean Vieira

2
c'è un difetto lì dentro, dovresti dividerlo in due ed eseguire il controllo ..dopo. Ad esempio .?.finirebbe per essere ... Anche se dal momento che filtri /non riesco a vedere come lo sfrutteresti ulteriormente in questo momento, ma mostra perché il controllo ..è inefficace qui. Meglio ancora probabilmente, non sostituire, rifiuta solo se non si qualifica.
falstro

2
Perché nessuno di questi valori è illegale nel file system di Windows e perché perdere più informazioni del necessario? Puoi cambiare l'espressione regolare in semplicemente [^a-z0-9_-]se vuoi essere davvero restrittivo - o semplicemente usare un nome generato e buttare via il nome dato ed evitare tutti questi problemi. :-)
Sean Vieira

3
Nota che: è illegale.
JasonXA

49

In questo modo è possibile disinfettare un file system come richiesto

function filter_filename($name) {
    // remove illegal file system characters https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
    $name = str_replace(array_merge(
        array_map('chr', range(0, 31)),
        array('<', '>', ':', '"', '/', '\\', '|', '?', '*')
    ), '', $name);
    // maximise filename length to 255 bytes http://serverfault.com/a/9548/44086
    $ext = pathinfo($name, PATHINFO_EXTENSION);
    $name= mb_strcut(pathinfo($name, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($name)) . ($ext ? '.' . $ext : '');
    return $name;
}

Tutto il resto è consentito in un filesystem, quindi la domanda ha una risposta perfetta ...

... ma potrebbe essere pericoloso consentire ad esempio virgolette singole 'in un nome di file se lo si utilizza in seguito in un contesto HTML non sicuro perché questo nome di file assolutamente legale:

 ' onerror= 'alert(document.cookie).jpg

diventa un foro XSS :

<img src='<? echo $image ?>' />
// output:
<img src=' ' onerror= 'alert(document.cookie)' />

Per questo motivo, il popolare software CMS Wordpress li rimuove, ma hanno coperto tutti i caratteri rilevanti solo dopo alcuni aggiornamenti :

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

Infine il loro elenco include ora la maggior parte dei caratteri che fanno parte dell'URI rerserved-characters e dell'URL non sicuri .

Ovviamente potresti semplicemente codificare tutti questi caratteri sull'output HTML, ma la maggior parte degli sviluppatori e anche io, segui l'idioma "Meglio prevenire che curare" ed eliminarli in anticipo.

Quindi alla fine suggerirei di usare questo:

function filter_filename($filename, $beautify=true) {
    // sanitize filename
    $filename = preg_replace(
        '~
        [<>:"/\\|?*]|            # file system reserved https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
        [\x00-\x1F]|             # control characters http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
        [\x7F\xA0\xAD]|          # non-printing characters DEL, NO-BREAK SPACE, SOFT HYPHEN
        [#\[\]@!$&\'()+,;=]|     # URI reserved https://tools.ietf.org/html/rfc3986#section-2.2
        [{}^\~`]                 # URL unsafe characters https://www.ietf.org/rfc/rfc1738.txt
        ~x',
        '-', $filename);
    // avoids ".", ".." or ".hiddenFiles"
    $filename = ltrim($filename, '.-');
    // optional beautification
    if ($beautify) $filename = beautify_filename($filename);
    // maximize filename length to 255 bytes http://serverfault.com/a/9548/44086
    $ext = pathinfo($filename, PATHINFO_EXTENSION);
    $filename = mb_strcut(pathinfo($filename, PATHINFO_FILENAME), 0, 255 - ($ext ? strlen($ext) + 1 : 0), mb_detect_encoding($filename)) . ($ext ? '.' . $ext : '');
    return $filename;
}

Tutto il resto che non causa problemi con il file system dovrebbe far parte di una funzione aggiuntiva:

function beautify_filename($filename) {
    // reduce consecutive characters
    $filename = preg_replace(array(
        // "file   name.zip" becomes "file-name.zip"
        '/ +/',
        // "file___name.zip" becomes "file-name.zip"
        '/_+/',
        // "file---name.zip" becomes "file-name.zip"
        '/-+/'
    ), '-', $filename);
    $filename = preg_replace(array(
        // "file--.--.-.--name.zip" becomes "file.name.zip"
        '/-*\.-*/',
        // "file...name..zip" becomes "file.name.zip"
        '/\.{2,}/'
    ), '.', $filename);
    // lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625
    $filename = mb_strtolower($filename, mb_detect_encoding($filename));
    // ".file-name.-" becomes "file-name"
    $filename = trim($filename, '.-');
    return $filename;
}

A questo punto è necessario generare un nome file se il risultato è vuoto e si può decidere se si desidera codificare i caratteri UTF-8. Ma non è necessario poiché UTF-8 è consentito in tutti i file system utilizzati nei contesti di hosting web.

L'unica cosa che devi fare è usare urlencode()(come si spera tu faccia con tutti i tuoi URL) in modo che il nome del file საბეჭდი_მანქანა.jpgdiventi questo URL come tuo <img src>o <a href>: http://www.maxrev.de/html/img/%E1%83% A1% E1% 83% 90% E1% 83% 91% E1% 83% 94% E1% 83% AD% E1% 83% 93% E1% 83% 98_% E1% 83% 9B% E1% 83% 90% E1% 83% 9C% E1% 83% A5% E1% 83% 90% E1% 83% 9C% E1% 83% 90.jpg

Stackoverflow lo fa, quindi posso pubblicare questo link come farebbe un utente:
http://www.maxrev.de/html/img/ საბეჭდი_მანქანა. Jpg

Quindi questo è un nome di file legale completo e non un problema come @ SequenceDigitale.com ha menzionato nella sua risposta .


3
Buon lavoro. La risposta più utile per me. +1

Oh ... La funzione funziona bene, ma da un po 'di tempo ha iniziato a mettere - tra ogni personaggio, mi piace r-u-l-e-se non ho idea del perché questo accada. Certo è che non è colpa della funzione, ma solo chiedere: quale potrebbe essere la ragione di tale comportamento? Codifica sbagliata?

1
Oh beh ... Ho appena fatto un debug e succede subito dopo l' preg_replacein filter_filename().

Dopo aver rimosso questi commenti, ha ripreso a funzionare.

Quali commenti hai rimosso? Mandami una mail se è più facile: gutt.it/contact.htm
mgutt

43

Che ne dici di usare rawurlencode ()? http://www.php.net/manual/en/function.rawurlencode.php

Ecco una funzione che disinfetta anche i caratteri cinesi:

public static function normalizeString ($str = '')
{
    $str = strip_tags($str); 
    $str = preg_replace('/[\r\n\t ]+/', ' ', $str);
    $str = preg_replace('/[\"\*\/\:\<\>\?\'\|]+/', ' ', $str);
    $str = strtolower($str);
    $str = html_entity_decode( $str, ENT_QUOTES, "utf-8" );
    $str = htmlentities($str, ENT_QUOTES, "utf-8");
    $str = preg_replace("/(&)([a-z])([a-z]+;)/i", '$2', $str);
    $str = str_replace(' ', '-', $str);
    $str = rawurlencode($str);
    $str = str_replace('%', '-', $str);
    return $str;
}

Ecco la spiegazione

  1. Rimuovi tag HTML
  2. Rimuovi interruzione / tabulazioni / ritorno a capo
  3. Rimuovi caratteri illegali per cartella e nome file
  4. Metti la stringa in minuscolo
  5. Rimuovi gli accenti stranieri come Éàû convertendolo in entità html, quindi rimuovi il codice e mantieni la lettera.
  6. Sostituisci gli spazi con i trattini
  7. Codifica caratteri speciali che potrebbero superare i passaggi precedenti e inserisci il nome del file in conflitto sul server. ex. "中文 百强 网"
  8. Sostituisci "%" con trattini per assicurarti che il collegamento del file non venga riscritto dal browser durante la query del file.

OK, alcuni nomi di file non saranno rilevanti ma nella maggior parte dei casi funzioneranno.

ex. Nome originale: "საბეჭდი-და-ტიპოგრაფიული. Jpg"

Nome uscita: "-E1-83-A1-E1-83-90-E1-83-91-E1-83-94-E1-83-AD-E1-83-93-E1-83-98 - E1- 83-93-E1-83-90 - E1-83-A2-E1-83-98-E1-83-9E-E1-83-9D-E1-83-92-E1-83-A0-E1-83 -90-E1-83-A4-E1-83-98-E1-83-A3-E1-83-9A-E1-83-98.jpg"

È meglio così che un errore 404.

Spero che sia stato utile.

Carl.


1
Non stai rimuovendo i caratteri NULL e Control. Gli ASCII compresi tra 0 e 32 dovrebbero essere tutti rimossi dalla stringa.
Basil Musa

UTF-8 è consentito nel file system ed è consentito negli URL, quindi perché dovrebbe produrre un errore 404? L'unica cosa che devi fare è quello di codificare l'URL http://www.maxrev.de/html/img/საბეჭდი_მანქანა.jpgper http://www.maxrev.de/html/img/%E1%83%A1%E1%83%90%E1%83%91%E1%83%94%E1%83%AD%E1%83%93%E1%83%98_%E1%83%9B%E1%83%90%E1%83%9C%E1%83%A5%E1%83%90%E1%83%9C%E1%83%90.jpgil codice sorgente HTML, come si spera di fare con tutti i tuoi URL.
mgutt

1
Alcuni altri punti: rimuovi i tag HTML strip_tags()e poi rimuovi [<>]. Con questo strip_tags()non è affatto necessario. Lo stesso punto sono le virgolette. Non ci sono virgolette quando decodifichi con ENT_QUOTES. E il str_replace()non rimuove gli spazi bianchi consecutivi e quindi si utilizza strtolower()per la stringa a più byte. E perché converti in minuscolo? E alla fine non hai catturato nessun personaggio riservato come menzionato da @BasilMusa. Maggiori dettagli nella mia risposta: stackoverflow.com/a/42058764/318765
mgutt

me ne sono innamorato!
Yash Kumar Verma

39

SOLUZIONE 1 - semplice ed efficace

$file_name = preg_replace( '/[^a-z0-9]+/', '-', strtolower( $url ) );

  • strtolower () garantisce che il nome del file sia minuscolo (poiché le maiuscole non hanno importanza all'interno dell'URL, ma nel nome del file NTFS)
  • [^a-z0-9]+ assicurerà, il nome del file conserva solo lettere e numeri
  • Sostituisci caratteri non validi con '-'mantiene leggibile il nome del file

Esempio:

URL:  http://stackoverflow.com/questions/2021624/string-sanitizer-for-filename
File: http-stackoverflow-com-questions-2021624-string-sanitizer-for-filename

SOLUZIONE 2 - per URL molto lunghi

Vuoi memorizzare nella cache il contenuto dell'URL e devi solo avere nomi di file univoci. Userei questa funzione:

$file_name = md5( strtolower( $url ) )

questo creerà un nome file con lunghezza fissa. L'hash MD5 è nella maggior parte dei casi abbastanza unico per questo tipo di utilizzo.

Esempio:

URL:  https://www.amazon.com/Interstellar-Matthew-McConaughey/dp/B00TU9UFTS/ref=s9_nwrsa_gw_g318_i10_r?_encoding=UTF8&fpl=fresh&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=desktop-1&pf_rd_r=BS5M1H560SMAR2JDKYX3&pf_rd_r=BS5M1H560SMAR2JDKYX3&pf_rd_t=36701&pf_rd_p=6822bacc-d4f0-466d-83a8-2c5e1d703f8e&pf_rd_p=6822bacc-d4f0-466d-83a8-2c5e1d703f8e&pf_rd_i=desktop
File: 51301f3edb513f6543779c3a5433b01c

4
Forse MD5 potrebbe essere un problema: fai attenzione quando usi hash con URL. Anche se la radice quadrata del numero skrenta.com/2007/08/md5_tutorial.html degli URL è ancora molto più grande delle dimensioni attuali del web, se si verifica una collisione, si otterranno pagine su Britney Spears quando ti aspettavi pagine su Bugzilla. Probabilmente non è un problema nel nostro caso, ma per miliardi di pagine opterei per un algoritmo di hashing molto più grande come SHA 256 o lo eviterei del tutto. Fonte: boyter.org/2013/01/code-for-a-search-engine-in-php-part-1
adilbo

15

Bene, tempnam () lo farà per te.

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

ma questo crea un nome completamente nuovo.

Per disinfettare una stringa esistente, limita ciò che i tuoi utenti possono inserire e rendila lettere, numeri, punto, trattino e trattino basso, quindi disinfetta con una semplice regex. Controlla di quali caratteri è necessario eseguire l'escape o potresti ottenere falsi positivi.

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

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

Aggiungi / rimuovi più caratteri validi a seconda di ciò che è consentito per il tuo sistema.

In alternativa puoi provare a creare il file e poi restituire un errore se non va bene.


5
Ciò consentirebbe attraverso nomi di file come .., che potrebbe o meno essere un problema.
Dominic Rodger

@ Dom - controlla solo separatamente, poiché è un valore fisso.
Tor Valamo

10

PHP fornisce una funzione per disinfettare un testo in un formato diverso

filter.filters.sanitize

Come :

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

blockquote LoremIpsumhasbeentheindustry's


1
Bene, ma non rimuoverebbe le barre, il che potrebbe essere un problema: l'attraversamento della directory.
func0der

7

sicuro: sostituire ogni sequenza di NOT "a-zA-Z0-9_-" con un trattino; aggiungi tu stesso un'estensione.

$name = preg_replace('/[^a-zA-Z0-9_-]+/', '-', strtolower($name)).'.'.$extension;

1
Devi aggiungere l'estensione del file separata da ".": $ Name = preg_replace ('/ [^ a-zA-Z0-9 _-] + /', '-', strtolower ($ name)). '.' . $ estensione;
Smith

6

La seguente espressione crea una stringa piacevole, pulita e utilizzabile:

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

Trasformare la finanziaria di oggi: la fatturazione nella fatturazione -finanziaria di oggi


quindi un nome di file non può avere un punto o un trattino basso o qualcosa del genere?
Tor Valamo

2
@ Jonathan - cosa sono i corsivi?
Dominic Rodger,

@ Tor, sì, mi dispiace. Aggiornato. @ Dominic, sto solo mettendo l'accento sul testo.
Sampson

Cos'è il gism? Ottengo "Avviso: preg_replace () [function.preg-replace]: Modificatore sconosciuto 'g'"
user151841

1
@ user151841 Per preg_replaceil flag globale è implicito. Quindi non è necessario utilizzare g se si utilizza preg_replace. Quando vogliamo controllare il numero di sostituzioni, preg_replace ha un limitparametro per questo. Leggi la documentazione preg_replace per ulteriori informazioni.
Rineez

6

Effettuando una piccola modifica alla soluzione di Sean Vieira per consentire singoli punti, è possibile utilizzare:

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

2

Questi possono essere un po 'pesanti, ma sono abbastanza flessibili da disinfettare qualsiasi stringa in un ennome di file o di cartella di stile "sicuro" (o diamine, anche di lumache e cose simili se lo pieghi).

1) Creazione di un nome file completo (con nome di fallback nel caso in cui l'input sia totalmente troncato):

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

2) O utilizzando solo il filtro util senza creare un nome file completo (la modalità rigorosa truenon consentirà [] o () nel nome file):

str_file_filter($string, $separator, $strict, $length);

3) Ed ecco quelle funzioni:

// Returns filesystem-safe string after cleaning, filtering, and trimming input
function str_file_filter(
    $str,
    $sep = '_',
    $strict = false,
    $trim = 248) {

    $str = strip_tags(htmlspecialchars_decode(strtolower($str))); // lowercase -> decode -> strip tags
    $str = str_replace("%20", ' ', $str); // convert rogue %20s into spaces
    $str = preg_replace("/%[a-z0-9]{1,2}/i", '', $str); // remove hexy things
    $str = str_replace("&nbsp;", ' ', $str); // convert all nbsp into space
    $str = preg_replace("/&#?[a-z0-9]{2,8};/i", '', $str); // remove the other non-tag things
    $str = preg_replace("/\s+/", $sep, $str); // filter multiple spaces
    $str = preg_replace("/\.+/", '.', $str); // filter multiple periods
    $str = preg_replace("/^\.+/", '', $str); // trim leading period

    if ($strict) {
        $str = preg_replace("/([^\w\d\\" . $sep . ".])/", '', $str); // only allow words and digits
    } else {
        $str = preg_replace("/([^\w\d\\" . $sep . "\[\]\(\).])/", '', $str); // allow words, digits, [], and ()
    }

    $str = preg_replace("/\\" . $sep . "+/", $sep, $str); // filter multiple separators
    $str = substr($str, 0, $trim); // trim filename to desired length, note 255 char limit on windows

    return $str;
}


// Returns full file name including fallback and extension
function str_file(
    $str,
    $sep = '_',
    $ext = '',
    $default = '',
    $trim = 248) {

    // Run $str and/or $ext through filters to clean up strings
    $str = str_file_filter($str, $sep);
    $ext = '.' . str_file_filter($ext, '', true);

    // Default file name in case all chars are trimmed from $str, then ensure there is an id at tail
    if (empty($str) && empty($default)) {
        $str = 'no_name__' . date('Y-m-d_H-m_A') . '__' . uniqid();
    } elseif (empty($str)) {
        $str = $default;
    }

    // Return completed string
    if (!empty($ext)) {
        return $str . $ext;
    } else {
        return $str;
    }
}

Quindi diciamo che l'input dell'utente è: .....&lt;div&gt;&lt;/div&gt;<script></script>&amp; Weiß Göbel 中文百强网File name %20 %20 %21 %2C Décor \/. /. . z \... y \...... x ./ “This name” is & 462^^ not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული

E vogliamo convertirlo in qualcosa di più amichevole per creare un tar.gz con una lunghezza del nome file di 255 caratteri. Ecco un esempio di utilizzo. Nota: questo esempio include un'estensione tar.gz non valida come prova del concetto, dovresti comunque filtrare l'ext dopo che la stringa è stata compilata rispetto alle tue whitelist.

$raw_str = '.....&lt;div&gt;&lt;/div&gt;<script></script>&amp; Weiß Göbel 中文百强网File name  %20   %20 %21 %2C Décor  \/.  /. .  z \... y \...... x ./  “This name” is & 462^^ not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = that grrrreat -][09]()1234747) საბეჭდი-და-ტიპოგრაფიული';
$fallback_str = 'generated_' . date('Y-m-d_H-m_A');
$bad_extension = '....t&+++a()r.gz[]';

echo str_file($raw_str, '_', $bad_extension, $fallback_str);

L'output sarebbe: _wei_gbel_file_name_dcor_._._._z_._y_._x_._this_name_is_462_not_that_grrrreat_][09]()1234747)_.tar.gz

Puoi giocarci qui: https://3v4l.org/iSgi8

O un Gist: https://gist.github.com/dhaupin/b109d3a8464239b7754a

EDIT: filtro script aggiornato per &nbsp;invece di spazio, collegamento 3v4l aggiornato


1

Il meglio che conosco oggi è il metodo statico Strings :: webalize dal framework Nette.

A proposito, questo traduce tutti i segni diacritici nella loro base .. š => s ü => u ß => ss ecc.

Per i nomi dei file devi aggiungere il punto "." al parametro dei caratteri consentiti.

/**
 * Converts to ASCII.
 * @param  string  UTF-8 encoding
 * @return string  ASCII
 */
public static function toAscii($s)
{
    static $transliterator = NULL;
    if ($transliterator === NULL && class_exists('Transliterator', FALSE)) {
        $transliterator = \Transliterator::create('Any-Latin; Latin-ASCII');
    }

    $s = preg_replace('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{2FF}\x{370}-\x{10FFFF}]#u', '', $s);
    $s = strtr($s, '`\'"^~?', "\x01\x02\x03\x04\x05\x06");
    $s = str_replace(
        array("\xE2\x80\x9E", "\xE2\x80\x9C", "\xE2\x80\x9D", "\xE2\x80\x9A", "\xE2\x80\x98", "\xE2\x80\x99", "\xC2\xB0"),
        array("\x03", "\x03", "\x03", "\x02", "\x02", "\x02", "\x04"), $s
    );
    if ($transliterator !== NULL) {
        $s = $transliterator->transliterate($s);
    }
    if (ICONV_IMPL === 'glibc') {
        $s = str_replace(
            array("\xC2\xBB", "\xC2\xAB", "\xE2\x80\xA6", "\xE2\x84\xA2", "\xC2\xA9", "\xC2\xAE"),
            array('>>', '<<', '...', 'TM', '(c)', '(R)'), $s
        );
        $s = @iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s); // intentionally @
        $s = strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e"
            . "\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3"
            . "\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
            . "\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe"
            . "\x96\xa0\x8b\x97\x9b\xa6\xad\xb7",
            'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.');
        $s = preg_replace('#[^\x00-\x7F]++#', '', $s);
    } else {
        $s = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); // intentionally @
    }
    $s = str_replace(array('`', "'", '"', '^', '~', '?'), '', $s);
    return strtr($s, "\x01\x02\x03\x04\x05\x06", '`\'"^~?');
}


/**
 * Converts to web safe characters [a-z0-9-] text.
 * @param  string  UTF-8 encoding
 * @param  string  allowed characters
 * @param  bool
 * @return string
 */
public static function webalize($s, $charlist = NULL, $lower = TRUE)
{
    $s = self::toAscii($s);
    if ($lower) {
        $s = strtolower($s);
    }
    $s = preg_replace('#[^a-z0-9' . preg_quote($charlist, '#') . ']+#i', '-', $s);
    $s = trim($s, '-');
    return $s;
}

Perché vuoi sostituire i segni diacritici? Usalo semplicemente urlencode()prima di usare il nome del file come srco href. L'unico file system attualmente utilizzato che ha problemi con UTF-8 è FATx (usato da XBOX): en.wikipedia.org/wiki/Comparison_of_file_systems#Limits E non penso che questo sia usato dai server web
mgutt

1

Sembra che tutto questo dipenda dalla domanda, è possibile creare un nome di file che può essere utilizzato per hackerare un server (o fare qualche altro danno). In caso contrario, sembra che la risposta semplice sia provare a creare il file ovunque verrà, in definitiva, utilizzato (poiché quello sarà il sistema operativo di scelta, senza dubbio). Lascia che sia il sistema operativo a risolverlo. In caso di reclamo, riportalo all'utente come errore di convalida.

Questo ha l'ulteriore vantaggio di essere portabile in modo affidabile, poiché tutti (sono abbastanza sicuro) i sistemi operativi si lamenteranno se il nome del file non è formato correttamente per quel sistema operativo.

Se è possibile fare cose nefaste con un nome di file, forse ci sono misure che possono essere applicate prima di testare il nome di file sul sistema operativo residente - misure meno complicate di una completa "pulizia" del nome di file.


0

senso unico

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

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

}
echo sanitize($string,$bad);

E i caratteri non stampabili? In questo caso è meglio utilizzare l'approccio della lista bianca piuttosto che l'approccio della lista nera. Fondamentalmente consentire solo i nomi di file ASCII stampabili escluse le lettere speciali ovviamente. Ma per le lingue non inglesi, questo è un altro problema.
TheRealChx101

0

/e ..nel nome file fornito dall'utente può essere dannoso. Quindi dovresti sbarazzartene con qualcosa del tipo:

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

Questo è insufficiente! Ad esempio, il nome del file "./.name" uscirà ancora dalla directory corrente. (La rimozione .. non fa nulla qui, ma la rimozione di / trasformerà il ./. In .. e quindi uscirà dalla directory di destinazione.)
cemper93

3
@ cemper93 No, questa risposta trasformerà solo la stringa in ..namecui non si spezzerebbe nulla. La rimozione di tutti i caratteri separatori di percorso dovrebbe essere sufficiente per impedire qualsiasi attraversamento di directory. (La rimozione di non ..è tecnicamente necessaria.)
cdhowie

@cdhowie Sì, ma il nome del file ./.diventa ... E infine questa risposta manca di tutti gli altri caratteri riservati del file system come NULL. Più nella mia risposta: stackoverflow.com/a/42058764/318765
mgutt

-4

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

Poiché gli utenti potrebbero utilizzare la barra per separare due parole, sarebbe meglio sostituirla con un trattino invece di NULL


Dove si dice che avrebbe sostituito con NULL? Inoltre, questo non gestisce tutti i caratteri speciali.
Travis Pessetto

Sì, ci sono anche altri caratteri speciali che devono essere gestiti. str_replace non sarà comunque la migliore offerta qui.
Martin Kovachev
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.