Zeichenfolgen bereinigen, um URL- und Dateinamen sicher zu machen?


136

Ich versuche, eine Funktion zu entwickeln, mit der bestimmte Zeichenfolgen gut bereinigt werden können, damit sie sicher in der URL verwendet werden können (wie ein Post-Slug) und auch sicher als Dateinamen verwendet werden können. Wenn zum Beispiel jemand eine Datei hochlädt, möchte ich sicherstellen, dass alle gefährlichen Zeichen aus dem Namen entfernt werden.

Bisher habe ich die folgende Funktion entwickelt, die dieses Problem hoffentlich löst und auch fremde UTF-8-Daten zulässt.

/**
 * 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');
}

Hat jemand knifflige Beispieldaten, die ich dagegen ausführen kann - oder kennt er einen besseren Weg, um unsere Apps vor schlechten Namen zu schützen?

$ is-filename erlaubt einige zusätzliche Zeichen wie temporäre VIM-Dateien

Update: Das Sternzeichen wurde entfernt, da mir keine gültige Verwendung einfiel


Sie entfernen besser alles außer [\ w.-]
elias

3
Möglicherweise finden Sie den Normalisierer und die Kommentare dazu hilfreich.
Matt Gibson

Antworten:


57

Einige Beobachtungen zu Ihrer Lösung:

  1. 'u' am Ende Ihres Musters bedeutet, dass das Muster und nicht der Text, mit dem es übereinstimmt, als UTF-8 interpretiert wird (ich nehme an, Sie haben letzteres angenommen?).
  2. \ w entspricht dem Unterstrich. Sie fügen es speziell für Dateien ein, was zu der Annahme führt, dass Sie sie nicht in URLs haben möchten, aber in dem Code, den Sie haben, dürfen URLs einen Unterstrich enthalten.
  3. Die Aufnahme von "fremdem UTF-8" scheint vom Gebietsschema abhängig zu sein. Es ist nicht klar, ob dies das Gebietsschema des Servers oder Clients ist. Aus den PHP-Dokumenten:

Ein "Wort" -Zeichen ist ein beliebiger Buchstabe oder eine Ziffer oder ein Unterstrich, dh ein beliebiges Zeichen, das Teil eines Perl- "Wortes" sein kann. Die Definition von Buchstaben und Ziffern wird durch die Zeichentabellen von PCRE gesteuert und kann variieren, wenn ein länderspezifischer Abgleich stattfindet. Beispielsweise werden im Gebietsschema "fr" (Französisch) einige Zeichencodes größer als 128 für Buchstaben mit Akzent verwendet, und diese werden mit \ w abgeglichen.

Schnecke erstellen

Sie sollten wahrscheinlich keine Zeichen mit Akzent usw. in Ihren Post-Slug aufnehmen, da diese technisch gesehen prozentual codiert sein sollten (gemäß den URL-Codierungsregeln), damit Sie hässlich aussehende URLs haben.

Wenn ich Sie wäre, würde ich nach dem Kleinbuchstaben alle 'Sonderzeichen' in ihre Entsprechungen (z. B. é -> e) konvertieren und Nicht-[az] -Zeichen durch '-' ersetzen, was sich auf Läufe eines einzelnen '-' beschränkt. wie du es getan hast. Hier können Sie Sonderzeichen konvertieren: https://web.archive.org/web/20130208144021/http://neo22s.com/slug

Desinfektion im Allgemeinen

OWASP verfügt über eine PHP-Implementierung seiner Enterprise Security-API, die unter anderem Methoden zum sicheren Codieren und Decodieren von Ein- und Ausgaben in Ihrer Anwendung enthält.

Die Encoder-Schnittstelle bietet:

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


Sie haben Recht mit meiner Annahme des Modifikators "u" - ich dachte, dass es für den Text war. Ich habe auch den Modifikator \ w einschließlich des Unterstrichs vergessen. Normalerweise würde ich alle Zeichen mit Akzent in ASCII konvertieren - aber ich möchte, dass dies auch für andere Sprachen funktioniert. Ich ging davon aus, dass es eine sichere UTF-8-Methode geben würde, mit der jedes Zeichen einer Sprache in einem URL-Slug oder Dateinamen verwendet werden kann, sodass auch arabische Titel funktionieren. Schließlich unterstützt Linux UTF-8-Dateinamen und Browser sollten HTML-Links nach Bedarf codieren. Vielen Dank für Ihre Eingabe hier.
Xeoncross

Beim zweiten Gedanken haben Sie tatsächlich Recht, aber es ist nicht nur ein Problem mit dem Browser, der die Links korrekt codiert. Der einfachste Weg, um nahe an das zu gelangen, was Sie möchten, besteht darin, Nicht-ASCII-Zeichen ihrem nächsten ASCII-Äquivalent zuzuordnen und dann Ihren Link im HTML-Text per URL zu codieren. Der schwierige Weg besteht darin, eine konsistente UTF-8-Codierung (oder UTF-16, glaube ich für einige chinesische Dialekte) von Ihrem Datenspeicher über Ihren Webserver, die Anwendungsschicht (PHP), den Seiteninhalt, den Webbrowser und nicht den Urlencode Ihrer URLs ( aber immer noch "unerwünschte" Zeichen entfernen). Dadurch erhalten Sie nette, nicht verschlüsselte Links und URLs.
Alan Donnelly

Guter Rat. Ich werde versuchen, eine reine UTF-8-Umgebung zu erstellen. Dann entferne ich einige Zeichenfolgen aus Nicht-ASCII-Sprachen, entferne gefährliche Zeichen (./;: etc ...) und erstelle Dateien und dann HTML-Links zu diesen Dateien, um zu sehen, ob ich darauf klicken kann und ob dies alles der Fall ist funktioniert. Wenn nicht, muss ich wahrscheinlich auf (raw)? Urlencode () zurückgreifen, um UTF-8 zuzulassen. Ich werde die Ergebnisse hier zurückschicken.
Xeoncross

3
Ich habe eine Datei namens erstellt สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txtund dann eine UTF-8-HTML-Datei mit einem Link dazu erstellt. Erstaunlicherweise hat es funktioniert - sogar unter Fenstern! Allerdings hatte ich dann PHP file_put_contents('สังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่.txt')und es konnte kein Basar-Dateiname aus dieser Zeichenfolge erstellt werden. Dann habe ich versucht, es mit zu erstellen fopen()und habe den gleichen durcheinandergebrachten Dateinamen erhalten. Offensichtlich ist PHP (zumindest unter Windows) nicht in der Lage, UTF-8-Dateinamen zu erstellen. bugs.php.net/bug.php?id=46990&thanks=6
Xeoncross

1
Ich vergebe diese Antwort, weil sie mich am meisten zum Nachdenken gebracht hat und auch einen nützlichen Link zu einem Projekt enthält, von dem ich noch nie gehört habe, dass es sich lohnt, es zu untersuchen. Ich werde posten, sobald ich eine Antwort gefunden habe.
Xeoncross

87

Ich habe diese größere Funktion im Chyrp- Code gefunden:

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

und dieser im 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);
}

Update September 2012

Alix Axel hat in diesem Bereich unglaubliche Arbeit geleistet. Sein Phunction-Framework enthält mehrere großartige Textfilter und Transformationen.


23
Der WordPress-Code ist nicht portabel, da er verwendetapply_filters
Kevin Mark

1
Beachten Sie, dass die Wordpress - Version ersetzt /[\s-]+/mit -denen ist besser als die erste Version (die nur ersetzt /\s+/) , die mehrere Striche in Folge führen kann
Yotam Omer

Nur als Referenz finden Sie hier apply_filters und hier sanitize_file_name .
Eric

Was ist mit mehreren Leerzeichen? Ersetzen
Jeffrey die Giraffe

8
Die $ anal-Variable klingt für mich mit der Force-Option sehr beängstigend.
Viljun

30

Dies sollte Ihre Dateinamen sicher machen ...

$string = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $string);

und eine tiefere Lösung dafür ist:

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

Dies setzt voraus, dass Sie einen Punkt im Dateinamen möchten. Wenn Sie möchten, dass es in Kleinbuchstaben übertragen wird, verwenden Sie einfach

$clean_name = strtolower($clean_name);

für die letzte Zeile.


1
Es fehlen noch einige tschechische und slowakische Charaktere:'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
Jasom Dotnet

22

Versuche dies:

function normal_chars($string)
{
    $string = htmlentities($string, ENT_QUOTES, 'UTF-8');
    $string = preg_replace('~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', $string);
    $string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
    $string = preg_replace(array('~[^0-9a-z]~i', '~[ -]+~'), ' ', $string);

    return trim($string, ' -');
}

Examples:

echo normal_chars('Álix----_Ãxel!?!?'); // Alix Axel
echo normal_chars('áéíóúÁÉÍÓÚ'); // aeiouAEIOU
echo normal_chars('üÿÄËÏÖÜŸåÅ'); // uyAEIOUYaA

Basierend auf der ausgewählten Antwort in diesem Thread: URL-freundlicher Benutzername in PHP?


Sehr schön - ich habe dies noch nie ohne Übersetzungstabelle gesehen (wie es WordPress verwendet). Ich denke jedoch nicht, dass diese Funktion so wie sie ist ausreicht, da sie nur Sonderzeichen übersetzt, aber keine gefährlichen Zeichen entfernt. Vielleicht kann es zu einem oben hinzugefügt werden ...
Xeoncross

4
Ha! Dieser Entity-Coding-Hack ist süß! Obwohl auf den ersten Blick nicht klar ist, wie diese Methode das macht, was sie macht. Es gibt jedoch ein Problem. Wird aus "Frédéric & Éric" nicht "Frederic amp Eric"?
Alan Donnelly

@AlanDonnelly: In der Tat habe ich die Funktion in meiner ursprünglichen Antwort aktualisiert (überprüfen Sie den Link), die trim()sollte auch sein trim($string, '-').
Alix Axel

@Xeoncross: Der letzte preg_replace()sollte alle gefährlichen Zeichen entfernen.
Alix Axel

@AlixAxel, du bist einfach überall, nicht wahr? Ich habe gerade das PHP AWS SDK gelesen und sie hatten einen Teil Ihres Codes für UUIDs. Der fantastische Code der Funktion ist nur schwer zu übertreffen.
Xeoncross

13

Dies ist nicht gerade eine Antwort, da es (noch!) Keine Lösungen bietet, aber es ist zu groß, um auf einen Kommentar zu passen ...


Ich habe einige Tests (in Bezug auf Dateinamen) unter Windows 7 und Ubuntu 12.04 durchgeführt und dabei festgestellt, dass:

1. PHP kann keine Nicht-ASCII-Dateinamen verarbeiten

Obwohl sowohl Windows als auch Ubuntu Unicode-Dateinamen verarbeiten können (auch RTL-Dateinamen, wie es scheint), erfordert PHP 5.3 Hacks, um auch mit dem einfachen alten ISO-8859-1 fertig zu werden. Daher ist es aus Sicherheitsgründen besser, ASCII beizubehalten.

2. Die Länge des Dateinamens ist wichtig (speziell unter Windows)

Unter Ubuntu beträgt die maximale Länge eines Dateinamens (einschließlich Erweiterung) 255 (ohne Pfad):

/var/www/uploads/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345/

Unter Windows 7 (NTFS) hängt die maximale Länge eines Dateinamens jedoch von seinem absoluten Pfad ab:

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

Wikipedia sagt, dass:

Mit NTFS kann jede Pfadkomponente (Verzeichnis oder Dateiname) 255 Zeichen lang sein.

Nach meinem besten Wissen (und Testen) ist dies falsch.

Insgesamt (Schrägstriche zählen) haben alle diese Beispiele 259 Zeichen, wenn Sie das entfernen C:\, das 256 Zeichen ergibt (nicht 255?!). Die Verzeichnisse wurden mit dem Explorer erstellt, und Sie werden feststellen, dass er nicht den gesamten verfügbaren Speicherplatz für den Verzeichnisnamen verwendet. Der Grund dafür ist, die Erstellung von Dateien unter Verwendung der 8.3-Dateinamenskonvention zu ermöglichen . Das gleiche passiert für andere Partitionen.

Dateien müssen natürlich nicht die Anforderungen für 8,3 Längen reservieren:

(255 chars) E:\12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.txt

Sie können keine Unterverzeichnisse mehr erstellen, wenn der absolute Pfad des übergeordneten Verzeichnisses mehr als 242 Zeichen enthält 256 = 242 + 1 + \ + 8 + . + 3. Mit Windows Explorer können Sie kein anderes Verzeichnis erstellen, wenn das übergeordnete Verzeichnis mehr als 233 Zeichen enthält (abhängig vom Gebietsschema des Systems) 256 = 233 + 10 + \ + 8 + . + 3. Das 10hier ist die Länge der Zeichenfolge New folder.

Das Windows-Dateisystem stellt ein unangenehmes Problem dar, wenn Sie die Interoperabilität zwischen Dateisystemen sicherstellen möchten.

3. Achten Sie auf reservierte Zeichen und Schlüsselwörter

Neben dem Entfernen von Nicht-ASCII-, nicht druckbaren und Steuerzeichen müssen Sie auch Folgendes neu platzieren (platzieren / verschieben):

"*/:<>?\|

