Annotation of embedaddon/php/main/output.c, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 The PHP Group |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Zeev Suraski <zeev@zend.com> |
16: | Thies C. Arntzen <thies@thieso.net> |
17: | Marcus Boerger <helly@php.net> |
18: +----------------------------------------------------------------------+
19: */
20:
21: /* $Id: output.c 321634 2012-01-01 13:15:04Z felipe $ */
22:
23: #include "php.h"
24: #include "ext/standard/head.h"
25: #include "ext/standard/basic_functions.h"
26: #include "ext/standard/url_scanner_ex.h"
27: #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
28: #include "ext/zlib/php_zlib.h"
29: #endif
30: #include "SAPI.h"
31:
32: #define OB_DEFAULT_HANDLER_NAME "default output handler"
33:
34: /* output functions */
35: static int php_b_body_write(const char *str, uint str_length TSRMLS_DC);
36:
37: static int php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC);
38: static void php_ob_append(const char *text, uint text_length TSRMLS_DC);
39: #if 0
40: static void php_ob_prepend(const char *text, uint text_length);
41: #endif
42:
43: #ifdef ZTS
44: int output_globals_id;
45: #else
46: php_output_globals output_globals;
47: #endif
48:
49: /* {{{ php_default_output_func */
50: PHPAPI int php_default_output_func(const char *str, uint str_len TSRMLS_DC)
51: {
52: fwrite(str, 1, str_len, stderr);
53: /* See http://support.microsoft.com/kb/190351 */
54: #ifdef PHP_WIN32
55: fflush(stderr);
56: #endif
57: return str_len;
58: }
59: /* }}} */
60:
61: /* {{{ php_output_init_globals */
62: static void php_output_init_globals(php_output_globals *output_globals_p TSRMLS_DC)
63: {
64: OG(php_body_write) = php_default_output_func;
65: OG(php_header_write) = php_default_output_func;
66: OG(implicit_flush) = 0;
67: OG(output_start_filename) = NULL;
68: OG(output_start_lineno) = 0;
69: }
70: /* }}} */
71:
72: /* {{{ php_output_startup
73: * Start output layer */
74: PHPAPI void php_output_startup(void)
75: {
76: #ifdef ZTS
77: ts_allocate_id(&output_globals_id, sizeof(php_output_globals), (ts_allocate_ctor) php_output_init_globals, NULL);
78: #else
79: php_output_init_globals(&output_globals TSRMLS_CC);
80: #endif
81: }
82: /* }}} */
83:
84: /* {{{ php_output_activate
85: * Initilize output global for activation */
86: PHPAPI void php_output_activate(TSRMLS_D)
87: {
88: OG(php_body_write) = php_ub_body_write;
89: OG(php_header_write) = sapi_module.ub_write;
90: OG(ob_nesting_level) = 0;
91: OG(ob_lock) = 0;
92: OG(disable_output) = 0;
93: OG(output_start_filename) = NULL;
94: OG(output_start_lineno) = 0;
95: }
96: /* }}} */
97:
98: /* {{{ php_output_register_constants */
99: void php_output_register_constants(TSRMLS_D)
100: {
101: REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT);
102: REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_CONT, CONST_CS | CONST_PERSISTENT);
103: REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_END, CONST_CS | CONST_PERSISTENT);
104: }
105: /* }}} */
106:
107: /* {{{ php_output_set_status
108: * Toggle output status. Do NOT use in application code, only in SAPIs where appropriate. */
109: PHPAPI void php_output_set_status(zend_bool status TSRMLS_DC)
110: {
111: OG(disable_output) = !status;
112: }
113: /* }}} */
114:
115: /* {{{ php_body_write
116: * Write body part */
117: PHPAPI int php_body_write(const char *str, uint str_length TSRMLS_DC)
118: {
119: return OG(php_body_write)(str, str_length TSRMLS_CC);
120: }
121: /* }}} */
122:
123: /* {{{ php_header_write
124: * Write HTTP header */
125: PHPAPI int php_header_write(const char *str, uint str_length TSRMLS_DC)
126: {
127: if (OG(disable_output)) {
128: return 0;
129: } else {
130: return OG(php_header_write)(str, str_length TSRMLS_CC);
131: }
132: }
133: /* }}} */
134:
135: /* {{{ php_start_ob_buffer
136: * Start output buffering */
137: PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
138: {
139: uint initial_size, block_size;
140:
141: if (OG(ob_lock)) {
142: if (SG(headers_sent) && !SG(request_info).headers_only) {
143: OG(php_body_write) = php_ub_body_write_no_header;
144: } else {
145: OG(php_body_write) = php_ub_body_write;
146: }
147: OG(ob_nesting_level) = 0;
148: php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers");
149: return FAILURE;
150: }
151: if (chunk_size > 0) {
152: if (chunk_size==1) {
153: chunk_size = 4096;
154: }
155: initial_size = (chunk_size*3/2);
156: block_size = chunk_size/2;
157: } else {
158: initial_size = 40*1024;
159: block_size = 10*1024;
160: }
161: return php_ob_init(initial_size, block_size, output_handler, chunk_size, erase TSRMLS_CC);
162: }
163: /* }}} */
164:
165: /* {{{ php_start_ob_buffer_named
166: * Start output buffering */
167: PHPAPI int php_start_ob_buffer_named(const char *output_handler_name, uint chunk_size, zend_bool erase TSRMLS_DC)
168: {
169: zval *output_handler;
170: int result;
171:
172: ALLOC_INIT_ZVAL(output_handler);
173: Z_STRLEN_P(output_handler) = strlen(output_handler_name); /* this can be optimized */
174: Z_STRVAL_P(output_handler) = estrndup(output_handler_name, Z_STRLEN_P(output_handler));
175: Z_TYPE_P(output_handler) = IS_STRING;
176: result = php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC);
177: zval_dtor(output_handler);
178: FREE_ZVAL(output_handler);
179: return result;
180: }
181: /* }}} */
182:
183: /* {{{ php_end_ob_buffer
184: * End output buffering (one level) */
185: PHPAPI void php_end_ob_buffer(zend_bool send_buffer, zend_bool just_flush TSRMLS_DC)
186: {
187: char *final_buffer=NULL;
188: unsigned int final_buffer_length=0;
189: zval *alternate_buffer=NULL;
190: char *to_be_destroyed_buffer, *to_be_destroyed_handler_name;
191: char *to_be_destroyed_handled_output[2] = { 0, 0 };
192: int status;
193: php_ob_buffer *prev_ob_buffer_p=NULL;
194: php_ob_buffer orig_ob_buffer;
195:
196: if (OG(ob_nesting_level)==0) {
197: return;
198: }
199: status = 0;
200: if (!OG(active_ob_buffer).status & PHP_OUTPUT_HANDLER_START) {
201: /* our first call */
202: status |= PHP_OUTPUT_HANDLER_START;
203: }
204: if (just_flush) {
205: status |= PHP_OUTPUT_HANDLER_CONT;
206: } else {
207: status |= PHP_OUTPUT_HANDLER_END;
208: }
209:
210: #if 0
211: {
212: FILE *fp;
213: fp = fopen("/tmp/ob_log", "a");
214: fprintf(fp, "NestLevel: %d ObStatus: %d HandlerName: %s\n", OG(ob_nesting_level), status, OG(active_ob_buffer).handler_name);
215: fclose(fp);
216: }
217: #endif
218:
219: if (OG(active_ob_buffer).internal_output_handler) {
220: final_buffer = OG(active_ob_buffer).internal_output_handler_buffer;
221: final_buffer_length = OG(active_ob_buffer).internal_output_handler_buffer_size;
222: 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);
223: } else if (OG(active_ob_buffer).output_handler) {
224: zval **params[2];
225: zval *orig_buffer;
226: zval *z_status;
227:
228: ALLOC_INIT_ZVAL(orig_buffer);
229: ZVAL_STRINGL(orig_buffer, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
230:
231: ALLOC_INIT_ZVAL(z_status);
232: ZVAL_LONG(z_status, status);
233:
234: params[0] = &orig_buffer;
235: params[1] = &z_status;
236: OG(ob_lock) = 1;
237:
238: if (call_user_function_ex(CG(function_table), NULL, OG(active_ob_buffer).output_handler, &alternate_buffer, 2, params, 1, NULL TSRMLS_CC)==SUCCESS) {
239: if (alternate_buffer && !(Z_TYPE_P(alternate_buffer)==IS_BOOL && Z_BVAL_P(alternate_buffer)==0)) {
240: convert_to_string_ex(&alternate_buffer);
241: final_buffer = Z_STRVAL_P(alternate_buffer);
242: final_buffer_length = Z_STRLEN_P(alternate_buffer);
243: }
244: }
245: OG(ob_lock) = 0;
246: if (!just_flush) {
247: zval_ptr_dtor(&OG(active_ob_buffer).output_handler);
248: }
249: zval_ptr_dtor(&orig_buffer);
250: zval_ptr_dtor(&z_status);
251: }
252:
253: if (!final_buffer) {
254: final_buffer = OG(active_ob_buffer).buffer;
255: final_buffer_length = OG(active_ob_buffer).text_length;
256: }
257:
258: if (OG(ob_nesting_level)==1) { /* end buffering */
259: if (SG(headers_sent) && !SG(request_info).headers_only) {
260: OG(php_body_write) = php_ub_body_write_no_header;
261: } else {
262: OG(php_body_write) = php_ub_body_write;
263: }
264: }
265:
266: to_be_destroyed_buffer = OG(active_ob_buffer).buffer;
267: to_be_destroyed_handler_name = OG(active_ob_buffer).handler_name;
268: if (OG(active_ob_buffer).internal_output_handler
269: && (final_buffer != OG(active_ob_buffer).internal_output_handler_buffer)
270: && (final_buffer != OG(active_ob_buffer).buffer)) {
271: to_be_destroyed_handled_output[0] = final_buffer;
272: }
273:
274: if (!just_flush) {
275: if (OG(active_ob_buffer).internal_output_handler) {
276: to_be_destroyed_handled_output[1] = OG(active_ob_buffer).internal_output_handler_buffer;
277: }
278: }
279: if (OG(ob_nesting_level)>1) { /* restore previous buffer */
280: zend_stack_top(&OG(ob_buffers), (void **) &prev_ob_buffer_p);
281: orig_ob_buffer = OG(active_ob_buffer);
282: OG(active_ob_buffer) = *prev_ob_buffer_p;
283: zend_stack_del_top(&OG(ob_buffers));
284: if (!just_flush && OG(ob_nesting_level)==2) { /* destroy the stack */
285: zend_stack_destroy(&OG(ob_buffers));
286: }
287: }
288: OG(ob_nesting_level)--;
289:
290: if (send_buffer) {
291: if (just_flush) { /* if flush is called prior to proper end, ensure presence of NUL */
292: final_buffer[final_buffer_length] = '\0';
293: }
294: OG(php_body_write)(final_buffer, final_buffer_length TSRMLS_CC);
295: }
296:
297: if (just_flush) { /* we restored the previous ob, return to the current */
298: if (prev_ob_buffer_p) {
299: zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer));
300: OG(active_ob_buffer) = orig_ob_buffer;
301: }
302: OG(ob_nesting_level)++;
303: }
304:
305: if (alternate_buffer) {
306: zval_ptr_dtor(&alternate_buffer);
307: }
308:
309: if (status & PHP_OUTPUT_HANDLER_END) {
310: efree(to_be_destroyed_handler_name);
311: }
312: if (!just_flush) {
313: efree(to_be_destroyed_buffer);
314: } else {
315: OG(active_ob_buffer).text_length = 0;
316: OG(active_ob_buffer).status |= PHP_OUTPUT_HANDLER_START;
317: OG(php_body_write) = php_b_body_write;
318: }
319: if (to_be_destroyed_handled_output[0]) {
320: efree(to_be_destroyed_handled_output[0]);
321: }
322: if (to_be_destroyed_handled_output[1]) {
323: efree(to_be_destroyed_handled_output[1]);
324: }
325: }
326: /* }}} */
327:
328: /* {{{ php_end_ob_buffers
329: * End output buffering (all buffers) */
330: PHPAPI void php_end_ob_buffers(zend_bool send_buffer TSRMLS_DC)
331: {
332: while (OG(ob_nesting_level)!=0) {
333: php_end_ob_buffer(send_buffer, 0 TSRMLS_CC);
334: }
335: }
336: /* }}} */
337:
338: /* {{{ php_start_implicit_flush
339: */
340: PHPAPI void php_start_implicit_flush(TSRMLS_D)
341: {
342: OG(implicit_flush) = 1;
343: }
344: /* }}} */
345:
346: /* {{{ php_end_implicit_flush
347: */
348: PHPAPI void php_end_implicit_flush(TSRMLS_D)
349: {
350: OG(implicit_flush) = 0;
351: }
352: /* }}} */
353:
354: /* {{{ char *php_get_output_start_filename(TSRMLS_D)
355: * Return filename start output something */
356: PHPAPI char *php_get_output_start_filename(TSRMLS_D)
357: {
358: return OG(output_start_filename);
359: }
360: /* }}} */
361:
362: /* {{{ char *php_get_output_start_lineno(TSRMLS_D)
363: * Return line number start output something */
364: PHPAPI int php_get_output_start_lineno(TSRMLS_D)
365: {
366: return OG(output_start_lineno);
367: }
368: /* }}} */
369:
370: /* {{{ php_ob_set_internal_handler
371: */
372: 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)
373: {
374: if (OG(ob_nesting_level) == 0 || OG(active_ob_buffer).internal_output_handler || strcmp(OG(active_ob_buffer).handler_name, OB_DEFAULT_HANDLER_NAME)) {
375: php_start_ob_buffer(NULL, buffer_size, erase TSRMLS_CC);
376: }
377:
378: OG(active_ob_buffer).internal_output_handler = internal_output_handler;
379: OG(active_ob_buffer).internal_output_handler_buffer = (char *) emalloc(buffer_size);
380: OG(active_ob_buffer).internal_output_handler_buffer_size = buffer_size;
381: if (OG(active_ob_buffer).handler_name) {
382: efree(OG(active_ob_buffer).handler_name);
383: }
384: OG(active_ob_buffer).handler_name = estrdup(handler_name);
385: OG(active_ob_buffer).erase = erase;
386: }
387: /* }}} */
388:
389: /*
390: * Output buffering - implementation
391: */
392:
393: /* {{{ php_ob_allocate
394: */
395: static inline void php_ob_allocate(uint text_length TSRMLS_DC)
396: {
397: uint new_len = OG(active_ob_buffer).text_length + text_length;
398:
399: if (OG(active_ob_buffer).size < new_len) {
400: uint buf_size = OG(active_ob_buffer).size;
401: while (buf_size <= new_len) {
402: buf_size += OG(active_ob_buffer).block_size;
403: }
404:
405: OG(active_ob_buffer).buffer = (char *) erealloc(OG(active_ob_buffer).buffer, buf_size+1);
406: OG(active_ob_buffer).size = buf_size;
407: }
408: OG(active_ob_buffer).text_length = new_len;
409: }
410: /* }}} */
411:
412: /* {{{ php_ob_init_conflict
413: * Returns 1 if handler_set is already used and generates error message */
414: PHPAPI int php_ob_init_conflict(char *handler_new, char *handler_set TSRMLS_DC)
415: {
416: if (php_ob_handler_used(handler_set TSRMLS_CC)) {
417: php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", handler_new, handler_set);
418: return 1;
419: }
420: return 0;
421: }
422: /* }}} */
423:
424: /* {{{ php_ob_init_named
425: */
426: static int php_ob_init_named(uint initial_size, uint block_size, char *handler_name, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
427: {
428: php_ob_buffer tmp_buf;
429:
430: if (output_handler && !zend_is_callable(output_handler, 0, NULL TSRMLS_CC)) {
431: return FAILURE;
432: }
433:
434: tmp_buf.block_size = block_size;
435: tmp_buf.size = initial_size;
436: tmp_buf.buffer = (char *) emalloc(initial_size+1);
437: tmp_buf.text_length = 0;
438: tmp_buf.output_handler = output_handler;
439: tmp_buf.chunk_size = chunk_size;
440: tmp_buf.status = 0;
441: tmp_buf.internal_output_handler = NULL;
442: tmp_buf.internal_output_handler_buffer = NULL;
443: tmp_buf.internal_output_handler_buffer_size = 0;
444: tmp_buf.handler_name = estrdup(handler_name&&handler_name[0]?handler_name:OB_DEFAULT_HANDLER_NAME);
445: tmp_buf.erase = erase;
446:
447: if (OG(ob_nesting_level)>0) {
448: #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
449: if (!strncmp(handler_name, "ob_gzhandler", sizeof("ob_gzhandler")) && php_ob_gzhandler_check(TSRMLS_C)) {
450: return FAILURE;
451: }
452: #endif
453: if (OG(ob_nesting_level)==1) { /* initialize stack */
454: zend_stack_init(&OG(ob_buffers));
455: }
456: zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer));
457: }
458: OG(ob_nesting_level)++;
459: OG(active_ob_buffer) = tmp_buf;
460: OG(php_body_write) = php_b_body_write;
461: return SUCCESS;
462: }
463: /* }}} */
464:
465: /* {{{ php_ob_handler_from_string
466: * Create zval output handler from string */
467: static zval* php_ob_handler_from_string(const char *handler_name, int len TSRMLS_DC)
468: {
469: zval *output_handler;
470:
471: ALLOC_INIT_ZVAL(output_handler);
472: Z_STRLEN_P(output_handler) = len;
473: Z_STRVAL_P(output_handler) = estrndup(handler_name, len);
474: Z_TYPE_P(output_handler) = IS_STRING;
475: return output_handler;
476: }
477: /* }}} */
478:
479: /* {{{ php_ob_init
480: */
481: static int php_ob_init(uint initial_size, uint block_size, zval *output_handler, uint chunk_size, zend_bool erase TSRMLS_DC)
482: {
483: int result = FAILURE, handler_len, len;
484: char *handler_name, *next_handler_name;
485: HashPosition pos;
486: zval **tmp;
487: zval *handler_zval;
488:
489: if (output_handler && output_handler->type == IS_STRING) {
490: handler_name = Z_STRVAL_P(output_handler);
491: handler_len = Z_STRLEN_P(output_handler);
492:
493: result = SUCCESS;
494: if (handler_len && handler_name[0] != '\0') {
495: while ((next_handler_name=strchr(handler_name, ',')) != NULL) {
496: len = next_handler_name-handler_name;
497: next_handler_name = estrndup(handler_name, len);
498: handler_zval = php_ob_handler_from_string(next_handler_name, len TSRMLS_CC);
499: result = php_ob_init_named(initial_size, block_size, next_handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
500: if (result != SUCCESS) {
501: zval_dtor(handler_zval);
502: FREE_ZVAL(handler_zval);
503: }
504: handler_name += len+1;
505: handler_len -= len+1;
506: efree(next_handler_name);
507: }
508: }
509: if (result == SUCCESS) {
510: handler_zval = php_ob_handler_from_string(handler_name, handler_len TSRMLS_CC);
511: result = php_ob_init_named(initial_size, block_size, handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
512: if (result != SUCCESS) {
513: zval_dtor(handler_zval);
514: FREE_ZVAL(handler_zval);
515: }
516: }
517: } else if (output_handler && output_handler->type == IS_ARRAY) {
518: /* do we have array(object,method) */
519: if (zend_is_callable(output_handler, 0, &handler_name TSRMLS_CC)) {
520: SEPARATE_ZVAL(&output_handler);
521: Z_ADDREF_P(output_handler);
522: result = php_ob_init_named(initial_size, block_size, handler_name, output_handler, chunk_size, erase TSRMLS_CC);
523: efree(handler_name);
524: } else {
525: efree(handler_name);
526: /* init all array elements recursively */
527: zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(output_handler), &pos);
528: while (zend_hash_get_current_data_ex(Z_ARRVAL_P(output_handler), (void **)&tmp, &pos) == SUCCESS) {
529: result = php_ob_init(initial_size, block_size, *tmp, chunk_size, erase TSRMLS_CC);
530: if (result == FAILURE) {
531: break;
532: }
533: zend_hash_move_forward_ex(Z_ARRVAL_P(output_handler), &pos);
534: }
535: }
536: } else if (output_handler && output_handler->type == IS_OBJECT) {
537: /* do we have callable object */
538: if (zend_is_callable(output_handler, 0, &handler_name TSRMLS_CC)) {
539: SEPARATE_ZVAL(&output_handler);
540: Z_ADDREF_P(output_handler);
541: result = php_ob_init_named(initial_size, block_size, handler_name, output_handler, chunk_size, erase TSRMLS_CC);
542: efree(handler_name);
543: } else {
544: efree(handler_name);
545: php_error_docref(NULL TSRMLS_CC, E_ERROR, "No method name given: use ob_start(array($object,'method')) to specify instance $object and the name of a method of class %s to use as output handler", Z_OBJCE_P(output_handler)->name);
546: result = FAILURE;
547: }
548: } else {
549: result = php_ob_init_named(initial_size, block_size, OB_DEFAULT_HANDLER_NAME, NULL, chunk_size, erase TSRMLS_CC);
550: }
551: return result;
552: }
553: /* }}} */
554:
555: /* {{{ php_ob_list_each
556: */
557: static int php_ob_list_each(php_ob_buffer *ob_buffer, zval *ob_handler_array)
558: {
559: add_next_index_string(ob_handler_array, ob_buffer->handler_name, 1);
560: return 0;
561: }
562: /* }}} */
563:
564: /* {{{ php_ob_used_each
565: Sets handler_name to NULL is found */
566: static int php_ob_handler_used_each(php_ob_buffer *ob_buffer, char **handler_name)
567: {
568: if (!strcmp(ob_buffer->handler_name, *handler_name)) {
569: *handler_name = NULL;
570: return 1;
571: }
572: return 0;
573: }
574: /* }}} */
575:
576: /* {{{ php_ob_used
577: returns 1 if given handler_name is used as output_handler */
578: PHPAPI int php_ob_handler_used(char *handler_name TSRMLS_DC)
579: {
580: char *tmp = handler_name;
581:
582: if (OG(ob_nesting_level)) {
583: if (!strcmp(OG(active_ob_buffer).handler_name, handler_name)) {
584: return 1;
585: }
586: if (OG(ob_nesting_level)>1) {
587: zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_ob_handler_used_each, &tmp);
588: }
589: }
590: return tmp ? 0 : 1;
591: }
592: /* }}} */
593:
594: /* {{{ php_ob_append
595: */
596: static inline void php_ob_append(const char *text, uint text_length TSRMLS_DC)
597: {
598: char *target;
599: int original_ob_text_length;
600:
601: original_ob_text_length=OG(active_ob_buffer).text_length;
602:
603: php_ob_allocate(text_length TSRMLS_CC);
604: target = OG(active_ob_buffer).buffer+original_ob_text_length;
605: memcpy(target, text, text_length);
606: target[text_length]=0;
607:
608: /* If implicit_flush is On or chunked buffering, send contents to next buffer and return. */
609: if (OG(active_ob_buffer).chunk_size
610: && OG(active_ob_buffer).text_length >= OG(active_ob_buffer).chunk_size) {
611:
612: php_end_ob_buffer(1, 1 TSRMLS_CC);
613: return;
614: }
615: }
616: /* }}} */
617:
618: #if 0
619: static inline void php_ob_prepend(const char *text, uint text_length)
620: {
621: char *p, *start;
622: TSRMLS_FETCH();
623:
624: php_ob_allocate(text_length TSRMLS_CC);
625:
626: /* php_ob_allocate() may change OG(ob_buffer), so we can't initialize p&start earlier */
627: p = OG(ob_buffer)+OG(ob_text_length);
628: start = OG(ob_buffer);
629:
630: while (--p>=start) {
631: p[text_length] = *p;
632: }
633: memcpy(OG(ob_buffer), text, text_length);
634: OG(ob_buffer)[OG(active_ob_buffer).text_length]=0;
635: }
636: #endif
637:
638: /* {{{ php_ob_get_buffer
639: * Return the current output buffer */
640: PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC)
641: {
642: if (OG(ob_nesting_level)==0) {
643: return FAILURE;
644: }
645: ZVAL_STRINGL(p, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
646: return SUCCESS;
647: }
648: /* }}} */
649:
650: /* {{{ php_ob_get_length
651: * Return the size of the current output buffer */
652: PHPAPI int php_ob_get_length(zval *p TSRMLS_DC)
653: {
654: if (OG(ob_nesting_level) == 0) {
655: return FAILURE;
656: }
657: ZVAL_LONG(p, OG(active_ob_buffer).text_length);
658: return SUCCESS;
659: }
660: /* }}} */
661:
662: /*
663: * Wrapper functions - implementation
664: */
665:
666: /* buffered output function */
667: static int php_b_body_write(const char *str, uint str_length TSRMLS_DC)
668: {
669: php_ob_append(str, str_length TSRMLS_CC);
670: return str_length;
671: }
672:
673: /* {{{ php_ub_body_write_no_header
674: */
675: PHPAPI int php_ub_body_write_no_header(const char *str, uint str_length TSRMLS_DC)
676: {
677: int result;
678:
679: if (OG(disable_output)) {
680: return 0;
681: }
682:
683: result = OG(php_header_write)(str, str_length TSRMLS_CC);
684:
685: if (OG(implicit_flush)) {
686: sapi_flush(TSRMLS_C);
687: }
688:
689: return result;
690: }
691: /* }}} */
692:
693: /* {{{ php_ub_body_write
694: */
695: PHPAPI int php_ub_body_write(const char *str, uint str_length TSRMLS_DC)
696: {
697: int result = 0;
698:
699: if (SG(request_info).headers_only) {
700: if(SG(headers_sent)) {
701: return 0;
702: }
703: php_header(TSRMLS_C);
704: zend_bailout();
705: }
706: if (php_header(TSRMLS_C)) {
707: if (zend_is_compiling(TSRMLS_C)) {
708: OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C);
709: OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C);
710: } else if (zend_is_executing(TSRMLS_C)) {
711: OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C);
712: OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C);
713: }
714:
715: OG(php_body_write) = php_ub_body_write_no_header;
716: result = php_ub_body_write_no_header(str, str_length TSRMLS_CC);
717: }
718:
719: return result;
720: }
721: /* }}} */
722:
723: /* {{{ int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result)
724: */
725: static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result)
726: {
727: zval *elem;
728:
729: MAKE_STD_ZVAL(elem);
730: array_init(elem);
731:
732: add_assoc_long(elem, "chunk_size", ob_buffer->chunk_size);
733: if (!ob_buffer->chunk_size) {
734: add_assoc_long(elem, "size", ob_buffer->size);
735: add_assoc_long(elem, "block_size", ob_buffer->block_size);
736: }
737: if (ob_buffer->internal_output_handler) {
738: add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_INTERNAL);
739: add_assoc_long(elem, "buffer_size", ob_buffer->internal_output_handler_buffer_size);
740: } else {
741: add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER);
742: }
743: add_assoc_long(elem, "status", ob_buffer->status);
744: add_assoc_string(elem, "name", ob_buffer->handler_name, 1);
745: add_assoc_bool(elem, "del", ob_buffer->erase);
746: add_next_index_zval(result, elem);
747:
748: return SUCCESS;
749: }
750: /* }}} */
751:
752: /*
753: * USERLAND (nearly 1:1 of old output.c)
754: */
755:
756: /* {{{ proto bool ob_start([string|array user_function [, int chunk_size [, bool erase]]])
757: Turn on Output Buffering (specifying an optional output handler). */
758: PHP_FUNCTION(ob_start)
759: {
760: zval *output_handler = NULL;
761: long chunk_size = 0;
762: zend_bool erase = 1;
763:
764: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/lb", &output_handler, &chunk_size, &erase) == FAILURE) {
765: return;
766: }
767:
768: if (chunk_size < 0) {
769: chunk_size = 0;
770: }
771:
772: if (php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC) == FAILURE) {
773: RETURN_FALSE;
774: }
775: RETURN_TRUE;
776: }
777: /* }}} */
778:
779: /* {{{ proto bool ob_flush(void)
780: Flush (send) contents of the output buffer. The last buffer content is sent to next buffer */
781: PHP_FUNCTION(ob_flush)
782: {
783: if (zend_parse_parameters_none() == FAILURE) {
784: return;
785: }
786:
787: if (!OG(ob_nesting_level)) {
788: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush");
789: RETURN_FALSE;
790: }
791:
792: if (!OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
793: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer %s", OG(active_ob_buffer).handler_name);
794: RETURN_FALSE;
795: }
796:
797: php_end_ob_buffer(1, 1 TSRMLS_CC);
798: RETURN_TRUE;
799: }
800: /* }}} */
801:
802: /* {{{ proto bool ob_clean(void)
803: Clean (delete) the current output buffer */
804: PHP_FUNCTION(ob_clean)
805: {
806: if (zend_parse_parameters_none() == FAILURE) {
807: return;
808: }
809:
810: if (!OG(ob_nesting_level)) {
811: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
812: RETURN_FALSE;
813: }
814:
815: if (!OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
816: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
817: RETURN_FALSE;
818: }
819:
820: php_end_ob_buffer(0, 1 TSRMLS_CC);
821: RETURN_TRUE;
822: }
823: /* }}} */
824:
825: /* {{{ proto bool ob_end_flush(void)
826: Flush (send) the output buffer, and delete current output buffer */
827: PHP_FUNCTION(ob_end_flush)
828: {
829: if (zend_parse_parameters_none() == FAILURE) {
830: return;
831: }
832:
833: if (!OG(ob_nesting_level)) {
834: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
835: RETURN_FALSE;
836: }
837:
838: if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
839: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
840: RETURN_FALSE;
841: }
842:
843: php_end_ob_buffer(1, 0 TSRMLS_CC);
844: RETURN_TRUE;
845: }
846: /* }}} */
847:
848: /* {{{ proto bool ob_end_clean(void)
849: Clean the output buffer, and delete current output buffer */
850: PHP_FUNCTION(ob_end_clean)
851: {
852: if (zend_parse_parameters_none() == FAILURE) {
853: return;
854: }
855:
856: if (!OG(ob_nesting_level)) {
857: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
858: RETURN_FALSE;
859: }
860:
861: if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
862: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
863: RETURN_FALSE;
864: }
865:
866: php_end_ob_buffer(0, 0 TSRMLS_CC);
867: RETURN_TRUE;
868: }
869: /* }}} */
870:
871: /* {{{ proto bool ob_get_flush(void)
872: Get current buffer contents, flush (send) the output buffer, and delete current output buffer */
873: PHP_FUNCTION(ob_get_flush)
874: {
875: if (zend_parse_parameters_none() == FAILURE) {
876: return;
877: }
878:
879: if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
880: RETURN_FALSE;
881: }
882:
883: if (!OG(ob_nesting_level)) {
884: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
885: zval_dtor(return_value);
886: RETURN_FALSE;
887: }
888:
889: if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
890: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
891: zval_dtor(return_value);
892: RETURN_FALSE;
893: }
894:
895: php_end_ob_buffer(1, 0 TSRMLS_CC);
896: }
897: /* }}} */
898:
899: /* {{{ proto bool ob_get_clean(void)
900: Get current buffer contents and delete current output buffer */
901: PHP_FUNCTION(ob_get_clean)
902: {
903: if (zend_parse_parameters_none() == FAILURE) {
904: return;
905: }
906:
907: if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
908: RETURN_FALSE;
909: }
910:
911: if (!OG(ob_nesting_level)) {
912: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
913: zval_dtor(return_value);
914: RETURN_FALSE;
915: }
916: if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
917: php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s", OG(active_ob_buffer).handler_name);
918: zval_dtor(return_value);
919: RETURN_FALSE;
920: }
921:
922: php_end_ob_buffer(0, 0 TSRMLS_CC);
923: }
924: /* }}} */
925:
926: /* {{{ proto string ob_get_contents(void)
927: Return the contents of the output buffer */
928: PHP_FUNCTION(ob_get_contents)
929: {
930: if (zend_parse_parameters_none() == FAILURE) {
931: return;
932: }
933:
934: if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
935: RETURN_FALSE;
936: }
937: }
938: /* }}} */
939:
940: /* {{{ proto int ob_get_level(void)
941: Return the nesting level of the output buffer */
942: PHP_FUNCTION(ob_get_level)
943: {
944: if (zend_parse_parameters_none() == FAILURE) {
945: return;
946: }
947:
948: RETURN_LONG(OG(ob_nesting_level));
949: }
950: /* }}} */
951:
952: /* {{{ proto int ob_get_length(void)
953: Return the length of the output buffer */
954: PHP_FUNCTION(ob_get_length)
955: {
956: if (zend_parse_parameters_none() == FAILURE) {
957: return;
958: }
959:
960: if (php_ob_get_length(return_value TSRMLS_CC) == FAILURE) {
961: RETURN_FALSE;
962: }
963: }
964: /* }}} */
965:
966: /* {{{ proto false|array ob_list_handlers()
967: List all output_buffers in an array */
968: PHP_FUNCTION(ob_list_handlers)
969: {
970: if (zend_parse_parameters_none() == FAILURE) {
971: return;
972: }
973:
974: array_init(return_value);
975:
976: if (OG(ob_nesting_level)) {
977: if (OG(ob_nesting_level) > 1) {
978: zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_ob_list_each, return_value);
979: }
980: php_ob_list_each(&OG(active_ob_buffer), return_value);
981: }
982: }
983: /* }}} */
984:
985: /* {{{ proto false|array ob_get_status([bool full_status])
986: Return the status of the active or all output buffers */
987: PHP_FUNCTION(ob_get_status)
988: {
989: zend_bool full_status = 0;
990:
991: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status) == FAILURE) {
992: return;
993: }
994:
995: array_init(return_value);
996:
997: if (full_status) {
998: if (OG(ob_nesting_level) > 1) {
999: zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *elem, void *))php_ob_buffer_status, return_value);
1000: }
1001: if (OG(ob_nesting_level) > 0 && php_ob_buffer_status(&OG(active_ob_buffer), return_value) == FAILURE) {
1002: RETURN_FALSE;
1003: }
1004: } else if (OG(ob_nesting_level) > 0) {
1005: add_assoc_long(return_value, "level", OG(ob_nesting_level));
1006: if (OG(active_ob_buffer).internal_output_handler) {
1007: add_assoc_long(return_value, "type", PHP_OUTPUT_HANDLER_INTERNAL);
1008: } else {
1009: add_assoc_long(return_value, "type", PHP_OUTPUT_HANDLER_USER);
1010: }
1011: add_assoc_long(return_value, "status", OG(active_ob_buffer).status);
1012: add_assoc_string(return_value, "name", OG(active_ob_buffer).handler_name, 1);
1013: add_assoc_bool(return_value, "del", OG(active_ob_buffer).erase);
1014: }
1015: }
1016: /* }}} */
1017:
1018: /* {{{ proto void ob_implicit_flush([int flag])
1019: Turn implicit flush on/off and is equivalent to calling flush() after every output call */
1020: PHP_FUNCTION(ob_implicit_flush)
1021: {
1022: long flag = 1;
1023:
1024: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag) == FAILURE) {
1025: return;
1026: }
1027:
1028: if (flag) {
1029: php_start_implicit_flush(TSRMLS_C);
1030: } else {
1031: php_end_implicit_flush(TSRMLS_C);
1032: }
1033: }
1034: /* }}} */
1035:
1036: /* {{{ proto bool output_reset_rewrite_vars(void)
1037: Reset(clear) URL rewriter values */
1038: PHP_FUNCTION(output_reset_rewrite_vars)
1039: {
1040: if (php_url_scanner_reset_vars(TSRMLS_C) == SUCCESS) {
1041: RETURN_TRUE;
1042: } else {
1043: RETURN_FALSE;
1044: }
1045: }
1046: /* }}} */
1047:
1048: /* {{{ proto bool output_add_rewrite_var(string name, string value)
1049: Add URL rewriter values */
1050: PHP_FUNCTION(output_add_rewrite_var)
1051: {
1052: char *name, *value;
1053: int name_len, value_len;
1054:
1055: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) {
1056: return;
1057: }
1058:
1059: if (php_url_scanner_add_var(name, name_len, value, value_len, 1 TSRMLS_CC) == SUCCESS) {
1060: RETURN_TRUE;
1061: } else {
1062: RETURN_FALSE;
1063: }
1064: }
1065: /* }}} */
1066:
1067: /*
1068: * Local variables:
1069: * tab-width: 4
1070: * c-basic-offset: 4
1071: * End:
1072: * vim600: sw=4 ts=4 fdm=marker
1073: * vim<600: sw=4 ts=4
1074: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>