Ajaxによるmultipart/postでの画像ファイルアップロード
モバイルアプリでは、サーバーと連動して動作するものが多くみられます。
ハイブリッドアプリでこうしたアプリを作る場合は、Ajaxで実現するのが一般的だと思いますので、そのやり方について説明します。
追記:Android 2.3系およびそれ以前のAndroidは、FormDataオブジェクトが未定義のため、この記事の方法は利用出来ません。ご注意下さい。
追記2:Android 4.4では、Formからのファイル選択自体ができないため、この記事の方法は利用出来ません。(4.4.2で確認。今後のバージョンアップ出来るようになるかは不明です)
formタグを使わない手段については、こちら
サーバー側の実装
まずは、サーバー側の機能の実装です。
ここでは、普通にブラウザからもアップロード出来るような作りを考えます。実装はphpですが、他の言語でも基本的に同じように作れると思います。
/uploader.php
<?php
$textUpload = "";
if ($_FILES['userfile']):
$uploadfile = __DIR__ . '/uploads/image.jpg';
if (move_uploaded_file($_FILES['userfile']['tmp_name'],$uploadfile)) {
$textUpload = "File is uploaded";
} else {
$textUplaod = "Upload fail";
}
endif;
if (preg_match('/^text\/html/', $_SERVER['HTTP_ACCEPT'])) : ?>
<pre>
<?php echo $textUpload; ?>
</pre>
<form enctype="multipart/form-data" action="/uploader.php" method="POST">
<input name="userfile" type="file" />
<input type="submit" value="Send" />
</form>
Current Image:
<a href="https://www.asial.co.jp/uploads/image.jpg?<?php echo time(); ?> &mode=1" class="popupimg"><img src="https://www.asial.co.jp/uploads/image.jpg?<?php echo time(); ?>"></a>
<a href="/uploader.php"> REFRESH </a>
<?php else:
header( 'Content-Type: application/json; charset=utf-8', true );
echo json_encode( array("message" => "Upload is OK") );
endif; ?>
写真をおくためにuploadsディレクトリを作成して、書き込み権限を付与しておきます。
この状態で、ブラウザからアクセスすると、投稿フォームがあるので、そこから画像を
アップロードしてみて下さい。
コードの中で$_SERVER['HTTP_ACCEPT'])) を見ているのは、ブラウザフォームからの
アクセス(html/textを要求)なのか、後に行うAjaxからのアクセス(jsonを要求)なのか
を判定するためです。
なので、もしAjaxからのアクセスしか行わないのであれば、$_SERVER['HTTP_ACCEPT']))
に対するif判定でtrueの部分の処理はいりません。
アプリ側の実装
次に、Monacaから「最小限のテンプレート」でプロジェクトを作成します。
利用するプラグインとして、「jQuery」を設定します。
index.htmlのheader部のjavascriptを以下のようにします。
function upload(form) {
$form = $('#upload-form');
fd = new FormData($form[0]);
$.ajax(
'http://[サーバーのURL]/uploader.php',
{
type: 'post',
processData: false,
contentType: false,
data: fd,
dataType: "json",
success: function(data) {
alert( data.message );
console.log(data);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert( "ERROR" );
alert( textStatus );
alert( errorThrown );
}
});
return false;
}
また、body部のhtmlは
<form id="upload-form" method="post" enctype="multipart/form-data" onSubmit="return upload(this);">
<input id="upload-form-file" name="userfile" size="27" type="file" accept="image/*;capture=camera"/>
<input type="submit" name="submit" value="OK" />
</form>
とします。
これで、アプリを起動して、写真を選択、OKボタンを押すと、サーバーに接続して、写真ファイルをアップロードが行えます。アップロード後、サーバー側の「REFRESH」リンクをクリックすると、投稿した画像に更新されていることが確認出来ます。
コードの内容は、フォーム内容をFormDataクラスとして取得し、それをAjaxによりサーバーに送っているだけなので、難しいところはあまりないと思います。。dataTypeを「json」としているのは、サーバからのレスポンスを受けるにはjsonが便利だからなので、htmlやtextとして取得しても問題ありません。(success処理の実装は少し変わります)
まとめ
簡単ではありますが、Ajaxを利用して画像ファイルをアップロードするサンプルコードを紹介しました。Ajaxを利用するとページの再読み込みが必要ないので、Onsen UIなどのフレームワークからも使えます。
便利なのは、通常のフォームからデータを取得しているので、画像以外のデータも合わせて送ることが出来ること、既存のフォームにもデータを送ることが出来ることなどです。
1つ注意点としては、上記の中でフォームからアップロードする写真を選ぶ部分は、ユーザーが手動でやらなくてはならず、勝手に写真をアップロードすることは出来ません。これはセキュリティ的な制限のためです。アプリの内部に保存した画像ファイルをアップロードする場合は、Monaca (Cordova)のFileTransferを使うことになります。
サーバーと連動するアプリの開発に役立ててみて下さい。