Current output control code have some problems. This patch solves some.

1) ob_end_clean/ob_end_flush destory buffer that is not supposed to.
    Deleteting output compression does not make sense once output is
    started. (Additional checks)
2) Memory leak, crash when deleting output buffer when nesting
    level is 0. (Additional checks)
3) User has no way to know which buffer is deleted by ob_end_*()
    functions. (ob_get_status())
4) User has no way to know buffer functions are executed correctly
    or not. (ob_*() functions return bool)
5) User has no way to know status of buffers. (ob_get_status())

TODO for output control.
  - Implicit flush is not working. Need more work to make
    implicit flush actually work with nested buffers...
  - Fix crash with user defined (PHP script) output handler.

Any comment is appreciated :)

PS: Session patch, I've posted here, is also includeed in
this patch. It fixes verious session problems.

-- 
Yasuo Ohgaki
? ext/standard/Makefile.frag
? ext/session/tmp.diff
? ext/session/bak
Index: main/output.c
===================================================================
RCS file: /repository/php4/main/output.c,v
retrieving revision 1.84
diff -u -r1.84 output.c
--- main/output.c       7 Feb 2002 02:50:28 -0000       1.84
+++ main/output.c       13 Feb 2002 08:41:58 -0000
@@ -29,7 +29,7 @@
 static int php_ub_body_write_no_header(const char *str, uint str_length TSRMLS_DC);
 static int php_b_body_write(const char *str, uint str_length TSRMLS_DC);
 
-static void php_ob_init(uint initial_size, uint block_size, zval *output_handler, 
uint chunk_size TSRMLS_DC);
+static void 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);
@@ -110,15 +110,15 @@
 
 /* {{{ php_start_ob_buffer
  * Start output buffering */
-PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size TSRMLS_DC)
+PHPAPI int php_start_ob_buffer(zval *output_handler, uint chunk_size, zend_bool erase 
+TSRMLS_DC)
 {
        if (OG(ob_lock)) {
                return FAILURE;
        }
        if (chunk_size) {
-               php_ob_init((chunk_size*3/2), chunk_size/2, output_handler, chunk_size 
TSRMLS_CC);
+               php_ob_init((chunk_size*3/2), chunk_size/2, output_handler, 
+chunk_size, erase TSRMLS_CC);
        } else {
-               php_ob_init(40*1024, 10*1024, output_handler, chunk_size TSRMLS_CC);
+               php_ob_init(40*1024, 10*1024, output_handler, chunk_size, erase 
+TSRMLS_CC);
        }
        OG(php_body_write) = php_b_body_write;
        return SUCCESS;
@@ -185,6 +185,7 @@
                        orig_buffer->refcount-=2;
                }
                zval_ptr_dtor(&z_status);
