PHP相机拍照上传图片生成0字节损坏文件的解决方法
相机拍照上传后图片为0字节损坏问题修复
问题场景
开发支持调用移动设备相机拍摄照片、并将图片上传至服务器的应用,现有代码执行后,目标上传目录可生成对应文件名的图片文件,但文件损坏、大小为0MB,无法正常打开。
原有实现代码
前端表单代码
<form id="theform" action="upload.php" onsubmit="event.preventDefault(); return myFunction();" method="post" enctype="multipart/form-data"> <input id="file" name="uploadedFile" onchange="uptoserver();" style="display:none;"type="file" accept="image/*" capture="camera"> <div class="row justify-content-center"> <button type="submit" class="btn wbtn border rounded-pill" style="font-family:Hana; font-size:32px;"> <img src="style\image\camera.png" width="64" /> تصوير النمودج </button> </div> </form>
后端upload.php处理代码
<?php $target_path = "uploads/"; $target_path = $target_path . basename( $_FILES['uploadedFile']['name']); if(move_uploaded_file($_FILES['uploadedFile']['tmp_name'], $target_path)) { echo "جاري إضافة الملف ". basename( $_FILES['uploadedFile']['name']). " إلى جدول ملف إكسل"; echo "<script>document.write(readfile(\"".$target_path."\"));</script>"; $stringPath = $target_path; //PASSING NAME PARAM // how can i pass the Name to prepare.php printf($stringPath); } else{ echo "There was an error uploading the file, please try again!"; } ?>
问题根因
- 前端上传逻辑存在冲突且实现错误:现有代码同时绑定了文件选择框的
onchange上传事件、表单submit拦截事件,但未给出uptoserver()和myFunction()的具体实现,90%以上概率是上传时未正确构造FormData对象传输文件二进制内容。若使用jQuery/axios等工具发送ajax请求时未关闭默认的参数序列化、未让浏览器自动生成带boundary的multipart/form-data请求头,就会导致后端接收到的文件内容为空。 - 后端代码存在逻辑错误:代码中输出到前端的
<script>标签内直接写入了PHP的readfile()函数,该函数会在服务端直接读取目标图片的二进制内容输出到响应流,不仅完全无法实现前端读取文件的预期效果,还可能在文件刚完成移动时抢占文件句柄,导致文件写入不完整;同时代码未校验PHP内置的上传错误码,未处理目录权限、文件名特殊字符、文件大小超限等边界情况。 - 交互逻辑冗余:隐藏的文件选择框同时被onchange和submit事件触发,容易出现重复提交、文件未完全读取就发起上传的问题,部分移动端浏览器拍完照后会存在短暂的文件写入缓存期,立刻上传容易读到空文件。
修复方案
- 精简前端交互与上传逻辑,去掉重复的事件绑定,使用标准FormData构造上传请求,示例代码如下:
<form id="theform" method="post" enctype="multipart/form-data"> <input id="file" name="uploadedFile" style="display:none;" type="file" accept="image/*" capture="camera"> <div class="row justify-content-center"> <button type="button" id="uploadBtn" class="btn wbtn border rounded-pill" style="font-family:Hana; font-size:32px;"> <img src="style/image/camera.png" width="64" /> تصوير النمودج </button> </div> </form> <script> const uploadBtn = document.getElementById('uploadBtn'); const fileInput = document.getElementById('file'); // 点击按钮触发相机/文件选择 uploadBtn.addEventListener('click', () => { fileInput.click(); }); // 选完文件后自动上传 fileInput.addEventListener('change', () => { const file = fileInput.files[0]; if(!file) return; // 构造FormData const formData = new FormData(); formData.append('uploadedFile', file); // 发起上传请求 fetch('upload.php', { method: 'POST', body: formData // 不要手动设置Content-Type,让浏览器自动带multipart边界 }).then(res => res.text()).then(res => { console.log('上传结果', res); }).catch(err => { console.error('上传失败', err); }); }); </script>
如果使用jQuery发送ajax,必须添加如下配置,否则会序列化FormData导致文件丢失:
$.ajax({ url: 'upload.php', type: 'POST', data: formData, processData: false, // 禁止jQuery处理数据 contentType: false, // 禁止jQuery设置Content-Type success: function(res) { console.log(res); } });
- 加固后端处理逻辑,增加错误校验,移除无效代码,示例如下:
<?php // 先定义上传目录,提前判断目录是否存在、是否可写 $target_dir = "uploads/"; if (!is_dir($target_dir)) { mkdir($target_dir, 0755, true); } // 先校验上传错误码 if ($_FILES['uploadedFile']['error'] !== UPLOAD_ERR_OK) { exit("上传出错,错误码:" . $_FILES['uploadedFile']['error']); } // 校验文件类型,只允许图片 $allow_ext = ['jpg', 'jpeg', 'png', 'gif', 'webp']; $file_ext = strtolower(pathinfo($_FILES['uploadedFile']['name'], PATHINFO_EXTENSION)); if (!in_array($file_ext, $allow_ext)) { exit("仅允许上传图片格式文件"); } // 重命名文件,避免特殊字符、重名问题 $new_filename = uniqid() . '.' . $file_ext; $target_path = $target_dir . $new_filename; if(move_uploaded_file($_FILES['uploadedFile']['tmp_name'], $target_path)) { echo "جاري إضافة الملف ". $new_filename. " إلى جدول ملف إكسل"; // 移除原来错误的readfile script输出逻辑 // 如果需要传递路径给prepare.php,可以存到session、或者直接跳转带参数,不要直接输出二进制内容 $stringPath = $target_path; echo $stringPath; } else{ echo "文件移动失败,请检查uploads目录权限"; } ?>
- 额外检查php.ini配置,确认
upload_max_filesize、post_max_size、memory_limit参数值大于需要上传的最大图片大小,避免大小超限导致空文件。
内容的提问来源于stack exchange,提问作者MrObscure
相关产品推荐
相关产品推荐

