PHPMailer文件上传实现的正确性、安全性验证及临时文件疑问
Hey there! Let's break down your questions and walk through your file upload + PHPMailer code to address both your security concerns and temporary file questions.
Short answer: Yes, the temporary files in sys_get_temp_dir() will still exist after compression, and you do need to delete them manually.
Here's why:
tempnam()creates a persistent file in the system's temporary directory—this file won't be automatically deleted by PHP or the OS (unless your system has a cron job to clean old temp files, which you shouldn't rely on).- After you run
compressImage($uploadfile, $target_dir . basename($fileName), 60);, the original temp file at$uploadfileis no longer needed.
Fix: Add unlink($uploadfile); right after your compression step to clean up the temp file. To avoid leaving orphan files if compression fails, wrap it in a conditional or use a try/finally block:
else { $fileName = clean($_POST['appName']). "_" . $key . "_" . $dateKey . "." . $imageFileType; $compressedPath = $target_dir . basename($fileName); if (compressImage($uploadfile, $compressedPath, 60)) { $msg .= "compression success; "; unlink($uploadfile); // Clean up temp file only if compression works } else { $msg .= "compression failed; "; unlink($uploadfile); // Still clean up even if compression fails $uploadOk = 0; } }
Your code works in basic scenarios, but there are several security gaps and functional tweaks to make it robust:
Critical Security Fixes
- Fix Email Validation: You're only sanitizing the email with
FILTER_SANITIZE_EMAIL—you should also validate it's a valid address withFILTER_VALIDATE_EMAIL:$clean_email = filter_var($_POST['appEmail'], FILTER_VALIDATE_EMAIL); if (!$clean_email) { die("Invalid email address"); } - Avoid Hardcoded Credentials: Your SMTP username/password are hardcoded in the script. This is a huge security risk (if your code is leaked, attackers can access your email account). Use environment variables instead:
$mail->Username = getenv('SMTP_USER'); $mail->Password = getenv('SMTP_PASS'); - Prevent XSS in Email Links: The
$fileStringuses raw$file['name']in the email HTML. Attackers could upload files with names containing malicious HTML/JS (e.g.,"><script>stealCookies()</script>.jpg). Escape the filename, and use the actual saved filename (not the original, which was broken):$safeFileName = htmlspecialchars($fileName, ENT_QUOTES); $fileString .= strtoupper($key).": <a href='XXXXXXXX/uploads/" . $safeFileName . "'>" . $safeFileName . "</a><br>"; - Better File Type Validation: Checking file extensions alone is insecure (attackers can rename a malware file to
.jpg). Use the MIME type fromgetimagesize()to confirm it's actually an image:$check = getimagesize($uploadfile); if($check === false) { $fileMessage .= $key."=noimage,"; $uploadOk = 0; } else { $allowedMimes = ['image/jpeg', 'image/png', 'image/gif']; if (!in_array($check['mime'], $allowedMimes)) { $fileMessage .= $key."=wrongfile,"; $uploadOk = 0; } }
Functional Improvements
- Fix File Existence Check: You're checking if the original filename exists in
$target_dir, but you're saving the file under$fileName. Update the check to use the actual saved filename:$target_file = $target_dir . $fileName; if (file_exists($target_file)) { $fileMessage .= $key."=fileexists,"; $uploadOk = 0; } - Improve Error Handling: Instead of concatenating strings to
$msg, use an array to track errors—this makes debugging easier:$errors = []; // ... later ... $errors[] = "File {$key} is not an image"; // ... at the end ... echo 'Message sent successfully. '.implode(' ', $errors); - Add the File Links to the Email: Right now, your email body doesn't include the
$fileStringyou built. Update theBodyline:$mail->Body = "This is the HTML message body <b>in bold!</b><br><br>Uploaded Files:<br>{$fileString}"; - Secure the
cleanFunction: Your current function allows hyphens, which is fine, but consider addingtrim()to remove leading/trailing spaces before replacing:function clean($string) { $string = trim($string); $string = str_replace(' ', '-', $string); return preg_replace('/[^A-Za-z0-9\-]/', '', $string); }
Overall, the core logic of uploading, compressing, and emailing works, but the security fixes are critical to prevent attacks like XSS, file upload malware, and credential leaks. Don't forget to test edge cases (large files, invalid file types, duplicate filenames) to ensure everything behaves as expected.
内容的提问来源于stack exchange,提问作者cannon303