+               zval_ptr_dtor(&OG(active_ob_buffer).output_handler);
        }
 
        if (!final_buffer) {
@@ -283,7 +284,7 @@
 
 /* {{{ php_ob_set_internal_handler
  */
-PHPAPI void php_ob_set_internal_handler(php_output_handler_func_t 
internal_output_handler, uint buffer_size TSRMLS_DC)
+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)
 {
        if (OG(ob_nesting_level)==0) {
                return;
@@ -292,6 +293,8 @@
        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;
+       OG(active_ob_buffer).handler_name = handler_name;
+       OG(active_ob_buffer).erase = erase;     
 }
 /* }}} */
 
@@ -315,7 +318,7 @@
 
 /* {{{ php_ob_init
  */
-static void php_ob_init(uint initial_size, uint block_size, zval *output_handler, 
uint chunk_size TSRMLS_DC)
+static void php_ob_init(uint initial_size, uint block_size, zval *output_handler, 
+uint chunk_size, zend_bool erase TSRMLS_DC)
 {
        if (OG(ob_nesting_level)>0) {
                if (OG(ob_nesting_level)==1) { /* initialize stack */
@@ -332,6 +335,18 @@
        OG(active_ob_buffer).chunk_size = chunk_size;
        OG(active_ob_buffer).status = 0;
        OG(active_ob_buffer).internal_output_handler = NULL;
+       if (output_handler && output_handler->type == IS_STRING) {
+               OG(active_ob_buffer).handler_name = Z_STRVAL_P(output_handler);
+       }
+       else if (output_handler && output_handler->type == IS_ARRAY) {
+               /* FIXME: Array type is not supported yet.
+                  See call_user_function_ex() for detials. */
+               OG(active_ob_buffer).handler_name = "array is not supported yet";
+       }
+       else {
+               OG(active_ob_buffer).handler_name = "default output handler";
+       }
+       OG(active_ob_buffer).erase = erase;     
 }
 /* }}} */
 
@@ -478,47 +493,24 @@
  * HEAD support
  */
 
-/* {{{ proto void ob_start([ string user_function [, int chunk_size]])
+/* {{{ proto void ob_start([ string user_function [, int chunk_size [, bool erase]]])
    Turn on Output Buffering (specifying an optional output handler). */
 PHP_FUNCTION(ob_start)
 {
        zval *output_handler=NULL;
        uint chunk_size=0;
+       zend_bool erase=1;
+       int argc = ZEND_NUM_ARGS();
+       
+       if (zend_parse_parameters(argc TSRMLS_CC, "|zlb", &output_handler, 
+                                                         &chunk_size, &erase) == 
+FAILURE)
+               return;
 
-       switch (ZEND_NUM_ARGS()) {
-               case 0:
-                       break;
-               case 1: {
-                               zval **output_handler_p;
-
-                               if (zend_get_parameters_ex(1, 
&output_handler_p)==FAILURE) {
-                                       RETURN_FALSE;
-                               }
-                               SEPARATE_ZVAL(output_handler_p);
-                               output_handler = *output_handler_p;
-                               output_handler->refcount++;
-                       }
-                       break;
-               case 2: {
-                               zval **output_handler_p, **chunk_size_p;
-
-                               if (zend_get_parameters_ex(2, &output_handler_p, 
&chunk_size_p)==FAILURE) {
-                                       RETURN_FALSE;
-                               }
-                               if (Z_STRLEN_PP(output_handler_p)>0) {
-                                       SEPARATE_ZVAL(output_handler_p);
-                                       output_handler = *output_handler_p;
-                                       output_handler->refcount++;
-                               }
-                               convert_to_long_ex(chunk_size_p);
-                               chunk_size = (uint) Z_LVAL_PP(chunk_size_p);
-                       }
-                       break;
-               default:
-                       ZEND_WRONG_PARAM_COUNT();
-                       break;
-       }
-       if (php_start_ob_buffer(output_handler, chunk_size TSRMLS_CC)==FAILURE) {
+       if (output_handler) {
+               SEPARATE_ZVAL(&output_handler);
+               output_handler->refcount++;
+       }       
+       if (php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC)==FAILURE) 
+{
                if (SG(headers_sent) && !SG(request_info).headers_only) {
                        OG(php_body_write) = php_ub_body_write_no_header;
                } else {
@@ -532,47 +524,91 @@
 }
 /* }}} */
 
-/* {{{ proto void ob_flush(void)
-   Flush (send) the output buffer */
+/* {{{ proto bool ob_flush(void)
+   Flush (send) contents of the output buffers */
 PHP_FUNCTION(ob_flush)
 {
        if (ZEND_NUM_ARGS() != 0)
                        WRONG_PARAM_COUNT;
+
+       if (!OG(ob_nesting_level)) {
+               php_error(E_NOTICE, "%s() failed to flush buffer. No buffer to flush.",
+                                 get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
                
        php_end_ob_buffer(1, 1 TSRMLS_CC);
+       RETURN_TRUE;
 }
 /* }}} */
 
-/* {{{ proto void ob_clean(void)
-   Clean (erase) the output buffer */
+/* {{{ proto bool ob_clean(void)
+   Clean (delete) the current output buffer */
 PHP_FUNCTION(ob_clean)
 {
        if (ZEND_NUM_ARGS() != 0)
                        WRONG_PARAM_COUNT;
-               
+
+       
+       if (!OG(ob_nesting_level)) {
+               php_error(E_NOTICE, "%s() failed to delete buffer. No buffer to 
+delete.",
+                                 get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
+       if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && 
+!OG(active_ob_buffer).erase) {
+               php_error(E_NOTICE, "%s() failed to delete buffer %s.",
+                                 get_active_function_name(TSRMLS_C), 
+OG(active_ob_buffer).handler_name);
+               RETURN_FALSE;
+       }
+       
        php_end_ob_buffer(0, 1 TSRMLS_CC);
+       RETURN_TRUE;
 }
 /* }}} */
 
-/* {{{ proto void ob_end_flush(void)
-   Flush (send) the output buffer, and turn off output buffering */
+/* {{{ proto bool ob_end_flush(void)
+   Flush (send) the output buffer, and delete current output buffer */
 PHP_FUNCTION(ob_end_flush)
 {
        if (ZEND_NUM_ARGS() != 0)
                        WRONG_PARAM_COUNT;
-               
+       
+       if (!OG(ob_nesting_level)) {
+               php_error(E_NOTICE, "%s() failed to delete and flush buffer. No buffer 
+to delete or flush.",
+                                 get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
+       if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && 
+!OG(active_ob_buffer).erase) {
+               php_error(E_NOTICE, "%s() failed to delete buffer %s.",
+                                 get_active_function_name(TSRMLS_C), 
+OG(active_ob_buffer).handler_name);
+               RETURN_FALSE;
+       }
+       
        php_end_ob_buffer(1, 0 TSRMLS_CC);
+       RETURN_TRUE;
 }
 /* }}} */
 
-/* {{{ proto void ob_end_clean(void)
-   Clean (erase) the output buffer, and turn off output buffering */
+/* {{{ proto bool ob_end_clean(void)
+   Clean the output buffer, and delete current output buffer */
 PHP_FUNCTION(ob_end_clean)
 {
        if (ZEND_NUM_ARGS() != 0)
                        WRONG_PARAM_COUNT;
                
+       if (!OG(ob_nesting_level)) {
+               php_error(E_NOTICE, "%s() failed to delete buffer. No buffer to 
+delete.",
+                                 get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
+       if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && 
+!OG(active_ob_buffer).erase) {
+               php_error(E_NOTICE, "%s() failed to delete buffer %s.",
+                                 get_active_function_name(TSRMLS_C), 
+OG(active_ob_buffer).handler_name);
+               RETURN_FALSE;
+       }
+       
        php_end_ob_buffer(0, 0 TSRMLS_CC);
+       RETURN_TRUE;
 }
 /* }}} */
 
@@ -612,6 +648,79 @@
        }
 }
 /* }}} */
+
+static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result) 
+{
+       zval *elem;
+
+       ALLOC_INIT_ZVAL(elem);
+       if (array_init(elem))
+               return FAILURE;
+       
+       if (ob_buffer->internal_output_handler) {
+               add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_INTERNAL);
+       }
+       else {
+               add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER);
+       }
+       add_assoc_long(elem, "status", ob_buffer->status);
+       add_assoc_string(elem, "name", ob_buffer->handler_name, 1);
+       add_assoc_bool(elem, "del", ob_buffer->erase);
+       add_next_index_zval(result, elem);
+
+       return SUCCESS;
+}
+
+
+/* {{{ poto array ob_get_status([bool full_status])
+   Return the nesting level of the output buffer */
+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 )
+                       return;
+       
+       if (array_init(return_value) == FAILURE) {
+               RETURN_FALSE;
+       }
+
+       if (full_status) {
+               zval *elem;
+
+               zend_stack_apply_with_argument(&OG(ob_buffers), 
+ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *elem, void *))php_ob_buffer_status, 
+return_value);
+
+               ALLOC_INIT_ZVAL(elem);
+               if (array_init(elem))
+                       RETURN_FALSE;
+       
+               if (OG(active_ob_buffer).internal_output_handler) {
+                       add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_INTERNAL);
+               }
+               else {
+                       add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER);
+               }
+               add_assoc_long(elem, "status", OG(active_ob_buffer).status);
+               add_assoc_string(elem, "name", OG(active_ob_buffer).handler_name, 1);
+               add_assoc_bool(elem, "del", OG(active_ob_buffer).erase);
+               add_next_index_zval(return_value, elem);
+       }
+       else {
+               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_string(return_value, "name", 
+OG(active_ob_buffer).handler_name, 1);
+               add_assoc_bool(return_value, "del", OG(active_ob_buffer).erase);
+       }
+}
+/* }}} */
+
 
 /* {{{ proto void ob_implicit_flush([int flag])
    Turn implicit flush on/off and is equivalent to calling flush() after every output 
call */
Index: main/php_output.h
===================================================================
RCS file: /repository/php4/main/php_output.h,v
retrieving revision 1.34
diff -u -r1.34 php_output.h
--- main/php_output.h   11 Dec 2001 15:31:04 -0000      1.34
+++ main/php_output.h   13 Feb 2002 08:41:58 -0000
@@ -29,7 +29,7 @@
 void php_output_register_constants(TSRMLS_D);
 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 TSRMLS_DC);
