Google Apps Scriptでファイルアップローダを作る

以前、GoogleのPicker APIを利用したアップローダを作成しました。正直な所、このAPIは非常に強力で、Google Driveと連携するアップローダやファイル選択ダイアログならばこれを素直に使ったほうがベストです。しかし、一方で他のサービスなどには利用出来ないので、Google Drive以外で使うシーンでは、これまで通り、HTMLでのアップロードの仕組みを構築する必要があります。

今回、単体のアップロード、File APIを利用した複数のファイルのアップロードの2種類を作成してみました。尚、複数ファイルの選択は、CtrlキーやShiftキーを押しながら選択する事が出来ます。

※2020/02/20現在、未だにV8でformとinputを使ってのアップロードだとファイルが壊れますので、Chrome V8ランタイムはオフにしておくのがベストです。

難易度:


今回使用するスプレッドシート等

form-inputを使った手法

単体アップローダの場合

GAS側コード

  • uploadmanがダイアログ表示を行うスクリプトです。
  • sendFormはHTML側から叩いて実行する実際にアップロード作業を行うスクリプトです。
  • theFormという引数部分で、ファイルをBLOB形式で受け取ります。myFileとはHTML側のアップロードするボタンに付けられてるname属性値です。

HTML側コード

  • 非常にシンプルです。アップロードボタンには、google.script.run.sendFormというGAS側の関数を叩くコマンドを入れてあります。
  • this.parentNodeでformの中身をまとめて引数として送りつけています。

実行結果

スプレッドシートを開き、上部にある「▶あぷろだ」メニューの中の【ファイル選択】を開くと、アップロード用のダイアログが開きます。但し、実際にはファイルを作るメソッドはオフにしてありますので、実際にはサンプルからはアップロードはできません。コピーして該当箇所のコメントアウトを解除し、folderIdを入れて使いましょう。

図:ダイアログ上からファイルをアップロードする

ポイント

  1. ダイアログは必ず、createTemplateFromFileメソッドで作成して出力しなければなりません。
  2. 仕様上、ファイルは1個ずつしか選択できません。但し、HTML5が使えるので、multipleを指定すると複数選択出来るようになります。サンプルスプレッドシートは複数選択出来るようにしています。複数選択は、Ctrlキーを押しながらファイルを選択するだけです。多分配列で渡されるんじゃなかろうか。
  3. G Suitesなどで使う場合、当たり前ですがフォルダに対してのアクセス権がない場合、アップロードが出来ません。但し、実行権限を各人ではなくファイルオーナーにしておくと、アクセス権限がなくともアップロードが可能です。
  4. 所定のフォルダは直接スクリプト内に書くのではなく、Propertie.Serviceなどを使って、スクリプトプロパティなどにフォルダIDを格納し、スクリプト内から呼び出す方式にしたほうが便利です。
  5. アップロード中に例えばスピナー(くるくる回転するgif画像など)や、アップロードしてるよというメッセージ、また、何度もボタンを押せないように送信したら、ボタンを押せなくするなどの対策をしておく必要性があります。

複数ファイルアップローダの場合

GAS側コード

  • uploadmanがダイアログ表示を行うスクリプトです。
  • saveFileが実際にドライブにファイルを生成するスクリプトです。Blobデータとファイル名を受け取ります。

HTML側コード

実行結果

スプレッドシートを開き、上部にある「▶複数あぷろだ」メニューの中の【ファイル選択】を開くと、アップロード用のダイアログが開きます。但し、実際にはファイルを作るメソッドはオフにしてありますので、実際にはサンプルからはアップロードはできません。コピーして該当箇所のコメントアウトを解除し、folderIdを入れて使いましょう。

図:複数のファイルをいっぺんにアップロードできる

ポイント

  • 単一のファイルのアップロードと異なり、HTML側でのFile APIに関する処理が加わっています。
  • GAS側のファイルを作る関数を呼び出すルーチンでは、少々特殊な書き方で、ループ処理を行わせています。
  • もちろん、inputには、multipleを入れて置きます。
  • formタグ関係はなくても問題ありません。
  • そのままHTML側からGAS側にデータを渡すと、Base64でエンコードされているので、デコードしてあげないと読めないファイルが出来てしまいます。

上書きアップロード

Google Apps Scriptは他のクラウドストレージやファイルサーバと異なり、同じファイル名が同じフォルダ内に存在する事が可能になっています。ファイルのIDで管理しているためこのような事が実現できるのですが、

