[英]PHPMailer multiple attachments sends email but no files
我已經嘗試了幾乎所有我能找到的關於這個特定主題的 StackOverflow(並且有很多),但大多數人忘記了表單標簽中的enctype
或其他東西。 我仍然收到電子郵件,只是沒有附加任何文件。
當我提交表單時,我的$_FILES
數組似乎沒有被填滿。 下面的代碼使用提交的字段數據發送 html 電子郵件非常好,但沒有附件。
這是表單提交輸入數據但沒有附件時日志中的最新錯誤:
[24-Jan-2020 22:06:33 UTC] PHP Warning: count(): Parameter must be an array or an object that implements Countable in *******/public_html/rtform/contact.php on line 89
我在下面的代碼中指出了第 89 行。
這是我的表單的開頭和結尾,我的文件輸入在底部(表單的其余部分太長,無法在此處包含整個內容:
<form id="contact-form" method="POST" action="contact.php" role="form" enctype="multipart/form-data">
<div class="controls">
<!-- the middle of the form here -->
<div class="row">
<h3 class="form_title">Upload Additional Supporting Documents</h3>
<div class="col-lg-12">
<label for="attachments[]">Select one or more files:
<input name="attachments[]" type="file" multiple="multiple">
</label>
</div>
</div>
<hr/>
<div class="form-group">
<div class="g-recaptcha" data-sitekey="**************************************" data-callback="verifyRecaptchaCallback" data-expired-callback="expiredRecaptchaCallback"></div>
<input class="form-control d-none" data-recaptcha="true" required data-error="Please complete the Captcha">
<div class="help-block with-errors"></div>
</div>
<p><span class="red">Fields marked with * denotes a required field.</span></p>
<input type="submit" class="btn btn-success btn-send" value="Submit Order">
<div class="messages"></div>
</div><!-- end .controls -->
</form>
我的表單處理 PHP 文件很長,但可能需要包含所有內容,因此:
<?php
// error_reporting(E_ALL); ini_set('display_errors', 1);
// Import PHPMailer classes into the global namespace
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'includes/phpmailer/src/Exception.php';
require 'includes/phpmailer/src/PHPMailer.php';
// Require ReCaptcha class
require('recaptcha-master/src/autoload.php');
// ReCaptch Secret
$recaptchaSecret = *******************************;
/*******************************************************
*
* Here I have a long array with all of the input names and variables which I use for
* the logic below for my html email template(which works great). Shouldn't be necessary
* for this problem, so I'm excluding it.
*
*******************************************************/
// Instantiation and passing `true` enables exceptions
$mail = new PHPMailer(true);
try {
if ( !empty($_POST) ) {
$msg = ''; // To be used for dynamic messaging
// ReCaptcha
// Validate the ReCaptcha, if something is wrong, we throw an Exception,
// i.e. code stops executing and goes to catch() block
if (!isset($_POST['g-recaptcha-response'])) {
throw new \Exception('ReCaptcha is not set.');
}
$recaptcha = new \ReCaptcha\ReCaptcha($recaptchaSecret, new \ReCaptcha\RequestMethod\CurlPost());
// we validate the ReCaptcha field together with the user's IP address
$response = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
if (!$response->isSuccess()) {
throw new \Exception('ReCaptcha was not validated.');
}
$requestorEmail = "";
//Make sure the address they provided is valid before trying to use it
if (array_key_exists('requestoremail', $_POST) && PHPMailer::validateAddress($_POST['requestoremail'])) {
$requestorEmail = $_POST['requestoremail'];
} else {
$msg = 'Error: invalid requestor email address provided';
throw new \Exception('Requestor email, ' . $requestorEmail . ', is not a valid email address.');
}
//Recipients
$mail->setFrom('senderemail@email.com', 'Sender');
$mail->addAddress('recipientemail@email.com', 'Recipient'); // Add a recipient
$mail->addAddress($requestorEmail, 'Requestor'); // Name is optional
$mail->addReplyTo('replytoemail@email.com', 'Reply To Email');
/*************************************
*
* The attachment-related stuff:
*
*************************************/
$maxSize = 2 * 1024 * 1024; // 2 MB
$fileTypes = array('text/plain', 'application/pdf', 'application/msword', 'application/rtf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'); // allowed mime-types
// Passing these variables to my jQuery ajax request at the bottom of this file to try to get some helpful info
$theFiles = $_FILES;
$filesCount = count($_FILES['attachments']['tmp_name']);
if (isset($_FILES)) {
//Attach multiple files one by one
//******************** The line below is line 89 ********************/
for ($ct = 0; $ct < count($_FILES['attachments']['tmp_name']); $ct++) {
$uploadfile = tempnam(sys_get_temp_dir(), hash('sha256', $_FILES['attachments']['name'][$ct]));
$filename = $_FILES['attachments']['name'][$ct];
$filesize = $_FILES['attachments']['size'][$ct];
$filemime = mime_content_type($uploadfile);
// Check $_FILES['upfile']['error'] value.
switch ($_FILES['attachments']['error'][$ct]) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new RuntimeException('No file sent.');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new RuntimeException('Exceeded filesize limit.');
default:
throw new RuntimeException('Unknown errors.');
}
try {
if (in_array($filemime, $fileTypes)){
if ($filesize <= $maxSize) {
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$ct], $uploadfile)) {
$mail->addAttachment($uploadfile, $filename);
} else {
$msg .= 'Failed to move file to ' . $uploadfile;
throw new \Exception('Failed to move file to ' . $uploadfile);
}
}
else {
$msg = "File[s] are too large. They must each be less than or equal to 2MB.";
throw new \Exception('File[s] are too large. They must each be less than or equal to 2MB.');
}
}
else {
$msg = "File[s] must only be of these types: .txt, .rtf, .pdf, .doc, .docx. Please try again.";
throw new \Exception('File[s] must only be of these types: .txt, .rtf, .pdf, .doc, .docx. Please try again.');
}
}
catch (Exception $e) {
$responseArray = array('type' => 'danger', 'message' => $msg); // or $e->getMessage()
}
}
}
else {
$msg = "No file added.";
throw new \Exception('No file added.');
}
// Get template file contents
$template = file_get_contents("email-template.html");
/*************************************************************************
*
* This is constructing my email html template with input data
*
**************************************************************************/
// Loop $_POST content, compare to $fields array, and include/replace if not empty
foreach($_POST as $key => $value) {
// Create a generic row to use for each
$value_row = "<li>$fields[$key]: $value</li>";
if ( !empty( $value ) ) {
// Check each group's first member and insert/replace appropriate title string
if( $key == "casenumber" ) {
$value_row = "<h2>General Information</h2>\n<ul style='list-style:none;'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "client-fullname" ) {
$value_row = "</ul><h2>Client/Applicant</h2>\n<ul style='list-style:none;'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "employer-fullname" ) {
$value_row = "</ul><h2>Employer/Insured</h2>\n<ul style='list-style:none;'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "requestor-attorney" ) {
$value_row = "</ul><h2>Requestor</h2>\n<ul style='list-style:none;'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "billingcarrier" ) {
$value_row = "</ul><h2>Billing Information</h2>\n<ul style='list-style:none;'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "caseplantiff" ) {
$value_row = "</ul><h2>Case Caption</h2>\n<ul style='list-style:none;'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "oclattorneyname" ) {
$value_row = "</ul><h2>Opposing Counsel</h2>\n<ul style='list-style:none;'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location1facility" ) {
$value_row = "</ul><h2>Delivery Instructions</h2><h3>Location 1</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location2facility" ) {
$value_row = "</ul><h3>Location 2</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location3facility" ) {
$value_row = "</ul><h3>Location 3</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location4facility" ) {
$value_row = "</ul><h3>Location 4</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location5facility" ) {
$value_row = "</ul><h3>Location 5</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location6facility" ) {
$value_row = "</ul><h3>Location 6</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location7facility" ) {
$value_row = "</ul><h3>Location 7</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location8facility" ) {
$value_row = "</ul><h3>Location 8</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location9facility" ) {
$value_row = "</ul><h3>Location 9</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
elseif( $key == "location10facility" ) {
$value_row = "</ul><h3>Location 10</h3>\n<ul style='list-style:none;' class='location-list'><li>$fields[$key]: $value</li>";
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
else {
$template = str_replace('{{ '.$key.' }}', $value_row, $template);
}
}
else {
$template = str_replace('{{ '.$key.' }}', '', $template);
}
}
// Content
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = 'Order Form Submission from Real Time Records Website';
$mail->Body = $template;
$mail->send();
// Generic success message
$msg = 'Your order has been received successfully. We will contact you shortly. Please contact us if you have any questions.';
$responseArray = array('type' => 'success', 'message' => $msg, 'files' => json_encode($theFiles), 'number-of-files' => "$filesCount");
} // end if( !empty( $_POST ) )
} catch (Exception $e) {
// Generic error message
$msg = 'There was an error while submitting the form. Please try again later';
$responseArray = array('type' => 'danger', 'message' => $msg); // or $e->getMessage()
// echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}
// This encodes the output message(with some of those attachment details) for the jQuery ajax request to pickup
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$encoded = json_encode($responseArray);
header('Content-Type: application/json');
echo $encoded;
} else {
echo $responseArray['message'];
}
我的 jQuery 實際上只是顯示傳遞的錯誤或成功消息,盡管我已經從$_FILES
向它傳遞了一些信息以查看它是否被填滿,但事實並非如此。
當發出ajax請求時,我在與附件相關的響應中看到的接收數據是:
files = '[]', 'number-of-files' = '0'
任何有 PHPMailer 經驗的人都能看出我做錯了什么嗎?
編輯 x2
這是我更新的 jQuery,根據下面 Synchro 的回答。 它現在從表單中獲取文件,並將多個文件正確附加到 FormData 對象,但 php $_FILES
對象只計算/顯示一個文件(當有兩個時)並且不將任何附加到發送的電子郵件:
$(function () {
window.verifyRecaptchaCallback = function (response) {
$('input[data-recaptcha]').val(response).trigger('change');
}
window.expiredRecaptchaCallback = function () {
$('input[data-recaptcha]').val("").trigger('change');
}
$('#contact-form').validator();
$('#contact-form').on('submit', function (e) {
if (!e.isDefaultPrevented()) {
var url = "contact.php";
const theForm = document.getElementById('contact-form');
var fd = new FormData(theForm);
var files = $("#file_attachments").prop('files');
for (var i = 0; i < files.length; i++) {
fd.append("attachments", files[i]);
console.log("File #"+(i+1)+" attached: "+files[i]);
}
$.ajax({
type: "POST",
url: url,
data: fd,
processData: false,
contentType: false,
success: function(data) {
var messageAlert = 'alert-' + data.type;
var messageText = data.message;
var messageFiles = data.files;
var messageFilesCount = data.numberOfFiles
var alertBox = '<div class="alert ' + messageAlert + ' alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + messageText + '</div><div>Number of Files: ' + messageFilesCount + ' - ' + messageFiles + '</div>';
if (messageAlert && messageText) {
$('#contact-form').find('.messages').html(alertBox);
$('#contact-form')[0].reset();
grecaptcha.reset();
}
},
error: function(data) {
//this is going to happen when you send something different from a 200 OK HTTP
alert('Ooops, something happened: ' + data.message);
}
});
return false;
}
})
});
值得向您的 JS 詢問...
你這樣做:
data: $(this).serialize(),
這將不包括文件附件。 您需要使用JS FormData
類並關閉一些 jQuery 功能。
首先,給文件輸入一個 id,這樣你就可以更容易地定位它(你的label
標簽也應該定位這個 id,而不是name
屬性):
<input name="attachments[]" id="attachments" type="file" multiple="multiple">
然后更改您的 ajax 代碼以將表單數據放入FormData
對象中,然后向其中添加文件元素:
var fd = new FormData('contact-form');
var files = $("#attachments").get(0).files;
for (var i = 0; i < files.length; i++) {
fd.append("attachments", files[i]);
}
$.ajax({
type: "POST",
url: url,
data: fd,
processData: false,
contentType: false,
success: function (data) {
var messageAlert = 'alert-' + data.type;
var messageText = data.message;
var alertBox = '<div class="alert ' + messageAlert + ' alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + messageText + '</div>';
if (messageAlert && messageText) {
$('#contact-form').find('.messages').html(alertBox);
$('#contact-form')[0].reset();
grecaptcha.reset();
}
},
error: function (data) {
//this is going to happen when you send something different from a 200 OK HTTP
alert('Ooops, something happened: ' + data.message);
}
});
注意:此方法在版本 10 之前的 Internet Explorer 中不起作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.