+PHPAPI int php_start_ob_buffer(zval *output_handler, 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);
@@ -38,7 +38,7 @@
 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 TSRMLS_DC);
+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);
 
 PHP_FUNCTION(ob_start);
 PHP_FUNCTION(ob_flush);
@@ -48,6 +48,7 @@
 PHP_FUNCTION(ob_get_contents);
 PHP_FUNCTION(ob_get_length);
 PHP_FUNCTION(ob_get_level);
+PHP_FUNCTION(ob_get_status);
 PHP_FUNCTION(ob_implicit_flush);
 
 typedef struct _php_ob_buffer {
@@ -61,6 +62,8 @@
        php_output_handler_func_t internal_output_handler;
        char *internal_output_handler_buffer;
        uint internal_output_handler_buffer_size;
+       char *handler_name;
+       zend_bool erase;
 } php_ob_buffer;
 
 typedef struct _php_output_globals {
@@ -76,7 +79,6 @@
        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;
@@ -88,5 +90,9 @@
 #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
+
 
 #endif /* PHP_OUTPUT_H */
Index: ext/standard/basic_functions.c
===================================================================
RCS file: /repository/php4/ext/standard/basic_functions.c,v
retrieving revision 1.442
diff -u -r1.442 basic_functions.c
--- ext/standard/basic_functions.c      10 Feb 2002 17:38:15 -0000      1.442
+++ ext/standard/basic_functions.c      13 Feb 2002 08:42:00 -0000
@@ -733,6 +733,7 @@
        PHP_FE(ob_end_clean,                                                           
                                         NULL)
        PHP_FE(ob_get_length,                                                          
                                         NULL)
        PHP_FE(ob_get_level,                                                           
                                         NULL)
+       PHP_FE(ob_get_status,                                                          
+                                         NULL)
        PHP_FE(ob_get_contents,                                                        
                                         NULL)
        PHP_FE(ob_implicit_flush,                                                      
                                         NULL)
 
@@ -1863,7 +1864,7 @@
        convert_to_string(filename);
 
        if (i) {
-               php_start_ob_buffer (NULL, 0 TSRMLS_CC);
+               php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC);
        }
 
        php_get_highlight_struct(&syntax_highlighter_ini);