Das Entfernen dieser Zeichen ist möglicherweise nicht die beste Idee, da der Dateiname möglicherweise etwas an Bedeutung verliert. Ich denke, dass zumindest mehrere Vorkommen dieser Zeichen durch einen einzigen Unterstrich ( _) oder vielleicht etwas Repräsentativeres ersetzt werden sollten (dies ist nur eine Idee):

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

Es gibt auch spezielle Schlüsselwörter, die vermieden werden sollten (wie NUL), obwohl ich nicht sicher bin, wie ich das überwinden soll. Vielleicht wäre eine schwarze Liste mit einem zufälligen Fallback ein guter Ansatz, um sie zu lösen.

4. Groß- und Kleinschreibung

Dies sollte selbstverständlich sein. Wenn Sie jedoch die Eindeutigkeit von Dateien unter verschiedenen Betriebssystemen sicherstellen möchten, sollten Sie die Dateinamen in einen normalisierten Fall umwandeln. Auf diese Weise my_file.txtund My_File.txtunter Linux werden unter my_file.txtWindows nicht beide zur gleichen Datei.

5. Stellen Sie sicher, dass es einzigartig ist

Wenn der Dateiname bereits vorhanden ist, sollte eine eindeutige Kennung an den Basisdateinamen angehängt werden .

