Search code examples
phpcphp-extension

How to use the PHP gzinflate function in C (PHP Extension)


I'm not sure the best way to call the PHP function gzinflate in the C (PHP Extension). Currently, I'm using the zlib to implement a similar gzinflate function (I reused the code from the zlib PHP extension). However I got the "Fatal error: Allowed memory size of 134217728 bytes exhausted" issue. Here is my code:

H file:

#define PHP_ZLIB_ENCODING_RAW -0xf
#define PHP_ZLIB_ENCODING_GZIP 0x1f
#define PHP_ZLIB_ENCODING_DEFLATE 0x0f

#define PHP_ZLIB_ENCODING_ANY 0x2f

#define PHP_ZLIB_BUFFER_SIZE_GUESS(in_len) (((size_t) ((double) in_len * (double) 1.015)) + 10 + 8 + 4 + 1)

C File:

#include "zlib.h"
static voidpf php_zlib_alloc(voidpf opaque, uInt items, uInt size)
{
    return (voidpf)safe_emalloc(items, size, 0);
}

static void php_zlib_free(voidpf opaque, voidpf address)
{
    efree((void*)address);
}

static zend_string *php_zlib_encode(const char *in_buf, size_t in_len, int encoding, int level)
{
     int status;
     z_stream Z;
     zend_string *out;

     memset(&Z, 0, sizeof(z_stream));
     Z.zalloc = php_zlib_alloc;
     Z.zfree = php_zlib_free;

     if (Z_OK == (status = deflateInit2(&Z, level, Z_DEFLATED, encoding, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY))) {
          out = zend_string_alloc(PHP_ZLIB_BUFFER_SIZE_GUESS(in_len), 0);

          Z.next_in = (Bytef *) in_buf;
          Z.next_out = (Bytef *) ZSTR_VAL(out);
          Z.avail_in = in_len;
          Z.avail_out = ZSTR_LEN(out);

          status = deflate(&Z, Z_FINISH);
          deflateEnd(&Z);

          if (Z_STREAM_END == status) {
               /* size buffer down to actual length */
               out = zend_string_truncate(out, Z.total_out, 0);
               ZSTR_VAL(out)[ZSTR_LEN(out)] = '\0';
               return out;
          } else {
               zend_string_efree(out);
          }
     }

     php_error_docref(NULL, E_WARNING, "%s", zError(status));
     return NULL;
}

Use the function:

zval data;
char *v;

v = "{\"ok\":1}";

php_json_decode_ex(&data, v, sizeof(v) - 1, 1, 512);

ZSTR_VAL(php_zlib_encode(Z_STRVAL_P(&data), Z_STRLEN_P(&data), PHP_ZLIB_ENCODING_DEFLATE, -1))

Solution

  • Call directly the gzinflate function instead of implementing the zlib function

    zval function, output, args[1];
    
    ZVAL_STRING(&args[0], Z_STRVAL_P("/* The gz data */"));
    
    ZVAL_STRING(&function, "gzinflate");
    
    call_user_function(NULL, NULL, &function, &output, 1, args);
    

    You can use the same way for calling any existing PHP function in the C