从网络表单将图像上传到 Google 电子表格

Upload an image to a Google spreadsheet from WEB FORM

所以基本上 它从 google 张自动生成的脚本。我找不到 link 或任何可以帮助我调整它的东西,所以我可以从我的网站上传图片。它只发送图像名称而不是实际图像。 如果有人能向我解释如何调整它以便发送实际图像,我将非常高兴。

<input type="text" id="email" name="email:" placeholder="">
 <input type="file" id="myFile" name="filename">
                    
 <button>
   Send
</button>
Out put
Email: Someone@gmail.com
FileName: Untitled-1.jpg

// if you want to store your email server-side (hidden), uncomment the next line
 var TO_ADDRESS = "***@gmail.com";

// spit out all the keys/values from the form in HTML for email
// uses an array of keys if provided or the object to determine field order
function formatMailBody(obj, order) {
  var result = "";
  if (!order) {
    order = Object.keys(obj);
  }
  
 
  
  // loop over all keys in the ordered form data
  for (var idx in order) {
    var key = order[idx];
    result += "<h4 style='text-transform: capitalize; margin-bottom: 0'>" + key + "</h4><div>" + sanitizeInput(obj[key]) + "</div>";
    // for every key, concatenate an `<h4 />`/`<div />` pairing of the key name and its value, 
    // and append it to the `result` string created at the start.
  }
  return result; // once the looping is done, `result` will be one long string to put in the email body
}

// sanitize content from the user - trust no one 
// ref: https://developers.google.com/apps-script/reference/html/html-output#appendUntrusted(String)
function sanitizeInput(rawInput) {
   var placeholder = HtmlService.createHtmlOutput(" ");
   placeholder.appendUntrusted(rawInput);
  
   return placeholder.getContent();
 }

function doPost(e) {

  try {
    Logger.log(e); // the Google Script version of console.log see: Class Logger
    record_data(e);
    
    // shorter name for form data
    var mailData = e.parameters;

    // names and order of form elements (if set)
    var orderParameter = e.parameters.formDataNameOrder;
    var dataOrder;
    if (orderParameter) {
      dataOrder = JSON.parse(orderParameter);
    }
    
    // determine recepient of the email
    // if you have your email uncommented above, it uses that `TO_ADDRESS`
    // otherwise, it defaults to the email provided by the form's data attribute
    var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
    
    // send email if to address is set
    if (sendEmailTo) {
      MailApp.sendEmail({
        to: String(sendEmailTo),
        subject: "Contact form submitted",
        // replyTo: String(mailData.email), // This is optional and reliant on your form actually collecting a field named `email`
        htmlBody: formatMailBody(mailData, dataOrder)
      });
    }

    return ContentService    // return json success results
          .createTextOutput(
            JSON.stringify({"result":"success",
                            "data": JSON.stringify(e.parameters) }))
          .setMimeType(ContentService.MimeType.JSON);
  } catch(error) { // if error return this
    Logger.log(error);
    return ContentService
          .createTextOutput(JSON.stringify({"result":"error", "error": error}))
          .setMimeType(ContentService.MimeType.JSON);
  }
}


/**
 * record_data inserts the data received from the html form submission
 * e is the data received from the POST
 */
function record_data(e) {
  var lock = LockService.getDocumentLock();
  lock.waitLock(30000); // hold off up to 30 sec to avoid concurrent writing
  
  try {
    Logger.log(JSON.stringify(e)); // log the POST data in case we need to debug it
    
    // select the 'responses' sheet by default
    var doc = SpreadsheetApp.getActiveSpreadsheet();
    var sheetName = e.parameters.formGoogleSheetName || "responses";
    var sheet = doc.getSheetByName(sheetName);
    
    var oldHeader = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
    var newHeader = oldHeader.slice();
    var fieldsFromForm = getDataColumns(e.parameters);
    var row = [new Date()]; // first element in the row should always be a timestamp
    
    // loop through the header columns
    for (var i = 1; i < oldHeader.length; i++) { // start at 1 to avoid Timestamp column
      var field = oldHeader[i];
      var output = getFieldFromData(field, e.parameters);
      row.push(output);
      
      // mark as stored by removing from form fields
      var formIndex = fieldsFromForm.indexOf(field);
      if (formIndex > -1) {
        fieldsFromForm.splice(formIndex, 1);
      }
    }
    
    // set any new fields in our form
    for (var i = 0; i < fieldsFromForm.length; i++) {
      var field = fieldsFromForm[i];
      var output = getFieldFromData(field, e.parameters);
      row.push(output);
      newHeader.push(field);
    }
    
    // more efficient to set values as [][] array than individually
    var nextRow = sheet.getLastRow() + 1; // get next row
    sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);

    // update header row with any new data
    if (newHeader.length > oldHeader.length) {
      sheet.getRange(1, 1, 1, newHeader.length).setValues([newHeader]);
    }
  }
  catch(error) {
    Logger.log(error);
  }
  finally {
    lock.releaseLock();
    return;
  }

}

