views:

83

answers:

3

I tried on Flex 3, facing issue with uploading JPG/PNG image, trace readUTFBytes would return correct bytes length but tmpFileContent is trucated, it would only appear to have upload just 3 characters of data to the server through PHP script which made image unusable. I have no issue for non-images format. What is wrong here?

var tmpFileContent:String = fileRef.data.readUTFBytes(fileRef.data.length);

Is String capable of handle bytes?

A: 

I'm not sure what you're looking to do with the image, but you might want to read this:

http://livedocs.adobe.com/flex/3/html/help.html?content=Filesystem_15.html

You may also need a image encoder such as the JPEGEncoder: http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/mx/graphics/codec/JPEGEncoder.html

quoo
A: 

You could always encode using base64:

var enc:Base64Encoder = new Base64Encoder();
enc.encodeBytes(fileRef.data);
var base64data:String = enc.drain();
maclema
+1 Base 64 is the way to go here (unless you want to change the backend code to read the raw input so you can post the bytearray directly)
Juan Pablo Califano
Posting data directly would be a lot more efficient. Don't need to spend time encoding to base64 in flash, and will use less bandwidth.
davr
@davr. Maybe. Arguably, sending the raw data will be faster. And, yes, you'll use more bandwidth: exactly an extra third of the original file size. But I've done this and, let me tell you, it's worked great, even with big files. So unless there's an actual performace problem (and especially since the OP seems to have the thing set up already, with AMFPHP and whatnot), there's a benefit in being able to just add a couple of lines of Actionscript and php and have the already set up "system" working for image files.
Juan Pablo Califano
@davr. Although if the php side (read AMFPHP) can handle receiving the object as raw bytes instead of a string transparently and safely (which possibly can, but I don't know really), you could in fact send the bytearray directly from AS and just change file_get_contents if necessary, and ditch the base 64 encoding/decoding altoghether
Juan Pablo Califano
AMFPHP can do it for sure, it's specifically designed to receive data from flash using Adobe's AMF protocol. For example: http://www.sephiroth.it/tutorials/flashPHP/amfphp_bytearray/
davr
@davr. Cool. So, you only have to access the data property of the ByteArray from the php side and write the file. From the example, it seems like the oneliner file_put_contents() could do the job with no problems.
Juan Pablo Califano
A: 

The method used in the tutorial is not going to work safely for anything but text files. An arbitrary binary format is likely to contain zeros. A zero (a byte whose value is 0) is generally considered a string terminator in many languages / platforms. This is also the case in Actionscript as this code shows:

var str:String = "abc\x00def";
trace(str);

The string will be truncated to "abc", since 0x00 is considered to mark the end of a string.

I think your best bet is to encode the content to base 64 as maclema suggested. From the php side, decode it back before writting the file with something like:

file_put_contents($myFilePath, base64_decode($fileData["filedata"]));

Also, I can't remember if file_put_contents is binary safe (I think it's not). If that's the case, you should use fopen('you_path',"wb"), fwrite() and fclose() to write the file. Notice the "b" in "wb", which stands for binary. If you don't pass that flag you'll probably have problems with some characters (newline and carriage return, for example).

Added:

Perhaps, following davr suggestion, you could try sending the data ByteArray to see if AMFPHP handles it correctly.

Php does allow embbeded Nuls in strings as this code shows:

$str = "a\x00b";

var_dump(ord($str{0}));     //  97
var_dump(ord($str{1}));     //  0
var_dump(ord($str{2}));     //  98

So, if AMFPHP converts the bytearray to a string and does not mangle it in the process, this could actually work.

// method saves files on the server
function uploadFiles($fileData) {
    // new file path an name
    // to not overwrite the files we add the microtime before the file name 
    $myFilePath = '../../_uploads/'.
        preg_replace("/[^0-9]+/","_",microtime()).'_'.$fileData["filename"];
    // writing on the disk
    $fp = fopen($myFilePath,"wb");
    if($fp) {
        fwrite($fp,$fileData["filedata"]);
        fclose($fp);
    }
    // returning response - is not used anywhere 
    return true;
} 

Otherwise, try echoing var_dump($fileData['filedata']) to see what the actual type AMFPHP is converting the data to (perhaps it uses an array, not sure; given how strings work in php (much like a buffer of single byte characters, though, I think it could be just using strings).

Juan Pablo Califano