5

ページをリロードせずにサーバーに送信できるように、HTML5 FileReader を介して Web ブラウザーでローカル JPEG ファイルを選択しようとしています。すべてのメカニズムが機能しており、JavaScript が提供した正確なデータを転送して保存していると思いますが、結果はサーバー上の無効な JPEG ファイルです。問題を示す基本的なコードは次のとおりです。

<form name="add_photos">
    ​&lt;input type=​"file" name=​"photo" id=​"photo" /><br />
    ​&lt;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>

次に、私のPHPスクリプトはこれを行います:

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

その最後の行は、「test.jpg は有効な JPEG ファイルではありません」という PHP エラーをスローします。データを Mac にダウンロードし直して Preview で開こうとすると、Preview はファイルが「破損しているか、Preview が認識しないファイル形式を使用している可能性があります」と表示します。

デスクトップ上の元のファイルとサーバー上のアップロードされたファイルの両方をテキスト エディターで開いて内容を調べると、ほとんど同じではありません。元のファイルは次のように始まります。

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

しかし、アップロードされたファイルは次のように始まります。

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

興味深いことに、上記のコメントアウトされた行を含む JavaScript アラートでデータを表示すると、アップロードされたファイルのデータとまったく同じように見えるため、FileReader が最初から正しいデータを提供していないように見えます。サーバー上でデータを転送または保存する際に発生する問題。誰でもこれを説明できますか?

Safari 6 を使用していますが、Firefox 14 も試しました。

更新: FileReader コードをスキップして ajax.send(data) を ajax.send(file) に変更すると、画像が転送され、サーバーに正しく保存されることがわかりました。したがって、私の問題は基本的に解決されましたが、readAsBinaryString を使用した元のアプローチが機能しなかった理由を説明できる人に回答ポイントを授与します。

4

1 に答える 1

5

あなたの問題はにありますreadAsBinaryString。これにより、バイナリデータがバイト単位で文字列に転送されるため、PHPファイルにテキスト文字列が送信されます。現在、テキスト文字列には常にエンコーディングがあります。XmlHttpRequestを使用して文字列をアップロードすると、デフォルトでUTF-8が使用されます

したがって、元々1バイトを表すことになっていた各文字は、UTF-8としてエンコードされます...これは、127を超えるコードポイントを持つ各文字に複数のバイトを使用します。

readAsArrayBufferの代わりに使用するのが最善ですreadAsBinaryString。これにより、すべての文字セット変換(文字列を処理するときに必要)が回避されます。

于 2013-03-22T12:34:29.680 に答える