@@ -1896,7 +1897,7 @@
        convert_to_string(expr);
 
        if (i) {
-               php_start_ob_buffer (NULL, 0 TSRMLS_CC);
+               php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC);
        }
 
        php_get_highlight_struct(&syntax_highlighter_ini);
Index: ext/standard/var.c
===================================================================
RCS file: /repository/php4/ext/standard/var.c,v
retrieving revision 1.127
diff -u -r1.127 var.c
--- ext/standard/var.c  10 Feb 2002 17:38:15 -0000      1.127
+++ ext/standard/var.c  13 Feb 2002 08:42:00 -0000
@@ -312,7 +312,7 @@
        }
        
        if (i) {
-               php_start_ob_buffer (NULL, 0 TSRMLS_CC);
+               php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC);
        }
        
        php_var_export(&var, 1 TSRMLS_CC);
Index: ext/zlib/zlib.c
===================================================================
RCS file: /repository/php4/ext/zlib/zlib.c,v
retrieving revision 1.105
diff -u -r1.105 zlib.c
--- ext/zlib/zlib.c     11 Dec 2001 15:30:59 -0000      1.105
+++ ext/zlib/zlib.c     13 Feb 2002 08:42:01 -0000
@@ -1283,8 +1283,8 @@
                return FAILURE;
        }
        
-       php_start_ob_buffer(NULL, buffer_size TSRMLS_CC);
-       php_ob_set_internal_handler(php_gzip_output_handler, buffer_size*1.5 
TSRMLS_CC);
+       php_start_ob_buffer(NULL, buffer_size, 0 TSRMLS_CC);
+       php_ob_set_internal_handler(php_gzip_output_handler, buffer_size*1.5, "zlib 
+output compression", 0 TSRMLS_CC);
        return SUCCESS;
 }
 /* }}} */
Index: ext/session/mod_files.c
===================================================================
RCS file: /repository/php4/ext/session/mod_files.c,v
retrieving revision 1.67
diff -u -r1.67 mod_files.c
--- ext/session/mod_files.c     3 Feb 2002 05:40:19 -0000       1.67
+++ ext/session/mod_files.c     13 Feb 2002 08:42:01 -0000
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: mod_files.c,v 1.67 2002/02/03 05:40:19 yohgaki Exp $ */
+/* $Id: mod_files.c,v 1.66 2002/02/03 03:17:35 yohgaki Exp $ */
 
 #include "php.h"
 
@@ -123,7 +123,7 @@
        }
 }
 
-static void ps_files_open(ps_files *data, const char *key)
+static int ps_files_open(ps_files *data, const char *key)
 {
        char buf[MAXPATHLEN];
        TSRMLS_FETCH();
@@ -138,7 +138,7 @@
                
                if (!ps_files_valid_key(key) || 
                                !ps_files_path_create(buf, sizeof(buf), data, key))
-                       return;
+                       return FAILURE;
                
                data->lastkey = estrdup(key);
                
@@ -153,10 +153,13 @@
                if (data->fd != -1) 
                        flock(data->fd, LOCK_EX);
 
-               if (data->fd == -1)
+               if (data->fd == -1) {
                        php_error(E_WARNING, "open(%s, O_RDWR) failed: %s (%d)", buf, 
                                        strerror(errno), errno);
+                       return FAILURE;
+               }
        }
+       return SUCCESS;
 }
 
 static int ps_files_cleanup_dir(const char *dirname, int maxlifetime)
@@ -254,7 +257,9 @@
        struct stat sbuf;
        PS_FILES_DATA;
 
-       ps_files_open(data, key);
+       if (ps_files_open(data, key) == FAILURE)
+               return FAILURE;
+       
        if (data->fd < 0)
                return FAILURE;
        
@@ -283,7 +288,9 @@
        long n;
        PS_FILES_DATA;
 
-       ps_files_open(data, key);
+       if (ps_files_open(data, key) == FAILURE)
+               return FAILURE;
+
        if (data->fd < 0)
                return FAILURE;
 
Index: ext/session/mod_mm.c
===================================================================
RCS file: /repository/php4/ext/session/mod_mm.c,v
retrieving revision 1.31
diff -u -r1.31 mod_mm.c
--- ext/session/mod_mm.c        25 Jan 2002 20:59:24 -0000      1.31
+++ ext/session/mod_mm.c        13 Feb 2002 08:42:01 -0000
@@ -319,7 +319,6 @@
 {
        PS_MM_DATA;
        ps_sd *sd;
-       int ret = FAILURE;
 
        mm_lock(data->mm, MM_LOCK_RD);
        
@@ -329,12 +328,14 @@
                *val = emalloc(sd->datalen + 1);
                memcpy(*val, sd->data, sd->datalen);
                (*val)[sd->datalen] = '\0';
-               ret = SUCCESS;
        }
