String-Desinfektionsmittel für Dateinamen

113

Ich suche nach einer PHP-Funktion, die einen String bereinigt und für einen Dateinamen einsatzbereit macht. Kennt jemand einen handlichen?

(Ich könnte einen schreiben, aber ich mache mir Sorgen, dass ich einen Charakter übersehen werde!)

Bearbeiten: Zum Speichern von Dateien in einem Windows NTFS-Dateisystem.

user151841
quelle
1
Können Sie genauer sein: Was soll mit Umlauten geschehen (entfernen oder in Basiszeichen konvertieren?) Was soll mit Sonderzeichen geschehen?
Pekka
Für welches Dateisystem? Sie unterscheiden sich. Siehe en.wikipedia.org/wiki/…
Gordon
Windows :) Benötige 15 Zeichen.
user151841
1
Ich möchte darauf hinweisen, dass die in einigen Antworten vorgeschlagenen "Blacklist" -Lösungen nicht ausreichen, da es unmöglich ist, nach allen möglichen unerwünschten Zeichen zu suchen (zusätzlich zu Sonderzeichen gibt es Zeichen mit Akzenten und Umlauten als Ganzes Nicht-Englisch / Latein-Alphabete, Steuerzeichen usw. zu behandeln). Daher würde ich argumentieren, dass ein "Whitelist" -Ansatz immer besser ist und die Normalisierung der Zeichenfolge (wie in Blair McMillans Kommentar zu Dominic Rodgers Antwort vorgeschlagen) den natürlichen Umgang mit Buchstaben mit Akzenten, Umlauten usw. ermöglicht
Sean the Bean
Ein guter Weg, vielleicht reguläre Ausdrücke zu verwenden, finden Sie in diesem Python-Skript, das ich erstellt habe: github.com/gsscoder/normalize-fn
gsscoder

Antworten:

41

Anstatt sich Gedanken über das Übersehen von Zeichen zu machen - wie wäre es mit einer Whitelist von Zeichen, die Sie gerne verwenden? Zum Beispiel könnten Sie einfach gute alte erlauben a-z, 0-9, _, und eine einzelne Instanz einer Periode ( .). Das ist natürlich einschränkender als die meisten Dateisysteme, sollte Sie aber schützen.

Dominic Rodger
quelle
40
Nicht gut für Sprachen mit Umlauten. Dies würde zu Qubec für Québec, Dsseldorf für Düsseldorf usw. führen.
Pekka
15
Richtig - aber wie gesagt: "Zum Beispiel".
Dominic Rodger
5
Was für das OP durchaus akzeptabel sein kann. Verwenden Sie andernfalls etwas wie php.net/manual/en/class.normalizer.php
Blair McMillan
3
Das wurde eigentlich nicht gefragt. Die Operation fordert eine Funktion zum Bereinigen von Zeichenfolgen an, keine Alternative.
i.am.michiel
3
@ i.am.michiel vielleicht, aber da das OP es akzeptiert hat, gehe ich davon aus, dass sie es hilfreich fanden.
Dominic Rodger
157

Wenn Sie die Lösung von Tor Valamo geringfügig anpassen, um das von Dominic Rodger festgestellte Problem zu beheben, können Sie Folgendes verwenden:

// 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);
Sean Vieira
quelle
43
Ich liebe Regex-Junkies! -_ ~
AVProgrammer
2
@ iim.hlk - yep, es fehlte die einschließende Klammer. Ich habe diese jetzt hinzugefügt. Vielen Dank!
Sean Vieira
2
Da ist ein Fehler drin, du solltest ihn in zwei Teile teilen und ..danach die Prüfung durchführen . Zum Beispiel .?.würde am Ende sein ... Da Sie filtern, /kann ich zwar nicht sehen, wie Sie das jetzt weiter ausnutzen würden, aber es zeigt, warum die Überprüfung ..hier unwirksam ist. Besser noch wahrscheinlich nicht ersetzen, nur ablehnen, wenn es nicht qualifiziert ist.
Falstro
2
Weil keiner dieser Werte im Windows-Dateisystem unzulässig ist und warum mehr Informationen verloren gehen, als Sie müssen? Sie können den regulären Ausdruck in einfach ändern, [^a-z0-9_-]wenn Sie wirklich restriktiv sein möchten - oder einfach einen generierten Namen verwenden und den angegebenen Namen wegwerfen und all diese Probleme vermeiden . :-)
Sean Vieira
3
Beachten Sie, dass: illegal ist.
JasonXA
49

