DIrk H.: Javascript Ajax Upload Sonderzeichen

Hallo,

habe leider ein Problem das ich alleine nicht gelöst bekomme.

Ich übertrage mit einem XMLHttpRequest eine Formular. Im Formular ist nur ein Input Field und ein File Object.

Die Daten werden mit PHP ausgewertet. Die Werte aus dem Input Feld können mit

utf8_encode( $_POST["testData"] )

ohne Probleme ausgewertet werden. Allerdings wird der Dateiname anscheinend in einem anderen Format übertragen. Hier schaffe ich es nicht den String "sauber" anzuzeigen.

Ist hier etwa ein Unterschied??

Bin für jeden Tipp dankbar! Danke für Eure Hilfe!

Dirk

  1. Lieber DIrk,

    Pro-Tipp: JavaScript-, HTML- und PHP-Dateien sind in UTF8 kodiert gespeichert. Das HTML-Dokument, welches an den Browser geliefert wird, wird auch als UTF8 deklariert (passendes meta-Element). Umlaute werden deshalb überall als UTF8-kodierter String behandelt.

    Liebe Grüße,

    Felix Riesterer.

    1. Habe schon viel über die Kodierung gelesen...auch schon einiges probiert ;-)

      Aber warum wird der String richtig übertragen und der Dateiname macht Probleme??

      1. Moin!

        Aber warum wird der String richtig übertragen und der Dateiname macht Probleme??

        Ich habe meine Kristallkugel aus Mitleid einem Anwalt geschenkt.

        Kannst Du das Wesen der Probleme irgendwie näher beschreiben und uns Deinen Code zeigen? Dieses utf8_encode macht mir nämlich Sorgen.

        Jörg Reinholz

        1. Hier ein paar Zeilen code...

          upload.php:

          <?PHP
          
          	header("Content-Type: text/html; charset=utf-8");
          
          
          	if( $_GET["testData"] )
          
          			$DATA = $_GET["testData"];
          	else
          			$DATA = 'Täst';
          
          	
          	
          	echo "	<HTML>
          			
          			<HEAD>
          			
          			<SCRIPT>
          
          
          			function filelistChange()
          			{
          				var fileList = document.getElementById('fileA').files;
          
          				var file = fileList[0];
          
          				
          				document.getElementById('fileinfo').innerHTML = file.type + ' - ' + parseInt(file.size/1024) + 'kb';
          				document.getElementById('files_result_output').style.display = 'block';
          
          				
          
          				var formData = new FormData();
          
          				client = new XMLHttpRequest();
          
          
          				var prog = document.getElementById('progress');
          				prog.value = 0;
          				prog.max = 100;
          
          				var proz = document.getElementById('prozent');				
          				proz.innerHTML = '0%';
          
          
          				
          				formData.append('datei', file );
          				formData.append('testData', file.name );
          
          				
          
          
          				client.onerror = function(e) {
          				
          					alert( e );
          				};
          
          				client.onload = function(e) {
          
          					proz.innerHTML = '100%';
          					prog.value = prog.max;
          
          					location.href = 'upload.php?action=done';
          				};
          
          				client.upload.onprogress = function(e) {
          
          					var p = Math.round(100 / e.total * e.loaded);
          					prog.value = p;            
          					proz.innerHTML = p + '%';
          				};
          
          				client.onabort = function(e) {
          	
          					prog.value =   0;
          					prog.max   = 100;
          					document.getElementById('prozent').innerHTML = '0%';					
          				};
          
          				client.open('POST', 'uploadFile.php');
          				client.send(formData);
          
          			}
          			
          			</SCRIPT>
          							
          			</HEAD>
          
          			<BODY>
          
          			<FORM>
          
          				<INPUT id='testData' name='testData' value='" . $DATA . "'>
          			
          				<INPUT type='file' id='fileA' onChange='filelistChange()'>
          		
          				<INPUT type='submit'>
          
          
          				<DIV id='files_result_output' style='display:none'>
          					<span id='fileinfo'></span>
          					<progress id='progress'></progress> <span id='prozent'></span>
          				</DIV>
          	
          			</FORM>
          
          			</BODY>
          			
          			</HTML>";
          
          ?>
          

          uploadFile.php:

          <?PHP
          
          	header("Content-Type: text/html; charset=utf-8");
          
          	
            
          	$f = fopen("uploadFile.log","w");
          
          
           		
          				
          		$ORG = $_FILES['datei']['tmp_name'];
          		$DST = $_FILES['datei']['name'];
          		$TST = $_POST["testData"];
          
          		fwrite($f,"org=" . $ORG . "\n" );
          		fwrite($f,"dst=" . $DST . "\n" );
          		
          		fwrite($f,"tst=" . utf8_decode( $TST ) . "\n" );
          	
          	
          		fclose($f);
          
          ?>
          
          1. Mir ist noch aufgefallen das es mit einem Safari Browser funktioniert aber mit dem Chrome nicht!

            1. Moin!

              Mir ist noch aufgefallen das es mit einem Safari Browser funktioniert aber mit dem Chrome nicht!

              Definiere "funktioniert".

              fwrite($f,"tst=" . utf8_decode( $TST ) . "\n" );
              

              ziemlicher Unsinn. Was willst Du damit erreichen? Was das auch sei:

              <?PHP
                  header("Content-Type: text/html; charset=utf-8");
                  if( ! empty($_GET["testData"]) ) {
                       $DATA = $_GET["testData"];
                  } else {
                      $DATA = 'Täst';
                  }
              ?>
              <HTML>
                  <HEAD>
                      <SCRIPT>
                          function filelistChange()  {
                              var fileList = document.getElementById('fileA').files;
                              var file = fileList[0];
                              document.getElementById('fileinfo').innerHTML = file.type + ' - ' + parseInt(file.size/1024) + 'kb';
                              document.getElementById('files_result_output').style.display = 'block';
                              var formData = new FormData();
                              client = new XMLHttpRequest();
                              var prog = document.getElementById('progress');
                              prog.value = 0;
                              prog.max = 100;
                              var proz = document.getElementById('prozent');
                              proz.innerHTML = '0%';
                              formData.append('datei', file );
                              formData.append('testData', file.name );
                              client.onerror = function(e) {
                                  alert( e );
                              };
              
                              client.onload = function(e) {
                                  proz.innerHTML = '100%';
                                  prog.value = prog.max;
                                  //location.href = '?action=done';
                                  document.getElementById('antwort').innerHTML=client.response;
                              };
              
                              client.upload.onprogress = function(e) {
                                  var p = Math.round(100 / e.total * e.loaded);
                                  prog.value = p;
                                  proz.innerHTML = p + '%';
                              };
              
                              client.onabort = function(e) {
                                  prog.value =   0;
                                  prog.max   = 100;
                                  document.getElementById('prozent').innerHTML = '0%';
                              };
              
                              client.open('POST', 'uploadFile.php');
                              client.send(formData);
                          }
                      </SCRIPT>
                  </HEAD>
                  <BODY>
                      <FORM action='uploadFile.php'>
                          <INPUT id='testData' name='testData' value='<?php echo $DATA; ?>'>
                          <INPUT name="datei" type='file' id='fileA' onChange='filelistChange()'>
                          <INPUT type='submit'>
                              <DIV id='files_result_output' style='display:none'>
                              <span id='fileinfo'></span>
                              <progress id='progress'></progress> <span id='prozent'></span>
                          </DIV>
                          <pre id="antwort"></pre>
                      </FORM>
                  </BODY>
              </HTML>
              

              und die uploadFile.php:

              <?php
              header("Content-Type: text/html; charset=utf-8");
              $FILEINFO['fileName'] = $_FILES['datei']['name'];
              $FILEINFO['fileSize'] = filesize($_FILES['datei']['tmp_name']);
              $FILEINFO['mimeType'] = mime_content_type($_FILES['datei']['tmp_name']);
              print_r($FILEINFO);
              

              ... bringen ohne den Unsinn die zu erwarteten Ergebnisse.

              Alternativ-Text

              Ich habe versucht so nah wie möglich an Deinem Ausgangsskript zu bleiben. Es fehlt also jeder Versuch, mit Fehlern umzugehen.

              Jörg Reinholz

              1. @@Jörg Reinholz

                            <INPUT id='testData' name='testData' value='<?php echo $DATA; ?>'>
                

                Das ist jetzt nicht dein Ernst, oder?

                LLAP 🖖

                --
                „Wir haben deinen numidischen Schreiber aufgegriffen, o Syndicus.“
                „Hat auf dem Forum herumgelungert …“
                (Wachen in Asterix 36: Der Papyrus des Cäsar)
                1. Moin!

                  Nee, nicht meiner. Ich musste ja vom Original was übriglassen.

                  Jörg Reinholz

          2. Moin!

            Und was (bitte) soll das Zeug eigentlich tun?

            Jörg Reinholz

          3. Lieber DIrk,

            header("Content-Type: text/html; charset=utf-8");

            OK, Du sendest ein UTF8-kodiertes Dokument an den Browser. Sind die Daten auch UTF8?

            echo " <HTML> <HEAD> <SCRIPT>

            Was soll das denn sein? HTML in der Ur-Version von 1992, oder HTML 2.0 von 1995, oder HTML3.0? Ohne Doctype können Browser damit machen, was sie für richtig halten. Da Du bei <SCRIPT> keine type-Angabe machst, setzt Du offensichtlich JavaScript voraus, was meines Wissens erst ab HTML5 vorausgesetzt werden darf. Daher empfehle ich Dir dringend einen korrekten Doctype zu verwenden!

            Desweiteren schreibt man die Elementnamen spätestens seit HTML5 klein. Du solltest ohnehin nur noch HTML5 verwenden (s.o.), dann sollte jeder derzeit aktuelle Browser auch keinen Bockmist mit Deinem Dokument anstellen.

            uploadFile.php: [...] header("Content-Type: text/html; charset=utf-8");

            Auch hier wieder sendest Du die korrekte Zeichenenkodierung. Soweit gut.

              fwrite($f,"tst=" . utf8_decode( $TST ) . "\n" );
            

            WTF?? Warum änderst Du hier etwas an der UTF8-Kodierung? Was soll das denn bitteschön? Du solltest vollumfänglich alles in UTF8 handhaben! Sonst knallt es Dir irgendwann um die Ohren.

            Solltest Du unter Windows testen, könnte es einen Sinn haben, den Dateinamen (aber nur diesen!!) von UTF8 nach ISO-8859-1 zu konvertieren, da Windows meines Wissens in seinem Dateisystem UTF8 nicht unterstützt. Aber auf einem Produktiv-System wird sicherlich irgend ein unixoides System (Linux, BSD oder gar Solaris) eingesetzt werden, welches mit UTF8 einwandfrei klar kommt.

            Wenn Du die gespeicherten Daten (den Dateiinhalt) nicht korrekt anschauen kannst, da Deine Windows-Version einen nicht-UTF8-fähigen Texteditor (Notepad) hat, dann nimm eben einen, der das kann, und stelle ihn als Standardprogramm für alle Arten von Textdateien ein.

            Liebe Grüße,

            Felix Riesterer.

            1. Hallo,

              Solltest Du unter Windows testen, könnte es einen Sinn haben, den Dateinamen (aber nur diesen!!) von UTF8 nach ISO-8859-1 zu konvertieren, da Windows meines Wissens in seinem Dateisystem UTF8 nicht unterstützt.

              unter Windows ist das tatsächlich etwas kompliziert.

              Windows hat vieles von DOS geerbt, unter anderem das Dateisystem. In Windows-Versionen seit 4.0 gibt es alle API-Funktionen, die mit Dateinamen umgehen, in zwei Ausführungen: Einmal die traditionelle, die eine Ein-Byte-Codierung verwendet (z.B. Windows-1252, in Windows selbst meist oberflächlich ANSI genannt), und dann die moderne, die von UCS-2 ausgeht (eine Untermenge von UTF-16).
              Auf dem Datenträger selbst werden Dateinamen generell in UCS-2 gespeichert, wenn man mal davon absieht, dass je nach Systemeinstellung der Abwärtskompatibilität wegen immer noch zusätzlich ASCII-codierte Kurznamen im 8.3-Format erzeugt werden.

              Diese Weisheit nützt einem als PHP-Programmierer aber nichts, weil PHP unter Windows noch die alten Dateisystemfunktionen verwendet. Überall da, wo man in PHP Dateinamen an eine Betriebssystemfunktion übergibt, z.B. fopen(), müssen diese also Windows-1252 oder einer vergleichbaren ISO-8859-x-Codierung vorliegen.

              UTF-8 wird vom Windows-API gar nicht unterstützt. Egal ob man die Dateisystemfunktionen nach altem oder neuem Strickmuster verwendet - übergibt man in UTF-8 codierte Namen an Windows, kommt Unsinn dabei raus. Bei den neuen auf UCS-2 ausgelegten Funktionen generell, bei den alten nur, wenn Zeichen mit Codes oberhalb von 0x80 auftreten. Umlaute werden dann plötzlich als Doppelzeichen dargesetellt, wie es hier wohl alle kennen, wenn ein UTF-8-Dokument fälschlicherweise als ISO-8859-x interpretiert wird.

              Das nur als Ergänzung ...

              So long,
               Martin

              1. Moin!

                Wenn es tatsächlich so ist, dass er die Dateinamen umkodieren muss um die Dateien auf einem Windows-OS zu speichern (Ich habe keine Ahnung, da ich PHP unter Windows nicht benutze) dann ist iconv das Mittel der Wahl:

                <?php
                // notiert in utf8!
                $text='Wündows ißt döff und köstet vile €';
                echo iconv("UTF-8", "cp1252", $text), PHP_EOL;
                echo iconv("UTF-8", "WINDOWS-1252", $text), PHP_EOL;
                echo iconv("WINDOWS-1252","UTF-8", iconv("UTF-8", "cp1252", $text)), PHP_EOL;
                

                exec():

                $ php testü.php 
                W�ndows i�t d�ff und k�stet vile �
                W�ndows i�t d�ff und k�stet vile �
                Wündows ißt döff und köstet vile €
                
                

                Jörg Reinholz

                1. Moin!

                  Wenn es tatsächlich so ist, dass er die Dateinamen umkodieren muss um die Dateien auf einem Windows-OS zu speichern (Ich habe keine Ahnung, da ich PHP unter Windows nicht benutze) dann ist iconv das Mittel der Wahl:

                  Ohne Rätselraten können wir zweifelsfrei fesstellen, dass bei einem FileUpload 2 (in Worten: Zwei) Systeme im Spiel sind, deren Zeichenkodierung ggf. verschieden sein kann. Das hat mit PHP zunächst gar nichts zu tun.

                  1. Hi,

                    Ohne Rätselraten können wir zweifelsfrei fesstellen, dass bei einem FileUpload 2 (in Worten: Zwei) Systeme im Spiel sind, deren Zeichenkodierung ggf. verschieden sein kann. Das hat mit PHP zunächst gar nichts zu tun.

                    korrekt, wir haben zunächst mal die Schnittstelle Client vs. Server, an der auch schon so einiges schiefgehen kann.

                    Die ebenfalls problematische Schnittstelle PHP vs. Windows-API kommt erst einen Schritt weiter ins Spiel; die hatte ich aber auch ausdrücklich nur als Ergänzung zum Beitrag von Felix gemeint, der die Problematik der Dateinamen unter Windows bereits angedeutet hat.

                    So long,
                     Martin

                    1. Wenn wir Glück haben, befinden sich Client und Server auf einer Maschine ;)

                  2. Moin!

                    Das hat mit PHP zunächst gar nichts zu tun.

                    Na. Mir wäre aber neu, dass ein Browser den Dateiname beim Senden nicht in das für Webseite verwendete charset umkodiert. Wenn jetzt clientseitig etwas anderes User-Agent am arbeiten ist (z.B. wget, curl,...) dann ist es der Job des Programmierers (des diesen Client steuernden Skriptes) bzw. des Anwenders, die Post-Daten richtig zu kodieren, der baut den Request ja selbst zusammen.

                    Ich habes deshalb mal umgekehrt gebaut:

                    <?PHP
                        #header("Content-Type: text/html; charset=utf-8");
                        header("Content-Type: text/html; charset=ISO-8859-15");
                        $maxPostSize=ini_get('post_max_size');
                        $maxFileSize=ini_get(' upload_max_filesize');
                        if ($maxPostSize < $maxFileSize) {
                            $maxFileSize = $maxPostSize;
                        }
                    ?>
                    <HTML>
                        <HEAD>
                            <SCRIPT>
                                function filelistChange()  {
                                    var fileList = document.getElementById('fileA').files;
                                    var file = fileList[0];
                                    //document.getElementById('fileinfo').innerHTML = file.type + ' - ' + parseInt(file.size/1024) + 'kb';
                                    document.getElementById('antwort').innerHTML = 'in Arbeit ...';
                                    var formData = new FormData();
                                    client = new XMLHttpRequest();
                                    var prog = document.getElementById('progress');
                                    prog.value = 0;
                                    prog.max = 100;
                                    var proz = document.getElementById('prozent');
                                    proz.innerHTML = '0%';
                                    formData.append('datei', file );
                                    formData.append('testData', file.name );
                                    client.onerror = function(e) {
                                        alert( e );
                                    };
                    
                                    client.onload = function(e) {
                                        proz.innerHTML = '100%';
                                        prog.value = prog.max;
                                        //location.href = '?action=done';
                                        document.getElementById('antwort').innerHTML=client.response;
                                    };
                    
                                    client.upload.onprogress = function(e) {
                                        var p = Math.round(100 / e.total * e.loaded);
                                        prog.value = p;
                                        proz.innerHTML = p + '%';
                                    };
                    
                                    client.onabort = function(e) {
                                        prog.value =   0;
                                        prog.max   = 100;
                                        document.getElementById('prozent').innerHTML = '0%';
                                    };
                    
                                    client.open('POST', 'uploadFile.php');
                                    client.send(formData);
                                }
                            </SCRIPT>
                        </HEAD>
                        <BODY>
                            <FORM  enctype="multipart/form-data" action='uploadFile.php?noscript=1'>
                                <input type="hidden" name="MAX_FILE_SIZE" value='<?php echo $maxFileSize; ?>' />
                                <INPUT name="datei" type='file' id='fileA' onChange='filelistChange()'>
                                <noscript><INPUT type='submit'></noscript>
                                    <progress id='progress' value="0" max="100" ></progress> <span id='prozent'></span>
                                <pre id="antwort"></pre>
                            </FORM>
                        </BODY>
                    </HTML>
                    
                    <?php
                    ## fileUpload.php
                    set_error_handler( function($errNo, $errStr, $errFile=__FILE__, $errLine=__LINE__) {
                        header("Cache-Control: no-store, no-cache, must-revalidate");
                        header($_SERVER['SERVER_PROTOCOL'].'/1.1 500');
                        header("Status: 500");
                        #header('Content-Type: text/plain; charset=utf-8');
                        header("Content-Type: text/plain; charset=ISO-8859-15");
                        echo $errStr;
                        exit;
                    }, E_ALL);
                    
                    header("Content-Type: text/plain; charset=utf-8");
                    
                    if (! empty($_FILES['datei']) ) {
                        $FILEINFO['fileName'] = $_FILES['datei']['name'];
                        $FILEINFO['fileSize'] = filesize($_FILES['datei']['tmp_name']);
                        $FILEINFO['mimeType'] = mime_content_type($_FILES['datei']['tmp_name']);
                        $scanaction = 'clamscan --quiet "' . $_FILES['datei']['tmp_name'] . '" 1> /dev/null 2> /dev/null; echo $?';
                        $FILEINFO['VirenScan'] = trim(`$scanaction`);
                        print_r($FILEINFO);
                    } else {
                        header('HTTP/1.1 500 Script Generated Error');
                        echo "Fehler beim Upload.\n";
                    }
                    
                    
                    if (! empty($_GET['noscript']) && 1==$_GET['noscript'] ) {
                        echo "Benutzen Sie den Zurück-Button um zum Upload-Formular zurück zu kehren.\n";
                    }
                    

                    Ergebnis?

                    Alternativ-Text

                    ... passt.

                    Jörg Reinholz

                    1. Moin!

                      Das hat mit PHP zunächst gar nichts zu tun.

                      Na. Mir wäre aber neu, dass ein Browser den Dateiname beim Senden nicht in das für Webseite verwendete charset umkodiert.

                      Eben. Wenn ein Browser umkodieren kann und ein anderer nicht, ist das eben ein lokales Problem.

                      Schönes Wochenende.

                      --
          4. @@DIrk H.

            Hier ein paar Zeilen code...

            Und da ist er auch schon wieder, der Kapitalfehler.

            	if( $_GET["testData"] )
            
            			$DATA = $_GET["testData"];
            	else
            			$DATA = 'Täst';
            

            Hier weist du der Variablen $DATA die Nutzereingabe (sofern vorhanden) zu.

            echo "  <HTML>
                    ⋮
                      <INPUT id='testData' name='testData' value='" . $DATA . "'>
            

            Und hier gibt du die Nutzereingabe unbehandelt als HTML aus – einschließlich Schadcode (JavaScript), den jeder nach Belieben einschleusen kann. Sicherheitsloch der Größe eines Hangartores. Deshalb:

            Niemals Daten unbehandelt mit PHP in HTML schreiben!!

            Du musst Daten vor der Ausgabe in HTML unbedingt mit htmlspecialchars() behandeln:

            echo "  <HTML>
                    ⋮
                      <INPUT id='testData' name='testData' value='" . htmlspecialchars($DATA) . "'>
            

            LLAP 🖖

            --
            „Wir haben deinen numidischen Schreiber aufgegriffen, o Syndicus.“
            „Hat auf dem Forum herumgelungert …“
            (Wachen in Asterix 36: Der Papyrus des Cäsar)
  2. Dateinamen sind eine lokale Angelegenheit. Schau doch ersteinmal nach welche Zeichenkodierung Dein PC verwendet, also Konsole, Dateimanager usw.

    Erst wenn du die lokale Kodierung kennst, kannst du zielgerichtet umkodieren z.b. von cp850 nach utf-8.