Google Apps ScriptのV8でGoogleドライブへのフォーム経由ファイルアップロードに不具合

2020年5月1日

2020年5月時点において、Google Apps Script(GAS)のV8を有効にした状態で、HTMLファイルで用意したフォームを経由してGoogleドライブへのファイルアップロードを行おうとすると、アップロードしたファイルが破損してしまう事象が発生しています。

GASで画像ファイルをGoogleドライブにアップロードすると不具合

不具合の事象としては、Google Apps Script(GAS)で以下の3つを実現しようとすると発生します。

  1. GASでHTMLファイルでファイルアップロードのフォームを用意
  2. アップロードボタンをトリガーにGASのスクリプトを起動
  3. フォームで設定した画像ファイルをGoogleドライブにアップロード

下記のようなGASのコードを用意して、Googleドライブにアップロードしようとすると、Googleドライブ上で画像が開けなくなります。

doget関数で表示するフォームのHTMLファイル

GASで公開したWebアプリケーションとして読み込むフォームのHTMLファイルは以下の通りです。

<!DOCTYPE html>
<html>
  <head>
    <base >
    <script>
      // Prevent forms from submitting.
      function preventFormSubmit() {
        var forms = document.querySelectorAll('form');
        for (var i = 0; i < forms.length; i++) {
          forms[i].addEventListener('submit', function(event) {
            event.preventDefault();
          });
        }
      }
      window.addEventListener('load', preventFormSubmit);

      function handleFormSubmit(formObject) {
        google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
      }
      function updateUrl(url) {
        var div = document.getElementById('output');
        div.innerHTML = '<a href="' + url + '">ファイルリンク</a>';
      }
    </script>
  </head>
  <body>
    <form id="myForm" onsubmit="handleFormSubmit(this)">
      <input name="myFile" type="file" />
      <input type="submit" value="Submit" />
    </form>
    <div id="output"></div>
 </body>
</html>

ファイルをGoogleドライブにアップロードするGASコード

フォームで入力されたファイルをGoogleドライブにアップロードするGASコードはこちらです。

//フォームのSubmitボタンがクリックされた際に実行する関数
function processForm(formObject) {
  //フォームに添付されたファイルをBlob形式で取得する
  var formBlob = formObject.myFile;
  //取得したファイルをGoogleドライブに格納する
  var driveFile = DriveApp.createFile(formBlob);
  //ファイルの共有リンクを有効にし、誰でも閲覧できるようにする
  driveFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
  //アップロードしたファイルのURL情報を取得し、返り値に設定する
  var file_url = drive_file.getDownloadUrl();
  return file_url;
}

フォームでSubmitボタンが押されたタイミングでprocessForm関数が実行され、Googleドライブにファイルがアップロードされます。

GAS経由でアップした画像ファイルが開けない

Googleドライブの管理画面をGUIで操作した際には発生しないのですが、GASのスクリプトで実行しようとすると、ファイルが破損してしまいます。

アップロードした画像を端末にダウンロードしても上手くファイルを開くことができない状態です。

なぜGASのフォームでアップした画像ファイルが開けない?

ネットの情報などを調べたところ、原因はGASが2020年2月に対応したChrome V8ランタイムのバグのようです。

Google Apps Script(GAS)のWebアプリケーションとしてHTMLフォームを用意し、フォーム経由でGoogle driveにファイルをアップロードするスクリプトはネット上に色々なソースがあります。

しかし、V8ランタイム対応となった2020年2月以前に書かれたものがほとんどで、V8ランタイムのバグで実行できないことは書かれていません。

テキストファイルやHTMLファイルは問題なし

ちなみにこの事象はテキストファイルでは問題が起きていません。

テキストファイルをGASで作成したページのフォームでアップロードしても、ドライブのプレビューで表示可能でした。

また、HTMLファイルなども問題なくGoogle Apps Script経由でアップロードできます。

  • 画像ファイル(jpg,png)
  • 音声ファイル(wav)
  • 音楽ファイル(mp3)
  • 動画ファイル(mp4)

などのメディアファイルが破損する事象が発生しています。

不具合回避策はGASのV8を無効にする

画像ファイルのアップロード不具合はGoogle Apps Script(GAS)のV8ランタイムを有効化した際に発生します。

そのため、不具合を回避する方法は、GASのV8モードを無効化にすることです。

V8ランタイムを無効にした状態で、GASスクリプトでGoogleドライブに画像をアップロードすると、問題なくドライブ上で画像を閲覧できます。

※Google Apps ScriptのV8ランタイム無効化の方法はこちら

ただ、GASのV8モードを無効化にすると、ES2015などのJavascriptのモダンな構文が使用できなくなります。

変数の宣言で「let」、定数の定義に「const」などの宣言文を利用していたり、アロー関数を利用している場合は、V8ランタイムを無効化すると、コードがエラーするため、注意が必要です。

まとめ・終わりに

今回、Google Apps Script(GAS)のV8ランタイムを有効にした状態で、Googleドライブへ画像ファイルをアップロードするコードを実行すると、ファイルが壊れる事象を発生します。

こちらはV8ランタイムのバグと推定されており、V8モードを無効化することで不具合は解消されます。

ただ、すでにV8ランタイムに対応したGASのコードを書いている場合に、V8を無効にするとコードが実行エラーになります。

そのためV8対応のものは残しつつ、V8無効化した状態で動くコードをコピーして準備するのがオススメです。