Zu den allgemeinen eindeutigen Kennungen gehören der UNIX-Zeitstempel, eine Zusammenfassung des Dateiinhalts oder eine zufällige Zeichenfolge.

6. Versteckte Dateien

Nur weil es benannt werden kann, heißt das nicht, dass es ...

Punkte werden normalerweise in Dateinamen auf die weiße Liste gesetzt, aber unter Linux wird eine versteckte Datei durch einen führenden Punkt dargestellt.

7. Andere Überlegungen

Wenn Sie einige Zeichen des Dateinamens entfernen müssen, ist die Erweiterung normalerweise wichtiger als der Basisname der Datei. Wenn Sie eine beträchtliche maximale Anzahl von Zeichen für die Dateierweiterung (8-16) zulassen, sollten Sie die Zeichen vom Basisnamen entfernen. Es ist auch wichtig , dass in dem unwahrscheinlichen Fall zu beachten , von einer mehr als eine langen Verlängerung mit - wie _.graphmlz.tag.gz- _.graphmlz.tagnur _als Dateibasisnamen in diesem Fall in Betracht gezogen werden sollte.

8. Ressourcen

Calibre geht ziemlich anständig mit dem Mangeln von Dateinamen um:

Wikipedia-Seite zum Mangeln von Dateinamen und zum verknüpften Kapitel von Using Samba .


