From 0f7f5c2c0e616445d14b49641e85dbddcc1651e5 Mon Sep 17 00:00:00 2001 From: Zeev Suraski Date: Mon, 13 Nov 2000 18:54:37 +0000 Subject: [PATCH] - Import Jade Nicoletti's transparent gzip encoding support as an output handler. Works quite nicely! - Fix buglets in output buffering - Add output_handler INI directive --- NEWS | 3 + ext/zlib/php_zlib.h | 20 +++- ext/zlib/zlib.c | 242 +++++++++++++++++++++++++++++++++++--- main/SAPI.c | 5 +- main/SAPI.h | 3 +- main/main.c | 15 ++- main/php_globals.h | 3 + php.ini-dist | 6 + php.ini-optimized | 6 + php.ini-recommended | 6 + sapi/apache/sapi_apache.c | 2 +- sapi/cgi/cgi_main.c | 7 +- 12 files changed, 288 insertions(+), 30 deletions(-) diff --git a/NEWS b/NEWS index e14c2e9d87..038b2d019e 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP 4.0 NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 2000, Version 4.0.4 +- Added 'output_handler' INI directive (Zeev) +- Fixed some buglets in the output buffering mechanism (Zeev) +- Added transparent gzip compression support (Jade Nicoletti, Zeev) - Major overhaul of domxml. Added basic XPath support as well (Uwe) - Added 'r' flag to date() which generates an RFC822 formatted date, e.g. "Thu, 9 Nov 2000 16:33:01 -0500" (Colin) diff --git a/ext/zlib/php_zlib.h b/ext/zlib/php_zlib.h index 518ae2543e..b856fc9fd0 100644 --- a/ext/zlib/php_zlib.h +++ b/ext/zlib/php_zlib.h @@ -22,10 +22,16 @@ #ifndef PHP_ZLIB_H #define PHP_ZLIB_H -#if HAVE_ZLIB +#include + typedef struct { int gzgetss_state; + + /* variables for transparent gzip encoding */ + int compression_coding; + z_stream stream; + uLong crc; } php_zlib_globals; extern zend_module_entry php_zlib_module_entry; @@ -52,21 +58,25 @@ PHP_FUNCTION(gzcompress); PHP_FUNCTION(gzuncompress); PHP_FUNCTION(gzdeflate); PHP_FUNCTION(gzinflate); +PHP_FUNCTION(gzencode); +PHP_FUNCTION(ob_gzhandler); #ifdef ZTS #define ZLIBLS_D php_zlib_globals *zlib_globals +#define ZLIBLS_DC , ZLIBLS_D +#define ZLIBLS_C zlib_globals +#define ZLIBLS_CC , ZLIBLS_C #define ZLIBG(v) (zlib_globals->v) #define ZLIBLS_FETCH() php_zlib_globals *zlib_globals = ts_resource(zlib_globals_id) #else #define ZLIBLS_D +#define ZLIBLS_DC +#define ZLIBLS_C +#define ZLIBLS_CC #define ZLIBG(v) (zlib_globals.v) #define ZLIBLS_FETCH() #endif -#else -#define zlib_module_ptr NULL -#endif /* HAVE_ZLIB */ - #define phpext_zlib_ptr zlib_module_ptr #endif /* PHP_ZLIB_H */ diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 7f4d4ec410..f70a911624 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -29,6 +29,7 @@ #endif #include "php.h" +#include "SAPI.h" #include #include @@ -57,12 +58,10 @@ #include #endif #endif -#if HAVE_ZLIB #if defined(HAVE_UNISTD_H) && defined(PHP_WIN32) #undef HAVE_UNISTD_H #endif -#include #ifdef COMPILE_DL_ZLIB #ifndef PUTS @@ -86,8 +85,14 @@ static php_zlib_globals zlib_globals; static FILE *zlib_fopen_wrapper(char *path, char *mode, int options, int *issock, int *socketd, char **opened_path); #endif +#define OS_CODE 0x03 /* FIXME */ +#define CODING_GZIP 1 +#define CODING_DEFLATE 2 + /* True globals, no need for thread safety */ static int le_zp; +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + function_entry php_zlib_functions[] = { PHP_FE(readgzfile, NULL) @@ -109,6 +114,8 @@ function_entry php_zlib_functions[] = { PHP_FE(gzuncompress, NULL) PHP_FE(gzdeflate, NULL) PHP_FE(gzinflate, NULL) + PHP_FE(gzencode, NULL) + PHP_FE(ob_gzhandler, NULL) {NULL, NULL, NULL} }; @@ -158,6 +165,9 @@ PHP_MINIT_FUNCTION(zlib) } #endif + REGISTER_LONG_CONSTANT("FORCE_GZIP", CODING_GZIP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("FORCE_DEFLATE", CODING_DEFLATE, CONST_CS | CONST_PERSISTENT); + return SUCCESS; } @@ -201,7 +211,8 @@ static gzFile php_gzopen_wrapper(char *path, char *mode, int options) /* {{{ proto array gzfile(string filename [, int use_include_path]) Read und uncompress entire .gz-file into an array */ -PHP_FUNCTION(gzfile) { +PHP_FUNCTION(gzfile) +{ pval **filename, **arg2; gzFile zp; char *slashed, buf[8192]; @@ -257,7 +268,8 @@ PHP_FUNCTION(gzfile) { /* {{{ proto int gzopen(string filename, string mode [, int use_include_path]) Open a .gz-file and return a .gz-file pointer */ -PHP_FUNCTION(gzopen) { +PHP_FUNCTION(gzopen) +{ pval **arg1, **arg2, **arg3; gzFile *zp; char *p; @@ -303,7 +315,8 @@ PHP_FUNCTION(gzopen) { /* {{{ proto int gzclose(int zp) Close an open .gz-file pointer */ -PHP_FUNCTION(gzclose) { +PHP_FUNCTION(gzclose) +{ pval **arg1; gzFile *zp; @@ -318,7 +331,8 @@ PHP_FUNCTION(gzclose) { /* {{{ proto int gzeof(int zp) Test for end-of-file on a .gz-file pointer */ -PHP_FUNCTION(gzeof) { +PHP_FUNCTION(gzeof) +{ pval **arg1; gzFile *zp; @@ -337,7 +351,8 @@ PHP_FUNCTION(gzeof) { /* {{{ proto string gzgets(int zp, int length) Get a line from .gz-file pointer */ -PHP_FUNCTION(gzgets) { +PHP_FUNCTION(gzgets) +{ pval **arg1, **arg2; gzFile *zp; int len; @@ -373,7 +388,8 @@ PHP_FUNCTION(gzgets) { /* {{{ proto string gzgetc(int zp) Get a character from .gz-file pointer */ -PHP_FUNCTION(gzgetc) { +PHP_FUNCTION(gzgetc) +{ pval **arg1; gzFile *zp; int c; @@ -456,7 +472,8 @@ PHP_FUNCTION(gzgetss) /* {{{ proto int gzwrite(int zp, string str [, int length]) Binary-safe .gz-file write */ -PHP_FUNCTION(gzwrite) { +PHP_FUNCTION(gzwrite) +{ pval **arg1, **arg2, **arg3=NULL; gzFile *zp; int ret; @@ -502,7 +519,8 @@ PHP_FUNCTION(gzwrite) { /* {{{ proto int gzrewind(int zp) Rewind the position of a .gz-file pointer */ -PHP_FUNCTION(gzrewind) { +PHP_FUNCTION(gzrewind) +{ pval **arg1; gzFile *zp; @@ -519,7 +537,8 @@ PHP_FUNCTION(gzrewind) { /* {{{ proto int gztell(int zp) Get .gz-file pointer's read/write position */ -PHP_FUNCTION(gztell) { +PHP_FUNCTION(gztell) +{ pval **arg1; long pos; gzFile *zp; @@ -537,7 +556,8 @@ PHP_FUNCTION(gztell) { /* {{{ proto int gzseek(int zp, int offset) Seek on a file pointer */ -PHP_FUNCTION(gzseek) { +PHP_FUNCTION(gzseek) +{ pval **arg1, **arg2; int ret; gzFile *zp; @@ -559,7 +579,8 @@ PHP_FUNCTION(gzseek) { */ /* {{{ proto int readgzfile(string filename [, int use_include_path]) Output a .gz-file */ -PHP_FUNCTION(readgzfile) { +PHP_FUNCTION(readgzfile) +{ pval **arg1, **arg2; char buf[8192]; gzFile *zp; @@ -610,7 +631,8 @@ PHP_FUNCTION(readgzfile) { */ /* {{{ proto int gzpassthru(int zp) Output all remaining data from a .gz-file pointer */ -PHP_FUNCTION(gzpassthru) { +PHP_FUNCTION(gzpassthru) +{ pval **arg1; gzFile *zp; char buf[8192]; @@ -992,8 +1014,198 @@ static FILE *zlib_fopen_wrapper(char *path, char *mode, int options, int *issock #endif +static int php_do_deflate(uint str_length, Bytef **p_buffer, uint *p_buf_used ZLIBLS_DC) +{ + Bytef *buffer; + uInt prev_outlen, outlen; + int err; + + outlen = sizeof(char) * (str_length * 1.001 + 12); + buffer = (Bytef *) emalloc(outlen+10+8); /* 10+8 for the header and trailer */ + + ZLIBG(stream).next_out = buffer+10; + ZLIBG(stream).avail_out = outlen; + + err = deflate(&ZLIBG(stream), Z_NO_FLUSH); + while (err == Z_OK && !ZLIBG(stream).avail_out) { + prev_outlen = outlen; + outlen *= 3; + buffer = realloc(buffer, outlen+10+8); + + ZLIBG(stream).next_out = buffer+10 + prev_outlen; + ZLIBG(stream).avail_out = prev_outlen * 2; + + err = deflate(&ZLIBG(stream), Z_NO_FLUSH); + } + + err = deflate(&ZLIBG(stream), Z_FINISH); + + *p_buffer = buffer; + *p_buf_used = outlen - ZLIBG(stream).avail_out; + return err; +} + + +int php_deflate_string(const char *str, uint str_length, char **newstr, uint *new_length, int coding) +{ + Bytef *buffer; + uInt buf_used; + int err; + Bytef header_buffer[11]; + Bytef trailer_buffer[9]; + ZLIBLS_FETCH(); + + ZLIBG(compression_coding) = coding; + + ZLIBG(stream).zalloc = Z_NULL; + ZLIBG(stream).zfree = Z_NULL; + ZLIBG(stream).opaque = Z_NULL; + + switch (coding) { + case CODING_GZIP: + /* windowBits is passed < 0 to suppress zlib header & trailer */ + if (deflateInit2(&ZLIBG(stream), Z_DEFAULT_COMPRESSION, Z_DEFLATED, + -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY) + != Z_OK) { + /* TODO: print out error */ + return FAILURE; + } + + /* + sapi_add_header("Content-Encoding: gzip", sizeof("Content-Encoding: gzip") - 1, 1); + sapi_send_headers(); + */ + + /* Write a very simple .gz header: */ + sprintf(header_buffer, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], + gz_magic[1], Z_DEFLATED, 0 /*flags*/, + 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + ZLIBG(crc) = crc32(0L, Z_NULL, 0); + break; + case CODING_DEFLATE: + if (deflateInit(&ZLIBG(stream), Z_DEFAULT_COMPRESSION) != Z_OK) { + /* TODO: print out error */ + return FAILURE; + } + /* + sapi_add_header("Content-Encoding: deflate", sizeof("Content-Encoding: deflate") - 1, 1); + */ + break; + } + + + ZLIBG(stream).next_in = (Bytef*) str; + ZLIBG(stream).avail_in = (uInt) str_length; + + if (ZLIBG(compression_coding) == 1) { + ZLIBG(crc) = crc32(ZLIBG(crc), (const Bytef *)str, str_length); + } + + err = php_do_deflate(str_length, &buffer, &buf_used ZLIBLS_CC); + /* TODO: error handling (err may be Z_STREAM_ERROR, Z_BUF_ERROR, ?) */ + + + if (ZLIBG(compression_coding) == 1) { + /* write crc & stream.total_in in LSB order */ + sprintf(trailer_buffer, "%c%c%c%c%c%c%c%c", + (char) ZLIBG(crc) & 0xFF, + (char) (ZLIBG(crc) >> 8) & 0xFF, + (char) (ZLIBG(crc) >> 16) & 0xFF, + (char) (ZLIBG(crc) >> 24) & 0xFF, + (char) ZLIBG(stream).total_in & 0xFF, + (char) (ZLIBG(stream).total_in >> 8) & 0xFF, + (char) (ZLIBG(stream).total_in >> 16) & 0xFF, + (char) (ZLIBG(stream).total_in >> 24) & 0xFF); + } + + + memcpy(buffer, header_buffer, 10); + memcpy(buffer+10+buf_used, trailer_buffer, 8); + + *new_length = buf_used + 10 + 8; + *newstr = buffer; + + return SUCCESS; +} + + +PHP_FUNCTION(gzencode) +{ + zval **zv_coding, **zv_string; + int coding; + + switch(ZEND_NUM_ARGS()) { + case CODING_GZIP: + if (zend_get_parameters_ex(1, &zv_string)==FAILURE) { + RETURN_FALSE; + } + convert_to_string_ex(zv_string); + coding = 1; + break; + case CODING_DEFLATE: + if (zend_get_parameters_ex(2, &zv_string, &zv_coding)==FAILURE) { + RETURN_FALSE; + } + convert_to_string_ex(zv_string); + convert_to_long_ex(zv_coding); + coding = Z_LVAL_PP(zv_coding); + break; + default: + ZEND_WRONG_PARAM_COUNT(); + break; + } + if (php_deflate_string(Z_STRVAL_PP(zv_string), Z_STRLEN_PP(zv_string), &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), coding)==SUCCESS) { + Z_TYPE_P(return_value) = IS_STRING; + } else { + RETURN_FALSE; + } +} + + +PHP_FUNCTION(ob_gzhandler) +{ + int coding; + zval **zv_string; + zval **data, **a_encoding; + + if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &zv_string)==FAILURE) { + ZEND_WRONG_PARAM_COUNT(); + } + + if (zend_hash_find(&EG(symbol_table), "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), (void **) &data)==FAILURE + || Z_TYPE_PP(data)!=IS_ARRAY + || zend_hash_find(Z_ARRVAL_PP(data), "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING"), (void **) &a_encoding)==FAILURE) { + /* return the original string */ + *return_value = **zv_string; + zval_copy_ctor(return_value); + return; + } + convert_to_string_ex(a_encoding); + if (php_memnstr(Z_STRVAL_PP(a_encoding), "gzip", 4, Z_STRVAL_PP(a_encoding) + Z_STRLEN_PP(a_encoding))) { + coding = CODING_GZIP; + } else if(php_memnstr(Z_STRVAL_PP(a_encoding), "deflate", 7, Z_STRVAL_PP(a_encoding) + Z_STRLEN_PP(a_encoding))) { + coding = CODING_DEFLATE; + } else { + RETURN_FALSE; + } + if (php_deflate_string(Z_STRVAL_PP(zv_string), Z_STRLEN_PP(zv_string), &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), coding)==SUCCESS) { + Z_TYPE_P(return_value) = IS_STRING; + switch (coding) { + case CODING_GZIP: + sapi_add_header("Content-Encoding: gzip", sizeof("Content-Encoding: gzip") - 1, 1); + break; + case CODING_DEFLATE: + sapi_add_header("Content-Encoding: deflate", sizeof("Content-Encoding: deflate") - 1, 1); + break; + } + } else { + /* return the original string */ + *return_value = **zv_string; + zval_copy_ctor(return_value); + } +} + -#endif /* HAVE_ZLIB */ /* * Local variables: * tab-width: 4 diff --git a/main/SAPI.c b/main/SAPI.c index 563f1cd072..67bd8019de 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -271,6 +271,7 @@ SAPI_API void sapi_activate(SLS_D) SG(request_info).post_data = NULL; SG(request_info).current_user = NULL; SG(request_info).current_user_length = 0; + SG(request_info).no_headers = 0; /* It's possible to override this general case in the activate() callback, if * necessary. @@ -363,7 +364,7 @@ SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bo char *colon_offset; SLS_FETCH(); - if (SG(headers_sent)) { + if (SG(headers_sent) && !SG(request_info).no_headers) { char *output_start_filename = php_get_output_start_filename(); int output_start_lineno = php_get_output_start_lineno(); @@ -457,7 +458,7 @@ SAPI_API int sapi_send_headers() int ret = FAILURE; SLS_FETCH(); - if (SG(headers_sent)) { + if (SG(headers_sent) || SG(request_info).no_headers) { return SUCCESS; } diff --git a/main/SAPI.h b/main/SAPI.h index 86eb356104..9c2f06abe3 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -73,7 +73,8 @@ typedef struct { const char *content_type; - unsigned char headers_only; + zend_bool headers_only; + zend_bool no_headers; sapi_post_entry *post_entry; diff --git a/main/main.c b/main/main.c index 2ef64e9af1..325a9802b5 100644 --- a/main/main.c +++ b/main/main.c @@ -223,6 +223,7 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("magic_quotes_runtime", "0", PHP_INI_ALL, OnUpdateBool, magic_quotes_runtime, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("magic_quotes_sybase", "0", PHP_INI_ALL, OnUpdateBool, magic_quotes_sybase, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("output_buffering", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM,OnUpdateBool, output_buffering, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("output_handler", NULL, PHP_INI_PERDIR|PHP_INI_SYSTEM,OnUpdateString, output_handler, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("register_argc_argv", "1", PHP_INI_ALL, OnUpdateBool, register_argc_argv, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("register_globals", "1", PHP_INI_ALL, OnUpdateBool, register_globals, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, safe_mode, php_core_globals, core_globals) @@ -623,7 +624,15 @@ int php_request_startup(CLS_D ELS_DC PLS_DC SLS_DC) sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1); } - if (PG(output_buffering)) { + if (PG(output_handler)) { + zval *output_handler; + + ALLOC_INIT_ZVAL(output_handler); + Z_STRLEN_P(output_handler) = strlen(PG(output_handler)); /* this can be optimized */ + Z_STRVAL_P(output_handler) = estrndup(PG(output_handler), Z_STRLEN_P(output_handler)); + Z_TYPE_P(output_handler) = IS_STRING; + php_start_ob_buffer(output_handler); + } else if (PG(output_buffering)) { php_start_ob_buffer(NULL); } else if (PG(implicit_flush)) { php_start_implicit_flush(); @@ -656,11 +665,11 @@ void php_request_shutdown(void *dummy) PLS_FETCH(); if (setjmp(EG(bailout))==0) { - sapi_send_headers(); + php_end_ob_buffers(SG(request_info).headers_only?0:1); } if (setjmp(EG(bailout))==0) { - php_end_ob_buffers(SG(request_info).headers_only?0:1); + sapi_send_headers(); } if (PG(modules_activated) && setjmp(EG(bailout))==0) { diff --git a/main/php_globals.h b/main/php_globals.h index 97461c1e0a..aa313a4075 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -65,6 +65,9 @@ struct _php_core_globals { zend_bool safe_mode; zend_bool sql_safe_mode; zend_bool enable_dl; + + char *output_handler; + char *safe_mode_exec_dir; long memory_limit; diff --git a/php.ini-dist b/php.ini-dist index 8d098e7d97..43b5032271 100644 --- a/php.ini-dist +++ b/php.ini-dist @@ -64,6 +64,12 @@ output_buffering = Off ; Output buffering allows you to send header lines (inclu ; You can enable output buffering by in runtime by calling the output ; buffering functions, or enable output buffering for all files ; by setting this directive to On. +output_handler = ; You can redirect all of the output of your scripts to a function, + ; that can be responsible to process or log it. For example, + ; if you set the output_handler to "ob_gzhandler", than output + ; will be transparently compressed for browsers that support gzip or + ; deflate encoding. Setting an output handler automatically turns on + ; output buffering. implicit_flush = Off ; Implicit flush tells PHP to tell the output layer to flush itself ; automatically after every output block. This is equivalent to ; calling the PHP function flush() after each and every call to print() diff --git a/php.ini-optimized b/php.ini-optimized index f0d4ca6ae5..1bdd0060aa 100644 --- a/php.ini-optimized +++ b/php.ini-optimized @@ -51,6 +51,12 @@ output_buffering = Off ; Output buffering allows you to send header lines (inclu ; You can enable output buffering by in runtime by calling the output ; buffering functions, or enable output buffering for all files ; by setting this directive to On. +output_handler = ; You can redirect all of the output of your scripts to a function, + ; that can be responsible to process or log it. For example, + ; if you set the output_handler to "ob_gzhandler", than output + ; will be transparently compressed for browsers that support gzip or + ; deflate encoding. Setting an output handler automatically turns on + ; output buffering. implicit_flush = Off ; Implicit flush tells PHP to tell the output layer to flush itself ; automatically after every output block. This is equivalent to ; calling the PHP function flush() after each and every call to print() diff --git a/php.ini-recommended b/php.ini-recommended index f0d4ca6ae5..1bdd0060aa 100644 --- a/php.ini-recommended +++ b/php.ini-recommended @@ -51,6 +51,12 @@ output_buffering = Off ; Output buffering allows you to send header lines (inclu ; You can enable output buffering by in runtime by calling the output ; buffering functions, or enable output buffering for all files ; by setting this directive to On. +output_handler = ; You can redirect all of the output of your scripts to a function, + ; that can be responsible to process or log it. For example, + ; if you set the output_handler to "ob_gzhandler", than output + ; will be transparently compressed for browsers that support gzip or + ; deflate encoding. Setting an output handler automatically turns on + ; output buffering. implicit_flush = Off ; Implicit flush tells PHP to tell the output layer to flush itself ; automatically after every output block. This is equivalent to ; calling the PHP function flush() after each and every call to print() diff --git a/sapi/apache/sapi_apache.c b/sapi/apache/sapi_apache.c index e2cb151c37..f6139a9dc8 100644 --- a/sapi/apache/sapi_apache.c +++ b/sapi/apache/sapi_apache.c @@ -92,8 +92,8 @@ int apache_php_module_main(request_rec *r, int display_source_mode CLS_DC ELS_DC if (setjmp(EG(bailout))!=0) { return OK; } - php_header(); /* Make sure headers have been sent */ php_end_ob_buffers(1); + php_header(); /* Make sure headers have been sent */ return (OK); } diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 67ed3b80b5..d966527c26 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -548,6 +548,7 @@ any .htaccess restrictions anywhere on your site you can leave doc_root undefine } } if (no_headers) { + SG(request_info).no_headers = 1; SG(headers_sent) = 1; } cgi_started=1; @@ -582,6 +583,7 @@ any .htaccess restrictions anywhere on your site you can leave doc_root undefine } if (no_headers) { SG(headers_sent) = 1; + SG(request_info).no_headers = 1; } cgi_started=1; php_print_info(0xFFFFFFFF); @@ -630,6 +632,7 @@ any .htaccess restrictions anywhere on your site you can leave doc_root undefine } if (no_headers) { SG(headers_sent) = 1; + SG(request_info).no_headers = 1; } php_printf("%s\n", PHP_VERSION); php_end_ob_buffers(1); @@ -677,6 +680,7 @@ any .htaccess restrictions anywhere on your site you can leave doc_root undefine } if (no_headers) { SG(headers_sent) = 1; + SG(request_info).no_headers = 1; } file_handle.filename = "-"; file_handle.type = ZEND_HANDLE_FP; @@ -766,9 +770,6 @@ any .htaccess restrictions anywhere on your site you can leave doc_root undefine #endif } - php_header(); /* Make sure headers have been sent */ - - if (SG(request_info).path_translated) { persist_alloc(SG(request_info).path_translated); -- 2.50.1