-
+       else {
+               *val = estrdup("\0");
+       }
+       
        mm_unlock(data->mm);
        
-       return ret;
+       return SUCCESS;
 }
 
 PS_WRITE_FUNC(mm)
Index: ext/session/php_session.h
===================================================================
RCS file: /repository/php4/ext/session/php_session.h,v
retrieving revision 1.69
diff -u -r1.69 php_session.h
--- ext/session/php_session.h   7 Feb 2002 22:00:21 -0000       1.69
+++ ext/session/php_session.h   13 Feb 2002 08:42:01 -0000
@@ -61,11 +61,16 @@
        #x, ps_open_##x, ps_close_##x, ps_read_##x, ps_write_##x, \
         ps_delete_##x, ps_gc_##x 
 
-typedef enum {
-       php_session_disabled,
-       php_session_none,
-       php_session_active
-} php_session_status;
+/* typedef enum { */
+/*     php_session_disabled, */
+/*     php_session_none, */
+/*     php_session_active */
+/* } php_session_status; */
+
+#define PS_DISABLED     1
+#define PS_NONE         2
+#define PS_ACTIVE       4
+#define PS_ERROR        8
 
 typedef struct _php_ps_globals {
        char *save_path;
@@ -79,10 +84,11 @@
        char *cookie_path;
        char *cookie_domain;
        zend_bool  cookie_secure;
+       long rinit_mod;
        ps_module *mod;
        void *mod_data;
        HashTable vars;
-       php_session_status session_status;
+       long session_status;
        long gc_probability;
        long gc_maxlifetime;
        int module_number;
Index: ext/session/session.c
===================================================================
RCS file: /repository/php4/ext/session/session.c,v
retrieving revision 1.276
diff -u -r1.276 session.c
--- ext/session/session.c       7 Feb 2002 22:00:21 -0000       1.276
+++ ext/session/session.c       13 Feb 2002 08:42:02 -0000
@@ -83,7 +83,7 @@
 
 static void php_session_output_handler(char *output, uint output_len, char 
**handled_output, uint *handled_output_len, int mode TSRMLS_DC)
 {
-       if ((PS(session_status) == php_session_active)) {
+       if ((PS(session_status) & PS_ACTIVE)) {
                *handled_output = url_adapt_ext_ex(output, output_len, 
PS(session_name), PS(id), handled_output_len, (zend_bool) (mode&PHP_OUTPUT_HANDLER_END 
? 1 : 0) TSRMLS_CC);
        } else {
                *handled_output = NULL;
@@ -95,8 +95,8 @@
 {
        php_url_scanner_activate(TSRMLS_C);
        php_url_scanner_ex_activate(TSRMLS_C);
-       php_start_ob_buffer(NULL, chunk_size TSRMLS_CC);
-       php_ob_set_internal_handler(php_session_output_handler, chunk_size TSRMLS_CC);
+       php_start_ob_buffer(NULL, chunk_size, 1 TSRMLS_CC);
+       php_ob_set_internal_handler(php_session_output_handler, chunk_size, "trans sid 
+session", 1 TSRMLS_CC);
        PS(output_handler_registered) = 1;
 }
 
@@ -124,9 +124,12 @@
 static PHP_INI_MH(OnUpdateSerializer)
 {
        PS(serializer) = _php_find_ps_serializer(new_value TSRMLS_CC);
-       if(!PS(serializer)) {
-         php_error(E_ERROR,"Cannot find serialization handler %s",new_value);
-       }         
+/* Following lines are commented out to prevent bogus error message at
+   start up. i.e. Serializer modules are not initilzied before Session
+   module. */
+/*     if(!PS(serializer)) { */
+/*       php_error(E_ERROR,"Cannot find serialization handler %s",new_value); */
+/*     }          */
        return SUCCESS;
 }
 
@@ -473,18 +476,23 @@
 {
        char *ret = NULL;
 
-       if (PS(serializer)->encode(&ret, newlen TSRMLS_CC) == FAILURE)
+       if (PS(serializer)->encode(&ret, newlen TSRMLS_CC) == FAILURE) {
+               PS(session_status) = PS_ERROR;
                ret = NULL;
-
+       }
+       
        return ret;
 }
 
 static void php_session_decode(const char *val, int vallen TSRMLS_DC)
 {
-       php_session_track_init(TSRMLS_C);
-       if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) {
-               php_session_destroy(TSRMLS_C);
-               php_error(E_WARNING, "Failed to decode session object. Session has 
been destroyed.");
+       if (PS(session_status) & PS_ACTIVE) {
+               php_session_track_init(TSRMLS_C);
+               if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) {
+                       PS(session_status) = PS_ERROR;
+                       php_session_destroy(TSRMLS_C);
+                       php_error(E_WARNING, "Failed to decode session object. Session 
+has been destroyed.");
+               }
        }
 }
 
@@ -545,13 +553,17 @@
        int vallen;
        
        if (PS(mod)->open(&PS(mod_data), PS(save_path), PS(session_name)) == FAILURE) {
-               php_error(E_ERROR, "Failed to initialize session module");
+               PS(session_status) = PS_ERROR;
+               php_error(E_WARNING, "Failed to initialize session module");
                return;
        }
-       if (PS(mod)->read(&PS(mod_data), PS(id), &val, &vallen) == SUCCESS) {
-               php_session_decode(val, vallen TSRMLS_CC);
-               efree(val);
+       if (PS(mod)->read(&PS(mod_data), PS(id), &val, &vallen) == FAILURE) {
+               PS(session_status) = PS_ERROR;
+               php_error(E_WARNING, "Failed to read session data");
+               return;
        }
+       php_session_decode(val, vallen TSRMLS_CC);
+       efree(val);
 }
 
 
@@ -565,16 +577,14 @@
        ulong num_key;
        HashPosition pos;
        
-       if (!PG(register_globals) && !PS(http_session_vars)) {
+       if ((!PG(register_globals) && !PS(http_session_vars)) || (PS(session_status) & 
+(PS_DISABLED|PS_NONE|PS_ERROR))) {
                return;
        }
                
-       if (PS(http_session_vars)) {
-               for 
(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(PS(http_session_vars)), &pos);
-                               
zend_hash_get_current_key_ex(Z_ARRVAL_P(PS(http_session_vars)), &variable, 
&variable_len, &num_key, 0, &pos) == HASH_KEY_IS_STRING;
-                               
zend_hash_move_forward_ex(Z_ARRVAL_P(PS(http_session_vars)),&pos)) {
-                       PS_ADD_VARL(variable,variable_len-1);
-               }
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(PS(http_session_vars)), 
+&pos);
+                zend_hash_get_current_key_ex(Z_ARRVAL_P(PS(http_session_vars)), 
+&variable, &variable_len, &num_key, 0, &pos) == HASH_KEY_IS_STRING;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(PS(http_session_vars)),&pos)) {
+               PS_ADD_VARL(variable,variable_len-1);
        }
 
        if (PS(mod_data)) {
@@ -587,13 +597,14 @@
                }
        }
        
-       if (ret == FAILURE)
+       if (ret == FAILURE) {
+               PS(session_status) = PS_ERROR;
                php_error(E_WARNING, "Failed to write session data (%s). Please "
-                               "verify that the current setting of session.save_path "
-                               "is correct (%s)",
-                               PS(mod)->name,
-                               PS(save_path));
-       
+                                 "verify that the current setting of 
+session.save_path "
+                                 "is correct (%s)",
+                                 PS(mod)->name,
+                                 PS(save_path));
+       }
        
        if (PS(mod_data))
                PS(mod)->close(&PS(mod_data));
@@ -740,6 +751,7 @@
        smart_str ncookie = {0};
        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);
@@ -830,10 +842,11 @@
        int module_number = PS(module_number);
        int nrand;
        int lensess;
+       smart_str var = {0};
 
        PS(apply_trans_sid) = PS(use_trans_sid);
 
-       if (PS(session_status) != php_session_none) 
+       if (PS(session_status) & (PS_ACTIVE|PS_ERROR)) 
                return;
 
        lensess = strlen(PS(session_name));
@@ -923,30 +936,23 @@
                php_session_send_cookie(TSRMLS_C);
        }
 
