Back to index

php5  5.3.10
output.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: Zeev Suraski <zeev@zend.com>                                |
00016    |          Thies C. Arntzen <thies@thieso.net>                         |
00017    |          Marcus Boerger <helly@php.net>                              |
00018    +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: output.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #include "php.h"
00024 #include "ext/standard/head.h"
00025 #include "ext/standard/basic_functions.h"
00026 #include "ext/standard/url_scanner_ex.h"
00027 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
00028 #include "ext/zlib/php_zlib.h"
00029 #endif
00030 #include "SAPI.h"
00031 
00032 #define OB_DEFAULT_HANDLER_NAME "default output handler"
00033 
00034 /* output functions */
00035 static int php_b_body_write(const char *str, uint str_length TSRMLS_DC);
00036 
00037 static int php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC);
00038 static void php_ob_append(const char *text, uint text_length TSRMLS_DC);
00039 #if 0
00040 static void php_ob_prepend(const char *text, uint text_length);
00041 #endif
00042 
00043 #ifdef ZTS
00044 int output_globals_id;
00045 #else
00046 php_output_globals output_globals;
00047 #endif
00048 
00049 /* {{{ php_default_output_func */
00050 PHPAPI int php_default_output_func(const char *str, uint str_len TSRMLS_DC)
00051 {
00052        fwrite(str, 1, str_len, stderr);
00053 /* See http://support.microsoft.com/kb/190351 */
00054 #ifdef PHP_WIN32
00055        fflush(stderr);
00056 #endif
00057        return str_len;
00058 }
00059 /* }}} */
00060 
00061 /* {{{ php_output_init_globals */
00062 static void php_output_init_globals(php_output_globals *output_globals_p TSRMLS_DC)
00063 {
00064        OG(php_body_write) = php_default_output_func;
00065        OG(php_header_write) = php_default_output_func;
00066        OG(implicit_flush) = 0;
00067        OG(output_start_filename) = NULL;
00068        OG(output_start_lineno) = 0;
00069 }
00070 /* }}} */
00071 
00072 /* {{{ php_output_startup
00073  * Start output layer */
00074 PHPAPI void php_output_startup(void)
00075 {
00076 #ifdef ZTS
00077        ts_allocate_id(&output_globals_id, sizeof(php_output_globals), (ts_allocate_ctor) php_output_init_globals, NULL);
00078 #else
00079        php_output_init_globals(&output_globals TSRMLS_CC);
00080 #endif
00081 }
00082 /* }}} */
00083 
00084 /* {{{ php_output_activate
00085  * Initilize output global for activation */
00086 PHPAPI void php_output_activate(TSRMLS_D)
00087 {
00088        OG(php_body_write) = php_ub_body_write;
00089        OG(php_header_write) = sapi_module.ub_write;
00090        OG(ob_nesting_level) = 0;
00091        OG(ob_lock) = 0;
00092        OG(disable_output) = 0;
00093        OG(output_start_filename) = NULL;
00094        OG(output_start_lineno) = 0;
00095 }
00096 /* }}} */
00097 
00098 /* {{{ php_output_register_constants */
00099 void php_output_register_constants(TSRMLS_D)
00100 {
00101        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT);
00102        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_CONT, CONST_CS | CONST_PERSISTENT);
00103        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_END, CONST_CS | CONST_PERSISTENT);
00104 }
00105 /* }}} */
00106 
00107 /* {{{ php_output_set_status
00108  * Toggle output status.  Do NOT use in application code, only in SAPIs where appropriate. */
00109 PHPAPI void php_output_set_status(zend_bool status TSRMLS_DC)
00110 {
00111        OG(disable_output) = !status;
00112 }
00113 /* }}} */
00114 
00115 /* {{{ php_body_write
00116  * Write body part */
00117 PHPAPI int php_body_write(const char *str, uint str_length TSRMLS_DC)
00118 {
00119        return OG(php_body_write)(str, str_length TSRMLS_CC);
00120 }
00121 /* }}} */
00122 
00123 /* {{{ php_header_write
00124  * Write HTTP header */
00125 PHPAPI int php_header_write(const char *str, uint str_length TSRMLS_DC)
00126 {
00127        if (OG(disable_output)) {
00128               return 0;
00129        } else {
00130               return OG(php_header_write)(str, str_length TSRMLS_CC);
00131        }
00132 }
00133 /* }}} */
00134 
00135 /* {{{ php_start_ob_buffer
00136  * Start output buffering */
00137 PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
00138 {
00139        uint initial_size, block_size;
00140 
00141        if (OG(ob_lock)) {
00142               if (SG(headers_sent) && !SG(request_info).headers_only) {
00143                      OG(php_body_write) = php_ub_body_write_no_header;
00144               } else {
00145                      OG(php_body_write) = php_ub_body_write;
00146               }
00147               OG(ob_nesting_level) = 0;
00148               php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers");
00149               return FAILURE;
00150        }
00151        if (chunk_size > 0) {
00152               if (chunk_size==1) {
00153                      chunk_size = 4096;
00154               }
00155               initial_size = (chunk_size*3/2);
00156               block_size = chunk_size/2;
00157        } else {
00158               initial_size = 40*1024;
00159               block_size = 10*1024;
00160        }
00161        return php_ob_init(initial_size, block_size, output_handler, chunk_size, erase TSRMLS_CC);
00162 }
00163 /* }}} */
00164 
00165 /* {{{ php_start_ob_buffer_named
00166  * Start output buffering */
00167 PHPAPI int php_start_ob_buffer_named(const char *output_handler_name, uint chunk_size, zend_bool erase TSRMLS_DC)
00168 {
00169        zval *output_handler;
00170        int result;
00171 
00172        ALLOC_INIT_ZVAL(output_handler);
00173        Z_STRLEN_P(output_handler) = strlen(output_handler_name);      /* this can be optimized */
00174        Z_STRVAL_P(output_handler) = estrndup(output_handler_name, Z_STRLEN_P(output_handler));
00175        Z_TYPE_P(output_handler) = IS_STRING;
00176        result = php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC);
00177        zval_dtor(output_handler);
00178        FREE_ZVAL(output_handler);
00179        return result;
00180 }
00181 /* }}} */
00182 
00183 /* {{{ php_end_ob_buffer
00184  * End output buffering (one level) */
00185 PHPAPI void php_end_ob_buffer(zend_bool send_buffer, zend_bool just_flush TSRMLS_DC)
00186 {
00187        char *final_buffer=NULL;
00188        unsigned int final_buffer_length=0;
00189        zval *alternate_buffer=NULL;
00190        char *to_be_destroyed_buffer, *to_be_destroyed_handler_name;
00191        char *to_be_destroyed_handled_output[2] = { 0, 0 };
00192        int status;
00193        php_ob_buffer *prev_ob_buffer_p=NULL;
00194        php_ob_buffer orig_ob_buffer;
00195 
00196        if (OG(ob_nesting_level)==0) {
00197               return;
00198        }
00199        status = 0;
00200        if (!OG(active_ob_buffer).status & PHP_OUTPUT_HANDLER_START) {
00201               /* our first call */
00202               status |= PHP_OUTPUT_HANDLER_START;
00203        }
00204        if (just_flush) {
00205               status |= PHP_OUTPUT_HANDLER_CONT;
00206        } else {
00207               status |= PHP_OUTPUT_HANDLER_END;
00208        }
00209 
00210 #if 0
00211  {
00212         FILE *fp;
00213         fp = fopen("/tmp/ob_log", "a");
00214         fprintf(fp, "NestLevel: %d  ObStatus: %d  HandlerName: %s\n", OG(ob_nesting_level), status, OG(active_ob_buffer).handler_name);
00215         fclose(fp);
00216  }
00217 #endif
00218 
00219        if (OG(active_ob_buffer).internal_output_handler) {
00220               final_buffer = OG(active_ob_buffer).internal_output_handler_buffer;
00221               final_buffer_length = OG(active_ob_buffer).internal_output_handler_buffer_size;
00222               OG(active_ob_buffer).internal_output_handler(OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, &final_buffer, &final_buffer_length, status TSRMLS_CC);
00223        } else if (OG(active_ob_buffer).output_handler) {
00224               zval **params[2];
00225               zval *orig_buffer;
00226               zval *z_status;
00227 
00228               ALLOC_INIT_ZVAL(orig_buffer);
00229               ZVAL_STRINGL(orig_buffer, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
00230 
00231               ALLOC_INIT_ZVAL(z_status);
00232               ZVAL_LONG(z_status, status);
00233 
00234               params[0] = &orig_buffer;
00235               params[1] = &z_status;
00236               OG(ob_lock) = 1;
00237 
00238               if (call_user_function_ex(CG(function_table), NULL, OG(active_ob_buffer).output_handler, &alternate_buffer, 2, params, 1, NULL TSRMLS_CC)==SUCCESS) {
00239                      if (alternate_buffer && !(Z_TYPE_P(alternate_buffer)==IS_BOOL && Z_BVAL_P(alternate_buffer)==0)) {
00240                             convert_to_string_ex(&alternate_buffer);
00241                             final_buffer = Z_STRVAL_P(alternate_buffer);
00242                             final_buffer_length = Z_STRLEN_P(alternate_buffer);
00243                      }
00244               }
00245               OG(ob_lock) = 0;
00246               if (!just_flush) {
00247                      zval_ptr_dtor(&OG(active_ob_buffer).output_handler);
00248               }
00249               zval_ptr_dtor(&orig_buffer);
00250               zval_ptr_dtor(&z_status);
00251        }
00252 
00253        if (!final_buffer) {
00254               final_buffer = OG(active_ob_buffer).buffer;
00255               final_buffer_length = OG(active_ob_buffer).text_length;
00256        }
00257 
00258        if (OG(ob_nesting_level)==1) { /* end buffering */
00259               if (SG(headers_sent) && !SG(request_info).headers_only) {
00260                      OG(php_body_write) = php_ub_body_write_no_header;
00261               } else {
00262                      OG(php_body_write) = php_ub_body_write;
00263               }
00264        }
00265 
00266        to_be_destroyed_buffer = OG(active_ob_buffer).buffer;
00267        to_be_destroyed_handler_name = OG(active_ob_buffer).handler_name;
00268        if (OG(active_ob_buffer).internal_output_handler
00269               && (final_buffer != OG(active_ob_buffer).internal_output_handler_buffer)
00270               && (final_buffer != OG(active_ob_buffer).buffer)) {
00271               to_be_destroyed_handled_output[0] = final_buffer;
00272        }
00273 
00274        if (!just_flush) {
00275               if (OG(active_ob_buffer).internal_output_handler) {
00276                      to_be_destroyed_handled_output[1] = OG(active_ob_buffer).internal_output_handler_buffer;
00277               }
00278        }
00279        if (OG(ob_nesting_level)>1) { /* restore previous buffer */
00280               zend_stack_top(&OG(ob_buffers), (void **) &prev_ob_buffer_p);
00281               orig_ob_buffer = OG(active_ob_buffer);
00282               OG(active_ob_buffer) = *prev_ob_buffer_p;
00283               zend_stack_del_top(&OG(ob_buffers));
00284               if (!just_flush && OG(ob_nesting_level)==2) { /* destroy the stack */
00285                      zend_stack_destroy(&OG(ob_buffers));
00286               }
00287        }
00288        OG(ob_nesting_level)--;
00289 
00290        if (send_buffer) {
00291               if (just_flush) { /* if flush is called prior to proper end, ensure presence of NUL */
00292                      final_buffer[final_buffer_length] = '\0';
00293               }
00294               OG(php_body_write)(final_buffer, final_buffer_length TSRMLS_CC);
00295        }
00296 
00297        if (just_flush) { /* we restored the previous ob, return to the current */
00298               if (prev_ob_buffer_p) {
00299                      zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer));
00300                      OG(active_ob_buffer) = orig_ob_buffer;
00301               }
00302               OG(ob_nesting_level)++;
00303        }
00304 
00305        if (alternate_buffer) {
00306               zval_ptr_dtor(&alternate_buffer);
00307        }
00308 
00309        if (status & PHP_OUTPUT_HANDLER_END) {
00310               efree(to_be_destroyed_handler_name);
00311        }
00312        if (!just_flush) {
00313               efree(to_be_destroyed_buffer);
00314        } else {
00315               OG(active_ob_buffer).text_length = 0;
00316               OG(active_ob_buffer).status |= PHP_OUTPUT_HANDLER_START;
00317               OG(php_body_write) = php_b_body_write;
00318        }
00319        if (to_be_destroyed_handled_output[0]) {
00320               efree(to_be_destroyed_handled_output[0]);
00321        }
00322        if (to_be_destroyed_handled_output[1]) {
00323               efree(to_be_destroyed_handled_output[1]);
00324        }
00325 }
00326 /* }}} */
00327 
00328 /* {{{ php_end_ob_buffers
00329  * End output buffering (all buffers) */
00330 PHPAPI void php_end_ob_buffers(zend_bool send_buffer TSRMLS_DC)
00331 {
00332        while (OG(ob_nesting_level)!=0) {
00333               php_end_ob_buffer(send_buffer, 0 TSRMLS_CC);
00334        }
00335 }
00336 /* }}} */
00337 
00338 /* {{{ php_start_implicit_flush
00339  */
00340 PHPAPI void php_start_implicit_flush(TSRMLS_D)
00341 {
00342        OG(implicit_flush) = 1;
00343 }
00344 /* }}} */
00345 
00346 /* {{{ php_end_implicit_flush
00347  */
00348 PHPAPI void php_end_implicit_flush(TSRMLS_D)
00349 {
00350        OG(implicit_flush) = 0;
00351 }
00352 /* }}} */
00353 
00354 /* {{{ char *php_get_output_start_filename(TSRMLS_D)
00355  *  Return filename start output something */
00356 PHPAPI char *php_get_output_start_filename(TSRMLS_D)
00357 {
00358        return OG(output_start_filename);
00359 }
00360 /* }}} */
00361 
00362 /* {{{ char *php_get_output_start_lineno(TSRMLS_D)
00363  * Return line number start output something */
00364 PHPAPI int php_get_output_start_lineno(TSRMLS_D)
00365 {
00366        return OG(output_start_lineno);
00367 }
00368 /* }}} */
00369 
00370 /* {{{ php_ob_set_internal_handler
00371  */
00372 PHPAPI void php_ob_set_internal_handler(php_output_handler_func_t internal_output_handler, uint buffer_size, char *handler_name, zend_bool erase TSRMLS_DC)
00373 {
00374        if (OG(ob_nesting_level) == 0 || OG(active_ob_buffer).internal_output_handler || strcmp(OG(active_ob_buffer).handler_name, OB_DEFAULT_HANDLER_NAME)) {
00375               php_start_ob_buffer(NULL, buffer_size, erase TSRMLS_CC);
00376        }
00377 
00378        OG(active_ob_buffer).internal_output_handler = internal_output_handler;
00379        OG(active_ob_buffer).internal_output_handler_buffer = (char *) emalloc(buffer_size);
00380        OG(active_ob_buffer).internal_output_handler_buffer_size = buffer_size;
00381        if (OG(active_ob_buffer).handler_name) {
00382               efree(OG(active_ob_buffer).handler_name);
00383        }
00384        OG(active_ob_buffer).handler_name = estrdup(handler_name);
00385        OG(active_ob_buffer).erase = erase;
00386 }
00387 /* }}} */
00388 
00389 /*
00390  * Output buffering - implementation
00391  */
00392 
00393 /* {{{ php_ob_allocate
00394  */
00395 static inline void php_ob_allocate(uint text_length TSRMLS_DC)
00396 {
00397        uint new_len = OG(active_ob_buffer).text_length + text_length;
00398 
00399        if (OG(active_ob_buffer).size < new_len) {
00400               uint buf_size = OG(active_ob_buffer).size;
00401               while (buf_size <= new_len) {
00402                      buf_size += OG(active_ob_buffer).block_size;
00403               }
00404 
00405               OG(active_ob_buffer).buffer = (char *) erealloc(OG(active_ob_buffer).buffer, buf_size+1);
00406               OG(active_ob_buffer).size = buf_size;
00407        }
00408        OG(active_ob_buffer).text_length = new_len;
00409 }
00410 /* }}} */
00411 
00412 /* {{{ php_ob_init_conflict
00413  * Returns 1 if handler_set is already used and generates error message */
00414 PHPAPI int php_ob_init_conflict(char *handler_new, char *handler_set TSRMLS_DC)
00415 {
00416        if (php_ob_handler_used(handler_set TSRMLS_CC)) {
00417               php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", handler_new, handler_set);
00418               return 1;
00419        }
00420        return 0;
00421 }
00422 /* }}} */
00423 
00424 /* {{{ php_ob_init_named
00425  */
00426 static int php_ob_init_named(uint initial_size, uint block_size, char *handler_name, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
00427 {
00428        php_ob_buffer tmp_buf;
00429 
00430        if (output_handler && !zend_is_callable(output_handler, 0, NULL TSRMLS_CC)) {
00431               return FAILURE;
00432        }
00433 
00434        tmp_buf.block_size = block_size;
00435        tmp_buf.size = initial_size;
00436        tmp_buf.buffer = (char *) emalloc(initial_size+1);
00437        tmp_buf.text_length = 0;
00438        tmp_buf.output_handler = output_handler;
00439        tmp_buf.chunk_size = chunk_size;
00440        tmp_buf.status = 0;
00441        tmp_buf.internal_output_handler = NULL;
00442        tmp_buf.internal_output_handler_buffer = NULL;
00443        tmp_buf.internal_output_handler_buffer_size = 0;
00444        tmp_buf.handler_name = estrdup(handler_name&&handler_name[0]?handler_name:OB_DEFAULT_HANDLER_NAME);
00445        tmp_buf.erase = erase;
00446 
00447        if (OG(ob_nesting_level)>0) {
00448 #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
00449               if (!strncmp(handler_name, "ob_gzhandler", sizeof("ob_gzhandler")) && php_ob_gzhandler_check(TSRMLS_C)) {
00450                      return FAILURE;
00451               }
00452 #endif
00453               if (OG(ob_nesting_level)==1) { /* initialize stack */
00454                      zend_stack_init(&OG(ob_buffers));
00455               }
00456               zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer));
00457        }
00458        OG(ob_nesting_level)++;
00459        OG(active_ob_buffer) = tmp_buf;
00460        OG(php_body_write) = php_b_body_write;
00461        return SUCCESS;
00462 }
00463 /* }}} */
00464 
00465 /* {{{ php_ob_handler_from_string
00466  * Create zval output handler from string */
00467 static zval* php_ob_handler_from_string(const char *handler_name, int len TSRMLS_DC)
00468 {
00469        zval *output_handler;
00470 
00471        ALLOC_INIT_ZVAL(output_handler);
00472        Z_STRLEN_P(output_handler) = len;
00473        Z_STRVAL_P(output_handler) = estrndup(handler_name, len);
00474        Z_TYPE_P(output_handler) = IS_STRING;
00475        return output_handler;
00476 }
00477 /* }}} */
00478 
00479 /* {{{ php_ob_init
00480  */
00481 static int php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
00482 {
00483        int result = FAILURE, handler_len, len;
00484        char *handler_name, *next_handler_name;
00485        HashPosition pos;
00486        zval **tmp;
00487        zval *handler_zval;
00488 
00489        if (output_handler && output_handler->type == IS_STRING) {
00490               handler_name = Z_STRVAL_P(output_handler);
00491               handler_len  = Z_STRLEN_P(output_handler);
00492 
00493               result = SUCCESS;
00494               if (handler_len && handler_name[0] != '\0') {
00495                      while ((next_handler_name=strchr(handler_name, ',')) != NULL) {
00496                             len = next_handler_name-handler_name;
00497                             next_handler_name = estrndup(handler_name, len);
00498                             handler_zval = php_ob_handler_from_string(next_handler_name, len TSRMLS_CC);
00499                             result = php_ob_init_named(initial_size, block_size, next_handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
00500                             if (result != SUCCESS) {
00501                                    zval_dtor(handler_zval);
00502                                    FREE_ZVAL(handler_zval);
00503                             }
00504                             handler_name += len+1;
00505                             handler_len -= len+1;
00506                             efree(next_handler_name);
00507                      }
00508               }
00509               if (result == SUCCESS) {
00510                      handler_zval = php_ob_handler_from_string(handler_name, handler_len TSRMLS_CC);
00511                      result = php_ob_init_named(initial_size, block_size, handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
00512                      if (result != SUCCESS) {
00513                             zval_dtor(handler_zval);
00514                             FREE_ZVAL(handler_zval);
00515                      }
00516               }
00517        } else if (output_handler && output_handler->type == IS_ARRAY) {
00518               /* do we have array(object,method) */
00519               if (zend_is_callable(output_handler, 0, &handler_name TSRMLS_CC)) {
00520                      SEPARATE_ZVAL(&output_handler);
00521                      Z_ADDREF_P(output_handler);
00522                      result = php_ob_init_named(initial_size, block_size, handler_name, output_handler, chunk_size, erase TSRMLS_CC);
00523                      efree(handler_name);
00524               } else {
00525                      efree(handler_name);
00526                      /* init all array elements recursively */
00527                      zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(output_handler), &pos);
00528                      while (zend_hash_get_current_data_ex(Z_ARRVAL_P(output_handler), (void **)&tmp, &pos) == SUCCESS) {
00529                             result = php_ob_init(initial_size, block_size, *tmp, chunk_size, erase TSRMLS_CC);
00530                             if (result == FAILURE) {
00531                                    break;
00532                             }
00533                             zend_hash_move_forward_ex(Z_ARRVAL_P(output_handler), &pos);
00534                      }
00535               }
00536        } else if (output_handler && output_handler->type == IS_OBJECT) {
00537               /* do we have callable object */
00538               if (zend_is_callable(output_handler, 0, &handler_name TSRMLS_CC)) {
00539                      SEPARATE_ZVAL(&output_handler);
00540                      Z_ADDREF_P(output_handler);
00541                      result = php_ob_init_named(initial_size, block_size, handler_name, output_handler, chunk_size, erase TSRMLS_CC);
00542                      efree(handler_name);
00543               } else {
00544                      efree(handler_name);
00545                      php_error_docref(NULL TSRMLS_CC, E_ERROR, "No method name given: use ob_start(array($object,'method')) to specify instance $object and the name of a method of class %s to use as output handler", Z_OBJCE_P(output_handler)->name);
00546                      result = FAILURE;
00547               }
00548        } else {
00549               result = php_ob_init_named(initial_size, block_size, OB_DEFAULT_HANDLER_NAME, NULL, chunk_size, erase TSRMLS_CC);
00550        }
00551        return result;
00552 }
00553 /* }}} */
00554 
00555 /* {{{ php_ob_list_each
00556  */
00557 static int php_ob_list_each(php_ob_buffer *ob_buffer, zval *ob_handler_array)
00558 {
00559        add_next_index_string(ob_handler_array, ob_buffer->handler_name, 1);
00560        return 0;
00561 }
00562 /* }}} */
00563 
00564 /* {{{ php_ob_used_each
00565    Sets handler_name to NULL is found */
00566 static int php_ob_handler_used_each(php_ob_buffer *ob_buffer, char **handler_name)
00567 {
00568        if (!strcmp(ob_buffer->handler_name, *handler_name)) {
00569               *handler_name = NULL;
00570               return 1;
00571        }
00572        return 0;
00573 }
00574 /* }}} */
00575 
00576 /* {{{ php_ob_used
00577    returns 1 if given handler_name is used as output_handler */
00578 PHPAPI int php_ob_handler_used(char *handler_name TSRMLS_DC)
00579 {
00580        char *tmp = handler_name;
00581 
00582        if (OG(ob_nesting_level)) {
00583               if (!strcmp(OG(active_ob_buffer).handler_name, handler_name)) {
00584                      return 1;
00585               }
00586               if (OG(ob_nesting_level)>1) {
00587                      zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_ob_handler_used_each, &tmp);
00588               }
00589        }
00590        return tmp ? 0 : 1;
00591 }
00592 /* }}} */
00593 
00594 /* {{{ php_ob_append
00595  */
00596 static inline void php_ob_append(const char *text, uint text_length TSRMLS_DC)
00597 {
00598        char *target;
00599        int original_ob_text_length;
00600 
00601        original_ob_text_length=OG(active_ob_buffer).text_length;
00602 
00603        php_ob_allocate(text_length TSRMLS_CC);
00604        target = OG(active_ob_buffer).buffer+original_ob_text_length;
00605        memcpy(target, text, text_length);
00606        target[text_length]=0;
00607 
00608        /* If implicit_flush is On or chunked buffering, send contents to next buffer and return. */
00609        if (OG(active_ob_buffer).chunk_size
00610               && OG(active_ob_buffer).text_length >= OG(active_ob_buffer).chunk_size) {
00611 
00612               php_end_ob_buffer(1, 1 TSRMLS_CC);
00613               return;
00614        }
00615 }
00616 /* }}} */
00617 
00618 #if 0
00619 static inline void php_ob_prepend(const char *text, uint text_length)
00620 {
00621        char *p, *start;
00622        TSRMLS_FETCH();
00623 
00624        php_ob_allocate(text_length TSRMLS_CC);
00625 
00626        /* php_ob_allocate() may change OG(ob_buffer), so we can't initialize p&start earlier */
00627        p = OG(ob_buffer)+OG(ob_text_length);
00628        start = OG(ob_buffer);
00629 
00630        while (--p>=start) {
00631               p[text_length] = *p;
00632        }
00633        memcpy(OG(ob_buffer), text, text_length);
00634        OG(ob_buffer)[OG(active_ob_buffer).text_length]=0;
00635 }
00636 #endif
00637 
00638 /* {{{ php_ob_get_buffer
00639  * Return the current output buffer */
00640 PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC)
00641 {
00642        if (OG(ob_nesting_level)==0) {
00643               return FAILURE;
00644        }
00645        ZVAL_STRINGL(p, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
00646        return SUCCESS;
00647 }
00648 /* }}} */
00649 
00650 /* {{{ php_ob_get_length
00651  * Return the size of the current output buffer */
00652 PHPAPI int php_ob_get_length(zval *p TSRMLS_DC)
00653 {
00654        if (OG(ob_nesting_level) == 0) {
00655               return FAILURE;
00656        }
00657        ZVAL_LONG(p, OG(active_ob_buffer).text_length);
00658        return SUCCESS;
00659 }
00660 /* }}} */
00661 
00662 /*
00663  * Wrapper functions - implementation
00664  */
00665 
00666 /* buffered output function */
00667 static int php_b_body_write(const char *str, uint str_length TSRMLS_DC)
00668 {
00669        php_ob_append(str, str_length TSRMLS_CC);
00670        return str_length;
00671 }
00672 
00673 /* {{{ php_ub_body_write_no_header
00674  */
00675 PHPAPI int php_ub_body_write_no_header(const char *str, uint str_length TSRMLS_DC)
00676 {
00677        int result;
00678 
00679        if (OG(disable_output)) {
00680               return 0;
00681        }
00682 
00683        result = OG(php_header_write)(str, str_length TSRMLS_CC);
00684 
00685        if (OG(implicit_flush)) {
00686               sapi_flush(TSRMLS_C);
00687        }
00688 
00689        return result;
00690 }
00691 /* }}} */
00692 
00693 /* {{{ php_ub_body_write
00694  */
00695 PHPAPI int php_ub_body_write(const char *str, uint str_length TSRMLS_DC)
00696 {
00697        int result = 0;
00698 
00699        if (SG(request_info).headers_only) {
00700               if(SG(headers_sent)) {
00701                      return 0;
00702               }
00703               php_header(TSRMLS_C);
00704               zend_bailout();
00705        }
00706        if (php_header(TSRMLS_C)) {
00707               if (zend_is_compiling(TSRMLS_C)) {
00708                      OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C);
00709                      OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C);
00710               } else if (zend_is_executing(TSRMLS_C)) {
00711                      OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C);
00712                      OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C);
00713               }
00714 
00715               OG(php_body_write) = php_ub_body_write_no_header;
00716               result = php_ub_body_write_no_header(str, str_length TSRMLS_CC);
00717        }
00718 
00719        return result;
00720 }
00721 /* }}} */
00722 
00723 /* {{{ int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result)
00724  */
00725 static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result)
00726 {
00727        zval *elem;
00728 
00729        MAKE_STD_ZVAL(elem);
00730        array_init(elem);
00731 
00732        add_assoc_long(elem, "chunk_size", ob_buffer->chunk_size);
00733        if (!ob_buffer->chunk_size) {
00734               add_assoc_long(elem, "size", ob_buffer->size);
00735               add_assoc_long(elem, "block_size", ob_buffer->block_size);
00736        }
00737        if (ob_buffer->internal_output_handler) {
00738               add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_INTERNAL);
00739               add_assoc_long(elem, "buffer_size", ob_buffer->internal_output_handler_buffer_size);
00740        } else {
00741               add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER);
00742        }
00743        add_assoc_long(elem, "status", ob_buffer->status);
00744        add_assoc_string(elem, "name", ob_buffer->handler_name, 1);
00745        add_assoc_bool(elem, "del", ob_buffer->erase);
00746        add_next_index_zval(result, elem);
00747 
00748        return SUCCESS;
00749 }
00750 /* }}} */
00751 
00752 /*
00753  * USERLAND (nearly 1:1 of old output.c)
00754  */
00755 
00756 /* {{{ proto bool ob_start([string|array user_function [, int chunk_size [, bool erase]]])
00757    Turn on Output Buffering (specifying an optional output handler). */
00758 PHP_FUNCTION(ob_start)
00759 {
00760        zval *output_handler = NULL;
00761        long chunk_size = 0;
00762        zend_bool erase = 1;
00763 
00764        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/lb", &output_handler, &chunk_size, &erase) == FAILURE) {
00765               return;
00766        }
00767 
00768        if (chunk_size < 0) {
00769               chunk_size = 0;
00770        }
00771 
00772        if (php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC) == FAILURE) {
00773               RETURN_FALSE;
00774        }
00775        RETURN_TRUE;
00776 }
00777 /* }}} */
00778 
00779 /* {{{ proto bool ob_flush(void)
00780    Flush (send) contents of the output buffer. The last buffer content is sent to next buffer */
00781 PHP_FUNCTION(ob_flush)
00782 {
00783        if (zend_parse_parameters_none() == FAILURE) {
00784               return;
00785        }
00786 
00787        if (!OG(ob_nesting_level)) {
00788               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush");
00789               RETURN_FALSE;
00790        }
00791 
00792        if (!OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
00793               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer %s", OG(active_ob_buffer).handler_name);
00794               RETURN_FALSE;
00795        }
00796 
00797        php_end_ob_buffer(1, 1 TSRMLS_CC);
00798        RETURN_TRUE;
00799 }
00800 /* }}} */
00801 
00802 /* {{{ proto bool ob_clean(void)
00803    Clean (delete) the current output buffer */
00804 PHP_FUNCTION(ob_clean)
00805 {
00806        if (zend_parse_parameters_none() == FAILURE) {
00807               return;
00808        }
00809 
00810        if (!OG(ob_nesting_level)) {
00811               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
00812               RETURN_FALSE;
00813        }
00814 
00815        if (!OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
00816               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
00817               RETURN_FALSE;
00818        }
00819 
00820        php_end_ob_buffer(0, 1 TSRMLS_CC);
00821        RETURN_TRUE;
00822 }
00823 /* }}} */
00824 
00825 /* {{{ proto bool ob_end_flush(void)
00826    Flush (send) the output buffer, and delete current output buffer */
00827 PHP_FUNCTION(ob_end_flush)
00828 {
00829        if (zend_parse_parameters_none() == FAILURE) {
00830               return;
00831        }
00832 
00833        if (!OG(ob_nesting_level)) {
00834               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
00835               RETURN_FALSE;
00836        }
00837 
00838        if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
00839               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
00840               RETURN_FALSE;
00841        }
00842 
00843        php_end_ob_buffer(1, 0 TSRMLS_CC);
00844        RETURN_TRUE;
00845 }
00846 /* }}} */
00847 
00848 /* {{{ proto bool ob_end_clean(void)
00849    Clean the output buffer, and delete current output buffer */
00850 PHP_FUNCTION(ob_end_clean)
00851 {
00852        if (zend_parse_parameters_none() == FAILURE) {
00853               return;
00854        }
00855 
00856        if (!OG(ob_nesting_level)) {
00857               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
00858               RETURN_FALSE;
00859        }
00860 
00861        if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
00862               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
00863               RETURN_FALSE;
00864        }
00865 
00866        php_end_ob_buffer(0, 0 TSRMLS_CC);
00867        RETURN_TRUE;
00868 }
00869 /* }}} */
00870 
00871 /* {{{ proto bool ob_get_flush(void)
00872    Get current buffer contents, flush (send) the output buffer, and delete current output buffer */
00873 PHP_FUNCTION(ob_get_flush)
00874 {
00875        if (zend_parse_parameters_none() == FAILURE) {
00876               return;
00877        }
00878 
00879        if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
00880               RETURN_FALSE;
00881        }
00882 
00883        if (!OG(ob_nesting_level)) {
00884               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
00885               zval_dtor(return_value);
00886               RETURN_FALSE;
00887        }
00888 
00889        if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
00890               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
00891               zval_dtor(return_value);
00892               RETURN_FALSE;
00893        }
00894 
00895        php_end_ob_buffer(1, 0 TSRMLS_CC);
00896 }
00897 /* }}} */
00898 
00899 /* {{{ proto bool ob_get_clean(void)
00900    Get current buffer contents and delete current output buffer */
00901 PHP_FUNCTION(ob_get_clean)
00902 {
00903        if (zend_parse_parameters_none() == FAILURE) {
00904               return;
00905        }
00906 
00907        if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
00908               RETURN_FALSE;
00909        }
00910 
00911        if (!OG(ob_nesting_level)) {
00912               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
00913               zval_dtor(return_value);
00914               RETURN_FALSE;
00915        }
00916        if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
00917               php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
00918               zval_dtor(return_value);
00919               RETURN_FALSE;
00920        }
00921 
00922        php_end_ob_buffer(0, 0 TSRMLS_CC);
00923 }
00924 /* }}} */
00925 
00926 /* {{{ proto string ob_get_contents(void)
00927    Return the contents of the output buffer */
00928 PHP_FUNCTION(ob_get_contents)
00929 {
00930        if (zend_parse_parameters_none() == FAILURE) {
00931               return;
00932        }
00933 
00934        if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
00935               RETURN_FALSE;
00936        }
00937 }
00938 /* }}} */
00939 
00940 /* {{{ proto int ob_get_level(void)
00941    Return the nesting level of the output buffer */
00942 PHP_FUNCTION(ob_get_level)
00943 {
00944        if (zend_parse_parameters_none() == FAILURE) {
00945               return;
00946        }
00947 
00948        RETURN_LONG(OG(ob_nesting_level));
00949 }
00950 /* }}} */
00951 
00952 /* {{{ proto int ob_get_length(void)
00953    Return the length of the output buffer */
00954 PHP_FUNCTION(ob_get_length)
00955 {
00956        if (zend_parse_parameters_none() == FAILURE) {
00957               return;
00958        }
00959 
00960        if (php_ob_get_length(return_value TSRMLS_CC) == FAILURE) {
00961               RETURN_FALSE;
00962        }
00963 }
00964 /* }}} */
00965 
00966 /* {{{ proto false|array ob_list_handlers()
00967    List all output_buffers in an array */
00968 PHP_FUNCTION(ob_list_handlers)
00969 {
00970        if (zend_parse_parameters_none() == FAILURE) {
00971               return;
00972        }
00973 
00974        array_init(return_value);
00975 
00976        if (OG(ob_nesting_level)) {
00977               if (OG(ob_nesting_level) > 1) {
00978                      zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_ob_list_each, return_value);
00979               }
00980               php_ob_list_each(&OG(active_ob_buffer), return_value);
00981        }
00982 }
00983 /* }}} */
00984 
00985 /* {{{ proto false|array ob_get_status([bool full_status])
00986    Return the status of the active or all output buffers */
00987 PHP_FUNCTION(ob_get_status)
00988 {
00989        zend_bool full_status = 0;
00990 
00991        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status) == FAILURE) {
00992               return;
00993        }
00994 
00995        array_init(return_value);
00996 
00997        if (full_status) {
00998               if (OG(ob_nesting_level) > 1) {
00999                      zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *elem, void *))php_ob_buffer_status, return_value);
01000               }
01001               if (OG(ob_nesting_level) > 0 && php_ob_buffer_status(&OG(active_ob_buffer), return_value) == FAILURE) {
01002                      RETURN_FALSE;
01003               }
01004        } else if (OG(ob_nesting_level) > 0) {
01005               add_assoc_long(return_value, "level", OG(ob_nesting_level));
01006               if (OG(active_ob_buffer).internal_output_handler) {
01007                      add_assoc_long(return_value, "type", PHP_OUTPUT_HANDLER_INTERNAL);
01008               } else {
01009                      add_assoc_long(return_value, "type", PHP_OUTPUT_HANDLER_USER);
01010               }
01011               add_assoc_long(return_value, "status", OG(active_ob_buffer).status);
01012               add_assoc_string(return_value, "name", OG(active_ob_buffer).handler_name, 1);
01013               add_assoc_bool(return_value, "del", OG(active_ob_buffer).erase);
01014        }
01015 }
01016 /* }}} */
01017 
01018 /* {{{ proto void ob_implicit_flush([int flag])
01019    Turn implicit flush on/off and is equivalent to calling flush() after every output call */
01020 PHP_FUNCTION(ob_implicit_flush)
01021 {
01022        long flag = 1;
01023 
01024        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag) == FAILURE) {
01025               return;
01026        }
01027 
01028        if (flag) {
01029               php_start_implicit_flush(TSRMLS_C);
01030        } else {
01031               php_end_implicit_flush(TSRMLS_C);
01032        }
01033 }
01034 /* }}} */
01035 
01036 /* {{{ proto bool output_reset_rewrite_vars(void)
01037    Reset(clear) URL rewriter values */
01038 PHP_FUNCTION(output_reset_rewrite_vars)
01039 {
01040        if (php_url_scanner_reset_vars(TSRMLS_C) == SUCCESS) {
01041               RETURN_TRUE;
01042        } else {
01043               RETURN_FALSE;
01044        }
01045 }
01046 /* }}} */
01047 
01048 /* {{{ proto bool output_add_rewrite_var(string name, string value)
01049    Add URL rewriter values */
01050 PHP_FUNCTION(output_add_rewrite_var)
01051 {
01052        char *name, *value;
01053        int name_len, value_len;
01054 
01055        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) {
01056               return;
01057        }
01058 
01059        if (php_url_scanner_add_var(name, name_len, value, value_len, 1 TSRMLS_CC) == SUCCESS) {
01060               RETURN_TRUE;
01061        } else {
01062               RETURN_FALSE;
01063        }
01064 }
01065 /* }}} */
01066 
01067 /*
01068  * Local variables:
01069  * tab-width: 4
01070  * c-basic-offset: 4
01071  * End:
01072  * vim600: sw=4 ts=4 fdm=marker
01073  * vim<600: sw=4 ts=4
01074  */