Multipart form data in as3 [Class version 1.2]

During my last project I faced a problem to upload multipart/form-data to server using Flash. I need to do it using ActionScript only. The idea was to send to server an image generated in flash and several variables but all this data had to be POST.
I found several projects that were using Flash Socket to send multipart requests to server but the problem was that sockets required custom server configuration to work. As you understand we cant ask remote service to reconfigure their system only because we need it.
So the only way was to build your own custom URLLoader class (not socket) to send multipart form data. Ok, no more words (I hate all this typings) here is simple but usefull (as I think) MultipartURLLoader class. You will find source and small samples with php script inside.
Unfortunately there is a problem getting progress event. We cant show any progress during sending data to server because flash doesnt support it. (the same problem with sockets)

LATEST VERSION UPLOADED TO GOOGLE CODE

UPDATES:
version 1.1
- Added options for MIME-types (default is application/octet-stream)
version 1.2
- Added clearVariables and clearFiles methods
- Small code refactoring
- Public methods documentaion

in short we can add variables and files to loader class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import flash.utils.ByteArray;
import ru.inspirit.net.MultipartURLLoader;
 
var data1:ByteArray = new ByteArray();
data1.writeUTFBytes("This is a test 1");
data1.position = 0;
 
var data2:ByteArray = new ByteArray();
data2.writeUTFBytes("This is a test 2");
data2.position = 0;
 
var ml:MultipartURLLoader = new MultipartURLLoader();
ml.addEventListener(Event.COMPLETE, onReady);
 
function onReady(e:Event):void
{
	// Upload Complete
}
 
// simple string data
ml.addVariable('test', 'test variable');
 
// file data: ByteArray, File name, Name of the file field, content MIME type (default application/octet-stream)
// use [] if you need identical file field name
// specify MIME type for your file part
ml.addFile(data1, 'test1.txt', 'Filedata[]');
ml.addFile(data2, 'test2.txt', 'Filedata[]', 'text/plain');
 
ml.load('test.php');