-
-       if (PS(apply_trans_sid)) {
-               smart_str var = {0};
-
-               smart_str_appends(&var, PS(session_name));
-               smart_str_appendc(&var, '=');
-               smart_str_appends(&var, PS(id));
-               smart_str_0(&var);
-               REGISTER_STRING_CONSTANT("SID", var.c, 0);
-       } else {
-               REGISTER_STRING_CONSTANT("SID", empty_string, 0);
-       }
-
-       PS(session_status) = php_session_active;
+       smart_str_appends(&var, PS(session_name));
+       smart_str_appendc(&var, '=');
+       smart_str_appends(&var, PS(id));
+       smart_str_0(&var);
+       REGISTER_STRING_CONSTANT("SID", var.c, 0);
        if (PS(apply_trans_sid)) {
                php_session_start_output_handler(4096 TSRMLS_CC);
        }
 
+       PS(session_status) = PS_ACTIVE;
+
        php_session_cache_limiter(TSRMLS_C);
        php_session_initialize(TSRMLS_C);
 
-       if (PS(mod_data) && PS(gc_probability) > 0) {
+       if ((PS(session_status) & PS_ACTIVE) && PS(gc_probability) > 0) {
                int nrdels = -1;
-
+               
                nrand = (int) (100.0*php_combined_lcg(TSRMLS_C));
                if (nrand < PS(gc_probability)) {
                        PS(mod)->gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels);
@@ -958,18 +964,20 @@
        }
 }
 
