2011-03-13 2 views
6

클라이언트 측 캔버스 요소의 이미지와 양식 필드를 $ _POST 및 $ _FILES로 끝나는 PHP 스크립트로 보낼 수 있어야합니다. 나는이처럼 보낼 때 :

<script type="text/javascript"> 
var img = canvas.toDataURL("image/png"); 
... 
ajax.setRequestHeader('Content-Type', "multipart/form-data; boundary=" + boundary_str); 
var request_body = boundary + '\n' 
+ 'Content-Disposition: form-data; name="formfield"' + '\n' 
+ '\n' 
+ formfield + '\n' 
+ '\n' 
+ boundary + '\n' 
+ 'Content-Disposition: form-data; name="async-upload"; filename="' 
+ "ajax_test64_2.png" + '"' + '\n' 
+ 'Content-Type: image/png' + '\n' 
+ '\n' 
+ img 
+ '\n' 
+ boundary; 
ajax.send(request_body); 
</script> 

$ _POST와 $ _FILES 모두 채워 돌아올하지만, $ _FILES의 이미지 데이터는 여전히 같은 디코딩이 필요 :하기 위해 ...

$loc = $_FILES['async-upload']['tmp_name']; 
$file = fopen($loc, 'rb'); 
$contents = fread($file, filesize($loc)); 
fclose($file); 
$filteredData=substr($contents, strpos($contents, ",")+1); 
$unencodedData=base64_decode($filteredData); 

그것을 읽을 수있는 PNG로 저장하십시오. 이것은 이미지를 Wordpress의 media_handle_upload() 함수에 전달하려고 시도하기 때문에 옵션이 아닙니다.이 함수는 읽을 수있는 이미지를 가리키는 $ _FILES에 대한 인덱스가 필요합니다. 나는 또한 보안 검사에 위배되기 때문에 'tmp_name'을 디코딩, 저장 및 변경할 수 없다.

그래서, 나는이 발견 http://www.webtoolkit.info/javascript-base64.html 를 클라이언트 측에서 디코딩을 시도 :

img_split = img.split(",",2)[1]; 
img_decoded = Base64.decode(img_split); 

하지만가 오면 어떤 이유로 난 여전히 읽을 수있는 파일로 끝나지 않는

PHP. 그래서 질문은 "왜?" 또는 "나는 뭘 잘못하고 있니?" 또는 "이것이 가능합니까?" :-)

도움을 주시면 대단히 감사하겠습니다!

감사합니다,

+0

'Content-Transfer-Encoding : base64'를 설정하고 [이 답변] (http://stackoverflow.com/questions/934012/get-image-data-in-javascript)에서 접두사, 비록 그것을 테스트하지 않았습니다. – Wrikken

+0

@Wrikken Content-Transfer-Encoding은 유효한 MIME 헤더가 유효한 HTTP 헤더가 아니지만. 이 사양의 [이 부록 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.4.5)]을 참조하십시오. –

+0

@ 네이선 : 아, 내 실수. 파일 업로드를 수동으로 빌드 할 필요가 없다는 것을 보여줍니까? – Wrikken

답변

4

빌딩, 나는 여전히 jQuery.ajax를 거치지 않는 곳에 finnagle 할 수 있었다. 그냥 아약스 요청이 추가

  xhr: function() { 
       var myXHR = new XMLHttpRequest(); 
       if (myXHR.sendAsBinary == undefined) { 
        myXHR.legacySend = myXHR.send; 
        myXHR.sendAsBinary = function (string) { 
         var bytes = Array.prototype.map.call(string, function (c) { 
          return c.charCodeAt(0) & 0xff; 
         }); 
         this.legacySend(new Uint8Array(bytes).buffer); 
        }; 
       } 
       myXHR.send = myXHR.sendAsBinary; 
       return myXHR; 
      }, 

기본적으로, 당신은 단지 있도록 "보내기"를 오버라이드 (override)되는 XHR 객체를 다시 반환 "sendAsBinary"는 것을 의미한다. 그렇다면 jQuery가 올바른 일을합니다.

+0

고마워요. 그냥 해 줘서 잘 작동합니다. 이 프로젝트는 Wordpress를 포기한 것으로 끝났지 만, WP가 유용 할 것이라는 점을 알아 냈습니다. 그래서 대단히 감사합니다! – BaronVonKaneHoffen

+0

http://stackoverflow.com/questions/9915199/download-a-html5-canvas-element-as-an-image-with-the-file-extension-with-javascr/11200935#11200935를 확인하십시오. 정말 도움이 될만한 답변을 게시했습니다. –

14

케인은 불행하게도,이 몇 가지 중간 인코딩없이 자바 스크립트에서 할 수 없습니다. 왜 그런지 이해하기 위해 예제에서 설명한 것처럼 base64를 디코딩하여 게시했다고 가정 해 보겠습니다. 유효한 PHP 파일의 진수의 처음 몇 줄은 다음과 같습니다

