You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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" />&nbsp;تصوير النمودج&nbsp;
    </button>&nbsp;
  </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事件触发,容易出现重复提交、文件未完全读取就发起上传的问题,部分移动端浏览器拍完照后会存在短暂的文件写入缓存期,立刻上传容易读到空文件。

修复方案

  1. 精简前端交互与上传逻辑,去掉重复的事件绑定,使用标准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" />&nbsp;تصوير النمودج&nbsp;
    </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);
  }
});
  1. 加固后端处理逻辑,增加错误校验,移除无效代码,示例如下:
<?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目录权限";
}
?>
  1. 额外检查php.ini配置,确认upload_max_filesize、post_max_size、memory_limit参数值大于需要上传的最大图片大小,避免大小超限导致空文件。

内容的提问来源于stack exchange,提问作者MrObscure

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 11:27:18