+
 static zend_bool php_session_destroy(TSRMLS_D)
 {
        zend_bool retval = SUCCESS;
 
-       if (PS(session_status) != php_session_active) {
-               php_error(E_WARNING, "Trying to destroy uninitialized session");
+       if (PS(session_status) & (PS_DISABLED|PS_NONE|PS_ERROR)) {
+               php_error(E_NOTICE, "Trying to destroy uninitialized session");
                return FAILURE;
        }
 
        if (PS(mod)->destroy(&PS(mod_data), PS(id)) == FAILURE) {
+               PS(session_status) = PS_ERROR;          
                retval = FAILURE;
-               php_error(E_WARNING, "Session object destruction failed");
+               php_error(E_NOTICE, "Session object destruction failed");
        }
        
        php_rshutdown_session_globals(TSRMLS_C);
@@ -996,9 +1004,15 @@
        PS(cookie_lifetime) = Z_LVAL_PP(lifetime);
 
        if (ZEND_NUM_ARGS() > 1) {
+               if (PS(session_status) & (PS_ACTIVE)) {
+                       php_error(E_NOTICE, "%s() cannot set cookie parameter once 
+session is started.",
+                                         get_active_function_name(TSRMLS_C));
+                       RETURN_FALSE;
+               }
+               
                convert_to_string_ex(path);
                zend_alter_ini_entry("session.cookie_path", 
sizeof("session.cookie_path"), Z_STRVAL_PP(path), Z_STRLEN_PP(path), PHP_INI_USER, 
PHP_INI_STAGE_RUNTIME);
-
+               
                if (ZEND_NUM_ARGS() > 2) {
                        convert_to_string_ex(domain);
                        zend_alter_ini_entry("session.cookie_domain", 
sizeof("session.cookie_domain"), Z_STRVAL_PP(domain), Z_STRLEN_PP(domain), 
PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
@@ -1008,6 +1022,7 @@
                        }
                }
        }
+       
 }
 /* }}} */
 
@@ -1045,6 +1060,12 @@
                WRONG_PARAM_COUNT;
 
        if (ac == 1) {
+               if (PS(session_status) & PS_ACTIVE) {
+                       efree(old);
+                       php_error(E_NOTICE, "%s() cannot set session name once session 
+is started.",
+                                         get_active_function_name(TSRMLS_C));
+                       RETURN_FALSE;
+               }
                convert_to_string_ex(p_name);
                zend_alter_ini_entry("session.name", sizeof("session.name"), 
Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name), PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        }
@@ -1069,19 +1090,28 @@
        if (ac == 1) {
                ps_module *tempmod;
 
+               if (PS(session_status) & (PS_ACTIVE|PS_ERROR)) {
+                       efree(old);
+                       php_error(E_NOTICE, "%s() cannot set session module name once 
+session is started. "
+                                         "Current session save handler (%s)",
+                                         get_active_function_name(TSRMLS_C),
+                                         (PS(mod)->name ? PS(mod)->name : "none"));
+                       RETURN_FALSE;
+               }
+                       
                convert_to_string_ex(p_name);
                tempmod = _php_find_ps_module(Z_STRVAL_PP(p_name) TSRMLS_CC);
-               if (tempmod) {
-                       if (PS(mod_data))
-                               PS(mod)->close(&PS(mod_data));
-                       PS(mod) = tempmod;
-                       PS(mod_data) = NULL;
-               } else {
+               if (!tempmod) {
                        efree(old);
-                       php_error(E_ERROR, "Cannot find named PHP session module (%s)",
-                                       Z_STRVAL_PP(p_name));
+                       php_error(E_NOTICE, "Cannot find named PHP session module 
+(%s)",
+                                         Z_STRVAL_PP(p_name));
                        RETURN_FALSE;
                }
+               if (PS(mod_data))
+                       PS(mod)->close(&PS(mod_data));
+               PS(mod) = tempmod;
+               PS(mod_data) = NULL;
+               PS(rinit_mod) = 1;
        }
 
        RETVAL_STRING(old, 0);
@@ -1099,8 +1129,13 @@
        if (ZEND_NUM_ARGS() != 6 || zend_get_parameters_array_ex(6, args) == FAILURE)
                WRONG_PARAM_COUNT;
        
-       if (PS(session_status) != php_session_none) 
+       if (PS(session_status) & PS_ACTIVE) {
+               php_error(E_NOTICE, "%s() cannot set session save handler functions 
+once session is started. "
+                                 "Current session save handler (%s)",
+                                 get_active_function_name(TSRMLS_C),
+                                 (PS(mod)->name ? PS(mod)->name : "none"));
                RETURN_FALSE;
+       }
        
        zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), 
"user", sizeof("user")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
 
@@ -1129,8 +1164,14 @@
 
        if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE)
                WRONG_PARAM_COUNT;