0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR 
0000010: 0000 0080 0000 0080 0806 0000 00c3 3e61 ..............>a 

당신이 업로드 PNG 파일의 진수의 동일한 범위 보았다한다면 다음과 같을 것이다 :

0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR 
0000010: 0000 00c2 8000 0000 c280 0806 0000 00c3 ................ 

차이점은 미묘합니다. 두 번째 줄의 두 번째와 세 번째 열을 비교하십시오. 유효한 파일에서 4 바이트는 0x000x800x000x00입니다. 업로드 한 파일에서 동일한 4 바이트는 0x000xc20x800x00입니다. 왜?

JavaScript 문자열은 UTF입니다. 즉 ASCII 바이너리 값 (0-127)은 1 바이트로 인코딩됩니다. 그러나 128-2047은 이고 두 개는 바이트입니다. 업로드 된 파일에있는이 0xc2은이 멀티 바이트 인코딩의 아티팩트입니다. 이 문제의 원인을 정확히 알고 싶다면 UTF encoding on Wikipedia에 대해 더 자세히 읽어 보시기 바랍니다.

JavaScript 문자열로 인해 발생하지 않도록 할 수 없으므로 base64를 사용하지 않고 AJAX를 통해이 바이너리 데이터를 업로드 할 수 없습니다.

편집 : 더 자세히 살펴보면 일부 최신 브라우저에서 가능합니다.브라우저가 XMLHttpRequest.prototype.sendAsBinary 지원 (파이어 폭스 3, 4), 당신과 같이 이미지를 보내려면이를 사용할 수있는 경우 : sendAsBinary을 가지고 있지만 Uint8Array (크롬과 웹킷)가하지 않는 브라우저의 경우

function postCanvasToURL(url, name, fn, canvas, type) { 
    var data = canvas.toDataURL(type); 
    data = data.replace('data:' + type + ';base64,', ''); 

    var xhr = new XMLHttpRequest(); 
    xhr.open('POST', url, true); 
    var boundary = 'ohaiimaboundary'; 
    xhr.setRequestHeader(
    'Content-Type', 'multipart/form-data; boundary=' + boundary); 
    xhr.sendAsBinary([ 
    '--' + boundary, 
    'Content-Disposition: form-data; name="' + name + '"; filename="' + fn + '"', 
    'Content-Type: ' + type, 
    '', 
    atob(data), 
    '--' + boundary + '--' 
    ].join('\r\n')); 
} 

, 당신이 그렇게처럼 polyfill 수 있습니다 나단의 훌륭한 대답에

if (XMLHttpRequest.prototype.sendAsBinary === undefined) { 
    XMLHttpRequest.prototype.sendAsBinary = function(string) { 
    var bytes = Array.prototype.map.call(string, function(c) { 
     return c.charCodeAt(0) & 0xff; 
    }); 
    this.send(new Uint8Array(bytes).buffer); 
    }; 
} 
+0

아 맞아! 설명 주셔서 감사합니다! 그래서 질문은 게시 요청을 어떻게 작성하여 PHP가 base64 데이터를 보내려고하는지 알 수 있도록 해독 해 야합니다. 나는'Content-Transfer-Encoding : base64' (감사합니다 @Wrikken!) 설정을 시도했지만 브라우저가 그것을 거부하는 유효한 헤더가 아니라고 말한 것처럼 ("안전하지 않은 헤더를 설정하는 것을 거부했습니다"). 내가 할 수있는'Content-Disposition' 이후에 넣을 수있는 것이 있습니까? 잠시 동안 실험했지만 아무 것도 발견하지 못했습니다. – BaronVonKaneHoffen

+0

... 또한 여기에서 혼란스러워하는 또 다른 점은 브라우저 자체에서 생성 된 작업 요청을 볼 때 (이미지 입력이있는 양식에서) 이미지 데이터가 표시되지 않는 경우입니다. 단지'Content-Disposition : form-data; name = "formfield"; filename = "picture.png"Content-type : image/png' 다음에는 아무 것도 없습니다. 이 데이터는 어디에 있습니까? 그것은 내가 별도의 요청 또는 실제 이미지 데이터를 전송해야한다는 것을 의미합니까? 죄송합니다. 저는 이런 종류의 물건에 익숙하지 않고 괜찮은 튜토리얼을 아직 찾지 못했습니다. – BaronVonKaneHoffen

+0

@BaronVonKaneHoffen PHP를 자동으로 base64로 디코딩하는 방법을 찾기 위해 오랫동안 혼란 스러웠습니다. 나는 하나를 찾을 수 없었다. (사용자 정의 PHP를 서버에 업로드 할 수 있습니까? 가능한 경우 사용자 정의 스크립트를 통해 요청을 프록시하여 디코드 할 수 있습니다.) –

관련 문제