Variable als Parameter wird nicht richtig verarbeitet.

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

  • Variable als Parameter wird nicht richtig verarbeitet.

    Hallo zusammen,

    hat irgendjemand eine Ahnung warum eine Variable ($fileName) welche als Parameter in eine Methode der Class xyz übergeben wird, sich nicht korrekt manipulieren lässt? Ich hätte gedacht es liegt an der Codierung, dies scheint aber nicht der Fall zu sein, in beide Beispiele ist utf-8:

    Beispiel 1, Variable wird als Parameter übergeben:

    PHP-Code:
    $fileName "Müller";

    class 
    MyClass {

    protected function 
    sanitizeFilename($fileName) {

        return 
    str_replace("ü"'_'$fileName);
    }

    $fileName $this->sanitizeFilename($fileName);

    echo 
    "detect: ".mb_detect_encoding($fileName);
    echo 
    "output: ".$fileName;
    ...

    Ausgabe:
    HTML-Code:
    detect: UTF-8
    output: Müller (nicht erwartete Resultat)
    Beispiel 2, string manuell hardcodiert:
    PHP-Code:
    $fileName str_replace("ü"'_'"Müller");

    echo 
    "detect: ".mb_detect_encoding($fileName);
    echo 
    "output: ".$fileName
    Ausgabe:
    HTML-Code:
    detect: UTF-8
    output: M_ller (erwartete Resultat)
    Im head habe ich <meta charset="UTF-8"/>, im Editor auch CR UTF-8

    Irgendeine Idee was ich hier tun kann?
    Zuletzt geändert von pippo; 19.10.2014, 21:00.
    In Flames - Pinbal Map
    Becoming the Archetype - No Fall Too Far
    Pantera

  • #2
    Du zeigst nicht den richtigen Code. Das Problem lässt sich mit Fantasiecode nicht reproduzieren.

    Kommentar


    • #3
      was ich damit meine, ist dass str_replace() oder preg_replace() trotz utf8 codierung, die Umlaute oder sonderzeichen nicht erkennen.

      PHP-Code:
      $str "Müller"// wird als Parameter übergeben 
      Das geht nicht:
      PHP-Code:
      echo preg_replace('/\[^\pL]/u''_'$str ); // Ausgabe Müller, Codierung UTF-8 
      Das auch nicht;
      PHP-Code:
      echo utf8_encode(preg_replace('/\[^\pL]/u''_'utf8_decode($str) )); // Ausgabe M?ller Codierung ASCII 
      OS ist Unix. Header und Editor und DB alles utf-8.

      Das einzige was geht, ist wenn ich anstatt $str als Parameter zu verwenden, den String hardcodiert direkt in preg_replace() schreibe:

      PHP-Code:
      echo preg_replace('/\[^\pL]/u''_''Müller' ); // Ausgabe korrekt: M_ller 
      Vielleicht muss ich was in der php.ini einstellen?

      HTML-Code:
      Multibyte Support 	enabled
      Multibyte string engine 	libmbfl
      HTTP input encoding translation 	disabled
      libmbfl version 	1.3.2 
      Multibyte (japanese) regex support 	enabled
      Multibyte regex (oniguruma) backtrack check 	On
      Multibyte regex (oniguruma) version 	4.7.1
      
      Directive	Local Value	Master Value
      mbstring.detect_order	no value	no value
      mbstring.encoding_translation	Off	Off
      mbstring.func_overload	0	0
      mbstring.http_input	pass	pass
      mbstring.http_output	pass	pass
      mbstring.http_output_conv_mimetypes	^(text/|application/xhtml\+xml)	^(text/|application/xhtml\+xml)
      mbstring.internal_encoding	no value	no value
      mbstring.language	neutral	neutral
      mbstring.strict_detection	Off	Off
      mbstring.substitute_character	no value	no value
      Zuletzt geändert von pippo; 19.10.2014, 20:17.
      In Flames - Pinbal Map
      Becoming the Archetype - No Fall Too Far
      Pantera

      Kommentar


      • #4
        Bitte poste einen Testcode, bei dem das Problem nachvollziehbar auftritt.

        Kommentar


        • #5
          gegebene Variable welche von symfony2 geliefert wird:

          PHP-Code:
          $str "Müller"
          Alle 5 Beispiele gehen bei mir nicht:

          PHP-Code:
          // Test 1
          echo "detect1: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: UTF-8
          echo "Ausgabe vorher: ".$name."\n\r";               // Ausgabe: Müller
          $name preg_replace('/\[^\pL]/u''_'$name );
          echo 
          "detect2: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: UTF-8
          echo "Ausgabe nachher: ".$name."\n\r";              // Ausgabe falsch: Müller

          // Test 2
          echo "detect1: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: UTF-8
          echo "Ausgabe vorher: ".$name."\n\r";               // Ausgabe: Müller
          $name utf8_encode(preg_replace('/\[^A-Za-z0-9]/''_'utf8_decode($name) ));
          echo 
          "detect2: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: ASCII
          echo "Ausgabe nachher: ".$name."\n\r";              // Ausgabe faslch: Mu?ller

          // Test 3
          echo "detect1: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: UTF-8
          echo "Ausgabe vorher: ".$name."\n\r";               // Ausgabe: Müller
          $name preg_replace('/\[^A-Za-z0-9]/''_'$name );
          echo 
          "detect2: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: UTF-8
          echo "Ausgabe nachher: ".$name."\n\r";              // Ausgabe faslch: Müller

          // Test 4
          echo "detect1: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: UTF-8
          echo "Ausgabe vorher: ".$name."\n\r";               // Ausgabe: Müller
          $name preg_replace('/[^A-Za-z0-9]/ui''_'$name );
          echo 
          "detect2: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: ASCII
          echo "Ausgabe nachher: ".$name."\n\r";              // Ausgabe fast richtig: Mu_ller 

          // Test 5 neues string
          $name "(55Teöäüsuu ?zwei:LLMüller :L'araéàèncio)<.jpeg";
          echo 
          "detect1: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: UTF-8
          echo "Ausgabe vorher: ".$name."\n\r";               // Ausgabe: (55Teöäüsuu ?zwei:LLMüller :L'araéàèncio)<.jpeg
          $name preg_replace('/[^A-Za-z0-9öäüéàèÖÄÜÉÀÈ -._]/ui''_'$name );
          echo 
          "detect2: ".mb_detect_encoding($name)."\n\r";  // Ausgabe: ASCII
          echo "Ausgabe nachher: ".$name."\n\r";              // Ausgabe faslch: (55Teo_a_u_suu _zwei_LLMu_ller _L'arae_a_e_ncio)_.jpeg 
          Bei test 5, wenn man die Umlaute vergisst, sollten keinen Klammer und keinen Apostroph drinnen sein.
          Zuletzt geändert von pippo; 19.10.2014, 22:24.
          In Flames - Pinbal Map
          Becoming the Archetype - No Fall Too Far
          Pantera

          Kommentar


          • #6
            Bitte zeig mal mittels bin2hex() den Inhalt von $name.

            Kommentar


            • #7
              Du hast in den Tests 1-3 einen falschen Backslash vor "[". Alle drei Patterns matchen deshalb für das Beispiel überhaupt nichts.

              Die (zufälligerweise unveränderte) Ausgabe des reparierten Tests 1 ist ansonsten das, was zu erwarten ist, weil ein "ü" ein Buchstabe ist und deshalb Teil von "\pL". (Jedenfalls zu erwarten für NFC. Für NFD würde das so sogar „irgendwie“ funktionieren. Siehe dazu auch nachfolgenden Absatz.)

              Eine sinnvolle Erklärung zu Test 4 ist, dass deine Eingabe in NFD vorliegt statt in NFC (UAX #15: Unicode Normalization Forms). Aber, ja, da wäre ein Hex-Dump jetzt nicht verkehrt.

              Wenn du bei Test 5 keine Klammern und Apostrophe zulassen möchtest, solltest du die in deinem Pattern nicht angeben. In deiner Charakterklasse steht " -." (Leerzeichen, Bindestrich, Punkt). Das definiert den Bereich aller Zeichen zwischen (einschließlich) dem Leerzeichen und dem Punkt. Guck mal in einer ASCII-Tabelle, was da so liegt. (Schreib den Bindestrich ganz ans Ende der Charakterklasse, um so was zu verhindern.)

              PS: "\n\r"? Meinst du "\r\n"?

              PPS: Welches Problem versuchst du eigentlich wirklich zu lösen? Bloß ü’s entfernen wohl nicht.
              Zuletzt geändert von mermshaus; 20.10.2014, 08:38.

              Kommentar


              • #8
                hallo zusammen, vielen Dank für eure Antworten.

                Mit war gar nicht bewusst dass mit (Leerzeichen, Bindestrich, Punkt) einen range automatisch definiere, eigentlich logisch ist mit A-Z auch so. mermshaus der Bindestrich zum Schluss zu bringen hat das Problem mit den Klammern gelöst.

                Jetzt muss ich nur noch die Umlaute erlauben. Was ich eigentlich schaffen will, ist eine Dateiname zu filtern für einen Upload-Tool. Der Admin-User soll, selber die Kriterien setzen welchen Charakter in der Dateiname erlaubt sind oder nicht. Per Default sollte alles verboten werden ausser a-z A-Z, die Umlaute öäü ÖÄÜ éàè ÖÄÜ und zum Schluss den Bindestrich, der Punkt und der Unterstrich. Die Dateiname soll auch auf eine Länge von 200 Zeichen begrenzt werden.

                Mein letztes Test 6 erkennt das Skript leider die Umalute immer noch als sonderzeichen und werden somit mit Unterstrich ersetzt. Wenn aber die Variable $name direkt im Skript editiere, also ohne Übergabe durch Methode, dann klappt.

                PHP-Code:
                // Test 6
                //$name ="(Müller).jpg";
                echo "bin2hex: ".bin2hex($name)."\r\n";             // 284d75cc886c6c6572292e6a7067
                echo "detect1: ".mb_detect_encoding($name)."\r\n";  // Ausgabe: UTF-8
                echo "Ausgabe vorher: ".$name."\r\n";               // Ausgabe: (Müller).jpeg
                $name preg_replace('/[^A-Za-z0-9  öäü éàè ÖÄÜ ÉÀÈ ._ -]/ui''_'$name );
                echo 
                "detect2: ".mb_detect_encoding($name)."\r\n";  // Ausgabe: ASCII
                echo "Ausgabe nachher: ".$name."\r\n";              // Ausgabe faslch: _Mu_ller_.jpg 
                Zuletzt geändert von pippo; 20.10.2014, 14:07.
                In Flames - Pinbal Map
                Becoming the Archetype - No Fall Too Far
                Pantera

                Kommentar


                • #9
                  im übrigens, die Buchstabe "ü" ergibt folgende Ausgabe:

                  PHP-Code:
                  bin2hex75cc88
                  detect1
                  UTF-8
                  Ausgabe vorher
                  ü
                  detect2
                  ASCII
                  Ausgabe nachher
                  u_ 
                  IM Test 7 mit str_replace() taucht das Problem mit der Umlaute ebenso auf:

                  PHP-Code:
                  // Test 7
                  $name str_replace(array("ö","ä","ü"">"), array("---oe---","---ae---","---ue---""groesser"),$name); 
                  Ausgabe von Test 7
                  PHP-Code:
                  Ausgabe vorheröäü>.jpg
                  detect1
                  UTF-8
                  bin2hex
                  6fcc8861cc8875cc883e2e6a7067
                  str_replace
                  (array('ö','ä','ü''>'), array('---oe---','---ae---','---ue---''groesser'),öäügroesser.jpg)
                  Ausgabe nachheröäügroesser.jpg
                  detect2
                  UTF-8
                  bin2hex
                  6fcc8861cc8875cc8867726f65737365722e6a7067 
                  Zuletzt geändert von pippo; 20.10.2014, 14:05.
                  In Flames - Pinbal Map
                  Becoming the Archetype - No Fall Too Far
                  Pantera

                  Kommentar


                  • #10
                    Ich habe nun mit mb_ereg_replace() ausprobiert. Damit werden die Umlaute zugelassen aber nicht nur, zugelassen werden auch zeichen wie <>@'? usw... Darum habe ich diesen vorher manuell mit str_replace() entfernt. Ich denke es geht sicher besser:

                    PHP-Code:
                    // Test 8
                    $name "(<Müll'er> Täst/.jpg";

                    // Böse Zeichen a priori entfernen
                    $badCharacters = array("'"":""<"">""@""("")""?""/");
                    $replaceCharacters = array("""_""_""_""_""""""""_");
                    $name str_replace($badCharacters$replaceCharacters$name); // Ausgabe: __Müller_ Täst_.jpg

                    $name =  mb_ereg_replace('/[^A-Za-z0-9  öäü éàè ÖÄÜ ÉÀÈ ._-]/ui''_'$fileNameWithoutExtension); // Ausgabe: __Müller_ Täst_.jpg 
                    Leider werden nun die Umlaute zugelassen selbst wenn ich den RegExp so anpasse:

                    PHP-Code:
                    // Test 9
                    $name "(<Müll'er> Täst/.jpg";

                    // Böse Zeichen a priori entfernen
                    $badCharacters = array("'"":""<"">""@""("")""?""/");
                    $replaceCharacters = array("""_""_""_""_""""""""_");
                    $name str_replace($badCharacters$replaceCharacters$name); // Ausgabe: __Müller_ Täst_.jpg

                    $name =  mb_ereg_replace('/[^A-Za-z0-9 ._-]/ui''_'$fileNameWithoutExtension); // Ausgabe: __Müller_ Täst_.jpg 
                    Ein reagieren explicit auf Umlaute bleibt also nach wie vor problematisch :-(
                    In Flames - Pinbal Map
                    Becoming the Archetype - No Fall Too Far
                    Pantera

                    Kommentar


                    • #11
                      Das liegt daran, dass deine Variable gar nicht diese Zeichen beinhaltet. Sie sehen nur optisch gleich aus. Siehe auch: Tottaste ? Wikipedia

                      Kurz erklärt:

                      C3 B6 entspricht dem Zeichen "ö" in UTF-8 Kodierung.
                      6F CC 88 entspricht dem Zeichen "o" mit anschließendem " ̈ " in UTF-8 Kodierung.

                      Vergleich: ö / ö

                      Sieht gleich aus, sind aber zwei unterschiedliche Zeichen. Am besten mal in einem Hex-Viewer anschauen.


                      Siehe auch: UAX #15: Unicode Normalization Forms

                      Mögliche Lösung: PHP: Normalizer::normalize - Manual
                      Zuletzt geändert von h3ll; 20.10.2014, 19:03.

                      Kommentar


                      • #12
                        Danke h3ll, ich werde deine Links anschauen und weiter forschen. Es scheint ganz und gar nicht so einfach zu sein wie ich am Anfang dachte.
                        In Flames - Pinbal Map
                        Becoming the Archetype - No Fall Too Far
                        Pantera

                        Kommentar


                        • #13
                          Zitat von h3ll
                          C3 B6 entspricht dem Zeichen "ö" in UTF-8 Kodierung.
                          6F CC 88 entspricht dem Zeichen "o" mit anschließendem " ̈ " in UTF-8 Kodierung.
                          Zur Vollständigkeit: Ersteres ist dabei NFC und Letzteres ist NFD. „Normalerweise“ hat und will man UTF-8 in NFC.

                          Wie man es umwandelt, hat h3ll ja verlinkt.

                          Das hier sind sehr praktische Tools: ishida >> apps (UniView und Code Converter nutze ich ständig, wenn ich mal schnell was nachsehen will.)

                          After some research I found out this is because OSX uses a different UTF character order from Linux. OSX filesystems use Unicode Normalization Form D (NFD), where linux uses Form C (NFC).
                          - macosx - Converting UTF-8 NFD filenames to UTF-8 NFC, in either rsync or afpd - Server Fault

                          Habe das inhaltlich nicht verifiziert, aber du bist nicht zufällig Mac-Nutzer?

                          Zitat von pippo
                          Es scheint ganz und gar nicht so einfach zu sein wie ich am Anfang dachte.
                          Das Handling von zulässigen Dateinamen ist gerade (datei)systemübergreifend ein ziemlicher Albtraum, ja.

                          Kannst auch mal das hier lesen, über das ich gestern zufällig gestolpert bin: Common Mistakes as Python Web Developer | Armin Ronacher's Thoughts and Writings (erster Abschnitt)

                          Kommentar


                          • #14
                            Zitat von pippo Beitrag anzeigen
                            Danke h3ll, ich werde deine Links anschauen und weiter forschen. Es scheint ganz und gar nicht so einfach zu sein wie ich am Anfang dachte.
                            Das liegt in der Hauptsache daran, dass du dir die Aufgabenstellung schwieriger als nötig gemacht hast:

                            Was ich eigentlich schaffen will, ist eine Dateiname zu filtern für einen Upload-Tool. ... Per Default sollte alles verboten werden ausser a-z A-Z, die Umlaute öäü ÖÄÜ éàè ÖÄÜ und zum Schluss den Bindestrich, der Punkt und der Unterstrich. Die Dateiname soll auch auf eine Länge von 200 Zeichen begrenzt werden.
                            Warum begrenzt du die Anzahl der erlaubten Buchstaben? Und warum so willkürlich? Irgendwie glaube ich nicht, dass damit alle Amtssprachen der Schweiz abgedeckt sind (auf entsprechenden Tastaturen kann man mehr eingeben, bspw. "ç" ...).

                            Warum dürfen keine Ziffern enthalten sein?

                            Und was ist mit Leerzeichen? Die sind in Dateinamen unter diversen Dateisystemen erlaubt.

                            Ohne dieses ganze Brimborium wäre ein PCRE relativ einfach zu basteln:
                            PHP-Code:
                            preg_match('/\A(?>\pL\pM*|[\-._]){1,200}\z/u'$input); 
                            Das fängt alle Buchstaben, ob mit Verbindungszeichen kombiniert oder nicht und egal in welcher Normalform. Außerdem natürlich "-", "." und "_". Und in der von dir gewünschten Länge.

                            Ein Regex für komplexere Tabellen lässt sich natürlich bauen, aber dann muss da eben jede "Buchstabenform" separat aufgeführt werden.

                            PHP-Code:
                            $pcre '/\A(
                                # -._ + latin letters
                                [\-._a-z]
                                # combined (acute,gravis,umlaut)
                                |[\xe0\xe1\xe4\xf2\xf3\xf6\xf9\xfa\xfc]
                                # decomposed + accent acute + gravis + umlauts
                                |[aoue][\x{300}\x{301}\x{308}]?
                            )+\z/xiu'
                            ;
                            preg_match($pcre$input); 
                            Das erlaubt ein paar mehr Kombinationen als du haben möchtest. Wenn du wirklich für jeden lateinischen Buchstaben eine extra Tabelle an Kompositionszeichen brauchst, wirds noch komplexer. Prinzipiell machbar, gefällt mir aber nicht ...

                            ... Der Admin-User soll, selber die Kriterien setzen welchen Charakter in der Dateiname erlaubt sind oder nicht. ...
                            Damit könnten dann wieder unerwünschte oder "gefährliche" Zeichen (wie bspw. \x00) vom Benutzer durchgeschleust werden. Ich würde ihm bestenfalls eine Auswahl aus verschiedenen vorgegebenen Zeichenvorräten erlauben. Das erspart dann auch die Prüfung des RegEx auf syntaktische Korrektheit.

                            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.
                            Klingon function calls do not have “parameters”‒they have “arguments”‒and they always win them!

                            Kommentar


                            • #15
                              Hallo fireweasel,

                              du hast es voll auf den Punkt getroffen! ;-) Ich stimme deinen Anmerkungen voll und ganz zu.

                              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); 
                              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. Mit str_repalce() und meiner alten RegExp werden nicht nur die Sonderzeichen ersetzt, sondern leider auch die Umlaute.

                              Ich werde, sobald ein wenig Zeit habe, das mal ausprobieren, solange vielen Dank dafür.
                              In Flames - Pinbal Map
                              Becoming the Archetype - No Fall Too Far
                              Pantera

                              Kommentar

                              Lädt...
                              X