【问题标题】:How to determine if a string was compressed?如何确定字符串是否被压缩?
【发布时间】:2012-06-11 07:08:34
【问题描述】:

如何确定字符串是否使用gzcompress 压缩(除了在调用gzuncompress 之前/之后比较字符串的大小,或者这是否是正确的做法)?

【问题讨论】:

    标签: php string compression


    【解决方案1】:

    PRE:
    我猜,如果您发送 请求,您可以立即查看 $http_response_header 以查看数组中的一项是否为Content-Encoding: gzip 的变体。但这是 LAME!
    有更好的方法。


    这是如何...

    检查它是否是 GZIP。像个BOSS!

    根据GZIP RFC

    gzip 内容的头部是这样的

    +---+---+---+---+---+---+---+---+---+---+
    |ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
    +---+---+---+---+---+---+---+---+---+---+
    

    ID1ID2 将内容标识为 GZIPCM 声明 ZLIB_ENCODING(压缩方法)是 ZLIB_ENCODING_DEFLATE - GZIP 通常将其用于所有 Web 服务器。

    哦!并且它们具有固定值:

    • ID1的值为"\x1f"
    • ID2的值为"\x8b"
    • CM 的值为 "\x08" (或只是 8...)

    差不多了:

    $is_gzip = 0 === mb_strpos($mystery_string , "\x1f" . "\x8b" . "\x08");

    工作示例

    <?php
    /** @link https://gist.github.com/eladkarako/d8f3addf4e3be92bae96#file-checking_gzip_like_a_boss-php */
    
    date_default_timezone_set("Asia/Jerusalem");
    
    while (ob_get_level() > 0) ob_end_flush();
    mb_language("uni");
    @mb_internal_encoding('UTF-8');
    setlocale(LC_ALL, 'en_US.UTF-8');
    
    header('Time-Zone: Asia/Jerusalem');
    header('Charset: UTF-8');
    header('Content-Encoding: UTF-8');
    header('Content-Type: text/plain; charset=UTF-8');
    header('Access-Control-Allow-Origin: *');
    
    function get($url, $cookie = '') {
      $html = @file_get_contents($url, false, stream_context_create([
        'http' => [
          'method' => "GET",
          'header' => implode("\r\n", [''
            , 'Pragma: no-cache'
            , 'Cache-Control: no-cache'
            , 'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2310.0 Safari/537.36'
            , 'DNT: 1'
            , 'Accept-Language: en-US,en;q=0.8'
            , 'Accept: text/plain'
            , 'X-Forwarded-For: ' . implode(', ', array_unique(array_filter(array_map(function ($item) { return filter_input(INPUT_SERVER, $item, FILTER_SANITIZE_SPECIAL_CHARS); }, ['HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR', 'HTTP_CLIENT_IP', 'SERVER_ADDR', 'REMOTE_ADDR']), function ($item) { return null !== $item; })))
            , 'Referer: http://eladkarako.com'
            , 'Connection: close'
            , 'Cookie: ' . $cookie
            , 'Accept-Encoding: gzip'
          ])
        ]]));
    
      $is_gzip = 0 === mb_strpos($html, "\x1f" . "\x8b" . "\x08", 0, "US-ASCII");
    
      return $is_gzip ? zlib_decode($html, ZLIB_ENCODING_DEFLATE) : $html;
    }
    
    $html = get('http://www.pogdesign.co.uk/cat/');
    
    echo $html;
    

    我们在这里看到什么值得一提的?

    • 首先初始化 PHP 引擎以使用 UTF-8(因为我们真的不知道网络服务器 是否会返回 GZIP 内容。
    • 提供标头Accept-Encoding: gzip,告诉网络服务器,它可能输出 GZIP 内容。
    • 发现 GZIP 内容(您应该使用带有 ASCII 编码的多字节函数。
    • 最后返回纯输出,使用ZLIB 方法很容易。

    【讨论】:

    • 适用于 gzencoded 字符串,但不适用于没有 gzip-header 的 gzcompressed 字符串,所以我这样做:function isGzipped($in) { if (mb_strpos($in , "\x1f" . "\x8b" . "\x08")===0) { return true; } else if (@gzuncompress($in)!==false) { return true; } else { return false; } }
    • @futtta - 不错的补充,顺便说一句。你仍然应该保留"US-ASCII"(在mb_strpos)..
    【解决方案2】:

    字符串和压缩字符串都是简单的字节序列。您无法真正区分一个字节序列和另一个字节序列。您应该知道从随附的元数据中字节块是否代表压缩格式。

    如果您真的需要以编程方式猜测,您可以尝试以下几件事:

    • 尝试解压字符串,看看解压操作是否成功。如果失败,则字节可能不代表压缩字符串。
    • 尝试检查明显的“奇怪”字节,例如0x20 之前的任何内容。这些字节通常不用于常规文本。但是,并不能真正保证它们出现在压缩字符串中。
    • 使用mb_check_encoding 来查看字符串在您怀疑它所在的编码中是否有效。如果不是,它可能已被压缩(或者您检查了错误的编码)。需要注意的是,几乎任何字节序列在几乎每个单字节编码中都是有效的,因此这仅适用于多字节编码。

    【讨论】:

    • 对不起,我这么无知,但我该如何执行第一个要点?当我在未压缩的字符串上调用 gzuncompress 时,它不会返回错误,只是返回相同的字符串。
    • 嗯,它为我返回false...var_dump(gzuncompress('foobar'));
    • 请注意,“\t”(制表符)、“\n”(换行符)和“\r”(回车符)都可能在任何字符串中,并且都低于 0x20。
    【解决方案3】:

    这对我来说很好:

    if (@gzuncompress($_xml)!==false) {
       // gzipped sring
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-08
      • 1970-01-01
      • 1970-01-01
      • 2015-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多