2009年 9月 29日(火曜日) 20:27

HTTPのPOSTでバイナリデータを転送するには

評価:
(0 票)

クライアント(Silverlight)でバイナリデータを作成し、サーバに転送する方法です。

今回はHTTPの"POST"メソッドを使って、HTMLのフォームからではなく、Silverlight (C#)で処理したデータをサーバにアップロードし、サーバ側(PHP)で受け取るアプリケーションを作ったのですが、その方法を調べるのにかなり苦労したのでまとめて書いておきます。

0. サーバ側でSilverlightからのアクセスを許可しておく

下のようなXMLファイルを作成し、clientaccesspolicy.xmlという名前で保存して、サーバのアクセスを許可するディレクトリの下に配置します。

<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from>
                <domain uri="*"></domain>
            </allow-from>
            <grant-to>
                <resource path="/" include-subpaths="true"></resource>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

※なお、上のXMLは全てのURLからのアクセスを許可しますので、オンラインで公開されているサーバに設置するときにはアクセス許可を編集するなどして、十分注意して下さい。

1. WebRequestを使ってPOSTリクエストを送信する

Silverlightでは.NET FrameworkのWebRequestクラスを使用できますが、リクエストやレスポンス関連のメソッドは非同期のもののみになっています。同期メソッドは使えません。

下の例は、サーバ側のPHPプログラム"http://testserver/testprogram.php"にPOSTリクエストを送信しています。

    private void sendPostRequest() {
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://testserver/testprogram.php");
        req.Method = "post";
        req.ContentType = "application/octet-stream";
        req.BeginGetRequestStream(new AsyncCallback(receiveRequestStream), req);
    }

ポイントは、リクエストのMethodプロパティを"post"に、ContentTypeプロパティを"application/octet-stream"にすることです。Content-typeヘッダには他に"application/x-www-form-urlencoded"を使う方法もあるようですが、これだとPOSTされたデータをPHP側で受け取ることができませんでした。

最後にリクエストのストリームを要求する非同期メソッドBeginGetRequestStreamを呼びます。

2. リクエストのストリームにバイナリデータを書き込む

上でBeginGetRequestStreamのコールバックとして登録したメソッドで、リクエストのストリームを受け取り、そこに送信したいバイナリデータを書き込みます。

    private void receiveRequestStream(IAsyncResult asynchronousResult) {
        WebRequest req = (WebRequest)asynchronousResult.AsyncState;
        Stream reqStream = req.EndGetRequestStream(asynchronousResult);
        byte[] data = Encoding.UTF8.GetBytes("hehehe"); // 送信するデータを作成
        reqStream.write(data);
        reqStream.Close();
        req.BeginGetResponse(new AsyncCallback(receiveResponse), req);
    }

この例では"hehehe"という文字列からバイト配列を作成しして送信していますが、実際にはここでバイナリpt>データをストリームに書き込みました。

書き込みの後、レスポンスを受け取るための非同期メソッドBeginGetResponseを呼びます。

3. サーバからのレスポンスを受け取る

サーバからのレスポンスを受け取ります。

    private void receiveResponse(IAsyncResult asynchronousResult) {
        WebRequest req = (WebRequest)asynchronousResult.AsyncState;
        WebResponse res = req.EndGetResponse(asynchronousResult);

        Stream resStream = res.GetResponseStream();
        StreamReader sr = new StreamReader(resStream);
        string res = sr.ReadToEnd();

        resStream.Close();
        sr.Close();
        res.Close();
    }

4. サーバ側(PHP)でデータを受信

サーバ側ではPOSTで送られてきたデータを受け取り、一時ファイルに書き込んでいます。一時ファイルの名前をechoしてレスポンスとしています。

<?php
    $post_fp = fopen("php://input", "r");
    $tmpFilePath = tempnam(sys_get_temp_dir(), 'tmp');
    file_put_contents($tmpFilePath, $post_fp);
    fclose($post_fp);
    echo $tmpFilePath;
?>
ポイントは、POSTされたデータが"php://input"で取得できる点です。POSTされたデータは$HTTP_RAW_POST_DATAでも取得できますが、"php://input"の方がメモリの使用が少なくおすすめだそうです。(http://jp2.php.net/manual/ja/wrappers.php.php)

"php://input"はファイル名のように考えて扱えるようですが、"php://input"から得られたリソースに対してseekやrewindはできないようです。

※なお、上のサンプルはファイルの中身を一切確認しないでサーバに保存していますが、実際にはファイルの形式を確認するなどしてセキュリティには十分注意しましょう。

その他、HTTPのPOSTに関する基本的な事項は、

http://developers.sun.com/mobility/midp/ttips/HTTPPost/

が参考になりました。

 

また、WebRequestクラスを使った非同期通信の方法は、

http://msdn.microsoft.com/ja-jp/library/system.net.webrequest.begingetrequeststream(VS.85).aspx

のサンプルを参考にしました。

 

ところで、私は基本的に、Linux, Apache, eclipse, PHP, C++などのオープンな開発環境を使うようにしてきたのですが、最近のRIAへの流れからSilverlightを使ってみたくなり、Microsoftの世界にやや引きずり込まれております。。。

とはいえ、RIAの現実的な選択肢はAdobeのFlexかMicrosoftのSilverlightぐらいしかなく、Flexよりも応用の利くSilverlightには結構期待しています。開発もFlexは高価なAdobe Flexを購入しなければならないのに対し、Silverlightの開発はMicrosoft Visual Web Developer 2008 Express Editionで完全に無料でできます。Silverlightは.NETフレームワークの多くを利用でき、Windowsアプリ開発と共通の知識で開発できるのでちょっと気に入っています。

ところがやはりサーバサイドはWindowsサーバをレンタルするのは費用がかかりすぎるのでLinux + PHPを使います。ASP .NETなんて全然興味ありません。。。

結果として今の選択は、サーバサイドはPHP、クライアントサイドはSilverlightというちょっと変わった組み合わせになってしまいました。

最終更新日: 2011年 6月 27日(月曜日) 01:37
くらち たかよし

くらち たかよし

モバイル・Webアプリ作家。最近は主にiPhoneアプリ制作を手がける。企画、UIデザイン、設計、実装、テストなどを1人〜数人の個人で行う全人的開発手法の確立を目指している。

使う言語はObjective-C, C++, C#, Java, PHPなど。Web関連で使うものはCakePHP, MySQL, Joomla! CMSなど。デザインではPhotoshopとIllustratorをかろうじて使う。

場所や時間に縛られない、インターネット時代の新しい働き方、自由な生き方を模索中。海外移住、低予算&低リスク起業、キャリアデザイン、心理学などにも興味あり。

Web: awaresoft.jp/