48 Responses to “Multipart form data in as3 [Class version 1.2]”


  1. 1 llops

    Wow, nice work!

    MarstonStudio wrote a similar class for multipart data in AS3 without sockets, but he only sends one file and one object.
    I was looking to modify the class, but your class is perfect! Thanks :)

  2. 2 zlatko

    Hi! Nice work, thx! Just a remark: i cant catch any event from it…

  3. 3 Eugene

    @zlatko
    can you be more specified in your problem? what you send and what is your receive script?

  4. 4 zlatko

    @Eugene

    Yep, sure

    var req:MultipartURLLoader = new MultipartURLLoader();
    req.addEventListener(Event.COMPLETE, _onReady); // never catched
    req.addFile(someByteArray, "1.jpg", "file_1", "image/jpeg");
    req.load(someURL);

    Also i try to set breakpoint into MultipartURLLoader.onComplete(), but never reached it..

    Hm…Maiby “image/jpeg” damage it?

  5. 5 Eugene

    @zlatko
    and what about your server script? it returns anything? As far as i know u should return anything so flash will see that everythink is ok. simple
    echo ‘ok’;
    is enough

    also have u tried not to use content type? and use default one?

  6. 6 zlatko

    @Eugene

    Yes, server script return some text. Also i try to use default header but nothing change… On server side we use nginx. Maiby it binded with that problem…

  7. 7 Eugene

    Thats strange I cant test it on nginx. But eveything is ok on my server. it sends data and fires Complete event…

  8. 8 zlatko

    @Eugene
    I clear that by changing value of ‘useWeakReference’ param on false in addEvenetListener for Event.COMPLETE.

  9. 9 Eugene

    @zlatko
    Thanx for posting that! I’ve updated my svn repo setting useWeakReference to false.
    the latest version currently on my google code repo.

  10. 10 zlatko

    @Eugene
    Sounds good ;-)
    It will be greate to see in future release some alike async upload, becouse now, if i want to send big file my environment go into sleep mode :-)

  11. 11 Eugene

    @zlatko
    yep. huge file uploading is a problem. :( but this class was designed to mirror web forms posting method. so the feature of partly uploading is required custom server side specially done for this class.

  12. 12 Mark Ledford

    Thanks for the handy class Eugene.
    2 things I noticed:

    You have urlRequest.requestHeaders.push( new URLRequestHeader( ‘Cache-Control’, ‘no-cache’ ) ); but I don’t believe this is necessary as it is a POST request. This was causing an issue for me as the swf doesn’t reside on the same server as the script and I was receiving:

    Error #2044: Unhandled securityError:. text=Error #2170: Security sandbox violation: http://domain1/swf.swf cannot send HTTP headers to http://domain2.com/script.php.

    This can be resolved by adding a variation of to the crossdomain.xml file but it was easier for me to comment out that line.

    2. It doesn’t seam possible to configure the returned dataFormat or even get the server response with the current MultipartURLLoader. I think this class should extend URLLoader directly so that these things are accessible.

    Thanks,
    Mark

  13. 13 zlatko

    @Eugene
    Hi! I mean some async preparing file for sending… I have sleep mode in that part, actually in getFilePartData() method…When file is huge there is long cycle that freeze my FlashPlayer….

    p.s. sorry for my poor English
    p.p.s. могу по русски поробовать ;-)

  14. 14 Eugene

    ага) по русски лучше конечно!)

    я тебя понял. это решит проблему с недоступностью флэша. Но я так понимаю что когда ты кодируешь этот кусок ByteArray который ты потом передаешь лоадеру у тебя тоже должно все подвисать. Ты же его как-то создаешь прежде чем отдать на загрузку? Обычно это случается при генерации большой картинки в PNG например.

  15. 15 zlatko

    Хе хе) не подвисает потому что юзаю что-то типа етого: http://www.switchonthecode.com/tutorials/flex-tutorial-an-asynchronous-jpeg-encoder
    Тоисть асинхронный энкодер..было бы круто повторить в твоем класе ;-)

  16. 16 Eugene

    Thanx, Mark
    I’m going to rewrite class to add async data object generation with progress event dispatching while building request. It will help avoid freezing flash player while generating huge file requests. Also I’ll remove ‘Cache-Control’ header.
    and I’ll think about configuring returned data…

  17. 17 Quentin

    Wow, you rock!
    You class just saved me lots of troubles…

    Many thanks!

  18. 18 Buti

    Hi! Nice work, thx!

    I retrieve the server response doing this:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    private function onComplete( event: Event ): void{
    	response(_loader.data);
    	removeListener();
    	dispatchEvent( event );
    }
    private function response(s:ByteArray):void {
    	var datos:Array = s.toString().split("&");
    	data = new Object();
    	for (var i:uint = 0; i < datos.length; i++) {
    		var par:Array = datos[i].split("=");
    		data[par[0]] = par[1];
    	}
    }
    public function getResponse():Object {
    	return data;
    }
  19. 19 Nikke

    Thank you very much for this!

    Your work saved my life (or at least made it substantially easier ;-)

  20. 20 Eugene

    You are welcome! :-)

  21. 21 mizzusano

    Awesome! Its special solution for my problem. Thanks!

  22. 22 Tmz

    In Flash 10 I get an error: SecurityError: Error #2176

  23. 23 James

    Thanks muchly for this – I’m trying to use it to upload files with a Content-Type of something other than the default application octet stream.

    I’ve added a couple of lines to the code, to make the class dispatch a DataEvent with the server response, just like the FileReference.upload class would;

    private function onComplete( event: Event ): void
    {
    removeListener();
    dispatchEvent( event );
    dispatchEvent(new DataEvent(DataEvent.UPLOAD_COMPLETE_DATA, event.bubbles, event.cancelable, loader.data));
    }

  24. 24 pearl

    omg! Thank you VERY MUCH for posting this.

    Every example of sending jpgs to a server never used URLVariables (they always just used URLLoader and set the data property to be the jpg byte array directly) so I was having the hardest time sending user login info along with the image.

    But I used yours and it worked like a charm! Thanks again.

  25. 25 Elad Elrom

    Tmz: Flash Player 10 change the security policy and you have to call the MultipartURLLoader class following user’s interaction such as mouse or keyboard event. So you need to make a call like so:

  26. 26 nicola

    thanks you save me! I was unable to use multipartLoader class. But your MultipartURLLoader rocks!!! Really thanks again!

  27. 27 Sam

    This was exceedingly helpful, thank you!

  28. 28 Arturas

    This was really helpful, it saves us some headaches!

  29. 29 Anthony

    Hi all,

    I corrected a POST problem with Python HTTP server. This patch is :

    private function closeDataObject(postData:ByteArray):ByteArray
    {
    postData = BOUNDARY(postData);
    postData = DOUBLEDASH(postData);

    // START CORRECTION
    postData = LINEBREAK(postData);
    // END CORRECTION

    return postData;
    }

  30. 30 Tom

    I know I’m probably just doing something wrong…When I test in Flash CS4 it sends off to the URL (running Apache on localhost) and processes just fine. However when I export the movie and run it through my web browser (on localhost) it doesn’t try to load. I get no io error, no http status code, no security error, nothing. And of course it doesn’t complete. Do the events fire for security issues and such? It’s really odd that it works within Flash CS4 but not embedded on the page…Bummer. And I have a crossdomain.xml which I wouldn’t think I’d need anyway on localhost but..

  31. 31 Crirus

    Hello

    I am building a large video uploader and looking ito flash options to do this with resume capabilities… any chance doing that with your class?

    I know I need php work server side, but how can I read only partial file in flash and send it?

    Thanks
    Cris Rus

  32. 32 Tom

    I think there’s a major security issue with Flash and it may only be possible to submit with an actual button within the flash movie… One of my issues was trying to submit via ExternalInterface. I wanted javascript to send the form. It had problems with that.

    Bringing the button into the flash I STILL have issues when on http://localhost … When testing from within Flash (test movie) it seems to work. That appears to be the only time it works.

    Is there something silly and basic I’m missing?

  33. 33 Tom

    Turns out security issue. The POST has to be made with a click event from within the Flash (IF and ONLY if you’re attaching an image, you can use this multi loader with just strings being passed with no problem via externalinterface). Or in other words, the “submit” button has to be in Flash. I was hoping to call it from ExternalInterface/Javascript. Adobe’s recent security change prevents that.

    Does anyone know if there is any way around this?
    I want to put a flash “browse for file” field that mimics a normal html form element up somewhere in the page, and then a normal submit button (javascript on the click, not 100% normal html form element submit button) down the page further after some other form fields. If the button has to be in Flash that really limits my layout abilities.

    Even if there is a server side tweak to be made…Anything??

  34. 34 Wouter Van den Broeck

    Tom: have you tried with an element in the element in
    your crossdomain.xml file?

  35. 35 Wouter Van den Broeck

    Tom: have you tried with an <allow-http-request-headers-from
    domain="*"/> element in the <cross-domain-policy> element in
    your crossdomain.xml file?

  36. 36 Tom

    I actually had an outdated version of this class. There was a very simple fix. Funny that I read so many other blogs/sites and they also had similar problems (different classes and such). Strange, but glad it worked out. Thanks for the suggestions. I ended up not needing a crossdomain.xml at all actually.

  37. 37 Tom

    Also wish someone could explain one of the two different approaches above to get the response from the server….Both snippets of code just seem worthless to me right now, trying everything. A tiny bit of help and explanation maybe?

  38. 38 Tom

    Ahh…. loader should be _loader.
    So the above does work (and I think a great small addition to the class):
    dispatchEvent(new DataEvent(DataEvent.UPLOAD_COMPLETE_DATA, event.bubbles, event.cancelable, _loader.data));

  39. 39 spencer

    Thanks for this work. It is very cool and works great! For the file attachment I am writing data to a ByteArray and then when it was ready, I make the multipart.addFile(..) call. What I would really like to do is incrementally add the data to the Byetarray (or some other structure), and have MultipartURLLoader chunk transfer encode the request to the server as data is fed to it. Any hints on how to accomplish this? Would this be a difficult project to add this sort of capability?

  40. 40 Tomasino

    Tom, you mentioned you found an easy fix to your problem but you didn’t mention what it was? I’m having a similar issue right now that I’d love to get around. I have a profanity filter happening on my form submission, and after it comes back successfully, I continue on with the multi-part post. Unfortunately, due to the intervening asynchronous call, flash is throwing that pesky security error.

  41. 41 velanse

    Thanx man! You are awesome! :) You solved the problem that I tryed to solve for several hours but with no success.

  42. 42 sergio

    Hi,when I export the movie and run it through my web browser (on localhost) …nothing,
    with swf works .Why please?

  43. 43 milushov

    Nice work, i wanted to write itself, since i have found i will use your class =)

  44. 44 Ganesh

    Hi Eugene,

    How can we set cookies to the multi part request.

    I am able to upload the file, but my server does authentication based on cookie being sent.

    Please help.

    Thanks in advance
    Ganesh

  1. 1 LLops Blog » Blog Archive » Envío de imágenes y datos con AS3
  2. 2 Multipart URLLoader Class updated | astatic notes
  3. 3 FoundChris » Blog Archive » FAILSAFE “bad content type” when POSTing multipart data in Rails
  4. 4 JPEGEncoder --- leeres ByteArray (

Leave a Reply