Сжатие с помощью Java Decompressing с помощью PHP

У меня ситуация, когда сервлет предоставляет сжатые данные для PHP script. Я сжимаю данные на стороне 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);

Может кто-нибудь, пожалуйста, назовите меня в правильном направлении.

Ответ 1

Я только что увидел ваш вопрос и ему было любопытно. Поэтому я сделал свой собственный тестовый сценарий. Я оставил все связанные с 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, где исходный плакат имеет ту же проблему, что и у вас: Может ли PHP распаковать файл, сжатый классом .NET GZipStream?. PHP, похоже, не способен распаковывать данные из .NET-эквивалента GZIPOutputStream.

Извините, что у меня нет "решения", но я, возможно, указал вам в нужном направлении.

EDIT: я нашел запись в PHP Bugtracker, которая объясняет проблему: http://bugs.php.net/bug.php?id=22967 Кажется, что gzuncompress не может распаковать GZIP-данные с заголовками, которые будут созданы GZIPOutputStream. Как указано в записи Bugtracker, попробуйте обрезать заголовок.

Ответ 2

Попробуйте использовать 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);

Ответ 4

Сочетание "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;
    }