ファイルのIDがわかってるものであれば、setContentで上書きが可能なのですが(テキストのみ)、ファイルアップローダのようにアップ先に同じファイル名のものがあるかどうかわからない場合には、このままだとファイルIDを調べるのに一工夫必要になります。また、Drive APIを利用してもアップロードが可能です。その場合は以下の手間が生じます。

  1. スクリプトエディタのメニューより、「リソース」⇒「Googleの拡張サービス」を開く
  2. Drive APIのスイッチをONにする

Drive APIを利用してファイルを上書きアップロードしてみましょう。

  • ためしに取得したfilenameで取得してみて、trueならば上書き、falseならば新規アップロードになります。
  • setContentにてファイルを上書きすることが可能ですが、引数はBlobじゃありませんのでBlob形式だとファイルが壊れます。
  • Drive APIを使って、Drive.Files.update({}, files.next().getId(), fileBlob);でも上書きが可能です。

注意点

本項目のアップロード手法は、Chrome V8ランタイムが有効な場合、アップロード後のファイルが破損します(GASのバグですね)。未だにこのバグはIssue Trackerには挙げられていて修正されていません。(このトラブルはtextなどのアップロードは問題なし。問題が起きるのは、画像や動画ファイルなどのバイナリファイル系)

よって、このソースコードで運用する場合には、以下の手順でV8ランタイムをオフにする必要性があります。(新IDEをベースに説明しています)

  1. スクリプトエディタを起動する
  2. 左サイドバーのプロジェクトの設定をクリック
  3. Chrome V8 ランタイムを有効にするのチェックを外す

これでOKです。

図:V8が有効だと壊れます

V8対応ライブラリを使った手法

単体アップローダの場合

前項の手法は一般的なウェブで使われてるアップロード手段なのですが、V8ランタイムが有効な場合、アップロード後のファイルが壊れるというバグがあり、GAS上ではV8ランタイムをオフにしなければ利用できません。しかし、そうなるとV8での構文が使えなくなってしまうため、不利益でもあります。

この問題を解決する為のライブラリが公開されており、基本的にはライブラリをロードして、onClickの送信時メソッドにちょっとした加工をするだけで、壊れずにV8ランタイムをオンの状態でアップロードが可能です。

GAS側コード

  • createFileにてUtilities.newBlobで受取ます。この時、mimetypeやfilenameも指定されています。

HTML側コード

  • V8対応ライブラリをロードしておきます
  • formのinputのonclickではParseFormObjectForGASでアップロードファイルを受取り、google.script.runにてGAS側へ渡すようにコードを記述します。

実行結果

本コードはV8ランタイムがオフである場合、動作しません。スプレッドシートを開き、上部にある「▶ファイル選択-V8対応」を開くと、アップロード用のダイアログが開きます。但し、フォルダIDは空っぽなので、実際にはサンプルからはアップロードはできません。folderIdを入れて使いましょう。

50MBオーバー対応アップローダ

通常のgoogle.script.run.withSuccessHandlerを使った手法の場合、Google Apps Scriptの制限によりファイルサイズは最大50MBまでしかアップロードすることが出来ません。しかし、Drive API V3を使った手法の場合、レジュームアップロードを利用することで、50MBの制限を超えてアップロードする事が可能です。

50MBオーバー対応の為のライブラリが公開されており、またgoogle.script.runを利用していないので、V8でも問題なく動作します。

GAS側コード

  • 複数ファイルを同時にアップロードするために、putFileInfにてロック制御やアップロードしたファイルの情報をスプレッドシートに記録しています。
  • getfolderidにてGAS側に記述しているアップロード先フォルダIDをHTML側へ送っています。

HTML側コード

  • 50MBオーバー対応ライブラリをロードしておきます。
  • HTML表示時にGAS側からアップロード先フォルダのIDを取得しています。
  • upload実行時にrun()が実行され、Access Tokenが取得されます。
  • Access Tokenをもって、Drive API V3をもって、HTML側から直接Google Driveにファイルがアップロードされます。
  • よって、今回はアップロードの為に、google.script.runは利用していません。

実行結果

本コードはV8ランタイムがオフである場合、動作しません。スプレッドシートを開き、上部にある「▶複数あぷろだ」→「ファイル選択-V8対応版」を開くと、アップロード用のダイアログが開きます。但し、フォルダIDは空っぽなので、実際にはサンプルからはアップロードはできません。folderIdを入れて使いましょう。

図:複数同時にアップも可能です。

関連リンク

共有してみる:

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。