Auf diese Weise können Sie nach Bedarf ein Dateisystem bereinigen

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;
}

Alles andere ist in einem Dateisystem erlaubt, daher ist die Frage perfekt beantwortet ...

... aber es könnte gefährlich sein, beispielsweise einfache Anführungszeichen 'in einem Dateinamen zuzulassen, wenn Sie ihn später in einem unsicheren HTML-Kontext verwenden, da dieser absolut legale Dateiname:

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

wird ein XSS-Loch :

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

Aus diesem Grund entfernt die beliebte CMS-Software Wordpress sie, deckte jedoch erst nach einigen Updates alle relevanten Zeichen ab :

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

Schließlich enthält ihre Liste jetzt die meisten Zeichen, die Teil der Liste der URI-reservierten Zeichen und der URL-unsicheren Zeichen sind .

Natürlich können Sie all diese Zeichen einfach in der HTML-Ausgabe codieren, aber die meisten Entwickler und auch ich folgen der Redewendung "Besser sicher als leid" und löschen sie im Voraus.

Schließlich würde ich vorschlagen, dies zu verwenden:

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;
}

Alles andere, was keine Probleme mit dem Dateisystem verursacht, sollte Teil einer zusätzlichen Funktion sein:

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;
}

Zu diesem Zeitpunkt müssen Sie einen Dateinamen generieren, wenn das Ergebnis leer ist, und Sie können entscheiden, ob Sie UTF-8-Zeichen codieren möchten. Dies ist jedoch nicht erforderlich, da UTF-8 in allen Dateisystemen zulässig ist, die in Webhosting-Kontexten verwendet werden.

Das einzige, was Sie tun müssen, ist zu verwenden urlencode()(wie Sie es hoffentlich mit all Ihren URLs tun), damit der Dateiname საბეჭდი_მანქანა.jpgzu Ihrer URL wird <img src>oder <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 macht das, also kann ich diesen Link so posten, wie es ein Benutzer tun würde:
http://www.maxrev.de/html/img/ საბეჭდი_მანქანა. Jpg

Dies ist also ein vollständiger legaler Dateiname und kein Problem, wie @ SequenceDigitale.com in seiner Antwort erwähnt .

mgutt
quelle
3
Gut gemacht. Die hilfreichste Antwort für mich. +1
Oh ... Die Funktion funktioniert gut, aber seit einiger Zeit beginnt sie zu setzen - zwischen jedem Charakter, wie r-u-l-e-sund ich habe keine Ahnung, warum dies passiert. Sicher ist, dass es nicht an der Funktion liegt, sondern nur zu fragen - was könnte der Grund für ein solches Verhalten sein? Falsche Kodierung?
1
Na ja ... Habe gerade ein Debug gemacht und es passiert kurz nach dem preg_replaceIn filter_filename().
Nachdem diese Kommentare entfernt wurden, funktionierte es wieder.
Welche Kommentare haben Sie entfernt? Senden Sie mir eine E-Mail, wenn dies einfacher ist: gutt.it/contact.htm
mgutt
43

Was ist mit rawurlencode ()? http://www.php.net/manual/en/function.rawurlencode.php

Hier ist eine Funktion, die sogar chinesische Zeichen bereinigt:

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;
}

Hier ist die Erklärung

  1. HTML-Tags entfernen
  2. Entfernen Sie Break / Tabs / Return Carriage
  3. Entfernen Sie unzulässige Zeichen für Ordner und Dateinamen
  4. Setzen Sie die Zeichenfolge in Kleinbuchstaben
  5. Entfernen Sie ausländische Akzente wie Éàû, indem Sie sie in HTML-Entitäten konvertieren. Entfernen Sie dann den Code und behalten Sie den Buchstaben.
  6. Ersetzen Sie Leerzeichen durch Bindestriche
  7. Codieren Sie spezielle Zeichen, die die vorherigen Schritte bestehen könnten, und geben Sie den Konfliktdateinamen auf dem Server ein. Ex. "中文 百强 网"
  8. Ersetzen Sie "%" durch Bindestriche, um sicherzustellen, dass der Link der Datei beim Abfragen der Datei nicht vom Browser neu geschrieben wird.