Wenn Sie beispielsweise versuchen, eine Datei zu erstellen, die gegen eine der Regeln 1/2/3 verstößt, wird eine sehr nützliche Fehlermeldung angezeigt:

Warning: touch(): Unable to create file ... because No error in ... on line ...

11

Ich habe immer gedacht, dass Kohana einen ziemlich guten Job gemacht hat .

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

Das Handy UTF8::transliterate_to_ascii()dreht Sachen wie ñ => n.

Natürlich können Sie die anderen UTF8::*Dinge durch mb_ * -Funktionen ersetzen .


5

In Bezug auf das Hochladen von Dateien ist es am sichersten, zu verhindern, dass der Benutzer den Dateinamen kontrolliert. Speichern Sie, wie bereits angedeutet, den kanonisierten Dateinamen in einer Datenbank zusammen mit einem zufällig ausgewählten und eindeutigen Namen, den Sie als tatsächlichen Dateinamen verwenden.

Mit OWASP ESAPI können diese Namen folgendermaßen generiert werden:

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

Sie können einen Zeitstempel an den $ safeFilename anhängen, um sicherzustellen, dass der zufällig generierte Dateiname eindeutig ist, ohne nach einer vorhandenen Datei zu suchen.

In Bezug auf die Kodierung der URL und erneut die Verwendung von ESAPI:

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

