Back to index

php5  5.3.10
zlib.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
00016    |          Stefan Röhrich <sr@linux.de>                                |
00017    |          Zeev Suraski <zeev@zend.com>                                |
00018    |          Jade Nicoletti <nicoletti@nns.ch>                           |
00019    +----------------------------------------------------------------------+
00020  */
00021 
00022 /* $Id: zlib.c 321634 2012-01-01 13:15:04Z felipe $ */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include "php.h"
00029 #include "SAPI.h"
00030 #include "php_ini.h"
00031 
00032 #include <stdlib.h>
00033 #include <errno.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <fcntl.h>
00037 
00038 #ifdef PHP_WIN32
00039 # define O_RDONLY _O_RDONLY
00040 # include "win32/param.h"
00041 #else
00042 # include <sys/param.h>
00043 /* #include <sys/uio.h> */
00044 #endif
00045 
00046 #include "ext/standard/head.h"
00047 #include "safe_mode.h"
00048 #include "ext/standard/php_standard.h"
00049 #include "ext/standard/info.h"
00050 #include "php_zlib.h"
00051 #include "fopen_wrappers.h"
00052 
00053 #if HAVE_PWD_H
00054 # ifdef PHP_WIN32
00055 #  include "win32/pwd.h"
00056 # else
00057 #  include <pwd.h>
00058 # endif
00059 #endif
00060 
00061 #if defined(HAVE_UNISTD_H) && defined(PHP_WIN32)
00062 # undef HAVE_UNISTD_H
00063 #endif
00064 
00065 #ifdef COMPILE_DL_ZLIB
00066 # ifndef PUTS
00067 #  define PUTS(a) php_printf("%s",a)
00068 # endif
00069 # ifndef PUTC
00070 #  define PUTC(a) PUTS(a)
00071 # endif
00072 # ifndef PHPWRITE
00073 #  define PHPWRITE(a,n) php_write((a),(n) TSRMLS_CC)
00074 # endif
00075 #endif
00076 
00077 /* Win32 needs some more memory */
00078 #ifdef PHP_WIN32
00079 # define PHP_ZLIB_MODIFIER 100
00080 #else
00081 # define PHP_ZLIB_MODIFIER 1000
00082 #endif
00083 
00084 #define OS_CODE                    0x03 /* FIXME */
00085 #define GZIP_HEADER_LENGTH         10
00086 #define GZIP_FOOTER_LENGTH         8
00087 
00088 /* True globals, no need for thread safety */
00089 static const int gz_magic[2] = {0x1f, 0x8b};     /* gzip magic header */
00090 
00091 static int php_zlib_output_compression_start(TSRMLS_D);
00092 
00093 static PHP_MINIT_FUNCTION(zlib);
00094 static PHP_MSHUTDOWN_FUNCTION(zlib);
00095 static PHP_RINIT_FUNCTION(zlib);
00096 static PHP_MINFO_FUNCTION(zlib);
00097 static PHP_FUNCTION(gzopen);
00098 static PHP_FUNCTION(readgzfile);
00099 static PHP_FUNCTION(gzfile);
00100 static PHP_FUNCTION(gzcompress);
00101 static PHP_FUNCTION(gzuncompress);
00102 static PHP_FUNCTION(gzdeflate);
00103 static PHP_FUNCTION(gzinflate);
00104 static PHP_FUNCTION(gzencode);
00105 static PHP_FUNCTION(ob_gzhandler);
00106 static PHP_FUNCTION(zlib_get_coding_type);
00107 
00108 /* {{{ arginfo */
00109 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzfile, 0, 0, 1)
00110        ZEND_ARG_INFO(0, filename)
00111        ZEND_ARG_INFO(0, use_include_path)
00112 ZEND_END_ARG_INFO()
00113 
00114 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzopen, 0, 0, 2)
00115        ZEND_ARG_INFO(0, filename)
00116        ZEND_ARG_INFO(0, mode)
00117        ZEND_ARG_INFO(0, use_include_path)
00118 ZEND_END_ARG_INFO()
00119 
00120 ZEND_BEGIN_ARG_INFO_EX(arginfo_readgzfile, 0, 0, 1)
00121        ZEND_ARG_INFO(0, filename)
00122        ZEND_ARG_INFO(0, use_include_path)
00123 ZEND_END_ARG_INFO()
00124 
00125 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzcompress, 0, 0, 1)
00126        ZEND_ARG_INFO(0, data)
00127        ZEND_ARG_INFO(0, level)
00128 ZEND_END_ARG_INFO()
00129 
00130 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzuncompress, 0, 0, 1)
00131        ZEND_ARG_INFO(0, data)
00132        ZEND_ARG_INFO(0, length)
00133 ZEND_END_ARG_INFO()
00134 
00135 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzdeflate, 0, 0, 1)
00136        ZEND_ARG_INFO(0, data)
00137        ZEND_ARG_INFO(0, level)
00138 ZEND_END_ARG_INFO()
00139 
00140 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzinflate, 0, 0, 1)
00141        ZEND_ARG_INFO(0, data)
00142        ZEND_ARG_INFO(0, length)
00143 ZEND_END_ARG_INFO()
00144 
00145 ZEND_BEGIN_ARG_INFO(arginfo_zlib_get_coding_type, 0)
00146 ZEND_END_ARG_INFO()
00147 
00148 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzencode, 0, 0, 1)
00149        ZEND_ARG_INFO(0, data)
00150        ZEND_ARG_INFO(0, level)
00151        ZEND_ARG_INFO(0, encoding_mode)
00152 ZEND_END_ARG_INFO()
00153 
00154 ZEND_BEGIN_ARG_INFO_EX(arginfo_ob_gzhandler, 0, 0, 2)
00155        ZEND_ARG_INFO(0, str)
00156        ZEND_ARG_INFO(0, mode)
00157 ZEND_END_ARG_INFO()
00158 
00159 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzputs, 0, 0, 2)
00160        ZEND_ARG_INFO(0, fp)
00161        ZEND_ARG_INFO(0, str)
00162        ZEND_ARG_INFO(0, length)
00163 ZEND_END_ARG_INFO()
00164 
00165 ZEND_BEGIN_ARG_INFO(arginfo_gzpassthru, 0)
00166        ZEND_ARG_INFO(0, fp)
00167 ZEND_END_ARG_INFO()
00168 
00169 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzseek, 0, 0, 2)
00170        ZEND_ARG_INFO(0, fp)
00171        ZEND_ARG_INFO(0, offset)
00172        ZEND_ARG_INFO(0, whence)
00173 ZEND_END_ARG_INFO()
00174 
00175 ZEND_BEGIN_ARG_INFO(arginfo_gzread, 0)
00176        ZEND_ARG_INFO(0, fp)
00177        ZEND_ARG_INFO(0, length)
00178 ZEND_END_ARG_INFO()
00179 
00180 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzgetss, 0, 0, 1)
00181        ZEND_ARG_INFO(0, fp)
00182        ZEND_ARG_INFO(0, length)
00183        ZEND_ARG_INFO(0, allowable_tags)
00184 ZEND_END_ARG_INFO()
00185 
00186 ZEND_BEGIN_ARG_INFO_EX(arginfo_gzgets, 0, 0, 1)
00187        ZEND_ARG_INFO(0, fp)
00188        ZEND_ARG_INFO(0, length)
00189 ZEND_END_ARG_INFO()
00190 /* }}} */
00191 
00192 /* {{{ php_zlib_functions[]
00193  */
00194 static const zend_function_entry php_zlib_functions[] = {
00195        PHP_FE(readgzfile,                                      arginfo_readgzfile)
00196        PHP_FALIAS(gzrewind, rewind,                     arginfo_gzpassthru)
00197        PHP_FALIAS(gzclose,         fclose,                     arginfo_gzpassthru)
00198        PHP_FALIAS(gzeof,           feof,                arginfo_gzpassthru)
00199        PHP_FALIAS(gzgetc,          fgetc,               arginfo_gzpassthru)
00200        PHP_FALIAS(gzgets,          fgets,               arginfo_gzgets)
00201        PHP_FALIAS(gzgetss,         fgetss,                     arginfo_gzgetss)
00202        PHP_FALIAS(gzread,          fread,               arginfo_gzread)
00203        PHP_FE(gzopen,                                                 arginfo_gzopen)
00204        PHP_FALIAS(gzpassthru,      fpassthru,           arginfo_gzpassthru)
00205        PHP_FALIAS(gzseek,          fseek,               arginfo_gzseek)
00206        PHP_FALIAS(gztell,          ftell,               arginfo_gzpassthru)
00207        PHP_FALIAS(gzwrite,         fwrite,                     arginfo_gzputs)
00208        PHP_FALIAS(gzputs,          fwrite,                     arginfo_gzputs)
00209        PHP_FE(gzfile,                                                 arginfo_gzfile)
00210        PHP_FE(gzcompress,                                      arginfo_gzcompress)
00211        PHP_FE(gzuncompress,                             arginfo_gzuncompress)
00212        PHP_FE(gzdeflate,                                       arginfo_gzdeflate)
00213        PHP_FE(gzinflate,                                       arginfo_gzinflate)
00214        PHP_FE(gzencode,                                        arginfo_gzencode)
00215        PHP_FE(ob_gzhandler,                             arginfo_ob_gzhandler)
00216        PHP_FE(zlib_get_coding_type,                     arginfo_zlib_get_coding_type)
00217        PHP_FE_END
00218 };
00219 /* }}} */
00220 
00221 ZEND_DECLARE_MODULE_GLOBALS(zlib)
00222 
00223 /* {{{ php_zlib_module_entry
00224  */
00225 zend_module_entry php_zlib_module_entry = {
00226        STANDARD_MODULE_HEADER,
00227        "zlib",
00228        php_zlib_functions,
00229        PHP_MINIT(zlib),
00230        PHP_MSHUTDOWN(zlib),
00231        PHP_RINIT(zlib),
00232        NULL,
00233        PHP_MINFO(zlib),
00234        "1.1",
00235        PHP_MODULE_GLOBALS(zlib),
00236        NULL,
00237        NULL,
00238        NULL,
00239        STANDARD_MODULE_PROPERTIES_EX
00240 };
00241 /* }}} */
00242 
00243 #ifdef COMPILE_DL_ZLIB
00244 ZEND_GET_MODULE(php_zlib)
00245 #endif
00246 
00247 /* {{{ Memory management wrappers */
00248 
00249 static voidpf php_zlib_alloc(voidpf opaque, uInt items, uInt size)
00250 {
00251        return (voidpf)safe_emalloc(items, size, 0);
00252 }
00253 
00254 static void php_zlib_free(voidpf opaque, voidpf address)
00255 {
00256        efree((void*)address);
00257 }
00258 /* }}} */
00259 
00260 /* {{{ OnUpdate_zlib_output_compression */
00261 static PHP_INI_MH(OnUpdate_zlib_output_compression)
00262 {
00263        int status, int_value;
00264        char *ini_value;
00265 
00266        if (new_value == NULL) {
00267               return FAILURE;
00268        }
00269 
00270        if (!strncasecmp(new_value, "off", sizeof("off"))) {
00271               new_value = "0";
00272               new_value_length = sizeof("0");
00273        } else if (!strncasecmp(new_value, "on", sizeof("on"))) {
00274               new_value = "1";
00275               new_value_length = sizeof("1");
00276        }
00277 
00278        int_value = zend_atoi(new_value, new_value_length);
00279        ini_value = zend_ini_string("output_handler", sizeof("output_handler"), 0);
00280 
00281        if (ini_value && *ini_value && int_value) {
00282               php_error_docref("ref.outcontrol" TSRMLS_CC, E_CORE_ERROR, "Cannot use both zlib.output_compression and output_handler together!!");
00283               return FAILURE;
00284        }
00285 
00286        if (stage == PHP_INI_STAGE_RUNTIME && SG(headers_sent) && !SG(request_info).no_headers) {
00287               php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "Cannot change zlib.output_compression - headers already sent");
00288               return FAILURE;
00289        }
00290 
00291        status = OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
00292 
00293        if (stage == PHP_INI_STAGE_RUNTIME && int_value) {
00294               status = php_zlib_output_compression_start(TSRMLS_C);
00295        }
00296 
00297        return status;
00298 }
00299 /* }}} */
00300 
00301 /* {{{ OnUpdate_zlib_output_compression_level */
00302 static PHP_INI_MH(OnUpdate_zlib_output_compression_level)
00303 {
00304        OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
00305 
00306        return SUCCESS;
00307 }
00308 /* }}} */
00309 
00310 /* {{{ OnUpdate_zlib_output_handler */
00311 static PHP_INI_MH(OnUpdate_zlib_output_handler)
00312 {
00313        if (stage == PHP_INI_STAGE_RUNTIME && SG(headers_sent) && !SG(request_info).no_headers) {
00314               php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "Cannot change zlib.output_handler - headers already sent");
00315               return FAILURE;
00316        }
00317 
00318        OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
00319 
00320        return SUCCESS;
00321 }
00322 /* }}} */
00323 
00324 
00325 PHP_INI_BEGIN()
00326        STD_PHP_INI_BOOLEAN("zlib.output_compression",      "0", PHP_INI_ALL, OnUpdate_zlib_output_compression,       output_compression,       zend_zlib_globals, zlib_globals)
00327        STD_PHP_INI_ENTRY("zlib.output_compression_level", "-1", PHP_INI_ALL, OnUpdate_zlib_output_compression_level, output_compression_level, zend_zlib_globals, zlib_globals)
00328        STD_PHP_INI_ENTRY("zlib.output_handler",             "", PHP_INI_ALL, OnUpdate_zlib_output_handler,           output_handler,           zend_zlib_globals, zlib_globals)
00329 PHP_INI_END()
00330 
00331 /* {{{ PHP_MINIT_FUNCTION
00332  */
00333 static PHP_MINIT_FUNCTION(zlib)
00334 {
00335        php_register_url_stream_wrapper("compress.zlib", &php_stream_gzip_wrapper TSRMLS_CC);
00336        php_stream_filter_register_factory("zlib.*", &php_zlib_filter_factory TSRMLS_CC);
00337 
00338        REGISTER_LONG_CONSTANT("FORCE_GZIP", CODING_GZIP, CONST_CS | CONST_PERSISTENT);
00339        REGISTER_LONG_CONSTANT("FORCE_DEFLATE", CODING_DEFLATE, CONST_CS | CONST_PERSISTENT);
00340 
00341        REGISTER_INI_ENTRIES();
00342 
00343        return SUCCESS;
00344 }
00345 /* }}} */
00346 
00347 /* {{{ PHP_RINIT_FUNCTION
00348  */
00349 static PHP_RINIT_FUNCTION(zlib)
00350 {
00351        ZLIBG(ob_gzhandler_status) = 0;
00352        ZLIBG(compression_coding) = 0;
00353 
00354        php_zlib_output_compression_start(TSRMLS_C);
00355 
00356        return SUCCESS;
00357 }
00358 /* }}} */
00359 
00360 /* {{{ PHP_MSHUTDOWN_FUNCTION
00361  */
00362 static PHP_MSHUTDOWN_FUNCTION(zlib)
00363 {
00364        php_unregister_url_stream_wrapper("zlib" TSRMLS_CC);
00365        php_stream_filter_unregister_factory("zlib.*" TSRMLS_CC);
00366 
00367        UNREGISTER_INI_ENTRIES();
00368 
00369        return SUCCESS;
00370 }
00371 /* }}} */
00372 
00373 /* {{{ PHP_MINFO_FUNCTION
00374  */
00375 static PHP_MINFO_FUNCTION(zlib)
00376 {
00377        php_info_print_table_start();
00378        php_info_print_table_row(2, "ZLib Support", "enabled");
00379        php_info_print_table_row(2, "Stream Wrapper support", "compress.zlib://");
00380        php_info_print_table_row(2, "Stream Filter support", "zlib.inflate, zlib.deflate");
00381        php_info_print_table_row(2, "Compiled Version", ZLIB_VERSION);
00382        php_info_print_table_row(2, "Linked Version", (char *) zlibVersion());
00383        php_info_print_table_end();
00384 
00385        DISPLAY_INI_ENTRIES();
00386 }
00387 /* }}} */
00388 
00389 /* {{{ proto array gzfile(string filename [, int use_include_path])
00390    Read und uncompress entire .gz-file into an array */
00391 static PHP_FUNCTION(gzfile)
00392 {
00393        char *filename;
00394        int filename_len;
00395        long flags = 0;
00396        char *slashed, buf[8192];
00397        register int i = 0;
00398        int use_include_path = 0;
00399        php_stream *stream;
00400 
00401        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &filename, &filename_len, &flags) == FAILURE) {
00402               return;
00403        }
00404 
00405        use_include_path = flags ? USE_PATH : 0;
00406 
00407        /* using a stream here is a bit more efficient (resource wise) than php_gzopen_wrapper */
00408        stream = php_stream_gzopen(NULL, filename, "rb", use_include_path | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, NULL STREAMS_CC TSRMLS_CC);
00409        if (stream == NULL) {
00410               /* Error reporting is already done by stream code */
00411               RETURN_FALSE;
00412        }
00413 
00414        /* Initialize return array */
00415        array_init(return_value);
00416 
00417        /* Now loop through the file and do the magic quotes thing if needed */
00418        memset(buf,0,sizeof(buf));
00419 
00420        while (php_stream_gets(stream, buf, sizeof(buf) - 1) != NULL) {
00421               if (PG(magic_quotes_runtime)) {
00422                      int len;
00423 
00424                      slashed = php_addslashes(buf, 0, &len, 0 TSRMLS_CC); /* 0 = don't free source string */
00425                      add_index_stringl(return_value, i++, slashed, len, 0);
00426               } else {
00427                      add_index_string(return_value, i++, buf, 1);
00428               }
00429        }
00430        php_stream_close(stream);
00431 }
00432 /* }}} */
00433 
00434 /* {{{ proto resource gzopen(string filename, string mode [, int use_include_path])
00435    Open a .gz-file and return a .gz-file pointer */
00436 static PHP_FUNCTION(gzopen)
00437 {
00438        char *filename, *mode;
00439        int filename_len, mode_len;
00440        long flags = 0;
00441        php_stream *stream;
00442        int use_include_path = 0;
00443 
00444        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &filename, &filename_len, &mode, &mode_len, &flags) == FAILURE) {
00445               return;
00446        }
00447 
00448        use_include_path = flags ? USE_PATH : 0;
00449 
00450        stream = php_stream_gzopen(NULL, filename, mode, use_include_path | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, NULL STREAMS_CC TSRMLS_CC);
00451 
00452        if (!stream) {
00453               RETURN_FALSE;
00454        }
00455        php_stream_to_zval(stream, return_value);
00456 }
00457 /* }}} */
00458 
00459 /*
00460  * Read a file and write the ouput to stdout
00461  */
00462 /* {{{ proto int readgzfile(string filename [, int use_include_path])
00463    Output a .gz-file */
00464 static PHP_FUNCTION(readgzfile)
00465 {
00466        char *filename;
00467        int filename_len;
00468        long flags = 0;
00469        php_stream *stream;
00470        int size;
00471        int use_include_path = 0;
00472 
00473        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &filename, &filename_len, &flags) == FAILURE) {
00474               return;
00475        }
00476 
00477        use_include_path = flags ? USE_PATH : 0;
00478 
00479        stream = php_stream_gzopen(NULL, filename, "rb", use_include_path | ENFORCE_SAFE_MODE, NULL, NULL STREAMS_CC TSRMLS_CC);
00480        if (!stream) {
00481               RETURN_FALSE;
00482        }
00483        size = php_stream_passthru(stream);
00484        php_stream_close(stream);
00485        RETURN_LONG(size);
00486 }
00487 /* }}} */
00488 
00489 /* {{{ proto string gzcompress(string data [, int level])
00490    Gzip-compress a string */
00491 static PHP_FUNCTION(gzcompress)
00492 {
00493        int data_len, status;
00494        long level = Z_DEFAULT_COMPRESSION;
00495        unsigned long l2;
00496        char *data, *s2;
00497 
00498        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &level) == FAILURE) {
00499               return;
00500        }
00501 
00502        if ((level < -1) || (level > 9)) {
00503               php_error_docref(NULL TSRMLS_CC, E_WARNING, "compression level (%ld) must be within -1..9", level);
00504               RETURN_FALSE;
00505        }
00506 
00507        l2 = data_len + (data_len / PHP_ZLIB_MODIFIER) + 15 + 1; /* room for \0 */
00508        s2 = (char *) emalloc(l2);
00509        if (!s2) {
00510               RETURN_FALSE;
00511        }
00512 
00513        if (level >= 0) {
00514               status = compress2(s2, &l2, data, data_len, level);
00515        } else {
00516               status = compress(s2, &l2, data, data_len);
00517        }
00518 
00519        if (status == Z_OK) {
00520               s2 = erealloc(s2, l2 + 1);
00521               s2[l2] = '\0';
00522               RETURN_STRINGL(s2, l2, 0);
00523        } else {
00524               efree(s2);
00525               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
00526               RETURN_FALSE;
00527        }
00528 }
00529 /* }}} */
00530 
00531 /* {{{ proto string gzuncompress(string data [, int length])
00532    Unzip a gzip-compressed string */
00533 static PHP_FUNCTION(gzuncompress)
00534 {
00535        int data_len, status;
00536        unsigned int factor=1, maxfactor=16;
00537        long limit = 0;
00538        unsigned long plength=0, length;
00539        char *data, *s1=NULL, *s2=NULL;
00540 
00541        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &limit) == FAILURE) {
00542               return;
00543        }
00544 
00545        if (limit < 0) {
00546               php_error_docref(NULL TSRMLS_CC, E_WARNING, "length (%ld) must be greater or equal zero", limit);
00547               RETURN_FALSE;
00548        }
00549        plength = limit;
00550 
00551        /*
00552         zlib::uncompress() wants to know the output data length
00553         if none was given as a parameter
00554         we try from input length * 2 up to input length * 2^15
00555         doubling it whenever it wasn't big enough
00556         that should be eneugh for all real life cases
00557        */
00558        do {
00559               length = plength ? plength : (unsigned long)data_len * (1 << factor++);
00560               s2 = (char *) erealloc(s1, length);
00561               status = uncompress(s2, &length, data, data_len);
00562               s1 = s2;
00563        } while ((status == Z_BUF_ERROR) && (!plength) && (factor < maxfactor));
00564 
00565        if (status == Z_OK) {
00566               s2 = erealloc(s2, length + 1); /* space for \0 */
00567               s2[ length ] = '\0';
00568               RETURN_STRINGL(s2, length, 0);
00569        } else {
00570               efree(s2);
00571               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
00572               RETURN_FALSE;
00573        }
00574 }
00575 /* }}} */
00576 
00577 /* {{{ proto string gzdeflate(string data [, int level])
00578    Gzip-compress a string */
00579 static PHP_FUNCTION(gzdeflate)
00580 {
00581        int data_len,status;
00582        long level = Z_DEFAULT_COMPRESSION;
00583        z_stream stream;
00584        char *data, *s2;
00585 
00586        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &level) == FAILURE) {
00587               return;
00588        }
00589 
00590        if ((level < -1) || (level > 9)) {
00591               php_error_docref(NULL TSRMLS_CC, E_WARNING, "compression level (%ld) must be within -1..9", level);
00592               RETURN_FALSE;
00593        }
00594 
00595        stream.data_type = Z_ASCII;
00596        stream.zalloc = php_zlib_alloc;
00597        stream.zfree  = php_zlib_free;
00598        stream.opaque = (voidpf) Z_NULL;
00599 
00600        stream.next_in = (Bytef *) data;
00601        stream.avail_in = data_len;
00602 
00603        stream.avail_out = stream.avail_in + (stream.avail_in / PHP_ZLIB_MODIFIER) + 15 + 1; /* room for \0 */
00604 
00605        s2 = (char *) emalloc(stream.avail_out);
00606        if (!s2) {
00607               RETURN_FALSE;
00608        }
00609 
00610        stream.next_out = s2;
00611 
00612        /* init with -MAX_WBITS disables the zlib internal headers */
00613        status = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, 0);
00614        if (status == Z_OK) {
00615               status = deflate(&stream, Z_FINISH);
00616               if (status != Z_STREAM_END) {
00617                      deflateEnd(&stream);
00618                      if (status == Z_OK) {
00619                             status = Z_BUF_ERROR;
00620                      }
00621               } else {
00622                      status = deflateEnd(&stream);
00623               }
00624        }
00625 
00626        if (status == Z_OK) {
00627               s2 = erealloc(s2,stream.total_out + 1); /* resize to buffer to the "right" size */
00628               s2[ stream.total_out ] = '\0';
00629               RETURN_STRINGL(s2, stream.total_out, 0);
00630        } else {
00631               efree(s2);
00632               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
00633               RETURN_FALSE;
00634        }
00635 }
00636 /* }}} */
00637 
00638 /* {{{ proto string gzinflate(string data [, int length])
00639    Unzip a gzip-compressed string */
00640 static PHP_FUNCTION(gzinflate)
00641 {
00642        int data_len, status;
00643        unsigned int factor=1, maxfactor=16;
00644        long limit = 0;
00645        unsigned long plength=0, length;
00646        char *data, *s1=NULL, *s2=NULL;
00647        z_stream stream;
00648 
00649        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &limit) == FAILURE) {
00650               return;
00651        }
00652 
00653        if (!data_len) {
00654               RETURN_FALSE;
00655        }
00656 
00657        if (limit < 0) {
00658               php_error_docref(NULL TSRMLS_CC, E_WARNING, "length (%ld) must be greater or equal zero", limit);
00659               RETURN_FALSE;
00660        }
00661        plength = limit;
00662 
00663        stream.zalloc = php_zlib_alloc;
00664        stream.zfree = php_zlib_free;
00665        stream.opaque = Z_NULL;
00666        stream.avail_in = data_len + 1; /* there is room for \0 */
00667        stream.next_in = (Bytef *) data;
00668        stream.total_out = 0;
00669 
00670        /* init with -MAX_WBITS disables the zlib internal headers */
00671        status = inflateInit2(&stream, -MAX_WBITS);
00672        if (status != Z_OK) {
00673               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
00674               RETURN_FALSE;
00675        }
00676 
00677        /*
00678          stream.avail_out wants to know the output data length
00679          if none was given as a parameter
00680          we try from input length * 2 up to input length * 2^15
00681          doubling it whenever it wasn't big enough
00682          that should be enaugh for all real life cases
00683        */
00684        do {
00685               length = plength ? plength : (unsigned long)data_len * (1 << factor++);
00686               s2 = (char *) erealloc(s1, length);
00687 
00688               if (!s2) {
00689                      if (s1) {
00690                             efree(s1);
00691                      }
00692                      inflateEnd(&stream);
00693                      RETURN_FALSE;
00694               }
00695               s1 = s2;
00696 
00697               stream.next_out = (Bytef *) &s2[stream.total_out];
00698               stream.avail_out = length - stream.total_out;
00699               status = inflate(&stream, Z_NO_FLUSH);
00700 
00701        } while ((Z_BUF_ERROR == status || (Z_OK == status && stream.avail_in)) && !plength && factor < maxfactor);
00702 
00703        inflateEnd(&stream);
00704 
00705        if ((plength && Z_OK == status) || factor >= maxfactor) {
00706               status = Z_MEM_ERROR;
00707        }
00708 
00709        if (Z_STREAM_END == status || Z_OK == status) {
00710               s2 = erealloc(s2, stream.total_out + 1); /* room for \0 */
00711               s2[ stream.total_out ] = '\0';
00712               RETURN_STRINGL(s2, stream.total_out, 0);
00713        } else {
00714               efree(s2);
00715               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
00716               RETURN_FALSE;
00717        }
00718 }
00719 /* }}} */
00720 
00721 /* {{{ proto string zlib_get_coding_type(void)
00722    Returns the coding type used for output compression */
00723 static PHP_FUNCTION(zlib_get_coding_type)
00724 {
00725        switch (ZLIBG(compression_coding)) {
00726               case CODING_GZIP:
00727                      RETURN_STRINGL("gzip", sizeof("gzip") - 1, 1);
00728 
00729               case CODING_DEFLATE:
00730                      RETURN_STRINGL("deflate", sizeof("deflate") - 1, 1);
00731        }
00732 
00733        RETURN_FALSE;
00734 }
00735 
00736 /* {{{ php_do_deflate
00737  */
00738 static int php_do_deflate(uint str_length, Bytef **p_buffer, uint *p_buffer_len, zend_bool do_start, zend_bool do_end TSRMLS_DC)
00739 {
00740        Bytef *buffer;
00741        uInt prev_outlen, outlen;
00742        int err;
00743        int start_offset = ((do_start && ZLIBG(compression_coding) == CODING_GZIP) ? 10 : 0);
00744        int end_offset = (do_end ? 8 : 0);
00745 
00746        outlen = (uint) (str_length + (str_length / PHP_ZLIB_MODIFIER) + 12 + 1); /* leave some room for a trailing \0 */
00747        if ((outlen + start_offset + end_offset) > *p_buffer_len) {
00748               buffer = (Bytef *) emalloc(outlen + start_offset + end_offset);
00749        } else {
00750               buffer = *p_buffer;
00751        }
00752 
00753        ZLIBG(stream).next_out = buffer + start_offset;
00754        ZLIBG(stream).avail_out = outlen;
00755 
00756        err = deflate(&ZLIBG(stream), Z_SYNC_FLUSH);
00757        while (err == Z_OK && !ZLIBG(stream).avail_out) {
00758               prev_outlen = outlen;
00759               outlen *= 3;
00760               if ((outlen + start_offset + end_offset) > *p_buffer_len) {
00761                      buffer = erealloc(buffer, outlen + start_offset + end_offset);
00762               }
00763 
00764               ZLIBG(stream).next_out = buffer + start_offset + prev_outlen;
00765               ZLIBG(stream).avail_out = prev_outlen * 2;
00766 
00767               err = deflate(&ZLIBG(stream), Z_SYNC_FLUSH);
00768        }
00769 
00770        if (do_end) {
00771               err = deflate(&ZLIBG(stream), Z_FINISH);
00772               buffer[outlen + start_offset - ZLIBG(stream).avail_out] = '\0';
00773        }
00774 
00775        *p_buffer = buffer;
00776        *p_buffer_len = outlen - ZLIBG(stream).avail_out;
00777 
00778        return err;
00779 }
00780 /* }}} */
00781 
00782 /* {{{ php_deflate_string
00783  */
00784 static int php_deflate_string(const char *str, uint str_length, char **newstr, uint *new_length, zend_bool do_start, zend_bool do_end TSRMLS_DC)
00785 {
00786        int err;
00787 
00788        if (do_start) {
00789               ZLIBG(stream).zalloc = php_zlib_alloc;
00790               ZLIBG(stream).zfree = php_zlib_free;
00791               ZLIBG(stream).opaque = Z_NULL;
00792 
00793               switch (ZLIBG(compression_coding)) {
00794                      case CODING_GZIP:
00795                             /* windowBits is passed < 0 to suppress zlib header & trailer */
00796                             if (deflateInit2(&ZLIBG(stream), ZLIBG(output_compression_level), Z_DEFLATED,       -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) {
00797                                    /* TODO: print out error */
00798                                    return FAILURE;
00799                             }
00800 
00801                             ZLIBG(crc) = crc32(0L, Z_NULL, 0);
00802                             break;
00803 
00804                      case CODING_DEFLATE:
00805                             if (deflateInit(&ZLIBG(stream), ZLIBG(output_compression_level)) != Z_OK) {
00806                                    /* TODO: print out error */
00807                                    return FAILURE;
00808                             }
00809                             break;
00810               }
00811        }
00812 
00813        ZLIBG(stream).next_in = (Bytef *) str;
00814        ZLIBG(stream).avail_in = (uInt) str_length;
00815 
00816        if (ZLIBG(compression_coding) == CODING_GZIP) {
00817               ZLIBG(crc) = crc32(ZLIBG(crc), (const Bytef *) str, str_length);
00818        }
00819 
00820        err = php_do_deflate(str_length, (Bytef **) newstr, new_length, do_start, do_end TSRMLS_CC);
00821        /* TODO: error handling (err may be Z_STREAM_ERROR, Z_BUF_ERROR, ?) */
00822 
00823        if (do_start && ZLIBG(compression_coding) == CODING_GZIP) {
00824               /* Write a very simple .gz header: */
00825               (*newstr)[0] = gz_magic[0];
00826               (*newstr)[1] = gz_magic[1];
00827               (*newstr)[2] = Z_DEFLATED;
00828               (*newstr)[3] = (*newstr)[4] = (*newstr)[5] = (*newstr)[6] = (*newstr)[7] = (*newstr)[8] = 0;
00829               (*newstr)[9] = OS_CODE;
00830               *new_length += 10;
00831        }
00832        if (do_end) {
00833               if (ZLIBG(compression_coding) == CODING_GZIP) {
00834                      char *trailer = (*newstr) + (*new_length);
00835 
00836                      /* write crc & stream.total_in in LSB order */
00837                      trailer[0] = (char) ZLIBG(crc) & 0xFF;
00838                      trailer[1] = (char) (ZLIBG(crc) >> 8) & 0xFF;
00839                      trailer[2] = (char) (ZLIBG(crc) >> 16) & 0xFF;
00840                      trailer[3] = (char) (ZLIBG(crc) >> 24) & 0xFF;
00841                      trailer[4] = (char) ZLIBG(stream).total_in & 0xFF;
00842                      trailer[5] = (char) (ZLIBG(stream).total_in >> 8) & 0xFF;
00843                      trailer[6] = (char) (ZLIBG(stream).total_in >> 16) & 0xFF;
00844                      trailer[7] = (char) (ZLIBG(stream).total_in >> 24) & 0xFF;
00845                      trailer[8] = '\0';
00846                      *new_length += 8;
00847               }
00848               deflateEnd(&ZLIBG(stream));
00849        }
00850 
00851        return SUCCESS;
00852 }
00853 /* }}} */
00854 
00855 /* {{{ proto string gzencode(string data [, int level [, int encoding_mode]])
00856    GZ encode a string */
00857 static PHP_FUNCTION(gzencode)
00858 {
00859        char *data, *s2;
00860        int data_len;
00861        long level = Z_DEFAULT_COMPRESSION, coding = CODING_GZIP;
00862        int status;
00863        z_stream stream;
00864 
00865        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &data, &data_len, &level, &coding) == FAILURE) {
00866               return;
00867        }
00868 
00869        if ((level < -1) || (level > 9)) {
00870               php_error_docref(NULL TSRMLS_CC, E_WARNING, "compression level(%ld) must be within -1..9", level);
00871               RETURN_FALSE;
00872        }
00873 
00874        if ((coding != CODING_GZIP) && (coding != CODING_DEFLATE)) {
00875               php_error_docref(NULL TSRMLS_CC, E_WARNING, "encoding mode must be FORCE_GZIP or FORCE_DEFLATE");
00876               RETURN_FALSE;
00877        }
00878 
00879        stream.zalloc = php_zlib_alloc;
00880        stream.zfree = php_zlib_free;
00881        stream.opaque = Z_NULL;
00882 
00883        stream.next_in = (Bytef *) data;
00884        stream.avail_in = data_len;
00885 
00886        stream.avail_out = stream.avail_in + (stream.avail_in / PHP_ZLIB_MODIFIER) + 15 + 1; /* room for \0 */
00887        s2 = (char *) emalloc(stream.avail_out + GZIP_HEADER_LENGTH + (coding == CODING_GZIP ? GZIP_FOOTER_LENGTH : 0));
00888 
00889        /* add gzip file header */
00890        s2[0] = gz_magic[0];
00891        s2[1] = gz_magic[1];
00892        s2[2] = Z_DEFLATED;
00893        s2[3] = s2[4] = s2[5] = s2[6] = s2[7] = s2[8] = 0; /* time set to 0 */
00894        s2[9] = OS_CODE;
00895 
00896        stream.next_out = &(s2[GZIP_HEADER_LENGTH]);
00897 
00898        switch (coding) {
00899               case CODING_GZIP:
00900                      /* windowBits is passed < 0 to suppress zlib header & trailer */
00901                      if ((status = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) != Z_OK) {
00902                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
00903                             RETURN_FALSE;
00904                      }
00905 
00906                      break;
00907               case CODING_DEFLATE:
00908                      if ((status = deflateInit(&stream, level)) != Z_OK) {
00909                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
00910                             RETURN_FALSE;
00911                      }
00912                      break;
00913        }
00914 
00915        status = deflate(&stream, Z_FINISH);
00916        if (status != Z_STREAM_END) {
00917               deflateEnd(&stream);
00918               if (status == Z_OK) {
00919                      status = Z_BUF_ERROR;
00920               }
00921        } else {
00922               status = deflateEnd(&stream);
00923        }
00924 
00925        if (status == Z_OK) {
00926               /* resize to buffer to the "right" size */
00927               s2 = erealloc(s2, stream.total_out + GZIP_HEADER_LENGTH + (coding == CODING_GZIP ? GZIP_FOOTER_LENGTH : 0) + 1);
00928 
00929               if (coding == CODING_GZIP) {
00930                      char *trailer = s2 + (stream.total_out + GZIP_HEADER_LENGTH);
00931                      uLong crc = crc32(0L, Z_NULL, 0);
00932 
00933                      crc = crc32(crc, (const Bytef *) data, data_len);
00934 
00935                      /* write crc & stream.total_in in LSB order */
00936                      trailer[0] = (char) crc & 0xFF;
00937                      trailer[1] = (char) (crc >> 8) & 0xFF;
00938                      trailer[2] = (char) (crc >> 16) & 0xFF;
00939                      trailer[3] = (char) (crc >> 24) & 0xFF;
00940                      trailer[4] = (char) stream.total_in & 0xFF;
00941                      trailer[5] = (char) (stream.total_in >> 8) & 0xFF;
00942                      trailer[6] = (char) (stream.total_in >> 16) & 0xFF;
00943                      trailer[7] = (char) (stream.total_in >> 24) & 0xFF;
00944                      trailer[8] = '\0';
00945               } else {
00946                      s2[stream.total_out + GZIP_HEADER_LENGTH + (coding == CODING_GZIP ? GZIP_FOOTER_LENGTH : 0)] = '\0';
00947               }
00948               RETURN_STRINGL(s2, stream.total_out + GZIP_HEADER_LENGTH + (coding == CODING_GZIP ? GZIP_FOOTER_LENGTH : 0), 0);
00949        } else {
00950               efree(s2);
00951               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
00952               RETURN_FALSE;
00953        }
00954 }
00955 /* }}} */
00956 
00957 /* {{{ php_ob_gzhandler_check
00958  */
00959 int php_ob_gzhandler_check(TSRMLS_D)
00960 {
00961        /* check for wrong usages */
00962        if (OG(ob_nesting_level > 0)) {
00963               if (php_ob_handler_used("ob_gzhandler" TSRMLS_CC)) {
00964                      php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler 'ob_gzhandler' cannot be used twice");
00965                      return FAILURE;
00966               }
00967               if (php_ob_handler_used("mb_output_handler" TSRMLS_CC)) {
00968                      php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler 'ob_gzhandler' cannot be used after 'mb_output_handler'");
00969                      return FAILURE;
00970               }
00971               if (php_ob_handler_used("URL-Rewriter" TSRMLS_CC)) {
00972                      php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler 'ob_gzhandler' cannot be used after 'URL-Rewriter'");
00973                      return FAILURE;
00974               }
00975               if (php_ob_init_conflict("ob_gzhandler", "zlib output compression" TSRMLS_CC)) {
00976                      return FAILURE;
00977               }
00978        }
00979 
00980        return SUCCESS;
00981 }
00982 
00983 /* }}} */
00984 
00985 /* {{{ proto string ob_gzhandler(string str, int mode)
00986    Encode str based on accept-encoding setting - designed to be called from ob_start() */
00987 static PHP_FUNCTION(ob_gzhandler)
00988 {
00989        char *string;
00990        int string_len;
00991        long mode;
00992        zval **a_encoding;
00993        zend_bool return_original = 0;
00994        zend_bool do_start, do_end;
00995 
00996        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &string, &string_len, &mode) == FAILURE) {
00997               return;
00998        }
00999 
01000        if (ZLIBG(ob_gzhandler_status) == -1) {
01001               RETURN_FALSE;
01002        }
01003 
01004        zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
01005 
01006        if (!PG(http_globals)[TRACK_VARS_SERVER]
01007               || zend_hash_find(PG(http_globals)[TRACK_VARS_SERVER]->value.ht, "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING"), (void **) &a_encoding) == FAILURE
01008        ) {
01009               ZLIBG(ob_gzhandler_status) = -1;
01010               RETURN_FALSE;
01011        }
01012 
01013        convert_to_string_ex(a_encoding);
01014        if (php_memnstr(Z_STRVAL_PP(a_encoding), "gzip", 4, Z_STRVAL_PP(a_encoding) + Z_STRLEN_PP(a_encoding))) {
01015               ZLIBG(compression_coding) = CODING_GZIP;
01016        } else if (php_memnstr(Z_STRVAL_PP(a_encoding), "deflate", 7, Z_STRVAL_PP(a_encoding) + Z_STRLEN_PP(a_encoding))) {
01017               ZLIBG(compression_coding) = CODING_DEFLATE;
01018        } else {
01019               ZLIBG(ob_gzhandler_status) = -1;
01020               RETURN_FALSE;
01021        }
01022 
01023        do_start = ((mode & PHP_OUTPUT_HANDLER_START) ? 1 : 0);
01024        do_end = ((mode & PHP_OUTPUT_HANDLER_END) ? 1 : 0);
01025        Z_STRVAL_P(return_value) = NULL;
01026        Z_STRLEN_P(return_value) = 0;
01027 
01028        if (php_deflate_string(string, string_len, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), do_start, do_end TSRMLS_CC) == SUCCESS) {
01029               Z_TYPE_P(return_value) = IS_STRING;
01030               if (do_start) {
01031                      switch (ZLIBG(compression_coding)) {
01032                             case CODING_GZIP:
01033                                    if (sapi_add_header("Content-Encoding: gzip", sizeof("Content-Encoding: gzip") - 1, 1) == FAILURE) {
01034                                           return_original = 1;
01035                                    }
01036                                    if (sapi_add_header_ex("Vary: Accept-Encoding", sizeof("Vary: Accept-Encoding") - 1, 1, 0 TSRMLS_CC)==FAILURE) {
01037                                           return_original = 1;
01038                                    }
01039                                    break;
01040                             case CODING_DEFLATE:
01041                                    if (sapi_add_header("Content-Encoding: deflate", sizeof("Content-Encoding: deflate") - 1, 1) == FAILURE) {
01042                                           return_original = 1;
01043                                    }
01044                                    if (sapi_add_header_ex("Vary: Accept-Encoding", sizeof("Vary: Accept-Encoding") - 1, 1, 0 TSRMLS_CC)==FAILURE) {
01045                                           return_original = 1;
01046                                    }
01047                                    break;
01048                             default:
01049                                    return_original = 1;
01050                                    break;
01051                      }
01052               }
01053 
01054               if (return_original) {
01055                      zval_dtor(return_value);
01056               }
01057 
01058        } else {
01059               return_original = 1;
01060        }
01061 
01062        if (return_original) {
01063               /* return the original string */
01064               RETURN_STRINGL(string, string_len, 1);
01065        }
01066 }
01067 /* }}} */
01068 
01069 /* {{{ php_gzip_output_handler
01070  */
01071 static void php_gzip_output_handler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
01072 {
01073        zend_bool do_start, do_end;
01074 
01075        if (!ZLIBG(output_compression) || SG(sapi_headers).http_response_code == 204 || SG(sapi_headers).http_response_code == 304) {
01076               *handled_output = NULL;
01077        } else {
01078               do_start = (mode & PHP_OUTPUT_HANDLER_START ? 1 : 0);
01079               do_end = (mode & PHP_OUTPUT_HANDLER_END ? 1 : 0);
01080 
01081               if (do_start) {
01082                      if (!SG(headers_sent) && !SG(request_info).no_headers) {
01083                             switch (ZLIBG(compression_coding)) {
01084                                    case CODING_GZIP:
01085                                           sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1 TSRMLS_CC);
01086                                           break;
01087                                    case CODING_DEFLATE:
01088                                           sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1 TSRMLS_CC);
01089                                           break;
01090                             }
01091                             sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 0 TSRMLS_CC);
01092                      } else {
01093                             /* Disable compression if headers can not be set (Fix for bug #49816) */
01094                             ZLIBG(output_compression) = 0;
01095                             *handled_output = NULL;
01096                             return;
01097                      }
01098               }
01099 
01100               if (php_deflate_string(output, output_len, handled_output, handled_output_len, do_start, do_end TSRMLS_CC) != SUCCESS) {
01101                      zend_error(E_ERROR, "Compression failed");
01102               }
01103        }
01104 }
01105 /* }}} */
01106 
01107 /* {{{ php_enable_output_compression
01108  */
01109 static int php_enable_output_compression(int buffer_size TSRMLS_DC)
01110 {
01111        zval **a_encoding;
01112 
01113        zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
01114 
01115        if (!PG(http_globals)[TRACK_VARS_SERVER]
01116               || zend_hash_find(PG(http_globals)[TRACK_VARS_SERVER]->value.ht, "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING"), (void **) &a_encoding) == FAILURE
01117        ) {
01118               return FAILURE;
01119        }
01120 
01121        convert_to_string_ex(a_encoding);
01122 
01123        if (php_memnstr(Z_STRVAL_PP(a_encoding), "gzip", 4, Z_STRVAL_PP(a_encoding) + Z_STRLEN_PP(a_encoding))) {
01124               ZLIBG(compression_coding) = CODING_GZIP;
01125        } else if (php_memnstr(Z_STRVAL_PP(a_encoding), "deflate", 7, Z_STRVAL_PP(a_encoding) + Z_STRLEN_PP(a_encoding))) {
01126               ZLIBG(compression_coding) = CODING_DEFLATE;
01127        } else {
01128               return FAILURE;
01129        }
01130 
01131        php_ob_set_internal_handler(php_gzip_output_handler, (uint)buffer_size, "zlib output compression", 0 TSRMLS_CC);
01132 
01133        if (ZLIBG(output_handler) && strlen(ZLIBG(output_handler))) {
01134               php_start_ob_buffer_named(ZLIBG(output_handler), 0, 1 TSRMLS_CC);
01135        }
01136        return SUCCESS;
01137 }
01138 /* }}} */
01139 
01140 /* {{{ php_zlib_output_compression_start() */
01141 static int php_zlib_output_compression_start(TSRMLS_D)
01142 {
01143        switch (ZLIBG(output_compression)) {
01144               case 0:
01145                      break;
01146               case 1:
01147                      ZLIBG(output_compression) = 4096;
01148                      /* break omitted intentionally */
01149               default:
01150                      /* ZLIBG(compression_coding) should be 0 when zlib compression hasn't been started yet.. */
01151                      if (ZLIBG(compression_coding) == 0) {
01152                             return php_enable_output_compression(ZLIBG(output_compression) TSRMLS_CC);
01153                      }
01154        }
01155        return SUCCESS;
01156 }
01157 /* }}} */
01158 
01159 /*
01160  * Local variables:
01161  * tab-width: 4
01162  * c-basic-offset: 4
01163  * End:
01164  * vim600: sw=4 ts=4 fdm=marker
01165  * vim<600: sw=4 ts=4
01166  */