1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> | 16 | Stefan Röhrich <sr@linux.de> | 17 | Zeev Suraski <zeev@zend.com> | 18 | Jade Nicoletti <nicoletti@nns.ch> | 19 | Michael Wallner <mike@php.net> | 20 +----------------------------------------------------------------------+ 21 */ 22 23/* $Id$ */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include "php.h" 30#include "SAPI.h" 31#include "php_ini.h" 32#include "ext/standard/info.h" 33#include "ext/standard/file.h" 34#include "ext/standard/php_string.h" 35#include "php_zlib.h" 36 37ZEND_DECLARE_MODULE_GLOBALS(zlib); 38 39/* {{{ Memory management wrappers */ 40 41static voidpf php_zlib_alloc(voidpf opaque, uInt items, uInt size) 42{ 43 return (voidpf)safe_emalloc(items, size, 0); 44} 45 46static void php_zlib_free(voidpf opaque, voidpf address) 47{ 48 efree((void*)address); 49} 50/* }}} */ 51 52/* {{{ php_zlib_output_conflict_check() */ 53static int php_zlib_output_conflict_check(const char *handler_name, size_t handler_name_len TSRMLS_DC) 54{ 55 if (php_output_get_level(TSRMLS_C) > 0) { 56 if (php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME) TSRMLS_CC) 57 || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("ob_gzhandler") TSRMLS_CC) 58 || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("mb_output_handler") TSRMLS_CC) 59 || php_output_handler_conflict(handler_name, handler_name_len, ZEND_STRL("URL-Rewriter") TSRMLS_CC)) { 60 return FAILURE; 61 } 62 } 63 return SUCCESS; 64} 65/* }}} */ 66 67/* {{{ php_zlib_output_encoding() */ 68static int php_zlib_output_encoding(TSRMLS_D) 69{ 70 zval **enc; 71 72 if (!ZLIBG(compression_coding)) { 73 zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC); 74 if (PG(http_globals)[TRACK_VARS_SERVER] && SUCCESS == zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING"), (void *) &enc)) { 75 convert_to_string(*enc); 76 if (strstr(Z_STRVAL_PP(enc), "gzip")) { 77 ZLIBG(compression_coding) = PHP_ZLIB_ENCODING_GZIP; 78 } else if (strstr(Z_STRVAL_PP(enc), "deflate")) { 79 ZLIBG(compression_coding) = PHP_ZLIB_ENCODING_DEFLATE; 80 } 81 } 82 } 83 return ZLIBG(compression_coding); 84} 85/* }}} */ 86 87/* {{{ php_zlib_output_handler_ex() */ 88static int php_zlib_output_handler_ex(php_zlib_context *ctx, php_output_context *output_context) 89{ 90 int flags = Z_SYNC_FLUSH; 91 PHP_OUTPUT_TSRMLS(output_context); 92 93 if (output_context->op & PHP_OUTPUT_HANDLER_START) { 94 /* start up */ 95 if (Z_OK != deflateInit2(&ctx->Z, ZLIBG(output_compression_level), Z_DEFLATED, ZLIBG(compression_coding), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) { 96 return FAILURE; 97 } 98 } 99 100 if (output_context->op & PHP_OUTPUT_HANDLER_CLEAN) { 101 /* free buffers */ 102 deflateEnd(&ctx->Z); 103 104 if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) { 105 /* discard */ 106 return SUCCESS; 107 } else { 108 /* restart */ 109 if (Z_OK != deflateInit2(&ctx->Z, ZLIBG(output_compression_level), Z_DEFLATED, ZLIBG(compression_coding), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) { 110 return FAILURE; 111 } 112 ctx->buffer.used = 0; 113 } 114 } else { 115 if (output_context->in.used) { 116 /* append input */ 117 if (ctx->buffer.free < output_context->in.used) { 118 if (!(ctx->buffer.aptr = erealloc_recoverable(ctx->buffer.data, ctx->buffer.used + ctx->buffer.free + output_context->in.used))) { 119 deflateEnd(&ctx->Z); 120 return FAILURE; 121 } 122 ctx->buffer.data = ctx->buffer.aptr; 123 ctx->buffer.free += output_context->in.used; 124 } 125 memcpy(ctx->buffer.data + ctx->buffer.used, output_context->in.data, output_context->in.used); 126 ctx->buffer.free -= output_context->in.used; 127 ctx->buffer.used += output_context->in.used; 128 } 129 output_context->out.size = PHP_ZLIB_BUFFER_SIZE_GUESS(output_context->in.used); 130 output_context->out.data = emalloc(output_context->out.size); 131 output_context->out.free = 1; 132 output_context->out.used = 0; 133 134 ctx->Z.avail_in = ctx->buffer.used; 135 ctx->Z.next_in = (Bytef *) ctx->buffer.data; 136 ctx->Z.avail_out = output_context->out.size; 137 ctx->Z.next_out = (Bytef *) output_context->out.data; 138 139 if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) { 140 flags = Z_FINISH; 141 } else if (output_context->op & PHP_OUTPUT_HANDLER_FLUSH) { 142 flags = Z_FULL_FLUSH; 143 } 144 145 switch (deflate(&ctx->Z, flags)) { 146 case Z_OK: 147 if (flags == Z_FINISH) { 148 deflateEnd(&ctx->Z); 149 return FAILURE; 150 } 151 case Z_STREAM_END: 152 if (ctx->Z.avail_in) { 153 memmove(ctx->buffer.data, ctx->buffer.data + ctx->buffer.used - ctx->Z.avail_in, ctx->Z.avail_in); 154 } 155 ctx->buffer.free += ctx->buffer.used - ctx->Z.avail_in; 156 ctx->buffer.used = ctx->Z.avail_in; 157 output_context->out.used = output_context->out.size - ctx->Z.avail_out; 158 break; 159 default: 160 deflateEnd(&ctx->Z); 161 return FAILURE; 162 } 163 164 if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) { 165 deflateEnd(&ctx->Z); 166 } 167 } 168 169 return SUCCESS; 170} 171/* }}} */ 172 173/* {{{ php_zlib_output_handler() */ 174static int php_zlib_output_handler(void **handler_context, php_output_context *output_context) 175{ 176 php_zlib_context *ctx = *(php_zlib_context **) handler_context; 177 PHP_OUTPUT_TSRMLS(output_context); 178 179 if (!php_zlib_output_encoding(TSRMLS_C)) { 180 /* "Vary: Accept-Encoding" header sent along uncompressed content breaks caching in MSIE, 181 so let's just send it with successfully compressed content or unless the complete 182 buffer gets discarded, see http://bugs.php.net/40325; 183 184 Test as follows: 185 +Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";' 186 +Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";' 187 -Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();' 188 -Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();' 189 */ 190 if ((output_context->op & PHP_OUTPUT_HANDLER_START) 191 && (output_context->op != (PHP_OUTPUT_HANDLER_START|PHP_OUTPUT_HANDLER_CLEAN|PHP_OUTPUT_HANDLER_FINAL)) 192 ) { 193 sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC); 194 } 195 return FAILURE; 196 } 197 198 if (SUCCESS != php_zlib_output_handler_ex(ctx, output_context)) { 199 return FAILURE; 200 } 201 202 if (!(output_context->op & PHP_OUTPUT_HANDLER_CLEAN)) { 203 int flags; 204 205 if (SUCCESS == php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS, &flags TSRMLS_CC)) { 206 /* only run this once */ 207 if (!(flags & PHP_OUTPUT_HANDLER_STARTED)) { 208 if (SG(headers_sent) || !ZLIBG(output_compression)) { 209 deflateEnd(&ctx->Z); 210 return FAILURE; 211 } 212 switch (ZLIBG(compression_coding)) { 213 case PHP_ZLIB_ENCODING_GZIP: 214 sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1 TSRMLS_CC); 215 break; 216 case PHP_ZLIB_ENCODING_DEFLATE: 217 sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1 TSRMLS_CC); 218 break; 219 default: 220 deflateEnd(&ctx->Z); 221 return FAILURE; 222 } 223 sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC); 224 php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL TSRMLS_CC); 225 } 226 } 227 } 228 229 return SUCCESS; 230} 231/* }}} */ 232 233/* {{{ php_zlib_output_handler_context_init() */ 234static php_zlib_context *php_zlib_output_handler_context_init(TSRMLS_D) 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 243/* {{{ php_zlib_output_handler_context_dtor() */ 244static void php_zlib_output_handler_context_dtor(void *opaq TSRMLS_DC) 245{ 246 php_zlib_context *ctx = (php_zlib_context *) opaq; 247 248 if (ctx) { 249 if (ctx->buffer.data) { 250 efree(ctx->buffer.data); 251 } 252 efree(ctx); 253 } 254} 255/* }}} */ 256 257/* {{{ php_zlib_output_handler_init() */ 258static php_output_handler *php_zlib_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags TSRMLS_DC) 259{ 260 php_output_handler *h = NULL; 261 262 if (!ZLIBG(output_compression)) { 263 ZLIBG(output_compression) = chunk_size ? chunk_size : PHP_OUTPUT_HANDLER_DEFAULT_SIZE; 264 } 265 266 ZLIBG(handler_registered) = 1; 267 268 if ((h = php_output_handler_create_internal(handler_name, handler_name_len, php_zlib_output_handler, chunk_size, flags TSRMLS_CC))) { 269 php_output_handler_set_context(h, php_zlib_output_handler_context_init(TSRMLS_C), php_zlib_output_handler_context_dtor TSRMLS_CC); 270 } 271 272 return h; 273} 274/* }}} */ 275 276/* {{{ php_zlib_output_compression_start() */ 277static void php_zlib_output_compression_start(TSRMLS_D) 278{ 279 zval *zoh; 280 php_output_handler *h; 281 282 switch (ZLIBG(output_compression)) { 283 case 0: 284 break; 285 case 1: 286 ZLIBG(output_compression) = PHP_OUTPUT_HANDLER_DEFAULT_SIZE; 287 /* break omitted intentionally */ 288 default: 289 if ( php_zlib_output_encoding(TSRMLS_C) && 290 (h = php_zlib_output_handler_init(ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME), ZLIBG(output_compression), PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC)) && 291 (SUCCESS == php_output_handler_start(h TSRMLS_CC))) { 292 if (ZLIBG(output_handler) && *ZLIBG(output_handler)) { 293 MAKE_STD_ZVAL(zoh); 294 ZVAL_STRING(zoh, ZLIBG(output_handler), 1); 295 php_output_start_user(zoh, ZLIBG(output_compression), PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC); 296 zval_ptr_dtor(&zoh); 297 } 298 } 299 break; 300 } 301} 302/* }}} */ 303 304/* {{{ php_zlib_encode() */ 305static int php_zlib_encode(const char *in_buf, size_t in_len, char **out_buf, size_t *out_len, int encoding, int level TSRMLS_DC) 306{ 307 int status; 308 z_stream Z; 309 310 memset(&Z, 0, sizeof(z_stream)); 311 Z.zalloc = php_zlib_alloc; 312 Z.zfree = php_zlib_free; 313 314 if (Z_OK == (status = deflateInit2(&Z, level, Z_DEFLATED, encoding, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY))) { 315 *out_len = PHP_ZLIB_BUFFER_SIZE_GUESS(in_len); 316 *out_buf = emalloc(*out_len); 317 318 Z.next_in = (Bytef *) in_buf; 319 Z.next_out = (Bytef *) *out_buf; 320 Z.avail_in = in_len; 321 Z.avail_out = *out_len; 322 323 status = deflate(&Z, Z_FINISH); 324 deflateEnd(&Z); 325 326 if (Z_STREAM_END == status) { 327 /* size buffer down to actual length */ 328 *out_buf = erealloc(*out_buf, Z.total_out + 1); 329 (*out_buf)[*out_len = Z.total_out] = '\0'; 330 return SUCCESS; 331 } else { 332 efree(*out_buf); 333 } 334 } 335 336 *out_buf = NULL; 337 *out_len = 0; 338 339 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status)); 340 return FAILURE; 341} 342/* }}} */ 343 344/* {{{ php_zlib_inflate_rounds() */ 345static inline int php_zlib_inflate_rounds(z_stream *Z, size_t max, char **buf, size_t *len) 346{ 347 int status, round = 0; 348 php_zlib_buffer buffer = {NULL, NULL, 0, 0, 0}; 349 350 *buf = NULL; 351 *len = 0; 352 353 buffer.size = (max && (max < Z->avail_in)) ? max : Z->avail_in; 354 355 do { 356 if ((max && (max <= buffer.used)) || !(buffer.aptr = erealloc_recoverable(buffer.data, buffer.size))) { 357 status = Z_MEM_ERROR; 358 } else { 359 buffer.data = buffer.aptr; 360 Z->avail_out = buffer.free = buffer.size - buffer.used; 361 Z->next_out = (Bytef *) buffer.data + buffer.used; 362#if 0 363 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); 364#endif 365 status = inflate(Z, Z_NO_FLUSH); 366 367 buffer.used += buffer.free - Z->avail_out; 368 buffer.free = Z->avail_out; 369#if 0 370 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); 371#endif 372 buffer.size += (buffer.size >> 3) + 1; 373 } 374 } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < 100); 375 376 if (status == Z_STREAM_END) { 377 buffer.data = erealloc(buffer.data, buffer.used + 1); 378 buffer.data[buffer.used] = '\0'; 379 *buf = buffer.data; 380 *len = buffer.used; 381 } else { 382 if (buffer.data) { 383 efree(buffer.data); 384 } 385 /* HACK: See zlib/examples/zpipe.c inf() function for explanation. */ 386 /* This works as long as this function is not used for streaming. Required to catch very short invalid data. */ 387 status = (status == Z_OK) ? Z_DATA_ERROR : status; 388 } 389 return status; 390} 391/* }}} */ 392 393/* {{{ php_zlib_decode() */ 394static 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 TSRMLS_DC) 395{ 396 int status = Z_DATA_ERROR; 397 z_stream Z; 398 399 memset(&Z, 0, sizeof(z_stream)); 400 Z.zalloc = php_zlib_alloc; 401 Z.zfree = php_zlib_free; 402 403 if (in_len) { 404retry_raw_inflate: 405 status = inflateInit2(&Z, encoding); 406 if (Z_OK == status) { 407 Z.next_in = (Bytef *) in_buf; 408 Z.avail_in = in_len + 1; /* NOTE: data must be zero terminated */ 409 410 switch (status = php_zlib_inflate_rounds(&Z, max_len, out_buf, out_len)) { 411 case Z_STREAM_END: 412 inflateEnd(&Z); 413 return SUCCESS; 414 415 case Z_DATA_ERROR: 416 /* raw deflated data? */ 417 if (PHP_ZLIB_ENCODING_ANY == encoding) { 418 inflateEnd(&Z); 419 encoding = PHP_ZLIB_ENCODING_RAW; 420 goto retry_raw_inflate; 421 } 422 } 423 inflateEnd(&Z); 424 } 425 } 426 427 *out_buf = NULL; 428 *out_len = 0; 429 430 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status)); 431 return FAILURE; 432} 433/* }}} */ 434 435/* {{{ php_zlib_cleanup_ob_gzhandler_mess() */ 436static void php_zlib_cleanup_ob_gzhandler_mess(TSRMLS_D) 437{ 438 if (ZLIBG(ob_gzhandler)) { 439 deflateEnd(&(ZLIBG(ob_gzhandler)->Z)); 440 php_zlib_output_handler_context_dtor(ZLIBG(ob_gzhandler) TSRMLS_CC); 441 ZLIBG(ob_gzhandler) = NULL; 442 } 443} 444/* }}} */ 445 446/* {{{ proto string ob_gzhandler(string data, int flags) 447 Legacy hack */ 448static PHP_FUNCTION(ob_gzhandler) 449{ 450 char *in_str; 451 int in_len; 452 long flags = 0; 453 php_output_context ctx = {0}; 454 int encoding, rv; 455 456 /* 457 * NOTE that the real ob_gzhandler is an alias to "zlib output compression". 458 * This is a really bad hack, because 459 * - we have to initialize a php_zlib_context on demand 460 * - we have to clean it up in RSHUTDOWN 461 * - OG(running) is not set or set to any other output handler 462 * - we have to mess around with php_output_context */ 463 464 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &in_str, &in_len, &flags)) { 465 RETURN_FALSE; 466 } 467 468 if (!(encoding = php_zlib_output_encoding(TSRMLS_C))) { 469 RETURN_FALSE; 470 } 471 472 if (flags & PHP_OUTPUT_HANDLER_START) { 473 switch (encoding) { 474 case PHP_ZLIB_ENCODING_GZIP: 475 sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1 TSRMLS_CC); 476 break; 477 case PHP_ZLIB_ENCODING_DEFLATE: 478 sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1 TSRMLS_CC); 479 break; 480 } 481 sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC); 482 } 483 484 if (!ZLIBG(ob_gzhandler)) { 485 ZLIBG(ob_gzhandler) = php_zlib_output_handler_context_init(TSRMLS_C); 486 } 487 488 TSRMLS_SET_CTX(ctx.tsrm_ls); 489 ctx.op = flags; 490 ctx.in.data = in_str; 491 ctx.in.used = in_len; 492 493 rv = php_zlib_output_handler_ex(ZLIBG(ob_gzhandler), &ctx); 494 495 if (SUCCESS != rv) { 496 if (ctx.out.data && ctx.out.free) { 497 efree(ctx.out.data); 498 } 499 php_zlib_cleanup_ob_gzhandler_mess(TSRMLS_C); 500 RETURN_FALSE; 501 } 502 503 if (ctx.out.data) { 504 RETVAL_STRINGL(ctx.out.data, ctx.out.used, 1); 505 if (ctx.out.free) { 506 efree(ctx.out.data); 507 } 508 } else { 509 RETVAL_EMPTY_STRING(); 510 } 511} 512/* }}} */ 513 514/* {{{ proto string zlib_get_coding_type(void) 515 Returns the coding type used for output compression */ 516static PHP_FUNCTION(zlib_get_coding_type) 517{ 518 if (zend_parse_parameters_none() == FAILURE) { 519 return; 520 } 521 switch (ZLIBG(compression_coding)) { 522 case PHP_ZLIB_ENCODING_GZIP: 523 RETURN_STRINGL("gzip", sizeof("gzip") - 1, 1); 524 case PHP_ZLIB_ENCODING_DEFLATE: 525 RETURN_STRINGL("deflate", sizeof("deflate") - 1, 1); 526 default: 527 RETURN_FALSE; 528 } 529} 530/* }}} */ 531 532/* {{{ proto array gzfile(string filename [, int use_include_path]) 533 Read and uncompress entire .gz-file into an array */ 534static PHP_FUNCTION(gzfile) 535{ 536 char *filename; 537 int filename_len; 538 int flags = REPORT_ERRORS; 539 char buf[8192] = {0}; 540 register int i = 0; 541 long use_include_path = 0; 542 php_stream *stream; 543 544 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|l", &filename, &filename_len, &use_include_path)) { 545 return; 546 } 547 548 if (use_include_path) { 549 flags |= USE_PATH; 550 } 551 552 /* using a stream here is a bit more efficient (resource wise) than php_gzopen_wrapper */ 553 stream = php_stream_gzopen(NULL, filename, "rb", flags, NULL, NULL STREAMS_CC TSRMLS_CC); 554 555 if (!stream) { 556 /* Error reporting is already done by stream code */ 557 RETURN_FALSE; 558 } 559 560 /* Initialize return array */ 561 array_init(return_value); 562 563 /* Now loop through the file and do the magic quotes thing if needed */ 564 memset(buf, 0, sizeof(buf)); 565 566 while (php_stream_gets(stream, buf, sizeof(buf) - 1) != NULL) { 567 add_index_string(return_value, i++, buf, 1); 568 } 569 php_stream_close(stream); 570} 571/* }}} */ 572 573/* {{{ proto resource gzopen(string filename, string mode [, int use_include_path]) 574 Open a .gz-file and return a .gz-file pointer */ 575static PHP_FUNCTION(gzopen) 576{ 577 char *filename; 578 char *mode; 579 int filename_len, mode_len; 580 int flags = REPORT_ERRORS; 581 php_stream *stream; 582 long use_include_path = 0; 583 584 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &filename, &filename_len, &mode, &mode_len, &use_include_path) == FAILURE) { 585 return; 586 } 587 588 if (use_include_path) { 589 flags |= USE_PATH; 590 } 591 592 stream = php_stream_gzopen(NULL, filename, mode, flags, NULL, NULL STREAMS_CC TSRMLS_CC); 593 594 if (!stream) { 595 RETURN_FALSE; 596 } 597 php_stream_to_zval(stream, return_value); 598} 599/* }}} */ 600 601/* {{{ proto int readgzfile(string filename [, int use_include_path]) 602 Output a .gz-file */ 603static PHP_FUNCTION(readgzfile) 604{ 605 char *filename; 606 int filename_len; 607 int flags = REPORT_ERRORS; 608 php_stream *stream; 609 int size; 610 long use_include_path = 0; 611 612 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &filename, &filename_len, &use_include_path) == FAILURE) { 613 return; 614 } 615 616 if (use_include_path) { 617 flags |= USE_PATH; 618 } 619 620 stream = php_stream_gzopen(NULL, filename, "rb", flags, NULL, NULL STREAMS_CC TSRMLS_CC); 621 622 if (!stream) { 623 RETURN_FALSE; 624 } 625 size = php_stream_passthru(stream); 626 php_stream_close(stream); 627 RETURN_LONG(size); 628} 629/* }}} */ 630 631#define PHP_ZLIB_ENCODE_FUNC(name, default_encoding) \ 632static PHP_FUNCTION(name) \ 633{ \ 634 char *in_buf, *out_buf; \ 635 int in_len; \ 636 size_t out_len; \ 637 long level = -1; \ 638 long encoding = default_encoding; \ 639 if (default_encoding) { \ 640 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &in_buf, &in_len, &level, &encoding)) { \ 641 return; \ 642 } \ 643 } else { \ 644 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &in_buf, &in_len, &encoding, &level)) { \ 645 return; \ 646 } \ 647 } \ 648 if (level < -1 || level > 9) { \ 649 php_error_docref(NULL TSRMLS_CC, E_WARNING, "compression level (%ld) must be within -1..9", level); \ 650 RETURN_FALSE; \ 651 } \ 652 switch (encoding) { \ 653 case PHP_ZLIB_ENCODING_RAW: \ 654 case PHP_ZLIB_ENCODING_GZIP: \ 655 case PHP_ZLIB_ENCODING_DEFLATE: \ 656 break; \ 657 default: \ 658 php_error_docref(NULL TSRMLS_CC, E_WARNING, "encoding mode must be either ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE"); \ 659 RETURN_FALSE; \ 660 } \ 661 if (SUCCESS != php_zlib_encode(in_buf, in_len, &out_buf, &out_len, encoding, level TSRMLS_CC)) { \ 662 RETURN_FALSE; \ 663 } \ 664 RETURN_STRINGL(out_buf, out_len, 0); \ 665} 666 667#define PHP_ZLIB_DECODE_FUNC(name, encoding) \ 668static PHP_FUNCTION(name) \ 669{ \ 670 char *in_buf, *out_buf; \ 671 int in_len; \ 672 size_t out_len; \ 673 long max_len = 0; \ 674 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &in_buf, &in_len, &max_len)) { \ 675 return; \ 676 } \ 677 if (max_len < 0) { \ 678 php_error_docref(NULL TSRMLS_CC, E_WARNING, "length (%ld) must be greater or equal zero", max_len); \ 679 RETURN_FALSE; \ 680 } \ 681 if (SUCCESS != php_zlib_decode(in_buf, in_len, &out_buf, &out_len, encoding, max_len TSRMLS_CC)) { \ 682 RETURN_FALSE; \ 683 } \ 684 RETURN_STRINGL(out_buf, out_len, 0); \ 685} 686 687/* {{{ proto binary zlib_encode(binary data, int encoding[, int level = -1]) 688 Compress data with the specified encoding */ 689PHP_ZLIB_ENCODE_FUNC(zlib_encode, 0); 690/* }}} */ 691 692/* {{{ proto binary zlib_decode(binary data[, int max_decoded_len]) 693 Uncompress any raw/gzip/zlib encoded data */ 694PHP_ZLIB_DECODE_FUNC(zlib_decode, PHP_ZLIB_ENCODING_ANY); 695/* }}} */ 696 697/* NOTE: The naming of these userland functions was quite unlucky */ 698/* {{{ proto binary gzdeflate(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_RAW]) 699 Encode data with the raw deflate encoding */ 700PHP_ZLIB_ENCODE_FUNC(gzdeflate, PHP_ZLIB_ENCODING_RAW); 701/* }}} */ 702 703/* {{{ proto binary gzencode(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_GZIP]) 704 Encode data with the gzip encoding */ 705PHP_ZLIB_ENCODE_FUNC(gzencode, PHP_ZLIB_ENCODING_GZIP); 706/* }}} */ 707 708/* {{{ proto binary gzcompress(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_DEFLATE]) 709 Encode data with the zlib encoding */ 710PHP_ZLIB_ENCODE_FUNC(gzcompress, PHP_ZLIB_ENCODING_DEFLATE); 711/* }}} */ 712 713/* {{{ proto binary gzinflate(binary data[, int max_decoded_len]) 714 Decode raw deflate encoded data */ 715PHP_ZLIB_DECODE_FUNC(gzinflate, PHP_ZLIB_ENCODING_RAW); 716/* }}} */ 717 718/* {{{ proto binary gzdecode(binary data[, int max_decoded_len]) 719 Decode gzip encoded data */ 720PHP_ZLIB_DECODE_FUNC(gzdecode, PHP_ZLIB_ENCODING_GZIP); 721/* }}} */ 722 723/* {{{ proto binary gzuncompress(binary data[, int max_decoded_len]) 724 Decode zlib encoded data */ 725PHP_ZLIB_DECODE_FUNC(gzuncompress, PHP_ZLIB_ENCODING_DEFLATE); 726/* }}} */ 727 728#ifdef COMPILE_DL_ZLIB 729ZEND_GET_MODULE(php_zlib) 730#endif 731 732/* {{{ arginfo */ 733ZEND_BEGIN_ARG_INFO_EX(arginfo_ob_gzhandler, 0, 0, 2) 734 ZEND_ARG_INFO(0, data) 735 ZEND_ARG_INFO(0, flags) 736ZEND_END_ARG_INFO() 737 738ZEND_BEGIN_ARG_INFO(arginfo_zlib_get_coding_type, 0) 739ZEND_END_ARG_INFO() 740 741ZEND_BEGIN_ARG_INFO_EX(arginfo_gzfile, 0, 0, 1) 742 ZEND_ARG_INFO(0, filename) 743 ZEND_ARG_INFO(0, use_include_path) 744ZEND_END_ARG_INFO() 745 746ZEND_BEGIN_ARG_INFO_EX(arginfo_gzopen, 0, 0, 2) 747 ZEND_ARG_INFO(0, filename) 748 ZEND_ARG_INFO(0, mode) 749 ZEND_ARG_INFO(0, use_include_path) 750ZEND_END_ARG_INFO() 751 752ZEND_BEGIN_ARG_INFO_EX(arginfo_readgzfile, 0, 0, 1) 753 ZEND_ARG_INFO(0, filename) 754 ZEND_ARG_INFO(0, use_include_path) 755ZEND_END_ARG_INFO() 756 757ZEND_BEGIN_ARG_INFO_EX(arginfo_zlib_encode, 0, 0, 2) 758 ZEND_ARG_INFO(0, data) 759 ZEND_ARG_INFO(0, encoding) 760 ZEND_ARG_INFO(0, level) 761ZEND_END_ARG_INFO() 762 763ZEND_BEGIN_ARG_INFO_EX(arginfo_zlib_decode, 0, 0, 1) 764 ZEND_ARG_INFO(0, data) 765 ZEND_ARG_INFO(0, max_decoded_len) 766ZEND_END_ARG_INFO() 767 768ZEND_BEGIN_ARG_INFO_EX(arginfo_gzdeflate, 0, 0, 1) 769 ZEND_ARG_INFO(0, data) 770 ZEND_ARG_INFO(0, level) 771 ZEND_ARG_INFO(0, encoding) 772ZEND_END_ARG_INFO() 773 774ZEND_BEGIN_ARG_INFO_EX(arginfo_gzencode, 0, 0, 1) 775 ZEND_ARG_INFO(0, data) 776 ZEND_ARG_INFO(0, level) 777 ZEND_ARG_INFO(0, encoding) 778ZEND_END_ARG_INFO() 779 780ZEND_BEGIN_ARG_INFO_EX(arginfo_gzcompress, 0, 0, 1) 781 ZEND_ARG_INFO(0, data) 782 ZEND_ARG_INFO(0, level) 783 ZEND_ARG_INFO(0, encoding) 784ZEND_END_ARG_INFO() 785 786ZEND_BEGIN_ARG_INFO_EX(arginfo_gzinflate, 0, 0, 1) 787 ZEND_ARG_INFO(0, data) 788 ZEND_ARG_INFO(0, max_decoded_len) 789ZEND_END_ARG_INFO() 790 791ZEND_BEGIN_ARG_INFO_EX(arginfo_gzdecode, 0, 0, 1) 792 ZEND_ARG_INFO(0, data) 793 ZEND_ARG_INFO(0, max_decoded_len) 794ZEND_END_ARG_INFO() 795 796ZEND_BEGIN_ARG_INFO_EX(arginfo_gzuncompress, 0, 0, 1) 797 ZEND_ARG_INFO(0, data) 798 ZEND_ARG_INFO(0, max_decoded_len) 799ZEND_END_ARG_INFO() 800 801ZEND_BEGIN_ARG_INFO_EX(arginfo_gzputs, 0, 0, 2) 802 ZEND_ARG_INFO(0, fp) 803 ZEND_ARG_INFO(0, str) 804 ZEND_ARG_INFO(0, length) 805ZEND_END_ARG_INFO() 806 807ZEND_BEGIN_ARG_INFO(arginfo_gzpassthru, 0) 808 ZEND_ARG_INFO(0, fp) 809ZEND_END_ARG_INFO() 810 811ZEND_BEGIN_ARG_INFO_EX(arginfo_gzseek, 0, 0, 2) 812 ZEND_ARG_INFO(0, fp) 813 ZEND_ARG_INFO(0, offset) 814 ZEND_ARG_INFO(0, whence) 815ZEND_END_ARG_INFO() 816 817ZEND_BEGIN_ARG_INFO(arginfo_gzread, 0) 818 ZEND_ARG_INFO(0, fp) 819 ZEND_ARG_INFO(0, length) 820ZEND_END_ARG_INFO() 821 822ZEND_BEGIN_ARG_INFO_EX(arginfo_gzgetss, 0, 0, 1) 823 ZEND_ARG_INFO(0, fp) 824 ZEND_ARG_INFO(0, length) 825 ZEND_ARG_INFO(0, allowable_tags) 826ZEND_END_ARG_INFO() 827 828ZEND_BEGIN_ARG_INFO_EX(arginfo_gzgets, 0, 0, 1) 829 ZEND_ARG_INFO(0, fp) 830 ZEND_ARG_INFO(0, length) 831ZEND_END_ARG_INFO() 832/* }}} */ 833 834/* {{{ php_zlib_functions[] */ 835static const zend_function_entry php_zlib_functions[] = { 836 PHP_FE(readgzfile, arginfo_readgzfile) 837 PHP_FALIAS(gzrewind, rewind, arginfo_gzpassthru) 838 PHP_FALIAS(gzclose, fclose, arginfo_gzpassthru) 839 PHP_FALIAS(gzeof, feof, arginfo_gzpassthru) 840 PHP_FALIAS(gzgetc, fgetc, arginfo_gzpassthru) 841 PHP_FALIAS(gzgets, fgets, arginfo_gzgets) 842 PHP_FALIAS(gzgetss, fgetss, arginfo_gzgetss) 843 PHP_FALIAS(gzread, fread, arginfo_gzread) 844 PHP_FE(gzopen, arginfo_gzopen) 845 PHP_FALIAS(gzpassthru, fpassthru, arginfo_gzpassthru) 846 PHP_FALIAS(gzseek, fseek, arginfo_gzseek) 847 PHP_FALIAS(gztell, ftell, arginfo_gzpassthru) 848 PHP_FALIAS(gzwrite, fwrite, arginfo_gzputs) 849 PHP_FALIAS(gzputs, fwrite, arginfo_gzputs) 850 PHP_FE(gzfile, arginfo_gzfile) 851 PHP_FE(gzcompress, arginfo_gzcompress) 852 PHP_FE(gzuncompress, arginfo_gzuncompress) 853 PHP_FE(gzdeflate, arginfo_gzdeflate) 854 PHP_FE(gzinflate, arginfo_gzinflate) 855 PHP_FE(gzencode, arginfo_gzencode) 856 PHP_FE(gzdecode, arginfo_gzdecode) 857 PHP_FE(zlib_encode, arginfo_zlib_encode) 858 PHP_FE(zlib_decode, arginfo_zlib_decode) 859 PHP_FE(zlib_get_coding_type, arginfo_zlib_get_coding_type) 860 PHP_FE(ob_gzhandler, arginfo_ob_gzhandler) 861 PHP_FE_END 862}; 863/* }}} */ 864 865/* {{{ OnUpdate_zlib_output_compression */ 866static PHP_INI_MH(OnUpdate_zlib_output_compression) 867{ 868 int status, int_value; 869 char *ini_value; 870 871 if (new_value == NULL) { 872 return FAILURE; 873 } 874 875 if (!strncasecmp(new_value, "off", sizeof("off"))) { 876 new_value = "0"; 877 new_value_length = sizeof("0"); 878 } else if (!strncasecmp(new_value, "on", sizeof("on"))) { 879 new_value = "1"; 880 new_value_length = sizeof("1"); 881 } 882 883 int_value = zend_atoi(new_value, new_value_length); 884 ini_value = zend_ini_string("output_handler", sizeof("output_handler"), 0); 885 886 if (ini_value && *ini_value && int_value) { 887 php_error_docref("ref.outcontrol" TSRMLS_CC, E_CORE_ERROR, "Cannot use both zlib.output_compression and output_handler together!!"); 888 return FAILURE; 889 } 890 if (stage == PHP_INI_STAGE_RUNTIME) { 891 status = php_output_get_status(TSRMLS_C); 892 if (status & PHP_OUTPUT_SENT) { 893 php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "Cannot change zlib.output_compression - headers already sent"); 894 return FAILURE; 895 } 896 } 897 898 status = OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); 899 900 ZLIBG(output_compression) = ZLIBG(output_compression_default); 901 if (stage == PHP_INI_STAGE_RUNTIME && int_value) { 902 if (!php_output_handler_started(ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME) TSRMLS_CC)) { 903 php_zlib_output_compression_start(TSRMLS_C); 904 } 905 } 906 907 return status; 908} 909/* }}} */ 910 911/* {{{ OnUpdate_zlib_output_handler */ 912static PHP_INI_MH(OnUpdate_zlib_output_handler) 913{ 914 if (stage == PHP_INI_STAGE_RUNTIME && (php_output_get_status(TSRMLS_C) & PHP_OUTPUT_SENT)) { 915 php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "Cannot change zlib.output_handler - headers already sent"); 916 return FAILURE; 917 } 918 919 return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); 920} 921/* }}} */ 922 923/* {{{ INI */ 924PHP_INI_BEGIN() 925 STD_PHP_INI_BOOLEAN("zlib.output_compression", "0", PHP_INI_ALL, OnUpdate_zlib_output_compression, output_compression_default, zend_zlib_globals, zlib_globals) 926 STD_PHP_INI_ENTRY("zlib.output_compression_level", "-1", PHP_INI_ALL, OnUpdateLong, output_compression_level, zend_zlib_globals, zlib_globals) 927 STD_PHP_INI_ENTRY("zlib.output_handler", "", PHP_INI_ALL, OnUpdate_zlib_output_handler, output_handler, zend_zlib_globals, zlib_globals) 928PHP_INI_END() 929 930/* }}} */ 931 932/* {{{ PHP_MINIT_FUNCTION */ 933static PHP_MINIT_FUNCTION(zlib) 934{ 935 php_register_url_stream_wrapper("compress.zlib", &php_stream_gzip_wrapper TSRMLS_CC); 936 php_stream_filter_register_factory("zlib.*", &php_zlib_filter_factory TSRMLS_CC); 937 938 php_output_handler_alias_register(ZEND_STRL("ob_gzhandler"), php_zlib_output_handler_init TSRMLS_CC); 939 php_output_handler_conflict_register(ZEND_STRL("ob_gzhandler"), php_zlib_output_conflict_check TSRMLS_CC); 940 php_output_handler_conflict_register(ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME), php_zlib_output_conflict_check TSRMLS_CC); 941 942 REGISTER_LONG_CONSTANT("FORCE_GZIP", PHP_ZLIB_ENCODING_GZIP, CONST_CS|CONST_PERSISTENT); 943 REGISTER_LONG_CONSTANT("FORCE_DEFLATE", PHP_ZLIB_ENCODING_DEFLATE, CONST_CS|CONST_PERSISTENT); 944 945 REGISTER_LONG_CONSTANT("ZLIB_ENCODING_RAW", PHP_ZLIB_ENCODING_RAW, CONST_CS|CONST_PERSISTENT); 946 REGISTER_LONG_CONSTANT("ZLIB_ENCODING_GZIP", PHP_ZLIB_ENCODING_GZIP, CONST_CS|CONST_PERSISTENT); 947 REGISTER_LONG_CONSTANT("ZLIB_ENCODING_DEFLATE", PHP_ZLIB_ENCODING_DEFLATE, CONST_CS|CONST_PERSISTENT); 948 REGISTER_INI_ENTRIES(); 949 return SUCCESS; 950} 951/* }}} */ 952 953/* {{{ PHP_MSHUTDOWN_FUNCTION */ 954static PHP_MSHUTDOWN_FUNCTION(zlib) 955{ 956 php_unregister_url_stream_wrapper("zlib" TSRMLS_CC); 957 php_stream_filter_unregister_factory("zlib.*" TSRMLS_CC); 958 959 UNREGISTER_INI_ENTRIES(); 960 961 return SUCCESS; 962} 963/* }}} */ 964 965/* {{{ PHP_RINIT_FUNCTION */ 966static PHP_RINIT_FUNCTION(zlib) 967{ 968 ZLIBG(compression_coding) = 0; 969 if (!ZLIBG(handler_registered)) { 970 ZLIBG(output_compression) = ZLIBG(output_compression_default); 971 php_zlib_output_compression_start(TSRMLS_C); 972 } 973 974 return SUCCESS; 975} 976/* }}} */ 977 978/* {{{ PHP_RSHUTDOWN_FUNCTION */ 979static PHP_RSHUTDOWN_FUNCTION(zlib) 980{ 981 php_zlib_cleanup_ob_gzhandler_mess(TSRMLS_C); 982 ZLIBG(handler_registered) = 0; 983 984 return SUCCESS; 985} 986/* }}} */ 987 988/* {{{ PHP_MINFO_FUNCTION */ 989static PHP_MINFO_FUNCTION(zlib) 990{ 991 php_info_print_table_start(); 992 php_info_print_table_header(2, "ZLib Support", "enabled"); 993 php_info_print_table_row(2, "Stream Wrapper", "compress.zlib://"); 994 php_info_print_table_row(2, "Stream Filter", "zlib.inflate, zlib.deflate"); 995 php_info_print_table_row(2, "Compiled Version", ZLIB_VERSION); 996 php_info_print_table_row(2, "Linked Version", (char *) zlibVersion()); 997 php_info_print_table_end(); 998 999 DISPLAY_INI_ENTRIES(); 1000} 1001/* }}} */ 1002 1003/* {{{ ZEND_MODULE_GLOBALS_CTOR */ 1004static ZEND_MODULE_GLOBALS_CTOR_D(zlib) 1005{ 1006 zlib_globals->ob_gzhandler = NULL; 1007 zlib_globals->handler_registered = 0; 1008} 1009/* }}} */ 1010 1011/* {{{ php_zlib_module_entry */ 1012zend_module_entry php_zlib_module_entry = { 1013 STANDARD_MODULE_HEADER, 1014 "zlib", 1015 php_zlib_functions, 1016 PHP_MINIT(zlib), 1017 PHP_MSHUTDOWN(zlib), 1018 PHP_RINIT(zlib), 1019 PHP_RSHUTDOWN(zlib), 1020 PHP_MINFO(zlib), 1021 "2.0", 1022 PHP_MODULE_GLOBALS(zlib), 1023 ZEND_MODULE_GLOBALS_CTOR_N(zlib), 1024 NULL, 1025 NULL, 1026 STANDARD_MODULE_PROPERTIES_EX 1027}; 1028/* }}} */ 1029 1030/* 1031 * Local variables: 1032 * tab-width: 4 1033 * c-basic-offset: 4 1034 * End: 1035 * vim600: sw=4 ts=4 fdm=marker 1036 * vim<600: sw=4 ts=4 1037 */ 1038