JavaScript编码PDF Blob为Base64,PHP解码存入SQL时PDF空白问题排查
问题分析与解决方案
核心问题根源
你当前的实现通过FileReader将二进制文件(如PDF)转成字符串后传输,这个过程会破坏二进制数据的完整性:
- PDF是结构化二进制文档,任何字节丢失或编码错误都会导致文件损坏(表现为空白页);
readAsText报错是因为PDF包含非Latin1字符,btoa无法编码这类字符;- 手动base64编码+URL编解码的流程极易出现字节不一致,图片能正常显示是因为其对轻微字节损坏的容错性比PDF高。
正确实现方案:用FormData传输文件
FormData是浏览器专门为文件上传设计的接口,能完整保留二进制数据,无需手动编码解码。
前端代码修改
替换原FileReader代码,改用FormData:
const formData = new FormData(); formData.append('csrf', CSRF); // 循环添加所有选中的文件 for(const [key, file] of Object.entries($('input').prop('files'))){ formData.append('upload_files[]', file); } // 提交请求(如果API类支持传递ajax配置参数) API.post("file/upload/", formData, { contentType: false, processData: false, success:function(result,status,xhr){ console.log(result) } }); // 若API类不支持自定义配置,直接用原生$.ajax: // $.ajax({ // url: "file/upload/", // type: "POST", // data: formData, // data: formData, // contentType: false, // processData: false, // headers: {'X-CSRF-Token': CSRF}, // 或把CSRF放到URL里 // success: function(result) { // console.log(result); // } // });
PHP后端代码修改
直接通过$_FILES处理上传的文件,无需手动解析base64内容:
// 处理批量上传的文件 if(isset($_FILES['upload_files'])){ foreach($_FILES['upload_files']['tmp_name'] as $idx => $tmp_path){ // 检查上传是否成功 if($_FILES['upload_files']['error'][$idx] !== UPLOAD_ERR_OK){ continue; } $file_name = $_FILES['upload_files']['name'][$idx]; $file_size = $_FILES['upload_files']['size'][$idx]; $file_type = $_FILES['upload_files']['type'][$idx]; // 读取完整的二进制文件内容 $file_content = file_get_contents($tmp_path); // 示例:将文件信息存入数据库(务必用预处理语句防注入) // $stmt = $pdo->prepare("INSERT INTO files (name, size, type, content) VALUES (?, ?, ?, ?)"); // $stmt->execute([$file_name, $file_size, $file_type, $file_content]); } }
关键说明
contentType: false和processData: false是必须的,告诉jQuery不要自动处理FormData的编码和数据格式;- 用
$_FILES获取上传文件是PHP处理文件上传的标准方式,能确保二进制数据完整; - 存储二进制数据到数据库时,字段类型需设为
LONGBLOB(MySQL)或对应大二进制类型,避免数据截断。
内容的提问来源于stack exchange,提问作者Louis Ouellet
相关产品推荐
相关产品推荐