function getDataColumns(data) {
  return Object.keys(data).filter(function(column) {
    return !(column === 'formDataNameOrder' || column === 'formGoogleSheetName' || column === 'formGoogleSendEmail' || column === 'honeypot');
  });
}

function getFieldFromData(field, data) {
  var values = data[field] || '';
  var output = values.join ? values.join(', ') : values;
  return output;
}```


在 Apps 脚本网络应用程序中,为了将 file-input 数据从 HTML 表单发送到服务器,推荐的方法是通过 [=28 调用 server-side 函数=].在这种情况下,您不会依赖 doPost 函数(当 POST 向 Web 应用 URL 发出请求时调用),而是依赖 server-side 函数(名为processForm 在下面的示例中)通过 google.script.run.

调用

以这种方式调用 server-side 函数时,如果将 HTML 表单元素作为参数传递,则可以访问输入字段名称,如 here 所述:

If you call a server function with a form element as a parameter, the form becomes a single object with field names as keys and field values as values. The values are all converted to strings, except for the contents of file-input fields, which become Blob objects.

现在,在决定如何将图像插入电子表格时,您有多种选择,具体取决于:

  • 是要将图像插入特定单元格还是将图像插入单元格(不绑定到特定单元格)。
  • 图像的大小。
  • 您是否担心使此图片public易于访问。

方法一。使用 insertImage:

如果您想“跨单元格”插入图像(也就是说,图像不在一个特定的单元格中),并且您不希望此图像 publicly可访问,您可以只提供与图像对应的 Blob 作为 Sheet.insertImage(blobSource, column, row).

的参数

对应的代码可能是这样的:

index.html:

<html>
  <body>
    <form>
      <input type="text" id="email" name="email:" placeholder="">
      <input type="file" id="myFile" name="filename">      
      <input type="button" value="Send" onclick="google.script.run.processForm(this.parentNode)">
    </form>
  </body>
</html>

Code.gs:

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

function processForm(e) {
  var contentType = 'image/jpeg'; // Could also be 'image/bmp', 'image/gif', or 'image/png'
  var image = e.filename;
  var image = image.getAs(contentType);
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Sheet1"); // Change sheet name if necessary
  sheet.insertImage(image, 1, 1); // Top-left corner of image is top-left corner of A1 (image not in A1, but "over cells")
}

来自输入字段的其他数据可以使用输入 namee 中检索。例如,输入的 email 将通过 e["email:"].

检索

重要:因为 this issue, images above a certain size cannot be inserted to a sheet via insertImage; trying to do so results in the following error message Exception: Service error: Spreadsheets (I have noticed this works with an image around 150 KB, but not with one around 260 KB). So if you want to insert an image with a higher size, you might want to check method #2 (or resize the image before inserting, for example, using the workaround found in this answer by Tanaike).

方法二。使用 =IMAGE(url):

如果您想将图像插入特定单元格,并且您不关心此图像是否 public 可访问,您可以通过创建 public 可访问 link 添加到此图像并使用函数 IMAGE.

例如,您可以将此图片上传到云端硬盘,使其 public 可访问(与 Anyone with the link 共享),并通过 public URL 添加=23=]。在这种情况下,您的 server-side 函数可能是这样的(有关 URL 的更多详细信息,请参阅 this):

function processForm(e) {
  var contentType = 'image/jpeg';
  var image = e.filename;
  var image = image.getAs(contentType);
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Sheet1"); // Change sheet name if necessary
  var file = DriveApp.createFile(image); // Add image to Drive
  file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW); // Share image with Anyone
  sheet.getRange("A1").setFormula("=IMAGE(\"https://drive.google.com/uc?export=view&id=" + file.getId() + "\")");
}

此方法的一个优点是您可以插入更大尺寸的图像。

重要提示:

  • 目前,由于 this issue,如果启用了 V8,则无法通过 HTML 表单 file-input 字段成功上传图像。因此,您必须禁用 V8 运行时才能正常工作(单击 Run > Disable new Apps Script runtime powered by Chrome V8)。