OK, einige Dateinamen sind nicht relevant, aber in den meisten Fällen funktionieren sie.

Ex. Ursprünglicher Name: "საბეჭდი-და-ტიპოგრაფიული. Jpg"

Ausgabename: "-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

Es ist besser so als ein 404-Fehler.

Hoffe das war hilfreich.

Carl.

SequenceDigitale.com
quelle
1
Sie entfernen keine NULL- und Steuerzeichen. ASCII von 0 bis 32 sollten alle aus der Zeichenfolge entfernt werden.
Basil Musa
UTF-8 ist im Dateisystem und in URLs zulässig. Warum sollte also ein 404-Fehler auftreten? Das einzige , was Sie tun müssen, ist es, die URL zu kodieren , http://www.maxrev.de/html/img/საბეჭდი_მანქანა.jpgum 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.jpgin dem HTML - Quellcode , wie Sie hoffentlich mit allen URLs tun.
mgutt
1
Einige andere Punkte: Sie entfernen HTML-Tags durch strip_tags()und danach entfernen Sie [<>]. Das strip_tags()wird überhaupt nicht wirklich gebraucht. Der gleiche Punkt sind die Anführungszeichen. Beim Dekodieren mit sind keine Anführungszeichen mehr vorhanden ENT_QUOTES. Und das entfernt str_replace()keine aufeinanderfolgenden Leerzeichen und dann verwenden Sie strtolower()für Multibyte-Zeichenfolge. Und warum konvertieren Sie überhaupt in Kleinbuchstaben? Und schließlich hast du keinen reservierten Charakter gefangen, wie @BasilMusa erwähnt hat. Weitere Details in meiner Antwort: stackoverflow.com/a/42058764/318765
mgutt
verliebte sich in es!
Yash Kumar Verma
38

LÖSUNG 1 - einfach und effektiv

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

  • strtolower () garantiert, dass der Dateiname in Kleinbuchstaben geschrieben ist (da die Groß- und Kleinschreibung in der URL, aber im NTFS-Dateinamen keine Rolle spielt).
  • [^a-z0-9]+ wird sicherstellen, dass der Dateiname nur Buchstaben und Zahlen enthält
  • Ersetzen Sie ungültige Zeichen durch, damit '-'der Dateiname lesbar bleibt

Beispiel:

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

LÖSUNG 2 - für sehr lange URLs

Sie möchten den URL-Inhalt zwischenspeichern und benötigen nur eindeutige Dateinamen. Ich würde diese Funktion verwenden:

$file_name = md5( strtolower( $url ) )

Dadurch wird ein Dateiname mit fester Länge erstellt. Der MD5-Hash ist in den meisten Fällen einzigartig genug für diese Art der Verwendung.

Beispiel:

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
Philipp
quelle
4
Möglicherweise könnte MD5 ein Problem haben: Seien Sie vorsichtig, wenn Sie Hashes mit URLs verwenden. Während die Quadratwurzel der Zahl skrenta.com/2007/08/md5_tutorial.html von URLs immer noch viel größer ist als die aktuelle Webgröße, werden Sie bei einer Kollision Seiten über Britney Spears erhalten, wenn Sie Seiten erwartet haben über Bugzilla. In unserem Fall ist dies wahrscheinlich kein Problem, aber für Milliarden von Seiten würde ich mich für einen viel größeren Hashing-Algorithmus wie SHA 256 entscheiden oder ihn ganz vermeiden. Quelle: boyter.org/2013/01/code-for-a-search-engine-in-php-part-1
adilbo
15

Nun, tempnam () wird es für Sie tun.

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

aber das schafft einen völlig neuen Namen.

Um eine vorhandene Zeichenfolge zu bereinigen, beschränken Sie einfach die Eingabe durch Ihre Benutzer und geben Sie Buchstaben, Zahlen, Punkte, Bindestriche und Unterstriche ein. Bereinigen Sie sie dann mit einem einfachen regulären Ausdruck. Überprüfen Sie, welche Zeichen maskiert werden müssen, da sonst Fehlalarme auftreten können.

$sanitized = preg_replace('/[^a-zA-Z0-9\-\._]/','', $filename);
Mark Moline
quelle
13
preg_replace("[^\w\s\d\.\-_~,;:\[\]\(\]]", '', $file)

Fügen Sie weitere gültige Zeichen hinzu oder entfernen Sie sie, je nachdem, was für Ihr System zulässig ist.