Diese Methode führt vor dem Codieren der Zeichenfolge eine Kanonisierung durch und verarbeitet alle Zeichencodierungen.


Auf jeden Fall - auch wenn Sie den Benutzern die Kontrolle über den Dateinamen entziehen, wird die Möglichkeit verhindert, dass zwei Uploads denselben Namen haben.
CodeVirtuoso

5

Ich empfehle * URLify für PHP (480+ Sterne auf Github) - "den PHP-Port von URLify.js aus dem Django-Projekt. Transliteriert Nicht-ASCII-Zeichen zur Verwendung in URLs".

Grundlegende Verwendung:

So generieren Sie Slugs für 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"

?>

So generieren Sie Slugs für Dateinamen:

<?php

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

?>

* Keiner der anderen Vorschläge entsprach meinen Kriterien:

  • Sollte über Composer installierbar sein
  • Sollte nicht von iconv abhängen, da es sich auf verschiedenen Systemen unterschiedlich verhält
  • Sollte erweiterbar sein, um Überschreibungen und das Ersetzen von benutzerdefinierten Zeichen zu ermöglichen
  • Beliebt (zum Beispiel viele Sterne auf Github)
  • Hat Tests

Als Bonus entfernt URLify auch bestimmte Wörter und entfernt alle nicht transliterierten Zeichen.

Hier ist ein Testfall, bei dem Tonnen von Fremdzeichen mithilfe von URLify ordnungsgemäß transliteriert werden: https://gist.github.com/motin/a65e6c1cc303e46900d10894bf2da87f


1
Danke - das sieht für meine Zwecke ideal aus.
David Goodwin

5

Ich habe mich aus einer anderen Quelle angepasst und ein paar zusätzliche hinzugefügt, vielleicht ein wenig übertrieben

