--- /dev/null
+$Id$
+
+
+API adjustment to the old output control code:
+
+ Everything now resides beneath the php_output namespace, and there's an
+ API call for every output handler op. However, there's a thin
+ compatibility layer unless PHP_OUTPUT_NOCOMPAT is defined.
+
+ Checking output control layers status:
+ // Using OG()
+ php_output_get_status();
+
+ Starting the default output handler:
+ // php_start_ob_buffer(NULL, 0, 1 TSRMLS_CC);
+ php_output_start_default();
+
+ Starting an user handler by zval:
+ // php_start_ob_buffer(zhandler, chunk_size, erase TSRMLS_CC);
+ php_output_start_user(zhandler, chunk_size, flags);
+
+ Starting an internal handler whithout context:
+ // php_ob_set_internal_handler(my_php_output_handler_func_t, buffer_size, "output handler name", erase TSRMLS_CC);
+ php_output_start_internal(handler_name_zval, my_php_output_handler_func_t, chunk_size, flags);
+
+ Starting an internal handler with context:
+ // not possible with old API
+ php_output_handler *h;
+ h = php_output_handler_create_internal(handler_name_zval, my_php_output_handler_context_func_t, chunk_size, flags);
+ php_output_handler_set_context(h, my_context, my_context_dtor);
+ php_output_handler_start(h);
+
+ Testing whether a certain output handler has already been started:
+ // php_ob_handler_used("output handler name" TSRMLS_CC);
+ php_output_handler_started(handler_name_zval);
+
+ Flushing one output buffer:
+ // php_ob_end_buffer(1, 1 TSRMLS_CC);
+ php_output_flush();
+
+ Flushing all output buffers:
+ // not possible with old API
+ php_output_flush_all();
+
+ Cleaning one output buffer:
+ // php_ob_end_buffer(0, 1 TSRMLS_CC);
+ php_output_clean();
+
+ Cleaning all output buffers:
+ // not possible with old API
+ php_output_clean_all();
+
+ Discarding one output buffer:
+ // php_ob_end_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
+
+ Discarding all output buffers:
+ // php_ob_end_buffers(0 TSRMLS_CC);
+ php_output_discard_all();
+
+ Stopping (and dropping) one output buffer:
+ // php_ob_end_buffer(1, 0 TSRMLS_CC)
+ php_output_end();
+
+ Stopping (and dropping) all output buffers:
+ // php_ob_end_buffers(1, 0 TSRMLS_CC);
+ php_output_end_all();
+
+ Retrieving output buffers contents:
+ // php_ob_get_buffer(zstring TSRMLS_CC);
+ php_output_get_contents(zstring);
+
+ Retrieving output buffers length:
+ // php_ob_get_length(zlength TSRMLS_CC);
+ php_output_get_length(zlenght);
+
+ Retrieving output buffering level:
+ // OG(nesting_level);
+ php_output_get_level();
+
+ Issue a warning because of an output handler conflict:
+ // php_ob_init_conflict("to be started handler name", "to be tested if already started handler name" TSRMLS_CC);
+ php_output_handler_conflict(new_handler_name_zval, set_handler_name_zval);
+
+ Registering a conflict checking function, which will be checked prior starting the handler:
+ // not possible with old API, unless hardcoding into output.c
+ php_output_handler_conflict_register(handler_name_zval, my_php_output_handler_conflict_check_t);
+
+ Registering a reverse conflict checking function, which will be checked prior starting the specified foreign handler:
+ // not possible with old API
+ php_output_handler_reverse_conflict_register(foreign_handler_name_zval, my_php_output_handler_conflict_check_t);
+
+ Facilitating a context from within an output handler callable with ob_start():
+ // not possible with old API
+ php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ, (void *) &custom_ctx_ptr_ptr);
+
+ Disabling of the output handler by itself:
+ //not possible with old API
+ php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL);
+
+ Marking an output handler immutable by itself because of irreversibility of its operation:
+ // not possible with old API
+ php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL);
+
+ Restarting the output handler because of a CLEAN operation:
+ // not possible with old API
+ if (flags & PHP_OUTPUT_HANDLER_CLEAN) { ... }
+
+ Recognizing by the output handler itself if it gets discarded:
+ // not possible with old API
+ if ((flags & PHP_OUTPUT_HANDLER_CLEAN) && (flags & PHP_OUTPUT_HANDLER_FINAL)) { ... }
+
+
+Output handler hooks
+
+ The output handler can change its abilities at runtime. Eg. the gz handler can
+ remove the CLEANABLE and REMOVABLE bits when the first output has passed through it;
+ or handlers implemented in C to be used with ob_start() can contain a non-global
+ context:
+ PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ
+ pass a void*** pointer as second arg to receive the address of a pointer
+ pointer to the opaque field of the output handler context
+ PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS
+ pass a int* pointer as second arg to receive the flags set for the output handler
+ PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE
+ the second arg is ignored; marks the output handler to be neither cleanable
+ nor removable
+ PHP_OUTPUT_HANDLER_HOOK_DISABLE
+ the second arg is ignored; marks the output handler as disabled
+
+
+Open questions
+
+ Should the userland API be adjusted and unified?
+
+ Many bits of the manual (and very first implementation) do not comply
+ with the behaviour of the current (to be obsoleted) code, thus should
+ the manual or the behaviour be adjusted?
+
+END
tbytes = 0;
while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
- php_body_write(buf, nbytes TSRMLS_CC);
+ PHPWRITE(buf, nbytes);
tbytes += nbytes;
}
RETURN_LONG(tbytes);
if (PS(cache_limiter)[0] == '\0') return 0;
if (SG(headers_sent)) {
- char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
- int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
+ char *output_start_filename = php_output_get_start_filename();
+ int output_start_lineno = php_output_get_start_lineno();
if (output_start_filename) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cache limiter - headers already sent (output started at %s:%d)",
char *date_fmt = NULL;
if (SG(headers_sent)) {
- char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
- int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
+ char *output_start_filename = php_output_get_start_filename();
+ int output_start_lineno = php_output_get_start_lineno();
if (output_start_filename) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cookie - headers already sent by (output started at %s:%d)",
}
}
- if (php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC) != SUCCESS) {
+ if (php_output_start_default() != SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,"ob_start failed");
}
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error calling constructor");
}
if (EG(exception)) {
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
}
#ifdef ZEND_ENGINE_2
if (EG(exception)) {
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
Z_TYPE_PP(tmp) != IS_NULL) {
headerfault = *tmp;
}
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
soap_server_fault_ex(function, &h->retval, h TSRMLS_CC);
efree(fn_name);
if (soap_obj) {zval_ptr_dtor(&soap_obj);}
goto fail;
#ifdef ZEND_ENGINE_2
} else if (EG(exception)) {
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
zval *headerfault = NULL, **tmp;
#ifdef ZEND_ENGINE_2
if (EG(exception)) {
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
if (Z_TYPE(retval) == IS_OBJECT &&
instanceof_function(Z_OBJCE(retval), soap_fault_class_entry TSRMLS_CC)) {
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
soap_server_fault_ex(function, &retval, NULL TSRMLS_CC);
goto fail;
}
}
/* Flush buffer */
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
if (doc_return) {
/* xmlDocDumpMemoryEnc(doc_return, &buf, &size, XML_CHAR_ENCODING_UTF8); */
code = "Server";
}
/* Get output buffer and send as fault detials */
- if (php_ob_get_length(&outbuflen TSRMLS_CC) != FAILURE && Z_LVAL(outbuflen) != 0) {
+ if (php_output_get_length(&outbuflen) != FAILURE && Z_LVAL(outbuflen) != 0) {
ALLOC_INIT_ZVAL(outbuf);
- php_ob_get_buffer(outbuf TSRMLS_CC);
+ php_output_get_contents(outbuf TSRMLS_CC);
}
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_discard();
INIT_ZVAL(fault_obj);
set_soap_fault(&fault_obj, NULL, code, buffer, NULL, outbuf, NULL TSRMLS_CC);
}
if (i) {
- php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC);
+ php_output_start_default();
}
php_get_highlight_struct(&syntax_highlighter_ini);
}
if (i) {
- php_ob_get_buffer (return_value TSRMLS_CC);
- php_end_ob_buffer (0, 0 TSRMLS_CC);
+ php_output_get_contents(return_value);
+ php_output_discard();
} else {
RETURN_TRUE;
}
RETURN_FALSE;
}
- php_start_ob_buffer(NULL, 0, 1 TSRMLS_CC);
+ php_output_start_default();
file_handle.type = ZEND_HANDLE_FILENAME;
file_handle.filename = filename;
zend_destroy_file_handle(&file_handle TSRMLS_CC);
zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
- php_ob_get_buffer(return_value TSRMLS_CC);
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ php_output_get_contents(return_value);
+ php_output_discard();
return;
}
convert_to_string(expr);
if (i) {
- php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC);
+ php_output_start_default();
}
EG(error_reporting) = E_ERROR;
EG(error_reporting) = old_error_reporting;
if (i) {
- php_ob_get_buffer (return_value TSRMLS_CC);
- php_end_ob_buffer (0, 0 TSRMLS_CC);
+ php_output_get_contents(return_value);
+ php_output_discard();
} else {
RETURN_TRUE;
}
}
if (i) {
- php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC);
+ php_output_start_default();
}
zend_print_zval_r(var, 0 TSRMLS_CC);
if (i) {
- php_ob_get_buffer (return_value TSRMLS_CC);
- php_end_ob_buffer (0, 0 TSRMLS_CC);
+ php_output_get_contents(return_value);
+ php_output_discard();
} else {
RETURN_TRUE;
}
return;
if (SG(headers_sent)) {
- line = php_get_output_start_lineno(TSRMLS_C);
- file = php_get_output_start_filename(TSRMLS_C);
+ line = php_output_get_start_lineno();
+ file = php_output_get_start_filename();
}
switch(ZEND_NUM_ARGS()) {
elem_esc = php_escape_html_entities((char *)str, str_length, &new_len, 0, ENT_QUOTES, NULL TSRMLS_CC);
- written = php_body_write(elem_esc, new_len TSRMLS_CC);
+ written = PHPWRITE(elem_esc, new_len);
efree(elem_esc);
}
#if HAVE_MBSTRING
- if (php_ob_handler_used("mb_output_handler" TSRMLS_CC)) {
+ if (php_output_handler_started("mb_output_handler")) {
if (MBSTRG(current_http_output_encoding) == mbfl_no_encoding_pass) {
charset = "US-ASCII";
} else {
#endif
#if HAVE_ICONV
- if (php_ob_handler_used("ob_iconv_handler" TSRMLS_CC)) {
+ if (php_output_handler_started("ob_iconv_handler")) {
charset = ICONVG(output_encoding);
}
#endif
}
/* Andale! Andale! Yee-Hah! */
- php_start_ob_buffer(NULL, 4096, 0 TSRMLS_CC);
+ php_output_start_default();
php_print_info(flag TSRMLS_CC);
- php_end_ob_buffer(1, 0 TSRMLS_CC);
+ php_output_end();
RETURN_TRUE;
}
q = (p = url->c) + url->len;
scan:
-
-#line 114 "ext/standard/url_scanner_ex.c"
{
- YYCTYPE yych;
- goto yy0;
- ++YYCURSOR;
-yy0:
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- switch(yych){
- case '#': goto yy6;
- case ':': goto yy2;
- case '?': goto yy4;
- default: goto yy8;
- }
-yy2: ++YYCURSOR;
- goto yy3;
-yy3:
+ static unsigned char yybm[] = {
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 0, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 0, 128, 128, 128, 128, 0,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ };
+
+#line 149 "ext/standard/url_scanner_ex.c"
+ {
+ YYCTYPE yych;
+
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yybm[0+yych] & 128) {
+ goto yy8;
+ }
+ if(yych <= '9') goto yy6;
+ if(yych >= ';') goto yy4;
+ ++YYCURSOR;
#line 115 "ext/standard/url_scanner_ex.re"
-{ smart_str_append(dest, url); return; }
-#line 133 "ext/standard/url_scanner_ex.c"
-yy4: ++YYCURSOR;
- goto yy5;
-yy5:
+ { smart_str_append(dest, url); return; }
+#line 163 "ext/standard/url_scanner_ex.c"
+yy4:
+ ++YYCURSOR;
#line 116 "ext/standard/url_scanner_ex.re"
-{ sep = separator; goto scan; }
-#line 139 "ext/standard/url_scanner_ex.c"
-yy6: ++YYCURSOR;
- goto yy7;
-yy7:
+ { sep = separator; goto scan; }
+#line 168 "ext/standard/url_scanner_ex.c"
+yy6:
+ ++YYCURSOR;
#line 117 "ext/standard/url_scanner_ex.re"
-{ bash = p - 1; goto done; }
-#line 145 "ext/standard/url_scanner_ex.c"
-yy8: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy9;
-yy9: switch(yych){
- case '#': case ':': case '?': goto yy10;
- default: goto yy8;
- }
-yy10:
+ { bash = p - 1; goto done; }
+#line 173 "ext/standard/url_scanner_ex.c"
+yy8:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yybm[0+yych] & 128) {
+ goto yy8;
+ }
#line 118 "ext/standard/url_scanner_ex.re"
-{ goto scan; }
-#line 157 "ext/standard/url_scanner_ex.c"
+ { goto scan; }
+#line 183 "ext/standard/url_scanner_ex.c"
+ }
}
#line 119 "ext/standard/url_scanner_ex.re"
state_plain:
start = YYCURSOR;
-
-#line 328 "ext/standard/url_scanner_ex.c"
{
- YYCTYPE yych;
- goto yy11;
- ++YYCURSOR;
-yy11:
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- switch(yych){
- case '<': goto yy13;
- default: goto yy15;
- }
-yy13: ++YYCURSOR;
- goto yy14;
-yy14:
+ static unsigned char yybm[] = {
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 0, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ };
+
+#line 390 "ext/standard/url_scanner_ex.c"
+ {
+ YYCTYPE yych;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yybm[0+yych] & 128) {
+ goto yy15;
+ }
+ ++YYCURSOR;
#line 287 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); STATE = STATE_TAG; goto state_tag; }
-#line 345 "ext/standard/url_scanner_ex.c"
-yy15: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy16;
-yy16: switch(yych){
- case '<': goto yy17;
- default: goto yy15;
- }
-yy17:
+ { passthru(STD_ARGS); STATE = STATE_TAG; goto state_tag; }
+#line 401 "ext/standard/url_scanner_ex.c"
+yy15:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yybm[0+yych] & 128) {
+ goto yy15;
+ }
#line 288 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); goto state_plain; }
-#line 357 "ext/standard/url_scanner_ex.c"
+ { passthru(STD_ARGS); goto state_plain; }
+#line 411 "ext/standard/url_scanner_ex.c"
+ }
}
#line 289 "ext/standard/url_scanner_ex.re"
state_tag:
start = YYCURSOR;
-
-#line 365 "ext/standard/url_scanner_ex.c"
{
- YYCTYPE yych;
- goto yy18;
- ++YYCURSOR;
-yy18:
- if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
- yych = *YYCURSOR;
- switch(yych){
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- case 'G':
- case 'H':
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- case 'Q':
- case 'R':
- case 'S':
- case 'T':
- case 'U':
- case 'V':
- case 'W':
- case 'X':
- case 'Y':
- case 'Z': case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'g':
- case 'h':
- case 'i':
- case 'j':
- case 'k':
- case 'l':
- case 'm':
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'r':
- case 's':
- case 't':
- case 'u':
- case 'v':
- case 'w':
- case 'x':
- case 'y':
- case 'z': goto yy20;
- default: goto yy22;
- }
-yy20: ++YYCURSOR;
- yych = *YYCURSOR;
- goto yy25;
+ static unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 0, 0, 0, 0, 0,
+ 0, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+#line 455 "ext/standard/url_scanner_ex.c"
+ {
+ YYCTYPE yych;
+ if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+ if(yych <= '@') goto yy22;
+ if(yych <= 'Z') goto yy20;
+ if(yych <= '`') goto yy22;
+ if(yych >= '{') goto yy22;
+yy20:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ goto yy25;
yy21:
#line 294 "ext/standard/url_scanner_ex.re"
-{ handle_tag(STD_ARGS); /* Sets STATE */; passthru(STD_ARGS); if (STATE == STATE_PLAIN) goto state_plain; else goto state_next_arg; }
-#line 433 "ext/standard/url_scanner_ex.c"
-yy22: ++YYCURSOR;
- goto yy23;
-yy23:
+ { handle_tag(STD_ARGS); /* Sets STATE */; passthru(STD_ARGS); if (STATE == STATE_PLAIN) goto state_plain; else goto state_next_arg; }
+#line 471 "ext/standard/url_scanner_ex.c"
+yy22:
+ ++YYCURSOR;
#line 295 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); goto state_plain_begin; }
-#line 439 "ext/standard/url_scanner_ex.c"
-yy24: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy25;
-yy25: switch(yych){
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- case 'G':
- case 'H':
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- case 'Q':
- case 'R':
- case 'S':
- case 'T':
- case 'U':
- case 'V':
- case 'W':
- case 'X':
- case 'Y':
- case 'Z': case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'g':
- case 'h':
- case 'i':
- case 'j':
- case 'k':
- case 'l':
- case 'm':
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'r':
- case 's':
- case 't':
- case 'u':
- case 'v':
- case 'w':
- case 'x':
- case 'y':
- case 'z': goto yy24;
- default: goto yy21;
+ { passthru(STD_ARGS); goto state_plain_begin; }
+#line 476 "ext/standard/url_scanner_ex.c"
+yy24:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy25:
+ if(yybm[0+yych] & 128) {
+ goto yy24;
+ }
+ goto yy21;
}
}
#line 296 "ext/standard/url_scanner_ex.re"
state_next_arg:
start = YYCURSOR;
-
-#line 508 "ext/standard/url_scanner_ex.c"
{
- YYCTYPE yych;
- goto yy26;
- ++YYCURSOR;
-yy26:
- if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
- yych = *YYCURSOR;
- switch(yych){
- case 0x09:
- case 0x0A:
- case 0x0B: case 0x0D: case ' ': goto yy30;
- case '>': goto yy28;
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- case 'G':
- case 'H':
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- case 'Q':
- case 'R':
- case 'S':
- case 'T':
- case 'U':
- case 'V':
- case 'W':
- case 'X':
- case 'Y':
- case 'Z': case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'g':
- case 'h':
- case 'i':
- case 'j':
- case 'k':
- case 'l':
- case 'm':
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'r':
- case 's':
- case 't':
- case 'u':
- case 'v':
- case 'w':
- case 'x':
- case 'y':
- case 'z': goto yy32;
- default: goto yy34;
- }
-yy28: ++YYCURSOR;
- goto yy29;
-yy29:
+ static unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 128, 128, 128, 0, 128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 128, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+#line 532 "ext/standard/url_scanner_ex.c"
+ {
+ YYCTYPE yych;
+ if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+ if(yych <= ' ') {
+ if(yych <= 0x0C) {
+ if(yych <= 0x08) goto yy34;
+ if(yych <= 0x0B) goto yy30;
+ goto yy34;
+ } else {
+ if(yych <= 0x0D) goto yy30;
+ if(yych <= 0x1F) goto yy34;
+ goto yy30;
+ }
+ } else {
+ if(yych <= '@') {
+ if(yych != '>') goto yy34;
+ } else {
+ if(yych <= 'Z') goto yy32;
+ if(yych <= '`') goto yy34;
+ if(yych <= 'z') goto yy32;
+ goto yy34;
+ }
+ }
+ ++YYCURSOR;
#line 304 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); handle_form(STD_ARGS); goto state_plain_begin; }
-#line 579 "ext/standard/url_scanner_ex.c"
-yy30: ++YYCURSOR;
- yych = *YYCURSOR;
- goto yy37;
+ { passthru(STD_ARGS); handle_form(STD_ARGS); goto state_plain_begin; }
+#line 560 "ext/standard/url_scanner_ex.c"
+yy30:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ goto yy37;
yy31:
#line 305 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); goto state_next_arg; }
-#line 586 "ext/standard/url_scanner_ex.c"
-yy32: ++YYCURSOR;
- goto yy33;
-yy33:
+ { passthru(STD_ARGS); goto state_next_arg; }
+#line 568 "ext/standard/url_scanner_ex.c"
+yy32:
+ ++YYCURSOR;
#line 306 "ext/standard/url_scanner_ex.re"
-{ --YYCURSOR; STATE = STATE_ARG; goto state_arg; }
-#line 592 "ext/standard/url_scanner_ex.c"
-yy34: ++YYCURSOR;
- goto yy35;
-yy35:
+ { --YYCURSOR; STATE = STATE_ARG; goto state_arg; }
+#line 573 "ext/standard/url_scanner_ex.c"
+yy34:
+ ++YYCURSOR;
#line 307 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); goto state_plain_begin; }
-#line 598 "ext/standard/url_scanner_ex.c"
-yy36: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy37;
-yy37: switch(yych){
- case 0x09:
- case 0x0A:
- case 0x0B: case 0x0D: case ' ': goto yy36;
- default: goto yy31;
+ { passthru(STD_ARGS); goto state_plain_begin; }
+#line 578 "ext/standard/url_scanner_ex.c"
+yy36:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy37:
+ if(yybm[0+yych] & 128) {
+ goto yy36;
+ }
+ goto yy31;
}
}
#line 308 "ext/standard/url_scanner_ex.re"
state_arg:
start = YYCURSOR;
-
-#line 616 "ext/standard/url_scanner_ex.c"
{
- YYCTYPE yych;
- goto yy38;
- ++YYCURSOR;
-yy38:
- if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
- yych = *YYCURSOR;
- switch(yych){
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- case 'G':
- case 'H':
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- case 'Q':
- case 'R':
- case 'S':
- case 'T':
- case 'U':
- case 'V':
- case 'W':
- case 'X':
- case 'Y':
- case 'Z': case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'g':
- case 'h':
- case 'i':
- case 'j':
- case 'k':
- case 'l':
- case 'm':
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'r':
- case 's':
- case 't':
- case 'u':
- case 'v':
- case 'w':
- case 'x':
- case 'y':
- case 'z': goto yy40;
- default: goto yy42;
- }
-yy40: ++YYCURSOR;
- yych = *YYCURSOR;
- goto yy45;
+ static unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 0, 0, 0, 0, 0,
+ 0, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+#line 631 "ext/standard/url_scanner_ex.c"
+ {
+ YYCTYPE yych;
+ if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+ if(yych <= '@') goto yy42;
+ if(yych <= 'Z') goto yy40;
+ if(yych <= '`') goto yy42;
+ if(yych >= '{') goto yy42;
+yy40:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ goto yy45;
yy41:
#line 313 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); handle_arg(STD_ARGS); STATE = STATE_BEFORE_VAL; goto state_before_val; }
-#line 684 "ext/standard/url_scanner_ex.c"
-yy42: ++YYCURSOR;
- goto yy43;
-yy43:
+ { passthru(STD_ARGS); handle_arg(STD_ARGS); STATE = STATE_BEFORE_VAL; goto state_before_val; }
+#line 647 "ext/standard/url_scanner_ex.c"
+yy42:
+ ++YYCURSOR;
#line 314 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); STATE = STATE_NEXT_ARG; goto state_next_arg; }
-#line 690 "ext/standard/url_scanner_ex.c"
-yy44: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy45;
-yy45: switch(yych){
- case '-': case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- case 'G':
- case 'H':
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- case 'Q':
- case 'R':
- case 'S':
- case 'T':
- case 'U':
- case 'V':
- case 'W':
- case 'X':
- case 'Y':
- case 'Z': case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'g':
- case 'h':
- case 'i':
- case 'j':
- case 'k':
- case 'l':
- case 'm':
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'r':
- case 's':
- case 't':
- case 'u':
- case 'v':
- case 'w':
- case 'x':
- case 'y':
- case 'z': goto yy44;
- default: goto yy41;
+ { passthru(STD_ARGS); STATE = STATE_NEXT_ARG; goto state_next_arg; }
+#line 652 "ext/standard/url_scanner_ex.c"
+yy44:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy45:
+ if(yybm[0+yych] & 128) {
+ goto yy44;
+ }
+ goto yy41;
}
}
#line 315 "ext/standard/url_scanner_ex.re"
state_before_val:
start = YYCURSOR;
-
-#line 756 "ext/standard/url_scanner_ex.c"
{
- YYCTYPE yych;
- unsigned int yyaccept = 0;
- goto yy46;
- ++YYCURSOR;
-yy46:
- if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
- yych = *YYCURSOR;
- switch(yych){
- case ' ': goto yy48;
- case '=': goto yy50;
- default: goto yy52;
- }
-yy48: yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- switch(yych){
- case ' ': goto yy55;
- case '=': goto yy53;
- default: goto yy49;
- }
+ static unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 128, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+#line 705 "ext/standard/url_scanner_ex.c"
+ {
+ YYCTYPE yych;
+ unsigned int yyaccept = 0;
+ if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+ if(yych == ' ') goto yy48;
+ if(yych == '=') goto yy50;
+ goto yy52;
+yy48:
+ yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ' ') goto yy55;
+ if(yych == '=') goto yy53;
yy49:
#line 321 "ext/standard/url_scanner_ex.re"
-{ --YYCURSOR; goto state_next_arg_begin; }
-#line 780 "ext/standard/url_scanner_ex.c"
-yy50: ++YYCURSOR;
- yych = *YYCURSOR;
- goto yy54;
+ { --YYCURSOR; goto state_next_arg_begin; }
+#line 722 "ext/standard/url_scanner_ex.c"
+yy50:
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ goto yy54;
yy51:
#line 320 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); STATE = STATE_VAL; goto state_val; }
-#line 787 "ext/standard/url_scanner_ex.c"
-yy52: yych = *++YYCURSOR;
- goto yy49;
-yy53: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy54;
-yy54: switch(yych){
- case ' ': goto yy53;
- default: goto yy51;
- }
-yy55: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy56;
-yy56: switch(yych){
- case ' ': goto yy55;
- case '=': goto yy53;
- default: goto yy57;
- }
-yy57: YYCURSOR = YYMARKER;
- switch(yyaccept){
- case 0: goto yy49;
+ { passthru(STD_ARGS); STATE = STATE_VAL; goto state_val; }
+#line 730 "ext/standard/url_scanner_ex.c"
+yy52:
+ yych = *++YYCURSOR;
+ goto yy49;
+yy53:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy54:
+ if(yybm[0+yych] & 128) {
+ goto yy53;
+ }
+ goto yy51;
+yy55:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yych == ' ') goto yy55;
+ if(yych == '=') goto yy53;
+ YYCURSOR = YYMARKER;
+ switch(yyaccept){
+ case 0: goto yy49;
+ }
}
}
#line 322 "ext/standard/url_scanner_ex.re"
state_val:
start = YYCURSOR;
-
-#line 819 "ext/standard/url_scanner_ex.c"
{
- YYCTYPE yych;
- unsigned int yyaccept = 0;
- goto yy58;
- ++YYCURSOR;
-yy58:
- if((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
- yych = *YYCURSOR;
- switch(yych){
- case 0x09:
- case 0x0A: case 0x0D: case ' ': case '>': goto yy64;
- case '"': goto yy60;
- case '\'': goto yy62;
- default: goto yy63;
- }
-yy60: yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- goto yy77;
+ static unsigned char yybm[] = {
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 160, 160, 248, 248, 160, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 160, 248, 56, 248, 248, 248, 248, 200,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 0, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248,
+ };
+
+#line 797 "ext/standard/url_scanner_ex.c"
+ {
+ YYCTYPE yych;
+ unsigned int yyaccept = 0;
+ if((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+ yych = *YYCURSOR;
+ if(yych <= ' ') {
+ if(yych <= 0x0C) {
+ if(yych <= 0x08) goto yy63;
+ if(yych <= 0x0A) goto yy64;
+ goto yy63;
+ } else {
+ if(yych <= 0x0D) goto yy64;
+ if(yych <= 0x1F) goto yy63;
+ goto yy64;
+ }
+ } else {
+ if(yych <= '&') {
+ if(yych != '"') goto yy63;
+ } else {
+ if(yych <= '\'') goto yy62;
+ if(yych == '>') goto yy64;
+ goto yy63;
+ }
+ }
+ yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ goto yy77;
yy61:
#line 330 "ext/standard/url_scanner_ex.re"
-{ handle_val(STD_ARGS, 0, ' '); goto state_next_arg_begin; }
-#line 841 "ext/standard/url_scanner_ex.c"
-yy62: yyaccept = 0;
- yych = *(YYMARKER = ++YYCURSOR);
- goto yy69;
-yy63: yych = *++YYCURSOR;
- goto yy67;
-yy64: ++YYCURSOR;
- goto yy65;
-yy65:
+ { handle_val(STD_ARGS, 0, ' '); goto state_next_arg_begin; }
+#line 828 "ext/standard/url_scanner_ex.c"
+yy62:
+ yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ goto yy69;
+yy63:
+ yych = *++YYCURSOR;
+ goto yy67;
+yy64:
+ ++YYCURSOR;
#line 331 "ext/standard/url_scanner_ex.re"
-{ passthru(STD_ARGS); goto state_next_arg_begin; }
-#line 852 "ext/standard/url_scanner_ex.c"
-yy66: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy67;
-yy67: switch(yych){
- case 0x09:
- case 0x0A: case 0x0D: case ' ': case '>': goto yy61;
- default: goto yy66;
- }
-yy68: yyaccept = 0;
- YYMARKER = ++YYCURSOR;
- if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
- yych = *YYCURSOR;
- goto yy69;
-yy69: switch(yych){
- case 0x09:
- case 0x0A: case 0x0D: case ' ': goto yy72;
- case '\'': goto yy70;
- case '>': goto yy61;
- default: goto yy68;
- }
-yy70: ++YYCURSOR;
- switch((yych = *YYCURSOR)) {
- case 0x09:
- case 0x0A: case 0x0D: case ' ': case '>': goto yy71;
- default: goto yy66;
- }
+ { passthru(STD_ARGS); goto state_next_arg_begin; }
+#line 840 "ext/standard/url_scanner_ex.c"
+yy66:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy67:
+ if(yybm[0+yych] & 8) {
+ goto yy66;
+ }
+ goto yy61;
+yy68:
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+yy69:
+ if(yybm[0+yych] & 16) {
+ goto yy68;
+ }
+ if(yych <= '&') goto yy72;
+ if(yych >= '(') goto yy61;
+ ++YYCURSOR;
+ if(yybm[0+(yych = *YYCURSOR)] & 8) {
+ goto yy66;
+ }
yy71:
#line 329 "ext/standard/url_scanner_ex.re"
-{ handle_val(STD_ARGS, 1, '\''); goto state_next_arg_begin; }
-#line 883 "ext/standard/url_scanner_ex.c"
-yy72: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy73;
-yy73: switch(yych){
- case '\'': goto yy75;
- case '>': goto yy74;
- default: goto yy72;
- }
-yy74: YYCURSOR = YYMARKER;
- switch(yyaccept){
- case 0: goto yy61;
- }
-yy75: yych = *++YYCURSOR;
- goto yy71;
-yy76: yyaccept = 0;
- YYMARKER = ++YYCURSOR;
- if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
- yych = *YYCURSOR;
- goto yy77;
-yy77: switch(yych){
- case 0x09:
- case 0x0A: case 0x0D: case ' ': goto yy80;
- case '"': goto yy78;
- case '>': goto yy61;
- default: goto yy76;
- }
-yy78: ++YYCURSOR;
- switch((yych = *YYCURSOR)) {
- case 0x09:
- case 0x0A: case 0x0D: case ' ': case '>': goto yy79;
- default: goto yy66;
- }
+ { handle_val(STD_ARGS, 1, '\''); goto state_next_arg_begin; }
+#line 868 "ext/standard/url_scanner_ex.c"
+yy72:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yybm[0+yych] & 32) {
+ goto yy72;
+ }
+ if(yych <= '=') goto yy75;
+yy74:
+ YYCURSOR = YYMARKER;
+ switch(yyaccept){
+ case 0: goto yy61;
+ }
+yy75:
+ yych = *++YYCURSOR;
+ goto yy71;
+yy76:
+ yyaccept = 0;
+ YYMARKER = ++YYCURSOR;
+ if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+yy77:
+ if(yybm[0+yych] & 64) {
+ goto yy76;
+ }
+ if(yych <= '!') goto yy80;
+ if(yych >= '#') goto yy61;
+ ++YYCURSOR;
+ if(yybm[0+(yych = *YYCURSOR)] & 8) {
+ goto yy66;
+ }
yy79:
#line 328 "ext/standard/url_scanner_ex.re"
-{ handle_val(STD_ARGS, 1, '"'); goto state_next_arg_begin; }
-#line 920 "ext/standard/url_scanner_ex.c"
-yy80: ++YYCURSOR;
- if(YYLIMIT == YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- goto yy81;
-yy81: switch(yych){
- case '"': goto yy82;
- case '>': goto yy74;
- default: goto yy80;
+ { handle_val(STD_ARGS, 1, '"'); goto state_next_arg_begin; }
+#line 903 "ext/standard/url_scanner_ex.c"
+yy80:
+ ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yybm[0+yych] & 128) {
+ goto yy80;
+ }
+ if(yych >= '>') goto yy74;
+ ++YYCURSOR;
+ yych = *YYCURSOR;
+ goto yy79;
}
-yy82: ++YYCURSOR;
- yych = *YYCURSOR;
- goto yy79;
}
#line 332 "ext/standard/url_scanner_ex.re"
if (! BG(url_adapt_state_ex).active) {
php_url_scanner_ex_activate(TSRMLS_C);
- php_ob_set_internal_handler(php_url_scanner_output_handler, 0, "URL-Rewriter", 1 TSRMLS_CC);
+ php_output_start_internal("URL-Rewriter", php_url_scanner_output_handler, 0, PHP_OUTPUT_HANDLER_STDFLAGS);
BG(url_adapt_state_ex).active = 1;
}
if (! BG(url_adapt_state_ex).active) {
php_url_scanner_ex_activate(TSRMLS_C);
- php_ob_set_internal_handler(php_url_scanner_output_handler, 0, "URL-Rewriter", 1 TSRMLS_CC);
+ php_output_start_internal("URL-Rewriter", php_url_scanner_output_handler, 0, PHP_OUTPUT_HANDLER_STDFLAGS);
BG(url_adapt_state_ex).active = 1;
}
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
- | Authors: Jani Lehtimäki <jkl@njet.net> |
+ | Authors: Jani Lehtim�i <jkl@njet.net> |
| Thies C. Arntzen <thies@thieso.net> |
| Sascha Schumann <sascha@schumann.cx> |
+----------------------------------------------------------------------+
}
if (return_output) {
- php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC);
+ php_output_start_default();
}
/* UTODO
php_var_export(&var, 1 TSRMLS_CC);
if (return_output) {
- php_ob_get_buffer (return_value TSRMLS_CC);
- php_end_ob_buffer (0, 0 TSRMLS_CC);
+ php_output_get_contents(return_value);
+ php_output_discard();
}
}
/* }}} */
PHP_RINIT_FUNCTION(tidy)
{
if (INI_BOOL("tidy.clean_output") == TRUE) {
- if (php_start_ob_buffer_named("ob_tidyhandler", 0, 1 TSRMLS_CC) == FAILURE) {
+ zval *name;
+ MAKE_STD_ZVAL(name);
+ ZVAL_ASCII_STRINGL(name, "ob_tidyhandler", sizeof("ob_tidyhandler"), ZSTR_DUPLICATE);
+ if (php_output_start_user(name, 0, PHP_OUTPUT_HANDLER_STDFLAGS) == FAILURE) {
zend_error(E_NOTICE, "Failure installing Tidy output buffering.");
}
+ zval_ptr_dtor(&name);
}
return SUCCESS;
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
- | Stefan Röhrich <sr@linux.de> |
+ | Stefan R�rich <sr@linux.de> |
+----------------------------------------------------------------------+
*/
PHP_FUNCTION(zlib_get_coding_type);
int php_enable_output_compression(int buffer_size TSRMLS_DC);
-int php_ob_gzhandler_check(TSRMLS_D);
+int php_ob_gzhandler_check(zval *handler_name TSRMLS_DC);
php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
extern php_stream_ops php_stream_gzio_ops;
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
- | Stefan Röhrich <sr@linux.de> |
+ | Stefan R�rich <sr@linux.de> |
| Zeev Suraski <zeev@zend.com> |
| Jade Nicoletti <nicoletti@nns.ch> |
+----------------------------------------------------------------------+
*/
PHP_MINIT_FUNCTION(zlib)
{
+ zval tmp;
#ifdef ZTS
ts_allocate_id(&zlib_globals_id, sizeof(zend_zlib_globals), (ts_allocate_ctor) php_zlib_init_globals, NULL);
#endif
php_register_url_stream_wrapper("compress.zlib", &php_stream_gzip_wrapper TSRMLS_CC);
php_stream_filter_register_factory("zlib.*", &php_zlib_filter_factory TSRMLS_CC);
+ INIT_PZVAL(&tmp);
+ ZVAL_ASCII_STRINGL(&tmp, "ob_gzhandler", sizeof("ob_gzhandler")-1, 0);
+ php_output_handler_conflict_register(&tmp, php_ob_gzhandler_check);
REGISTER_LONG_CONSTANT("FORCE_GZIP", CODING_GZIP, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FORCE_DEFLATE", CODING_DEFLATE, CONST_CS | CONST_PERSISTENT);
/* {{{ php_ob_gzhandler_check
*/
-int php_ob_gzhandler_check(TSRMLS_D)
+int php_ob_gzhandler_check(zval *handler_name TSRMLS_DC)
{
/* check for wrong usages */
- if (OG(ob_nesting_level > 0)) {
- if (php_ob_handler_used("ob_gzhandler" TSRMLS_CC)) {
+ if (php_output_get_level() > 0) {
+ zval tmp;
+
+ if (php_output_handler_started(handler_name)) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler 'ob_gzhandler' cannot be used twice");
return FAILURE;
}
- if (php_ob_handler_used("mb_output_handler" TSRMLS_CC)) {
+ INIT_PZVAL(&tmp);
+ ZVAL_ASCII_STRINGL(&tmp, "mb_output_handler", sizeof("mb_output_handler")-1, ZSTR_DUPLICATE);
+ if (php_output_handler_started(&tmp)) {
+ zval_dtor(&tmp);
php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler 'ob_gzhandler' cannot be used after 'mb_output_handler'");
return FAILURE;
}
- if (php_ob_handler_used("URL-Rewriter" TSRMLS_CC)) {
+ zval_dtor(&tmp);
+ ZVAL_ASCII_STRINGL(&tmp, "URL-Reqriter", sizeof("URL-Rewriter")-1, ZSTR_DUPLICATE);
+ if (php_output_handler_started(&tmp)) {
+ zval_dtor(&tmp);
php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler 'ob_gzhandler' cannot be used after 'URL-Rewriter'");
return FAILURE;
}
- if (php_ob_init_conflict("ob_gzhandler", "zlib output compression" TSRMLS_CC)) {
+ zval_dtor(&tmp);
+ ZVAL_ASCII_STRINGL(&tmp, "zlib output compression", sizeof("zlib output compression")-1, ZSTR_DUPLICATE);
+ if (php_output_handler_conflict(handler_name, &tmp)) {
+ zval_dtor(&tmp);
return FAILURE;
}
+ zval_dtor(&tmp);
}
return SUCCESS;
}
-
/* }}} */
/* {{{ proto string ob_gzhandler(string str, int mode)
return;
}
- if(ZLIBG(ob_gzhandler_status) == -1)
+ if(ZLIBG(ob_gzhandler_status) == -1) {
RETURN_FALSE;
+ }
zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
|| zend_hash_find(PG(http_globals)[TRACK_VARS_SERVER]->value.ht, "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING"), (void **) &a_encoding) == FAILURE
) {
ZLIBG(ob_gzhandler_status) = -1;
- RETURN_FALSE;
- }
-
- 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))) {
- ZLIBG(compression_coding) = CODING_GZIP;
- } else if (php_memnstr(Z_STRVAL_PP(a_encoding), "deflate", 7, Z_STRVAL_PP(a_encoding) + Z_STRLEN_PP(a_encoding))) {
- ZLIBG(compression_coding) = CODING_DEFLATE;
} else {
- ZLIBG(ob_gzhandler_status) = -1;
+ 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))) {
+ ZLIBG(compression_coding) = CODING_GZIP;
+ } else if (php_memnstr(Z_STRVAL_PP(a_encoding), "deflate", 7, Z_STRVAL_PP(a_encoding) + Z_STRLEN_PP(a_encoding))) {
+ ZLIBG(compression_coding) = CODING_DEFLATE;
+ } else {
+ ZLIBG(ob_gzhandler_status) = -1;
+ }
+ }
+
+ if (ZLIBG(ob_gzhandler_status == -1)) {
+ /* don't call this handler any more */
+ php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL);
RETURN_FALSE;
}
}
if (return_original) {
+ /* don't call this handler any more */
+ php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL);
/* return the original string */
RETURN_STRINGL(string, string_len, 1);
+ } else {
+ /* don't allow cleaning and removing any longer */
+ php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL);
}
}
/* }}} */
*/
int php_enable_output_compression(int buffer_size TSRMLS_DC)
{
- zval **a_encoding;
+ zval **a_encoding, *output_handler;
zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
return FAILURE;
}
- php_ob_set_internal_handler(php_gzip_output_handler, (uint)buffer_size, "zlib output compression", 0 TSRMLS_CC);
-
- if (ZLIBG(output_handler) && strlen(ZLIBG(output_handler))) {
- php_start_ob_buffer_named(ZLIBG(output_handler), 0, 1 TSRMLS_CC);
+ MAKE_STD_ZVAL(output_handler);
+ ZVAL_ASCII_STRINGL(output_handler, "zlib output compression", sizeof("zlib output compression")-1, ZSTR_DUPLICATE);
+ php_output_start_internal(output_handler, php_gzip_output_handler, buffer_size, PHP_OUTPUT_HANDLER_STDFLAGS);
+ zval_ptr_dtor(&output_handler);
+
+ if (ZLIBG(output_handler) && *ZLIBG(output_handler)) {
+ MAKE_STD_ZVAL(output_handler);
+ ZVAL_ASCII_STRING(output_handler, ZLIBG(output_handler), ZSTR_DUPLICATE);
+ php_output_start_user(output_handler, 0, PHP_OUTPUT_HANDLER_STDFLAGS);
+ zval_ptr_dtor(&output_handler);
}
return SUCCESS;
}
int http_response_code;
if (SG(headers_sent) && !SG(request_info).no_headers) {
- char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
- int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
+ char *output_start_filename = php_output_get_start_filename();
+ int output_start_lineno = php_output_get_start_lineno();
if (output_start_filename) {
sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
}
#if HAVE_ZLIB
+ /* TODO: move to zlib.c */
/* Add output compression headers at this late stage in order to make
it possible to switch it off inside the script. */
#define PHP_INI_OPTION_HEADERS_SENT(option_name) \
if (SG(headers_sent)) { \
- char *output_start_filename = php_get_output_start_filename(TSRMLS_C); \
- int output_start_lineno = php_get_output_start_lineno(TSRMLS_C); \
+ char *output_start_filename = php_output_get_start_filename(); \
+ int output_start_lineno = php_output_get_start_lineno(); \
if (output_start_filename) { \
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Option " #option_name " cannot be changed after headers have been sent (output started at %s:%d)", \
output_start_filename, output_start_lineno); \
php_log_err(log_buffer TSRMLS_CC);
efree(log_buffer);
}
- if (PG(display_errors)
- && ((module_initialized && !PG(during_request_startup))
- || (PG(display_startup_errors)
- && (OG(php_body_write)==php_default_output_func || OG(php_body_write)==php_ub_body_write_no_header || OG(php_body_write)==php_ub_body_write)
- )
- )
- ) {
-
+ if (PG(display_errors) && ((module_initialized && !PG(during_request_startup)) || (PG(display_startup_errors)))) {
if (PG(xmlrpc_errors)) {
php_printf("<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>%ld</int></value></member><member><name>faultString</name><value><string>%s:%s in %s on line %d</string></value></member></struct></value></fault></methodResponse>", PG(xmlrpc_error_number), error_type_str, buffer, error_filename, error_lineno);
} else {
zend_try {
PG(during_request_startup) = 1;
- php_output_activate(TSRMLS_C);
+ php_output_activate();
/* initialize global variables */
PG(modules_activated) = 0;
}
if (PG(output_handler) && PG(output_handler)[0]) {
- php_start_ob_buffer_named(PG(output_handler), 0, 1 TSRMLS_CC);
+ zval *oh;
+
+ MAKE_STD_ZVAL(oh);
+ ZVAL_ASCII_STRING(oh, PG(output_handler), ZSTR_DUPLICATE);
+ php_output_start_user(oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS);
+ zval_ptr_dtor(&oh);
} else if (PG(output_buffering)) {
- if (PG(output_buffering)>1) {
- php_start_ob_buffer(NULL, PG(output_buffering), 1 TSRMLS_CC);
- } else {
- php_start_ob_buffer(NULL, 0, 1 TSRMLS_CC);
- }
+ php_output_start_user(NULL, PG(output_buffering) > 1 ? PG(output_buffering) : 0, PHP_OUTPUT_HANDLER_STDFLAGS);
} else if (PG(implicit_flush)) {
- php_start_implicit_flush(TSRMLS_C);
+ php_output_set_implicit_flush(1);
}
/* We turn this off in php_execute_script() */
return FAILURE;
}
- php_output_activate(TSRMLS_C);
+ php_output_activate();
sapi_activate(TSRMLS_C);
php_hash_environment(TSRMLS_C);
zend_try {
PG(during_request_startup) = 1;
- php_output_activate(TSRMLS_C);
if (PG(expose_php)) {
sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1);
}
return FAILURE;
}
- php_output_activate(TSRMLS_C);
+ php_output_activate();
sapi_activate_headers_only(TSRMLS_C);
php_hash_environment(TSRMLS_C);
/* 3. Flush all output buffers */
zend_try {
- php_end_ob_buffers((zend_bool)(SG(request_info).headers_only?0:1) TSRMLS_CC);
+ if (SG(request_info).headers_only) {
+ php_output_discard_all();
+ } else {
+ php_output_end_all();
+ }
+ php_output_deactivate();
} zend_end_try();
/* 4. Send the set HTTP headers (note: This must be done AFTER php_end_ob_buffers() !!) */
/* }}} */
-/* {{{ php_body_write_wrapper
+/* {{{ php_output_wrapper
*/
-static int php_body_write_wrapper(const char *str, uint str_length)
+static int php_output_wrapper(const char *str, uint str_length)
{
TSRMLS_FETCH();
- return php_body_write(str, str_length TSRMLS_CC);
+ return php_output_write(str, str_length);
}
/* }}} */
zuf.error_function = php_error_cb;
zuf.printf_function = php_printf;
- zuf.write_function = php_body_write_wrapper;
+ zuf.write_function = php_output_wrapper;
zuf.fopen_function = php_fopen_wrapper_for_zend;
zuf.message_handler = php_message_handler_for_zend;
zuf.block_interruptions = sapi_module.block_interruptions;
REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS);
REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS);
REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS);
- php_output_register_constants(TSRMLS_C);
+ php_output_register_constants();
php_rfc1867_register_constants(TSRMLS_C);
if (php_startup_ticks(TSRMLS_C) == FAILURE) {
zend_ini_global_shutdown(TSRMLS_C);
#endif
+ php_output_shutdown();
+
module_initialized = 0;
if (PG(last_error_message)) {
free(PG(last_error_message));
TSRMLS_FETCH();
PG(connection_status) = PHP_CONNECTION_ABORTED;
- php_output_set_status(0 TSRMLS_CC);
+ php_output_set_status(PHP_OUTPUT_DISABLED);
if (!PG(ignore_user_abort)) {
zend_bailout();
-/*
+/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Authors: Zeev Suraski <zeev@zend.com> |
| Thies C. Arntzen <thies@thieso.net> |
| Marcus Boerger <helly@php.net> |
+ | New API: Michael Wallner <mike@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
+#ifndef PHP_OUTPUT_DEBUG
+# define PHP_OUTPUT_DEBUG 0
+#endif
+#ifndef PHP_OUTPUT_NOINLINE
+# define PHP_OUTPUT_NOINLINE 0
+#endif
+
#include "php.h"
#include "ext/standard/head.h"
-#include "ext/standard/basic_functions.h"
#include "ext/standard/url_scanner_ex.h"
-#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
-#include "ext/zlib/php_zlib.h"
-#endif
#include "SAPI.h"
+#include "zend_stack.h"
+#include "php_output.h"
-#define OB_DEFAULT_HANDLER_NAME "default output handler"
-
-/* output functions */
-static int php_b_body_write(const char *str, uint str_length TSRMLS_DC);
+ZEND_DECLARE_MODULE_GLOBALS(output);
-static int php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC);
-static void php_ob_append(const char *text, uint text_length TSRMLS_DC);
-#if 0
-static void php_ob_prepend(const char *text, uint text_length);
+#if PHP_OUTPUT_NOINLINE || PHP_OUTPUT_DEBUG
+# undef inline
+# define inline
#endif
-#ifdef ZTS
-int output_globals_id;
-#else
-php_output_globals output_globals;
-#endif
+/* {{{ aliases, conflict and reverse conflict hash tables */
+static HashTable php_output_handler_aliases;
+static HashTable php_output_handler_conflicts;
+static HashTable php_output_handler_reverse_conflicts;
+/* }}} */
+
+/* {{{ forward declarations */
+static inline int php_output_lock_error(int op TSRMLS_DC);
+static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC);
+
+static inline php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags);
+static inline int php_output_handler_op(php_output_handler *handler, php_output_context *context);
+static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC);
+static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry);
+
+static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC);
+static inline void php_output_context_reset(php_output_context *context);
+static inline void php_output_context_swap(php_output_context *context);
+static inline void php_output_context_dtor(php_output_context *context);
+
+static inline int php_output_stack_pop(int discard, int shutdown TSRMLS_DC);
-/* {{{ php_default_output_func */
-PHPAPI int php_default_output_func(const char *str, uint str_len TSRMLS_DC)
+static int php_output_stack_apply_op(void *h, void *c);
+static int php_output_stack_apply_clean(void *h, void *c);
+static int php_output_stack_apply_list(void *h, void *z);
+static int php_output_stack_apply_status(void *h, void *z);
+
+static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context);
+static int php_output_handler_default_func(void **handler_context, php_output_context *output_context);
+static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context);
+/* }}} */
+
+/* {{{ static void php_output_init_globals(zend_output_globals *G)
+ Initialize the module globals on MINIT */
+static inline void php_output_init_globals(zend_output_globals *G)
{
- fwrite(str, 1, str_len, stderr);
- return str_len;
+ memset(G, 0, sizeof(*G));
}
/* }}} */
-/* {{{ php_output_init_globals */
-static void php_output_init_globals(php_output_globals *output_globals_p TSRMLS_DC)
+/* {{{ void php_output_startup(void)
+ Set up module globals and initalize the conflict and reverse conflict hash tables */
+PHPAPI void php_output_startup(void)
{
- OG(php_body_write) = php_default_output_func;
- OG(php_header_write) = php_default_output_func;
- OG(implicit_flush) = 0;
- OG(output_start_filename) = NULL;
- OG(output_start_lineno) = 0;
+ ZEND_INIT_MODULE_GLOBALS(output, php_output_init_globals, NULL);
+ zend_hash_init(&php_output_handler_aliases, 0, NULL, NULL, 1);
+ zend_hash_init(&php_output_handler_conflicts, 0, NULL, NULL, 1);
+ zend_hash_init(&php_output_handler_reverse_conflicts, 0, NULL, (void (*)(void *)) zend_hash_destroy, 1);
}
/* }}} */
+/* {{{ void php_output_shutdown(void)
+ Destroy module globals and the conflict and reverse conflict hash tables */
+PHPAPI void php_output_shutdown(void)
+{
+ zend_hash_destroy(&php_output_handler_aliases);
+ zend_hash_destroy(&php_output_handler_conflicts);
+ zend_hash_destroy(&php_output_handler_reverse_conflicts);
+}
+/* }}} */
-/* {{{ php_output_startup
- Start output layer */
-PHPAPI void php_output_startup(void)
+/* {{{ SUCCESS|FAILURE php_output_activate(TSRMLS_D)
+ Reset output globals and setup the output handler stack */
+PHPAPI int _php_output_activate(TSRMLS_D)
{
#ifdef ZTS
- ts_allocate_id(&output_globals_id, sizeof(php_output_globals), (ts_allocate_ctor) php_output_init_globals, NULL);
-#else
- php_output_init_globals(&output_globals TSRMLS_CC);
+ memset((*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)], 0, sizeof(zend_output_globals));
+#else
+ memset(&output_globals, 0, sizeof(zend_output_globals));
#endif
+ if (SUCCESS != zend_stack_init(&OG(handlers))) {
+ return FAILURE;
+ }
+
+ MAKE_STD_ZVAL(OG(default_output_handler_name));
+ ZVAL_ASCII_STRINGL(OG(default_output_handler_name), "default output handler", sizeof("default output handler")-1, ZSTR_DUPLICATE);
+ MAKE_STD_ZVAL(OG(devnull_output_handler_name));
+ ZVAL_ASCII_STRINGL(OG(devnull_output_handler_name), "null output handler", sizeof("null output handler")-1, ZSTR_DUPLICATE);
+
+ return SUCCESS;
}
/* }}} */
-
-/* {{{ php_output_activate
- Initilize output global for activation */
-PHPAPI void php_output_activate(TSRMLS_D)
+/* {{{ void php_output_deactivate(TSRMLS_D)
+ Destroy the output handler stack */
+PHPAPI void _php_output_deactivate(TSRMLS_D)
{
- OG(php_body_write) = php_ub_body_write;
- OG(php_header_write) = sapi_module.ub_write;
- OG(ob_nesting_level) = 0;
- OG(ob_lock) = 0;
- OG(disable_output) = 0;
- OG(output_start_filename) = NULL;
- OG(output_start_lineno) = 0;
+ php_output_handler **handler = NULL;
+
+ OG(active) = NULL;
+ OG(running) = NULL;
+ /* release all output handlers */
+ while (SUCCESS == zend_stack_top(&OG(handlers), (void *) &handler)) {
+ php_output_handler_free(handler);
+ zend_stack_del_top(&OG(handlers));
+ }
+ zend_stack_destroy(&OG(handlers));
+
+ zval_ptr_dtor(&OG(default_output_handler_name));
+ zval_ptr_dtor(&OG(devnull_output_handler_name));
}
/* }}} */
+/* {{{ void _php_output_register_constants() */
+PHPAPI void _php_output_register_constants(TSRMLS_D)
+{
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_WRITE", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSH", PHP_OUTPUT_HANDLER_FLUSH, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEAN", PHP_OUTPUT_HANDLER_CLEAN, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FINAL", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
+
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEANABLE", PHP_OUTPUT_HANDLER_CLEANABLE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_REMOVABLE", PHP_OUTPUT_HANDLER_REMOVABLE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STDFLAGS", PHP_OUTPUT_HANDLER_STDFLAGS, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STARTED", PHP_OUTPUT_HANDLER_STARTED, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_DISABLED", PHP_OUTPUT_HANDLER_DISABLED, CONST_CS | CONST_PERSISTENT);
+}
+/* }}} */
-/* {{{ php_output_set_status
- Toggle output status. Do NOT use in application code, only in SAPIs where appropriate. */
-PHPAPI void php_output_set_status(zend_bool status TSRMLS_DC)
+/* {{{ void php_output_set_status(int status)
+ Used by SAPIs to disable output */
+PHPAPI void _php_output_set_status(int status TSRMLS_DC)
{
- OG(disable_output) = !status;
+ OG(flags) = status & 0xf;
}
/* }}} */
-/* {{{ php_output_register_constants */
-void php_output_register_constants(TSRMLS_D)
+/* {{{ int php_output_get_status()
+ Get output control status */
+PHPAPI int _php_output_get_status(TSRMLS_D)
{
- REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT);
- REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_CONT, CONST_CS | CONST_PERSISTENT);
- REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_END, CONST_CS | CONST_PERSISTENT);
+ return OG(flags)
+ | (OG(active) ? PHP_OUTPUT_ACTIVE : 0)
+ | (OG(running)? PHP_OUTPUT_LOCKED : 0);
}
/* }}} */
+/* {{{ zval *php_output_get_default_handler_name() */
+PHPAPI zval *_php_output_get_default_handler_name(TSRMLS_D)
+{
+ return OG(default_output_handler_name);
+}
+/* }}} */
-/* {{{ php_body_wirte
- * Write body part */
-PHPAPI int php_body_write(const char *str, uint str_length TSRMLS_DC)
+/* {{{ zval *php_output_get_devnull_handler_name() */
+PHPAPI zval *_php_output_get_devnull_handler_name(TSRMLS_D)
{
- return OG(php_body_write)(str, str_length TSRMLS_CC);
+ return OG(devnull_output_handler_name);
}
/* }}} */
-/* {{{ php_header_wirte
- * Write HTTP header */
-PHPAPI int php_header_write(const char *str, uint str_length TSRMLS_DC)
+/* {{{ int php_output_write_unbuffered(const char *str, size_t len)
+ Unbuffered write */
+PHPAPI int _php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC)
{
- if (OG(disable_output)) {
+ if (OG(flags) & PHP_OUTPUT_DISABLED) {
return 0;
- } else {
- return OG(php_header_write)(str, str_length TSRMLS_CC);
}
+ return sapi_module.ub_write(str, len TSRMLS_CC);
}
/* }}} */
-/* {{{ php_start_ob_buffer
- * Start output buffering */
-PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
+/* {{{ int php_output_write(const char *str, size_t len)
+ Buffered write */
+PHPAPI int _php_output_write(const char *str, size_t len TSRMLS_DC)
{
- uint initial_size, block_size;
-
- if (OG(ob_lock)) {
- if (SG(headers_sent) && !SG(request_info).headers_only) {
- OG(php_body_write) = php_ub_body_write_no_header;
- } else {
- OG(php_body_write) = php_ub_body_write;
- }
- OG(ob_nesting_level) = 0;
- php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers");
- return FAILURE;
+ if (OG(flags) & PHP_OUTPUT_DISABLED) {
+ return 0;
}
- if (chunk_size > 0) {
- if (chunk_size==1) {
- chunk_size = 4096;
+ php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len TSRMLS_CC);
+ return (int) len;
+}
+/* }}} */
+
+/* {{{ void php_output_flush()
+ Flush the most recent output handlers buffer */
+PHPAPI void _php_output_flush(TSRMLS_D)
+{
+ php_output_context context;
+
+ if (OG(active)) {
+ php_output_context_init(&context, PHP_OUTPUT_HANDLER_FLUSH TSRMLS_CC);
+ php_output_handler_op(OG(active), &context);
+ if (context.out.data && context.out.used) {
+ zend_stack_del_top(&OG(handlers));
+ php_output_write(context.out.data, context.out.used);
+ zend_stack_push(&OG(handlers), &OG(active), sizeof(php_output_handler *));
}
- initial_size = (chunk_size*3/2);
- block_size = chunk_size/2;
- } else {
- initial_size = 40*1024;
- block_size = 10*1024;
+ php_output_context_dtor(&context);
}
- return php_ob_init(initial_size, block_size, output_handler, chunk_size, erase TSRMLS_CC);
}
/* }}} */
-/* {{{ php_start_ob_buffer_named
- * Start output buffering */
-PHPAPI int php_start_ob_buffer_named(const char *output_handler_name, uint chunk_size, zend_bool erase TSRMLS_DC)
+/* {{{ void php_output_flush_all()
+ Flush all output buffers subsequently */
+PHPAPI void _php_output_flush_all(TSRMLS_D)
{
- zval *output_handler;
- int result;
-
- ALLOC_INIT_ZVAL(output_handler);
- Z_STRLEN_P(output_handler) = strlen(output_handler_name); /* this can be optimized */
- Z_STRVAL_P(output_handler) = estrndup(output_handler_name, Z_STRLEN_P(output_handler));
- Z_TYPE_P(output_handler) = IS_STRING;
- result = php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC);
- zval_dtor(output_handler);
- FREE_ZVAL(output_handler);
- return result;
+ if (OG(active)) {
+ php_output_op(PHP_OUTPUT_HANDLER_FLUSH, NULL, 0 TSRMLS_CC);
+ }
}
/* }}} */
-/* {{{ php_end_ob_buffer
- * End output buffering (one level) */
-PHPAPI void php_end_ob_buffer(zend_bool send_buffer, zend_bool just_flush TSRMLS_DC)
+/* {{{ SUCCESS|FAILURE php_output_clean()
+ Cleans the most recent output handlers buffer if the handler is cleanable */
+PHPAPI int _php_output_clean(TSRMLS_D)
{
- char *final_buffer=NULL;
- unsigned int final_buffer_length=0;
- zval *alternate_buffer=NULL;
- char *to_be_destroyed_buffer, *to_be_destroyed_handler_name;
- char *to_be_destroyed_handled_output[2] = { 0, 0 };
- int status;
- php_ob_buffer *prev_ob_buffer_p=NULL;
- php_ob_buffer orig_ob_buffer;
-
- if (OG(ob_nesting_level)==0) {
- return;
- }
- status = 0;
- if (!OG(active_ob_buffer).status & PHP_OUTPUT_HANDLER_START) {
- /* our first call */
- status |= PHP_OUTPUT_HANDLER_START;
- }
- if (just_flush) {
- status |= PHP_OUTPUT_HANDLER_CONT;
- } else {
- status |= PHP_OUTPUT_HANDLER_END;
- }
+ php_output_context context;
+
+ if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_CLEANABLE)) {
+ OG(active)->buffer.used = 0;
+ php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
+ php_output_handler_op(OG(active), &context);
+ php_output_context_dtor(&context);
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
-#if 0
- {
- FILE *fp;
- fp = fopen("/tmp/ob_log", "a");
- fprintf(fp, "NestLevel: %d ObStatus: %d HandlerName: %s\n", OG(ob_nesting_level), status, OG(active_ob_buffer).handler_name.s);
- fclose(fp);
- }
-#endif
+/* {{{ void php_output_clean_all()
+ Cleans all output handler buffers, without regard whether the handler is cleanable */
+PHPAPI void _php_output_clean_all(TSRMLS_D)
+{
+ php_output_context context;
- if (OG(active_ob_buffer).internal_output_handler) {
- final_buffer = OG(active_ob_buffer).internal_output_handler_buffer;
- final_buffer_length = OG(active_ob_buffer).internal_output_handler_buffer_size;
- 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);
- } else if (OG(active_ob_buffer).output_handler) {
- zval **params[2];
- zval *orig_buffer;
- zval *z_status;
-
- ALLOC_INIT_ZVAL(orig_buffer);
- ZVAL_U_STRINGL(ZEND_U_CONVERTER(UG(output_encoding_conv)), orig_buffer, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
- orig_buffer->refcount=2; /* don't let call_user_function() destroy our buffer */
- orig_buffer->is_ref=1;
-
- ALLOC_INIT_ZVAL(z_status);
- ZVAL_LONG(z_status, status);
-
- params[0] = &orig_buffer;
- params[1] = &z_status;
- OG(ob_lock) = 1;
-
- if (call_user_function_ex(CG(function_table), NULL, OG(active_ob_buffer).output_handler, &alternate_buffer, 2, params, 1, NULL TSRMLS_CC)==SUCCESS) {
- if (alternate_buffer && !(Z_TYPE_P(alternate_buffer)==IS_BOOL && Z_BVAL_P(alternate_buffer)==0)) {
- convert_to_string_ex(&alternate_buffer);
- final_buffer = Z_STRVAL_P(alternate_buffer);
- final_buffer_length = Z_STRLEN_P(alternate_buffer);
- }
- }
- OG(ob_lock) = 0;
- if (!just_flush) {
- zval_ptr_dtor(&OG(active_ob_buffer).output_handler);
- }
- orig_buffer->refcount -=2;
- if (orig_buffer->refcount <= 0) { /* free the zval */
- zval_dtor(orig_buffer);
- FREE_ZVAL(orig_buffer);
- }
- zval_ptr_dtor(&z_status);
+ if (OG(active)) {
+ php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_clean, &context);
}
+}
- if (!final_buffer) {
- final_buffer = OG(active_ob_buffer).buffer;
- final_buffer_length = OG(active_ob_buffer).text_length;
+/* {{{ SUCCESS|FAILURE php_output_end()
+ Finalizes the most recent output handler at pops it off the stack if the handler is removable */
+PHPAPI int _php_output_end(TSRMLS_D)
+{
+ if (php_output_stack_pop(0, 0 TSRMLS_CC)) {
+ return SUCCESS;
}
+ return FAILURE;
+}
+/* }}} */
- if (OG(ob_nesting_level)==1) { /* end buffering */
- if (SG(headers_sent) && !SG(request_info).headers_only) {
- OG(php_body_write) = php_ub_body_write_no_header;
- } else {
- OG(php_body_write) = php_ub_body_write;
- }
- }
+/* {{{ void php_output_end_all()
+ Finalizes all output handlers and ends output buffering without regard whether a handler is removable */
+PHPAPI void _php_output_end_all(TSRMLS_D)
+{
+ while (OG(active) && php_output_stack_pop(0, 1 TSRMLS_CC));
+}
+/* }}} */
- to_be_destroyed_buffer = OG(active_ob_buffer).buffer;
- /* FIXME: unicode support??? */
- to_be_destroyed_handler_name = OG(active_ob_buffer).handler_name.s;
- if (OG(active_ob_buffer).internal_output_handler
- && (final_buffer != OG(active_ob_buffer).internal_output_handler_buffer)
- && (final_buffer != OG(active_ob_buffer).buffer)) {
- to_be_destroyed_handled_output[0] = final_buffer;
+/* {{{ SUCCESS|FAILURE php_output_discard()
+ Discards the most recent output handlers buffer and pops it off the stack if the handler is removable */
+PHPAPI int _php_output_discard(TSRMLS_D)
+{
+ if (php_output_stack_pop(1, 0 TSRMLS_CC)) {
+ return SUCCESS;
}
+ return FAILURE;
+}
+/* }}} */
- if (!just_flush) {
- if (OG(active_ob_buffer).internal_output_handler) {
- to_be_destroyed_handled_output[1] = OG(active_ob_buffer).internal_output_handler_buffer;
- }
- }
- if (OG(ob_nesting_level)>1) { /* restore previous buffer */
- zend_stack_top(&OG(ob_buffers), (void **) &prev_ob_buffer_p);
- orig_ob_buffer = OG(active_ob_buffer);
- OG(active_ob_buffer) = *prev_ob_buffer_p;
- zend_stack_del_top(&OG(ob_buffers));
- if (!just_flush && OG(ob_nesting_level)==2) { /* destroy the stack */
- zend_stack_destroy(&OG(ob_buffers));
- }
+/* {{{ void php_output_discard_all()
+ Discard all output handlers and buffers without regard whether a handler is removable */
+PHPAPI void _php_output_discard_all(TSRMLS_D)
+{
+ while (OG(active)) {
+ php_output_stack_pop(1, 1 TSRMLS_CC);
}
- OG(ob_nesting_level)--;
+}
+/* }}} */
- if (send_buffer) {
- if (just_flush) { /* if flush is called prior to proper end, ensure presence of NUL */
- final_buffer[final_buffer_length] = '\0';
- }
- OG(php_body_write)(final_buffer, final_buffer_length TSRMLS_CC);
+/* {{{ int php_output_get_level()
+ Get output buffering level, ie. how many output handlers the stack contains */
+PHPAPI int _php_output_get_level(TSRMLS_D)
+{
+ return OG(active) ? zend_stack_count(&OG(handlers)) : 0;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_get_contents(zval *z)
+ Get the contents of the active output handlers buffer */
+PHPAPI int _php_output_get_contents(zval *p TSRMLS_DC)
+{
+ if (OG(active)) {
+ ZVAL_STRINGL(p, OG(active)->buffer.data, OG(active)->buffer.used, 1);
+ return SUCCESS;
+ } else {
+ ZVAL_NULL(p);
+ return FAILURE;
}
+}
- if (just_flush) { /* we restored the previous ob, return to the current */
- if (prev_ob_buffer_p) {
- zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer));
- OG(active_ob_buffer) = orig_ob_buffer;
- }
- OG(ob_nesting_level)++;
+/* {{{ SUCCESS|FAILURE php_output_get_length(zval *z)
+ Get the length of the active output handlers buffer */
+PHPAPI int _php_output_get_length(zval *p TSRMLS_DC)
+{
+ if (OG(active)) {
+ ZVAL_LONG(p, OG(active)->buffer.used);
+ return SUCCESS;
+ } else {
+ ZVAL_NULL(p);
+ return FAILURE;
}
+}
+/* }}} */
- if (alternate_buffer) {
- zval_ptr_dtor(&alternate_buffer);
+/* {{{ SUCCESS|FAILURE php_output_handler_start_default()
+ Start a "default output handler" */
+PHPAPI int _php_output_start_default(TSRMLS_D)
+{
+ php_output_handler *handler;
+
+ handler = php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, 0, PHP_OUTPUT_HANDLER_STDFLAGS);
+ if (SUCCESS == php_output_handler_start(handler)) {
+ return SUCCESS;
}
+ php_output_handler_free(&handler);
+ return FAILURE;
+}
+/* }}} */
- if (status & PHP_OUTPUT_HANDLER_END) {
- efree(to_be_destroyed_handler_name);
+/* {{{ SUCCESS|FAILURE php_output_handler_start_devnull()
+ Start a "null output handler" */
+PHPAPI int _php_output_start_devnull(TSRMLS_D)
+{
+ php_output_handler *handler;
+
+ handler = php_output_handler_create_internal(OG(devnull_output_handler_name), php_output_handler_devnull_func, PHP_OUTPUT_HANDLER_DEFAULT_SIZE, 0);
+ if (SUCCESS == php_output_handler_start(handler)) {
+ return SUCCESS;
}
- if (!just_flush) {
- efree(to_be_destroyed_buffer);
+ php_output_handler_free(&handler);
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_start_user(zval *handler, size_t chunk_size, int flags)
+ Start a user level output handler */
+PHPAPI int _php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
+{
+ php_output_handler *handler;
+
+ if (output_handler) {
+ handler = php_output_handler_create_user(output_handler, chunk_size, flags);
} else {
- OG(active_ob_buffer).text_length = 0;
- OG(active_ob_buffer).status |= PHP_OUTPUT_HANDLER_START;
- OG(php_body_write) = php_b_body_write;
- }
- if (to_be_destroyed_handled_output[0]) {
- efree(to_be_destroyed_handled_output[0]);
+ handler = php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, chunk_size, flags);
}
- if (to_be_destroyed_handled_output[1]) {
- efree(to_be_destroyed_handled_output[1]);
+ if (SUCCESS == php_output_handler_start(handler)) {
+ return SUCCESS;
}
+ php_output_handler_free(&handler);
+ return FAILURE;
}
/* }}} */
-/* {{{ php_end_ob_buffers
- * End output buffering (all buffers) */
-PHPAPI void php_end_ob_buffers(zend_bool send_buffer TSRMLS_DC)
+/* {{{ SUCCESS|FAILURE php_output_start_internal(const char *name, php_output_handler_func_t handler, size_t chunk_size, int flags)
+ Start an internal output handler that does not have to maintain a non-global state */
+PHPAPI int _php_output_start_internal(zval *name, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
{
- while (OG(ob_nesting_level)!=0) {
- php_end_ob_buffer(send_buffer, 0 TSRMLS_CC);
+ php_output_handler *handler;
+
+ handler = php_output_handler_create_internal(name, php_output_handler_compat_func, chunk_size, flags);
+ php_output_handler_set_context(handler, output_handler, NULL);
+ if (SUCCESS == php_output_handler_start(handler)) {
+ return SUCCESS;
}
+ php_output_handler_free(&handler);
+ return FAILURE;
}
/* }}} */
-/* {{{ php_start_implicit_flush
- */
-PHPAPI void php_start_implicit_flush(TSRMLS_D)
+/* {{{ php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags)
+ Create a user level output handler */
+PHPAPI php_output_handler *_php_output_handler_create_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
{
- OG(implicit_flush)=1;
+ zval *handler_name = NULL;
+ php_output_handler *handler = NULL;
+ php_output_handler_context_func_t *internal = NULL;
+
+ switch (Z_TYPE_P(output_handler)) {
+ case IS_NULL:
+ break;
+ case IS_STRING:
+ case IS_UNICODE:
+ if (Z_UNILEN_P(output_handler) && (internal = php_output_handler_alias(output_handler))) {
+ return php_output_handler_create_internal(output_handler, *internal, chunk_size, flags);
+ }
+ default:
+ MAKE_STD_ZVAL(handler_name);
+ ZVAL_NULL(handler_name);
+ if (zend_is_callable(output_handler, 0, handler_name)) {
+ handler = php_output_handler_init(handler_name, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_USER);
+ ZVAL_ADDREF(output_handler);
+ handler->user = output_handler;
+ }
+ zval_ptr_dtor(&handler_name);
+ return handler;
+ }
+
+ return php_output_handler_create_internal(OG(default_output_handler_name), php_output_handler_default_func, chunk_size, flags);
}
/* }}} */
-/* {{{ php_end_implicit_flush
- */
-PHPAPI void php_end_implicit_flush(TSRMLS_D)
+/* {{{ php_output_handler *php_output_handler_create_internal(const char *name, php_output_handler_context_func_t handler, size_t chunk_size, int flags)
+ Create an internal output handler that can maintain a non-global state */
+PHPAPI php_output_handler *_php_output_handler_create_internal(zval *name, php_output_handler_context_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
{
- OG(implicit_flush)=0;
+ php_output_handler *handler;
+
+ handler = php_output_handler_init(name, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_INTERNAL);
+ handler->internal = output_handler;
+
+ return handler;
}
-/* }}} */
-/* {{{ php_ob_set_internal_handler
- */
-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)
+/* {{{ void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC))
+ Set the context/state of an output handler. Calls the dtor of the previous context if there is one */
+PHPAPI void _php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
{
- /* FIXME: Unicode support??? */
- if (OG(ob_nesting_level)==0 || OG(active_ob_buffer).internal_output_handler || strcmp(OG(active_ob_buffer).handler_name.s, OB_DEFAULT_HANDLER_NAME)) {
- php_start_ob_buffer(NULL, buffer_size, erase TSRMLS_CC);
+ if (handler->dtor && handler->opaq) {
+ handler->dtor(handler->opaq TSRMLS_CC);
}
+ handler->dtor = dtor;
+ handler->opaq = opaq;
+}
+/* }}} */
- OG(active_ob_buffer).internal_output_handler = internal_output_handler;
- OG(active_ob_buffer).internal_output_handler_buffer = (char *) emalloc(buffer_size);
- OG(active_ob_buffer).internal_output_handler_buffer_size = buffer_size;
- if (OG(active_ob_buffer).handler_name.s) {
- efree(OG(active_ob_buffer).handler_name.s);
+/* {{{ SUCCESS|FAILURE php_output_handler_start(php_output_handler *handler)
+ Starts the set up output handler and pushes it on top of the stack. Checks for any conflicts regarding the output handler to start */
+PHPAPI int _php_output_handler_start(php_output_handler *handler TSRMLS_DC)
+{
+ HashTable *rconflicts;
+ php_output_handler_conflict_check_t *conflict;
+
+ if (php_output_lock_error(PHP_OUTPUT_HANDLER_START TSRMLS_CC) || !handler) {
+ return FAILURE;
+ }
+ if (SUCCESS == zend_u_hash_find(&php_output_handler_conflicts, Z_TYPE_P(handler->name), Z_UNIVAL_P(handler->name), Z_UNILEN_P(handler->name), (void *) &conflict)) {
+ if (SUCCESS != (*conflict)(handler->name TSRMLS_CC)) {
+ return FAILURE;
+ }
}
- OG(active_ob_buffer).handler_name.s = estrdup(handler_name);
- OG(active_ob_buffer).erase = erase;
+ if (SUCCESS == zend_u_hash_find(&php_output_handler_reverse_conflicts, Z_TYPE_P(handler->name), Z_UNIVAL_P(handler->name), Z_UNILEN_P(handler->name), (void *) &rconflicts)) {
+ for ( zend_hash_internal_pointer_reset(rconflicts);
+ zend_hash_get_current_data(rconflicts, (void *) &conflict) == SUCCESS;
+ zend_hash_move_forward(rconflicts)) {
+ if (SUCCESS != (*conflict)(handler->name TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ }
+ /* zend_stack_push never returns SUCCESS but FAILURE or stack level */
+ if (FAILURE == (handler->level = zend_stack_push(&OG(handlers), &handler, sizeof(php_output_handler *)))) {
+ return FAILURE;
+ }
+ OG(active) = handler;
+ return SUCCESS;
}
/* }}} */
-/*
- * Output buffering - implementation
- */
-
-/* {{{ php_ob_allocate
- */
-static inline void php_ob_allocate(uint text_length TSRMLS_DC)
+/* {{{ int php_output_handler_started(const char *name)
+ Check whether a certain output handler is in use */
+PHPAPI int _php_output_handler_started(zval *name TSRMLS_DC)
{
- uint new_len = OG(active_ob_buffer).text_length + text_length;
-
- if (OG(active_ob_buffer).size < new_len) {
- uint buf_size = OG(active_ob_buffer).size;
- while (buf_size <= new_len) {
- buf_size += OG(active_ob_buffer).block_size;
+ php_output_handler **handlers;
+ int i, count = php_output_get_level();
+
+ if (count) {
+ handlers = *(php_output_handler ***) zend_stack_base(&OG(handlers));
+
+ for (i = 0; i < count; ++i) {
+ if (!zend_binary_zval_strcmp(handlers[i]->name, name)) {
+ return 1;
+ }
}
-
- OG(active_ob_buffer).buffer = (char *) erealloc(OG(active_ob_buffer).buffer, buf_size+1);
- OG(active_ob_buffer).size = buf_size;
}
- OG(active_ob_buffer).text_length = new_len;
+
+ return 0;
}
/* }}} */
-/* {{{ php_ob_init_conflict
- * Returns 1 if handler_set is already used and generates error message
- */
-PHPAPI int php_ob_init_conflict(char *handler_new, char *handler_set TSRMLS_DC)
+/* {{{ int php_output_handler_conflict(const char *handler_new, const char *handler_old)
+ Check whether a certain handler is in use and issue a warning that the new handler would conflict with the already used one */
+PHPAPI int _php_output_handler_conflict(zval *handler_new, zval *handler_set TSRMLS_DC)
{
- if (php_ob_handler_used(handler_set TSRMLS_CC)) {
- php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", handler_new, handler_set);
+ if (php_output_handler_started(handler_set)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%v' conflicts with '%v'", Z_UNIVAL_P(handler_new), Z_UNIVAL_P(handler_set));
return 1;
}
return 0;
}
/* }}} */
-/* {{{ php_ob_init_named
- */
-static int php_ob_init_named(uint initial_size, uint block_size, zend_uchar type, zstr handler_name, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
+/* {{{ SUCCESS|FAILURE php_output_handler_conflict_register(const char name[], php_output_handler_conflict_check_t check_func)
+ Register a conflict checking function on MINIT */
+PHPAPI int _php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
{
- int handler_len;
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register an output handler conflict outside of MINIT");
+ return FAILURE;
+ }
+ return zend_u_hash_update(&php_output_handler_conflicts, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name), &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
+}
+/* }}} */
- if (output_handler && !zend_is_callable(output_handler, 0, NULL)) {
+/* {{{ SUCCESS|FAILURE php_output_handler_reverse_conflict_register(const char name[], php_output_handler_conflict_check_t check_func)
+ Register a reverse conflict checking function on MINIT */
+PHPAPI int _php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
+{
+ HashTable rev, *rev_ptr = NULL;
+
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register a reverse output handler conflict outside of MINIT");
return FAILURE;
}
- if (type == IS_UNICODE) {
- handler_len = u_strlen(handler_name.u);
+ if (SUCCESS == zend_u_hash_find(&php_output_handler_reverse_conflicts, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name), (void *) &rev_ptr)) {
+ return zend_hash_next_index_insert(rev_ptr, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
} else {
- handler_len = strlen(handler_name.s);
- }
- if (OG(ob_nesting_level)>0) {
-#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
- if ((handler_len == sizeof("ob_gzhandler")-1) &&
- (ZEND_U_EQUAL(type, handler_name, handler_len, "ob_gzhandler", sizeof("ob_gzhandler"))) &&
- php_ob_gzhandler_check(TSRMLS_C)) {
+ zend_hash_init(&rev, 1, NULL, NULL, 1);
+ if (SUCCESS != zend_hash_next_index_insert(&rev, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL)) {
+ zend_hash_destroy(&rev);
return FAILURE;
}
-#endif
- if (OG(ob_nesting_level)==1) { /* initialize stack */
- zend_stack_init(&OG(ob_buffers));
+ if (SUCCESS != zend_u_hash_update(&php_output_handler_reverse_conflicts, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name), &rev, sizeof(HashTable), NULL)) {
+ zend_hash_destroy(&rev);
+ return FAILURE;
}
- zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer));
- }
- OG(ob_nesting_level)++;
- OG(active_ob_buffer).block_size = block_size;
- OG(active_ob_buffer).size = initial_size;
- OG(active_ob_buffer).buffer = (char *) emalloc(initial_size+1);
- OG(active_ob_buffer).text_length = 0;
- OG(active_ob_buffer).output_handler = output_handler;
- OG(active_ob_buffer).chunk_size = chunk_size;
- OG(active_ob_buffer).status = 0;
- OG(active_ob_buffer).internal_output_handler = NULL;
- if (type == IS_UNICODE) {
- /* FIXME: Unicode support??? */
- OG(active_ob_buffer).handler_name.u = eustrdup((handler_name.u && handler_name.u[0])?handler_name.u:(UChar*)OB_DEFAULT_HANDLER_NAME);
- } else {
- OG(active_ob_buffer).handler_name.s = estrdup((handler_name.s && handler_name.s[0])?handler_name.s:OB_DEFAULT_HANDLER_NAME);
+ return SUCCESS;
}
- OG(active_ob_buffer).erase = erase;
- OG(php_body_write) = php_b_body_write;
- return SUCCESS;
}
/* }}} */
-/* {{{ php_ob_handler_from_string
- * Create zval output handler from string
- */
-static zval* php_ob_handler_from_string(const char *handler_name, int len TSRMLS_DC)
+/* {{{ php_output_handler_context_func_t php_output_handler_alias(const char[] name)
+ Get an internal output handler for a user handler if it exists */
+PHPAPI php_output_handler_context_func_t *_php_output_handler_alias(zval *name TSRMLS_DC)
{
- zval *output_handler;
-
- ALLOC_INIT_ZVAL(output_handler);
- Z_STRLEN_P(output_handler) = len;
- Z_STRVAL_P(output_handler) = estrndup(handler_name, len);
- Z_TYPE_P(output_handler) = IS_STRING;
- return output_handler;
+ php_output_handler_context_func_t *func = NULL;
+
+ zend_u_hash_find(&php_output_handler_aliases, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name), (void *) &func);
+ return func;
}
/* }}} */
-/* {{{ php_ob_handler_from_unicode
- * Create zval output handler from unicode
- */
-static zval* php_ob_handler_from_unicode(const UChar *handler_name, int len TSRMLS_DC)
+/* {{{ SUCCESS|FAILURE php_output_handler_alias_register(const char[] name, php_output_handler_context_func_t func)
+ Registers an internal output handler as alias for a user handler */
+PHPAPI int _php_output_handler_alias_register_ex(zval *name, php_output_handler_context_func_t func TSRMLS_DC)
{
- zval *output_handler;
-
- ALLOC_INIT_ZVAL(output_handler);
- Z_USTRLEN_P(output_handler) = len;
- Z_USTRVAL_P(output_handler) = eustrndup(handler_name, len);
- Z_TYPE_P(output_handler) = IS_UNICODE;
- return output_handler;
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register an output handler alias outside of MINIT");
+ return FAILURE;
+ }
+ return zend_u_hash_update(&php_output_handler_aliases, Z_TYPE_P(name), Z_UNIVAL_P(name), Z_UNILEN_P(name), &func, sizeof(php_output_handler_context_func_t *), NULL);
}
/* }}} */
-/* {{{ php_ob_init
- */
-static int php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
-{
- int result = FAILURE, handler_len, len;
- HashPosition pos;
- zval **tmp;
- zval *handler_zval;
-
- if (output_handler && output_handler->type == IS_STRING) {
- zstr next_handler_name;
- zstr handler_name = Z_UNIVAL_P(output_handler);
- handler_len = Z_UNILEN_P(output_handler);
-
- result = SUCCESS;
- if (handler_len && handler_name.s[0] != '\0') {
- while ((next_handler_name.s=strchr(handler_name.s, ',')) != NULL) {
- len = next_handler_name.s-handler_name.s;
- next_handler_name.s = estrndup(handler_name.s, len);
- handler_zval = php_ob_handler_from_string(next_handler_name.s, len TSRMLS_CC);
- result = php_ob_init_named(initial_size, block_size, IS_STRING, next_handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
- if (result != SUCCESS) {
- zval_dtor(handler_zval);
- FREE_ZVAL(handler_zval);
- }
- handler_name.s += len+1;
- handler_len -= len+1;
- efree(next_handler_name.s);
- }
- }
- if (result == SUCCESS) {
- handler_zval = php_ob_handler_from_string(handler_name.s, handler_len TSRMLS_CC);
- result = php_ob_init_named(initial_size, block_size, IS_STRING, handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
- if (result != SUCCESS) {
- zval_dtor(handler_zval);
- FREE_ZVAL(handler_zval);
- }
- }
- } else if (output_handler && output_handler->type == IS_UNICODE) {
- zstr next_handler_name;
- zstr handler_name = Z_UNIVAL_P(output_handler);
- handler_len = Z_UNILEN_P(output_handler);
-
- result = SUCCESS;
- if (handler_len && handler_name.u[0] != 0) {
- while ((next_handler_name.u=u_strchr(handler_name.u, ',')) != NULL) {
- len = next_handler_name.u-handler_name.u;
- next_handler_name.u = eustrndup(handler_name.u, len);
- handler_zval = php_ob_handler_from_unicode(next_handler_name.u, len TSRMLS_CC);
- result = php_ob_init_named(initial_size, block_size, IS_UNICODE, next_handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
- if (result != SUCCESS) {
- zval_dtor(handler_zval);
- FREE_ZVAL(handler_zval);
- }
- handler_name.u += len+1;
- handler_len -= len+1;
- efree(next_handler_name.u);
- }
- }
- if (result == SUCCESS) {
- handler_zval = php_ob_handler_from_unicode(handler_name.u, handler_len TSRMLS_CC);
- result = php_ob_init_named(initial_size, block_size, IS_UNICODE, handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
- if (result != SUCCESS) {
- zval_dtor(handler_zval);
- FREE_ZVAL(handler_zval);
- }
- }
- } else if (output_handler && output_handler->type == IS_ARRAY) {
- zval handler_name;
-
- /* do we have array(object,method) */
- if (zend_is_callable(output_handler, 0, &handler_name)) {
- SEPARATE_ZVAL(&output_handler);
- output_handler->refcount++;
- result = php_ob_init_named(initial_size, block_size, Z_TYPE(handler_name), Z_UNIVAL(handler_name), output_handler, chunk_size, erase TSRMLS_CC);
- zval_dtor(&handler_name);
- } else {
- zval_dtor(&handler_name);
- /* init all array elements recursively */
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(output_handler), &pos);
- while (zend_hash_get_current_data_ex(Z_ARRVAL_P(output_handler), (void **)&tmp, &pos) == SUCCESS) {
- result = php_ob_init(initial_size, block_size, *tmp, chunk_size, erase TSRMLS_CC);
- if (result == FAILURE) {
- break;
- }
- zend_hash_move_forward_ex(Z_ARRVAL_P(output_handler), &pos);
- }
+/* {{{ SUCCESS|FAILURE php_output_handler_hook(int type, void *arg)
+ Output handler hook for output handler functions to check/modify the current handlers abilities */
+PHPAPI int _php_output_handler_hook(int type, void *arg TSRMLS_DC)
+{
+ if (OG(running)) {
+ switch (type) {
+ case PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ:
+ *(void ***) arg = &OG(running)->opaq;
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS:
+ *(int *) arg = OG(running)->flags;
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE:
+ OG(running)->flags &= ~PHP_OUTPUT_HANDLER_STDFLAGS;
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_DISABLE:
+ OG(running)->flags |= PHP_OUTPUT_HANDLER_DISABLED;
+ return SUCCESS;
}
- } else if (output_handler && output_handler->type == IS_OBJECT) {
- 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 %v to use as output handler", Z_OBJCE_P(output_handler)->name);
- result = FAILURE;
- } else {
- zstr z_name;
-
- z_name.s = OB_DEFAULT_HANDLER_NAME;
- result = php_ob_init_named(initial_size, block_size, IS_STRING, z_name, NULL, chunk_size, erase TSRMLS_CC);
}
- return result;
+ return FAILURE;
}
/* }}} */
-/* {{{ php_ob_list_each
- */
-static int php_ob_list_each(php_ob_buffer *ob_buffer, zval *ob_handler_array)
+/* {{{ void php_output_handler_dtor(php_output_handler *handler)
+ Destroy an output handler */
+PHPAPI void _php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
{
- TSRMLS_FETCH();
-
- add_next_index_text(ob_handler_array, ob_buffer->handler_name, 1);
- return 0;
+ zval_ptr_dtor(&handler->name);
+ STR_FREE(handler->buffer.data);
+ if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
+ zval_ptr_dtor(&handler->user);
+ }
+ if (handler->dtor && handler->opaq) {
+ handler->dtor(handler->opaq TSRMLS_CC);
+ }
+ memset(handler, 0, sizeof(*handler));
}
/* }}} */
-/* {{{ proto false|array ob_list_handlers()
- * List all output_buffers in an array
- */
-PHP_FUNCTION(ob_list_handlers)
+/* {{{ void php_output_handler_free(php_output_handler **handler)
+ Destroy and free an output handler */
+PHPAPI void _php_output_handler_free(php_output_handler **h TSRMLS_DC)
{
- if (ZEND_NUM_ARGS()!=0) {
- ZEND_WRONG_PARAM_COUNT();
- RETURN_FALSE;
+ if (*h) {
+ php_output_handler_dtor(*h);
+ efree(*h);
+ *h = NULL;
}
+}
+/* }}} */
- array_init(return_value);
- if (OG(ob_nesting_level)) {
- if (OG(ob_nesting_level)>1) {
- zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_ob_list_each, return_value);
- }
- php_ob_list_each(&OG(active_ob_buffer), return_value);
+/* void php_output_set_implicit_flush(int enabled)
+ Enable or disable implicit flush */
+PHPAPI void _php_output_set_implicit_flush(int flush TSRMLS_DC)
+{
+ if (flush) {
+ OG(flags) |= PHP_OUTPUT_IMPLICITFLUSH;
+ } else {
+ OG(flags) &= ~PHP_OUTPUT_IMPLICITFLUSH;
}
}
/* }}} */
-/* {{{ php_ob_used_each
- * Sets handler_name to NULL is found
- */
-static int php_ob_handler_used_each(php_ob_buffer *ob_buffer, char **handler_name)
+/* {{{ char *php_output_get_start_filename()
+ Get the file name where output has started */
+PHPAPI char *_php_output_get_start_filename(TSRMLS_D)
+{
+ return OG(output_start_filename);
+}
+/* }}} */
+
+/* {{{ int php_output_get_start_lineno()
+ Get the line number where output has started */
+PHPAPI int _php_output_get_start_lineno(TSRMLS_D)
+{
+ return OG(output_start_lineno);
+}
+/* }}} */
+
+/* {{{ static int php_output_lock_error(int op TSRMLS_DC)
+ Checks whether an unallowed operation is attempted from within the output handler and issues a fatal error */
+static inline int php_output_lock_error(int op TSRMLS_DC)
{
- /* FIXME: Unicode support??? */
- if (!strcmp(ob_buffer->handler_name.s, *handler_name)) {
- *handler_name = NULL;
+ /* if there's no ob active, ob has been stopped */
+ if (op && OG(active) && OG(running)) {
+ /* fatal error */
+ php_output_deactivate();
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers");
return 1;
}
return 0;
}
/* }}} */
-/* {{{ php_ob_used
- * returns 1 if given handler_name is used as output_handler
- */
-PHPAPI int php_ob_handler_used(char *handler_name TSRMLS_DC)
+/* {{{ static php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
+ Initialize a new output context */
+static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
{
- /* FIXME: Unicode support??? */
- char *tmp = handler_name;
-
- if (OG(ob_nesting_level)) {
- if (!strcmp(OG(active_ob_buffer).handler_name.s, handler_name)) {
- return 1;
- }
- if (OG(ob_nesting_level)>1) {
- zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_ob_handler_used_each, &tmp);
- }
+ if (!context) {
+ context = emalloc(sizeof(php_output_context));
}
- return tmp ? 0 : 1;
+
+ memset(context, 0, sizeof(php_output_context));
+ TSRMLS_SET_CTX(context->tsrm_ls);
+ context->op = op;
+
+ return context;
}
/* }}} */
-/* {{{ php_ob_append
- */
-static inline void php_ob_append(const char *text, uint text_length TSRMLS_DC)
+/* {{{ static void php_output_context_reset(php_output_context *context)
+ Reset an output context */
+static inline void php_output_context_reset(php_output_context *context)
{
- char *target;
- int original_ob_text_length;
+ int op = context->op;
+ php_output_context_dtor(context);
+ memset(context, 0, sizeof(php_output_context));
+ context->op = op;
+}
+/* }}} */
- original_ob_text_length=OG(active_ob_buffer).text_length;
+/* {{{ static void php_output_context_swap(php_output_context *context)
+ Swap output contexts buffers */
+static inline void php_output_context_swap(php_output_context *context)
+{
+ if (context->in.free && context->in.data) {
+ efree(context->in.data);
+ }
+ context->in.data = context->out.data;
+ context->in.used = context->out.used;
+ context->in.free = context->out.free;
+ context->in.size = context->out.size;
+ context->out.data = NULL;
+ context->out.used = 0;
+ context->out.size = 0;
+}
+/* }}} */
- php_ob_allocate(text_length TSRMLS_CC);
- target = OG(active_ob_buffer).buffer+original_ob_text_length;
- memcpy(target, text, text_length);
- target[text_length]=0;
+/* {{{ static void php_output_context_pass(php_output_context *context)
+ Pass input to output buffer */
+static inline void php_output_context_pass(php_output_context *context)
+{
+ context->out.data = context->in.data;
+ context->out.used = context->in.used;
+ context->out.size = context->in.size;
+ context->out.free = context->in.free;
+ context->in.data = NULL;
+ context->in.used = 0;
+ context->in.size = 0;
+}
+/* }}} */
- /* If implicit_flush is On or chunked buffering, send contents to next buffer and return. */
- if (OG(active_ob_buffer).chunk_size
- && OG(active_ob_buffer).text_length >= OG(active_ob_buffer).chunk_size) {
-
- php_end_ob_buffer(1, 1 TSRMLS_CC);
- return;
+/* {{{ static void php_output_context_dtor(php_output_context *context)
+ Destroy the contents of an output context */
+static inline void php_output_context_dtor(php_output_context *context)
+{
+ if (context->in.free && context->in.data) {
+ efree(context->in.data);
+ }
+ if (context->out.free && context->out.data) {
+ efree(context->out.data);
}
}
/* }}} */
-#if 0
-static inline void php_ob_prepend(const char *text, uint text_length)
+/* {{{ static php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags)
+ Allocates and initializes a php_output_handler structure */
+static inline php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags)
{
- char *p, *start;
- TSRMLS_FETCH();
-
- php_ob_allocate(text_length TSRMLS_CC);
-
- /* php_ob_allocate() may change OG(ob_buffer), so we can't initialize p&start earlier */
- p = OG(ob_buffer)+OG(ob_text_length);
- start = OG(ob_buffer);
+ php_output_handler *handler;
+
+ handler = ecalloc(1, sizeof(php_output_handler));
+ ZVAL_ADDREF(name);
+ handler->name = name;
+ handler->size = chunk_size;
+ handler->flags = flags;
+ handler->buffer.size = PHP_OUTPUT_HANDLER_INITBUF_SIZE(chunk_size);
+ handler->buffer.data = emalloc(handler->buffer.size);
+
+ return handler;
+}
+/* }}} */
- while (--p>=start) {
- p[text_length] = *p;
+/* {{{ static int php_output_handler_appen(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
+ Appends input to the output handlers buffer and indicates whether the buffer does not have to be processed by the output handler */
+static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
+{
+ /* store it away */
+ if ((handler->buffer.size - handler->buffer.used) <= buf->used) {
+ size_t grow_int = PHP_OUTPUT_HANDLER_INITBUF_SIZE(handler->size);
+ size_t grow_buf = PHP_OUTPUT_HANDLER_INITBUF_SIZE(buf->used + 1 - (handler->buffer.size - handler->buffer.used));
+ size_t grow_max = MAX(grow_int, grow_buf);
+
+ handler->buffer.data = erealloc(handler->buffer.data, handler->buffer.size += grow_max);
+ }
+ memcpy(handler->buffer.data + handler->buffer.used, buf->data, buf->used);
+ handler->buffer.used += buf->used;
+ handler->buffer.data[handler->buffer.used] = '\0';
+
+ /* chunked buffering */
+ if (handler->size && (handler->buffer.used >= handler->size)) {
+ /* store away errors and/or any intermediate output */
+ return OG(running) ? 1 : 0;
}
- memcpy(OG(ob_buffer), text, text_length);
- OG(ob_buffer)[OG(active_ob_buffer).text_length]=0;
+ return 1;
}
+/* }}} */
+
+/* {{{ static PHP_OUTPUT_HANDLER_(SUCCESS|FAILURE|NO_DATA) php_output_handler_op(php_output_handler *handler, php_output_context *context)
+ Output handler operation dispatcher, applying context op to the php_output_handler handler */
+static inline int php_output_handler_op(php_output_handler *handler, php_output_context *context)
+{
+ int status, op;
+ PHP_OUTPUT_TSRMLS(context);
+
+#if PHP_OUTPUT_DEBUG
+ fprintf(stderr, ">>> op(%d, "
+ "handler=%p, "
+ "name=%s, "
+ "flags=%d, "
+ "buffer.data=%s, "
+ "buffer.used=%lu, "
+ "buffer.size=%lu, "
+ "in.data=%s, "
+ "in.used=%lu)\n",
+ context->op,
+ handler,
+ handler->name,
+ handler->flags,
+ handler->buffer.data,
+ handler->buffer.used,
+ handler->buffer.size,
+ context->in.data,
+ context->in.used
+ );
#endif
+
+ op = context->op;
+ if (php_output_lock_error(op TSRMLS_CC)) {
+ /* fatal error */
+ return PHP_OUTPUT_HANDLER_FAILURE;
+ }
+
+ /* storable? */
+ if (php_output_handler_append(handler, &context->in TSRMLS_CC) && !op) {
+ status = PHP_OUTPUT_HANDLER_NO_DATA;
+ } else {
+ /* need to start? */
+ if (!(handler->flags & PHP_OUTPUT_HANDLER_STARTED)) {
+ handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
+ op |= PHP_OUTPUT_HANDLER_START;
+ }
+
+ OG(running) = handler;
+ if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
+ zval *retval = NULL, **params[2], *flags, *input;
+
+ MAKE_STD_ZVAL(input);
+ ZVAL_STRINGL(input, handler->buffer.data, handler->buffer.used, 1);
+ MAKE_STD_ZVAL(flags);
+ ZVAL_LONG(flags, (long) op);
+ params[0] = &input;
+ params[1] = &flags;
+
+ if ( (SUCCESS == call_user_function_ex(CG(function_table), NULL, handler->user, &retval, 2, params, 1, NULL TSRMLS_CC)) &&
+ retval && (Z_TYPE_P(retval) != IS_NULL) && (Z_TYPE_P(retval) != IS_BOOL || Z_BVAL_P(retval))) {
+ /* user handler may have returned TRUE */
+ status = PHP_OUTPUT_HANDLER_NO_DATA;
+ if (Z_TYPE_P(retval) != IS_BOOL) {
+ convert_to_string_ex(&retval);
+ if (Z_STRLEN_P(retval)) {
+ context->out.data = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
+ context->out.used = Z_STRLEN_P(retval);
+ context->out.free = 1;
+ status = PHP_OUTPUT_HANDLER_SUCCESS;
+ }
+ }
+ } else {
+ /* call failed, pass internal buffer along */
+ status = PHP_OUTPUT_HANDLER_FAILURE;
+ }
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ zval_ptr_dtor(&input);
+ zval_ptr_dtor(&flags);
+ } else {
+
+ context->in.data = handler->buffer.data;
+ context->in.used = handler->buffer.used;
+ context->in.free = 0;
+
+ if (SUCCESS == handler->internal(&handler->opaq, context)) {
+ if (context->out.used) {
+ status = PHP_OUTPUT_HANDLER_SUCCESS;
+ } else {
+ status = PHP_OUTPUT_HANDLER_NO_DATA;
+ }
+ } else {
+ status = PHP_OUTPUT_HANDLER_FAILURE;
+ }
+ }
+ OG(running) = NULL;
+ }
+
+ switch (status) {
+ case PHP_OUTPUT_HANDLER_FAILURE:
+ /* disable this handler */
+ handler->flags |= PHP_OUTPUT_HANDLER_DISABLED;
+ /* returns handlers buffer */
+ context->out.data = handler->buffer.data;
+ context->out.used = handler->buffer.used;
+ context->out.free = 1;
+ handler->buffer.data = NULL;
+ handler->buffer.used = 0;
+ handler->buffer.size = 0;
+ break;
+ case PHP_OUTPUT_HANDLER_SUCCESS:
+ /* no more buffered data */
+ handler->buffer.used = 0;
+ break;
+ case PHP_OUTPUT_HANDLER_NO_DATA:
+ /* handler ate all */
+ php_output_context_reset(context);
+ break;
+ }
+
+ return status;
+}
+/* }}} */
-/* {{{ php_ob_get_buffer
- * Return the current output buffer */
-PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC)
+/* {{{ static void php_output_op(int op, const char *str, size_t len TSRMLS_DC)
+ Output op dispatcher, passes input and output handlers output through the output handler stack until it gets written to the SAPI */
+static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC)
{
- if (OG(ob_nesting_level)==0) {
- return FAILURE;
+ php_output_context context;
+ php_output_handler **active;
+ int obh_cnt;
+
+ if (php_output_lock_error(op TSRMLS_CC)) {
+ return;
}
- ZVAL_U_STRINGL(ZEND_U_CONVERTER(UG(output_encoding_conv)), p, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
- return SUCCESS;
+
+ php_output_context_init(&context, op TSRMLS_CC);
+
+ /*
+ * broken up for better performance:
+ * - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush
+ * - or apply op to the handler stack
+ */
+ if (OG(active) && (obh_cnt = zend_stack_count(&OG(handlers)))) {
+ context.in.data = (char *) str;
+ context.in.used = len;
+
+ if (obh_cnt > 1) {
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_op, &context);
+ } else if ((SUCCESS == zend_stack_top(&OG(handlers), (void *) &active)) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
+ php_output_handler_op(*active, &context);
+ } else {
+ php_output_context_pass(&context);
+ }
+ } else {
+ context.out.data = (char *) str;
+ context.out.used = len;
+ }
+
+ if (context.out.data) {
+ if (context.out.used) {
+#if PHP_OUTPUT_DEBUG
+ fprintf(stderr, "::: sapi_write('%s', %lu)\n", context.out.data, context.out.used);
+#endif
+ if (!SG(headers_sent) && php_header(TSRMLS_C)) {
+ if (zend_is_compiling(TSRMLS_C)) {
+ OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C);
+ OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C);
+ } else if (zend_is_executing(TSRMLS_C)) {
+ OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C);
+ OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C);
+ }
+#if PHP_OUTPUT_DEBUG
+ fprintf(stderr, "!!! output started at: %s (%d)\n", OG(output_start_filename), OG(output_start_lineno));
+#endif
+ }
+ sapi_module.ub_write(context.out.data, context.out.used TSRMLS_CC);
+ if (OG(flags) & PHP_OUTPUT_IMPLICITFLUSH) {
+ sapi_flush(TSRMLS_C);
+ }
+ }
+ }
+ php_output_context_dtor(&context);
}
/* }}} */
-/* {{{ php_ob_get_length
- * Return the size of the current output buffer */
-PHPAPI int php_ob_get_length(zval *p TSRMLS_DC)
+/* {{{ static int php_output_stack_apply_op(void *h, void *c)
+ Operation callback for the stack apply function */
+static int php_output_stack_apply_op(void *h, void *c)
{
- if (OG(ob_nesting_level) == 0) {
- return FAILURE;
+ int status = PHP_OUTPUT_HANDLER_FAILURE, was_disabled;
+ php_output_handler *handler = *(php_output_handler **) h;
+ php_output_context *context = (php_output_context *) c;
+
+ if (!(was_disabled = (handler->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
+ status = php_output_handler_op(handler, context);
+ }
+
+ /*
+ * handler ate all => break
+ * handler returned data or failed resp. is disabled => continue
+ */
+ switch (status) {
+ case PHP_OUTPUT_HANDLER_NO_DATA:
+ return 1;
+
+ case PHP_OUTPUT_HANDLER_SUCCESS:
+ /* swap contexts buffers, unless this is the last handler in the stack */
+ if (handler->level) {
+ php_output_context_swap(context);
+ }
+ return 0;
+
+ case PHP_OUTPUT_HANDLER_FAILURE:
+ default:
+ if (was_disabled) {
+ /* pass input along, if it's the last handler in the stack */
+ if (!handler->level) {
+ php_output_context_pass(context);
+ }
+ } else {
+ /* swap buffers, unless this is the last handler */
+ if (handler->level) {
+ php_output_context_swap(context);
+ }
+ }
+ return 0;
}
- ZVAL_LONG(p, OG(active_ob_buffer).text_length);
- return SUCCESS;
}
/* }}} */
-/*
- * Wrapper functions - implementation
- */
-
-
-/* buffered output function */
-static int php_b_body_write(const char *str, uint str_length TSRMLS_DC)
+/* {{{ static int php_output_stack_apply_clean(void *h, void *c)
+ Clean callback for the stack apply function */
+static int php_output_stack_apply_clean(void *h, void *c)
{
- php_ob_append(str, str_length TSRMLS_CC);
- return str_length;
+ php_output_handler *handler = *(php_output_handler **) h;
+ php_output_context *context = (php_output_context *) c;
+
+ handler->buffer.used = 0;
+ php_output_handler_op(handler, context);
+ php_output_context_reset(context);
+ return 0;
}
+/* }}} */
-/* {{{ php_ub_body_write_no_header
- */
-PHPAPI int php_ub_body_write_no_header(const char *str, uint str_length TSRMLS_DC)
+/* {{{ static int php_output_stack_apply_list(void *h, void *z)
+ List callback for the stack apply function */
+static int php_output_stack_apply_list(void *h, void *z)
{
- int result;
-
- if (OG(disable_output)) {
- return 0;
- }
-
- result = OG(php_header_write)(str, str_length TSRMLS_CC);
-
- if (OG(implicit_flush)) {
- sapi_flush(TSRMLS_C);
+ php_output_handler *handler = *(php_output_handler **) h;
+ zval *array = (zval *) z;
+
+ if (Z_TYPE_P(handler->name) == IS_UNICODE) {
+ add_next_index_unicodel(array, Z_USTRVAL_P(handler->name), Z_USTRLEN_P(handler->name), 1);
+ } else {
+ add_next_index_stringl(array, Z_STRVAL_P(handler->name), Z_STRLEN_P(handler->name), 1);
}
+ return 0;
+}
+/* }}} */
- return result;
+/* {{{ static int php_output_stack_apply_status(void *h, void *z)
+ Status callback for the stack apply function */
+static int php_output_stack_apply_status(void *h, void *z)
+{
+ php_output_handler *handler = *(php_output_handler **) h;
+ zval *array = (zval *) z;
+
+ add_next_index_zval(array, php_output_handler_status(handler, NULL));
+
+ return 0;
}
/* }}} */
-/* {{{ php_ub_body_write
- */
-PHPAPI int php_ub_body_write(const char *str, uint str_length TSRMLS_DC)
+/* {{{ static zval *php_output_handler_status(php_output_handler *handler, zval *entry)
+ Returns an array with the status of the output handler */
+static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry)
{
- int result = 0;
+ if (!entry) {
+ MAKE_STD_ZVAL(entry);
+ array_init(entry);
+ }
+
+ if (Z_TYPE_P(handler->name) == IS_UNICODE) {
+ add_assoc_unicodel(entry, "name", Z_USTRVAL_P(handler->name), Z_USTRLEN_P(handler->name), 1);
+ } else {
+ add_assoc_stringl(entry, "name", Z_STRVAL_P(handler->name), Z_STRLEN_P(handler->name), 1);
+ }
+ add_assoc_long(entry, "type", (long) (handler->flags & 0xf));
+ add_assoc_long(entry, "flags", (long) handler->flags);
+ add_assoc_long(entry, "level", (long) handler->level);
+ add_assoc_long(entry, "chunk_size", (long) handler->size);
+ add_assoc_long(entry, "buffer_size", (long) handler->buffer.size);
+ add_assoc_long(entry, "buffer_used", (long) handler->buffer.used);
+
+ return entry;
+}
+/* }}} */
- if (SG(request_info).headers_only) {
- if(SG(headers_sent)) {
- return 0;
+/* {{{ static int php_output_stack_pop(int discard, int shutdown TSRMLS_DC)
+ Pops an output handler off the stack, ignores whether the handler is removable if shutdown==1, discards the handlers output if discard==1 */
+static inline int php_output_stack_pop(int discard, int shutdown TSRMLS_DC)
+{
+ php_output_context context;
+ php_output_handler **current, *orphan = OG(active);
+
+ if (!orphan) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete.");
+ return 0;
+ } else if (!shutdown && !(orphan->flags & PHP_OUTPUT_HANDLER_REMOVABLE)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", orphan->name);
+ return 0;
+ } else {
+ php_output_context_init(&context, PHP_OUTPUT_HANDLER_FINAL TSRMLS_CC);
+
+ /* don't run the output handler if it's disabled */
+ if (!(orphan->flags & PHP_OUTPUT_HANDLER_DISABLED)) {
+ /* didn't it start yet? */
+ if (!(orphan->flags & PHP_OUTPUT_HANDLER_STARTED)) {
+ context.op |= PHP_OUTPUT_HANDLER_START;
+ }
+ /* signal that we're cleaning up */
+ if (discard) {
+ context.op |= PHP_OUTPUT_HANDLER_CLEAN;
+ }
+ php_output_handler_op(orphan, &context);
+ }
+
+ /* pop it off the stack */
+ zend_stack_del_top(&OG(handlers));
+ if (SUCCESS == zend_stack_top(&OG(handlers), (void *) ¤t)) {
+ OG(active) = *current;
+ } else {
+ OG(active) = NULL;
}
- php_header(TSRMLS_C);
- zend_bailout();
- }
- if (php_header(TSRMLS_C)) {
- if (zend_is_compiling(TSRMLS_C)) {
- OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C);
- OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C);
- } else if (zend_is_executing(TSRMLS_C)) {
- OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C);
- OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C);
+
+ /* pass output along */
+ if (context.out.data && context.out.used && !discard) {
+ php_output_write(context.out.data, context.out.used);
}
+
+ /* destroy the handler (after write!) */
+ php_output_handler_free(&orphan);
+ php_output_context_dtor(&context);
+
+ return 1;
+ }
+}
+/* }}} */
- OG(php_body_write) = php_ub_body_write_no_header;
- result = php_ub_body_write_no_header(str, str_length TSRMLS_CC);
+/* {{{ static SUCCESS|FAILURE php_output_handler_compat_func(void *ctx, int op, const char *in, size_t in_len, char **out, size_t *out_len TSRMLS_DC)
+ php_output_handler_context_func_t for php_output_handler_func_t output handlers */
+static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context)
+{
+ php_output_handler_func_t func = *(php_output_handler_func_t *) handler_context;
+ PHP_OUTPUT_TSRMLS(output_context);
+
+ if (func) {
+ func(output_context->in.data, output_context->in.used, &output_context->out.data, &output_context->out.used, output_context->op TSRMLS_CC);
+ output_context->out.free = 1;
+ return SUCCESS;
}
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ static SUCCESS|FAILURE php_output_handler_default_func(void *ctx, int op, const char *in, size_t in_len, char **out, size_t *out_len TSRMLS_DC)
+ Default output handler */
+static int php_output_handler_default_func(void **handler_context, php_output_context *output_context)
+{
+ output_context->out.data = output_context->in.data;
+ output_context->out.used = output_context->in.used;
+ output_context->out.free = output_context->in.free;
+ output_context->in.data = NULL;
+ output_context->in.used = 0;
+ return SUCCESS;
+}
+/* }}} */
- return result;
+/* {{{ static SUCCESS|FAILURE php_output_handler_devnull_func(void *ctx, int op, const char *in, size_t in_len, char **out, size_t *out_len TSRMLS_DC)
+ Null output handler */
+static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context)
+{
+ return SUCCESS;
}
/* }}} */
/*
- * HEAD support
+ * USERLAND (nearly 1:1 of old output.c)
*/
-/* {{{ proto bool ob_start([ string|array user_function [, int chunk_size [, bool erase]]])
+/* {{{ proto bool ob_start([ string|array user_function [, int chunk_size [, int flags]]])
Turn on Output Buffering (specifying an optional output handler). */
PHP_FUNCTION(ob_start)
{
- zval *output_handler=NULL;
- long chunk_size=0;
- zend_bool erase=1;
- int argc = ZEND_NUM_ARGS();
+ zval *output_handler = NULL;
+ long chunk_size = 0;
+ long flags = PHP_OUTPUT_HANDLER_CLEANABLE|PHP_OUTPUT_HANDLER_REMOVABLE;
- if (zend_parse_parameters(argc TSRMLS_CC, "|zlb", &output_handler, &chunk_size, &erase) == FAILURE) {
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|zlb", &output_handler, &chunk_size, &flags)) {
RETURN_FALSE;
}
-
- if (chunk_size < 0)
+ if (chunk_size < 0) {
chunk_size = 0;
+ }
- if (php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC)==FAILURE) {
+ if (SUCCESS != php_output_start_user(output_handler, chunk_size, flags)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to create buffer.");
RETURN_FALSE;
}
RETURN_TRUE;
Flush (send) contents of the output buffer. The last buffer content is sent to next buffer */
PHP_FUNCTION(ob_flush)
{
- if (ZEND_NUM_ARGS() != 0) {
+ if (ZEND_NUM_ARGS()) {
ZEND_WRONG_PARAM_COUNT();
}
-
- if (!OG(ob_nesting_level)) {
+
+ if (!OG(active)) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush.");
RETURN_FALSE;
}
- php_end_ob_buffer(1, 1 TSRMLS_CC);
+ php_output_flush();
RETURN_TRUE;
}
/* }}} */
Clean (delete) the current output buffer */
PHP_FUNCTION(ob_clean)
{
- if (ZEND_NUM_ARGS() != 0) {
+ if (ZEND_NUM_ARGS()) {
ZEND_WRONG_PARAM_COUNT();
}
- if (!OG(ob_nesting_level)) {
+ if (!OG(active)) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete.");
RETURN_FALSE;
}
-
- if (!OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
- php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name);
+ if (SUCCESS != php_output_clean()) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active)->name);
RETURN_FALSE;
}
-
- php_end_ob_buffer(0, 1 TSRMLS_CC);
RETURN_TRUE;
}
/* }}} */
Flush (send) the output buffer, and delete current output buffer */
PHP_FUNCTION(ob_end_flush)
{
- if (ZEND_NUM_ARGS() != 0) {
+ if (ZEND_NUM_ARGS()) {
ZEND_WRONG_PARAM_COUNT();
}
- if (!OG(ob_nesting_level)) {
+ if (!OG(active)) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush.");
RETURN_FALSE;
}
- if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
- php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name);
+ if (SUCCESS != php_output_end()) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active)->name);
RETURN_FALSE;
}
-
- php_end_ob_buffer(1, 0 TSRMLS_CC);
RETURN_TRUE;
}
/* }}} */
Clean the output buffer, and delete current output buffer */
PHP_FUNCTION(ob_end_clean)
{
- if (ZEND_NUM_ARGS() != 0) {
+ if (ZEND_NUM_ARGS()) {
ZEND_WRONG_PARAM_COUNT();
}
-
- if (!OG(ob_nesting_level)) {
+
+ if (!OG(active)) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete.");
RETURN_FALSE;
}
- if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
- php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name);
+ if (SUCCESS != php_output_discard()) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active)->name);
RETURN_FALSE;
}
-
- php_end_ob_buffer(0, 0 TSRMLS_CC);
RETURN_TRUE;
}
/* }}} */
Get current buffer contents, flush (send) the output buffer, and delete current output buffer */
PHP_FUNCTION(ob_get_flush)
{
- if (ZEND_NUM_ARGS() != 0) {
+ if (ZEND_NUM_ARGS()) {
ZEND_WRONG_PARAM_COUNT();
}
-
- /* get contents */
- if (php_ob_get_buffer(return_value TSRMLS_CC)==FAILURE) {
- RETURN_FALSE;
- }
- /* error checks */
- if (!OG(ob_nesting_level)) {
+
+ if (SUCCESS != php_output_get_contents(return_value)) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush.");
RETURN_FALSE;
}
- if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
- php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name);
- RETURN_FALSE;
+ if (SUCCESS != php_output_end()) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active)->name);
}
- /* flush */
- php_end_ob_buffer(1, 0 TSRMLS_CC);
}
/* }}} */
Get current buffer contents and delete current output buffer */
PHP_FUNCTION(ob_get_clean)
{
- if (ZEND_NUM_ARGS() != 0)
- ZEND_WRONG_PARAM_COUNT();
-
- /* get contents */
- if (php_ob_get_buffer(return_value TSRMLS_CC)==FAILURE) {
- RETURN_FALSE;
+ if (ZEND_NUM_ARGS()) {
+ ZEND_WRONG_PARAM_COUNT();
}
- /* error checks */
- if (!OG(ob_nesting_level)) {
+
+ if (SUCCESS != php_output_get_contents(return_value)) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete.");
RETURN_FALSE;
}
- if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
- php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name);
- RETURN_FALSE;
+ if (SUCCESS != php_output_discard()) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active)->name);
}
- /* delete buffer */
- php_end_ob_buffer(0, 0 TSRMLS_CC);
}
/* }}} */
Return the contents of the output buffer */
PHP_FUNCTION(ob_get_contents)
{
- if (ZEND_NUM_ARGS() != 0) {
+ if (ZEND_NUM_ARGS()) {
ZEND_WRONG_PARAM_COUNT();
}
-
- if (php_ob_get_buffer(return_value TSRMLS_CC)==FAILURE) {
+ if (SUCCESS != php_output_get_contents(return_value)) {
RETURN_FALSE;
}
}
Return the nesting level of the output buffer */
PHP_FUNCTION(ob_get_level)
{
- if (ZEND_NUM_ARGS() != 0) {
+ if (ZEND_NUM_ARGS()) {
ZEND_WRONG_PARAM_COUNT();
}
-
- RETURN_LONG (OG(ob_nesting_level));
+ RETURN_LONG(php_output_get_level());
}
/* }}} */
Return the length of the output buffer */
PHP_FUNCTION(ob_get_length)
{
- if (ZEND_NUM_ARGS() != 0) {
+ if (ZEND_NUM_ARGS()) {
ZEND_WRONG_PARAM_COUNT();
}
-
- if (php_ob_get_length(return_value TSRMLS_CC)==FAILURE) {
+ if (SUCCESS != php_output_get_length(return_value)) {
RETURN_FALSE;
}
}
/* }}} */
-/* {{{ int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result) */
-static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result)
+/* {{{ proto false|array ob_list_handlers()
+ * List all output_buffers in an array
+ */
+PHP_FUNCTION(ob_list_handlers)
{
- zval *elem;
- TSRMLS_FETCH();
-
- MAKE_STD_ZVAL(elem);
- array_init(elem);
-
- add_assoc_long(elem, "chunk_size", ob_buffer->chunk_size);
- if (!ob_buffer->chunk_size) {
- add_assoc_long(elem, "size", ob_buffer->size);
- add_assoc_long(elem, "block_size", ob_buffer->block_size);
- }
- if (ob_buffer->internal_output_handler) {
- add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_INTERNAL);
- add_assoc_long(elem, "buffer_size", ob_buffer->internal_output_handler_buffer_size);
+ if (ZEND_NUM_ARGS()) {
+ ZEND_WRONG_PARAM_COUNT();
}
- else {
- add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER);
+ if (!OG(active)) {
+ RETURN_FALSE;
}
- add_assoc_long(elem, "status", ob_buffer->status);
- add_assoc_text(elem, "name", ob_buffer->handler_name, 1);
- add_assoc_bool(elem, "del", ob_buffer->erase);
- add_next_index_zval(result, elem);
-
- return SUCCESS;
+
+ array_init(return_value);
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_list, return_value);
}
/* }}} */
-
/* {{{ proto false|array ob_get_status([bool full_status])
Return the status of the active or all output buffers */
PHP_FUNCTION(ob_get_status)
{
- int argc = ZEND_NUM_ARGS();
zend_bool full_status = 0;
- if (zend_parse_parameters(argc TSRMLS_CC, "|b", &full_status) == FAILURE )
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status)) {
RETURN_FALSE;
+ }
+ if (!OG(active)) {
+ RETURN_FALSE;
+ }
array_init(return_value);
-
if (full_status) {
- if (OG(ob_nesting_level)>1) {
- zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *elem, void *))php_ob_buffer_status, return_value);
- }
- if (OG(ob_nesting_level)>0 && php_ob_buffer_status(&OG(active_ob_buffer), return_value)==FAILURE) {
- RETURN_FALSE;
- }
- } else if (OG(ob_nesting_level)>0) {
- add_assoc_long(return_value, "level", OG(ob_nesting_level));
- if (OG(active_ob_buffer).internal_output_handler) {
- add_assoc_long(return_value, "type", PHP_OUTPUT_HANDLER_INTERNAL);
- } else {
- add_assoc_long(return_value, "type", PHP_OUTPUT_HANDLER_USER);
- }
- add_assoc_long(return_value, "status", OG(active_ob_buffer).status);
- add_assoc_text(return_value, "name", OG(active_ob_buffer).handler_name, 1);
- add_assoc_bool(return_value, "del", OG(active_ob_buffer).erase);
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_status, return_value);
+ } else {
+ php_output_handler_status(OG(active), return_value);
}
}
/* }}} */
-
/* {{{ proto void ob_implicit_flush([int flag])
Turn implicit flush on/off and is equivalent to calling flush() after every output call */
PHP_FUNCTION(ob_implicit_flush)
{
- zval **zv_flag;
- int flag;
-
- switch(ZEND_NUM_ARGS()) {
- case 0:
- flag = 1;
- break;
- case 1:
- if (zend_get_parameters_ex(1, &zv_flag)==FAILURE) {
- RETURN_FALSE;
- }
- convert_to_long_ex(zv_flag);
- flag = Z_LVAL_PP(zv_flag);
- break;
- default:
- ZEND_WRONG_PARAM_COUNT();
- break;
- }
- if (flag) {
- php_start_implicit_flush(TSRMLS_C);
- } else {
- php_end_implicit_flush(TSRMLS_C);
+ long flag = 1;
+
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag)) {
+ php_output_set_implicit_flush(flag);
}
}
/* }}} */
-
-/* {{{ char *php_get_output_start_filename(TSRMLS_D)
- Return filename start output something */
-PHPAPI char *php_get_output_start_filename(TSRMLS_D)
-{
- return OG(output_start_filename);
-}
-/* }}} */
-
-
-/* {{{ char *php_get_output_start_lineno(TSRMLS_D)
- Return line number start output something */
-PHPAPI int php_get_output_start_lineno(TSRMLS_D)
-{
- return OG(output_start_lineno);
-}
-/* }}} */
-
-
/* {{{ proto bool output_reset_rewrite_vars(void)
Reset(clear) URL rewriter values */
PHP_FUNCTION(output_reset_rewrite_vars)
}
/* }}} */
-
/* {{{ proto bool output_add_rewrite_var(string name, string value)
Add URL rewriter values */
PHP_FUNCTION(output_add_rewrite_var)
/* Output support */
#include "main/php_output.h"
-#define PHPWRITE(str, str_len) php_body_write((str), (str_len) TSRMLS_CC)
-#define PUTS(str) do { \
- const char *__str = (str); \
- php_body_write(__str, strlen(__str) TSRMLS_CC); \
-} while (0)
-
-#define PUTC(c) (php_body_write(&(c), 1 TSRMLS_CC), (c))
-#define PHPWRITE_H(str, str_len) php_header_write((str), (str_len) TSRMLS_CC)
-#define PUTS_H(str) do { \
- const char *__str = (str); \
- php_header_write(__str, strlen(__str) TSRMLS_CC); \
-} while (0)
-
-#define PUTC_H(c) (php_header_write(&(c), 1 TSRMLS_CC), (c))
+
#ifdef ZTS
#define VIRTUAL_DIR
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
- | Author: Zeev Suraski <zeev@zend.com> |
+ | Author: Michael Wallner <mike@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef PHP_OUTPUT_H
#define PHP_OUTPUT_H
+#define PHP_OUTPUT_NEWAPI 1
+
+/* handler ops */
+#define PHP_OUTPUT_HANDLER_WRITE 0x00 /* standard passthru */
+#define PHP_OUTPUT_HANDLER_START 0x01 /* start */
+#define PHP_OUTPUT_HANDLER_CLEAN 0x02 /* restart */
+#define PHP_OUTPUT_HANDLER_FLUSH 0x04 /* pass along as much as possible */
+#define PHP_OUTPUT_HANDLER_FINAL 0x08 /* finalize */
+#define PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_WRITE
+#define PHP_OUTPUT_HANDLER_END PHP_OUTPUT_HANDLER_FINAL
+
+/* handler types */
+#define PHP_OUTPUT_HANDLER_INTERNAL 0x0000
+#define PHP_OUTPUT_HANDLER_USER 0x0001
+
+/* handler ability flags */
+#define PHP_OUTPUT_HANDLER_CLEANABLE 0x0010
+#define PHP_OUTPUT_HANDLER_REMOVABLE 0x0020
+#define PHP_OUTPUT_HANDLER_STDFLAGS 0x0030
+
+/* handler status flags */
+#define PHP_OUTPUT_HANDLER_STARTED 0x1000
+#define PHP_OUTPUT_HANDLER_DISABLED 0x2000
+
+/* handler op return values */
+#define PHP_OUTPUT_HANDLER_FAILURE 0
+#define PHP_OUTPUT_HANDLER_SUCCESS 1
+#define PHP_OUTPUT_HANDLER_NO_DATA 2
+
+/* real global flags */
+#define PHP_OUTPUT_IMPLICITFLUSH 0x01
+#define PHP_OUTPUT_DISABLED 0x02
+/* supplementary flags for php_output_get_status() */
+#define PHP_OUTPUT_ACTIVE 0x10
+#define PHP_OUTPUT_LOCKED 0x20
+
+/* handler hooks */
+#define PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ 1
+#define PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS 2
+#define PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE 3
+#define PHP_OUTPUT_HANDLER_HOOK_DISABLE 4
+
+#define PHP_OUTPUT_HANDLER_INITBUF_SIZE(s) \
+( (s) ? \
+ (s) + PHP_OUTPUT_HANDLER_ALIGNTO_SIZE - ((s) % (PHP_OUTPUT_HANDLER_ALIGNTO_SIZE >> 2)) : \
+ PHP_OUTPUT_HANDLER_DEFAULT_SIZE \
+)
+#define PHP_OUTPUT_HANDLER_ALIGNTO_SIZE 0x1000
+#define PHP_OUTPUT_HANDLER_DEFAULT_SIZE 0x4000
+#define PHP_OUTPUT_HANDLER_DEFAULT_NAME "default output handler"
+#define PHP_OUTPUT_HANDLER_DEVNULL_NAME "null output handler"
+
+PHPAPI zval php_output_handler_default;
+PHPAPI zval php_output_handler_devnull;
+
+typedef struct _php_output_buffer {
+ char *data;
+ size_t size;
+ size_t used;
+ uint free:1;
+ uint _res:31;
+} php_output_buffer;
+
+typedef struct _php_output_context {
+ int op;
+ php_output_buffer in;
+ php_output_buffer out;
+#ifdef ZTS
+ void ***tsrm_ls;
+#endif
+} php_output_context;
+
+#define PHP_OUTPUT_TSRMLS(ctx) TSRMLS_FETCH_FROM_CTX((ctx)->tsrm_ls)
+
+/* old-style, stateless callback */
typedef void (*php_output_handler_func_t)(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC);
+/* new-style, opaque context callback */
+typedef int (*php_output_handler_context_func_t)(void **handler_context, php_output_context *output_context);
+/* conflict check callback */
+typedef int (*php_output_handler_conflict_check_t)(zval *handler_name TSRMLS_DC);
+
+typedef struct _php_output_handler {
+ zval *name;
+ int flags;
+ int level;
+ size_t size;
+ php_output_buffer buffer;
+
+ void *opaq;
+ void (*dtor)(void *opaq TSRMLS_DC);
+
+ union {
+ zval *user;
+ php_output_handler_context_func_t internal;
+ };
+} php_output_handler;
+
+ZEND_BEGIN_MODULE_GLOBALS(output)
+ int flags;
+ zend_stack handlers;
+ php_output_handler *active;
+ php_output_handler *running;
+ char *output_start_filename;
+ int output_start_lineno;
+ zval *default_output_handler_name;
+ zval *devnull_output_handler_name;
+ZEND_END_MODULE_GLOBALS(output);
+
+/* there should not be a need to use OG() from outside of output.c */
+#ifdef ZTS
+#define OG(v) TSRMG(output_globals_id, zend_output_globals *, v)
+#else
+#define OG(v) (output_globals.v)
+#endif
+
+/* convenience macros */
+#define PHPWRITE(str, str_len) php_output_write((str), (str_len))
+#define PHPWRITE_H(str, str_len) php_output_write_unbuffered((str), (str_len))
+
+#define PUTC(c) (php_output_write(&(c), 1), (c))
+#define PUTC_H(c) (php_output_write_unbuffered(&(c), 1), (c))
+
+#define PUTS(str) do { \
+ const char *__str = (str); \
+ php_output_write(__str, strlen(__str)); \
+} while (0)
+#define PUTS_H(str) do { \
+ const char *__str = (str); \
+ php_output_write_unbuffered(__str, strlen(__str)); \
+} while (0)
+
BEGIN_EXTERN_C()
+#define php_output_tearup() \
+ php_output_startup(); \
+ php_output_activate()
+#define php_output_teardown() \
+ php_output_end_all(); \
+ php_output_deactivate(); \
+ php_output_shutdown()
+
+/* MINIT */
PHPAPI void php_output_startup(void);
-PHPAPI void php_output_activate(TSRMLS_D);
-PHPAPI void php_output_set_status(zend_bool status TSRMLS_DC);
-PHPAPI void php_output_register_constants(TSRMLS_D);
-PHPAPI int php_default_output_func(const char *str, uint str_len TSRMLS_DC);
-PHPAPI int php_ub_body_write(const char *str, uint str_length TSRMLS_DC);
-PHPAPI int php_ub_body_write_no_header(const char *str, uint str_length TSRMLS_DC);
-PHPAPI int php_body_write(const char *str, uint str_length TSRMLS_DC);
-PHPAPI int php_header_write(const char *str, uint str_length TSRMLS_DC);
-PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC);
-PHPAPI int php_start_ob_buffer_named(const char *output_handler_name, uint chunk_size, zend_bool erase TSRMLS_DC);
-PHPAPI void php_end_ob_buffer(zend_bool send_buffer, zend_bool just_flush TSRMLS_DC);
-PHPAPI void php_end_ob_buffers(zend_bool send_buffer TSRMLS_DC);
-PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC);
-PHPAPI int php_ob_get_length(zval *p TSRMLS_DC);
-PHPAPI void php_start_implicit_flush(TSRMLS_D);
-PHPAPI void php_end_implicit_flush(TSRMLS_D);
-PHPAPI char *php_get_output_start_filename(TSRMLS_D);
-PHPAPI int php_get_output_start_lineno(TSRMLS_D);
-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);
-PHPAPI int php_ob_handler_used(char *handler_name TSRMLS_DC);
-PHPAPI int php_ob_init_conflict(char *handler_new, char *handler_set TSRMLS_DC);
-PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC);
-PHPAPI int php_ob_get_length(zval *p TSRMLS_DC);
+/* MSHUTDOWN */
+PHPAPI void php_output_shutdown(void);
+
+#define php_output_register_constants() _php_output_register_constants(TSRMLS_C)
+PHPAPI void _php_output_register_constants(TSRMLS_D);
+
+/* RINIT */
+#define php_output_activate() _php_output_activate(TSRMLS_C)
+PHPAPI int _php_output_activate(TSRMLS_D);
+/* RSHUTDOWN */
+#define php_output_deactivate() _php_output_deactivate(TSRMLS_C)
+PHPAPI void _php_output_deactivate(TSRMLS_D);
+
+
+#define php_output_get_default_handler_name() _php_output_get_default_handler_name(TSRMLS_C)
+PHPAPI zval *_php_output_get_default_handler_name(TSRMLS_D);
+
+#define php_output_get_devnull_handler_name() _php_output_get_devnull_handler_name(TSRMLS_C)
+PHPAPI zval *_php_output_get_devnull_handler_name(TSRMLS_D);
+
+
+#define php_output_set_status(s) _php_output_set_status((s) TSRMLS_CC)
+PHPAPI void _php_output_set_status(int status TSRMLS_DC);
+
+#define php_output_get_status() _php_output_get_status(TSRMLS_C)
+PHPAPI int _php_output_get_status(TSRMLS_D);
+
+#define php_output_write_unbuffered(s, l) _php_output_write_unbuffered((s), (l) TSRMLS_CC)
+PHPAPI int _php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC);
+
+#define php_output_write(s, l) _php_output_write((s), (l) TSRMLS_CC)
+PHPAPI int _php_output_write(const char *str, size_t len TSRMLS_DC);
+
+#define php_output_flush() _php_output_flush(TSRMLS_C)
+PHPAPI void _php_output_flush(TSRMLS_D);
+
+#define php_output_flush_all() _php_output_flush_all(TSRMLS_C)
+PHPAPI void _php_output_flush_all(TSRMLS_D);
+
+#define php_output_clean() _php_output_clean(TSRMLS_C)
+PHPAPI int _php_output_clean(TSRMLS_D);
+
+#define php_output_clean_all() _php_output_clean_all(TSRMLS_C)
+PHPAPI void _php_output_clean_all(TSRMLS_D);
+
+#define php_output_end() _php_output_end(TSRMLS_C)
+PHPAPI int _php_output_end(TSRMLS_D);
+
+#define php_output_end_all() _php_output_end_all(TSRMLS_C)
+PHPAPI void _php_output_end_all(TSRMLS_D);
+
+#define php_output_discard() _php_output_discard(TSRMLS_C)
+PHPAPI int _php_output_discard(TSRMLS_D);
+
+#define php_output_discard_all() _php_output_discard_all(TSRMLS_C)
+PHPAPI void _php_output_discard_all(TSRMLS_D);
+
+
+#define php_output_get_contents(p) _php_output_get_contents((p) TSRMLS_CC)
+PHPAPI int _php_output_get_contents(zval *p TSRMLS_DC);
+
+#define php_output_get_length(p) _php_output_get_length((p) TSRMLS_CC)
+PHPAPI int _php_output_get_length(zval *TSRMLS_DC);
+
+#define php_output_get_level() _php_output_get_level(TSRMLS_C)
+PHPAPI int _php_output_get_level(TSRMLS_D);
+
+
+#define php_output_start_default() _php_output_start_default(TSRMLS_C)
+PHPAPI int _php_output_start_default(TSRMLS_D);
+
+#define php_output_start_devnull() _php_output_start_devnull(TSRMLS_C)
+PHPAPI int _php_output_start_devnull(TSRMLS_D);
+
+#define php_output_start_user(h, s, f) _php_output_start_user((h), (s), (f) TSRMLS_CC)
+PHPAPI int _php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC);
+
+#define php_output_start_internal(n, h, s, f) _php_output_start_internal((n), (h), (s), (f) TSRMLS_CC)
+PHPAPI int _php_output_start_internal(zval *name, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC);
+
+#define php_output_handler_create_user(h, s, f) _php_output_handler_create_user((h), (s), (f) TSRMLS_CC)
+PHPAPI php_output_handler *_php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC);
+
+#define php_output_handler_create_internal(n, h, s, f) _php_output_handler_create_internal((n), (h), (s), (f) TSRMLS_CC)
+PHPAPI php_output_handler *_php_output_handler_create_internal(zval *name, php_output_handler_context_func_t handler, size_t chunk_size, int flags TSRMLS_DC);
+
+#define php_output_handler_set_context(h, c, d) _php_output_handler_set_context((h), (c), (d) TSRMLS_CC)
+PHPAPI void _php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC);
+
+#define php_output_handler_start(h) _php_output_handler_start((h) TSRMLS_CC)
+PHPAPI int _php_output_handler_start(php_output_handler *handler TSRMLS_DC);
+
+#define php_output_handler_started(n) _php_output_handler_started((n) TSRMLS_CC)
+PHPAPI int _php_output_handler_started(zval *name TSRMLS_DC);
+
+#define php_output_handler_hook(t, a) _php_output_handler_hook((t), (a) TSRMLS_CC)
+PHPAPI int _php_output_handler_hook(int type, void *arg TSRMLS_DC);
+
+#define php_output_handler_dtor(h) _php_output_handler_dtor((h) TSRMLS_CC)
+PHPAPI void _php_output_handler_dtor(php_output_handler *handler TSRMLS_DC);
+
+#define php_output_handler_free(h) _php_output_handler_free((h) TSRMLS_CC)
+PHPAPI void _php_output_handler_free(php_output_handler **handler TSRMLS_DC);
+
+
+#define php_output_set_implicit_flush(f) _php_output_set_implicit_flush((f) TSRMLS_CC)
+PHPAPI void _php_output_set_implicit_flush(int flush TSRMLS_DC);
+
+#define php_output_get_start_filename() _php_output_get_start_filename(TSRMLS_C)
+PHPAPI char *_php_output_get_start_filename(TSRMLS_D);
+
+#define php_output_get_start_lineno() _php_output_get_start_lineno(TSRMLS_C)
+PHPAPI int _php_output_get_start_lineno(TSRMLS_D);
+
+
+#define php_output_handler_conflict(n, s) _php_output_handler_conflict((n), (s) TSRMLS_CC)
+PHPAPI int _php_output_handler_conflict(zval *handler_new, zval *handler_set TSRMLS_DC);
+
+#define php_output_handler_conflict_register(n, f) _php_output_handler_conflict_register((n), (f) TSRMLS_CC)
+PHPAPI int _php_output_handler_conflict_register(zval *handler_name, php_output_handler_conflict_check_t check_func TSRMLS_DC);
+
+#define php_output_handler_reverse_conflict_register(n, f) _php_output_handler_reverse_conflict_register((n), (f) TSRMLS_CC)
+PHPAPI int _php_output_handler_reverse_conflict_register(zval *handler_name, php_output_handler_conflict_check_t check_func TSRMLS_DC);
+
+#define php_output_handler_alias(n) _php_output_handler_alias((n) TSRMLS_CC)
+PHPAPI php_output_handler_context_func_t *_php_output_handler_alias(zval *handler_name TSRMLS_DC);
+
+#define php_output_handler_alias_register(n, f) _php_output_handler_alias_register((n), (f) TSRMLS_CC)
+PHPAPI int _php_output_handler_alias_register(zval *handler_name, php_output_handler_context_func_t func TSRMLS_DC);
+
END_EXTERN_C()
+
PHP_FUNCTION(ob_start);
PHP_FUNCTION(ob_flush);
PHP_FUNCTION(ob_clean);
PHP_FUNCTION(ob_implicit_flush);
PHP_FUNCTION(ob_list_handlers);
-typedef struct _php_ob_buffer {
- char *buffer;
- uint size;
- uint text_length;
- int block_size;
- uint chunk_size;
- int status;
- zval *output_handler;
- php_output_handler_func_t internal_output_handler;
- char *internal_output_handler_buffer;
- uint internal_output_handler_buffer_size;
- zstr handler_name;
- zend_bool erase;
-} php_ob_buffer;
-
-typedef struct _php_output_globals {
- int (*php_body_write)(const char *str, uint str_length TSRMLS_DC); /* string output */
- int (*php_header_write)(const char *str, uint str_length TSRMLS_DC); /* unbuffer string output */
- php_ob_buffer active_ob_buffer;
- unsigned char implicit_flush;
- char *output_start_filename;
- int output_start_lineno;
- zend_stack ob_buffers;
- int ob_nesting_level;
- zend_bool ob_lock;
- zend_bool disable_output;
-} php_output_globals;
-
-#ifdef ZTS
-#define OG(v) TSRMG(output_globals_id, php_output_globals *, v)
-ZEND_API extern int output_globals_id;
-#else
-#define OG(v) (output_globals.v)
-ZEND_API extern php_output_globals output_globals;
-#endif
-
-#define PHP_OUTPUT_HANDLER_START (1<<0)
-#define PHP_OUTPUT_HANDLER_CONT (1<<1)
-#define PHP_OUTPUT_HANDLER_END (1<<2)
-
-#define PHP_OUTPUT_HANDLER_INTERNAL 0
-#define PHP_OUTPUT_HANDLER_USER 1
-
PHP_FUNCTION(output_add_rewrite_var);
PHP_FUNCTION(output_reset_rewrite_vars);
+#endif
-#endif /* PHP_OUTPUT_H */
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
{
TSRMLS_FETCH();
- php_output_set_status(0 TSRMLS_CC);
+ php_output_set_status(PHP_OUTPUT_DISABLED);
if (AP(in_request)) {
AP(in_request) = 0;
php_request_shutdown(dummy);
RETURN_FALSE;
}
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all();
php_header(TSRMLS_C);
if (run_sub_req(rr)) {
}
/* Flush everything. */
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all();
php_header(TSRMLS_C);
/* Ensure that the ap_r* layer for the main request is flushed, to
{
TSRMLS_FETCH();
AP(current_hook) = AP_CLEANUP;
- php_output_set_status(0 TSRMLS_CC);
+ php_output_set_status(PHP_OUTPUT_DISABLED);
SG(server_context) = NULL; /* The server context (request) is invalid by the time run_cleanups() is called */
if(SG(sapi_started)) {
php_request_shutdown(dummy);
RETURN_FALSE;
}
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all();
php_header(TSRMLS_C);
if (run_sub_req(rr)) {
case 'h':
case '?':
no_headers = 1;
- php_output_startup();
- php_output_activate(TSRMLS_C);
+ php_output_tearup();
SG(headers_sent) = 1;
php_cgi_usage(argv[0]);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
exit(1);
break;
}
if (!cgi && !fastcgi) {
if (cgi_sapi_module.php_ini_path_override && cgi_sapi_module.php_ini_ignore) {
no_headers = 1;
- php_output_startup();
- php_output_activate(TSRMLS_C);
+ php_output_tearup();
SG(headers_sent) = 1;
php_printf("You cannot use both -n and -c switch. Use -h for help.\n");
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
exit(1);
}
SG(request_info).no_headers = 1;
}
php_print_info(0xFFFFFFFF TSRMLS_CC);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
exit(0);
break;
break;
case 'm': /* list compiled in modules */
- php_output_startup();
- php_output_activate(TSRMLS_C);
+ php_output_tearup();
SG(headers_sent) = 1;
php_printf("[PHP Modules]\n");
print_modules(TSRMLS_C);
php_printf("\n[Zend Modules]\n");
print_extensions(TSRMLS_C);
php_printf("\n");
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
exit(0);
break;
#else
php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2006 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
#endif
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
exit(0);
break;
if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
zend_strip(TSRMLS_C);
fclose(file_handle.handle.fp);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
}
return SUCCESS;
break;
php_get_highlight_struct(&syntax_highlighter_ini);
zend_highlight(&syntax_highlighter_ini TSRMLS_CC);
fclose(file_handle.handle.fp);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
}
return SUCCESS;
}
open_file_for_scanning(&file_handle TSRMLS_CC);
zend_indent();
fclose(file_handle.handle.fp);
+ php_output_teardown();
return SUCCESS;
break;
#endif
goto err;
}
php_cli_usage(argv[0]);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all();
exit_status=0;
goto out;
goto err;
}
php_print_info(0xFFFFFFFF TSRMLS_CC);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all();
exit_status=0;
goto out;
php_printf("\n[Zend Modules]\n");
print_extensions(TSRMLS_C);
php_printf("\n");
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all();
exit_status=0;
goto out;
#endif
get_zend_version()
);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all();
exit_status=0;
goto out;
while ((c=ap_php_getopt(argc, argv, OPTSTRING))!=-1) {
switch (c) {
case '?':
- php_output_startup();
- php_output_activate(TSRMLS_C);
+ php_output_tearup();
SG(headers_sent) = 1;
php_milter_usage(argv[0]);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
exit(1);
break;
}
case 'h': /* help & quit */
case '?':
- php_output_startup();
- php_output_activate(TSRMLS_C);
+ php_output_tearup();
SG(headers_sent) = 1;
php_milter_usage(argv[0]);
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
exit(1);
break;
SG(headers_sent) = 1;
SG(request_info).no_headers = 1;
php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2006 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_teardown();
exit(1);
break;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include uri '%s' - Sub-requests do not work with zlib.output_compression", (*uri)->value.str.val);
RETURN_FALSE;
} else {
- php_end_ob_buffers(1 TSRMLS_CC);
+ php_output_end_all();
php_header(TSRMLS_C);
/* do the sub-request */
--- /dev/null
+--TEST--
+output buffering - nothing
+--FILE--
+<?php
+echo "foo\n";
+?>
+--EXPECTF--
+foo
--- /dev/null
+--TEST--
+output buffering - ob_start
+--FILE--
+<?php
+ob_start();
+echo "foo\n";
+?>
+--EXPECT--
+foo
--- /dev/null
+--TEST--
+output buffering - ob_flush
+--FILE--
+<?php
+ob_start();
+echo "foo\n";
+ob_flush();
+echo "bar\n";
+ob_flush();
+?>
+--EXPECT--
+foo
+bar
--- /dev/null
+--TEST--
+output buffering - ob_clean
+--FILE--
+<?php
+ob_start();
+echo "foo\n";
+ob_clean();
+echo "bar\n";
+?>
+--EXPECT--
+bar
--- /dev/null
+--TEST--
+output buffering - ob_end_clean
+--FILE--
+<?php
+ob_start();
+echo "foo\n";
+ob_start();
+echo "bar\n";
+ob_end_clean();
+echo "baz\n";
+?>
+--EXPECT--
+foo
+baz
--- /dev/null
+--TEST--
+output buffering - ob_end_flush
+--FILE--
+<?php
+ob_start();
+echo "foo\n";
+ob_end_flush();
+var_dump(ob_get_level());
+?>
+--EXPECT--
+foo
+int(0)
--- /dev/null
+--TEST--
+output buffering - ob_get_clean
+--FILE--
+<?php
+ob_start();
+echo "foo\n";
+var_dump(ob_get_clean());
+?>
+--EXPECT--
+string(4) "foo
+"
--- /dev/null
+--TEST--
+output buffering - ob_get_contents
+--FILE--
+<?php
+ob_start();
+echo "foo\n";
+echo ob_get_contents();
+?>
+--EXPECT--
+foo
+foo
--- /dev/null
+--TEST--
+output buffering - ob_get_flush
+--FILE--
+<?php
+ob_start();
+echo "foo\n";
+var_dump(ob_get_flush());
+?>
+--EXPECT--
+foo
+string(4) "foo
+"
--- /dev/null
+--TEST--
+output buffering - fatalism
+--FILE--
+<?php
+function obh($s)
+{
+ print_r($s, 1);
+}
+ob_start("obh");
+echo "foo\n";
+?>
+--EXPECTF--
+Fatal error: print_r(): Cannot use output buffering in output buffering display handlers in %s/ob_010.php on line %d
--- /dev/null
+--TEST--
+output buffering - fatalism
+--FILE--
+<?php
+function obh($s)
+{
+ return ob_get_flush();
+}
+ob_start("obh");
+echo "foo\n";
+?>
+--EXPECTF--
+Fatal error: ob_get_flush(): Cannot use output buffering in output buffering display handlers in %s/ob_011.php on line %d
--- /dev/null
+--TEST--
+output buffering - multiple
+--FILE--
+<?php
+echo 0;
+ ob_start();
+ ob_start();
+ ob_start();
+ ob_start();
+ echo 1;
+ ob_end_flush();
+ echo 2;
+ $ob = ob_get_clean();
+ echo 3;
+ ob_flush();
+ ob_end_clean();
+ echo 4;
+ ob_end_flush();
+echo $ob;
+?>
+--EXPECT--
+03412
--- /dev/null
+--TEST--
+output buffering - handlers/status
+--FILE--
+<?php
+function a($s){return $s;}
+function b($s){return $s;}
+function c($s){return $s;}
+function d($s){return $s;}
+
+ob_start();
+ob_start('a');
+ob_start('b');
+ob_start('c');
+ob_start('d');
+ob_start();
+
+echo "foo\n";
+
+ob_flush();
+ob_end_clean();
+ob_flush();
+
+print_r(ob_list_handlers());
+print_r(ob_get_status());
+print_r(ob_get_status(true));
+
+?>
+--EXPECT--
+foo
+Array
+(
+ [0] => default output handler
+ [1] => a
+ [2] => b
+ [3] => c
+ [4] => d
+)
+Array
+(
+ [name] => d
+ [type] => 1
+ [flags] => 4145
+ [level] => 4
+ [chunk_size] => 0
+ [buffer_size] => 16384
+ [buffer_used] => 96
+)
+Array
+(
+ [0] => Array
+ (
+ [name] => default output handler
+ [type] => 0
+ [flags] => 48
+ [level] => 0
+ [chunk_size] => 0
+ [buffer_size] => 16384
+ [buffer_used] => 0
+ )
+
+ [1] => Array
+ (
+ [name] => a
+ [type] => 1
+ [flags] => 49
+ [level] => 1
+ [chunk_size] => 0
+ [buffer_size] => 16384
+ [buffer_used] => 0
+ )
+
+ [2] => Array
+ (
+ [name] => b
+ [type] => 1
+ [flags] => 49
+ [level] => 2
+ [chunk_size] => 0
+ [buffer_size] => 16384
+ [buffer_used] => 0
+ )
+
+ [3] => Array
+ (
+ [name] => c
+ [type] => 1
+ [flags] => 49
+ [level] => 3
+ [chunk_size] => 0
+ [buffer_size] => 16384
+ [buffer_used] => 4
+ )
+
+ [4] => Array
+ (
+ [name] => d
+ [type] => 1
+ [flags] => 4145
+ [level] => 4
+ [chunk_size] => 0
+ [buffer_size] => 16384
+ [buffer_used] => 248
+ )
+
+)
--- /dev/null
+--TEST--
+output buffering - failure
+--FILE--
+<?php
+/*
+ * apparently the error handler cannot get the current function name on shutdown
+ */
+ob_start("str_rot13");
+echo "foo\n";
+?>
+--EXPECTF--
+foo
+
+Warning: Wrong parameter count for (null)() in %s on line %d
--- /dev/null
+--TEST--
+output buffering - failure
+--FILE--
+<?php
+ob_start("str_rot13", 1);
+echo "foo\n";
+?>
+--EXPECTF--
+foo
+
+Warning: Wrong parameter count for str_rot13() in %s on line %d