2013-03-22 6 views
5

Próbuję wybrać lokalny plik JPEG w przeglądarce internetowej za pomocą narzędzia FileReader HTML5, aby można było przesłać go na serwer bez ponownego ładowania strony. Wszystkie mechanizmy działają i myślę, że przesyłam i zapisuję dokładne dane, które otrzymałem od JavaScript, ale wynikiem jest nieprawidłowy plik JPEG na serwerze. Oto podstawowy kod, który demonstruje problem:Dane JPEG uzyskane z FileReader nie pasują do danych w pliku

<form name="add_photos"> 
    ​<input type=​"file" name=​"photo" id=​"photo" /><br /> 
    ​<input type=​"button" value=​"Upload" onclick=​"upload_photo()​;​" />​ 
</form> 

<script type="text/javascript"> 
    function upload_photo() { 
     file = document.add_photos.photo.files[0]; 
     if (file) { 
      fileReader = new FileReader(); 
      fileReader.onload = upload_photo_ready; 
      fileReader.readAsBinaryString(file); 
     } 
    } 

    function upload_photo_ready(event) { 
     data = event.target.result; 
     // alert(data); 

     URL = "submit.php"; 
     ajax = new XMLHttpRequest(); 
     ajax.open("POST", URL, 1); 
     ajax.setRequestHeader("Ajax-Request", "1"); 
     ajax.send(data); 
    } 
</script> 

Wtedy mój skrypt PHP wykonuje to:

$data = file_get_contents("php://input"); 
$filename = "test.jpg"; 
file_put_contents($filename, $data); 
$result = imagecreatefromjpeg($filename); 

Ta ostatnia linia generuje błąd PHP „test.jpg nie jest prawidłowym plikiem JPEG.” Jeśli pobierze dane z powrotem na mój komputer Mac i spróbuję otworzyć go w Podglądzie, podgląd mówi, że plik "może być uszkodzony lub użyć formatu pliku, którego podgląd nie rozpoznaje".

Po otwarciu zarówno oryginalnego pliku na pulpicie, jak i przesłanego pliku na serwerze w edytorach tekstowych w celu sprawdzenia ich zawartości, są one prawie, ale nie do końca takie same. Oryginalny plik zaczyna się tak:

ˇÿˇ‡JFIFˇ˛;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90 

Ale Przesłany plik zaczyna tak:

ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90 

Co ciekawe, jeśli przeglądać dane w pogotowiu JavaScript z linią zakomentowanych powyżej, to wygląda podobnie jak dane przesłanego pliku, więc wydaje się, że FileReader nie podaje poprawnych danych na samym początku, w przeciwieństwie do problemu, który został wprowadzony podczas przesyłania lub zapisywania danych na serwerze. Czy ktoś może to wyjaśnić?

Używam Safari 6 i próbowałem również Firefox 14.

UPDATE: Właśnie zorientowali się, że jeśli pominąć kod FileReader i zmienić ajax.send (dane) do ajax.send (pliku), obraz jest przesyłany i zapisywany poprawnie na serwerze. Mój problem jest w zasadzie rozwiązany, ale przyznam punkty odpowiedzi każdemu, kto potrafi wyjaśnić, dlaczego moje oryginalne podejście z readAsBinaryString nie działa.

+2

'alert' nie jest przeznaczony do wyświetlania danych binarnych. A jak "otworzyć plik w edytorze tekstów"? Jakie kodowanie jest używane do dekodowania? –

+1

Pierwsze dwa bajty powinny być 0xFFE0 zgodnie ze specyfikacją pliku jpeg. Dwa bajty są oczywiście interpretowane jako tekst w różny sposób przez twoją przeglądarkę i edytor tekstu. Używają różnych kodowań, a jako distroy mówi się, że tego rodzaju dane nie mają być używane jako tekst. –

+0

Problem polega na tym, że plik zapisany na serwerze nie jest prawidłowym plikiem JPEG. Prześledziłem go przez wszystkie etapy procesu przenoszenia i jest on niepoprawny aż do tego pierwszego kroku. To jest punkt alertu - aby pokazać, że problem najwyraźniej występuje, zanim dane zostaną przesłane na serwer.To, co widzę w oknie alertu, pasuje do danych zapisanych na serwerze, więc uważam, że jest to ważny test. – arlomedia

Odpowiedz

4

Twój problem dotyczy readAsBinaryString. Spowoduje to przeniesienie binarnego bajtu danych na ciąg znaków, tak abyś wysłał ciąg tekstowy do pliku PHP. Teraz ciąg tekstowy zawsze ma kodowanie; i kiedy używasz XmlHttpRequest do przesłania łańcucha, by default it will use UTF-8.

Tak więc każdy znak, który pierwotnie miał reprezentować jeden bajt, będzie zakodowany jako UTF-8 ... który używa wielu bajtów dla każdej litery z kodem powyżej 127!

Najlepiej jest użyć readAsArrayBuffer zamiast readAsBinaryString. Pozwoli to uniknąć wszystkich konwersji zestawów znaków (które są konieczne, gdy dealing with strings).

+0

Podejrzewam, że nazwa readAsArrayBuffer mnie zastraszyła, więc nigdy jej nie wypróbowałem. Ale masz rację, zmieniłem się na to i teraz mój kod działa idealnie. Wyjaśnienie ma również sens. – arlomedia

+1

@arlomedia: [nigdy się nie bój] (http://goo.gl/Kqpkn) o złożonych metodach. Google jest twoim przyjacielem, a dowiesz się! ;-) – Martijn

Powiązane problemy