2011-03-13 26 views
6

Bir istemci tarafındaki tuval öğesinden bir PHP betiğine bir resim ve bazı form alanları gönderebilmek için $ _POST ve $ _FILES olarak bitebiliriz. Ben böyle gönderdiğinizde:

<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 ve $ _FILES hem doldurulan gel, ama $ _FILES görüntü veriler hala böyle deşifre gerekir: amacıyla ...

$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); 

okunabilir bir PNG olarak kaydedin. Görüntüyü WordPress'in media_handle_upload() işlevine iletmeye çalıştığım bir seçenek değil, bu da okunabilir bir resme işaret eden $ _FILES dizinine ihtiyaç duyuyor. Güvenlik kontrollerinin faulüne düştüğü için, 'tmp_name' kodunu buna göre deşifre edemiyorum, değiştiremiyorum ve değiştiremiyorum.

Yani, bu bulundu: http://www.webtoolkit.info/javascript-base64.html ve istemci tarafında kod çözmeyi yapmaya çalıştım:

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

ama aldığında nedense hala okunabilir bir dosya ile sonunda yok

PHP. Yani soru şu: "Neden?" veya "Neyi yanlış yapıyorum?" veya "Bu mümkün mü?" :-)

Herhangi bir yardım çok takdir!

sayesinde

+0

Bir "Content-Transfer-Encoding: base64" kurar ve [bu yanıtı] (http://stackoverflow.com/questions/934012/get-image-data-in-javascript) adresine bakmak için önek, yine de test etmedim. – Wrikken

+0

@Wrikken Content-Transfer-Kodlaması geçerli bir MIME üstbilgisi olmasına rağmen geçerli bir HTTP üstbilgisi değildir. Speklerin [bu ek] bölümüne bakın (http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.4.5). –

+0

@Nathan: Ack, benim hatam. Bir dosya yüklemesini manuel olarak kurmaya hiç gerek duymadığımmı gösteriyor mu? :) – Wrikken

cevap

4

Bina, ben hala jQuery.ajax geçiyor ki bunu finnagle başardı. Sadece ajax isteği bu ekleyin:

  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; 
      }, 

Temel olarak, sadece o kadar "gönder" değiştirileceğini bir xhr nesneyi geri dönüş "sendAsBinary" anlamına gelir. Sonra jQuery doğru olanı yapar.

+0

Bunun için teşekkürler - sadece bir go verdi ve harika çalışıyor. Bu orijinal proje için Wordpress'ten vazgeçilmişti, ama bunun için yararlı olması gereken bir başka WP var, bu yüzden çok takdir ediyorum efendim! – BaronVonKaneHoffen

+0

http://stackoverflow.com/questions/9915199/download-a-html5-canvas-element-as-an-image-with-the-file-extension-with-javascr/11200935#11200935 adresine bakın. Gerçekten faydalı olabilecek bir cevap yazdım. –

14

Kane Ne yazık ki bu bazı ara kodlama olmadan JavaScript mümkün değildir. Neden olduğunu anlayabilmek için, örneğinizde açıkladığınız gibi, kodu çözdüğünüze ve verileri yayınlayacağınıza karar verelim. Geçerli bir PHP dosyasının hex ilk birkaç satırı aşağıdaki gibi görünebilir:

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

Yüklediğiniz PNG dosyasının hex'in aynı aralıkta baktıysanız, bu şekilde görünecektir:

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

Farklılıklar ince. İkinci satırın ikinci ve üçüncü sütunlarını karşılaştırın. Geçerli dosyada, dört bayt, 0x000x800x000x00. Yüklediğiniz dosyada, aynı dört bayt, 0x000xc20x800x00. Niye ya?

JavaScript dizeleri UTF'dir. Bu, herhangi bir ASCII ikili değerinin (0-127) bir bayt ile kodlandığı anlamına gelir. Bununla birlikte, 128-2047 arası her şey iki bayt alır. Yüklenen dosyadaki bu fazladan 0xc2, bu çok baytlı kodlamanın bir öğesidir. Bunun neden olduğunu tam olarak bilmek istiyorsanız, UTF encoding on Wikipedia hakkında daha fazla bilgi edinebilirsiniz.

JavaScript dizeleri ile bunun olmasını engelleyemez, bu nedenle base64 kullanmadan AJAX yoluyla bu ikili veri yükleyemezsiniz.

DÜZENLEME: Bazı kazı çalışmalarından sonra, bu bazı modern tarayıcılarda mümkündür.Bir tarayıcı XMLHttpRequest.prototype.sendAsBinary destekler (Firefox 3 ve 4), bunu gibi bir görüntü göndermek için kullanabilir edin: sendAsBinary var, ama Uint8Array (Chrome ve WebKit) var tarayıcılar için

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')); 
} 

, bunu gibi polyfill edebilirsiniz: Nathan'ın mükemmel cevap üzerine

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

Ah doğru! Açıklama için teşekkürler! Bu yüzden soru, PHP'nin base64 verilerini göndermeyi denediğimi ve şifresini çözmesi gerektiğini anlatan posta isteğini nasıl oluşturabilirim? Content-Transfer-Encoding: base64'ü (teşekkürler @Wrikken!) Ayarlamayı denedim, ancak tarayıcının bunu yapmayı reddettiği için geçerli bir başlık olmadığını söylediğiniz gibi ("Güvenli olmayan başlığı ayarlamak reddetti"). İçerik-Dispozisyonu'ndan sonra yapabileceğim bir şey var mı? Bir süredir deniyor ama işe yarayan hiçbir şey bulamadım. – BaronVonKaneHoffen

+0

... Ayrıca, burada kafa karıştırıcı buluyorum başka bir şey ben tarayıcı tarafından oluşturulan bir çalışma isteğine baktığımızda (bir resim girişi olan bir formdan), ben herhangi bir görüntü verisi görmüyorum. Sadece 'Content-Disposition: form-data; = "FormField" adını; filename = "picture.png" İçerik türü: image/png' sonra hiçbir şey. Bu veriler nerede? Bu, gerçek görüntü verilerini ayrı bir istekte veya başka bir şeyde aktarmam gerektiği anlamına mı geliyor? Üzgünüz, ben bu tür şeyler için çok yeni ve düzgün bir öğretici bulmak için henüz ... – BaronVonKaneHoffen

+0

@BaronVonKaneHoffen Ben PHP otomatik olarak base64 decode dosyayı almak için bir yol bulmak için oldukça uzun bir süre için onunla karıştırdı. Ben bir tane bulamadım. :(Sunucuya herhangi bir özel PHP yükleyebiliyor musunuz? Eğer yapabilirseniz, bunu çözmek için özel bir komut dosyası ile proxy gönderebilirsiniz. –