-2

I need to upload files to my Google Drive via a Google App Script. The goal is to be able to let users upload a file to my Google Drive from my website. The code is largely the same as a tutorial I found online, I just added a link to my website banner and also added some code to send me an email when someone uploads a file.

The problem is, it works for text file but not binary files (jpeg, pdf, etc). It correctly creates a file in the appropriate folder, but the file cannot be opened. The binary file that gets created does have some data in it.. when I open the created file in TextEdit, it does look somewhat similar to the original, but some of the characters look different. The filesize of the new created file is also larger than the original.

The problem does not occur with text files. The code is listed below.

HTML code

<!doctype html>
<style type="text/css">
body {
    background-color: #FFFFFF;
}
</style>
<BR>
<BR>
<BR>
<div align="center">
  <p><img src="https://rosspalmermd.files.wordpress.com/2020/05/color-logo-with-background.png" width=320></p>
  <table width="459" border="0">
    <tbody>
      <tr>
        <td width="462"><div align="center">
          <hr>
        </div>
          <form id="myForm" align="center">
            <input type="text" name="myName" placeholder="Your name...">
            <input type="email" name="myEmail" placeholder="Your email...">
            <input type="file" name="myFile">
            <input type="submit" value="Upload File" 
           onclick="this.value='Uploading..';
                    google.script.run.withSuccessHandler(fileUploaded)
                    .uploadFiles(this.parentNode);
                    return false;">
          </form>
          <div id="output"></div>
          <script>
    function fileUploaded(status) {
        document.getElementById('myForm').style.display = 'none';
        document.getElementById('output').innerHTML = status;
    }
          </script>
        <style>
 input { display:block; margin: 20px; }
 
          </style>
        <hr></td>
      </tr>
    </tbody>
  </table>
  <h3>&nbsp;</h3>
  <p>&nbsp;</p>
</div>

Server side code:



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

function uploadFiles(form) {
  
  try {
    
    var dropbox = "DriveUploader";
    var folder, folders = DriveApp.getFoldersByName(dropbox);
    
    if (folders.hasNext()) {
      folder = folders.next();
    } else {
      folder = DriveApp.createFolder(dropbox);
    }
    
    var blob = form.myFile; 
    var file = folder.createFile(blob); 
    
    file.setDescription("Uploaded by " + form.myName);
        
    MailApp.sendEmail("email@email.com",
                  "File uploaded to website",
                  form.myName + " (" + form.myEmail + ") has uploaded a file " + file.getUrl());
    
    return "File uploaded successfully. We will contact you soon.";
    
  } catch (error) {
    
    return error.toString();
  }
}
Marios
  • 26,333
  • 8
  • 32
  • 52
  • I will PayPal $20 to anyone who can solve my problem – Ross Palmer May 22 '20 at 14:31
  • maybe use 'var blob = form.myFile.getBlob; ' instead of 'var blob = form.myFile;' – Michiel the Temp May 22 '20 at 14:46
  • Thanks, tried it. Got: "Exception: Argument cannot be null: blob" – Ross Palmer May 22 '20 at 14:48
  • I should add that the file that gets created does have some data in it.. when I open the created file in TextEdit, it does look somewhat similar to the original, but some of the characters look different. – Ross Palmer May 22 '20 at 14:50
  • https://stackoverflow.com/a/41997307/7215091 – Cooper May 22 '20 at 14:50
  • Does this answer your question? [How do I convert jpg or png to blob on google app script?](https://stackoverflow.com/questions/41994351/how-do-i-convert-jpg-or-png-to-blob-on-google-app-script) – TheMaster May 22 '20 at 14:53
  • How about setting the `MimeType`? –  May 22 '20 at 14:53
  • Try replacing using this syntax for createFile: createFile(name, content, mimeType) More about MIME Types: https://developers.google.com/apps-script/reference/base/mime-type – Eduardo Conte May 22 '20 at 14:53
  • Thanks Cooper. Unfortunately I do not know the contentType at design time, so hardcoding "image/jpeg" won't work. I need to be able to accept any kind of file. – Ross Palmer May 22 '20 at 14:59
  • 1
    See https://meta.stackoverflow.com/q/292222/ – TheMaster May 22 '20 at 15:01
  • Could there be a way to accept only JPG, PNG, and PDF? Somehow query the "myFile" object to find out what it is, then do different createFile functions for those 3 file types? Thanks. – Ross Palmer May 22 '20 at 15:03
  • `var mimeType = blob.getContentType();` To create the file use `Drive` instead of `DriveApp` –  May 22 '20 at 15:04
  • 1
    If you read the answer, you would know that contentType is not hardcoded, but inferred on the client side: `file.type` – TheMaster May 22 '20 at 15:04

1 Answers1

3

I found the solution for your problem, here is the code:

HTML code:

<!DOCTYPE html>
<style type="text/css">

body {
    background-color: #FFFFFF;
}
</style>
<BR>
<BR>
<BR>
<div align="center">
  <p><img src="https://rosspalmermd.files.wordpress.com/2020/05/color-logo-with-background.png" width=320></p>
  <table width="459" border="0">

    <tbody>
      <tr>
        <td width="462"><div align="center">
          <hr>
        </div>
          <form id="myForm" align="center">
            <div id="data"></div>
            <input type="text" id="myName" name="myName" placeholder="Your name...">
            <input type="email" id="myEmail" name="myEmail" placeholder="Your email...">
            <input id="uploadfile" type="file" name="myFile">
            <input type="submit" value="Upload File" 
           onclick="this.value='Uploading..';
           getFiles();
            return false;">
          </form>
          <div id="output"></div>

          <script>

    function getFiles() {
     const name = document.getElementById('myName').value;
     const email = document.getElementById('myEmail').value;
     const f = document.getElementById('uploadfile');
     [...f.files].forEach((file, i) => {
      const fr = new FileReader();
      fr.onload = (e) => {
       const data = e.target.result.split(",");
       const obj = {fileName: f.files[i].name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1],myName: name,myEmail: email};
       google.script.run.withSuccessHandler(fileUploaded)
       .uploadFiles(obj);
      }
     fr.readAsDataURL(file);
    });
    }

     function fileUploaded(status) {
        document.getElementById('myForm').style.display = 'none';
        document.getElementById('output').innerHTML = status;
    }
    </script>

        <style>
 input { display:block; margin: 20px; }

          </style>
        <hr></td>
      </tr>
    </tbody>
  </table>
  <h3>&nbsp;</h3>
  <p>&nbsp;</p>
</div>

Server side code:

function doGet(e) {
  return HtmlService.createHtmlOutputFromFile('form.html');

}

function uploadFiles(obj) {

  try {

    var dropbox = "DriveUploader";
    var folder, folders = DriveApp.getFoldersByName(dropbox);

    if (folders.hasNext()) {
      folder = folders.next();
    } else {
      folder = DriveApp.createFolder(dropbox);
    }

    var blob = Utilities.newBlob(Utilities.base64Decode(obj.data), obj.mimeType, obj.fileName);
    var file = folder.createFile(blob);
    file.setDescription("Uploaded by " + obj.myName);

    MailApp.sendEmail("email@email.com",
                  "File uploaded to website",
                  obj.myName + " (" + obj.myEmail + ") has uploaded a file " + file.getUrl());

    return "File uploaded successfully. We will contact you soon.";

  } catch (error) {

    return error.toString();
  }
}
Eduardo Conte
  • 1,145
  • 11
  • 18