如何通过AJAX请求使用PHP存储上传的图片
问题:使用FormData+AJAX上传图片到PHP后端,
move_uploaded_file无法存储文件 我正在结合FormData、JS和AJAX将文件发送到服务器,但在存储文件时遇到问题。move_uploaded_file()处理数组时直接失败,尝试使用文件名时无报错但仍无法成功存储文件。
AJAX请求代码
let fd = new FormData(); fd.append('id', id); fd.append('name', name); fd.append('caption', caption); if( upload.cachedFileArray[0] !== null || typeof upload.cachedFileArray !== "undefined"){ alert('defined...'); alert(upload.cachedFileArray[0]); fd.append('file', upload.cachedFileArray[0]); } else { alert(upload.cachedFileArray[0]); alert('U heeft nog geen afbeelding toegevoegd!'); } $.ajax({ url: '/SaveSlide', type: 'POST', processData: false, contentType: false, beforeSend: function (xhr) { const token = jQuery('meta[name="csrf_token"]').attr('content'); if (token) { return xhr.setRequestHeader('X-CSRF-TOKEN', token); } }, data: fd, success: function (data) { alert(data); } });
PHP代码(原始错误版本)
public function SaveSlide(){ if($_FILES['file']){ //echo json_encode($_POST['id'] . $_POST ['name'] .$_POST['caption'] . var_dump($_FILES ['file'])); if($_FILES['file']['type'] === "image/jpeg") { if (move_uploaded_file($_FILES['file'], asset('assets/img/'))) { echo json_encode('Uploaded!'); } else { echo json_encode('Not uploaded :(!'); } } //$html = $this->slideController->EditSlide($data); } }
AJAX请求确实已将数据发送到服务器,我可以回显$_FILES['file']数组并查看,其结构如下:
name: "example.jpg" lastmodified: 1620000000 lastmodifieddate: ... WebkitRelativePath: "" size: 123456 type: "image/jpeg" slice: function(){}
请问如何将上传的图片成功存储到服务器?
解决方案
你的PHP代码里有两个核心错误导致move_uploaded_file执行失败,下面逐一修正并说明:
1. 修正move_uploaded_file的第一个参数
move_uploaded_file要求第一个参数是服务器临时文件的路径,也就是$_FILES['file']['tmp_name'],而不是整个$_FILES['file']数组。PHP接收上传文件时,会先把文件存到服务器临时目录,你需要从这个临时路径将文件移动到目标目录。
2. 修正目标路径
asset('assets/img/')是Laravel生成前端访问URL的辅助函数,输出的是类似http://yourdomain.com/assets/img/的网络地址,但move_uploaded_file需要的是服务器本地的文件系统绝对路径(比如/var/www/html/public/assets/img/)。
在Laravel中,你可以用public_path()获取public目录的绝对路径,再拼接上目标文件名(建议生成唯一文件名避免覆盖已有文件)。
修正后的PHP代码
public function SaveSlide(){ // 先确认文件是否真的上传成功 if(isset($_FILES['file']) && is_uploaded_file($_FILES['file']['tmp_name'])){ $file = $_FILES['file']; // 放宽验证类型,同时后续可以补充更严谨的文件校验 if(in_array($file['type'], ["image/jpeg", "image/png", "image/gif"])) { // 定义目标目录的绝对路径 $targetDir = public_path('assets/img/'); // 确保目录存在,不存在则递归创建 if(!file_exists($targetDir)){ mkdir($targetDir, 0755, true); } // 生成唯一文件名,避免同名文件覆盖 $fileName = uniqid('slide_') . '_' . $file['name']; $targetPath = $targetDir . $fileName; // 执行文件移动操作 if (move_uploaded_file($file['tmp_name'], $targetPath)) { // 返回前端可访问的文件URL,方便后续使用 $fileUrl = asset('assets/img/' . $fileName); echo json_encode(['status' => 'success', 'message' => 'Uploaded!', 'file_url' => $fileUrl]); } else { echo json_encode(['status' => 'error', 'message' => 'Not uploaded :(!']); } } else { echo json_encode(['status' => 'error', 'message' => 'Only JPG/PNG/GIF files allowed!']); } } else { echo json_encode(['status' => 'error', 'message' => 'No file uploaded or upload failed!']); } }
额外注意事项
- 目录权限:确保
public/assets/img/目录有服务器写入权限(通常设置为0755),否则move_uploaded_file会因权限不足失败。 - 文件安全验证:仅靠
type字段验证不够安全,建议同时验证文件扩展名,并用finfo函数检查文件真实类型,防止恶意文件上传。 - 文件名处理:使用
uniqid()生成唯一前缀可以有效避免同名文件覆盖,也可以根据业务需求自定义命名规则。
内容的提问来源于stack exchange,提问作者Rick J
相关产品推荐
相关产品推荐