-
+       
        if (ac == 1) {
+               if (PS(session_status) & PS_ACTIVE) {
+                       efree(old);
+                       php_error(E_NOTICE, "%s() cannot change session save path  
+once session is started.",
+                                         get_active_function_name(TSRMLS_C));
+                       RETURN_FALSE;
+               }
                convert_to_string_ex(p_name);
                zend_alter_ini_entry("session.save_path", sizeof("session.save_path"), 
Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name), PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        }
@@ -1152,10 +1193,16 @@
 
        if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE)
                WRONG_PARAM_COUNT;
-
+       
        if (ac == 1) {
-               convert_to_string_ex(p_name);
                if (PS(id)) efree(PS(id));
+               if (PS(session_status) & PS_ACTIVE) {
+                       efree(old);
+                       php_error(E_NOTICE, "%s() cannot set session id once session 
+is started.",
+                                         get_active_function_name(TSRMLS_C));
+                       RETURN_FALSE;
+               }
+               convert_to_string_ex(p_name);
                PS(id) = estrndup(Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name));
        }
        
@@ -1177,6 +1224,13 @@
                WRONG_PARAM_COUNT;
 
        if (ac == 1) {
+               if (PS(session_status) & (PS_ACTIVE|PS_ERROR)) {
+                       efree(old);
+                       php_error(E_NOTICE, "%s() cannot set session module name once 
+session is started.",
+                                         get_active_function_name(TSRMLS_C));
+                       RETURN_FALSE;
+               }
+               
                convert_to_string_ex(p_cache_limiter);
                zend_alter_ini_entry("session.cache_limiter", 
sizeof("session.cache_limiter"), Z_STRVAL_PP(p_cache_limiter), 
Z_STRLEN_PP(p_cache_limiter), PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        }
@@ -1248,7 +1302,7 @@
                WRONG_PARAM_COUNT;
        }
 
-       if (PS(session_status) == php_session_none)
+       if (PS(session_status) & PS_NONE)
                php_session_start(TSRMLS_C);
 
        for (i = 0; i < argc; i++) {
@@ -1272,7 +1326,13 @@
 
        if (ac != 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE)
                WRONG_PARAM_COUNT;
-       
+
+       if (!(PS(session_status) & PS_ACTIVE)) {
+               php_error(E_NOTICE, "%s() cannot be used unless session is started.",
+                                 get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
+               
        convert_to_string_ex(p_name);
        
        PS_DEL_VARL(Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name));
@@ -1292,6 +1352,12 @@
        if (ac != 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE)
                WRONG_PARAM_COUNT;
        
+       if (!(PS(session_status) & PS_ACTIVE)) {
+               php_error(E_NOTICE, "%s() cannot be used unless session is started.",
+                                 get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
+
        convert_to_string_ex(p_name);
        
        if (zend_hash_find(&PS(vars), Z_STRVAL_PP(p_name), 
@@ -1368,7 +1434,7 @@
        char     *variable;
        ulong     num_key;
        
-       if (PS(session_status) == php_session_none)
+       if (PS(session_status) & PS_NONE)
                RETURN_FALSE;
 
        if (PG(register_globals)) {
@@ -1389,7 +1455,7 @@
 
 PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t 
*newlen TSRMLS_DC)
 {
-       if (PS(apply_trans_sid) && (PS(session_status) == php_session_active)) {
+       if (PS(apply_trans_sid) && (PS(session_status) & PS_ACTIVE)) {
                *new = url_adapt_single_url(url, urllen, PS(session_name), PS(id), 
newlen TSRMLS_CC);
        }
 }
@@ -1399,7 +1465,7 @@
 {              
        zend_hash_init(&PS(vars), 0, NULL, NULL, 0);
        PS(id) = NULL;
-       PS(session_status) = php_session_none;
+       PS(session_status) = PS_NONE;
        PS(mod_data) = NULL;
        PS(output_handler_registered) = 0;
 }
@@ -1420,8 +1486,9 @@
 {
        php_rinit_session_globals(TSRMLS_C);
 
-       if (PS(mod) == NULL) {
+       if (PS(mod) == NULL || PS(rinit_mod)) {
                char *value;
+               PS(rinit_mod) = 0;
 
                value = zend_ini_string("session.save_handler", 
sizeof("session.save_handler"), 0);
                if (value) {
@@ -1430,7 +1497,7 @@
 
                if (!PS(mod)) {
                        /* current status is unusable */
-                       PS(session_status) = php_session_disabled;
+                       PS(session_status) = PS_DISABLED;
                        return SUCCESS;
                }
        }
@@ -1444,9 +1511,9 @@
 
 static void php_session_flush(TSRMLS_D)
 {
-       if(PS(session_status)==php_session_active) {
+       if(PS(session_status) & PS_ACTIVE) {
                php_session_save_current_state(TSRMLS_C);
-               PS(session_status)=php_session_none;
+               PS(session_status) = PS_DISABLED;
        }
 }
 
@@ -1464,6 +1531,7 @@
        }
        php_session_flush(TSRMLS_C);
        php_rshutdown_session_globals(TSRMLS_C);
+       PS(session_status) = PS_DISABLED;
        return SUCCESS;
 }
 /* }}} */

-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to