【发布时间】:2021-01-22 22:12:20
【问题描述】:
您好,我有一个相当大的 PhpMailer 脚本,它可以上传 9 个文件并通过电子邮件发送 HTML 申请表。
它通过一个非常标准的 AJAX 脚本发送。我已经在各种设备和平台上对其进行了测试,一切正常。事实上,无论我试图做什么,我都无法打破它,但我客户的租户似乎已经找到了一种方法来打破它。
他们说他们已经使用了它,并且就他们而言,它已成功发送,但是没有发送或接收电子邮件或上传到服务器的任何文件的记录。
这里是完整的脚本,减去了一些表单字段以及连接到数据库以进行垃圾邮件检查的详细信息。
if ( isset($_POST['email']) && isset($_POST['name']) && filter_var($_POST['email'], FILTER_VALIDATE_EMAIL) ) {
// detect & prevent header injections
$test = "/(content-type|bcc:|cc:|to:)/i";
foreach ( $_POST as $key => $val ) {
if ( preg_match( $test, $val ) ) {
exit;
}
}
$dateKey = date( 'd-m-Y--H-i-s' );
$my_email = "control@XXXXXXXXXXXX.com";
ob_start();
require("smtp/class.phpmailer.php");
$mail = new PHPMailer();
$mail->IsSMTP();
$mail->Host = "mail.XXXXXXXX.com";
$mail->SMTPAuth = true;
$mail->Username = $my_email;
$mail->Password = "XXXXXXXXXXX";
$mail->From = $mail->Username;
$mail->FromName = $_POST['name'];
$mail->Sender = $_POST['email'];
function clean($string) {
$string = str_replace(' ', '-', $string);
return preg_replace('/[^A-Za-z0-9\-]/', '', $string);
}
if(isset($_FILES)) {
$uploadOk = 1;
$fileString = '';
$fileMessage = 'FILEERROR(';
$files = $_FILES;
$target_dir = $_SERVER['DOCUMENT_ROOT'] . "/XXXXXXXXXX/uploads/";
foreach ( $_FILES as $key => $file ) {
$imageFileExt = strtolower( pathinfo( $file["name"], PATHINFO_EXTENSION ) );
$file['name'] = clean($_POST['name']). "_" . $key . "_" . $dateKey . "." . $imageFileExt;
$target_file = $target_dir . basename($file["name"]);
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
$check = getimagesize($file["tmp_name"]);
if($check === false) {
$fileMessage .= $key."=noimage,";
$uploadOk = 0;
}
// Allow certain file formats
else if($imageFileType !== "jpg" && $imageFileType !== "png" && $imageFileType !== "jpeg"
&& $imageFileType !== "gif" ) {
$fileMessage .= $key."=wrongfile,";
$uploadOk = 0;
}
// Check if file already exists
else if (file_exists($target_file)) {
$fileMessage .= $key."=fileexists,";
$uploadOk = 0;
}
// Check file size
else if ($file["size"] > 20000000) { //20mb
$fileMessage .= $key."=toobig,";
$uploadOk = 0;
}
$fileString .= strtoupper($key).": <a href='http://www.XXXXXXXXXXXX.com/XXXXXXXXX/uploads/".$file['name']."'>".$file['name']."</a><br>";
}
$fileMessage .= ')';
}
$mail->CharSet = 'utf-8';
$mail->Encoding = 'quoted-printable';
$bcc = "xxx@xxxxx.com";
$mail->AddBCC($bcc);
$mail->AddReplyTo($_POST['email']);
$mail->WordWrap = 50;
$mail->Body = "<p><strong>APPLICATION<br /></strong></p>
<p>Property ".$_POST['address']."<br />
<div style='background:#f1f1f1;padding:5px 15px; margin-bottom:20px;'><p><strong>APPLICANT DETAILS:<br /></strong></p><p>
Name: ".$_POST['name']."<br />
Email: ".$_POST['email']."<br />
Telephone: ".$_POST['tel']."<br />
Date of birth: ".$_POST['DOB']."<br />
National insurance number: ".$_POST['NI']."<br /></p></div>
<div style='background:#f1f1f1;padding:5px 15px; margin-bottom:20px;'><p><strong>ADDRESS<br /></strong></p><p>
Address: ".$_POST['address']."<br />
Time at address: ".$_POST['addLength']."<br />
Reason to move: ".$_POST['move']."<br />";
///more fields added to body here but not necessary to show
$mail->Body.="<div style='background:#f1f1f1;padding:5px 15px; margin-bottom:20px;'><p><strong>FILE ATTACHMENTS:<br /></strong></p><p>".$fileString."</p></div>";
$mail->IsHTML(true);
$mail->Subject = 'Application';
/* my own validation */
$formerrors = array();
$errorstring = "";
///connects to database here, details removed but checks against spam keywords and creates an array of $formerrors
$conn->close();
if (sizeof($formerrors) > 0){
$errorstring = "(" ;
foreach($formerrors as $key=>$value){
if($y < sizeof($formerrors) ){
$errorstring .= $value.",";
$y++;
} else{
$errorstring .= $value.")";
}
}
echo $errorstring;
#### file errors ####
} else if($uploadOk === 0){
echo $fileMessage;
}
else {
$mail->AddAddress("XXX@XXXXX.com", 'recipient');
///send here
if ($mail->Send() == true) {
if ($uploadOk === 1) {
if(isset($_FILES)) {
$uploadfiles = $_FILES;
// Compress image
function compressImage($source, $destination, $quality) {
$info = getimagesize($source);
if ($info['mime'] == 'image/jpeg') {
$image = imagecreatefromjpeg($source);
} elseif ($info['mime'] == 'image/gif') {
$image = imagecreatefromgif($source);
} elseif ($info['mime'] == 'image/png') {
$image = imagecreatefrompng($source);
}
imagejpeg($image, $destination, $quality);
}
foreach ( $uploadfiles as $key => $upfile ) {
$imageFileType = strtolower( pathinfo( $upfile['name'], PATHINFO_EXTENSION ) );
$fileName = clean($_POST['name']). "_" . $key . "_" . $dateKey . "." . $imageFileType;
$target_file = $target_dir . basename( $fileName );
$img_dir = "img/";
compressImage($upfile["tmp_name"], $target_dir . basename( $fileName ), 60);
}
}
}
echo 'Message sent successfully';
}
else {
echo "failed";
}
}
}
【问题讨论】:
-
这看起来你可能没有关注PHP docs on handling uploads safely。看看the PHPMailer "send file upload" example。这是您之前提出的问题的延伸——分解您的问题并一次解决一个问题;你试图一次完成整个事情,但你需要先检查每个部分是否单独工作。添加更多日志记录!
-
对不起,我不明白哪个位不安全?我最初确实使用了 move_uploaded_file() 但发现我需要将它与 compressImage() 交换,以便我可以存储压缩图像。是这样还是因为我正在发送电子邮件然后在您的示例脚本以相反方式执行时存储文件?
-
我已经编辑了帖子以显示完整的 phpmailer 脚本。
-
感谢 Martin,问题是当我将其设置为 tmp_name 时,我的脚本将其标记为错误的文件类型。
-
在您的原始问题中,您没有显示您对
move_uploaded_file的使用,只是您直接访问$_FILES,因此我怀疑。您需要在使用它包含的 anything 之前验证$_FILES- 所以我看不出在安全处理上传的文件之前如何选择压缩图像:处理上传,然后压缩图像,而不是相反,而不是一个而不是另一个。发送电子邮件时是否不涉及图像文件是完全独立的决定。
标签: php ajax file-upload phpmailer