Alternativ können Sie versuchen, die Datei zu erstellen und dann einen Fehler zurückgeben, wenn er fehlerhaft ist.

Tor Valamo
quelle
5
Das würde durch Dateinamen wie erlauben .., was ein Problem sein kann oder nicht.
Dominic Rodger
@ Dom - prüfen Sie dies einfach separat, da es sich um einen festen Wert handelt.
Tor Valamo
10

PHP bietet eine Funktion zum Bereinigen eines Textes in ein anderes Format

filter.filters.sanitize

Wie man :

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

Blockquote LoremIpsumhasbeentheindustry's

120DEV
quelle
1
Gut, aber es würde keine Schrägstriche entfernen, was ein Problem sein könnte: Verzeichnisüberquerung.
func0der
6

Der folgende Ausdruck erstellt eine schöne, saubere und verwendbare Zeichenfolge:

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

Das heutige Finanzwesen verwandeln: Abrechnung in heutige Finanzabrechnung

Sampson
quelle
Ein Dateiname kann also keinen Punkt oder Unterstrich haben oder so etwas?
Tor Valamo
2
@ Jonathan - was ist mit der Kursivschrift?
Dominic Rodger
@Tor, ja, sorry. Aktualisiert. @Dominic, nur die Betonung auf den Text ziehen.
Sampson
Was ist Gisma? Ich erhalte "Warnung: preg_replace () [function.preg-replace]: Unbekannter Modifikator 'g'"
user151841
1
@ user151841 Für preg_replacedas globale Flag ist implizit. G wird also nicht benötigt, wenn preg_replace verwendet wird. Wenn wir die Anzahl der Ersetzungen steuern möchten, hat preg_replace einen limitParameter dafür. Weitere Informationen finden Sie in der Dokumentation zu preg_replace.
Rineez
6

Wenn Sie eine kleine Anpassung an Sean Vieiras Lösung vornehmen, um einzelne Punkte zu berücksichtigen, können Sie Folgendes verwenden:

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

sicher: Ersetzen Sie jede Folge von NICHT "a-zA-Z0-9_-" durch einen Bindestrich. Fügen Sie selbst eine Erweiterung hinzu.

$name = preg_replace('/[^a-zA-Z0-9_-]+/', '-', strtolower($name)).'.'.$extension;
Commonpike
quelle
1
Sie müssen die durch ein "." Getrennte Dateierweiterung hinzufügen: $ name = preg_replace ('/ [^ a-zA-Z0-9 _-] + /', '-', strtolower ($ name)). '.' . $ extension;
Smith
2

Diese mögen etwas schwer sein, aber sie sind flexibel genug, um jede Saite in einen "Safe" zu verwandeln. en Dateinamen oder Ordnernamen im Stil zu bereinigen (oder zum Teufel sogar geschrubbte Schnecken und Dinge, wenn Sie sie biegen).

1) Erstellen eines vollständigen Dateinamens (mit Fallback-Namen, falls die Eingabe vollständig abgeschnitten ist):

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

2) Oder verwenden Sie nur den Filter util, ohne einen vollständigen Dateinamen zu erstellen (im strengen Modus truesind [] oder () im Dateinamen nicht zulässig ):

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

3) Und hier sind diese Funktionen:

// 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;
    }
}

Nehmen wir also an, einige Benutzereingaben lauten: .....&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) საბეჭდი-და-ტიპოგრაფიული

Und wir wollen es in etwas Freundlicheres konvertieren, um ein tar.gz mit einer Dateinamenlänge von 255 Zeichen zu erstellen. Hier ist ein Beispiel für die Verwendung. Hinweis: Dieses Beispiel enthält eine fehlerhafte tar.gz-Erweiterung als Proof of Concept. Sie sollten die ext trotzdem filtern, nachdem die Zeichenfolge anhand Ihrer Whitelist (s) erstellt wurde.

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

Die Ausgabe wäre: _wei_gbel_file_name_dcor_._._._z_._y_._x_._this_name_is_462_not_that_grrrreat_][09]()1234747)_.tar.gz

Sie können hier damit spielen: https://3v4l.org/iSgi8

Oder eine Zusammenfassung: https://gist.github.com/dhaupin/b109d3a8464239b7754a

BEARBEITEN:&nbsp; Aktualisierter Skriptfilter für anstelle von Speicherplatz, aktualisierter 3v4l-Link

