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(); }
んーこれでいいんかなぁ?エラーはでなくなったけど、意味があってリクエストしているので、これをキルしちゃうのはダメなのかも?
プラグインとか、フレームワークって独特な動きするものがあるので注意ですね。