6

My question is exactly as this one: Upload a file to a Google Web Apps with doPost

How to upload a file directly to a Google Script's Web App from another domain? I answered a workaround in that question to convert the file in a base64 string but the question remains. Is it possible to upload a file to Google Scripts or only strings?

Community
  • 1
  • 1
Maycow Moura
  • 6,471
  • 2
  • 22
  • 19

1 Answers1

14

Files cannot be uploaded directly by "doPost()" of GAS from HTML form on local PC. Because "multipart/form-data" may be not able to be used for "doPost()". So converting Base64 leads to the solution as you say.

There are 2 ways for uploading files by "doPost()".

1. Upload a file from HTML form on GAS project

This uploads a file using GAS and HTML in GAS project. In this case, the file doesn't convert to Base64 by the script. (It may convert as the internal process.)

2. Upload a file from HTML form on local PC

This uploads a file from HTML form on local PC. GAS controls "doPost()". In this case, the file is encoded to Base64 and upload as text data, and then decoded to the file using GAS.


1. Upload a file from HTML form on GAS project

Rule :

  1. Following sample script and HTML have to be made into a project of Google Apps Script.

  2. Deploy the GAS project as a web application. https://developers.google.com/apps-script/guides/web And retrieve URL.

  3. After updated the script, it has to be updated as a new version.

Form.html :

<html>
  <body>
    <form>
      <input type="file" name="upFile">
      <input type="button" value="ok" onclick="google.script.run.upload(this.parentNode)">
    </form>
  </body>
</html>

Script :

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Form.html');
}

function upload(e) {
  DriveApp.createFile(e.upFile);
}

2. Upload a file from HTML form on local PC

The rule is almost the same to above one. The script is placed on GAS project. But HTML form is placed on local PC.

Script :

function doGet(e) {
  return message("Error: no parameters");
}

function doPost(e) {
  if (!e.parameters.filename || !e.parameters.file) {
    return message("Error: Bad parameters");
  } else {
    var data = Utilities.base64Decode(e.parameters.file, Utilities.Charset.UTF_8);
    var blob = Utilities.newBlob(data, MimeType.PNG, e.parameters.filename);
    DriveApp.createFile(blob);
    return message("completed");
  }
}

function message(msg) {
  return ContentService.createTextOutput(JSON.stringify({result: msg})).setMimeType(ContentService.MimeType.JSON);
}

HTML :

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
</head>
<body>
    <input type="file" id="file">

    <script type="text/javascript">
        $(function(){
            var url = 'https://script.google.com/macros/s/[Project ID]/exec';
            var params = {
                filename: 'samplefile',
                imageformat: 'PNG'
            };

            $('#file').on("change", function() {
                var file = this.files[0];
                var fr = new FileReader();
                fr.onload = function(e) {
                    params.file = e.target.result.replace(/^.*,/, '');
                    postJump();
                }
                fr.readAsDataURL(file);
            });

            function postJump(){
                var html = '<form method="post" action="'+url+'" id="postjump" style="display: none;">';
                Object.keys(params).forEach(function (key) {
                    html += '<input type="hidden" name="'+key+'" value="'+params[key]+'" >';
                });
                html += '</form>';
                $("body").append(html);
                $('#postjump').submit();
                $('#postjump').remove();
            }
        });
    </script>
</body>
</html>

This sample script supposes to upload a PNG file as a test. If you want to upload other files, please change mime type. https://developers.google.com/apps-script/reference/base/mime-type

For HTML sample, the file is uploaded when the file is selected.

If this will be helpful for you, I'm glad.

Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • Thank you for clarifying. I already know about base64 files but wasn't sure if direct file uploading was allowed – Maycow Moura Feb 16 '17 at 22:59
  • @Tanaike this is tremendously helpful, as is your blog. Thanks for your great work! – duhaime Jul 24 '17 at 00:38
  • 1
    @duhaime Welcome. Thank you for stopping at my blog, too. – Tanaike Jul 24 '17 at 00:40
  • @Tanaike the only question I have is: why do you use `.replace(/^.*,/, '')` on the input data? I'd be very grateful for any insight you can offer on this question. – duhaime Jul 24 '17 at 01:22
  • 1
    @duhaime When data is encoded to Base64,in order to remove the unnecessary portions and use it as a blob, that is used. – Tanaike Jul 24 '17 at 03:18
  • When I use the first technique e.upFile is just a 10 byte text file - "FileUpload". Where's the file gone?? – Andrew Roberts Mar 06 '19 at 19:40
  • @Andrew Roberts I apologize for the inconvenience. In my environment, I could confirm that the text file with the size of 10 bytes can be uploaded and created on root folder (``DriveApp.createFile(e.upFile)`` creates the file to root folder as the default.) as a text file. I'm really sorry that I couldn't replicate your situation. Can I ask you about the method for replicating your situation? – Tanaike Mar 06 '19 at 23:51
  • @Tanaike Thanks for the reply. When I copied your code verbatim it worked fine :) Must be missing something in mine somwhere. Thanks. – Andrew Roberts Mar 07 '19 at 09:47
  • @Andrew Roberts Thank you for testing it again. I'm glad it worked. – Tanaike Mar 08 '19 at 00:45