ng-file-uploadを使って画像をサーバにUPしよう
Angular JSを使って、画像データをサーバにUPするには、とりあえずng-file-uploadを使いましょう。ng-file-uploadの使い方と筆者が陥ったミスをご紹介です。
ng-file-uploadのインストール
bowerをお使いならば、コマンドラインから
bower install ng-file-upload –save
とタイプします。
もしbowerを使っていないのであれば、是非このタイミングで導入をお勧めします。様々なプラグインのダウンロード、展開、紐づけ(スクリプトタグ)を、コマンド1つで全部やってくれるので、開発がすごく楽になります
その後、angular JSファイルに
angular
.module('yo9App', ['ngFileUpload'])
と書き足します。
htmlのコーディングin ng-file-upload
ファイルをアップロードするには、
<input type="file">
と書くのが通常のHTMLです。Angular JS + ng-file-uploadでは、次のように変わります
<form>
<input type="file" ngf-select ng-model="picFile" name="file" ngf-max-size="1MB" required ngf-accept="'image/png'" ngf-pattern="'image/png'" ngf-resize="{width: 200, height: 200}" ngf-ratio="1:1" ngf-multiple="false">
<br>
<button class="btn btn-success" ng-disabled="!stampUpload.$valid" ng-click="uploadPic(picFile)">送信</button>
<button class="btn btn-warning" ng-click="picFile = null" ng-show="picFile">キャンセル</button>
</form>
えぇ、そうです。ものすごく長くなります。ただ悲観するだけではありません。ファイルのアップロードに様々な制約を課すことができるので、入口をしっかりしておけば後がラクになります。
例えばファイルのサイズ上限や、縦列比率、リサイズ後のサイズなどかなり細かく条件が指定できます。セキュリティ的には当然PHP側でも入念にチェックが必要ですが、ユーザサイドのJavaScriptでもここまでできるのは便利です。
angular JS側の処理を記述
///////画像アップロード処理
$scope.uploadPic = function(item){
Upload.upload({
url:'ぴーえいちぴーのファイルパス/xxxxx.php',
data: {
loginId:$scope.loginId,
file: item
},
})
.then(function (resp){//送信成功
$log.info("画像アップロード完了");
},function (resp) {}
,function (evt) {}
);
}
ジャバスクリプト側はまぁ普通な感じです
クライアントからサーバへリクエストが2回飛ぶ
ng-file-uploadは、何故かしらないけど、requestが2回送られます。色々調べたけど結局わかりませんでした。
ファイルを選択して、送信ボタンクリックすると
Request Method:OPTIONS が走ります。その後すぐ
Request Method:POST が走ります。
送信ボタン1回で、リクエストが2回送られます。1回めのoptionsのリクエストは、何が起きてるのかよくわからんのですが、実際何も起きてないようです。
実際にファイル名を取得して、色々書き換えやファイルアップロードするのは、2回目のリクエスト( POST)の方です。
この挙動のせいで5時間近くはまりました。
PHP側でangular JSから送られたデータを処理する
<?php
$res = array("status"=>-1);//成功失敗フラグ
$uploaddir = '../stamp/';//保存先Directory
$uploadfile = $uploaddir . ($data['orgId']) . ".png";
echo "orgIDは" . $data['orgId'] ;
print_r($_FILES);
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
$res['status'] = 1;
die(json_encode($res));
} else {
die(json_encode($res));
}
?>
php側では、こんな感じで書いてみました。
とりあえずファイルの書き込みが成功したら、statusが1を返し、失敗したら-1を返す。これをAngular JS側で受け取れば、成功したか、失敗したかメッセージを出力できるので、それをもとにAngular JSではメッセージを出力すればいいのです。「成功しましたよー」とか、「失敗やでー」という具合です。
ただ、何故か statusが-1ばかり返ってくる。でもちゃんとファイルはUPできていました。
ちゃんと動いているのに、 return -1 なんで???
まぁ、結論は上でも書いたように、リクエストが2回送られてるからなんです。OPTIONSのリクエストの方は、実際何のデータもまだ来てないので、当然ファイルのプットは失敗するんですね。これで -1が返ってくるんです。それを受け取ってAngular JS側で、
if(rsp[‘status’]==-1){tostr.error(“ファイル送信失敗”);
なんて書いてるので、画面上は失敗メッセージが表示されるのに、サーバを見るとちゃんとデータがあるんで、頭を抱えることになります。
とりあえず、1回めのリクエストは何の意味があるのかわからないけど、きっとファイルをアップするために必要なんでしょうね。
マニュアル見ると、リクエストを1回でやる方法?みたいなのもかいてあります。
(Upload multiple files one by one on file select)
1リクエストでファイルアップロード
ただこれ、multiple filesってことで、複数ファイルをなんかまとめて送るやり方みたいなので、わたしはスルーしましたけどね。
とりあえず、-1エラーが帰ってくるのは困るので、応急処置
if($_SERVER['REQUEST_METHOD']=='OPTIONS'){
die();
}
んーこれでいいんかなぁ?エラーはでなくなったけど、意味があってリクエストしているので、これをキルしちゃうのはダメなのかも?
プラグインとか、フレームワークって独特な動きするものがあるので注意ですね。