/**
 * 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

und das ist Joomla 3.3.2 Version von 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));
}

4

Ich denke nicht, dass es sicher ist, eine Liste mit Zeichen zu haben, die entfernt werden müssen. Ich würde lieber folgendes verwenden:

Für Dateinamen: Verwenden Sie eine interne ID oder einen Hash des Dateiinhalts. Speichern Sie den Dokumentnamen in einer Datenbank. Auf diese Weise können Sie den ursprünglichen Dateinamen beibehalten und die Datei trotzdem finden.

Für URL-Parameter: Verwenden Sie diese Option urlencode(), um Sonderzeichen zu codieren.


1
Ich bin damit einverstanden, dass die meisten der hier aufgeführten Methoden bekannte gefährliche Zeichen entfernen - meine Methode entfernt alles, was kein bekanntes sicheres Zeichen ist. Da die meisten Systeme Post - URLs mit Slugs codieren, würde ich vorschlagen, dass wir weiterhin diese bewährte Methode anwenden, anstatt den dokumentierten unsicheren UTF-8- Urlencode () zu verwenden.
Xeoncross

3

Je nachdem, wie Sie es verwenden, möchten Sie möglicherweise eine Längenbeschränkung hinzufügen, um sich vor Pufferüberläufen zu schützen.


Ja, das Testen auf mb_strlen () ist immer wichtig!
Xeoncross

3

Dies ist eine gute Möglichkeit, einen Upload-Dateinamen zu sichern:

$file_name = trim(basename(stripslashes($name)), ".\x00..\x20");

Da bin ich mir nicht so sicher, denn man .\x00..\x20kann sich darauf reduzieren .\x00\x20.
Xeoncross

@Xeoncross: Ich denke, das .\x00..\x20entfernt Punkte und jedes Zeichen zwischen \x00und \x20, während .\x00\x20nur diese 3 Bytes entfernen sollten.
Alix Axel

Diese Antwort erfordert weitere Erklärungen, damit sie sicher verwendet werden kann. Nicht viele Informationen über die genaue Syntax für charlist im Netz.
Manuel Arwed Schmidt

3

Hier ist die Implementierung von 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));
}

Und die remove_invisible_charactersAbhängigkeit.

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

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

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

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

    return $str;
}

2

warum nicht einfach PHPs verwenden urlencode? Es ersetzt "gefährliche" Zeichen durch ihre hexadezimale Darstellung für URLs (dh %20für ein Leerzeichen).


2
Das% -Zeichen wird für Dateinamen nicht empfohlen, und hexadezimal codierte Zeichen sehen in der URL nicht so gut aus. Browser können UTF-8-Zeichenfolgen unterstützen, die für Nicht-ASCII-Sprachen viel besser und einfacher sind.
Xeoncross

Sie könnten einen Urlencode und dann einen str_replace ('% 20', '-', URL) machen?
Francesco

2

Es gibt bereits mehrere Lösungen für diese Frage, aber ich habe den größten Teil des Codes hier gelesen und getestet und bin zu dieser Lösung gekommen, die eine Mischung aus dem ist, was ich hier gelernt habe:

Die Funktion

Die Funktion ist hier in einem Symfony2- Bundle gebündelt, kann jedoch extrahiert werden, um als einfaches PHP verwendet zu werden. Sie hängt nur von der iconvFunktion ab, die aktiviert werden muss:

Filesystem.php :

<?php

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

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

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

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

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

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

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

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

    return $fileName. $fileExt;
    }
}

Das Gerät testet

Interessant ist, dass ich PHPUnit-Tests erstellt habe, um zunächst Randfälle zu testen. So können Sie überprüfen, ob sie Ihren Anforderungen entsprechen: (Wenn Sie einen Fehler finden, können Sie einen Testfall hinzufügen.)

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

Die Testergebnisse: (unter Ubuntu mit PHP 5.3.2 und MacOsX mit PHP 5.3.17 überprüft:

All tests pass:

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

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

.

Time: 0 seconds, Memory: 5.75Mb

OK (1 test, 17 assertions)

1
Dies setzt hauptsächlich lateinische Eingaben voraus. Fügen Sie weitere UTF-8-Zeichen aus anderen Sprachen hinzu, um festzustellen, wo Probleme auftreten.
Xeoncross

@Xeoncross Ich stimme zu, wie Christian sagte, muss man eine ID oder einen Hash UND den ursprünglichen Dateinamen speichern. Diese Funktion bietet jedoch eine Alternative, da Sie eine Standardzeichenfolge angeben können, wenn der Bereinigungsprozess fehlschlägt. Ich habe einen Komponententest für diesen Fall hinzugefügt. Vielen Dank, dass Sie den Fehler gemeldet haben.
COil

2

Ich habe Eintragstitel mit allen Arten von seltsamen lateinischen Zeichen sowie einige HTML-Tags, die ich in ein nützliches, durch Bindestriche getrenntes Dateinamenformat übersetzen musste. Ich habe die Antwort von @ SoLoGHoST mit ein paar Elementen aus der Antwort von @ Xeoncross kombiniert und ein wenig angepasst.

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

Ich musste das em-Strichzeichen (-) manuell zum Übersetzungsarray hinzufügen. Es mag andere geben, aber bisher sehen meine Dateinamen gut aus.

So:

Teil 1: Die "Žurburts" meines Vaters? - sie sind (nicht) die besten!

wird:

Teil-1-meine-Väter-zurburts-sie sind-nicht-die-besten

Ich füge einfach ".html" zur zurückgegebenen Zeichenfolge hinzu.


1
Es fehlen noch einige tschechische und slowakische Charaktere:'ľ' => 'l', 'Ľ' => 'L', 'č' => 'c', 'Č' => 'C', 'ť' => 't', 'Ť' => 'T', 'ň' => 'n', 'Ň' => 'N', 'ĺ' => 'l', 'Ĺ' => 'L', 'Ř' => 'R', 'ř' => 'r', 'ě' => 'e', 'Ě' => 'E', 'ů' => 'u', 'Ů' => 'U'
Jasom Dotnet

1
Und zweifellos noch viel mehr. Ich versuche tatsächlich herauszufinden, ob es einen ISO-Satz gibt, der Zeichenkombinationen enthält. Wie "wählt" man einen Satz aus, wenn der Inhalt von allen Zeichen verlangt? UTF-8 Ich gehe davon aus ...
cbmtrx

Ich habe herausgefunden, wie man eine Zeichenfolge mit einer Zeile PHP transliteriert : $string = transliterator_transliterate('Any-Latin;Latin-ASCII;', $string);Siehe meine Antwort unten oder lesen Sie den verlinkten Blog-Beitrag.
Jasom Dotnet

1
Nein, Sie haben es falsch gelesen: WENN Sie PHP-Erweiterungen auf Ihrem Server (oder Hosting) installieren können :-) Hier ist der Beitrag .
Jasom Dotnet

1
Ah, verstanden. Danke @JasomDotnet - Ich habe meine aktuelle Lösung im Moment, aber es ist ein begrenzter Zeichensatz, daher lohnt es sich, die Erweiterung zu überprüfen.
cbmtrx

2

Lösung 1: Sie können PHP-Erweiterungen auf dem Server installieren (Hosting)

Für die Transliteration von "fast jeder einzelnen Sprache auf dem Planeten Erde" in ASCII-Zeichen.

  1. Installieren Sie zuerst die PHP Intl- Erweiterung. Dies ist der Befehl für Debian (Ubuntu):sudo aptitude install php5-intl

  2. Dies ist meine Dateinamenfunktion (erstelle test.php und füge dort folgenden Code ein):

<!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>

Diese Linie ist der Kern:

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

Antwort basierend auf diesem Beitrag .

Lösung 2: Sie können keine PHP-Erweiterungen auf dem Server installieren (Hosting)

Geben Sie hier die Bildbeschreibung ein

Das Transliterationsmodul für CMS Drupal leistet ziemlich gute Arbeit . Es unterstützt fast jede einzelne Sprache auf dem Planeten Erde. Ich schlage vor, das Plugin- Repository zu überprüfen, wenn Sie wirklich vollständige Lösungsbereinigungszeichenfolgen haben möchten.



1

Dies ist eine gute Funktion:

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

Das sieht schlecht aus. \\s+bedeutet einen Backslash, gefolgt von einem oder mehreren Leerzeichen. Worum geht es? Dies verwendet auch Blacklisting anstelle von Whitelisting, wobei Dinge wie CMDnull oder ignoriert werden BEL.
Xeoncross

Immernoch schlecht. Jetzt sind Strings wie /blog/2014-02/just-in-timenicht erlaubt. Bitte verwenden Sie den oben getesteten Code oder den phunctionPHP-Framework-Code.
Xeoncross

Das stimmt. Diese Funktion ist nur für den "Just-in-Time" -Teil vorgesehen. Könnte für einige Leute nützlich sein.
joan16v

1
Sie können die Regexpreg_replace('~[^\-\pL\pN\s]+~u', '-', $string)
Xeoncross

Genial! Ich habe auch hinzugefügt: string = trim ($ string, "-");
joan16v

0

Dies ist der Code, der von Prestashop verwendet wird, um URLs zu bereinigen:

replaceAccentedChars

wird verwendet von

str2url

diakritische Mittel zu entfernen

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

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

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

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

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

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

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

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

    return $str;
}


-4
// CLEAN ILLEGAL CHARACTERS
function clean_filename($source_file)
{
    $search[] = " ";
    $search[] = "&";
    $search[] = "$";
    $search[] = ",";
    $search[] = "!";
    $search[] = "@";
    $search[] = "#";
    $search[] = "^";
    $search[] = "(";
    $search[] = ")";
    $search[] = "+";
    $search[] = "=";
    $search[] = "[";
    $search[] = "]";

    $replace[] = "_";
    $replace[] = "and";
    $replace[] = "S";
    $replace[] = "_";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";

    return str_replace($search,$replace,$source_file);

} 
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.