本文详解 PHP 文件上传时自定义文件名的正确方法,重点解决因 MIME 类型误用导致的 `move_uploaded_file()` 路径
错误问题,并提供安全、可复用的重命名与上传实践。
在 PHP 中为上传文件指定新名称是常见需求,但若处理不当(如直接将完整 MIME 类型 text/plain 作为文件名一部分),极易引发 failed to open stream: No such file or directory 错误——这并非权限或目录问题,而是文件路径非法所致。原代码中:
$file_type = $_FILES['$_FILES']['type']; // 例如:'text/plain'
$new_filename = "$userid-".$file_type.date('d-m-y').".".$file_ext;
// → 生成类似 "123-text/plain09-02-22.txt" 的文件名该字符串含非法字符 /,操作系统无法将其识别为有效文件名,move_uploaded_file() 因此找不到目标路径而失败。
✅ 正确做法是仅提取 MIME 类型的主类型(如 text)或完全避免使用 type 字段(因其由客户端提供,不可信且格式不统一)。推荐方案如下:
$path = 'temp/';
if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) { // 注意:键名应为 'file',非 '$_FILES'
$file = $_FILES['file'];
$file_name = $file['name'];
$file_tmp = $file['tmp_name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
// ✅ 方案1:仅取 MIME 主类型(更语义化)
$file_type = explode('/', $file['type']);
$main_type = $file_type[0] ?? 'unknown';
$new_filename = "{$userid}-{$main_type}-".date('d-m-y').".{$file_ext}";
// ✅ 方案2(更推荐):彻底弃用 type,用扩展名+时间戳保证唯一性
// $new_filename = "{$userid}-".date('YmdHis')."-".uniqid().".{$file_ext}";
$upload_path = $path . $new_filename;
// ? 确保上传目录存在且可写
if (!is_dir($path)) {
mkdir($path, 0755, true);
}
if (move_uploaded_file($file_tmp, $upload_path)) {
echo "Upload success: {$new_filename}";
http_response_code(200);
} else {
error_log("Failed to move uploaded file to {$upload_path}");
echo "Upload failed";
http_response_code(400);
}
} else {
echo "No file uploaded or upload error occurred.";
http_response_code(400);
}通过以上修正,即可稳定实现带业务标识(如用户 ID)、时间戳和合法扩展名的文件重命名上传,兼顾功能性与安全性。