Dhaupin
quelle
1

Das Beste, was ich heute weiß, ist die statische Methode Strings :: webalize aus dem Nette-Framework.

Übrigens übersetzt dies alle diakritischen Zeichen in ihre Grundzeichen. Š => s ü => u ß => ss usw.

Für Dateinamen müssen Sie den Punkt "." Hinzufügen. zu erlaubten Zeichen Parameter.

/**
 * 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;
}
DnD
quelle
Warum möchten Sie Diakritika ersetzen? Verwenden urlencode()Sie einfach, bevor Sie den Dateinamen als srcoder verwenden href. Das einzige derzeit verwendete Dateisystem, das Probleme mit UTF-8 hat, ist FATx (von XBOX verwendet): en.wikipedia.org/wiki/Comparison_of_file_systems#Limits Und ich glaube nicht, dass dies von Webservern verwendet wird
mgutt
1

Es scheint, dass dies alles von der Frage abhängt, ob es möglich ist, einen Dateinamen zu erstellen, der zum Hacken in einen Server verwendet werden kann (oder einen solchen anderen Schaden anrichtet). Wenn nicht, scheint es die einfache Antwort zu sein, die Datei dort zu erstellen, wo sie letztendlich verwendet wird (da dies zweifellos das Betriebssystem der Wahl sein wird). Lassen Sie das Betriebssystem das klären. Wenn es sich beschwert, portieren Sie diese Beschwerde als Validierungsfehler zurück an den Benutzer.

Dies hat den zusätzlichen Vorteil, dass es zuverlässig portierbar ist, da sich alle (ich bin mir ziemlich sicher) Betriebssysteme beschweren, wenn der Dateiname für dieses Betriebssystem nicht richtig gebildet wird.

Wenn es ist möglich schändliche Dinge mit einem Dateinamen zu tun, vielleicht gibt es Maßnahmen , die vor dem Testen den Dateinamen auf dem residenten Betriebssystem angewandt werden können - Maßnahmen weniger kompliziert als eine vollständige „Hygiene“ des Dateinamen.

ReverseEMF
quelle
0

Einweg

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

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

}
echo sanitize($string,$bad);
Ghostdog74
quelle
Was ist mit nicht druckbaren Zeichen? In diesem Fall ist es besser, den White-List-Ansatz als den Black-List-Ansatz zu verwenden. Erlauben Sie grundsätzlich nur die druckbaren ASCII-Dateinamen mit Ausnahme der Sonderbuchstaben. Aber für nicht englische Länder ist das ein weiteres Problem.
TheRealChx101
0

/und ..im vom Benutzer angegebenen Dateinamen kann schädlich sein. Also sollten Sie diese durch etwas wie: loswerden.

$fname = str_replace('..', '', $fname);
$fname = str_replace('/',  '', $fname);
Spiel ist aus
quelle
Das reicht nicht aus! Beispielsweise wird der Dateiname "./.name" weiterhin aus dem aktuellen Verzeichnis herausgebrochen. (Das Entfernen von .. bewirkt hier nichts, aber das Entfernen von / verwandelt die ./. In .. und bricht daher aus dem Zielverzeichnis aus.)
cemper93
3
@ cemper93 Nein, diese Antwort verwandelt nur den String, in ..nameden nichts ausbrechen würde. Das Entfernen aller Pfadtrennzeichen sollte ausreichen, um ein Durchlaufen des Verzeichnisses zu verhindern. (Das Entfernen von ..ist technisch unnötig.)
cdhowie
@cdhowie Ja, aber der Dateiname ./.wird ... Und schließlich fehlen bei dieser Antwort alle anderen für das Dateisystem reservierten Zeichen wie NULL. Mehr in meiner Antwort: stackoverflow.com/a/42058764/318765
mgutt
-4

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

Da Benutzer den Schrägstrich möglicherweise verwenden, um zwei Wörter zu trennen, ist es besser, anstelle von NULL einen Bindestrich zu verwenden

user2246924
quelle
Wo steht, dass er durch NULL ersetzen würde? Dies behandelt auch nicht alle Sonderzeichen.
Travis Pessetto
Ja - es gibt andere Sonderzeichen, die ebenfalls behandelt werden müssen. str_replace ist hier sowieso nicht das beste Gebot.
Martin Kovachev