使用Java进行压缩,使用PHP进行解压缩

10

我遇到了这样一种情况:一个servlet向PHP脚本提供压缩数据。我在Java端成功地进行了数据压缩,但是PHP似乎无法解压缩。

以下是相关的代码片段 Java端:

  OutputStream o=response.getOutputStream();

GZIPOutputStream gz=new GZIPOutputStream(o);
gz.write(GridCoder.encode(rs,id, perPage, page).getBytes());
gz.close();
o.close();

PHP侧:

$xml= gzuncompress($xml);

请问是否能指点我正确的方向。


你有错误吗?能把日志贴出来吗? - rogeriopvl
请确保您的Java代码设置了Content-Encoding: gzip HTTP头。 - Asaph
警告:gzuncompress():数据错误。我尝试仅回显数据而不尝试解压缩它,以确保我获取实际数据,并获得一个以:�������[开头的数据块。 Java端设置Content-Encoding为gZip。 - David Hamilton
4个回答

11

我刚看到你的问题,对此很感兴趣。所以我自己做了一个测试案例。我将所有与Servlet相关的内容从问题中剔除,并编写了以下类似代码:

import java.io.*;
import java.util.zip.GZIPOutputStream;

public class GZIPTestcase {

    public static void main(String[] args) throws Throwable {
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new FileOutputStream(new File("/Users/malax/foo2.gz")));
        PrintWriter pw = new PrintWriter(gzipOutputStream);

        pw.println("All your base are belong to us!");
        pw.flush();
        pw.close();
    }
}

GNU gunzip可以解压数据。然后我尝试使用PHP进行解压缩,但是出现了与您相同的错误。我进一步调查并找到了以下方法:
  • gzdecode()
  • gzinflate()
gzinflate也无法工作,gzdecode仅随PHP6一起提供,而我没有安装。也许你可以试试这个。(根据http://bugs.php.net/bug.php?id=22123,这将起作用)
我怀疑问题不在Java方面,因为GNU的gunzip可以解压缩数据,所以它必须是正确的。您可能需要进一步调查PHP方面的问题。
有一个与.NET和PHP相关的问题,原始发布者遇到了与您相同的问题:Can PHP decompress a file compressed with the .NET GZipStream class?。PHP似乎也无法解压缩来自.NET GZIPOutputStream等效物的数据。
很抱歉我没有“解决方案”,但我可能已经指出了您正确的方向。

编辑:我在PHP Bugtracker中找到了一篇文章,解释了这个问题:http://bugs.php.net/bug.php?id=22967。看起来gzuncompress无法解压由GZIPOutputStream生成的带有标头的GZIP数据。正如Bugtracker条目中所述,请尝试裁剪标题。


6

尝试使用DeflaterOutputStream替代GZIPOutputStream

PHP函数调用libzlib实现DEFLATE。而Gzip是完全不同的东西。

给PHP函数命名为gzXXX只会增加混淆。


3
我找到了一种解决方法,使用Devon_C_Miller和Malax的帖子作为指南。
Java代码:
   String body = "Lorem ipsum shizzle ma nizle";

   URL url = new URL("http://some.url/file.php?id=" + uid);
   URLConnection conn = url.openConnection();
   conn.setDoOutput(true);
   conn.setRequestProperty("Content-encoding", "deflate");
   conn.setRequestProperty("Content-type", "application/octet-stream");

   DeflaterOutputStream dos = new DeflaterOutputStream(conn.getOutputStream());

   dos.write(body.getBytes());
   dos.flush();
   dos.close();

PHP方面:

   $content = http_get_request_body();

   $uncontent = gzuncompress($content);

我尝试了许多解决方案,包括“剪切PHP无法识别的头文件”,但只有这个有效。谢谢。 - firebear
无法处理压缩后大小> 300b的字符串...不知道为什么,但在这些情况下,DeflaterOutputStream的行为类似于GZIPOutputStream(产生相同的结果,PHP无法解压缩)。 - Flash Thunder
@FlashThunder,我使用PHP 5.6.15和Java 8无法重现您的问题。我能够在PHP中使用gzuncompress()解压缩一个使用Java DeflaterOutputStream压缩的100万字符长的随机文本UTF-8字符串(使用类似于firebear答案的方法)。这是300KB压缩和1MB压缩 - 远远超过您的300b。以下是用于测试您的错误的代码:https://gist.github.com/cordje/48a957333cd045afa3792c82334d9b06 - Richard EB

2

我使用“Java Deflater + PHP gzuncompress”的组合方法,成功解决了问题。客户端:Android 4.1.1,服务器端:PHP 5.3。

对于那些需要在某些情况下仅压缩请求体的部分内容(例如像我一样,使用HTTP表单来提交一些参数和文件)的人,以下是我在Android端使用的代码片段:

    public static byte[] compressString(String data) throws IOException {
        byte[] compressed = null;
        byte[] byteData = data.getBytes();
        ByteArrayOutputStream bos = new ByteArrayOutputStream(byteData.length);
        Deflater compressor = new Deflater();
        compressor.setLevel(Deflater.BEST_COMPRESSION);
        compressor.setInput(byteData, 0, byteData.length);
        compressor.finish();

        // Compress the data
        final byte[] buf = new byte[1024];
        while (!compressor.finished()) {
            int count = compressor.deflate(buf);
            bos.write(buf, 0, count);
        }
        compressor.end();
        compressed = bos.toByteArray();
        bos.close();
        return compressed;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接