PHP+AngularJS使用$_FILES与ZipArchive下载文件不完整问题求助
问题:AngularJS + PHP 处理JAR文件添加JSON后返回下载,文件损坏无内容
需求为获取JAR文件,在其META-INF文件夹中添加JSON文件后返回前端下载。当前实现返回的JAR文件不完整,可通过7Zip打开但无内容,不确定问题出在PHP还是AngularJS,求其他实现思路。
前端AngularJS控制器代码
//Upload the Two Files: exportFile = document.getElementById('jar-file-export'); exportFile.addEventListener('change',(event)=>{ //Get Jar File, and Save name for later use. let i = document.getElementById('jar-file-export'); let formData = new FormData(); formData.append('jar', i.files[0]); $scope.export.filename = i.files[0].name; //GET JSON File: let tFile = new Blob([JSON.stringify($scope.export.file)], {type: 'application/json'}); formData.append('descriptor',tFile); $http({ method:"POST", url:"assets/api/fileExport.php", data: formData, headers:{"Content-Type":undefined}, dataType: 'text', mimeType: 'text/plain; charset=x-user-defined', }).then(function success(response){ //saveAs = fileSaver.js console.log('File Export,Success',response.data); let data = response.data; //Code copied from StackOverFlow: let newContent = ""; for (var i = 0; i < data.length; i++) { newContent += String.fromCharCode(data.charCodeAt(i) & 0xFF); } var bytes = new Uint8Array(newContent.length); for (var i=0; i<newContent.length; i++) { bytes[i] = newContent.charCodeAt(i); } blob = new Blob([bytes], {type: "application/zip"}) saveAs(blob, $scope.export.filename); },function error(response){ console.log('File Export,error',response); }); })
后端PHP实现(尝试添加JSON版本)
<?php switch($_SERVER["REQUEST_METHOD"]) { case("POST"):{ $zip = new ZipArchive; if ($zip->open($_FILES['jar']['tmp_name']) === true){ $zip->open($_FILES['jar']['tmp_name']); $zip->addFile($_FILES['descriptor']['tmp_name'],file_get_contents($_FILES['descriptor']['tmp_name'])); $zip->close(); echo (file_get_contents($_FILES['jar']['tmp_name'])); } break; } ?>
后端PHP测试版本(直接返回原JAR)
<?php switch($_SERVER["REQUEST_METHOD"]) { case("POST"):{ $zip = new ZipArchive; $newZip = new ZipArchive; if ($zip->open($_FILES['jar']['tmp_name']) === true){ echo (file_get_contents($_FILES['jar']['tmp_name'])); } break; } ?>
问题分析与修复方案
1. PHP端核心问题
- 重复调用
$zip->open,重置了操作状态,导致修改丢失 addFile参数错误:第二个参数应为压缩包内的路径,而非文件内容- 未设置正确响应头,浏览器无法识别二进制文件,传输中易损坏
- 直接修改上传临时文件存在权限风险
修复后的PHP代码
<?php switch($_SERVER["REQUEST_METHOD"]) { case("POST"):{ // 校验文件上传状态 if (!isset($_FILES['jar']) || $_FILES['jar']['error'] !== UPLOAD_ERR_OK) { http_response_code(400); exit("Jar文件上传失败"); } if (!isset($_FILES['descriptor']) || $_FILES['descriptor']['error'] !== UPLOAD_ERR_OK) { http_response_code(400); exit("JSON描述文件上传失败"); } // 复制原JAR到临时文件,避免修改上传源文件 $tempJar = tempnam(sys_get_temp_dir(), "modified_jar_"); copy($_FILES['jar']['tmp_name'], $tempJar); $zip = new ZipArchive; if ($zip->open($tempJar, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) { // 将JSON文件添加到META-INF目录,自定义文件名 $zip->addFile($_FILES['descriptor']['tmp_name'], 'META-INF/descriptor.json'); $zip->close(); // 设置二进制文件响应头 header('Content-Type: application/java-archive'); header('Content-Disposition: attachment; filename="' . $_FILES['jar']['name'] . '"'); header('Content-Length: ' . filesize($tempJar)); readfile($tempJar); // 清理临时文件 unlink($tempJar); } else { http_response_code(500); exit("无法打开JAR文件"); } break; } ?>
2. AngularJS端优化
- 设置
responseType: 'arraybuffer'直接获取二进制数据,避免字符编码转换损坏文件 - 简化Blob创建逻辑:
exportFile = document.getElementById('jar-file-export'); exportFile.addEventListener('change',(event)=>{ let i = document.getElementById('jar-file-export'); let formData = new FormData(); formData.append('jar', i.files[0]); $scope.export.filename = i.files[0].name; let tFile = new Blob([JSON.stringify($scope.export.file)], {type: 'application/json'}); formData.append('descriptor',tFile); $http({ method:"POST", url:"assets/api/fileExport.php", data: formData, headers:{"Content-Type":undefined}, responseType: 'arraybuffer' // 关键:直接获取二进制流 }).then(function success(response){ console.log('File Export,Success'); const blob = new Blob([response.data], {type: "application/java-archive"}); saveAs(blob, $scope.export.filename); },function error(response){ console.log('File Export,error',response); }); })
其他实现思路
- 使用PHP的
Phar扩展处理JAR文件(JAR本质为ZIP格式,Phar操作更专业) - 前端使用JSZip库直接在浏览器端修改JAR文件,无需后端参与(适合小体积文件)
内容的提问来源于stack exchange,提问作者ALAVGUY
相关产品推荐
相关产品推荐

