从网络表单将图像上传到 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")
}
来自输入字段的其他数据可以使用输入 name
从 e
中检索。例如,输入的 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
)。
所以基本上 它从 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")
}
来自输入字段的其他数据可以使用输入 name
从 e
中检索。例如,输入的 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
)。