PageRenderTime 71ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/zlib/zlib.c

http://github.com/php/php-src
C | 1442 lines | 1078 code | 193 blank | 171 comment | 259 complexity | 9ebc4c3e64fe2cfb5d6e62ce792895b3 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
  14. | Stefan Röhrich <sr@linux.de> |
  15. | Zeev Suraski <zeev@php.net> |
  16. | Jade Nicoletti <nicoletti@nns.ch> |
  17. | Michael Wallner <mike@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include "php.h"
  24. #include "SAPI.h"
  25. #include "php_ini.h"
  26. #include "ext/standard/info.h"
  27. #include "ext/standard/php_string.h"
  28. #include "php_zlib.h"
  29. #include "zlib_arginfo.h"
  30. /*
  31. * zlib include files can define the following preprocessor defines which rename
  32. * the corresponding PHP functions to gzopen64, gzseek64 and gztell64 and thereby
  33. * breaking some software, most notably PEAR's Archive_Tar, which halts execution
  34. * without error message on gzip compressed archivesa.
  35. *
  36. * This only seems to happen on 32bit systems with large file support.
  37. */
  38. #undef gzopen
  39. #undef gzseek
  40. #undef gztell
  41. int le_deflate;
  42. #define le_deflate_name "zlib deflate"
  43. int le_inflate;
  44. #define le_inflate_name "zlib inflate"
  45. ZEND_DECLARE_MODULE_GLOBALS(zlib)
  46. /* {{{ Memory management wrappers */
  47. static voidpf php_zlib_alloc(voidpf opaque, uInt items, uInt size)
  48. {
  49. return (voidpf)safe_emalloc(items, size, 0);
  50. }
  51. static void php_zlib_free(voidpf opaque, voidpf address)
  52. {
  53. efree((void*)address);
  54. }
  55. /* }}} */
  56. /* {{{ Incremental deflate/inflate resource destructors */
  57. void deflate_rsrc_dtor(zend_resource *res)
  58. {
  59. z_stream *ctx = zend_fetch_resource(res, le_deflate_name, le_deflate);
  60. deflateEnd(ctx);
  61. efree(ctx);
  62. }
  63. void inflate_rsrc_dtor(zend_resource *res)
  64. {
  65. z_stream *ctx = zend_fetch_resource(res, le_inflate_name, le_inflate);
  66. if (((php_zlib_context *) ctx)->inflateDict) {
  67. efree(((php_zlib_context *) ctx)->inflateDict);
  68. }
  69. inflateEnd(ctx);
  70. efree(ctx);
  71. }
  72. /* }}} */
  73. /* {{{ php_zlib_output_conflict_check() */
  74. static int php_zlib_output_conflict_check(const char *handler_name, size_t handler_name_len)
  75. {
  76. if (php_output_get_level() > 0) {
  77. if (php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME))
  78. || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("ob_gzhandler"))
  79. || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("mb_output_handler"))
  80. || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("URL-Rewriter"))) {
  81. return FAILURE;
  82. }
  83. }
  84. return SUCCESS;
  85. }
  86. /* }}} */
  87. /* {{{ php_zlib_output_encoding() */
  88. static int php_zlib_output_encoding(void)
  89. {
  90. zval *enc;
  91. if (!ZLIBG(compression_coding)) {
  92. if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
  93. (enc = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING") - 1))) {
  94. convert_to_string(enc);
  95. if (strstr(Z_STRVAL_P(enc), "gzip")) {
  96. ZLIBG(compression_coding) = PHP_ZLIB_ENCODING_GZIP;
  97. } else if (strstr(Z_STRVAL_P(enc), "deflate")) {
  98. ZLIBG(compression_coding) = PHP_ZLIB_ENCODING_DEFLATE;
  99. }
  100. }
  101. }
  102. return ZLIBG(compression_coding);
  103. }
  104. /* }}} */
  105. /* {{{ php_zlib_output_handler_ex() */
  106. static int php_zlib_output_handler_ex(php_zlib_context *ctx, php_output_context *output_context)
  107. {
  108. int flags = Z_SYNC_FLUSH;
  109. if (output_context->op & PHP_OUTPUT_HANDLER_START) {
  110. /* start up */
  111. if (Z_OK != deflateInit2(&ctx->Z, ZLIBG(output_compression_level), Z_DEFLATED, ZLIBG(compression_coding), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) {
  112. return FAILURE;
  113. }
  114. }
  115. if (output_context->op & PHP_OUTPUT_HANDLER_CLEAN) {
  116. /* free buffers */
  117. deflateEnd(&ctx->Z);
  118. if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) {
  119. /* discard */
  120. return SUCCESS;
  121. } else {
  122. /* restart */
  123. if (Z_OK != deflateInit2(&ctx->Z, ZLIBG(output_compression_level), Z_DEFLATED, ZLIBG(compression_coding), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) {
  124. return FAILURE;
  125. }
  126. ctx->buffer.used = 0;
  127. }
  128. } else {
  129. if (output_context->in.used) {
  130. /* append input */
  131. if (ctx->buffer.free < output_context->in.used) {
  132. if (!(ctx->buffer.aptr = erealloc_recoverable(ctx->buffer.data, ctx->buffer.used + ctx->buffer.free + output_context->in.used))) {
  133. deflateEnd(&ctx->Z);
  134. return FAILURE;
  135. }
  136. ctx->buffer.data = ctx->buffer.aptr;
  137. ctx->buffer.free += output_context->in.used;
  138. }
  139. memcpy(ctx->buffer.data + ctx->buffer.used, output_context->in.data, output_context->in.used);
  140. ctx->buffer.free -= output_context->in.used;
  141. ctx->buffer.used += output_context->in.used;
  142. }
  143. output_context->out.size = PHP_ZLIB_BUFFER_SIZE_GUESS(output_context->in.used);
  144. output_context->out.data = emalloc(output_context->out.size);
  145. output_context->out.free = 1;
  146. output_context->out.used = 0;
  147. ctx->Z.avail_in = ctx->buffer.used;
  148. ctx->Z.next_in = (Bytef *) ctx->buffer.data;
  149. ctx->Z.avail_out = output_context->out.size;
  150. ctx->Z.next_out = (Bytef *) output_context->out.data;
  151. if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) {
  152. flags = Z_FINISH;
  153. } else if (output_context->op & PHP_OUTPUT_HANDLER_FLUSH) {
  154. flags = Z_FULL_FLUSH;
  155. }
  156. switch (deflate(&ctx->Z, flags)) {
  157. case Z_OK:
  158. if (flags == Z_FINISH) {
  159. deflateEnd(&ctx->Z);
  160. return FAILURE;
  161. }
  162. case Z_STREAM_END:
  163. if (ctx->Z.avail_in) {
  164. memmove(ctx->buffer.data, ctx->buffer.data + ctx->buffer.used - ctx->Z.avail_in, ctx->Z.avail_in);
  165. }
  166. ctx->buffer.free += ctx->buffer.used - ctx->Z.avail_in;
  167. ctx->buffer.used = ctx->Z.avail_in;
  168. output_context->out.used = output_context->out.size - ctx->Z.avail_out;
  169. break;
  170. default:
  171. deflateEnd(&ctx->Z);
  172. return FAILURE;
  173. }
  174. if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) {
  175. deflateEnd(&ctx->Z);
  176. }
  177. }
  178. return SUCCESS;
  179. }
  180. /* }}} */
  181. /* {{{ php_zlib_output_handler() */
  182. static int php_zlib_output_handler(void **handler_context, php_output_context *output_context)
  183. {
  184. php_zlib_context *ctx = *(php_zlib_context **) handler_context;
  185. if (!php_zlib_output_encoding()) {
  186. /* "Vary: Accept-Encoding" header sent along uncompressed content breaks caching in MSIE,
  187. so let's just send it with successfully compressed content or unless the complete
  188. buffer gets discarded, see http://bugs.php.net/40325;
  189. Test as follows:
  190. +Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";'
  191. +Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";'
  192. -Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();'
  193. -Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();'
  194. */
  195. if ((output_context->op & PHP_OUTPUT_HANDLER_START)
  196. && (output_context->op != (PHP_OUTPUT_HANDLER_START|PHP_OUTPUT_HANDLER_CLEAN|PHP_OUTPUT_HANDLER_FINAL))
  197. ) {
  198. sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 0);
  199. }
  200. return FAILURE;
  201. }
  202. if (SUCCESS != php_zlib_output_handler_ex(ctx, output_context)) {
  203. return FAILURE;
  204. }
  205. if (!(output_context->op & PHP_OUTPUT_HANDLER_CLEAN)) {
  206. int flags;
  207. if (SUCCESS == php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS, &flags)) {
  208. /* only run this once */
  209. if (!(flags & PHP_OUTPUT_HANDLER_STARTED)) {
  210. if (SG(headers_sent) || !ZLIBG(output_compression)) {
  211. deflateEnd(&ctx->Z);
  212. return FAILURE;
  213. }
  214. switch (ZLIBG(compression_coding)) {
  215. case PHP_ZLIB_ENCODING_GZIP:
  216. sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1);
  217. break;
  218. case PHP_ZLIB_ENCODING_DEFLATE:
  219. sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1);
  220. break;
  221. default:
  222. deflateEnd(&ctx->Z);
  223. return FAILURE;
  224. }
  225. sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 0);
  226. php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL);
  227. }
  228. }
  229. }
  230. return SUCCESS;
  231. }
  232. /* }}} */
  233. /* {{{ php_zlib_output_handler_context_init() */
  234. static php_zlib_context *php_zlib_output_handler_context_init(void)
  235. {
  236. php_zlib_context *ctx = (php_zlib_context *) ecalloc(1, sizeof(php_zlib_context));
  237. ctx->Z.zalloc = php_zlib_alloc;
  238. ctx->Z.zfree = php_zlib_free;
  239. return ctx;
  240. }
  241. /* }}} */
  242. /* {{{ php_zlib_output_handler_context_dtor() */
  243. static void php_zlib_output_handler_context_dtor(void *opaq)
  244. {
  245. php_zlib_context *ctx = (php_zlib_context *) opaq;
  246. if (ctx) {
  247. if (ctx->buffer.data) {
  248. efree(ctx->buffer.data);
  249. }
  250. efree(ctx);
  251. }
  252. }
  253. /* }}} */
  254. /* {{{ php_zlib_output_handler_init() */
  255. static php_output_handler *php_zlib_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags)
  256. {
  257. php_output_handler *h = NULL;
  258. if (!ZLIBG(output_compression)) {
  259. ZLIBG(output_compression) = chunk_size ? chunk_size : PHP_OUTPUT_HANDLER_DEFAULT_SIZE;
  260. }
  261. ZLIBG(handler_registered) = 1;
  262. if ((h = php_output_handler_create_internal(handler_name, handler_name_len, php_zlib_output_handler, chunk_size, flags))) {
  263. php_output_handler_set_context(h, php_zlib_output_handler_context_init(), php_zlib_output_handler_context_dtor);
  264. }
  265. return h;
  266. }
  267. /* }}} */
  268. /* {{{ php_zlib_output_compression_start() */
  269. static void php_zlib_output_compression_start(void)
  270. {
  271. zval zoh;
  272. php_output_handler *h;
  273. switch (ZLIBG(output_compression)) {
  274. case 0:
  275. break;
  276. case 1:
  277. ZLIBG(output_compression) = PHP_OUTPUT_HANDLER_DEFAULT_SIZE;
  278. /* break omitted intentionally */
  279. default:
  280. if ( php_zlib_output_encoding() &&
  281. (h = php_zlib_output_handler_init(ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME), ZLIBG(output_compression), PHP_OUTPUT_HANDLER_STDFLAGS)) &&
  282. (SUCCESS == php_output_handler_start(h))) {
  283. if (ZLIBG(output_handler) && *ZLIBG(output_handler)) {
  284. ZVAL_STRING(&zoh, ZLIBG(output_handler));
  285. php_output_start_user(&zoh, ZLIBG(output_compression), PHP_OUTPUT_HANDLER_STDFLAGS);
  286. zval_ptr_dtor(&zoh);
  287. }
  288. }
  289. break;
  290. }
  291. }
  292. /* }}} */
  293. /* {{{ php_zlib_encode() */
  294. static zend_string *php_zlib_encode(const char *in_buf, size_t in_len, int encoding, int level)
  295. {
  296. int status;
  297. z_stream Z;
  298. zend_string *out;
  299. memset(&Z, 0, sizeof(z_stream));
  300. Z.zalloc = php_zlib_alloc;
  301. Z.zfree = php_zlib_free;
  302. if (Z_OK == (status = deflateInit2(&Z, level, Z_DEFLATED, encoding, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY))) {
  303. out = zend_string_alloc(PHP_ZLIB_BUFFER_SIZE_GUESS(in_len), 0);
  304. Z.next_in = (Bytef *) in_buf;
  305. Z.next_out = (Bytef *) ZSTR_VAL(out);
  306. Z.avail_in = in_len;
  307. Z.avail_out = ZSTR_LEN(out);
  308. status = deflate(&Z, Z_FINISH);
  309. deflateEnd(&Z);
  310. if (Z_STREAM_END == status) {
  311. /* size buffer down to actual length */
  312. out = zend_string_truncate(out, Z.total_out, 0);
  313. ZSTR_VAL(out)[ZSTR_LEN(out)] = '\0';
  314. return out;
  315. } else {
  316. zend_string_efree(out);
  317. }
  318. }
  319. php_error_docref(NULL, E_WARNING, "%s", zError(status));
  320. return NULL;
  321. }
  322. /* }}} */
  323. /* {{{ php_zlib_inflate_rounds() */
  324. static inline int php_zlib_inflate_rounds(z_stream *Z, size_t max, char **buf, size_t *len)
  325. {
  326. int status, round = 0;
  327. php_zlib_buffer buffer = {NULL, NULL, 0, 0, 0};
  328. *buf = NULL;
  329. *len = 0;
  330. buffer.size = (max && (max < Z->avail_in)) ? max : Z->avail_in;
  331. do {
  332. if ((max && (max <= buffer.used)) || !(buffer.aptr = erealloc_recoverable(buffer.data, buffer.size))) {
  333. status = Z_MEM_ERROR;
  334. } else {
  335. buffer.data = buffer.aptr;
  336. Z->avail_out = buffer.free = buffer.size - buffer.used;
  337. Z->next_out = (Bytef *) buffer.data + buffer.used;
  338. #if 0
  339. fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
  340. #endif
  341. status = inflate(Z, Z_NO_FLUSH);
  342. buffer.used += buffer.free - Z->avail_out;
  343. buffer.free = Z->avail_out;
  344. #if 0
  345. fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
  346. #endif
  347. buffer.size += (buffer.size >> 3) + 1;
  348. }
  349. } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < 100);
  350. if (status == Z_STREAM_END) {
  351. buffer.data = erealloc(buffer.data, buffer.used + 1);
  352. buffer.data[buffer.used] = '\0';
  353. *buf = buffer.data;
  354. *len = buffer.used;
  355. } else {
  356. if (buffer.data) {
  357. efree(buffer.data);
  358. }
  359. /* HACK: See zlib/examples/zpipe.c inf() function for explanation. */
  360. /* This works as long as this function is not used for streaming. Required to catch very short invalid data. */
  361. status = (status == Z_OK) ? Z_DATA_ERROR : status;
  362. }
  363. return status;
  364. }
  365. /* }}} */
  366. /* {{{ php_zlib_decode() */
  367. static int php_zlib_decode(const char *in_buf, size_t in_len, char **out_buf, size_t *out_len, int encoding, size_t max_len)
  368. {
  369. int status = Z_DATA_ERROR;
  370. z_stream Z;
  371. memset(&Z, 0, sizeof(z_stream));
  372. Z.zalloc = php_zlib_alloc;
  373. Z.zfree = php_zlib_free;
  374. if (in_len) {
  375. retry_raw_inflate:
  376. status = inflateInit2(&Z, encoding);
  377. if (Z_OK == status) {
  378. Z.next_in = (Bytef *) in_buf;
  379. Z.avail_in = in_len + 1; /* NOTE: data must be zero terminated */
  380. switch (status = php_zlib_inflate_rounds(&Z, max_len, out_buf, out_len)) {
  381. case Z_STREAM_END:
  382. inflateEnd(&Z);
  383. return SUCCESS;
  384. case Z_DATA_ERROR:
  385. /* raw deflated data? */
  386. if (PHP_ZLIB_ENCODING_ANY == encoding) {
  387. inflateEnd(&Z);
  388. encoding = PHP_ZLIB_ENCODING_RAW;
  389. goto retry_raw_inflate;
  390. }
  391. }
  392. inflateEnd(&Z);
  393. }
  394. }
  395. *out_buf = NULL;
  396. *out_len = 0;
  397. php_error_docref(NULL, E_WARNING, "%s", zError(status));
  398. return FAILURE;
  399. }
  400. /* }}} */
  401. /* {{{ php_zlib_cleanup_ob_gzhandler_mess() */
  402. static void php_zlib_cleanup_ob_gzhandler_mess(void)
  403. {
  404. if (ZLIBG(ob_gzhandler)) {
  405. deflateEnd(&(ZLIBG(ob_gzhandler)->Z));
  406. php_zlib_output_handler_context_dtor(ZLIBG(ob_gzhandler));
  407. ZLIBG(ob_gzhandler) = NULL;
  408. }
  409. }
  410. /* }}} */
  411. /* {{{ proto string ob_gzhandler(string data, int flags)
  412. Legacy hack */
  413. PHP_FUNCTION(ob_gzhandler)
  414. {
  415. char *in_str;
  416. size_t in_len;
  417. zend_long flags = 0;
  418. php_output_context ctx = {0};
  419. int encoding, rv;
  420. /*
  421. * NOTE that the real ob_gzhandler is an alias to "zlib output compression".
  422. * This is a really bad hack, because
  423. * - we have to initialize a php_zlib_context on demand
  424. * - we have to clean it up in RSHUTDOWN
  425. * - OG(running) is not set or set to any other output handler
  426. * - we have to mess around with php_output_context */
  427. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &in_str, &in_len, &flags)) {
  428. RETURN_THROWS();
  429. }
  430. if (!(encoding = php_zlib_output_encoding())) {
  431. RETURN_FALSE;
  432. }
  433. if (flags & PHP_OUTPUT_HANDLER_START) {
  434. switch (encoding) {
  435. case PHP_ZLIB_ENCODING_GZIP:
  436. sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1);
  437. break;
  438. case PHP_ZLIB_ENCODING_DEFLATE:
  439. sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1);
  440. break;
  441. }
  442. sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 0);
  443. }
  444. if (!ZLIBG(ob_gzhandler)) {
  445. ZLIBG(ob_gzhandler) = php_zlib_output_handler_context_init();
  446. }
  447. ctx.op = flags;
  448. ctx.in.data = in_str;
  449. ctx.in.used = in_len;
  450. rv = php_zlib_output_handler_ex(ZLIBG(ob_gzhandler), &ctx);
  451. if (SUCCESS != rv) {
  452. if (ctx.out.data && ctx.out.free) {
  453. efree(ctx.out.data);
  454. }
  455. php_zlib_cleanup_ob_gzhandler_mess();
  456. RETURN_FALSE;
  457. }
  458. if (ctx.out.data) {
  459. RETVAL_STRINGL(ctx.out.data, ctx.out.used);
  460. if (ctx.out.free) {
  461. efree(ctx.out.data);
  462. }
  463. } else {
  464. RETVAL_EMPTY_STRING();
  465. }
  466. }
  467. /* }}} */
  468. /* {{{ proto string zlib_get_coding_type(void)
  469. Returns the coding type used for output compression */
  470. PHP_FUNCTION(zlib_get_coding_type)
  471. {
  472. if (zend_parse_parameters_none() == FAILURE) {
  473. RETURN_THROWS();
  474. }
  475. switch (ZLIBG(compression_coding)) {
  476. case PHP_ZLIB_ENCODING_GZIP:
  477. RETURN_STRINGL("gzip", sizeof("gzip") - 1);
  478. case PHP_ZLIB_ENCODING_DEFLATE:
  479. RETURN_STRINGL("deflate", sizeof("deflate") - 1);
  480. default:
  481. RETURN_FALSE;
  482. }
  483. }
  484. /* }}} */
  485. /* {{{ proto array gzfile(string filename [, int use_include_path])
  486. Read and uncompress entire .gz-file into an array */
  487. PHP_FUNCTION(gzfile)
  488. {
  489. char *filename;
  490. size_t filename_len;
  491. int flags = REPORT_ERRORS;
  492. char buf[8192] = {0};
  493. register int i = 0;
  494. zend_long use_include_path = 0;
  495. php_stream *stream;
  496. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &filename, &filename_len, &use_include_path)) {
  497. RETURN_THROWS();
  498. }
  499. if (use_include_path) {
  500. flags |= USE_PATH;
  501. }
  502. /* using a stream here is a bit more efficient (resource wise) than php_gzopen_wrapper */
  503. stream = php_stream_gzopen(NULL, filename, "rb", flags, NULL, NULL STREAMS_CC);
  504. if (!stream) {
  505. /* Error reporting is already done by stream code */
  506. RETURN_FALSE;
  507. }
  508. /* Initialize return array */
  509. array_init(return_value);
  510. /* Now loop through the file and do the magic quotes thing if needed */
  511. memset(buf, 0, sizeof(buf));
  512. while (php_stream_gets(stream, buf, sizeof(buf) - 1) != NULL) {
  513. add_index_string(return_value, i++, buf);
  514. }
  515. php_stream_close(stream);
  516. }
  517. /* }}} */
  518. /* {{{ proto resource gzopen(string filename, string mode [, int use_include_path])
  519. Open a .gz-file and return a .gz-file pointer */
  520. PHP_FUNCTION(gzopen)
  521. {
  522. char *filename;
  523. char *mode;
  524. size_t filename_len, mode_len;
  525. int flags = REPORT_ERRORS;
  526. php_stream *stream;
  527. zend_long use_include_path = 0;
  528. if (zend_parse_parameters(ZEND_NUM_ARGS(), "ps|l", &filename, &filename_len, &mode, &mode_len, &use_include_path) == FAILURE) {
  529. RETURN_THROWS();
  530. }
  531. if (use_include_path) {
  532. flags |= USE_PATH;
  533. }
  534. stream = php_stream_gzopen(NULL, filename, mode, flags, NULL, NULL STREAMS_CC);
  535. if (!stream) {
  536. RETURN_FALSE;
  537. }
  538. php_stream_to_zval(stream, return_value);
  539. }
  540. /* }}} */
  541. /* {{{ proto int readgzfile(string filename [, int use_include_path])
  542. Output a .gz-file */
  543. PHP_FUNCTION(readgzfile)
  544. {
  545. char *filename;
  546. size_t filename_len;
  547. int flags = REPORT_ERRORS;
  548. php_stream *stream;
  549. size_t size;
  550. zend_long use_include_path = 0;
  551. if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &filename, &filename_len, &use_include_path) == FAILURE) {
  552. RETURN_THROWS();
  553. }
  554. if (use_include_path) {
  555. flags |= USE_PATH;
  556. }
  557. stream = php_stream_gzopen(NULL, filename, "rb", flags, NULL, NULL STREAMS_CC);
  558. if (!stream) {
  559. RETURN_FALSE;
  560. }
  561. size = php_stream_passthru(stream);
  562. php_stream_close(stream);
  563. RETURN_LONG(size);
  564. }
  565. /* }}} */
  566. #define PHP_ZLIB_ENCODE_FUNC(name, default_encoding) \
  567. PHP_FUNCTION(name) \
  568. { \
  569. zend_string *in, *out; \
  570. zend_long level = -1; \
  571. zend_long encoding = default_encoding; \
  572. if (default_encoding) { \
  573. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S|ll", &in, &level, &encoding)) { \
  574. RETURN_THROWS(); \
  575. } \
  576. } else { \
  577. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l", &in, &encoding, &level)) { \
  578. RETURN_THROWS(); \
  579. } \
  580. } \
  581. if (level < -1 || level > 9) { \
  582. zend_value_error("Compression level (" ZEND_LONG_FMT ") must be within -1..9", level); \
  583. RETURN_THROWS(); \
  584. } \
  585. switch (encoding) { \
  586. case PHP_ZLIB_ENCODING_RAW: \
  587. case PHP_ZLIB_ENCODING_GZIP: \
  588. case PHP_ZLIB_ENCODING_DEFLATE: \
  589. break; \
  590. default: \
  591. zend_value_error("Encoding mode must be either ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE"); \
  592. RETURN_THROWS(); \
  593. } \
  594. if ((out = php_zlib_encode(ZSTR_VAL(in), ZSTR_LEN(in), encoding, level)) == NULL) { \
  595. RETURN_FALSE; \
  596. } \
  597. RETURN_STR(out); \
  598. }
  599. #define PHP_ZLIB_DECODE_FUNC(name, encoding) \
  600. PHP_FUNCTION(name) \
  601. { \
  602. char *in_buf, *out_buf; \
  603. size_t in_len; \
  604. size_t out_len; \
  605. zend_long max_len = 0; \
  606. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &in_buf, &in_len, &max_len)) { \
  607. RETURN_THROWS(); \
  608. } \
  609. if (max_len < 0) { \
  610. zend_value_error("Length (" ZEND_LONG_FMT ") must be greater or equal zero", max_len); \
  611. RETURN_THROWS(); \
  612. } \
  613. if (SUCCESS != php_zlib_decode(in_buf, in_len, &out_buf, &out_len, encoding, max_len)) { \
  614. RETURN_FALSE; \
  615. } \
  616. RETVAL_STRINGL(out_buf, out_len); \
  617. efree(out_buf); \
  618. }
  619. /* {{{ proto binary zlib_encode(binary data, int encoding[, int level = -1])
  620. Compress data with the specified encoding */
  621. PHP_ZLIB_ENCODE_FUNC(zlib_encode, 0);
  622. /* }}} */
  623. /* {{{ proto binary zlib_decode(binary data[, int max_decoded_len])
  624. Uncompress any raw/gzip/zlib encoded data */
  625. PHP_ZLIB_DECODE_FUNC(zlib_decode, PHP_ZLIB_ENCODING_ANY);
  626. /* }}} */
  627. /* NOTE: The naming of these userland functions was quite unlucky */
  628. /* {{{ proto binary gzdeflate(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_RAW])
  629. Encode data with the raw deflate encoding */
  630. PHP_ZLIB_ENCODE_FUNC(gzdeflate, PHP_ZLIB_ENCODING_RAW);
  631. /* }}} */
  632. /* {{{ proto binary gzencode(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_GZIP])
  633. Encode data with the gzip encoding */
  634. PHP_ZLIB_ENCODE_FUNC(gzencode, PHP_ZLIB_ENCODING_GZIP);
  635. /* }}} */
  636. /* {{{ proto binary gzcompress(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_DEFLATE])
  637. Encode data with the zlib encoding */
  638. PHP_ZLIB_ENCODE_FUNC(gzcompress, PHP_ZLIB_ENCODING_DEFLATE);
  639. /* }}} */
  640. /* {{{ proto binary gzinflate(binary data[, int max_decoded_len])
  641. Decode raw deflate encoded data */
  642. PHP_ZLIB_DECODE_FUNC(gzinflate, PHP_ZLIB_ENCODING_RAW);
  643. /* }}} */
  644. /* {{{ proto binary gzdecode(binary data[, int max_decoded_len])
  645. Decode gzip encoded data */
  646. PHP_ZLIB_DECODE_FUNC(gzdecode, PHP_ZLIB_ENCODING_GZIP);
  647. /* }}} */
  648. /* {{{ proto binary gzuncompress(binary data[, int max_decoded_len])
  649. Decode zlib encoded data */
  650. PHP_ZLIB_DECODE_FUNC(gzuncompress, PHP_ZLIB_ENCODING_DEFLATE);
  651. /* }}} */
  652. static zend_bool zlib_create_dictionary_string(HashTable *options, char **dict, size_t *dictlen) {
  653. zval *option_buffer;
  654. if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("dictionary"))) != NULL) {
  655. ZVAL_DEREF(option_buffer);
  656. switch (Z_TYPE_P(option_buffer)) {
  657. case IS_STRING: {
  658. zend_string *str = Z_STR_P(option_buffer);
  659. *dict = emalloc(ZSTR_LEN(str));
  660. memcpy(*dict, ZSTR_VAL(str), ZSTR_LEN(str));
  661. *dictlen = ZSTR_LEN(str);
  662. } break;
  663. case IS_ARRAY: {
  664. HashTable *dictionary = Z_ARR_P(option_buffer);
  665. if (zend_hash_num_elements(dictionary) > 0) {
  666. char *dictptr;
  667. zval *cur;
  668. zend_string **strings = emalloc(sizeof(zend_string *) * zend_hash_num_elements(dictionary));
  669. zend_string **end, **ptr = strings - 1;
  670. ZEND_HASH_FOREACH_VAL(dictionary, cur) {
  671. size_t i;
  672. *++ptr = zval_get_string(cur);
  673. if (!*ptr || ZSTR_LEN(*ptr) == 0 || EG(exception)) {
  674. if (*ptr) {
  675. efree(*ptr);
  676. }
  677. while (--ptr >= strings) {
  678. efree(ptr);
  679. }
  680. efree(strings);
  681. if (!EG(exception)) {
  682. zend_value_error("Dictionary entries must be non-empty strings");
  683. }
  684. return 0;
  685. }
  686. for (i = 0; i < ZSTR_LEN(*ptr); i++) {
  687. if (ZSTR_VAL(*ptr)[i] == 0) {
  688. do {
  689. efree(ptr);
  690. } while (--ptr >= strings);
  691. efree(strings);
  692. zend_value_error("Dictionary entries must not contain a NULL-byte");
  693. return 0;
  694. }
  695. }
  696. *dictlen += ZSTR_LEN(*ptr) + 1;
  697. } ZEND_HASH_FOREACH_END();
  698. dictptr = *dict = emalloc(*dictlen);
  699. ptr = strings;
  700. end = strings + zend_hash_num_elements(dictionary);
  701. do {
  702. memcpy(dictptr, ZSTR_VAL(*ptr), ZSTR_LEN(*ptr));
  703. dictptr += ZSTR_LEN(*ptr);
  704. *dictptr++ = 0;
  705. zend_string_release_ex(*ptr, 0);
  706. } while (++ptr != end);
  707. efree(strings);
  708. }
  709. } break;
  710. default:
  711. zend_argument_type_error(2, "must be of type zero-terminated string or array, %s given", zend_get_type_by_const(Z_TYPE_P(option_buffer)));
  712. return 0;
  713. }
  714. }
  715. return 1;
  716. }
  717. /* {{{ proto resource inflate_init(int encoding)
  718. Initialize an incremental inflate context with the specified encoding */
  719. PHP_FUNCTION(inflate_init)
  720. {
  721. z_stream *ctx;
  722. zend_long encoding, window = 15;
  723. char *dict = NULL;
  724. size_t dictlen = 0;
  725. HashTable *options = NULL;
  726. zval *option_buffer;
  727. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) {
  728. RETURN_THROWS();
  729. }
  730. if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("window"))) != NULL) {
  731. window = zval_get_long(option_buffer);
  732. }
  733. if (window < 8 || window > 15) {
  734. zend_value_error("zlib window size (logarithm) (" ZEND_LONG_FMT ") must be within 8..15", window);
  735. RETURN_THROWS();
  736. }
  737. if (!zlib_create_dictionary_string(options, &dict, &dictlen)) {
  738. RETURN_FALSE;
  739. }
  740. switch (encoding) {
  741. case PHP_ZLIB_ENCODING_RAW:
  742. case PHP_ZLIB_ENCODING_GZIP:
  743. case PHP_ZLIB_ENCODING_DEFLATE:
  744. break;
  745. default:
  746. zend_value_error("Encoding mode must be ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE");
  747. RETURN_THROWS();
  748. }
  749. ctx = ecalloc(1, sizeof(php_zlib_context));
  750. ctx->zalloc = php_zlib_alloc;
  751. ctx->zfree = php_zlib_free;
  752. ((php_zlib_context *) ctx)->inflateDict = dict;
  753. ((php_zlib_context *) ctx)->inflateDictlen = dictlen;
  754. ((php_zlib_context *) ctx)->status = Z_OK;
  755. if (encoding < 0) {
  756. encoding += 15 - window;
  757. } else {
  758. encoding -= 15 - window;
  759. }
  760. if (Z_OK == inflateInit2(ctx, encoding)) {
  761. if (encoding == PHP_ZLIB_ENCODING_RAW && dictlen > 0) {
  762. php_zlib_context *php_ctx = (php_zlib_context *) ctx;
  763. switch (inflateSetDictionary(ctx, (Bytef *) php_ctx->inflateDict, php_ctx->inflateDictlen)) {
  764. case Z_OK:
  765. efree(php_ctx->inflateDict);
  766. php_ctx->inflateDict = NULL;
  767. break;
  768. case Z_DATA_ERROR:
  769. php_error_docref(NULL, E_WARNING, "Dictionary does not match expected dictionary (incorrect adler32 hash)");
  770. efree(php_ctx->inflateDict);
  771. php_ctx->inflateDict = NULL;
  772. EMPTY_SWITCH_DEFAULT_CASE()
  773. }
  774. }
  775. RETURN_RES(zend_register_resource(ctx, le_inflate));
  776. } else {
  777. efree(ctx);
  778. php_error_docref(NULL, E_WARNING, "Failed allocating zlib.inflate context");
  779. RETURN_FALSE;
  780. }
  781. }
  782. /* }}} */
  783. /* {{{ proto string inflate_add(resource context, string encoded_data[, int flush_mode = ZLIB_SYNC_FLUSH])
  784. Incrementally inflate encoded data in the specified context */
  785. PHP_FUNCTION(inflate_add)
  786. {
  787. zend_string *out;
  788. char *in_buf;
  789. size_t in_len, buffer_used = 0, CHUNK_SIZE = 8192;
  790. zval *res;
  791. z_stream *ctx;
  792. zend_long flush_type = Z_SYNC_FLUSH;
  793. int status;
  794. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &res, &in_buf, &in_len, &flush_type)) {
  795. RETURN_THROWS();
  796. }
  797. if ((ctx = zend_fetch_resource(Z_RES_P(res), le_inflate_name, le_inflate)) == NULL) {
  798. RETURN_THROWS();
  799. }
  800. switch (flush_type) {
  801. case Z_NO_FLUSH:
  802. case Z_PARTIAL_FLUSH:
  803. case Z_SYNC_FLUSH:
  804. case Z_FULL_FLUSH:
  805. case Z_BLOCK:
  806. case Z_FINISH:
  807. break;
  808. default:
  809. zend_value_error(
  810. "Flush mode must be ZLIB_NO_FLUSH, ZLIB_PARTIAL_FLUSH, ZLIB_SYNC_FLUSH, ZLIB_FULL_FLUSH, ZLIB_BLOCK or ZLIB_FINISH");
  811. RETURN_THROWS();
  812. }
  813. /* Lazy-resetting the zlib stream so ctx->total_in remains available until the next inflate_add() call. */
  814. if (((php_zlib_context *) ctx)->status == Z_STREAM_END)
  815. {
  816. ((php_zlib_context *) ctx)->status = Z_OK;
  817. inflateReset(ctx);
  818. }
  819. if (in_len <= 0 && flush_type != Z_FINISH) {
  820. RETURN_EMPTY_STRING();
  821. }
  822. out = zend_string_alloc((in_len > CHUNK_SIZE) ? in_len : CHUNK_SIZE, 0);
  823. ctx->next_in = (Bytef *) in_buf;
  824. ctx->next_out = (Bytef *) ZSTR_VAL(out);
  825. ctx->avail_in = in_len;
  826. ctx->avail_out = ZSTR_LEN(out);
  827. do {
  828. status = inflate(ctx, flush_type);
  829. buffer_used = ZSTR_LEN(out) - ctx->avail_out;
  830. ((php_zlib_context *) ctx)->status = status; /* Save status for exposing to userspace */
  831. switch (status) {
  832. case Z_OK:
  833. if (ctx->avail_out == 0) {
  834. /* more output buffer space needed; realloc and try again */
  835. out = zend_string_realloc(out, ZSTR_LEN(out) + CHUNK_SIZE, 0);
  836. ctx->avail_out = CHUNK_SIZE;
  837. ctx->next_out = (Bytef *) ZSTR_VAL(out) + buffer_used;
  838. break;
  839. } else {
  840. goto complete;
  841. }
  842. case Z_STREAM_END:
  843. goto complete;
  844. case Z_BUF_ERROR:
  845. if (flush_type == Z_FINISH && ctx->avail_out == 0) {
  846. /* more output buffer space needed; realloc and try again */
  847. out = zend_string_realloc(out, ZSTR_LEN(out) + CHUNK_SIZE, 0);
  848. ctx->avail_out = CHUNK_SIZE;
  849. ctx->next_out = (Bytef *) ZSTR_VAL(out) + buffer_used;
  850. break;
  851. } else {
  852. /* No more input data; we're finished */
  853. goto complete;
  854. }
  855. case Z_NEED_DICT:
  856. if (((php_zlib_context *) ctx)->inflateDict) {
  857. php_zlib_context *php_ctx = (php_zlib_context *) ctx;
  858. switch (inflateSetDictionary(ctx, (Bytef *) php_ctx->inflateDict, php_ctx->inflateDictlen)) {
  859. case Z_OK:
  860. efree(php_ctx->inflateDict);
  861. php_ctx->inflateDict = NULL;
  862. break;
  863. case Z_DATA_ERROR:
  864. php_error_docref(NULL, E_WARNING, "Dictionary does not match expected dictionary (incorrect adler32 hash)");
  865. efree(php_ctx->inflateDict);
  866. zend_string_release_ex(out, 0);
  867. php_ctx->inflateDict = NULL;
  868. RETURN_FALSE;
  869. EMPTY_SWITCH_DEFAULT_CASE()
  870. }
  871. break;
  872. } else {
  873. php_error_docref(NULL, E_WARNING, "Inflating this data requires a preset dictionary, please specify it in the options array of inflate_init()");
  874. RETURN_FALSE;
  875. }
  876. default:
  877. zend_string_release_ex(out, 0);
  878. php_error_docref(NULL, E_WARNING, "%s", zError(status));
  879. RETURN_FALSE;
  880. }
  881. } while (1);
  882. complete: {
  883. out = zend_string_realloc(out, buffer_used, 0);
  884. ZSTR_VAL(out)[buffer_used] = 0;
  885. RETURN_STR(out);
  886. }
  887. }
  888. /* }}} */
  889. /* {{{ proto bool inflate_get_status(resource context)
  890. Get decompression status, usually returns either ZLIB_OK or ZLIB_STREAM_END. */
  891. PHP_FUNCTION(inflate_get_status)
  892. {
  893. zval *res;
  894. z_stream *ctx;
  895. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "r", &res))
  896. {
  897. RETURN_THROWS();
  898. }
  899. if ((ctx = zend_fetch_resource(Z_RES_P(res), le_inflate_name, le_inflate)) == NULL) {
  900. RETURN_THROWS();
  901. }
  902. RETURN_LONG(((php_zlib_context *) ctx)->status);
  903. }
  904. /* }}} */
  905. /* {{{ proto bool inflate_get_read_len(resource context)
  906. Get number of bytes read so far. */
  907. PHP_FUNCTION(inflate_get_read_len)
  908. {
  909. zval *res;
  910. z_stream *ctx;
  911. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "r", &res))
  912. {
  913. RETURN_THROWS();
  914. }
  915. if ((ctx = zend_fetch_resource(Z_RES_P(res), le_inflate_name, le_inflate)) == NULL) {
  916. RETURN_THROWS();
  917. }
  918. RETURN_LONG(ctx->total_in);
  919. }
  920. /* }}} */
  921. /* {{{ proto resource deflate_init(int encoding[, array options])
  922. Initialize an incremental deflate context using the specified encoding */
  923. PHP_FUNCTION(deflate_init)
  924. {
  925. z_stream *ctx;
  926. zend_long encoding, level = -1, memory = 8, window = 15, strategy = Z_DEFAULT_STRATEGY;
  927. char *dict = NULL;
  928. size_t dictlen = 0;
  929. HashTable *options = NULL;
  930. zval *option_buffer;
  931. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) {
  932. RETURN_THROWS();
  933. }
  934. if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("level"))) != NULL) {
  935. level = zval_get_long(option_buffer);
  936. }
  937. if (level < -1 || level > 9) {
  938. zend_value_error("Compression level (" ZEND_LONG_FMT ") must be within -1..9", level);
  939. RETURN_THROWS();
  940. }
  941. if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("memory"))) != NULL) {
  942. memory = zval_get_long(option_buffer);
  943. }
  944. if (memory < 1 || memory > 9) {
  945. zend_value_error("Compression memory level (" ZEND_LONG_FMT ") must be within 1..9", memory);
  946. RETURN_THROWS();
  947. }
  948. if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("window"))) != NULL) {
  949. window = zval_get_long(option_buffer);
  950. }
  951. if (window < 8 || window > 15) {
  952. zend_value_error("zlib window size (logarithm) (" ZEND_LONG_FMT ") must be within 8..15", window);
  953. RETURN_THROWS();
  954. }
  955. if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("strategy"))) != NULL) {
  956. strategy = zval_get_long(option_buffer);
  957. }
  958. switch (strategy) {
  959. case Z_FILTERED:
  960. case Z_HUFFMAN_ONLY:
  961. case Z_RLE:
  962. case Z_FIXED:
  963. case Z_DEFAULT_STRATEGY:
  964. break;
  965. default:
  966. zend_value_error("Strategy must be one of ZLIB_FILTERED, ZLIB_HUFFMAN_ONLY, ZLIB_RLE, ZLIB_FIXED or ZLIB_DEFAULT_STRATEGY");
  967. RETURN_THROWS();
  968. }
  969. if (!zlib_create_dictionary_string(options, &dict, &dictlen)) {
  970. RETURN_FALSE;
  971. }
  972. switch (encoding) {
  973. case PHP_ZLIB_ENCODING_RAW:
  974. case PHP_ZLIB_ENCODING_GZIP:
  975. case PHP_ZLIB_ENCODING_DEFLATE:
  976. break;
  977. default:
  978. zend_value_error("Encoding mode must be ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE");
  979. RETURN_THROWS();
  980. }
  981. ctx = ecalloc(1, sizeof(php_zlib_context));
  982. ctx->zalloc = php_zlib_alloc;
  983. ctx->zfree = php_zlib_free;
  984. if (encoding < 0) {
  985. encoding += 15 - window;
  986. } else {
  987. encoding -= 15 - window;
  988. }
  989. if (Z_OK == deflateInit2(ctx, level, Z_DEFLATED, encoding, memory, strategy)) {
  990. if (dict) {
  991. int success = deflateSetDictionary(ctx, (Bytef *) dict, dictlen);
  992. ZEND_ASSERT(success == Z_OK);
  993. efree(dict);
  994. }
  995. RETURN_RES(zend_register_resource(ctx, le_deflate));
  996. } else {
  997. efree(ctx);
  998. php_error_docref(NULL, E_WARNING, "Failed allocating zlib.deflate context");
  999. RETURN_FALSE;
  1000. }
  1001. }
  1002. /* }}} */
  1003. /* {{{ proto string deflate_add(resource context, string data[, int flush_mode = ZLIB_SYNC_FLUSH])
  1004. Incrementally deflate data in the specified context */
  1005. PHP_FUNCTION(deflate_add)
  1006. {
  1007. zend_string *out;
  1008. char *in_buf;
  1009. size_t in_len, out_size, buffer_used;
  1010. zval *res;
  1011. z_stream *ctx;
  1012. zend_long flush_type = Z_SYNC_FLUSH;
  1013. int status;
  1014. if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &res, &in_buf, &in_len, &flush_type)) {
  1015. RETURN_THROWS();
  1016. }
  1017. if ((ctx = zend_fetch_resource(Z_RES_P(res), le_deflate_name, le_deflate)) == NULL) {
  1018. RETURN_THROWS();
  1019. }
  1020. switch (flush_type) {
  1021. case Z_BLOCK:
  1022. #if ZLIB_VERNUM < 0x1240L
  1023. zend_throw_error(NULL, "zlib >= 1.2.4 required for BLOCK deflate; current version: %s", ZLIB_VERSION);
  1024. RETURN_THROWS();
  1025. #endif
  1026. case Z_NO_FLUSH:
  1027. case Z_PARTIAL_FLUSH:
  1028. case Z_SYNC_FLUSH:
  1029. case Z_FULL_FLUSH:
  1030. case Z_FINISH:
  1031. break;
  1032. default:
  1033. zend_value_error(
  1034. "Flush mode must be ZLIB_NO_FLUSH, ZLIB_PARTIAL_FLUSH, ZLIB_SYNC_FLUSH, ZLIB_FULL_FLUSH, ZLIB_BLOCK or ZLIB_FINISH");
  1035. RETURN_THROWS();
  1036. }
  1037. if (in_len <= 0 && flush_type != Z_FINISH) {
  1038. RETURN_EMPTY_STRING();
  1039. }
  1040. out_size = PHP_ZLIB_BUFFER_SIZE_GUESS(in_len);
  1041. out_size = (out_size < 64) ? 64 : out_size;
  1042. out = zend_string_alloc(out_size, 0);
  1043. ctx->next_in = (Bytef *) in_buf;
  1044. ctx->next_out = (Bytef *) ZSTR_VAL(out);
  1045. ctx->avail_in = in_len;
  1046. ctx->avail_out = ZSTR_LEN(out);
  1047. buffer_used = 0;
  1048. do {
  1049. if (ctx->avail_out == 0) {
  1050. /* more output buffer space needed; realloc and try again */
  1051. /* adding 64 more bytes solved every issue I have seen */
  1052. out = zend_string_realloc(out, ZSTR_LEN(out) + 64, 0);
  1053. ctx->avail_out = 64;
  1054. ctx->next_out = (Bytef *) ZSTR_VAL(out) + buffer_used;
  1055. }
  1056. status = deflate(ctx, flush_type);
  1057. buffer_used = ZSTR_LEN(out) - ctx->avail_out;
  1058. } while (status == Z_OK && ctx->avail_out == 0);
  1059. switch (status) {
  1060. case Z_OK:
  1061. ZSTR_LEN(out) = (char *) ctx->next_out - ZSTR_VAL(out);
  1062. ZSTR_VAL(out)[ZSTR_LEN(out)] = 0;
  1063. RETURN_STR(out);
  1064. break;
  1065. case Z_STREAM_END:
  1066. ZSTR_LEN(out) = (char *) ctx->next_out - ZSTR_VAL(out);
  1067. ZSTR_VAL(out)[ZSTR_LEN(out)] = 0;
  1068. deflateReset(ctx);
  1069. RETURN_STR(out);
  1070. break;
  1071. default:
  1072. zend_string_release_ex(out, 0);
  1073. php_error_docref(NULL, E_WARNING, "zlib error (%s)", zError(status));
  1074. RETURN_FALSE;
  1075. }
  1076. }
  1077. /* }}} */
  1078. #ifdef COMPILE_DL_ZLIB
  1079. #ifdef ZTS
  1080. ZEND_TSRMLS_CACHE_DEFINE()
  1081. #endif
  1082. ZEND_GET_MODULE(php_zlib)
  1083. #endif
  1084. /* {{{ OnUpdate_zlib_output_compression */
  1085. static PHP_INI_MH(OnUpdate_zlib_output_compression)
  1086. {
  1087. int int_value;
  1088. char *ini_value;
  1089. if (new_value == NULL) {
  1090. return FAILURE;
  1091. }
  1092. if (!strncasecmp(ZSTR_VAL(new_value), "off", sizeof("off"))) {
  1093. int_value = 0;
  1094. } else if (!strncasecmp(ZSTR_VAL(new_value), "on", sizeof("on"))) {
  1095. int_value = 1;
  1096. } else {
  1097. int_value = zend_atoi(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
  1098. }
  1099. ini_value = zend_ini_string("output_handler", sizeof("output_handler"), 0);
  1100. if (ini_value && *ini_value && int_value) {
  1101. php_error_docref("ref.outcontrol", E_CORE_ERROR, "Cannot use both zlib.output_compression and output_handler together!!");
  1102. return FAILURE;
  1103. }
  1104. if (stage == PHP_INI_STAGE_RUNTIME) {
  1105. int status = php_output_get_status();
  1106. if (status & PHP_OUTPUT_SENT) {
  1107. php_error_docref("ref.outcontrol", E_WARNING, "Cannot change zlib.output_compression - headers already sent");
  1108. return FAILURE;
  1109. }
  1110. }
  1111. zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
  1112. *p = int_value;
  1113. ZLIBG(output_compression) = ZLIBG(output_compression_default);
  1114. if (stage == PHP_INI_STAGE_RUNTIME && int_value) {
  1115. if (!php_output_handler_started(ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME))) {
  1116. php_zlib_output_compression_start();
  1117. }
  1118. }
  1119. return SUCCESS;
  1120. }
  1121. /* }}} */
  1122. /* {{{ OnUpdate_zlib_output_handler */
  1123. static PHP_INI_MH(OnUpdate_zlib_output_handler)
  1124. {
  1125. if (stage == PHP_INI_STAGE_RUNTIME && (php_output_get_status() & PHP_OUTPUT_SENT)) {
  1126. php_error_docref("ref.outcontrol", E_WARNING, "Cannot change zlib.output_handler - headers already sent");
  1127. return FAILURE;
  1128. }
  1129. return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
  1130. }
  1131. /* }}} */
  1132. /* {{{ INI */
  1133. PHP_INI_BEGIN()
  1134. STD_PHP_INI_BOOLEAN("zlib.output_compression", "0", PHP_INI_ALL, OnUpdate_zlib_output_compression, output_compression_default, zend_zlib_globals, zlib_globals)
  1135. STD_PHP_INI_ENTRY("zlib.output_compression_level", "-1", PHP_INI_ALL, OnUpdateLong, output_compression_level, zend_zlib_globals, zlib_globals)
  1136. STD_PHP_INI_ENTRY("zlib.output_handler", "", PHP_INI_ALL, OnUpdate_zlib_output_handler, output_handler, zend_zlib_globals, zlib_globals)
  1137. PHP_INI_END()
  1138. /* }}} */
  1139. /* {{{ PHP_MINIT_FUNCTION */
  1140. static PHP_MINIT_FUNCTION(zlib)
  1141. {
  1142. php_register_url_stream_wrapper("compress.zlib", &php_stream_gzip_wrapper);
  1143. php_stream_filter_register_factory("zlib.*", &php_zlib_filter_factory);
  1144. php_output_handler_alias_register(ZEND_STRL("ob_gzhandler"), php_zlib_output_handler_init);
  1145. php_output_handler_conflict_register(ZEND_STRL("ob_gzhandler"), php_zlib_output_conflict_check);
  1146. php_output_handler_conflict_register(ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME), php_zlib_output_conflict_check);
  1147. le_deflate = zend_register_list_destructors_ex(deflate_rsrc_dtor, NULL, "zlib.deflate", module_number);
  1148. le_inflate = zend_register_list_destructors_ex(inflate_rsrc_dtor, NULL, "zlib.inflate", module_number);
  1149. REGISTER_LONG_CONSTANT("FORCE_GZIP", PHP_ZLIB_ENCODING_GZIP, CONST_CS|CONST_PERSISTENT);
  1150. REGISTER_LONG_CONSTANT("FORCE_DEFLATE", PHP_ZLIB_ENCODING_DEFLATE, CONST_CS|CONST_PERSISTENT);
  1151. REGISTER_LONG_CONSTANT("ZLIB_ENCODING_RAW", PHP_ZLIB_ENCODING_RAW, CONST_CS|CONST_PERSISTENT);
  1152. REGISTER_LONG_CONSTANT("ZLIB_ENCODING_GZIP", PHP_ZLIB_ENCODING_GZIP, CONST_CS|CONST_PERSISTENT);
  1153. REGISTER_LONG_CONSTANT("ZLIB_ENCODING_DEFLATE", PHP_ZLIB_ENCODING_DEFLATE, CONST_CS|CONST_PERSISTENT);
  1154. REGISTER_LONG_CONSTANT("ZLIB_NO_FLUSH", Z_NO_FLUSH, CONST_CS|CONST_PERSISTENT);
  1155. REGISTER_LONG_CONSTANT("ZLIB_PARTIAL_FLUSH", Z_PARTIAL_FLUSH, CONST_CS|CONST_PERSISTENT);
  1156. REGISTER_LONG_CONSTANT("ZLIB_SYNC_FLUSH", Z_SYNC_FLUSH, CONST_CS|CONST_PERSISTENT);
  1157. REGISTER_LONG_CONSTANT("ZLIB_FULL_FLUSH", Z_FULL_FLUSH, CONST_CS|CONST_PERSISTENT);
  1158. REGISTER_LONG_CONSTANT("ZLIB_BLOCK", Z_BLOCK, CONST_CS|CONST_PERSISTENT);
  1159. REGISTER_LONG_CONSTANT("ZLIB_FINISH", Z_FINISH, CONST_CS|CONST_PERSISTENT);
  1160. REGISTER_LONG_CONSTANT("ZLIB_FILTERED", Z_FILTERED, CONST_CS|CONST_PERSISTENT);
  1161. REGISTER_LONG_CONSTANT("ZLIB_HUFFMAN_ONLY", Z_HUFFMAN_ONLY, CONST_CS|CONST_PERSISTENT);
  1162. REGISTER_LONG_CONSTANT("ZLIB_RLE", Z_RLE, CONST_CS|CONST_PERSISTENT);
  1163. REGISTER_LONG_CONSTANT("ZLIB_FIXED", Z_FIXED, CONST_CS|CONST_PERSISTENT);
  1164. REGISTER_LONG_CONSTANT("ZLIB_DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY, CONST_CS|CONST_PERSISTENT);
  1165. REGISTER_STRING_CONSTANT("ZLIB_VERSION", ZLIB_VERSION, CONST_CS|CONST_PERSISTENT);
  1166. REGISTER_LONG_CONSTANT("ZLIB_VERNUM", ZLIB_VERNUM, CONST_CS|CONST_PERSISTENT);
  1167. REGISTER_LONG_CONSTANT("ZLIB_OK", Z_OK, CONST_CS|CONST_PERSISTENT);
  1168. REGISTER_LONG_CONSTANT("ZLIB_STREAM_END", Z_STREAM_END, CONST_CS|CONST_PERSISTENT);
  1169. REGISTER_LONG_CONSTANT("ZLIB_NEED_DICT", Z_NEED_DICT, CONST_CS|CONST_PERSISTENT);
  1170. REGISTER_LONG_CONSTANT("ZLIB_ERRNO", Z_ERRNO, CONST_CS|CONST_PERSISTENT);
  1171. REGISTER_LONG_CONSTANT("ZLIB_STREAM_ERROR", Z_STREAM_ERROR, CONST_CS|CONST_PERSISTENT);
  1172. REGISTER_LONG_CONSTANT("ZLIB_DATA_ERROR", Z_DATA_ERROR, CONST_CS|CONST_PERSISTENT);
  1173. REGISTER_LONG_CONSTANT("ZLIB_MEM_ERROR", Z_MEM_ERROR, CONST_CS|CONST_PERSISTENT);
  1174. REGISTER_LONG_CONSTANT("ZLIB_BUF_ERROR", Z_BUF_ERROR, CONST_CS|CONST_PERSISTENT);
  1175. REGISTER_LONG_CONSTANT("ZLIB_VERSION_ERROR", Z_VERSION_ERROR, CONST_CS|CONST_PERSISTENT);
  1176. REGISTER_INI_ENTRIES();
  1177. return SUCCESS;
  1178. }
  1179. /* }}} */
  1180. /* {{{ PHP_MSHUTDOWN_FUNCTION */
  1181. static PHP_MSHUTDOWN_FUNCTION(zlib)
  1182. {
  1183. php_unregister_url_stream_wrapper("zlib");
  1184. php_stream_filter_unregister_factory("zlib.*");
  1185. UNREGISTER_INI_ENTRIES();
  1186. return SUCCESS;
  1187. }
  1188. /* }}} */
  1189. /* {{{ PHP_RINIT_FUNCTION */
  1190. static PHP_RINIT_FUNCTION(zlib)
  1191. {
  1192. ZLIBG(compression_coding) = 0;
  1193. if (!ZLIBG(handler_registered)) {
  1194. ZLIBG(output_compression) = ZLIBG(output_compression_default);
  1195. php_zlib_output_compression_start();
  1196. }
  1197. return SUCCESS;
  1198. }
  1199. /* }}} */
  1200. /* {{{ PHP_RSHUTDOWN_FUNCTION */
  1201. static PHP_RSHUTDOWN_FUNCTION(zlib)
  1202. {
  1203. php_zlib_cleanup_ob_gzhandler_mess();
  1204. ZLIBG(handler_registered) = 0;
  1205. return SUCCESS;
  1206. }
  1207. /* }}} */
  1208. /* {{{ PHP_MINFO_FUNCTION */
  1209. static PHP_MINFO_FUNCTION(zlib)
  1210. {
  1211. php_info_print_table_start();
  1212. php_info_print_table_header(2, "ZLib Support", "enabled");
  1213. php_info_print_table_row(2, "Stream Wrapper", "compress.zlib://");
  1214. php_info_print_table_row(2, "Stream Filter", "zlib.inflate, zlib.deflate");
  1215. php_info_print_table_row(2, "Compiled Version", ZLIB_VERSION);
  1216. php_info_print_table_row(2, "Linked Version", (char *) zlibVersion());
  1217. php_info_print_table_end();
  1218. DISPLAY_INI_ENTRIES();
  1219. }
  1220. /* }}} */
  1221. /* {{{ ZEND_MODULE_GLOBALS_CTOR */
  1222. static PHP_GINIT_FUNCTION(zlib)
  1223. {
  1224. #if defined(COMPILE_DL_ZLIB) && defined(ZTS)
  1225. ZEND_TSRMLS_CACHE_UPDATE();
  1226. #endif
  1227. zlib_globals->ob_gzhandler = NULL;
  1228. zlib_globals->handler_registered = 0;
  1229. }
  1230. /* }}} */
  1231. /* {{{ php_zlib_module_entry */
  1232. zend_module_entry php_zlib_module_entry = {
  1233. STANDARD_MODULE_HEADER,
  1234. "zlib",
  1235. ext_functions,
  1236. PHP_MINIT(zlib),
  1237. PHP_MSHUTDOWN(zlib),
  1238. PHP_RINIT(zlib),
  1239. PHP_RSHUTDOWN(zlib),
  1240. PHP_MINFO(zlib),
  1241. PHP_ZLIB_VERSION,
  1242. PHP_MODULE_GLOBALS(zlib),
  1243. PHP_GINIT(zlib),
  1244. NULL,
  1245. NULL,
  1246. STANDARD_MODULE_PROPERTIES_EX
  1247. };
  1248. /* }}} */