Georgemayer
Georgemayer

Reputation: 325

Decompressing PHP's gzcompress in Java

I'm trying to decompress a json object in Java that was initially compressed in PHP. Here's how it gets compressed into PHP:

function zip_json_encode(&$arr) {
  $uncompressed = json_encode($arr);
  return pack('L', strlen($uncompressed)).gzcompress($uncompressed);
}

and decoded (again in PHP):

function unzip_json_decode(&$data) {
  $uncompressed = @gzuncompress(substr($data,4));
  return json_decode($uncompressed, $array_instead_of_object);
}

That gets put into MySQL and now it must be pulled out of the db by Java. We pull it out from the ResultSet like this:

String field = rs.getString("field");

I then pass that string to a method to decompress it. This is where it falls apart.

private String decompressHistory(String historyString) throws SQLException {
    StringBuffer buffer = new StringBuffer();
    try {
        byte[] historyBytes = historyString.substring(4).getBytes();
        ByteArrayInputStream bin = new ByteArrayInputStream(historyBytes);
        InflaterInputStream in = new InflaterInputStream(bin, new Inflater(true));
        int len;
        byte[] buf = new byte[1024];
        while ((len = in.read(buf)) != -1) {
            // buf should be decoded, right?
        }

    } catch (IOException e) {
        e.getStackTrace();
    }
    return buffer.toString();

}

Not quite sure what's going wrong here, but any pointers would be appreciated!

Upvotes: 0

Views: 1453

Answers (3)

Georgemayer
Georgemayer

Reputation: 325

In the end, neither of the above solutions worked, but both have merits. When we pulled the data out of mysql and cast it to bytes we have a number of missing character bytes (67). This made it impossible to decompress on the java side. As for the answers above. Mark is correct that gzcompress() uses zlib and therefore you should use the Inflater() class in Java.

Joop is correct that the data conversion is faulty. Our table was too large to convert it to varbinary or blob. That may have solved the problem, but didn't work for us. We ended up having java make a request to our PHP app, then simply unpacked the compressed data on the PHP side. This worked well. Hopefully this is helpful to anyone else that stumbles across it.

Upvotes: 1

Joop Eggen
Joop Eggen

Reputation: 109547

Gzipped data is binary, byte[]. Using String, Unicode text, not only needs conversion, but is faulty.

For instance this involves a conversion:

byte[] historyBytes = historyString.substring(4).getBytes();
byte[] historyBytes = historyString.substring(4).getBytes("ISO-8859-1");

The first version uses the default platform encoding, making the application non-portable.

The first to-do is to use binary data in the database as VARBINARY or BLOB.

ImputStream field = rs.getBinaryStream("field");
try (InputStream in = new GZIPInputStream(field)) {
    ...
}

Or so. Mind the other answer.

Upvotes: 1

Mark Adler
Mark Adler

Reputation: 112349

You need to get rid of the true in Inflater(true). Use just Inflater(). The true makes it expect raw deflate data. Without the true, it is expecting zlib-wrapped deflate data. PHP's gzcompress() produces zlib-wrapped deflate data.

Upvotes: 1

Related Questions