Variable als Parameter wird nicht richtig verarbeitet.

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • #16
    Zitat von pippo Beitrag anzeigen
    Spontan überlege ich, ob die RegExp in preg_match(), also ohne multibyte support, mitspielt vor allem mit den Umlauten:

    PHP-Code:
    preg_match('/\A(?>\pL\pM*|[\-._]){1,200}\z/u'$input); 
    Prinzipiell kann die PCRE-Erweiterung (also alles, was mit preg_... anfängt), mit UTF-8 umgehen (dafür sorgt das "/u"). Die interne PCRE-Library kann zusätzlich UTF-32 und UTF-16. Nur hat man das derzeit in PHP noch nicht eingebaut. Das kommt aber sicher irgendwann. Andere Kodierungen kannst du zwar mit der MBString-Erweiterung abdecken, allerdings ist deren RegEx-Funktionalität und -Syntax etwas anders. Und ich weiß nicht, ob sie Tabellen für die Zeichenklassen \pL und \pM eingebaut hat. Die Dokumentation ist da etwas dürftig, wenn man kein Japanisch lesen kann.

    Wenn preg_match() true zurückgibt, ist alles ok, und wenn nicht? Wie soll man da am besten reagieren, ich möchte dem User keinen Fehler zurückgeben, sondern der Dateiname soll sich automatisch anpassen.
    Wenn du den benutzer-gegebenen Namen weiterverwenden willst, wirst du immer auf Fehler stoßen. Bspw. kann der Namen schon vergeben sein. Das kann der Regex nicht wissen, nur das Dateisystem.

    Manchmal ist es einfacher einen eindeutigen Datei-Namen zu generieren und den vom Browser gelieferten irgendwo anders abzuspeichern, falls ihn irgendwer nochmal braucht.
    Klingon function calls do not have “parameters”‒they have “arguments”‒and they always win them!

    Kommentar


    • #17
      Zitat von fireweasel Beitrag anzeigen
      Im Übrigen sind diverse Zeichen in Dateinamen sowieso verboten und diese sind abhängig vom unterliegenden Betriebssystem und Dateisystem. Du musst dich also zusätzlich auf Fehler einstellen, die auftreten, obwohl der Dateiname (d)eine Prüfung per RegEx überstanden hat.
      Du hast Recht, nachdem eine Datei ($fileName) hochgeladen wird, muss sie noch durch mehrere Prozessen gehen, ExifTool (MetaTags auslesen), weitere Bildmanipulationen mit GraphicsMagick, Sips, ZIP erstellen usw...
      Das ganze ist trotz RegExp-Check sehr fehleranfällig, darum habe ich mich entschieden, den Original-Dateinamen in einem extra Feld zu speichern und der Variable $fileName eine eindeutige Unique-Id zu verpassen.

      Zitat von fireweasel Beitrag anzeigen
      Prinzipiell kann die PCRE-Erweiterung (also alles, was mit preg_... anfängt), mit UTF-8 umgehen (dafür sorgt das "/u"). Die interne PCRE-Library kann zusätzlich UTF-32 und UTF-16. Nur hat man das derzeit in PHP noch nicht eingebaut...
      Nur rein interessehalber, wie würde die negierte Variante deines vorherigen Beispiels mit preg_match() aussehen, wenn ich mit preg_replace() eine Art sanitized Behandlung anwenden möchte. Man sollte diese RegExp ('/\A(?>\pL\pM*|[\ .-])\z/u'), welche ja gut mit preg_match() funktioniert hat, umkehren. So werden die Sonderzeichen nicht gefiltert:

      PHP-Code:
       $fileName preg_replace'/\^A(?>\pL\pM*|[\ _.-])\z/u''_'$fileName ); 
      In Flames - Pinbal Map
      Becoming the Archetype - No Fall Too Far
      Pantera

      Kommentar


      • #18
        Negatives Matching ist schwierig. (Soll heißen: schwierig für mich. )

        Du kannst dir aber in diesem Fall recht problemlos (Speicher, Laufzeit) aus den positiven Treffern eine Maske konstruieren, die du dann noch mal auf den Ausgangsstring anwendest.

        (Alles natürlich als UTF-8.)

        PHP-Code:
        <?php

        function f($s)
        {
            
        $allowedCharactersPattern '/\pL\pM*|[\-._ ]/u';

            
        $replacementChar '_';

            
        $mask preg_replace_callback(
                
        $allowedCharactersPattern,
                function (
        $matches) use ($replacementChar) {
                    return 
        str_repeat($replacementCharstrlen($matches[0]));
                },
                
        $s
            
        );

            
        // $mask enthält an dieser Stelle: "__________12*3_()_\r\n__"
            // Jede Position, an der sich ein Unterstrich/$replacementChar befindet,
            // markiert ein *erlaubtes* Byte in der Eingabe

            // Alle *unerlaubten* Bytes rauswerfen
            // (Indizes in der Eingabe, an denen in der Maske *kein*
            // replacementChar steht)

            
        $len strlen($s);
            
        $sanitized '';

            for (
        $i 0$i $len$i++) {
                
        $sanitized .= ($replacementChar === $mask[$i])
                        ? 
        $s[$i]
                        : 
        $replacementChar;
            }

            return 
        $sanitized;
        }

        $input "\xC3\xA4 \x6F\xCC\x88 \xC3\xBC 12*3 ()-\r\n._";
               
        // (ä NFC ) (  ö NFD   ) (ü NFC )

        $tmp f($input);

        var_dump(
            
        $tmp,
            
        bin2hex($tmp)
        );
        Ausgabe:

        Code:
        string(22) "ä ö ü ____ __-__._"
        string(44) "c3a4206fcc8820c3bc205f5f5f5f205f5f2d5f5f2e5f"
        Das "ö" ist NFD, "ä" und "ü" sind NFC. Ich weiß nicht, ob die Unterscheidung meine Shell/meinen Browser/die Forensoftware überlebt.

        Die Längenbegrenzung bekommst du mit mb_substr($input, 0, 200, 'UTF-8'); hin. Du musst dabei aber bedenken, dass das keine 200 Bytes sind, sondern 200 UTF-8-Characters, die jeweils mehr als ein Byte belegen können. Wie lang 200 UTF-8-Characters in Byte maximal sein können, ist diskutabel.

        Der Algorithmus lässt theoretisch bis zu acht Bytes lange Byteketten und dadurch über vier Billionen Zeichen zu. Die letzte Stufe enthielt als erstes Byte 11111111 und danach sieben Folge-Bytes mit jeweils sechs Nutz-Bits. Die gesamte Codefolge wäre dann 2(7*6) = 242 = 4.398.046.511.104 Zeichen). Real definiert wurde ursprünglich eine Folge aus einem ersten Byte mit bis zu 1111110x und somit fünf Folge-Bytes der Form 10xxxxxx, also zusammen sechs Byte mit insgesamt 31 Bit für den enthaltenen Unicode-Wert. In seiner Verwendung als UTF-Kodierung ist er aber auf den gemeinsamen Coderaum aller Unicode-Kodierungen beschränkt, also von 0 bis 0010 FFFF (1.114.112 Möglichkeiten) und weist maximal vier Bytes lange Byteketten auf.
        - https://de.wikipedia.org/wiki/UTF-8

        Es gibt Argumente für 4, 6 und 8 Byte pro Character, also 800, 1200 oder 1600 Byte insgesamt.

        substr kannst du für so was übrigens vergessen, weil es die UTF-8-Characters zerhackt. Wenn du die Länge auf eine Anzahl an Bytes begrenzen möchtest, würde ich eine Schleife machen mit mb_substr, die so lange einen Character hinzufügt, bis die strlen (nicht die mb_strlen) des entstandenen Strings die gewünschte Länge überschreitet. Dann wieder einen Character abziehen – fertig.

        Fun fact:

        PHP-Code:
        $input 'u' str_repeat("\xCC\x88"300);
                
        // "u" + <U+0308 COMBINING DIAERESIS> (300-mal)

        var_dump(mb_substr($input0200'UTF-8'));
                
        // string(399) "ü" (je nach Software wird das nicht unbedingt ein "ü")
                //                 (Und hier im Code ist das ein NFC-"ü", keine Angst) 
        Zuletzt geändert von mermshaus; 27.10.2014, 09:58.

        Kommentar


        • #19
          Hallo mermshaus,

          ich habe mehreren Tests laufen lassen, es scheint wirklich gut zu funktionieren.

          Jetzt fehlt nur noch dass die Funktion in die PHP-Bibliothek hinzugefügt wird ;-)
          In Flames - Pinbal Map
          Becoming the Archetype - No Fall Too Far
          Pantera

          Kommentar

          Lädt...
          X