7月 22
AS3でバイナリーデータをPHPに送信する。
バイナリーのみの送信
単純にバイナリーのみを送信する場合は、URLRequestオブジェクトのdataプロパティにByteArrayオブジェクトを格納して、Content-Typeにバイナリデータであることを示すapplication/octet-streamを指定。(36行~39行辺り)
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="appComp(event)" xmlns:component="component.*"> <mx:Script> <![CDATA[ import mx.graphics.codec.PNGEncoder; import mx.graphics.codec.IImageEncoder; import mx.core.BitmapAsset; import mx.events.FlexEvent; import flash.filters.BitmapFilterQuality; import mx.graphics.codec.PNGEncoder; [Bindable] private var _quality:Array = [{label:'低', data:BitmapFilterQuality.LOW}, {label:'中', data:BitmapFilterQuality.MEDIUM}, {label:'高', data:BitmapFilterQuality.HIGH}]; public function appComp(ev:FlexEvent):void{ ; } public function applyFilter(event:FlexEvent):void{ var filter:BlurFilter = new BlurFilter(blurX.value, blurY.value, quality.selectedItem.data); src.filters = [filter]; } public function submit(ev:FlexEvent):void{ var codec:IImageEncoder = new PNGEncoder(); var bmpData:BitmapData = new BitmapData(src.width, src.height, true, 0x00000000); var byteArray:ByteArray; var req:URLRequest = new URLRequest(); var loader:URLLoader = new URLLoader(); bmpData.draw(src); byteArray = codec.encode(bmpData); req.url = './raw_post.php'; req.contentType = 'application/octet-stream'; req.method = URLRequestMethod.POST; req.data = byteArray; loader.addEventListener(Event.COMPLETE, _hdlResponse); loader.load(req); } private function _hdlResponse(ev:Event):void{ var loader:URLLoader = ev.target as URLLoader; dist.load(loader.data); dist.toolTip = loader.data; } ]]> </mx:Script> <mx:Canvas backgroundColor="0xffffff"> <mx:HBox> <mx:Image id="src" source="@Embed(source='./assets/image/small_mabu.jpg')" /> <mx:VBox horizontalAlign="left"> <mx:Label text="Blur フィルターテスト" textAlign="center" width="100%" fontWeight="bold"/> <mx:Label text="blurX"/> <component:MySlider id="blurX" /> <mx:Label text="blurY"/> <component:MySlider id="blurY" /> <mx:HBox width="100%" horizontalAlign="right"> <mx:Label text="品質" width="100%"/> <mx:ComboBox id="quality" dataProvider="{_quality}"></mx:ComboBox> </mx:HBox> <mx:Button id="btnApply" label="適用" buttonDown="applyFilter(event)" /> <mx:Spacer height="20" /> <mx:Button id="btnSubmit" label="サーバに送信" buttonDown="submit(event)" /> </mx:VBox> </mx:HBox> </mx:Canvas> <mx:Image id="dist" /> </mx:Application>
PHP側でバイナリデータを受信する場合は、php://inputストリームから直接に生のデータのストリームにアクセスしてやればOK。この方法はバイナリーデータに限らずXMLを受信するときにも使える。
<?php $img_path = 'images'; $img = file_get_contents("php://input"); $path = dirname(__FILE__); $tmpfname = tempnam($path.$img_path, "img_"); unlink($tmpfname); $tmpfname = $tmpfname . '.png'; $fp = fopen($tmpfname, 'wb'); fwrite($fp, $img); fclose($fp); print './images/'.basename($tmpfname); ?>
multipartで送信する
HTMLのフォームからファイルを送信するように、mulitpart/form-dataで送信を行なう場合は、ByteArrayオブジェクトに対して、writeMultiByte()メソッドや、writeBytes()メソッドを使用して各部分を書き込んでやり、自分でデータを作ってやる。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" applicationComplete="appCmp(event)"> <mx:Script> <![CDATA[ import mx.graphics.codec.PNGEncoder; import mx.graphics.codec.IImageEncoder; import mx.graphics.codec.PNGEncoder; import mx.events.FlexEvent; import flash.net.navigateToURL; private function appCmp(ev:FlexEvent):void{ ; } private function dataPost(ev:FlexEvent):void{ var multipart:MultiPartData = new MultiPartData(); var req:URLRequest = new URLRequest(); var loader:URLLoader = new URLLoader(); var bytes:ByteArray; var bmpData:BitmapData; var encoder:IImageEncoder = new PNGEncoder();//mx.graphics.codec.PNGEncoderはFlex3のコンポーネントです。 bmpData = new BitmapData(srcImage.width, srcImage.height); bmpData.draw(srcImage); bytes = encoder.encode(bmpData); //リクエストのボディーを作成 multipart.addString('subject', msgModel.subject); multipart.addString('comment', msgModel.comment); multipart.addBynary('image', bytes, 'mabu2.png', encoder.contentType); //リクエストの作成 req.url = settings.post.url; req.method = URLRequestMethod.POST; req.contentType = "multipart/form-data, boundary=" + multipart.boundary; req.data = multipart.data; // navigateToURL(req, '_blank'); loader.addEventListener(Event.COMPLETE, _hdlComplete); try{ loader.load(req); }catch(err:Error){ throw(err); } } private function _hdlComplete(ev:Event):void{ var loader:URLLoader = ev.target as URLLoader;; distImage.load(loader.data); } ]]> </mx:Script> <mx:Model id="msgModel"> <message> <subject>日本語</subject> <comment>コメント</comment> </message> </mx:Model> <mx:Binding source="subject.text" destination="msgModel.subject"/> <mx:Binding source="comment.text" destination="msgModel.comment"/> <mx:Model id="settings" source="./settings.xml" /> <mx:HBox width="100%"> <mx:VBox> <mx:Label text="ソース" /> <mx:Image id="srcImage" source="assets/image/small_mabu.jpg"/> <mx:Label text="タイトル" /> <mx:TextInput id="subject" text="" width="100%"/> <mx:Label text="コメント" /> <mx:TextArea id="comment" text="" width="100%"> </mx:TextArea> <mx:Button label="送信" buttonDown="dataPost(event)"/> </mx:VBox> <mx:VBox> <mx:Label text="結果" /> <mx:Image id="distImage" /> </mx:VBox> </mx:HBox> </mx:Application>
18行~22行、26行~34行で各パートを作成。
package { import flash.utils.ByteArray; public class MultiPartData { private const N:String = 'rn'; private var _boundary:String; private var _data:ByteArray; public function MultiPartData( boundary:String = '-------------------------7d76d1b56035e'){ _boundary = boundary; _data = new ByteArray(); } public function addString( name:String, value:String):void{ var str:String; str = '--'+_boundary+N; str += "Content-Disposition: form-data; name=\""+name+ "\""+N+N; str += value + N; _data.writeMultiByte(str, 'utf-8'); } public function addBynary( name:String, value:ByteArray, filename:String, type:String = 'application/octet-stream'):void{ var str:String; str = '--'+_boundary+N; str += "Content-Disposition: form-data; name=\""+name+ "\"; filename=\""+ filename +"\""+N; str += "Content-Type: " + type +""+ N + N; _data.writeMultiByte(str, 'utf-8'); _data.writeBytes(value, 0, value.length); _data.writeMultiByte(N, 'ascii'); } public function resetData():void{ _data = new ByteArray(); } public function get data():ByteArray{ var ret:ByteArray = new ByteArray(); ret.writeBytes(_data, 0, _data.length); ret.writeMultiByte('--'+_boundary+'--', 'ascii'); return ret; } public function get boundary():String{ return _boundary; } public function set boundary(value:String):void{ _boundary = value; } } }
PHP受信側は、普通に$_FILEや$_POSTが使える。
<?php function LoadPNG($imgname){ $im = imagecreatefrompng($imgname); if($im){ $color = imagecolorallocate($im, 255, 0, 0); imagestring($im, 3, 10, 10, $_POST['subject'], $color); }else{ error_log('ロードできません。'); } return $im; } $MAXIMUM_FILESIZE = 1024 * 200; // 200KB $MAXIMUM_FILE_COUNT = 10; // サーバー上のファイル数を 10 個までに制限する if ($_FILES['image']['size'] <= $MAXIMUM_FILESIZE) { move_uploaded_file($_FILES['image']['tmp_name'], "./tmp/".$_FILES['image']['name']); //ファイルの種類をチェック $type = exif_imagetype("./tmp/".$_FILES['image']['name']); if ($type == 1 || $type == 2 || $type == 3) { if(file_exists("./images/".$_FILES['image']['name'])){ unlink("./images/".$_FILES['image']['name']); } $png = LoadPNG("./tmp/".$_FILES['image']['name']); imagepng($png, "./images/".$_FILES['image']['name']); print("./images/".$_FILES['image']['name']); } else { unlink("./tmp/".$_FILES['image']['name']); } } ?>