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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 01:01:20