summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/SAPI.c341
-rw-r--r--main/SAPI.h18
-rw-r--r--main/fopen_wrappers.c147
-rw-r--r--main/fopen_wrappers.h3
-rw-r--r--main/main.c446
-rw-r--r--main/network.c6
-rw-r--r--main/output.c1671
-rw-r--r--main/php.h32
-rw-r--r--main/php3_compat.h122
-rw-r--r--main/php_content_types.c6
-rw-r--r--main/php_globals.h20
-rw-r--r--main/php_ini.c63
-rw-r--r--main/php_logos.c2
-rw-r--r--main/php_main.h1
-rw-r--r--main/php_network.h5
-rw-r--r--main/php_open_temporary_file.c2
-rw-r--r--main/php_output.h299
-rw-r--r--main/php_streams.h24
-rw-r--r--main/php_variables.c337
-rw-r--r--main/php_version.h8
-rw-r--r--main/rfc1867.c391
-rw-r--r--main/rfc1867.h15
-rw-r--r--main/safe_mode.c276
-rw-r--r--main/safe_mode.h41
-rw-r--r--main/snprintf.c6
-rw-r--r--main/spprintf.c2
-rw-r--r--main/streams/cast.c2
-rw-r--r--main/streams/glob_wrapper.c2
-rw-r--r--main/streams/memory.c18
-rw-r--r--main/streams/php_stream_context.h6
-rw-r--r--main/streams/plain_wrapper.c284
-rw-r--r--main/streams/streams.c103
-rw-r--r--main/streams/userspace.c508
-rw-r--r--main/streams/xp_socket.c4
34 files changed, 2783 insertions, 2428 deletions
diff --git a/main/SAPI.c b/main/SAPI.c
index 05644df11d..fc4b7bee84 100644
--- a/main/SAPI.c
+++ b/main/SAPI.c
@@ -37,6 +37,8 @@
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
+#elif defined(PHP_WIN32)
+#include "win32/time.h"
#endif
#include "rfc1867.h"
@@ -73,6 +75,10 @@ SAPI_API sapi_module_struct sapi_module;
SAPI_API void sapi_startup(sapi_module_struct *sf)
{
+#ifdef ZEND_SIGNALS
+ zend_signal_startup();
+#endif
+
sf->ini_entries = NULL;
sapi_module = *sf;
@@ -117,6 +123,58 @@ SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
efree(sapi_header->header);
}
+/* {{{ proto bool header_register_callback(mixed callback)
+ call a header function */
+PHP_FUNCTION(header_register_callback)
+{
+ zval *callback_func;
+ char *callback_name;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &callback_func) == FAILURE) {
+ return;
+ }
+
+ if (!zend_is_callable(callback_func, 0, &callback_name TSRMLS_CC)) {
+ efree(callback_name);
+ RETURN_FALSE;
+ }
+ efree(callback_name);
+
+ if (SG(callback_func)) {
+ zval_ptr_dtor(&SG(callback_func));
+ SG(fci_cache) = empty_fcall_info_cache;
+ }
+
+ Z_ADDREF_P(callback_func);
+
+ SG(callback_func) = callback_func;
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+static void sapi_run_header_callback(TSRMLS_D)
+{
+ int error;
+ zend_fcall_info fci;
+ zval *retval_ptr = NULL;
+
+ fci.size = sizeof(fci);
+ fci.function_table = EG(function_table);
+ fci.object_ptr = NULL;
+ fci.function_name = SG(callback_func);
+ fci.retval_ptr_ptr = &retval_ptr;
+ fci.param_count = 0;
+ fci.params = NULL;
+ fci.no_separation = 0;
+ fci.symbol_table = NULL;
+
+ error = zend_call_function(&fci, &SG(fci_cache) TSRMLS_CC);
+ if (error == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the sapi_header_callback");
+ } else if (retval_ptr) {
+ zval_ptr_dtor(&retval_ptr);
+ }
+}
SAPI_API void sapi_handle_post(void *arg TSRMLS_DC)
{
@@ -227,35 +285,61 @@ SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
}
-SAPI_API char *sapi_get_default_content_type(TSRMLS_D)
+static inline char *get_default_content_type(uint prefix_len, uint *len TSRMLS_DC)
{
char *mimetype, *charset, *content_type;
+ uint mimetype_len, charset_len;
- mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
- charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
+ if (SG(default_mimetype)) {
+ mimetype = SG(default_mimetype);
+ mimetype_len = strlen(SG(default_mimetype));
+ } else {
+ mimetype = SAPI_DEFAULT_MIMETYPE;
+ mimetype_len = sizeof(SAPI_DEFAULT_MIMETYPE) - 1;
+ }
+ if (SG(default_charset)) {
+ charset = SG(default_charset);
+ charset_len = strlen(SG(default_charset));
+ } else {
+ charset = SAPI_DEFAULT_CHARSET;
+ charset_len = sizeof(SAPI_DEFAULT_CHARSET) - 1;
+ }
- if (strncasecmp(mimetype, "text/", 5) == 0 && *charset) {
- int len = strlen(mimetype) + sizeof("; charset=") + strlen(charset); /* sizeof() includes \0 */
- content_type = emalloc(len);
- snprintf(content_type, len, "%s; charset=%s", mimetype, charset);
+ if (*charset && strncasecmp(mimetype, "text/", 5) == 0) {
+ char *p;
+
+ *len = prefix_len + mimetype_len + sizeof("; charset=") - 1 + charset_len;
+ content_type = (char*)emalloc(*len + 1);
+ p = content_type + prefix_len;
+ memcpy(p, mimetype, mimetype_len);
+ p += mimetype_len;
+ memcpy(p, "; charset=", sizeof("; charset=") - 1);
+ p += sizeof("; charset=") - 1;
+ memcpy(p, charset, charset_len + 1);
} else {
- content_type = estrdup(mimetype);
+ *len = prefix_len + mimetype_len;
+ content_type = (char*)emalloc(*len + 1);
+ memcpy(content_type + prefix_len, mimetype, mimetype_len + 1);
}
return content_type;
}
+SAPI_API char *sapi_get_default_content_type(TSRMLS_D)
+{
+ uint len;
+
+ return get_default_content_type(0, &len TSRMLS_CC);
+}
+
+
SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header TSRMLS_DC)
{
- char *default_content_type = sapi_get_default_content_type(TSRMLS_C);
- int default_content_type_len = strlen(default_content_type);
-
- default_header->header_len = (sizeof("Content-type: ")-1) + default_content_type_len;
- default_header->header = emalloc(default_header->header_len+1);
- memcpy(default_header->header, "Content-type: ", sizeof("Content-type: "));
- memcpy(default_header->header+sizeof("Content-type: ")-1, default_content_type, default_content_type_len);
- default_header->header[default_header->header_len] = 0;
- efree(default_content_type);
+ uint len;
+
+ default_header->header = get_default_content_type(sizeof("Content-type: ")-1, &len TSRMLS_CC);
+ default_header->header_len = len;
+ memcpy(default_header->header, "Content-type: ", sizeof("Content-type: ") - 1);
}
/*
@@ -346,6 +430,8 @@ SAPI_API void sapi_activate(TSRMLS_D)
SG(sapi_headers).http_status_line = NULL;
SG(sapi_headers).mimetype = NULL;
SG(headers_sent) = 0;
+ SG(callback_run) = 0;
+ SG(callback_func) = NULL;
SG(read_post_bytes) = 0;
SG(request_info).post_data = NULL;
SG(request_info).raw_post_data = NULL;
@@ -356,9 +442,7 @@ SAPI_API void sapi_activate(TSRMLS_D)
SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
SG(global_request_time) = 0;
- /* It's possible to override this general case in the activate() callback, if
- * necessary.
- */
+ /* It's possible to override this general case in the activate() callback, if necessary. */
if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
SG(request_info).headers_only = 1;
} else {
@@ -366,22 +450,19 @@ SAPI_API void sapi_activate(TSRMLS_D)
}
SG(rfc1867_uploaded_files) = NULL;
- /* handle request mehtod */
+ /* Handle request method */
if (SG(server_context)) {
- if ( SG(request_info).request_method) {
- if(!strcmp(SG(request_info).request_method, "POST")
- && (SG(request_info).content_type)) {
- /* HTTP POST -> may contain form data to be read into variables
- depending on content type given
- */
+ if (PG(enable_post_data_reading) && SG(request_info).request_method) {
+ if (SG(request_info).content_type && !strcmp(SG(request_info).request_method, "POST")) {
+ /* HTTP POST may contain form data to be processed into variables
+ * depending on given content type */
sapi_read_post_data(TSRMLS_C);
} else {
- /* any other method with content payload will fill
- $HTTP_RAW_POST_DATA if enabled by always_populate_raw_post_data
- it is up to the webserver to decide whether to allow a method or not
- */
+ /* Any other method with content payload will fill $HTTP_RAW_POST_DATA
+ * if it is enabled by always_populate_raw_post_data.
+ * It's up to the webserver to decide whether to allow a method or not. */
SG(request_info).content_type_dup = NULL;
- if(sapi_module.default_post_reader) {
+ if (sapi_module.default_post_reader) {
sapi_module.default_post_reader(TSRMLS_C);
}
}
@@ -391,11 +472,12 @@ SAPI_API void sapi_activate(TSRMLS_D)
/* Cookies */
SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
+
if (sapi_module.activate) {
sapi_module.activate(TSRMLS_C);
}
}
- if (sapi_module.input_filter_init ) {
+ if (sapi_module.input_filter_init) {
sapi_module.input_filter_init(TSRMLS_C);
}
}
@@ -456,6 +538,10 @@ SAPI_API void sapi_deactivate(TSRMLS_D)
sapi_send_headers_free(TSRMLS_C);
SG(sapi_started) = 0;
SG(headers_sent) = 0;
+ SG(callback_run) = 0;
+ if (SG(callback_func)) {
+ zval_ptr_dtor(&SG(callback_func));
+ }
SG(request_info).headers_read = 0;
SG(global_request_time) = 0;
}
@@ -550,19 +636,38 @@ SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bo
return r;
}
+static void sapi_header_add_op(sapi_header_op_enum op, sapi_header_struct *sapi_header TSRMLS_DC)
+{
+ if (!sapi_module.header_handler ||
+ (SAPI_HEADER_ADD & sapi_module.header_handler(sapi_header, op, &SG(sapi_headers) TSRMLS_CC))) {
+ if (op == SAPI_HEADER_REPLACE) {
+ char *colon_offset = strchr(sapi_header->header, ':');
+
+ if (colon_offset) {
+ char sav = *colon_offset;
+
+ *colon_offset = 0;
+ sapi_remove_header(&SG(sapi_headers).headers, sapi_header->header, strlen(sapi_header->header));
+ *colon_offset = sav;
+ }
+ }
+ zend_llist_add_element(&SG(sapi_headers).headers, (void *) sapi_header);
+ } else {
+ sapi_free_header(sapi_header);
+ }
+}
+
SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
{
- int retval;
sapi_header_struct sapi_header;
char *colon_offset;
- long myuid = 0L;
char *header_line;
uint header_line_len;
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);
+ const char *output_start_filename = php_output_get_start_filename(TSRMLS_C);
+ int output_start_lineno = php_output_get_start_lineno(TSRMLS_C);
if (output_start_filename) {
sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
@@ -606,8 +711,12 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
header_line = estrndup(header_line, header_line_len);
/* cut of trailing spaces, linefeeds and carriage-returns */
- while(header_line_len && isspace(header_line[header_line_len-1]))
- header_line[--header_line_len]='\0';
+ if (header_line_len && isspace(header_line[header_line_len-1])) {
+ do {
+ header_line_len--;
+ } while(header_line_len && isspace(header_line[header_line_len-1]));
+ header_line[header_line_len]='\0';
+ }
if (op == SAPI_HEADER_DELETE) {
if (strchr(header_line, ':')) {
@@ -615,6 +724,14 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
return FAILURE;
}
+ if (sapi_module.header_handler) {
+ sapi_header.header = header_line;
+ sapi_header.header_len = header_line_len;
+ sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
+ }
+ sapi_remove_header(&SG(sapi_headers).headers, header_line, header_line_len);
+ efree(header_line);
+ return SUCCESS;
} else {
/* new line/NUL character safety check */
int i;
@@ -642,15 +759,6 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
sapi_header.header = header_line;
sapi_header.header_len = header_line_len;
- if (op == SAPI_HEADER_DELETE) {
- if (sapi_module.header_handler) {
- sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
- }
- sapi_remove_header(&SG(sapi_headers).headers, sapi_header.header, sapi_header.header_len);
- sapi_free_header(&sapi_header);
- return SUCCESS;
- }
-
/* Check the header for a few cases that we have special support for in SAPI */
if (header_line_len>=5
&& !strncasecmp(header_line, "HTTP/", 5)) {
@@ -696,6 +804,14 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
}
efree(mimetype);
SG(sapi_headers).send_default_content_type = 0;
+ } else if (!STRCASECMP(header_line, "Content-Length")) {
+ /* Script is setting Content-length. The script cannot reasonably
+ * know the size of the message body after compression, so it's best
+ * do disable compression altogether. This contributes to making scripts
+ * portable between setups that have and don't have zlib compression
+ * enabled globally. See req #44164 */
+ zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"),
+ "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
} else if (!STRCASECMP(header_line, "Location")) {
if ((SG(sapi_headers).http_response_code < 300 ||
SG(sapi_headers).http_response_code > 307) &&
@@ -713,75 +829,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
}
}
} else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
-
sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */
-
- if(PG(safe_mode))
-#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
- {
- zval *repl_temp;
- char *ptr = colon_offset+1, *result, *newheader;
- int ptr_len=0, result_len = 0, newlen = 0;
-
- /* skip white space */
- while (isspace(*ptr)) {
- ptr++;
- }
-
- myuid = php_getuid();
-
- ptr_len = strlen(ptr);
- MAKE_STD_ZVAL(repl_temp);
- Z_TYPE_P(repl_temp) = IS_STRING;
- Z_STRLEN_P(repl_temp) = spprintf(&Z_STRVAL_P(repl_temp), 0, "realm=\"\\1-%ld\"", myuid);
- /* Modify quoted realm value */
- result = php_pcre_replace("/realm=\"(.*?)\"/i", 16,
- ptr, ptr_len,
- repl_temp,
- 0, &result_len, -1, NULL TSRMLS_CC);
- if(result_len==ptr_len) {
- efree(result);
- efree(Z_STRVAL_P(repl_temp));
- Z_STRLEN_P(repl_temp) = spprintf(&Z_STRVAL_P(repl_temp), 0, "realm=\\1-%ld\\2", myuid);
- /* modify unquoted realm value */
- result = php_pcre_replace("/realm=([^\\s]+)(.*)/i", 21,
- ptr, ptr_len,
- repl_temp,
- 0, &result_len, -1, NULL TSRMLS_CC);
- if(result_len==ptr_len) {
- char *lower_temp = estrdup(ptr);
- char conv_temp[32];
- int conv_len;
-
- php_strtolower(lower_temp,strlen(lower_temp));
- /* If there is no realm string at all, append one */
- if(!strstr(lower_temp,"realm")) {
- efree(result);
- conv_len = slprintf(conv_temp, sizeof(conv_temp), " realm=\"%ld\"",myuid);
- result = emalloc(ptr_len+conv_len+1);
- result_len = ptr_len+conv_len;
- memcpy(result, ptr, ptr_len);
- memcpy(result+ptr_len, conv_temp, conv_len);
- *(result+ptr_len+conv_len) = '\0';
- }
- efree(lower_temp);
- }
- }
- newlen = spprintf(&newheader, 0, "WWW-Authenticate: %s", result);
- efree(header_line);
- sapi_header.header = newheader;
- sapi_header.header_len = newlen;
- efree(result);
- efree(Z_STRVAL_P(repl_temp));
- efree(repl_temp);
- }
-#else
- {
- myuid = php_getuid();
- efree(header_line);
- sapi_header.header_len = spprintf(&sapi_header.header, 0, "WWW-Authenticate: Basic realm=\"%ld\"", myuid);
- }
-#endif
}
if (sapi_header.header==header_line) {
*colon_offset = ':';
@@ -791,28 +839,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
if (http_response_code) {
sapi_update_response_code(http_response_code TSRMLS_CC);
}
- if (sapi_module.header_handler) {
- retval = sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
- } else {
- retval = SAPI_HEADER_ADD;
- }
- if (retval & SAPI_HEADER_ADD) {
- /* in replace mode first remove the header if it already exists in the headers llist */
- if (op == SAPI_HEADER_REPLACE) {
- colon_offset = strchr(sapi_header.header, ':');
- if (colon_offset) {
- char sav;
- sav = *colon_offset;
- *colon_offset = 0;
- sapi_remove_header(&SG(sapi_headers).headers, sapi_header.header, strlen(sapi_header.header));
- *colon_offset = sav;
- }
- }
-
- zend_llist_add_element(&SG(sapi_headers).headers, (void *) &sapi_header);
- } else {
- sapi_free_header(&sapi_header);
- }
+ sapi_header_add_op(op, &sapi_header TSRMLS_CC);
return SUCCESS;
}
@@ -822,7 +849,7 @@ SAPI_API int sapi_send_headers(TSRMLS_D)
int retval;
int ret = FAILURE;
- if (SG(headers_sent) || SG(request_info).no_headers) {
+ if (SG(headers_sent) || SG(request_info).no_headers || SG(callback_run)) {
return SUCCESS;
}
@@ -831,8 +858,20 @@ SAPI_API int sapi_send_headers(TSRMLS_D)
*/
if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
sapi_header_struct default_header;
- sapi_get_default_content_type_header(&default_header TSRMLS_CC);
- sapi_add_header_ex(default_header.header, default_header.header_len, 0, 0 TSRMLS_CC);
+ uint len;
+
+ SG(sapi_headers).mimetype = get_default_content_type(0, &len TSRMLS_CC);
+ default_header.header_len = sizeof("Content-type: ") - 1 + len;
+ default_header.header = emalloc(default_header.header_len + 1);
+ memcpy(default_header.header, "Content-type: ", sizeof("Content-type: ") - 1);
+ memcpy(default_header.header + sizeof("Content-type: ") - 1, SG(sapi_headers).mimetype, len + 1);
+ sapi_header_add_op(SAPI_HEADER_ADD, &default_header TSRMLS_CC);
+ SG(sapi_headers).send_default_content_type = 0;
+ }
+
+ if (SG(callback_func) && !SG(callback_run)) {
+ SG(callback_run) = 1;
+ sapi_run_header_callback(TSRMLS_C);
}
SG(headers_sent) = 1;
@@ -917,9 +956,8 @@ SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
}
-SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D))
+SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D) TSRMLS_DC)
{
- TSRMLS_FETCH();
if (SG(sapi_started) && EG(in_execution)) {
return FAILURE;
}
@@ -928,9 +966,8 @@ SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRML
}
-SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC))
+SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC) TSRMLS_DC)
{
- TSRMLS_FETCH();
if (SG(sapi_started) && EG(in_execution)) {
return FAILURE;
}
@@ -938,9 +975,8 @@ SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zva
return SUCCESS;
}
-SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D))
+SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D) TSRMLS_DC)
{
- TSRMLS_FETCH();
if (SG(sapi_started) && EG(in_execution)) {
return FAILURE;
}
@@ -1025,14 +1061,19 @@ SAPI_API int sapi_get_target_gid(gid_t *obj TSRMLS_DC)
}
}
-SAPI_API time_t sapi_get_request_time(TSRMLS_D)
+SAPI_API double sapi_get_request_time(TSRMLS_D)
{
if(SG(global_request_time)) return SG(global_request_time);
if (sapi_module.get_request_time && SG(server_context)) {
SG(global_request_time) = sapi_module.get_request_time(TSRMLS_C);
} else {
- SG(global_request_time) = time(0);
+ struct timeval tp = {0};
+ if (!gettimeofday(&tp, NULL)) {
+ SG(global_request_time) = (double)(tp.tv_sec + tp.tv_usec / 1000000.00);
+ } else {
+ SG(global_request_time) = (double)time(0);
+ }
}
return SG(global_request_time);
}
diff --git a/main/SAPI.h b/main/SAPI.h
index 9a063d396a..8f2536b84f 100644
--- a/main/SAPI.h
+++ b/main/SAPI.h
@@ -128,8 +128,11 @@ typedef struct _sapi_globals_struct {
long post_max_size;
int options;
zend_bool sapi_started;
- time_t global_request_time;
+ double global_request_time;
HashTable known_post_content_types;
+ zval *callback_func;
+ zend_fcall_info_cache fci_cache;
+ zend_bool callback_run;
} sapi_globals_struct;
@@ -189,9 +192,9 @@ SAPI_API void sapi_handle_post(void *arg TSRMLS_DC);
SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entry TSRMLS_DC);
SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC);
SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC);
-SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D));
-SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC));
-SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D));
+SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D) TSRMLS_DC);
+SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC) TSRMLS_DC);
+SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D) TSRMLS_DC);
SAPI_API int sapi_flush(TSRMLS_D);
SAPI_API struct stat *sapi_get_stat(TSRMLS_D);
@@ -207,7 +210,7 @@ SAPI_API int sapi_force_http_10(TSRMLS_D);
SAPI_API int sapi_get_target_uid(uid_t * TSRMLS_DC);
SAPI_API int sapi_get_target_gid(gid_t * TSRMLS_DC);
-SAPI_API time_t sapi_get_request_time(TSRMLS_D);
+SAPI_API double sapi_get_request_time(TSRMLS_D);
SAPI_API void sapi_terminate_process(TSRMLS_D);
END_EXTERN_C()
@@ -236,8 +239,8 @@ struct _sapi_module_struct {
char *(*read_cookies)(TSRMLS_D);
void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
- void (*log_message)(char *message);
- time_t (*get_request_time)(TSRMLS_D);
+ void (*log_message)(char *message TSRMLS_DC);
+ double (*get_request_time)(TSRMLS_D);
void (*terminate_process)(TSRMLS_D);
char *php_ini_path_override;
@@ -250,6 +253,7 @@ struct _sapi_module_struct {
char *executable_location;
int php_ini_ignore;
+ int php_ini_ignore_cwd; /* don't look for php.ini in the current directory */
int (*get_fd)(int *fd TSRMLS_DC);
diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c
index 1ea07e1f13..9d4a8a85c2 100644
--- a/main/fopen_wrappers.c
+++ b/main/fopen_wrappers.c
@@ -39,7 +39,6 @@
#include <sys/param.h>
#endif
-#include "safe_mode.h"
#include "ext/standard/head.h"
#include "ext/standard/php_standard.h"
#include "zend_compile.h"
@@ -338,55 +337,6 @@ PHPAPI int php_check_open_basedir_ex(const char *path, int warn TSRMLS_DC)
}
/* }}} */
-/* {{{ php_check_safe_mode_include_dir
- */
-PHPAPI int php_check_safe_mode_include_dir(const char *path TSRMLS_DC)
-{
- if (PG(safe_mode)) {
- if (PG(safe_mode_include_dir) && *PG(safe_mode_include_dir)) {
- char *pathbuf;
- char *ptr;
- char *end;
- char resolved_name[MAXPATHLEN];
-
- /* Resolve the real path into resolved_name */
- if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
- return -1;
- }
- pathbuf = estrdup(PG(safe_mode_include_dir));
- ptr = pathbuf;
-
- while (ptr && *ptr) {
- end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
- if (end != NULL) {
- *end = '\0';
- end++;
- }
-
- /* Check the path */
-#ifdef PHP_WIN32
- if (strncasecmp(ptr, resolved_name, strlen(ptr)) == 0)
-#else
- if (strncmp(ptr, resolved_name, strlen(ptr)) == 0)
-#endif
- {
- /* File is in the right directory */
- efree(pathbuf);
- return 0;
- }
-
- ptr = end;
- }
- efree(pathbuf);
- }
- return -1;
- }
-
- /* Nothing to check... */
- return 0;
-}
-/* }}} */
-
/* {{{ php_fopen_and_set_opened_path
*/
static FILE *php_fopen_and_set_opened_path(const char *path, const char *mode, char **opened_path TSRMLS_DC)
@@ -398,7 +348,7 @@ static FILE *php_fopen_and_set_opened_path(const char *path, const char *mode, c
}
fp = VCWD_FOPEN(path, mode);
if (fp && opened_path) {
- *opened_path = expand_filepath(path, NULL TSRMLS_CC);
+ *opened_path = expand_filepath_with_mode(path, NULL, NULL, 0, CWD_EXPAND TSRMLS_CC);
}
return fp;
}
@@ -408,14 +358,11 @@ static FILE *php_fopen_and_set_opened_path(const char *path, const char *mode, c
*/
PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
{
- FILE *fp;
-#ifndef PHP_WIN32
- struct stat st;
-#endif
char *path_info;
char *filename = NULL;
char *resolved_path = NULL;
int length;
+ zend_bool orig_display_errors;
path_info = SG(request_info).request_uri;
#if HAVE_PWD_H
@@ -496,17 +443,12 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
SG(request_info).path_translated = NULL;
return FAILURE;
}
- fp = VCWD_FOPEN(resolved_path, "rb");
+ efree(resolved_path);
-#ifndef PHP_WIN32
- /* refuse to open anything that is not a regular file */
- if (fp && (0 > fstat(fileno(fp), &st) || !S_ISREG(st.st_mode))) {
- fclose(fp);
- fp = NULL;
- }
-#endif
-
- if (!fp) {
+ orig_display_errors = PG(display_errors);
+ PG(display_errors) = 0;
+ if (zend_stream_open(filename, file_handle TSRMLS_CC) == FAILURE) {
+ PG(display_errors) = orig_display_errors;
if (SG(request_info).path_translated != filename) {
STR_FREE(filename);
}
@@ -514,19 +456,13 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
SG(request_info).path_translated = NULL;
return FAILURE;
}
-
- file_handle->opened_path = resolved_path;
+ PG(display_errors) = orig_display_errors;
if (SG(request_info).path_translated != filename) {
STR_FREE(SG(request_info).path_translated); /* for same reason as above */
SG(request_info).path_translated = filename;
}
- file_handle->filename = SG(request_info).path_translated;
- file_handle->free_filename = 0;
- file_handle->handle.fp = fp;
- file_handle->type = ZEND_HANDLE_FP;
-
return SUCCESS;
}
/* }}} */
@@ -542,11 +478,7 @@ PHPAPI char *php_resolve_path(const char *filename, int filename_length, const c
char *actual_path;
php_stream_wrapper *wrapper;
- if (!filename) {
- return NULL;
- }
-
- if (strlen(filename) != filename_length) {
+ if (!filename || CHECK_NULL_PATH(filename, filename_length)) {
return NULL;
}
@@ -633,7 +565,7 @@ PHPAPI char *php_resolve_path(const char *filename, int filename_length, const c
/* check in calling scripts' current working directory as a fall back case
*/
if (zend_is_executing(TSRMLS_C)) {
- char *exec_fname = zend_get_executed_filename(TSRMLS_C);
+ const char *exec_fname = zend_get_executed_filename(TSRMLS_C);
int exec_fname_length = strlen(exec_fname);
while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
@@ -679,9 +611,8 @@ PHPAPI char *php_resolve_path(const char *filename, int filename_length, const c
PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const char *path, char **opened_path TSRMLS_DC)
{
char *pathbuf, *ptr, *end;
- char *exec_fname;
+ const char *exec_fname;
char trypath[MAXPATHLEN];
- struct stat sb;
FILE *fp;
int path_length;
int filename_length;
@@ -698,34 +629,11 @@ PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const c
filename_length = strlen(filename);
/* Relative path open */
- if (*filename == '.') {
- if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
- return NULL;
- }
- return php_fopen_and_set_opened_path(filename, mode, opened_path TSRMLS_CC);
- }
-
- /*
- * files in safe_mode_include_dir (or subdir) are excluded from
- * safe mode GID/UID checks
- */
-
+ if ((*filename == '.')
/* Absolute path open */
- if (IS_ABSOLUTE_PATH(filename, filename_length)) {
- if (php_check_safe_mode_include_dir(filename TSRMLS_CC) == 0) {
- /* filename is in safe_mode_include_dir (or subdir) */
- return php_fopen_and_set_opened_path(filename, mode, opened_path TSRMLS_CC);
- }
- if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
- return NULL;
- }
- return php_fopen_and_set_opened_path(filename, mode, opened_path TSRMLS_CC);
- }
-
- if (!path || (path && !*path)) {
- if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
- return NULL;
- }
+ || IS_ABSOLUTE_PATH(filename, filename_length)
+ || (!path || (path && !*path))
+ ) {
return php_fopen_and_set_opened_path(filename, mode, opened_path TSRMLS_CC);
}
@@ -764,21 +672,6 @@ PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const c
if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN);
}
- if (PG(safe_mode)) {
- if (VCWD_STAT(trypath, &sb) == 0) {
- /* file exists ... check permission */
- if (php_check_safe_mode_include_dir(trypath TSRMLS_CC) == 0 ||
- php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM)
- ) {
- /* UID ok, or trypath is in safe_mode_include_dir */
- fp = php_fopen_and_set_opened_path(trypath, mode, opened_path TSRMLS_CC);
- } else {
- fp = NULL;
- }
- efree(pathbuf);
- return fp;
- }
- }
fp = php_fopen_and_set_opened_path(trypath, mode, opened_path TSRMLS_CC);
if (fp) {
efree(pathbuf);
@@ -844,6 +737,14 @@ PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC)
*/
PHPAPI char *expand_filepath_ex(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len TSRMLS_DC)
{
+ return expand_filepath_with_mode(filepath, real_path, relative_to, relative_to_len, CWD_FILEPATH TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ expand_filepath_use_realpath
+ */
+PHPAPI char *expand_filepath_with_mode(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len, int realpath_mode TSRMLS_DC)
+{
cwd_state new_state;
char cwd[MAXPATHLEN];
int copy_len;
@@ -888,7 +789,7 @@ PHPAPI char *expand_filepath_ex(const char *filepath, char *real_path, const cha
new_state.cwd = strdup(cwd);
new_state.cwd_length = strlen(cwd);
- if (virtual_file_ex(&new_state, filepath, NULL, CWD_FILEPATH)) {
+ if (virtual_file_ex(&new_state, filepath, NULL, realpath_mode TSRMLS_CC)) {
free(new_state.cwd);
return NULL;
}
diff --git a/main/fopen_wrappers.h b/main/fopen_wrappers.h
index 8f48a1c2f5..6dcc6e1ccc 100644
--- a/main/fopen_wrappers.h
+++ b/main/fopen_wrappers.h
@@ -28,13 +28,14 @@ BEGIN_EXTERN_C()
PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC);
PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC);
PHPAPI char *expand_filepath_ex(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len TSRMLS_DC);
+PHPAPI char *expand_filepath_with_mode(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len, int realpath_mode TSRMLS_DC);
PHPAPI int php_check_open_basedir(const char *path TSRMLS_DC);
PHPAPI int php_check_open_basedir_ex(const char *path, int warn TSRMLS_DC);
PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path TSRMLS_DC);
/* {{{ OPENBASEDIR_CHECKPATH(filename) to ease merge between 6.x and 5.x */
-#if (PHP_MAJOR_VERSION < 6)
+#if PHP_API_VERSION < 20100412
# define OPENBASEDIR_CHECKPATH(filename) \
(PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)
#else
diff --git a/main/main.c b/main/main.c
index 631a6a9fea..44c61c6005 100644
--- a/main/main.c
+++ b/main/main.c
@@ -82,6 +82,7 @@
#include "zend_indent.h"
#include "zend_extensions.h"
#include "zend_ini.h"
+#include "zend_dtrace.h"
#include "php_content_types.h"
#include "php_ticks.h"
@@ -125,9 +126,9 @@ PHPAPI int core_globals_id;
#ifdef PHP_WIN32
#include "win32_internal_function_disabled.h"
-static php_win32_disable_functions() {
+static php_win32_disable_functions(TSRMLS_D)
+{
int i;
- TSRMLS_FETCH();
if (EG(windows_version_info).dwMajorVersion < 5) {
for (i = 0; i < function_name_cnt_5; i++) {
@@ -254,6 +255,57 @@ static void php_disable_classes(TSRMLS_D)
}
/* }}} */
+/* {{{ php_binary_init
+ */
+static void php_binary_init(TSRMLS_D)
+{
+ char *binary_location;
+#ifdef PHP_WIN32
+ binary_location = (char *)malloc(MAXPATHLEN);
+ if (GetModuleFileName(0, binary_location, MAXPATHLEN) == 0) {
+ free(binary_location);
+ PG(php_binary) = NULL;
+ }
+#else
+ if (sapi_module.executable_location) {
+ binary_location = (char *)malloc(MAXPATHLEN);
+ if (!strchr(sapi_module.executable_location, '/')) {
+ char *envpath, *path;
+ int found = 0;
+
+ if ((envpath = getenv("PATH")) != NULL) {
+ char *search_dir, search_path[MAXPATHLEN];
+ char *last = NULL;
+
+ path = estrdup(envpath);
+ search_dir = php_strtok_r(path, ":", &last);
+
+ while (search_dir) {
+ snprintf(search_path, MAXPATHLEN, "%s/%s", search_dir, sapi_module.executable_location);
+ if (VCWD_REALPATH(search_path, binary_location) && !VCWD_ACCESS(binary_location, X_OK)) {
+ found = 1;
+ break;
+ }
+ search_dir = php_strtok_r(NULL, ":", &last);
+ }
+ efree(path);
+ }
+ if (!found) {
+ free(binary_location);
+ binary_location = NULL;
+ }
+ } else if (!VCWD_REALPATH(sapi_module.executable_location, binary_location) || VCWD_ACCESS(binary_location, X_OK)) {
+ free(binary_location);
+ binary_location = NULL;
+ }
+ } else {
+ binary_location = NULL;
+ }
+#endif
+ PG(php_binary) = binary_location;
+}
+/* }}} */
+
/* {{{ PHP_INI_MH
*/
static PHP_INI_MH(OnUpdateTimeout)
@@ -365,14 +417,9 @@ static PHP_INI_MH(OnUpdateErrorLog)
{
/* Only do the safemode/open_basedir check at runtime */
if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && new_value && strcmp(new_value, "syslog")) {
- if (PG(safe_mode) && (!php_checkuid(new_value, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
- return FAILURE;
- }
-
if (PG(open_basedir) && php_check_open_basedir(new_value TSRMLS_CC)) {
return FAILURE;
}
-
}
OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
return SUCCESS;
@@ -385,14 +432,9 @@ static PHP_INI_MH(OnUpdateMailLog)
{
/* Only do the safemode/open_basedir check at runtime */
if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && new_value) {
- if (PG(safe_mode) && (!php_checkuid(new_value, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
- return FAILURE;
- }
-
if (PG(open_basedir) && php_check_open_basedir(new_value TSRMLS_CC)) {
return FAILURE;
}
-
}
OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
return SUCCESS;
@@ -414,10 +456,8 @@ static PHP_INI_MH(OnChangeMailForceExtra)
/* defined in browscap.c */
PHP_INI_MH(OnChangeBrowscap);
-/* Need to convert to strings and make use of:
- * PHP_SAFE_MODE
- *
- * Need to be read from the environment (?):
+
+/* Need to be read from the environment (?):
* PHP_AUTO_PREPEND_FILE
* PHP_AUTO_APPEND_FILE
* PHP_DOCUMENT_ROOT
@@ -425,10 +465,6 @@ PHP_INI_MH(OnChangeBrowscap);
* PHP_INCLUDE_PATH
*/
-#ifndef PHP_SAFE_MODE_EXEC_DIR
-# define PHP_SAFE_MODE_EXEC_DIR ""
-#endif
-
/* Windows and Netware use the internal mail */
#if defined(PHP_WIN32) || defined(NETWARE)
# define DEFAULT_SENDMAIL_PATH NULL
@@ -441,15 +477,12 @@ PHP_INI_MH(OnChangeBrowscap);
/* {{{ PHP_INI
*/
PHP_INI_BEGIN()
- PHP_INI_ENTRY_EX("define_syslog_variables", "0", PHP_INI_ALL, NULL, php_ini_boolean_displayer_cb)
- PHP_INI_ENTRY_EX("highlight.bg", HL_BG_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
PHP_INI_ENTRY_EX("highlight.comment", HL_COMMENT_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
PHP_INI_ENTRY_EX("highlight.default", HL_DEFAULT_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
PHP_INI_ENTRY_EX("highlight.html", HL_HTML_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
PHP_INI_ENTRY_EX("highlight.keyword", HL_KEYWORD_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
PHP_INI_ENTRY_EX("highlight.string", HL_STRING_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
- STD_PHP_INI_BOOLEAN("allow_call_time_pass_reference", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, allow_call_time_pass_reference, zend_compiler_globals, compiler_globals)
STD_PHP_INI_BOOLEAN("asp_tags", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, asp_tags, zend_compiler_globals, compiler_globals)
STD_PHP_INI_ENTRY_EX("display_errors", "1", PHP_INI_ALL, OnUpdateDisplayErrors, display_errors, php_core_globals, core_globals, display_errors_mode)
STD_PHP_INI_BOOLEAN("display_startup_errors", "0", PHP_INI_ALL, OnUpdateBool, display_startup_errors, php_core_globals, core_globals)
@@ -469,26 +502,13 @@ PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("ignore_repeated_source", "0", PHP_INI_ALL, OnUpdateBool, ignore_repeated_source, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("report_memleaks", "1", PHP_INI_ALL, OnUpdateBool, report_memleaks, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("report_zend_debug", "1", PHP_INI_ALL, OnUpdateBool, report_zend_debug, php_core_globals, core_globals)
- STD_PHP_INI_BOOLEAN("magic_quotes_gpc", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, magic_quotes_gpc, php_core_globals, core_globals)
- STD_PHP_INI_BOOLEAN("magic_quotes_runtime", "0", PHP_INI_ALL, OnUpdateBool, magic_quotes_runtime, php_core_globals, core_globals)
- STD_PHP_INI_BOOLEAN("magic_quotes_sybase", "0", PHP_INI_ALL, OnUpdateBool, magic_quotes_sybase, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("output_buffering", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateLong, output_buffering, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("output_handler", NULL, PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateString, output_handler, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("register_argc_argv", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, register_argc_argv, php_core_globals, core_globals)
- STD_PHP_INI_BOOLEAN("register_globals", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, register_globals, php_core_globals, core_globals)
- STD_PHP_INI_BOOLEAN("register_long_arrays", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, register_long_arrays, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("auto_globals_jit", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, auto_globals_jit, php_core_globals, core_globals)
-#if PHP_SAFE_MODE
- STD_PHP_INI_BOOLEAN("safe_mode", "1", PHP_INI_SYSTEM, OnUpdateBool, safe_mode, php_core_globals, core_globals)
-#else
- STD_PHP_INI_BOOLEAN("safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, safe_mode, php_core_globals, core_globals)
-#endif
- STD_PHP_INI_ENTRY("safe_mode_include_dir", NULL, PHP_INI_SYSTEM, OnUpdateString, safe_mode_include_dir, php_core_globals, core_globals)
- STD_PHP_INI_BOOLEAN("safe_mode_gid", "0", PHP_INI_SYSTEM, OnUpdateBool, safe_mode_gid, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("short_open_tag", DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals)
STD_PHP_INI_BOOLEAN("sql.safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, sql_safe_mode, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("track_errors", "0", PHP_INI_ALL, OnUpdateBool, track_errors, php_core_globals, core_globals)
- STD_PHP_INI_BOOLEAN("y2k_compliance", "1", PHP_INI_ALL, OnUpdateBool, y2k_compliance, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateString, unserialize_callback_func, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("serialize_precision", "17", PHP_INI_ALL, OnUpdateLongGEZero, serialize_precision, php_core_globals, core_globals)
@@ -505,7 +525,6 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("include_path", PHP_INCLUDE_PATH, PHP_INI_ALL, OnUpdateStringUnempty, include_path, php_core_globals, core_globals)
PHP_INI_ENTRY("max_execution_time", "30", PHP_INI_ALL, OnUpdateTimeout)
STD_PHP_INI_ENTRY("open_basedir", NULL, PHP_INI_ALL, OnUpdateBaseDir, open_basedir, php_core_globals, core_globals)
- STD_PHP_INI_ENTRY("safe_mode_exec_dir", PHP_SAFE_MODE_EXEC_DIR, PHP_INI_SYSTEM, OnUpdateString, safe_mode_exec_dir, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("file_uploads", "1", PHP_INI_SYSTEM, OnUpdateBool, file_uploads, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("upload_max_filesize", "2M", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, upload_max_filesize, php_core_globals, core_globals)
@@ -533,10 +552,11 @@ PHP_INI_BEGIN()
PHP_INI_ENTRY("mail.force_extra_parameters",NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnChangeMailForceExtra)
PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL)
PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL)
- PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM, NULL)
+ PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL)
STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("enable_post_data_reading", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, enable_post_data_reading, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("always_populate_raw_post_data", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, always_populate_raw_post_data, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("realpath_cache_size", "16K", PHP_INI_SYSTEM, OnUpdateLong, realpath_cache_size_limit, virtual_cwd_globals, cwd_globals)
@@ -571,6 +591,14 @@ static int php_during_module_shutdown(void)
}
/* }}} */
+/* {{{ php_get_module_initialized
+ */
+PHPAPI int php_get_module_initialized(void)
+{
+ return module_initialized;
+}
+/* }}} */
+
/* {{{ php_log_err
*/
PHPAPI void php_log_err(char *log_message TSRMLS_DC)
@@ -613,7 +641,7 @@ PHPAPI void php_log_err(char *log_message TSRMLS_DC)
#ifdef PHP_WIN32
php_flock(fd, 2);
#endif
- write(fd, tmp, len);
+ php_ignore_value(write(fd, tmp, len));
efree(tmp);
efree(error_time_str);
close(fd);
@@ -625,7 +653,7 @@ PHPAPI void php_log_err(char *log_message TSRMLS_DC)
/* Otherwise fall back to the default logging location, if we have one */
if (sapi_module.log_message) {
- sapi_module.log_message(log_message);
+ sapi_module.log_message(log_message TSRMLS_CC);
}
PG(in_error_log) = 0;
}
@@ -671,9 +699,9 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c
char *docref_target = "", *docref_root = "";
char *p;
int buffer_len = 0;
- char *space = "";
- char *class_name = "";
- char *function;
+ const char *space = "";
+ const char *class_name = "";
+ const char *function;
int origin_len;
char *origin;
char *message;
@@ -681,8 +709,9 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c
/* get error text into buffer and escape for html if necessary */
buffer_len = vspprintf(&buffer, 0, format, args);
+
if (PG(html_errors)) {
- int len;
+ size_t len;
char *replace = php_escape_html_entities(buffer, buffer_len, &len, 0, ENT_COMPAT, NULL TSRMLS_CC);
efree(buffer);
buffer = replace;
@@ -698,7 +727,7 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c
EG(current_execute_data)->opline &&
EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL
) {
- switch (EG(current_execute_data)->opline->op2.u.constant.value.lval) {
+ switch (EG(current_execute_data)->opline->extended_value) {
case ZEND_EVAL:
function = "eval";
is_function = 1;
@@ -740,7 +769,7 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c
}
if (PG(html_errors)) {
- int len;
+ size_t len;
char *replace = php_escape_html_entities(origin, origin_len, &len, 0, ENT_COMPAT, NULL TSRMLS_CC);
efree(origin);
origin = replace;
@@ -767,10 +796,10 @@ PHPAPI void php_verror(const char *docref, const char *params, int type, const c
}
/* we have a docref for a function AND
- * - we show erroes in html mode OR
- * - the user wants to see the links anyway
+ * - we show errors in html mode AND
+ * - the user wants to see the links
*/
- if (docref && is_function && (PG(html_errors) || strlen(PG(docref_root)))) {
+ if (docref && is_function && PG(html_errors) && strlen(PG(docref_root))) {
if (strncmp(docref, "http://", 7)) {
/* We don't have 'http://' so we use docref_root */
@@ -932,6 +961,9 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
/* store the error if it has changed */
if (display) {
+#ifdef ZEND_SIGNALS
+ HANDLE_BLOCK_INTERRUPTIONS();
+#endif
if (PG(last_error_message)) {
free(PG(last_error_message));
PG(last_error_message) = NULL;
@@ -940,6 +972,9 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
free(PG(last_error_file));
PG(last_error_file) = NULL;
}
+#ifdef ZEND_SIGNALS
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+#endif
if (!error_filename) {
error_filename = "Unknown";
}
@@ -1032,14 +1067,7 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
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 {
@@ -1047,8 +1075,8 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
char *append_string = INI_STR("error_append_string");
if (PG(html_errors)) {
- if (type == E_ERROR) {
- int len;
+ if (type == E_ERROR || type == E_PARSE) {
+ size_t len;
char *buf = php_escape_html_entities(buffer, buffer_len, &len, 0, ENT_COMPAT, NULL TSRMLS_CC);
php_printf("%s<br />\n<b>%s</b>: %s in <b>%s</b> on line <b>%d</b><br />\n%s", STR_PRINT(prepend_string), error_type_str, buf, error_filename, error_lineno, STR_PRINT(append_string));
efree(buf);
@@ -1061,7 +1089,7 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
PG(display_errors) == PHP_DISPLAY_ERRORS_STDERR
) {
#ifdef PHP_WIN32
- fprintf(stderr, "%s: %s in %s on line%d\n", error_type_str, buffer, error_filename, error_lineno);
+ fprintf(stderr, "%s: %s in %s on line %d\n", error_type_str, buffer, error_filename, error_lineno);
fflush(stderr);
#else
fprintf(stderr, "%s: %s in %s on line %d\n", error_type_str, buffer, error_filename, error_lineno);
@@ -1114,11 +1142,13 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
sapi_header_line ctr = {0};
ctr.line = "HTTP/1.0 500 Internal Server Error";
- ctr.line_len = strlen(ctr.line);
+ ctr.line_len = sizeof("HTTP/1.0 500 Internal Server Error") - 1;
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
}
/* the parser would return 1 (failure), we can bail out nicely */
- if (type != E_PARSE) {
+ if (type == E_PARSE) {
+ CG(parse_error) = 0;
+ } else {
/* restore memory limit */
zend_set_memory_limit(PG(memory_limit));
efree(buffer);
@@ -1152,6 +1182,69 @@ static void php_error_cb(int type, const char *error_filename, const uint error_
}
/* }}} */
+/* {{{ php_get_current_user
+ */
+PHPAPI char *php_get_current_user(TSRMLS_D)
+{
+ struct stat *pstat;
+
+ if (SG(request_info).current_user) {
+ return SG(request_info).current_user;
+ }
+
+ /* FIXME: I need to have this somehow handled if
+ USE_SAPI is defined, because cgi will also be
+ interfaced in USE_SAPI */
+
+ pstat = sapi_get_stat(TSRMLS_C);
+
+ if (!pstat) {
+ return "";
+ } else {
+#ifdef PHP_WIN32
+ char name[256];
+ DWORD len = sizeof(name)-1;
+
+ if (!GetUserName(name, &len)) {
+ return "";
+ }
+ name[len] = '\0';
+ SG(request_info).current_user_length = len;
+ SG(request_info).current_user = estrndup(name, len);
+ return SG(request_info).current_user;
+#else
+ struct passwd *pwd;
+#if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ struct passwd _pw;
+ struct passwd *retpwptr = NULL;
+ int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+ char *pwbuf;
+
+ if (pwbuflen < 1) {
+ return "";
+ }
+ pwbuf = emalloc(pwbuflen);
+ if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) {
+ efree(pwbuf);
+ return "";
+ }
+ pwd = &_pw;
+#else
+ if ((pwd=getpwuid(pstat->st_uid))==NULL) {
+ return "";
+ }
+#endif
+ SG(request_info).current_user_length = strlen(pwd->pw_name);
+ SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length);
+#if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ efree(pwbuf);
+#endif
+ return SG(request_info).current_user;
+#endif
+ }
+}
+/* }}} */
+
/* {{{ proto bool set_time_limit(int seconds)
Sets the maximum time a script can run */
PHP_FUNCTION(set_time_limit)
@@ -1160,11 +1253,6 @@ PHP_FUNCTION(set_time_limit)
char *new_timeout_str;
int new_timeout_strlen;
- if (PG(safe_mode)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot set time limit in safe mode");
- RETURN_FALSE;
- }
-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &new_timeout) == FAILURE) {
return;
}
@@ -1184,7 +1272,7 @@ PHP_FUNCTION(set_time_limit)
*/
static FILE *php_fopen_wrapper_for_zend(const char *filename, char **opened_path TSRMLS_DC)
{
- return php_stream_open_wrapper_as_file((char *)filename, "rb", ENFORCE_SAFE_MODE|USE_PATH|IGNORE_URL_WIN|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE, opened_path);
+ return php_stream_open_wrapper_as_file((char *)filename, "rb", USE_PATH|IGNORE_URL_WIN|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE, opened_path);
}
/* }}} */
@@ -1213,7 +1301,7 @@ static size_t php_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
static int php_stream_open_for_zend(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */
{
- return php_stream_open_for_zend_ex(filename, handle, ENFORCE_SAFE_MODE|USE_PATH|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+ return php_stream_open_for_zend_ex(filename, handle, USE_PATH|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
}
/* }}} */
@@ -1283,7 +1371,7 @@ static int php_get_configuration_directive_for_zend(const char *name, uint name_
/* {{{ php_message_handler_for_zend
*/
-static void php_message_handler_for_zend(long message, void *data TSRMLS_DC)
+static void php_message_handler_for_zend(long message, const void *data TSRMLS_DC)
{
switch (message) {
case ZMSG_FAILED_INCLUDE_FOPEN:
@@ -1377,8 +1465,12 @@ void php_on_timeout(int seconds TSRMLS_DC)
*/
static void sigchld_handler(int apar)
{
+ int errno_save = errno;
+
while (waitpid(-1, NULL, WNOHANG) > 0);
signal(SIGCHLD, sigchld_handler);
+
+ errno = errno_save;
}
/* }}} */
#endif
@@ -1420,6 +1512,10 @@ int php_request_startup(TSRMLS_D)
{
int retval = SUCCESS;
+#ifdef HAVE_DTRACE
+ DTRACE_REQUEST_STARTUP(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), SAFE_FILENAME(SG(request_info).request_method));
+#endif /* HAVE_DTRACE */
+
#ifdef PHP_WIN32
PG(com_initialized) = 0;
#endif
@@ -1443,14 +1539,18 @@ int php_request_startup(TSRMLS_D)
zend_activate(TSRMLS_C);
sapi_activate(TSRMLS_C);
+#ifdef ZEND_SIGNALS
+ zend_signal_activate(TSRMLS_C);
+#endif
+
if (PG(max_input_time) == -1) {
zend_set_timeout(EG(timeout_seconds), 1);
} else {
zend_set_timeout(PG(max_input_time), 1);
}
- /* Disable realpath cache if safe_mode or open_basedir are set */
- if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
+ /* Disable realpath cache if an open_basedir is set */
+ if (PG(open_basedir) && *PG(open_basedir)) {
CWDG(realpath_cache_size_limit) = 0;
}
@@ -1459,15 +1559,16 @@ int php_request_startup(TSRMLS_D)
}
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_STRING(oh, PG(output_handler), 1);
+ php_output_start_user(oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC);
+ 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 TSRMLS_CC);
} else if (PG(implicit_flush)) {
- php_start_implicit_flush(TSRMLS_C);
+ php_output_set_implicit_flush(1 TSRMLS_CC);
}
/* We turn this off in php_execute_script() */
@@ -1503,7 +1604,6 @@ int php_request_startup(TSRMLS_D)
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);
}
@@ -1547,6 +1647,7 @@ void php_request_shutdown_for_exec(void *dummy)
/* used to close fd's in the 3..255 range here, but it's problematic
*/
shutdown_memory_manager(1, 1 TSRMLS_CC);
+ zend_interned_strings_restore(TSRMLS_C);
}
/* }}} */
@@ -1566,6 +1667,10 @@ void php_request_shutdown_for_hook(void *dummy)
}
zend_try {
+ zend_unset_timeout(TSRMLS_C);
+ } zend_end_try();
+
+ zend_try {
int i;
for (i = 0; i < NUM_TRACK_VARS; i++) {
@@ -1589,9 +1694,13 @@ void php_request_shutdown_for_hook(void *dummy)
shutdown_memory_manager(CG(unclean_shutdown), 0 TSRMLS_CC);
} zend_end_try();
+ zend_interned_strings_restore(TSRMLS_C);
+
+#ifdef ZEND_SIGNALS
zend_try {
- zend_unset_timeout(TSRMLS_C);
+ zend_signal_deactivate(TSRMLS_C);
} zend_end_try();
+#endif
}
/* }}} */
@@ -1626,16 +1735,23 @@ void php_request_shutdown(void *dummy)
/* 3. Flush all output buffers */
zend_try {
zend_bool send_buffer = SG(request_info).headers_only ? 0 : 1;
+
if (CG(unclean_shutdown) && PG(last_error_type) == E_ERROR &&
- OG(ob_nesting_level) && !OG(active_ob_buffer).chunk_size && PG(memory_limit) < zend_memory_usage(1 TSRMLS_CC)) {
+ (size_t)PG(memory_limit) < zend_memory_usage(1 TSRMLS_CC)
+ ) {
send_buffer = 0;
}
- php_end_ob_buffers(send_buffer TSRMLS_CC);
+
+ if (!send_buffer) {
+ php_output_discard_all(TSRMLS_C);
+ } else {
+ php_output_end_all(TSRMLS_C);
+ }
} zend_end_try();
- /* 4. Send the set HTTP headers (note: This must be done AFTER php_end_ob_buffers() !!) */
+ /* 4. Reset max_execution_time (no longer executing php code after response sent) */
zend_try {
- sapi_send_headers(TSRMLS_C);
+ zend_unset_timeout(TSRMLS_C);
} zend_end_try();
/* 5. Call all extensions RSHUTDOWN functions */
@@ -1644,7 +1760,12 @@ void php_request_shutdown(void *dummy)
php_free_shutdown_functions(TSRMLS_C);
}
- /* 6. Destroy super-globals */
+ /* 6. Shutdown output layer (send the set HTTP headers, cleanup output handlers, etc.) */
+ zend_try {
+ php_output_deactivate(TSRMLS_C);
+ } zend_end_try();
+
+ /* 7. Destroy super-globals */
zend_try {
int i;
@@ -1655,7 +1776,7 @@ void php_request_shutdown(void *dummy)
}
} zend_end_try();
- /* 6.5 free last error information */
+ /* 7.5 free last error information */
if (PG(last_error_message)) {
free(PG(last_error_message));
PG(last_error_message) = NULL;
@@ -1687,6 +1808,7 @@ void php_request_shutdown(void *dummy)
zend_try {
shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0 TSRMLS_CC);
} zend_end_try();
+ zend_interned_strings_restore(TSRMLS_C);
/* 12. Reset max_execution_time */
zend_try {
@@ -1699,6 +1821,10 @@ void php_request_shutdown(void *dummy)
PG(com_initialized) = 0;
}
#endif
+
+#ifdef HAVE_DTRACE
+ DTRACE_REQUEST_SHUTDOWN(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), SAFE_FILENAME(SG(request_info).request_method));
+#endif /* HAVE_DTRACE */
}
/* }}} */
@@ -1716,12 +1842,12 @@ PHPAPI void php_com_initialize(TSRMLS_D)
}
/* }}} */
-/* {{{ 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 TSRMLS_CC);
}
/* }}} */
@@ -1753,6 +1879,9 @@ static void core_globals_dtor(php_core_globals *core_globals TSRMLS_DC)
if (core_globals->disable_classes) {
free(core_globals->disable_classes);
}
+ if (core_globals->php_binary) {
+ free(core_globals->php_binary);
+ }
php_shutdown_ticks(TSRMLS_C);
}
@@ -1784,7 +1913,7 @@ int php_register_extensions(zend_module_entry **ptr, int count TSRMLS_DC)
}
/* }}} */
-#if defined(PHP_WIN32) && defined(_MSC_VER) && (_MSC_VER >= 1400)
+#if defined(PHP_WIN32) && _MSC_VER >= 1400
static _invalid_parameter_handler old_invalid_parameter_handler;
void dummy_invalid_parameter_handler(
@@ -1824,7 +1953,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
{
zend_utility_functions zuf;
zend_utility_values zuv;
- int module_number=0; /* for REGISTER_INI_ENTRIES() */
+ int retval = SUCCESS, module_number=0; /* for REGISTER_INI_ENTRIES() */
char *php_os;
zend_module_entry *module;
#ifdef ZTS
@@ -1832,19 +1961,14 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
void ***tsrm_ls;
php_core_globals *core_globals;
#endif
+
#if defined(PHP_WIN32) || (defined(NETWARE) && defined(USE_WINSOCK))
WORD wVersionRequested = MAKEWORD(2, 0);
WSADATA wsaData;
#endif
#ifdef PHP_WIN32
- DWORD dwVersion = GetVersion();
- /* Get build numbers for Windows NT or Win95 */
- if (dwVersion < 0x80000000){
- php_os="WINNT";
- } else {
- php_os="WIN32";
- }
-#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ php_os = "WINNT";
+#if _MSC_VER >= 1400
old_invalid_parameter_handler =
_set_invalid_parameter_handler(dummy_invalid_parameter_handler);
if (old_invalid_parameter_handler != NULL) {
@@ -1881,7 +2005,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
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;
@@ -1991,11 +2115,6 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
REGISTER_MAIN_LONG_CONSTANT("PHP_MAXPATHLEN", MAXPATHLEN, 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);
-#ifdef ZEND_MULTIBYTE
- REGISTER_MAIN_LONG_CONSTANT("ZEND_MULTIBYTE", 1, CONST_PERSISTENT | CONST_CS);
-#else
- REGISTER_MAIN_LONG_CONSTANT("ZEND_MULTIBYTE", 0, CONST_PERSISTENT | CONST_CS);
-#endif
#ifdef PHP_WIN32
REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_MAJOR", EG(windows_version_info).dwMajorVersion, CONST_PERSISTENT | CONST_CS);
@@ -2011,6 +2130,13 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_WORKSTATION", VER_NT_WORKSTATION, CONST_PERSISTENT | CONST_CS);
#endif
+ php_binary_init(TSRMLS_C);
+ if (PG(php_binary)) {
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINARY", PG(php_binary), strlen(PG(php_binary)), CONST_PERSISTENT | CONST_CS);
+ } else {
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINARY", "", 0, CONST_PERSISTENT | CONST_CS);
+ }
+
php_output_register_constants(TSRMLS_C);
php_rfc1867_register_constants(TSRMLS_C);
@@ -2027,8 +2153,8 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
/* Register Zend ini entries */
zend_register_standard_ini_entries(TSRMLS_C);
- /* Disable realpath cache if safe_mode or open_basedir are set */
- if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
+ /* Disable realpath cache if an open_basedir is set */
+ if (PG(open_basedir) && *PG(open_basedir)) {
CWDG(realpath_cache_size_limit) = 0;
}
@@ -2076,6 +2202,8 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
/* start Zend extensions */
zend_startup_extensions();
+ zend_collect_module_handlers(TSRMLS_C);
+
/* register additional functions */
if (sapi_module.additional_functions) {
if (zend_hash_find(&module_registry, "standard", sizeof("standard"), (void**)&module)==SUCCESS) {
@@ -2098,7 +2226,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
#ifdef PHP_WIN32
/* Disable incompatible functions for the running platform */
- if (php_win32_disable_functions() == FAILURE) {
+ if (php_win32_disable_functions(TSRMLS_C) == FAILURE) {
php_printf("Unable to disable unsupported functions\n");
return FAILURE;
}
@@ -2111,41 +2239,74 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
module_initialized = 1;
/* Check for deprecated directives */
- /* NOTE: If you add anything here, remember to add it also in Makefile.global! */
+ /* NOTE: If you add anything here, remember to add it to Makefile.global! */
{
- static const char *directives[] = {
- "define_syslog_variables",
- "register_globals",
- "register_long_arrays",
- "safe_mode",
- "magic_quotes_gpc",
- "magic_quotes_runtime",
- "magic_quotes_sybase",
- NULL
+ struct {
+ const long error_level;
+ const char *phrase;
+ const char *directives[16]; /* Remember to change this if the number of directives change */
+ } directives[2] = {
+ {
+ E_DEPRECATED,
+ "Directive '%s' is deprecated in PHP 5.3 and greater",
+ {
+ NULL
+ }
+ },
+ {
+ E_CORE_ERROR,
+ "Directive '%s' is no longer available in PHP",
+ {
+ "allow_call_time_pass_reference",
+ "define_syslog_variables",
+ "highlight.bg",
+ "magic_quotes_gpc",
+ "magic_quotes_runtime",
+ "magic_quotes_sybase",
+ "register_globals",
+ "register_long_arrays",
+ "safe_mode",
+ "safe_mode_gid",
+ "safe_mode_include_dir",
+ "safe_mode_exec_dir",
+ "safe_mode_allowed_env_vars",
+ "safe_mode_protected_env_vars",
+ "zend.ze1_compatibility_mode",
+ NULL
+ }
+ }
};
- const char **p = directives;
- long val;
- while (*p) {
- if (cfg_get_long((char*)*p, &val) == SUCCESS && val) {
- zend_error(E_DEPRECATED, "Directive '%s' is deprecated in PHP 5.3 and greater", *p);
- }
- ++p;
- }
+ unsigned int i;
+
+ zend_try {
+ /* 2 = Count of deprecation structs */
+ for (i = 0; i < 2; i++) {
+ const char **p = directives[i].directives;
- /* This is not too nice, but since its the only one theres no need for extra stuff here */
- if (cfg_get_long("zend.ze1_compatibility_mode", &val) == SUCCESS && val) {
- zend_error(E_CORE_ERROR, "zend.ze1_compatibility_mode is no longer supported in PHP 5.3 and greater");
- }
+ while(*p) {
+ long value;
+
+ if (cfg_get_long((char*)*p, &value) == SUCCESS && value) {
+ zend_error(directives[i].error_level, directives[i].phrase, *p);
+ }
+
+ ++p;
+ }
+ }
+ } zend_catch {
+ retval = FAILURE;
+ } zend_end_try();
}
sapi_deactivate(TSRMLS_C);
module_startup = 0;
shutdown_memory_manager(1, 0 TSRMLS_CC);
+ zend_interned_strings_snapshot(TSRMLS_C);
/* we're done */
- return SUCCESS;
+ return retval;
}
/* }}} */
@@ -2205,17 +2366,22 @@ void php_module_shutdown(TSRMLS_D)
#ifndef ZTS
zend_ini_shutdown(TSRMLS_C);
shutdown_memory_manager(CG(unclean_shutdown), 1 TSRMLS_CC);
- core_globals_dtor(&core_globals TSRMLS_CC);
- gc_globals_dtor(TSRMLS_C);
#else
zend_ini_global_shutdown(TSRMLS_C);
- ts_free_id(core_globals_id);
#endif
+ php_output_shutdown();
php_shutdown_temporary_directory();
module_initialized = 0;
+#ifndef ZTS
+ core_globals_dtor(&core_globals TSRMLS_CC);
+ gc_globals_dtor(TSRMLS_C);
+#else
+ ts_free_id(core_globals_id);
+#endif
+
#if defined(PHP_WIN32) && defined(_MSC_VER) && (_MSC_VER >= 1400)
if (old_invalid_parameter_handler == NULL) {
_set_invalid_parameter_handler(old_invalid_parameter_handler);
@@ -2265,7 +2431,7 @@ PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC)
/* this looks nasty to me */
old_cwd_fd = open(".", 0);
#else
- VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1);
+ php_ignore_value(VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1));
#endif
VCWD_CHDIR_FILE(primary_file->filename);
}
@@ -2324,7 +2490,7 @@ PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC)
}
#else
if (old_cwd[0] != '\0') {
- VCWD_CHDIR(old_cwd);
+ php_ignore_value(VCWD_CHDIR(old_cwd));
}
free_alloca(old_cwd, use_heap);
#endif
@@ -2354,14 +2520,14 @@ PHPAPI int php_execute_simple_script(zend_file_handle *primary_file, zval **ret
PG(during_request_startup) = 0;
if (primary_file->filename && !(SG(options) & SAPI_OPTION_NO_CHDIR)) {
- VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1);
+ php_ignore_value(VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1));
VCWD_CHDIR_FILE(primary_file->filename);
}
zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, ret, 1, primary_file);
} zend_end_try();
if (old_cwd[0] != '\0') {
- VCWD_CHDIR(old_cwd);
+ php_ignore_value(VCWD_CHDIR(old_cwd));
}
free_alloca(old_cwd, use_heap);
@@ -2376,7 +2542,7 @@ PHPAPI void php_handle_aborted_connection(void)
TSRMLS_FETCH();
PG(connection_status) = PHP_CONNECTION_ABORTED;
- php_output_set_status(0 TSRMLS_CC);
+ php_output_set_status(PHP_OUTPUT_DISABLED TSRMLS_CC);
if (!PG(ignore_user_abort)) {
zend_bailout();
diff --git a/main/network.c b/main/network.c
index 56b08978a7..6c7031f983 100644
--- a/main/network.c
+++ b/main/network.c
@@ -148,7 +148,7 @@ static const char *php_gai_strerror(int code)
/* {{{ php_network_freeaddresses
*/
-static void php_network_freeaddresses(struct sockaddr **sal)
+PHPAPI void php_network_freeaddresses(struct sockaddr **sal)
{
struct sockaddr **sap;
@@ -163,7 +163,7 @@ static void php_network_freeaddresses(struct sockaddr **sal)
/* {{{ php_network_getaddresses
* Returns number of addresses, 0 for none/error
*/
-static int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, char **error_string TSRMLS_DC)
+PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, char **error_string TSRMLS_DC)
{
struct sockaddr **sap;
int n;
@@ -1058,7 +1058,7 @@ PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short p
reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
- stream = php_stream_xport_create(res, reslen, ENFORCE_SAFE_MODE | REPORT_ERRORS,
+ stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
efree(res);
diff --git a/main/output.c b/main/output.c
index 5a7ed7b1a2..e100057ca9 100644
--- a/main/output.c
+++ b/main/output.c
@@ -15,39 +15,83 @@
| 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"
+ZEND_DECLARE_MODULE_GLOBALS(output);
-/* output functions */
-static int php_b_body_write(const char *str, uint str_length TSRMLS_DC);
+const char php_output_default_handler_name[sizeof("default output handler")] = "default output handler";
+const char php_output_devnull_handler_name[sizeof("null output handler")] = "null output handler";
-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(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC);
+static inline php_output_handler_status_t 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 flags 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);
-/* {{{ php_default_output_func */
-PHPAPI int php_default_output_func(const char *str, uint str_len TSRMLS_DC)
+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)
+{
+ memset(G, 0, sizeof(*G));
+}
+/* }}} */
+
+/* {{{ stderr/stdout writer if not PHP_OUTPUT_ACTIVATED */
+static int php_output_stdout(const char *str, size_t str_len)
+{
+ fwrite(str, 1, str_len, stdout);
+ return str_len;
+}
+static int php_output_stderr(const char *str, size_t str_len)
{
fwrite(str, 1, str_len, stderr);
/* See http://support.microsoft.com/kb/190351 */
@@ -56,706 +100,1199 @@ PHPAPI int php_default_output_func(const char *str, uint str_len TSRMLS_DC)
#endif
return str_len;
}
+static int (*php_output_direct)(const char *str, size_t str_len) = php_output_stderr;
/* }}} */
-/* {{{ php_output_init_globals */
-static void php_output_init_globals(php_output_globals *output_globals_p TSRMLS_DC)
+/* {{{ void php_output_header(TSRMLS_D) */
+static void php_output_header(TSRMLS_D)
{
- 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;
+ if (!SG(headers_sent)) {
+ if (!OG(output_start_filename)) {
+ 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
+ }
+ if (!php_header(TSRMLS_C)) {
+ OG(flags) |= PHP_OUTPUT_DISABLED;
+ }
+ }
}
/* }}} */
-/* {{{ php_output_startup
- * Start output layer */
+/* {{{ void php_output_startup(void)
+ * Set up module globals and initalize the conflict and reverse conflict hash tables */
PHPAPI void php_output_startup(void)
{
+ 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);
+ php_output_direct = php_output_stdout;
+}
+/* }}} */
+
+/* {{{ void php_output_shutdown(void)
+ * Destroy module globals and the conflict and reverse conflict hash tables */
+PHPAPI void php_output_shutdown(void)
+{
+ php_output_direct = php_output_stderr;
+ zend_hash_destroy(&php_output_handler_aliases);
+ zend_hash_destroy(&php_output_handler_conflicts);
+ zend_hash_destroy(&php_output_handler_reverse_conflicts);
+}
+/* }}} */
+
+/* {{{ 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);
+ memset((*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)], 0, sizeof(zend_output_globals));
#else
- php_output_init_globals(&output_globals TSRMLS_CC);
+ memset(&output_globals, 0, sizeof(zend_output_globals));
#endif
+
+ zend_stack_init(&OG(handlers));
+ OG(flags) |= PHP_OUTPUT_ACTIVATED;
+
+ 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;
+
+ php_output_header(TSRMLS_C);
+
+ OG(flags) ^= PHP_OUTPUT_ACTIVATED;
+ OG(active) = NULL;
+ OG(running) = NULL;
+
+ /* release all output handlers */
+ if (OG(handlers).elements) {
+ while (SUCCESS == zend_stack_top(&OG(handlers), (void *) &handler)) {
+ php_output_handler_free(handler TSRMLS_CC);
+ zend_stack_del_top(&OG(handlers));
+ }
+ zend_stack_destroy(&OG(handlers));
+ }
+
}
/* }}} */
-/* {{{ php_output_register_constants */
-void php_output_register_constants(TSRMLS_D)
+/* {{{ 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_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);
+ 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_FLUSHABLE", PHP_OUTPUT_HANDLER_FLUSHABLE, 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 TSRMLS_DC)
+ * Used by SAPIs to disable output */
+PHPAPI void php_output_set_status(int status TSRMLS_DC)
{
- OG(disable_output) = !status;
+ OG(flags) = (OG(flags) & ~0xf) | (status & 0xf);
}
/* }}} */
-/* {{{ php_body_write
- * Write body part */
-PHPAPI int php_body_write(const char *str, uint str_length TSRMLS_DC)
+/* {{{ int php_output_get_status(TSRMLS_C)
+ * Get output control status */
+PHPAPI int php_output_get_status(TSRMLS_D)
{
- return OG(php_body_write)(str, str_length TSRMLS_CC);
+ return (
+ OG(flags)
+ | (OG(active) ? PHP_OUTPUT_ACTIVE : 0)
+ | (OG(running)? PHP_OUTPUT_LOCKED : 0)
+ ) & 0xff;
}
/* }}} */
-/* {{{ php_header_write
- * 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 TSRMLS_DC)
+ * 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);
}
+ if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
+ return sapi_module.ub_write(str, len TSRMLS_CC);
+ }
+ return php_output_direct(str, len);
}
/* }}} */
-/* {{{ 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 TSRMLS_DC)
+ * Buffered write */
+PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC)
{
- uint initial_size, block_size;
+ if (OG(flags) & PHP_OUTPUT_DISABLED) {
+ return 0;
+ }
+ if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
+ php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len TSRMLS_CC);
+ return (int) len;
+ }
+ return php_output_direct(str, len);
+}
+/* }}} */
- 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;
+/* {{{ SUCCESS|FAILURE php_output_flush(TSRMLS_D)
+ * Flush the most recent output handlers buffer */
+PHPAPI int php_output_flush(TSRMLS_D)
+{
+ php_output_context context;
+
+ if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_FLUSHABLE)) {
+ 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 TSRMLS_CC);
+ zend_stack_push(&OG(handlers), &OG(active), sizeof(php_output_handler *));
}
- 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;
+ php_output_context_dtor(&context);
+ return SUCCESS;
}
- if (chunk_size > 0) {
- if (chunk_size==1) {
- chunk_size = 4096;
- }
- initial_size = (chunk_size*3/2);
- block_size = chunk_size/2;
- } else {
- initial_size = 40*1024;
- block_size = 10*1024;
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ void php_output_flush_all(TSRMLS_C)
+ * Flush all output buffers subsequently */
+PHPAPI void php_output_flush_all(TSRMLS_D)
+{
+ if (OG(active)) {
+ php_output_op(PHP_OUTPUT_HANDLER_FLUSH, NULL, 0 TSRMLS_CC);
}
- 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)
+/* {{{ SUCCESS|FAILURE php_output_clean(TSRMLS_D)
+ * Cleans the most recent output handlers buffer if the handler is cleanable */
+PHPAPI int php_output_clean(TSRMLS_D)
{
- zval *output_handler;
- int result;
+ php_output_context context;
- 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) && (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;
}
/* }}} */
-/* {{{ 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)
+/* {{{ void php_output_clean_all(TSRMLS_D)
+ * Cleans all output handler buffers, without regard whether the handler is cleanable */
+PHPAPI void php_output_clean_all(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;
+ php_output_context context;
- 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;
+ 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 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);
- fclose(fp);
- }
-#endif
+/* {{{ SUCCESS|FAILURE php_output_end(TSRMLS_D)
+ * 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(PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
- 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;
-
- 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;
- }
+/* {{{ void php_output_end_all(TSRMLS_D)
+ * 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(PHP_OUTPUT_POP_FORCE TSRMLS_CC));
+}
+/* }}} */
- ALLOC_INIT_ZVAL(orig_buffer);
- ZVAL_STRINGL(orig_buffer, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
+/* {{{ SUCCESS|FAILURE php_output_discard(TSRMLS_D)
+ * 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(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
- ALLOC_INIT_ZVAL(z_status);
- ZVAL_LONG(z_status, status);
+/* {{{ void php_output_discard_all(TSRMLS_D)
+ * 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(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_FORCE TSRMLS_CC);
+ }
+}
+/* }}} */
- params[0] = &orig_buffer;
- params[1] = &z_status;
- OG(ob_lock) = 1;
+/* {{{ int php_output_get_level(TSRMLS_D)
+ * 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;
+}
+/* }}} */
- 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);
- }
- zval_ptr_dtor(&orig_buffer);
- zval_ptr_dtor(&z_status);
+/* {{{ SUCCESS|FAILURE php_output_get_contents(zval *z TSRMLS_DC)
+ * 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 (!final_buffer) {
- final_buffer = OG(active_ob_buffer).buffer;
- final_buffer_length = OG(active_ob_buffer).text_length;
+/* {{{ SUCCESS|FAILURE php_output_get_length(zval *z TSRMLS_DC)
+ * 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 (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;
- }
- }
+/* {{{ php_output_handler* php_output_get_active_handler(TSRMLS_D)
+ * Get active output handler */
+PHPAPI php_output_handler* php_output_get_active_handler(TSRMLS_D)
+{
+ return OG(active);
+}
+/* }}} */
- to_be_destroyed_buffer = OG(active_ob_buffer).buffer;
- to_be_destroyed_handler_name = OG(active_ob_buffer).handler_name;
- 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_handler_start_default(TSRMLS_D)
+ * Start a "default output handler" */
+PHPAPI int php_output_start_default(TSRMLS_D)
+{
+ php_output_handler *handler;
- 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;
- }
+ handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC);
+ if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
+ return SUCCESS;
}
- 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));
- }
- }
- OG(ob_nesting_level)--;
+ php_output_handler_free(&handler TSRMLS_CC);
+ return FAILURE;
+}
+/* }}} */
- 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);
- }
+/* {{{ SUCCESS|FAILURE php_output_handler_start_devnull(TSRMLS_D)
+ * Start a "null output handler" */
+PHPAPI int php_output_start_devnull(TSRMLS_D)
+{
+ php_output_handler *handler;
- 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)++;
+ handler = php_output_handler_create_internal(ZEND_STRL(php_output_devnull_handler_name), php_output_handler_devnull_func, PHP_OUTPUT_HANDLER_DEFAULT_SIZE, 0 TSRMLS_CC);
+ if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
+ return SUCCESS;
}
+ php_output_handler_free(&handler TSRMLS_CC);
+ return FAILURE;
+}
+/* }}} */
- if (alternate_buffer) {
- zval_ptr_dtor(&alternate_buffer);
- }
+/* {{{ SUCCESS|FAILURE php_output_start_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
+ * 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 (status & PHP_OUTPUT_HANDLER_END) {
- efree(to_be_destroyed_handler_name);
- }
- if (!just_flush) {
- efree(to_be_destroyed_buffer);
+ if (output_handler) {
+ handler = php_output_handler_create_user(output_handler, chunk_size, flags TSRMLS_CC);
} 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(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
}
- if (to_be_destroyed_handled_output[1]) {
- efree(to_be_destroyed_handled_output[1]);
+ if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
+ return SUCCESS;
}
+ php_output_handler_free(&handler TSRMLS_CC);
+ 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(zval *name, php_output_handler_func_t handler, size_t chunk_size, int flags TSRMLS_DC)
+ * Start an internal output handler that does not have to maintain a non-global state */
+PHPAPI int php_output_start_internal(const char *name, size_t name_len, 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, name_len, php_output_handler_compat_func, chunk_size, flags TSRMLS_CC);
+ php_output_handler_set_context(handler, output_handler, NULL TSRMLS_CC);
+ if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
+ return SUCCESS;
}
+ php_output_handler_free(&handler TSRMLS_CC);
+ 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 TSRMLS_DC)
+ * 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;
-}
-/* }}} */
+ char *handler_name = NULL, *error = NULL;
+ php_output_handler *handler = NULL;
+ php_output_handler_alias_ctor_t *alias = NULL;
+ php_output_handler_user_func_t *user = NULL;
+
+ switch (Z_TYPE_P(output_handler)) {
+ case IS_NULL:
+ handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
+ break;
+ case IS_STRING:
+ if (Z_STRLEN_P(output_handler) && (alias = php_output_handler_alias(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler) TSRMLS_CC))) {
+ handler = (*alias)(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler), chunk_size, flags TSRMLS_CC);
+ break;
+ }
+ default:
+ user = ecalloc(1, sizeof(php_output_handler_user_func_t));
+ if (SUCCESS == zend_fcall_info_init(output_handler, 0, &user->fci, &user->fcc, &handler_name, &error TSRMLS_CC)) {
+ handler = php_output_handler_init(handler_name, strlen(handler_name), chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_USER TSRMLS_CC);
+ Z_ADDREF_P(output_handler);
+ user->zoh = output_handler;
+ handler->func.user = user;
+ } else {
+ efree(user);
+ }
+ if (error) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "%s", error);
+ efree(error);
+ }
+ if (handler_name) {
+ efree(handler_name);
+ }
+ }
-/* {{{ php_end_implicit_flush
- */
-PHPAPI void php_end_implicit_flush(TSRMLS_D)
-{
- OG(implicit_flush) = 0;
+ return handler;
}
/* }}} */
-/* {{{ char *php_get_output_start_filename(TSRMLS_D)
- * Return filename start output something */
-PHPAPI char *php_get_output_start_filename(TSRMLS_D)
+/* {{{ 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)
+ * Create an internal output handler that can maintain a non-global state */
+PHPAPI php_output_handler *php_output_handler_create_internal(const char *name, size_t name_len, php_output_handler_context_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
{
- return OG(output_start_filename);
+ php_output_handler *handler;
+
+ handler = php_output_handler_init(name, name_len, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_INTERNAL TSRMLS_CC);
+ handler->func.internal = output_handler;
+
+ return handler;
}
/* }}} */
-/* {{{ char *php_get_output_start_lineno(TSRMLS_D)
- * Return line number start output something */
-PHPAPI int php_get_output_start_lineno(TSRMLS_D)
+/* {{{ void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) 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)
{
- return OG(output_start_lineno);
+ if (handler->dtor && handler->opaq) {
+ handler->dtor(handler->opaq TSRMLS_CC);
+ }
+ handler->dtor = dtor;
+ handler->opaq = opaq;
}
/* }}} */
-/* {{{ 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)
+/* {{{ SUCCESS|FAILURE php_output_handler_start(php_output_handler *handler TSRMLS_DC)
+ * 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)
{
- if (OG(ob_nesting_level) == 0 || OG(active_ob_buffer).internal_output_handler || strcmp(OG(active_ob_buffer).handler_name, OB_DEFAULT_HANDLER_NAME)) {
- php_start_ob_buffer(NULL, buffer_size, erase TSRMLS_CC);
- }
+ HashPosition pos;
+ HashTable *rconflicts;
+ php_output_handler_conflict_check_t *conflict;
- 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) {
- efree(OG(active_ob_buffer).handler_name);
+ if (php_output_lock_error(PHP_OUTPUT_HANDLER_START TSRMLS_CC) || !handler) {
+ return FAILURE;
}
- OG(active_ob_buffer).handler_name = estrdup(handler_name);
- OG(active_ob_buffer).erase = erase;
+ if (SUCCESS == zend_hash_find(&php_output_handler_conflicts, handler->name, handler->name_len+1, (void *) &conflict)) {
+ if (SUCCESS != (*conflict)(handler->name, handler->name_len TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, handler->name, handler->name_len+1, (void *) &rconflicts)) {
+ for (zend_hash_internal_pointer_reset_ex(rconflicts, &pos);
+ zend_hash_get_current_data_ex(rconflicts, (void *) &conflict, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(rconflicts, &pos)
+ ) {
+ if (SUCCESS != (*conflict)(handler->name, handler->name_len 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(zval *name TSRMLS_DC)
+ * Check whether a certain output handler is in use */
+PHPAPI int php_output_handler_started(const char *name, size_t name_len TSRMLS_DC)
{
- uint new_len = OG(active_ob_buffer).text_length + text_length;
+ php_output_handler ***handlers;
+ int i, count = php_output_get_level(TSRMLS_C);
- 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;
- }
+ if (count) {
+ handlers = (php_output_handler ***) zend_stack_base(&OG(handlers));
- OG(active_ob_buffer).buffer = (char *) erealloc(OG(active_ob_buffer).buffer, buf_size+1);
- OG(active_ob_buffer).size = buf_size;
+ for (i = 0; i < count; ++i) {
+ if (name_len == (*(handlers[i]))->name_len && !memcmp((*(handlers[i]))->name, name, name_len)) {
+ return 1;
+ }
+ }
}
- 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(zval *handler_new, zval *handler_old TSRMLS_DC)
+ * 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(const char *handler_new, size_t handler_new_len, const char *handler_set, size_t handler_set_len 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, handler_set_len TSRMLS_CC)) {
+ if (handler_new_len != handler_set_len || memcmp(handler_new, handler_set, handler_set_len)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", handler_new, handler_set);
+ } else {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' cannot be used twice", handler_new);
+ }
return 1;
}
return 0;
}
/* }}} */
-/* {{{ php_ob_init_named
- */
-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)
+/* {{{ SUCCESS|FAILURE php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
+ * Register a conflict checking function on MINIT */
+PHPAPI int php_output_handler_conflict_register(const char *name, size_t name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC)
+{
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register an output handler conflict outside of MINIT");
+ return FAILURE;
+ }
+ return zend_hash_update(&php_output_handler_conflicts, name, name_len+1, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
+ * Register a reverse conflict checking function on MINIT */
+PHPAPI int php_output_handler_reverse_conflict_register(const char *name, size_t name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC)
{
- php_ob_buffer tmp_buf;
+ HashTable rev, *rev_ptr = NULL;
- if (output_handler && !zend_is_callable(output_handler, 0, NULL TSRMLS_CC)) {
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register a reverse output handler conflict outside of MINIT");
return FAILURE;
}
- tmp_buf.block_size = block_size;
- tmp_buf.size = initial_size;
- tmp_buf.buffer = (char *) emalloc(initial_size+1);
- tmp_buf.text_length = 0;
- tmp_buf.output_handler = output_handler;
- tmp_buf.chunk_size = chunk_size;
- tmp_buf.status = 0;
- tmp_buf.internal_output_handler = NULL;
- tmp_buf.internal_output_handler_buffer = NULL;
- tmp_buf.internal_output_handler_buffer_size = 0;
- tmp_buf.handler_name = estrdup(handler_name&&handler_name[0]?handler_name:OB_DEFAULT_HANDLER_NAME);
- tmp_buf.erase = erase;
-
- if (OG(ob_nesting_level)>0) {
-#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
- if (!strncmp(handler_name, "ob_gzhandler", sizeof("ob_gzhandler")) && php_ob_gzhandler_check(TSRMLS_C)) {
+ if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, name, name_len+1, (void *) &rev_ptr)) {
+ return zend_hash_next_index_insert(rev_ptr, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
+ } else {
+ 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_hash_update(&php_output_handler_reverse_conflicts, name, name_len+1, &rev, sizeof(HashTable), NULL)) {
+ zend_hash_destroy(&rev);
+ return FAILURE;
}
- zend_stack_push(&OG(ob_buffers), &OG(active_ob_buffer), sizeof(php_ob_buffer));
+ return SUCCESS;
}
- OG(ob_nesting_level)++;
- OG(active_ob_buffer) = tmp_buf;
- 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_alias_ctor_t php_output_handler_alias(zval *name TSRMLS_DC)
+ * Get an internal output handler for a user handler if it exists */
+PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(const char *name, size_t name_len TSRMLS_DC)
{
- zval *output_handler;
+ php_output_handler_alias_ctor_t *func = NULL;
- 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;
+ zend_hash_find(&php_output_handler_aliases, name, name_len+1, (void *) &func);
+ return func;
}
/* }}} */
-/* {{{ 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)
+/* {{{ SUCCESS|FAILURE php_output_handler_alias_register(zval *name, php_output_handler_alias_ctor_t func TSRMLS_DC)
+ * Registers an internal output handler as alias for a user handler */
+PHPAPI int php_output_handler_alias_register(const char *name, size_t name_len, php_output_handler_alias_ctor_t func TSRMLS_DC)
{
- int result = FAILURE, handler_len, len;
- char *handler_name, *next_handler_name;
- HashPosition pos;
- zval **tmp;
- zval *handler_zval;
-
- if (output_handler && output_handler->type == IS_STRING) {
- handler_name = Z_STRVAL_P(output_handler);
- handler_len = Z_STRLEN_P(output_handler);
-
- result = SUCCESS;
- if (handler_len && handler_name[0] != '\0') {
- while ((next_handler_name=strchr(handler_name, ',')) != NULL) {
- len = next_handler_name-handler_name;
- next_handler_name = estrndup(handler_name, len);
- handler_zval = php_ob_handler_from_string(next_handler_name, len TSRMLS_CC);
- result = php_ob_init_named(initial_size, block_size, next_handler_name, handler_zval, chunk_size, erase TSRMLS_CC);
- if (result != SUCCESS) {
- zval_dtor(handler_zval);
- FREE_ZVAL(handler_zval);
- }
- handler_name += len+1;
- handler_len -= len+1;
- efree(next_handler_name);
- }
- }
- if (result == SUCCESS) {
- handler_zval = php_ob_handler_from_string(handler_name, handler_len TSRMLS_CC);
- result = php_ob_init_named(initial_size, block_size, 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) {
- /* do we have array(object,method) */
- if (zend_is_callable(output_handler, 0, &handler_name TSRMLS_CC)) {
- SEPARATE_ZVAL(&output_handler);
- Z_ADDREF_P(output_handler);
- result = php_ob_init_named(initial_size, block_size, handler_name, output_handler, chunk_size, erase TSRMLS_CC);
- efree(handler_name);
- } else {
- efree(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);
- }
- }
- } else if (output_handler && output_handler->type == IS_OBJECT) {
- /* do we have callable object */
- if (zend_is_callable(output_handler, 0, &handler_name TSRMLS_CC)) {
- SEPARATE_ZVAL(&output_handler);
- Z_ADDREF_P(output_handler);
- result = php_ob_init_named(initial_size, block_size, handler_name, output_handler, chunk_size, erase TSRMLS_CC);
- efree(handler_name);
- } else {
- efree(handler_name);
- 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);
- result = FAILURE;
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register an output handler alias outside of MINIT");
+ return FAILURE;
+ }
+ return zend_hash_update(&php_output_handler_aliases, name, name_len+1, &func, sizeof(php_output_handler_alias_ctor_t *), NULL);
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_hook(php_output_handler_hook_t type, void *arg TSMRLS_DC)
+ * Output handler hook for output handler functions to check/modify the current handlers abilities */
+PHPAPI int php_output_handler_hook(php_output_handler_hook_t 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_GET_LEVEL:
+ *(int *) arg = OG(running)->level;
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE:
+ OG(running)->flags &= ~(PHP_OUTPUT_HANDLER_REMOVABLE|PHP_OUTPUT_HANDLER_CLEANABLE);
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_DISABLE:
+ OG(running)->flags |= PHP_OUTPUT_HANDLER_DISABLED;
+ return SUCCESS;
+ default:
+ break;
}
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
+ * Destroy an output handler */
+PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
+{
+ STR_FREE(handler->name);
+ STR_FREE(handler->buffer.data);
+ if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
+ zval_ptr_dtor(&handler->func.user->zoh);
+ efree(handler->func.user);
+ }
+ if (handler->dtor && handler->opaq) {
+ handler->dtor(handler->opaq TSRMLS_CC);
+ }
+ memset(handler, 0, sizeof(*handler));
+}
+/* }}} */
+
+/* {{{ void php_output_handler_free(php_output_handler **handler TSMRLS_DC)
+ * Destroy and free an output handler */
+PHPAPI void php_output_handler_free(php_output_handler **h TSRMLS_DC)
+{
+ if (*h) {
+ php_output_handler_dtor(*h TSRMLS_CC);
+ efree(*h);
+ *h = NULL;
+ }
+}
+/* }}} */
+
+/* void php_output_set_implicit_flush(int enabled TSRMLS_DC)
+ * Enable or disable implicit flush */
+PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC)
+{
+ if (flush) {
+ OG(flags) |= PHP_OUTPUT_IMPLICITFLUSH;
} else {
- result = php_ob_init_named(initial_size, block_size, OB_DEFAULT_HANDLER_NAME, NULL, chunk_size, erase TSRMLS_CC);
+ OG(flags) &= ~PHP_OUTPUT_IMPLICITFLUSH;
}
- return result;
}
/* }}} */
-/* {{{ php_ob_list_each
- */
-static int php_ob_list_each(php_ob_buffer *ob_buffer, zval *ob_handler_array)
+/* {{{ char *php_output_get_start_filename(TSRMLS_D)
+ * Get the file name where output has started */
+PHPAPI const char *php_output_get_start_filename(TSRMLS_D)
{
- add_next_index_string(ob_handler_array, ob_buffer->handler_name, 1);
- return 0;
+ return OG(output_start_filename);
}
/* }}} */
-/* {{{ 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)
+/* {{{ int php_output_get_start_lineno(TSRMLS_D)
+ * Get the line number where output has started */
+PHPAPI int php_output_get_start_lineno(TSRMLS_D)
{
- if (!strcmp(ob_buffer->handler_name, *handler_name)) {
- *handler_name = NULL;
+ 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)
+{
+ /* if there's no ob active, ob has been stopped */
+ if (op && OG(active) && OG(running)) {
+ /* fatal error */
+ php_output_deactivate(TSRMLS_C);
+ 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)
{
- char *tmp = handler_name;
+ if (!context) {
+ context = emalloc(sizeof(php_output_context));
+ }
- if (OG(ob_nesting_level)) {
- if (!strcmp(OG(active_ob_buffer).handler_name, handler_name)) {
- return 1;
+ memset(context, 0, sizeof(php_output_context));
+ TSRMLS_SET_CTX(context->tsrm_ls);
+ context->op = op;
+
+ return context;
+}
+/* }}} */
+
+/* {{{ 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)
+{
+ int op = context->op;
+ php_output_context_dtor(context);
+ memset(context, 0, sizeof(php_output_context));
+ context->op = op;
+}
+/* }}} */
+
+/* {{{ static void php_output_context_feed(php_output_context *context, char *, size_t, size_t)
+ * Feed output contexts input buffer */
+static inline void php_output_context_feed(php_output_context *context, char *data, size_t size, size_t used, zend_bool free)
+{
+ if (context->in.free && context->in.data) {
+ efree(context->in.data);
+ }
+ context->in.data = data;
+ context->in.used = used;
+ context->in.free = free;
+ context->in.size = size;
+}
+/* }}} */
+
+/* {{{ 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.free = 0;
+ context->out.size = 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.free = 0;
+ context->in.size = 0;
+}
+/* }}} */
+
+/* {{{ 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);
+ context->in.data = NULL;
+ }
+ if (context->out.free && context->out.data) {
+ efree(context->out.data);
+ context->out.data = NULL;
+ }
+}
+/* }}} */
+
+/* {{{ static php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags TSRMLS_DC)
+ * Allocates and initializes a php_output_handler structure */
+static inline php_output_handler *php_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC)
+{
+ php_output_handler *handler;
+
+ handler = ecalloc(1, sizeof(php_output_handler));
+ handler->name = estrndup(name, name_len);
+ handler->name_len = name_len;
+ 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;
+}
+/* }}} */
+
+/* {{{ 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)
+{
+ if (buf->used) {
+ OG(flags) |= PHP_OUTPUT_WRITTEN;
+ /* 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 - (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);
+ handler->buffer.size += grow_max;
}
- 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);
+ memcpy(handler->buffer.data + handler->buffer.used, buf->data, buf->used);
+ handler->buffer.used += buf->used;
+
+ /* chunked buffering */
+ if (handler->size && (handler->buffer.used >= handler->size)) {
+ /* store away errors and/or any intermediate output */
+ return OG(running) ? 1 : 0;
}
}
- return tmp ? 0 : 1;
+ return 1;
}
/* }}} */
-/* {{{ php_ob_append
- */
-static inline void php_ob_append(const char *text, uint text_length TSRMLS_DC)
+/* {{{ static php_output_handler_status_t 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 php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
{
- char *target;
- int original_ob_text_length;
+ php_output_handler_status_t status;
+ int original_op = context->op;
+ PHP_OUTPUT_TSRMLS(context);
+
+#if PHP_OUTPUT_DEBUG
+ fprintf(stderr, ">>> op(%d, "
+ "handler=%p, "
+ "name=%s, "
+ "flags=%d, "
+ "buffer.data=%s, "
+ "buffer.used=%zu, "
+ "buffer.size=%zu, "
+ "in.data=%s, "
+ "in.used=%zu)\n",
+ context->op,
+ handler,
+ handler->name,
+ handler->flags,
+ handler->buffer.used?handler->buffer.data:"",
+ handler->buffer.used,
+ handler->buffer.size,
+ context->in.used?context->in.data:"",
+ context->in.used
+ );
+#endif
- original_ob_text_length=OG(active_ob_buffer).text_length;
+ if (php_output_lock_error(context->op TSRMLS_CC)) {
+ /* fatal error */
+ return PHP_OUTPUT_HANDLER_FAILURE;
+ }
+
+ /* storable? */
+ if (php_output_handler_append(handler, &context->in TSRMLS_CC) && !context->op) {
+ context->op = original_op;
+ return PHP_OUTPUT_HANDLER_NO_DATA;
+ } else {
+ /* need to start? */
+ if (!(handler->flags & PHP_OUTPUT_HANDLER_STARTED)) {
+ context->op |= PHP_OUTPUT_HANDLER_START;
+ }
- 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;
+ OG(running) = handler;
+ if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
+ zval *retval = NULL, *ob_data, *ob_mode;
+
+ MAKE_STD_ZVAL(ob_data);
+ ZVAL_STRINGL(ob_data, handler->buffer.data, handler->buffer.used, 1);
+ MAKE_STD_ZVAL(ob_mode);
+ ZVAL_LONG(ob_mode, (long) context->op);
+ zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 2, &ob_data, &ob_mode);
+
+#define PHP_OUTPUT_USER_SUCCESS(retval) (retval && !(Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)==0))
+ if (SUCCESS == zend_fcall_info_call(&handler->func.user->fci, &handler->func.user->fcc, &retval, NULL TSRMLS_CC) && PHP_OUTPUT_USER_SUCCESS(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 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) {
+ zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 0);
+ zval_ptr_dtor(&ob_data);
+ zval_ptr_dtor(&ob_mode);
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
- php_end_ob_buffer(1, 1 TSRMLS_CC);
- return;
+ } else {
+
+ php_output_context_feed(context, handler->buffer.data, handler->buffer.size, handler->buffer.used, 0);
+
+ if (SUCCESS == handler->func.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;
+ }
+ }
+ handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
+ OG(running) = NULL;
}
+
+ switch (status) {
+ case PHP_OUTPUT_HANDLER_FAILURE:
+ /* disable this handler */
+ handler->flags |= PHP_OUTPUT_HANDLER_DISABLED;
+ /* discard any output */
+ if (context->out.data && context->out.free) {
+ efree(context->out.data);
+ }
+ /* 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_NO_DATA:
+ /* handler ate all */
+ php_output_context_reset(context);
+ /* no break */
+ case PHP_OUTPUT_HANDLER_SUCCESS:
+ /* no more buffered data */
+ handler->buffer.used = 0;
+ handler->flags |= PHP_OUTPUT_HANDLER_PROCESSED;
+ break;
+ }
+
+ context->op = original_op;
+ return status;
}
/* }}} */
-#if 0
-static inline void php_ob_prepend(const char *text, uint text_length)
+
+/* {{{ 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)
{
- char *p, *start;
- TSRMLS_FETCH();
+ php_output_context context;
+ php_output_handler **active;
+ int obh_cnt;
+
+ if (php_output_lock_error(op TSRMLS_CC)) {
+ return;
+ }
- php_ob_allocate(text_length TSRMLS_CC);
+ php_output_context_init(&context, op 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);
+ /*
+ * 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;
- while (--p>=start) {
- p[text_length] = *p;
+ 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;
}
- memcpy(OG(ob_buffer), text, text_length);
- OG(ob_buffer)[OG(active_ob_buffer).text_length]=0;
-}
+
+ if (context.out.data && context.out.used) {
+ php_output_header(TSRMLS_C);
+
+ if (!(OG(flags) & PHP_OUTPUT_DISABLED)) {
+#if PHP_OUTPUT_DEBUG
+ fprintf(stderr, "::: sapi_write('%s', %zu)\n", context.out.data, context.out.used);
#endif
+ sapi_module.ub_write(context.out.data, context.out.used TSRMLS_CC);
-/* {{{ php_ob_get_buffer
- * Return the current output buffer */
-PHPAPI int php_ob_get_buffer(zval *p TSRMLS_DC)
-{
- if (OG(ob_nesting_level)==0) {
- return FAILURE;
+ if (OG(flags) & PHP_OUTPUT_IMPLICITFLUSH) {
+ sapi_flush(TSRMLS_C);
+ }
+
+ OG(flags) |= PHP_OUTPUT_SENT;
+ }
}
- ZVAL_STRINGL(p, OG(active_ob_buffer).buffer, OG(active_ob_buffer).text_length, 1);
- return SUCCESS;
+ 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 was_disabled;
+ php_output_handler_status_t status;
+ 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_FAILURE;
+ } else {
+ 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
- */
+/* {{{ 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_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;
+}
+/* }}} */
-/* buffered output function */
-static int php_b_body_write(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)
{
- php_ob_append(str, str_length TSRMLS_CC);
- return str_length;
+ php_output_handler *handler = *(php_output_handler **) h;
+ zval *array = (zval *) z;
+
+ add_next_index_stringl(array, handler->name, handler->name_len, 1);
+ 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_status(void *h, void *z)
+ * Status callback for the stack apply function */
+static int php_output_stack_apply_status(void *h, void *z)
{
- int result;
+ php_output_handler *handler = *(php_output_handler **) h;
+ zval *array = (zval *) z;
- if (OG(disable_output)) {
- return 0;
- }
+ add_next_index_zval(array, php_output_handler_status(handler, NULL));
- result = OG(php_header_write)(str, str_length TSRMLS_CC);
+ return 0;
+}
- if (OG(implicit_flush)) {
- sapi_flush(TSRMLS_C);
+/* {{{ 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)
+{
+ if (!entry) {
+ MAKE_STD_ZVAL(entry);
+ array_init(entry);
}
- return result;
+ add_assoc_stringl(entry, "name", handler->name, handler->name_len, 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;
}
/* }}} */
-/* {{{ php_ub_body_write
- */
-PHPAPI int php_ub_body_write(const char *str, uint str_length TSRMLS_DC)
+/* {{{ static int php_output_stack_pop(int flags TSRMLS_DC)
+ * Pops an output handler off the stack */
+static inline int php_output_stack_pop(int flags TSRMLS_DC)
{
- int result = 0;
+ php_output_context context;
+ php_output_handler **current, *orphan = OG(active);
- if (SG(request_info).headers_only) {
- if(SG(headers_sent)) {
- return 0;
+ if (!orphan) {
+ if (!(flags & PHP_OUTPUT_POP_SILENT)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer. No buffer to %s", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send");
+ }
+ return 0;
+ } else if (!(flags & PHP_OUTPUT_POP_FORCE) && !(orphan->flags & PHP_OUTPUT_HANDLER_REMOVABLE)) {
+ if (!(flags & PHP_OUTPUT_POP_SILENT)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer of %s (%d)", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", orphan->name, orphan->level);
+ }
+ 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 (flags & PHP_OUTPUT_POP_DISCARD) {
+ context.op |= PHP_OUTPUT_HANDLER_CLEAN;
+ orphan->buffer.used = 0;
+ }
+ 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 *) &current)) {
+ 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 && !(flags & PHP_OUTPUT_POP_DISCARD)) {
+ php_output_write(context.out.data, context.out.used TSRMLS_CC);
}
- OG(php_body_write) = php_ub_body_write_no_header;
- result = php_ub_body_write_no_header(str, str_length TSRMLS_CC);
- }
+ /* destroy the handler (after write!) */
+ php_output_handler_free(&orphan TSRMLS_CC);
+ php_output_context_dtor(&context);
- return result;
+ return 1;
+ }
}
/* }}} */
-/* {{{ 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)
+/* {{{ static SUCCESS|FAILURE php_output_handler_compat_func(void *ctx, php_output_context *)
+ * 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)
{
- zval *elem;
+ php_output_handler_func_t func = *(php_output_handler_func_t *) handler_context;
+ PHP_OUTPUT_TSRMLS(output_context);
- MAKE_STD_ZVAL(elem);
- array_init(elem);
+ if (func) {
+ char *out_str = NULL;
+ uint out_len = 0;
- 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);
- } else {
- add_assoc_long(elem, "type", PHP_OUTPUT_HANDLER_USER);
+ func(output_context->in.data, output_context->in.used, &out_str, &out_len, output_context->op TSRMLS_CC);
+
+ if (out_str) {
+ output_context->out.data = out_str;
+ output_context->out.used = out_len;
+ output_context->out.free = 1;
+ } else {
+ php_output_context_pass(output_context);
+ }
+
+ return SUCCESS;
}
- 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 FAILURE;
+}
+/* }}} */
+
+/* {{{ static SUCCESS|FAILURE php_output_handler_default_func(void *ctx, php_output_context *)
+ * Default output handler */
+static int php_output_handler_default_func(void **handler_context, php_output_context *output_context)
+{
+ php_output_context_pass(output_context);
+ return SUCCESS;
+}
+/* }}} */
+/* {{{ static SUCCESS|FAILURE php_output_handler_devnull_func(void *ctx, php_output_context *)
+ * Null output handler */
+static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context)
+{
return SUCCESS;
}
/* }}} */
@@ -764,15 +1301,15 @@ static int php_ob_buffer_status(php_ob_buffer *ob_buffer, zval *result)
* 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;
+ long flags = PHP_OUTPUT_HANDLER_STDFLAGS;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/lb", &output_handler, &chunk_size, &erase) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/ll", &output_handler, &chunk_size, &flags) == FAILURE) {
return;
}
@@ -780,7 +1317,8 @@ PHP_FUNCTION(ob_start)
chunk_size = 0;
}
- if (php_start_ob_buffer(output_handler, chunk_size, erase TSRMLS_CC) == FAILURE) {
+ if (php_output_start_user(output_handler, chunk_size, flags TSRMLS_CC) == FAILURE) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to create buffer");
RETURN_FALSE;
}
RETURN_TRUE;
@@ -795,17 +1333,15 @@ PHP_FUNCTION(ob_flush)
return;
}
- 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;
}
- if (!OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) {
- php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer %s", OG(active_ob_buffer).handler_name);
+ if (SUCCESS != php_output_flush(TSRMLS_C)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer of %s (%d)", OG(active)->name, OG(active)->level);
RETURN_FALSE;
}
-
- php_end_ob_buffer(1, 1 TSRMLS_CC);
RETURN_TRUE;
}
/* }}} */
@@ -818,17 +1354,15 @@ PHP_FUNCTION(ob_clean)
return;
}
- 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(TSRMLS_C)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
RETURN_FALSE;
}
-
- php_end_ob_buffer(0, 1 TSRMLS_CC);
RETURN_TRUE;
}
/* }}} */
@@ -841,18 +1375,12 @@ PHP_FUNCTION(ob_end_flush)
return;
}
- 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);
- RETURN_FALSE;
- }
-
- php_end_ob_buffer(1, 0 TSRMLS_CC);
- RETURN_TRUE;
+ RETURN_BOOL(SUCCESS == php_output_end(TSRMLS_C));
}
/* }}} */
@@ -864,18 +1392,12 @@ PHP_FUNCTION(ob_end_clean)
return;
}
- 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);
- RETURN_FALSE;
- }
-
- php_end_ob_buffer(0, 0 TSRMLS_CC);
- RETURN_TRUE;
+ RETURN_BOOL(SUCCESS == php_output_discard(TSRMLS_C));
}
/* }}} */
@@ -887,23 +1409,14 @@ PHP_FUNCTION(ob_get_flush)
return;
}
- if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (!OG(ob_nesting_level)) {
+ if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
- zval_dtor(return_value);
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);
- zval_dtor(return_value);
- RETURN_FALSE;
+ if (SUCCESS != php_output_end(TSRMLS_C)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
}
-
- php_end_ob_buffer(1, 0 TSRMLS_CC);
}
/* }}} */
@@ -915,22 +1428,18 @@ PHP_FUNCTION(ob_get_clean)
return;
}
- if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
+ if(!OG(active)) {
RETURN_FALSE;
}
- if (!OG(ob_nesting_level)) {
+ if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
- zval_dtor(return_value);
- 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);
- zval_dtor(return_value);
RETURN_FALSE;
}
- php_end_ob_buffer(0, 0 TSRMLS_CC);
+ if (SUCCESS != php_output_discard(TSRMLS_C)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
+ }
}
/* }}} */
@@ -942,7 +1451,7 @@ PHP_FUNCTION(ob_get_contents)
return;
}
- if (php_ob_get_buffer(return_value TSRMLS_CC) == FAILURE) {
+ if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
}
@@ -956,7 +1465,7 @@ PHP_FUNCTION(ob_get_level)
return;
}
- RETURN_LONG(OG(ob_nesting_level));
+ RETURN_LONG(php_output_get_level(TSRMLS_C));
}
/* }}} */
@@ -968,7 +1477,7 @@ PHP_FUNCTION(ob_get_length)
return;
}
- if (php_ob_get_length(return_value TSRMLS_CC) == FAILURE) {
+ if (php_output_get_length(return_value TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
}
@@ -984,12 +1493,11 @@ PHP_FUNCTION(ob_list_handlers)
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);
+ if (!OG(active)) {
+ return;
}
+
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_list, return_value);
}
/* }}} */
@@ -1005,23 +1513,14 @@ PHP_FUNCTION(ob_get_status)
array_init(return_value);
+ if (!OG(active)) {
+ return;
+ }
+
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_string(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);
}
}
/* }}} */
@@ -1036,11 +1535,7 @@ PHP_FUNCTION(ob_implicit_flush)
return;
}
- if (flag) {
- php_start_implicit_flush(TSRMLS_C);
- } else {
- php_end_implicit_flush(TSRMLS_C);
- }
+ php_output_set_implicit_flush(flag TSRMLS_CC);
}
/* }}} */
diff --git a/main/php.h b/main/php.h
index 497439d17a..2a93118ac6 100644
--- a/main/php.h
+++ b/main/php.h
@@ -26,7 +26,7 @@
#include <dmalloc.h>
#endif
-#define PHP_API_VERSION 20090626
+#define PHP_API_VERSION 20100412
#define PHP_HAVE_STREAMS
#define YYDEBUG 0
@@ -60,6 +60,7 @@
# else
# define PHPAPI
# endif
+
# define THREAD_LS
# define PHP_DIR_SEPARATOR '/'
# define PHP_EOL "\n"
@@ -142,7 +143,11 @@ END_EXTERN_C()
#endif
#ifndef HAVE_SOCKLEN_T
+# if PHP_WIN32
+typedef int socklen_t;
+# else
typedef unsigned int socklen_t;
+# endif
#endif
#define CREATE_MUTEX(a, b)
@@ -177,7 +182,6 @@ typedef unsigned int socklen_t;
#endif
#include "zend_hash.h"
-#include "php3_compat.h"
#include "zend_alloc.h"
#include "zend_stack.h"
@@ -192,8 +196,6 @@ typedef unsigned int socklen_t;
# endif
#endif
-#include "safe_mode.h"
-
#ifndef HAVE_STRERROR
char *strerror(int);
#endif
@@ -253,6 +255,11 @@ END_EXTERN_C()
# endif
#endif
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define php_ignore_value(x) (({ __typeof__ (x) __x = (x); (void) __x; }))
+#else
+# define php_ignore_value(x) ((void) (x))
+#endif
/* global variables */
#if !defined(PHP_WIN32)
@@ -274,6 +281,7 @@ void phperror(char *error);
PHPAPI int php_write(void *buf, uint size TSRMLS_DC);
PHPAPI int php_printf(const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 1,
2);
+PHPAPI int php_get_module_initialized(void);
PHPAPI void php_log_err(char *log_message TSRMLS_DC);
int Debug(char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 1, 2);
int cfgparse(void);
@@ -327,6 +335,7 @@ PHPAPI int php_register_internal_extensions(TSRMLS_D);
PHPAPI int php_mergesort(void *base, size_t nmemb, register size_t size, int (*cmp)(const void *, const void * TSRMLS_DC) TSRMLS_DC);
PHPAPI void php_register_pre_request_shutdown(void (*func)(void *), void *userdata);
PHPAPI void php_com_initialize(TSRMLS_D);
+PHPAPI char *php_get_current_user(TSRMLS_D);
END_EXTERN_C()
/* PHP-named Zend macro wrappers */
@@ -382,20 +391,7 @@ END_EXTERN_C()
/* 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))
+
#include "php_streams.h"
#include "php_memory_streams.h"
diff --git a/main/php3_compat.h b/main/php3_compat.h
deleted file mode 100644
index 3b9e710385..0000000000
--- a/main/php3_compat.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2012 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id$ */
-
-#ifndef PHP3_COMPAT_H
-#define PHP3_COMPAT_H
-
-typedef zval pval;
-
-#define pval_copy_constructor zval_copy_ctor
-#define pval_destructor zval_dtor
-
-#define _php3_hash_init zend_hash_init
-#define _php3_hash_destroy zend_hash_destroy
-
-#define _php3_hash_clean zend_hash_clean
-
-#define _php3_hash_add_or_update zend_hash_add_or_update
-#define _php3_hash_add zend_hash_add
-#define _php3_hash_update zend_hash_update
-
-#define _php3_hash_quick_add_or_update zend_hash_quick_add_or_update
-#define _php3_hash_quick_add zend_hash_quick_add
-#define _php3_hash_quick_update zend_hash_quick_update
-
-#define _php3_hash_index_update_or_next_insert zend_hash_index_update_or_next_insert
-#define _php3_hash_index_update zend_hash_index_update
-#define _php3_hash_next_index_insert zend_hash_next_index_insert
-
-#define _php3_hash_pointer_update zend_hash_pointer_update
-
-#define _php3_hash_pointer_index_update_or_next_insert zend_hash_pointer_index_update_or_next_insert
-#define _php3_hash_pointer_index_update zend_hash_pointer_index_update
-#define _php3_hash_next_index_pointer_update zend_hash_next_index_pointer_update
-#define _php3_hash_next_index_pointer_insert zend_hash_next_index_pointer_insert
-
-#define _php3_hash_del_key_or_index zend_hash_del_key_or_index
-#define _php3_hash_del zend_hash_del
-#define _php3_hash_index_del zend_hash_index_del
-
-#define _php3_hash_find zend_hash_find
-#define _php3_hash_quick_find zend_hash_quick_find
-#define _php3_hash_index_find zend_hash_index_find
-
-#define _php3_hash_exists zend_hash_exists
-#define _php3_hash_index_exists zend_hash_index_exists
-#define _php3_hash_is_pointer zend_hash_is_pointer
-#define _php3_hash_index_is_pointer zend_hash_index_is_pointer
-#define _php3_hash_next_free_element zend_hash_next_free_element
-
-#define _php3_hash_move_forward zend_hash_move_forward
-#define _php3_hash_move_backwards zend_hash_move_backwards
-#define _php3_hash_get_current_key zend_hash_get_current_key
-#define _php3_hash_get_current_data zend_hash_get_current_data
-#define _php3_hash_internal_pointer_reset zend_hash_internal_pointer_reset
-#define _php3_hash_internal_pointer_end zend_hash_internal_pointer_end
-
-#define _php3_hash_copy zend_hash_copy
-#define _php3_hash_merge zend_hash_merge
-#define _php3_hash_sort zend_hash_sort
-#define _php3_hash_minmax zend_hash_minmax
-
-#define _php3_hash_num_elements zend_hash_num_elements
-
-#define _php3_hash_apply zend_hash_apply
-#define _php3_hash_apply_with_argument zend_hash_apply_with_argument
-
-
-#define php3_error php_error
-
-#define php3_printf php_printf
-#define _php3_sprintf php_sprintf
-
-
-
-#define php3_module_entry zend_module_entry
-
-#define php3_strndup zend_strndup
-#define php3_str_tolower zend_str_tolower
-#define php3_binary_strcmp zend_binary_strcmp
-
-
-#define php3_list_insert zend_list_insert
-#define php3_list_find zend_list_find
-#define php3_list_delete zend_list_delete
-
-#define php3_plist_insert zend_plist_insert
-#define php3_plist_find zend_plist_find
-#define php3_plist_delete zend_plist_delete
-
-#define zend_print_pval zend_print_zval
-#define zend_print_pval_r zend_print_zval_r
-
-
-#define function_entry zend_function_entry
-
-#define _php3_addslashes php_addslashes
-#define _php3_stripslashes php_stripslashes
-#define php3_dl php_dl
-
-#define getParameters zend_get_parameters
-#define getParametersArray zend_get_parameters_array
-
-#define list_entry zend_rsrc_list_entry
-
-#endif /* PHP3_COMPAT_H */
diff --git a/main/php_content_types.c b/main/php_content_types.c
index 97f8022e17..cca006ad6a 100644
--- a/main/php_content_types.c
+++ b/main/php_content_types.c
@@ -73,9 +73,9 @@ SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader)
*/
int php_startup_sapi_content_types(TSRMLS_D)
{
- sapi_register_default_post_reader(php_default_post_reader);
- sapi_register_treat_data(php_default_treat_data);
- sapi_register_input_filter(php_default_input_filter, NULL);
+ sapi_register_default_post_reader(php_default_post_reader TSRMLS_CC);
+ sapi_register_treat_data(php_default_treat_data TSRMLS_CC);
+ sapi_register_input_filter(php_default_input_filter, NULL TSRMLS_CC);
return SUCCESS;
}
/* }}} */
diff --git a/main/php_globals.h b/main/php_globals.h
index 70f3bbfbbe..514c27869b 100644
--- a/main/php_globals.h
+++ b/main/php_globals.h
@@ -54,19 +54,10 @@ typedef struct _arg_separators {
} arg_separators;
struct _php_core_globals {
- zend_bool magic_quotes_gpc;
- zend_bool magic_quotes_runtime;
- zend_bool magic_quotes_sybase;
-
- zend_bool safe_mode;
-
- zend_bool allow_call_time_pass_reference;
zend_bool implicit_flush;
long output_buffering;
- char *safe_mode_include_dir;
- zend_bool safe_mode_gid;
zend_bool sql_safe_mode;
zend_bool enable_dl;
@@ -75,8 +66,6 @@ struct _php_core_globals {
char *unserialize_callback_func;
long serialize_precision;
- char *safe_mode_exec_dir;
-
long memory_limit;
long max_input_time;
@@ -95,6 +84,7 @@ struct _php_core_globals {
char *include_path;
char *open_basedir;
char *extension_dir;
+ char *php_binary;
char *upload_tmp_dir;
long upload_max_filesize;
@@ -122,13 +112,9 @@ struct _php_core_globals {
zend_bool expose_php;
- zend_bool register_globals;
- zend_bool register_long_arrays;
zend_bool register_argc_argv;
zend_bool auto_globals_jit;
- zend_bool y2k_compliance;
-
char *docref_root;
char *docref_ext;
@@ -143,6 +129,7 @@ struct _php_core_globals {
zend_bool file_uploads;
zend_bool during_request_startup;
zend_bool allow_url_fopen;
+ zend_bool enable_post_data_reading;
zend_bool always_populate_raw_post_data;
zend_bool report_zend_debug;
@@ -159,6 +146,7 @@ struct _php_core_globals {
zend_bool com_initialized;
#endif
long max_input_nesting_level;
+ long max_input_vars;
zend_bool in_user_include;
char *user_ini_filename;
@@ -174,8 +162,6 @@ struct _php_core_globals {
#ifdef PHP_WIN32
zend_bool windows_show_crt_warning;
#endif
-
- long max_input_vars;
};
diff --git a/main/php_ini.c b/main/php_ini.c
index eed600f134..89a3d7e461 100644
--- a/main/php_ini.c
+++ b/main/php_ini.c
@@ -368,7 +368,6 @@ int php_init_config(TSRMLS_D)
char *php_ini_file_name = NULL;
char *php_ini_search_path = NULL;
int php_ini_scanned_path_len;
- int safe_mode_state;
char *open_basedir;
int free_ini_search_path = 0;
zend_file_handle fh;
@@ -384,7 +383,6 @@ int php_init_config(TSRMLS_D)
zend_llist_init(&extension_lists.engine, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
zend_llist_init(&extension_lists.functions, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
- safe_mode_state = PG(safe_mode);
open_basedir = PG(open_basedir);
if (sapi_module.php_ini_path_override) {
@@ -395,7 +393,6 @@ int php_init_config(TSRMLS_D)
int search_path_size;
char *default_location;
char *env_location;
- char *binary_location;
static const char paths_separator[] = { ZEND_PATHS_SEPARATOR, 0 };
#ifdef PHP_WIN32
char *reg_location;
@@ -423,7 +420,11 @@ int php_init_config(TSRMLS_D)
env_location = "";
} else {
size = GetEnvironmentVariableA("PHPRC", phprc_path, size);
- env_location = phprc_path;
+ if (size == 0) {
+ env_location = "";
+ } else {
+ env_location = phprc_path;
+ }
}
}
}
@@ -463,58 +464,18 @@ int php_init_config(TSRMLS_D)
#endif
/* Add cwd (not with CLI) */
- if (strcmp(sapi_module.name, "cli") != 0) {
+ if (!sapi_module.php_ini_ignore_cwd) {
if (*php_ini_search_path) {
strlcat(php_ini_search_path, paths_separator, search_path_size);
}
strlcat(php_ini_search_path, ".", search_path_size);
}
- /* Add binary directory */
-#ifdef PHP_WIN32
- binary_location = (char *) emalloc(MAXPATHLEN);
- if (GetModuleFileName(0, binary_location, MAXPATHLEN) == 0) {
- efree(binary_location);
- binary_location = NULL;
- }
-#else
- if (sapi_module.executable_location) {
- binary_location = (char *)emalloc(MAXPATHLEN);
- if (!strchr(sapi_module.executable_location, '/')) {
- char *envpath, *path;
- int found = 0;
-
- if ((envpath = getenv("PATH")) != NULL) {
- char *search_dir, search_path[MAXPATHLEN];
- char *last = NULL;
-
- path = estrdup(envpath);
- search_dir = php_strtok_r(path, ":", &last);
-
- while (search_dir) {
- snprintf(search_path, MAXPATHLEN, "%s/%s", search_dir, sapi_module.executable_location);
- if (VCWD_REALPATH(search_path, binary_location) && !VCWD_ACCESS(binary_location, X_OK)) {
- found = 1;
- break;
- }
- search_dir = php_strtok_r(NULL, ":", &last);
- }
- efree(path);
- }
- if (!found) {
- efree(binary_location);
- binary_location = NULL;
- }
- } else if (!VCWD_REALPATH(sapi_module.executable_location, binary_location) || VCWD_ACCESS(binary_location, X_OK)) {
- efree(binary_location);
- binary_location = NULL;
- }
- } else {
- binary_location = NULL;
- }
-#endif
- if (binary_location) {
- char *separator_location = strrchr(binary_location, DEFAULT_SLASH);
+ if (PG(php_binary)) {
+ char *separator_location, *binary_location;
+
+ binary_location = estrdup(PG(php_binary));
+ separator_location = strrchr(binary_location, DEFAULT_SLASH);
if (separator_location && separator_location != binary_location) {
*(separator_location) = 0;
@@ -557,7 +518,6 @@ int php_init_config(TSRMLS_D)
#endif
}
- PG(safe_mode) = 0;
PG(open_basedir) = NULL;
/*
@@ -610,7 +570,6 @@ int php_init_config(TSRMLS_D)
efree(php_ini_search_path);
}
- PG(safe_mode) = safe_mode_state;
PG(open_basedir) = open_basedir;
if (fh.handle.fp) {
diff --git a/main/php_logos.c b/main/php_logos.c
index 55204aa816..3689f71e95 100644
--- a/main/php_logos.c
+++ b/main/php_logos.c
@@ -85,7 +85,7 @@ int php_info_logos(const char *logo_string TSRMLS_DC)
content_header[len] = '\0';
sapi_add_header(content_header, len, 0);
- PHPWRITE(logo_image->data, logo_image->size);
+ PHPWRITE((char*)logo_image->data, logo_image->size);
return 1;
}
diff --git a/main/php_main.h b/main/php_main.h
index 93ba5a32ac..124be2379a 100644
--- a/main/php_main.h
+++ b/main/php_main.h
@@ -35,6 +35,7 @@ PHPAPI void php_module_shutdown(TSRMLS_D);
PHPAPI void php_module_shutdown_for_exec(void);
PHPAPI int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals);
PHPAPI int php_request_startup_for_hook(TSRMLS_D);
+PHPAPI void php_request_shutdown_for_hook(void *dummy);
PHPAPI int php_register_extensions(zend_module_entry **ptr, int count TSRMLS_DC);
diff --git a/main/php_network.h b/main/php_network.h
index 214a66077b..6078890049 100644
--- a/main/php_network.h
+++ b/main/php_network.h
@@ -194,10 +194,12 @@ PHPAPI void _php_emit_fd_setsize_warning(int max_fd);
/* it is safe to FD_SET too many fd's under win32; the macro will simply ignore
* descriptors that go beyond the default FD_SETSIZE */
# define PHP_SAFE_FD_SET(fd, set) FD_SET(fd, set)
+# define PHP_SAFE_FD_CLR(fd, set) FD_CLR(fd, set)
# define PHP_SAFE_FD_ISSET(fd, set) FD_ISSET(fd, set)
# define PHP_SAFE_MAX_FD(m, n) do { if (n + 1 >= FD_SETSIZE) { _php_emit_fd_setsize_warning(n); }} while(0)
#else
# define PHP_SAFE_FD_SET(fd, set) do { if (fd < FD_SETSIZE) FD_SET(fd, set); } while(0)
+# define PHP_SAFE_FD_CLR(fd, set) do { if (fd < FD_SETSIZE) FD_CLR(fd, set); } while(0)
# define PHP_SAFE_FD_ISSET(fd, set) ((fd < FD_SETSIZE) && FD_ISSET(fd, set))
# define PHP_SAFE_MAX_FD(m, n) do { if (m >= FD_SETSIZE) { _php_emit_fd_setsize_warning(m); m = FD_SETSIZE - 1; }} while(0)
#endif
@@ -220,6 +222,9 @@ typedef struct {
#endif
BEGIN_EXTERN_C()
+PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, char **error_string TSRMLS_DC);
+PHPAPI void php_network_freeaddresses(struct sockaddr **sal);
+
PHPAPI php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
int socktype, int asynchronous, struct timeval *timeout, char **error_string,
int *error_code, char *bindto, unsigned short bindport
diff --git a/main/php_open_temporary_file.c b/main/php_open_temporary_file.c
index f6fe0ff9fd..8d5c9e9ee7 100644
--- a/main/php_open_temporary_file.c
+++ b/main/php_open_temporary_file.c
@@ -127,7 +127,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, char **
new_state.cwd = strdup(cwd);
new_state.cwd_length = strlen(cwd);
- if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) {
+ if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH TSRMLS_CC)) {
free(new_state.cwd);
return -1;
}
diff --git a/main/php_output.h b/main/php_output.h
index cb98839de8..d050a141a1 100644
--- a/main/php_output.h
+++ b/main/php_output.h
@@ -12,7 +12,7 @@
| 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> |
+----------------------------------------------------------------------+
*/
@@ -21,35 +21,235 @@
#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_FLUSHABLE 0x0020
+#define PHP_OUTPUT_HANDLER_REMOVABLE 0x0040
+#define PHP_OUTPUT_HANDLER_STDFLAGS 0x0070
+
+/* handler status flags */
+#define PHP_OUTPUT_HANDLER_STARTED 0x1000
+#define PHP_OUTPUT_HANDLER_DISABLED 0x2000
+#define PHP_OUTPUT_HANDLER_PROCESSED 0x4000
+
+/* handler op return values */
+typedef enum _php_output_handler_status_t {
+ PHP_OUTPUT_HANDLER_FAILURE,
+ PHP_OUTPUT_HANDLER_SUCCESS,
+ PHP_OUTPUT_HANDLER_NO_DATA
+} php_output_handler_status_t;
+
+/* php_output_stack_pop() flags */
+#define PHP_OUTPUT_POP_TRY 0x000
+#define PHP_OUTPUT_POP_FORCE 0x001
+#define PHP_OUTPUT_POP_DISCARD 0x010
+#define PHP_OUTPUT_POP_SILENT 0x100
+
+/* real global flags */
+#define PHP_OUTPUT_IMPLICITFLUSH 0x01
+#define PHP_OUTPUT_DISABLED 0x02
+#define PHP_OUTPUT_WRITTEN 0x04
+#define PHP_OUTPUT_SENT 0x08
+/* supplementary flags for php_output_get_status() */
+#define PHP_OUTPUT_ACTIVE 0x10
+#define PHP_OUTPUT_LOCKED 0x20
+/* output layer is ready to use */
+#define PHP_OUTPUT_ACTIVATED 0x100000
+
+/* handler hooks */
+typedef enum _php_output_handler_hook_t {
+ PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ,
+ PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS,
+ PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL,
+ PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE,
+ PHP_OUTPUT_HANDLER_HOOK_DISABLE,
+ /* unused */
+ PHP_OUTPUT_HANDLER_HOOK_LAST
+} php_output_handler_hook_t;
+
+#define PHP_OUTPUT_HANDLER_INITBUF_SIZE(s) \
+( ((s) > 1) ? \
+ (s) + PHP_OUTPUT_HANDLER_ALIGNTO_SIZE - ((s) % (PHP_OUTPUT_HANDLER_ALIGNTO_SIZE)) : \
+ PHP_OUTPUT_HANDLER_DEFAULT_SIZE \
+)
+#define PHP_OUTPUT_HANDLER_ALIGNTO_SIZE 0x1000
+#define PHP_OUTPUT_HANDLER_DEFAULT_SIZE 0x4000
+
+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);
+/* output handler context dtor */
+typedef void (*php_output_handler_context_dtor_t)(void *opaq TSRMLS_DC);
+/* conflict check callback */
+typedef int (*php_output_handler_conflict_check_t)(const char *handler_name, size_t handler_name_len TSRMLS_DC);
+/* ctor for aliases */
+typedef struct _php_output_handler *(*php_output_handler_alias_ctor_t)(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags TSRMLS_DC);
+
+typedef struct _php_output_handler_user_func_t {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval *zoh;
+} php_output_handler_user_func_t;
+
+typedef struct _php_output_handler {
+ char *name;
+ size_t name_len;
+ int flags;
+ int level;
+ size_t size;
+ php_output_buffer buffer;
+
+ void *opaq;
+ void (*dtor)(void *opaq TSRMLS_DC);
+
+ union {
+ php_output_handler_user_func_t *user;
+ php_output_handler_context_func_t internal;
+ } func;
+} php_output_handler;
+
+ZEND_BEGIN_MODULE_GLOBALS(output)
+ int flags;
+ zend_stack handlers;
+ php_output_handler *active;
+ php_output_handler *running;
+ const char *output_start_filename;
+ int output_start_lineno;
+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) TSRMLS_CC)
+#define PHPWRITE_H(str, str_len) php_output_write_unbuffered((str), (str_len) TSRMLS_CC)
+
+#define PUTC(c) (php_output_write(&(c), 1 TSRMLS_CC), (c))
+#define PUTC_H(c) (php_output_write_unbuffered(&(c), 1 TSRMLS_CC), (c))
+
+#define PUTS(str) do { \
+ const char *__str = (str); \
+ php_output_write(__str, strlen(__str) TSRMLS_CC); \
+} while (0)
+#define PUTS_H(str) do { \
+ const char *__str = (str); \
+ php_output_write_unbuffered(__str, strlen(__str) TSRMLS_CC); \
+} while (0)
+
BEGIN_EXTERN_C()
+
+extern const char php_output_default_handler_name[sizeof("default output handler")];
+extern const char php_output_devnull_handler_name[sizeof("null output handler")];
+
+#define php_output_tearup() \
+ php_output_startup(); \
+ php_output_activate(TSRMLS_C)
+#define php_output_teardown() \
+ php_output_end_all(TSRMLS_C); \
+ php_output_deactivate(TSRMLS_C); \
+ 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);
+/* MSHUTDOWN */
+PHPAPI void php_output_shutdown(void);
+
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);
+
+/* RINIT */
+PHPAPI int php_output_activate(TSRMLS_D);
+/* RSHUTDOWN */
+PHPAPI void php_output_deactivate(TSRMLS_D);
+
+PHPAPI void php_output_set_status(int status TSRMLS_DC);
+PHPAPI int php_output_get_status(TSRMLS_D);
+PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC);
+PHPAPI const char *php_output_get_start_filename(TSRMLS_D);
+PHPAPI int php_output_get_start_lineno(TSRMLS_D);
+
+PHPAPI int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC);
+PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC);
+
+PHPAPI int php_output_flush(TSRMLS_D);
+PHPAPI void php_output_flush_all(TSRMLS_D);
+PHPAPI int php_output_clean(TSRMLS_D);
+PHPAPI void php_output_clean_all(TSRMLS_D);
+PHPAPI int php_output_end(TSRMLS_D);
+PHPAPI void php_output_end_all(TSRMLS_D);
+PHPAPI int php_output_discard(TSRMLS_D);
+PHPAPI void php_output_discard_all(TSRMLS_D);
+
+PHPAPI int php_output_get_contents(zval *p TSRMLS_DC);
+PHPAPI int php_output_get_length(zval *p TSRMLS_DC);
+PHPAPI int php_output_get_level(TSRMLS_D);
+PHPAPI php_output_handler* php_output_get_active_handler(TSRMLS_D);
+
+PHPAPI int php_output_start_default(TSRMLS_D);
+PHPAPI int php_output_start_devnull(TSRMLS_D);
+
+PHPAPI int php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC);
+PHPAPI int php_output_start_internal(const char *name, size_t name_len, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC);
+
+PHPAPI php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC);
+PHPAPI php_output_handler *php_output_handler_create_internal(const char *name, size_t name_len, php_output_handler_context_func_t handler, size_t chunk_size, int flags TSRMLS_DC);
+
+PHPAPI void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC);
+PHPAPI int php_output_handler_start(php_output_handler *handler TSRMLS_DC);
+PHPAPI int php_output_handler_started(const char *name, size_t name_len TSRMLS_DC);
+PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSRMLS_DC);
+PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC);
+PHPAPI void php_output_handler_free(php_output_handler **handler TSRMLS_DC);
+
+PHPAPI int php_output_handler_conflict(const char *handler_new, size_t handler_new_len, const char *handler_set, size_t handler_set_len TSRMLS_DC);
+PHPAPI int php_output_handler_conflict_register(const char *handler_name, size_t handler_name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC);
+PHPAPI int php_output_handler_reverse_conflict_register(const char *handler_name, size_t handler_name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC);
+
+PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(const char *handler_name, size_t handler_name_len TSRMLS_DC);
+PHPAPI int php_output_handler_alias_register(const char *handler_name, size_t handler_name_len, php_output_handler_alias_ctor_t func TSRMLS_DC);
+
END_EXTERN_C()
+
PHP_FUNCTION(ob_start);
PHP_FUNCTION(ob_flush);
PHP_FUNCTION(ob_clean);
@@ -64,51 +264,16 @@ PHP_FUNCTION(ob_get_status);
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;
- char *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
+ */
diff --git a/main/php_streams.h b/main/php_streams.h
index 83b18c008b..82498d6619 100644
--- a/main/php_streams.h
+++ b/main/php_streams.h
@@ -154,6 +154,8 @@ typedef struct _php_stream_wrapper_ops {
/* Create/Remove directory */
int (*stream_mkdir)(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC);
int (*stream_rmdir)(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+ /* Metadata handling */
+ int (*stream_metadata)(php_stream_wrapper *wrapper, char *url, int options, void *value, php_stream_context *context TSRMLS_DC);
} php_stream_wrapper_ops;
struct _php_stream_wrapper {
@@ -225,9 +227,11 @@ struct _php_stream {
int eof;
#if ZEND_DEBUG
- char *open_filename;
+ const char *open_filename;
uint open_lineno;
#endif
+
+ struct _php_stream *enclosing_stream; /* this is a private stream owned by enclosing_stream */
}; /* php_stream */
/* state definitions when closing down; these are private to streams.c */
@@ -259,6 +263,10 @@ END_EXTERN_C()
#define php_stream_from_zval_no_verify(xstr, ppzval) (xstr) = (php_stream*)zend_fetch_resource((ppzval) TSRMLS_CC, -1, "stream", NULL, 2, php_file_le_stream(), php_file_le_pstream())
BEGIN_EXTERN_C()
+PHPAPI php_stream *php_stream_encloses(php_stream *enclosing, php_stream *enclosed);
+#define php_stream_free_enclosed(stream_enclosed, close_options) _php_stream_free_enclosed((stream_enclosed), (close_options) TSRMLS_CC)
+PHPAPI int _php_stream_free_enclosed(php_stream *stream_enclosed, int close_options TSRMLS_DC);
+
PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC);
#define PHP_STREAM_PERSISTENT_SUCCESS 0 /* id exists */
#define PHP_STREAM_PERSISTENT_FAILURE 1 /* id exists but is not a stream! */
@@ -269,6 +277,7 @@ PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream *
#define PHP_STREAM_FREE_PRESERVE_HANDLE 4 /* tell ops->close to not close it's underlying handle */
#define PHP_STREAM_FREE_RSRC_DTOR 8 /* called from the resource list dtor */
#define PHP_STREAM_FREE_PERSISTENT 16 /* manually freeing a persistent connection */
+#define PHP_STREAM_FREE_IGNORE_ENCLOSING 32 /* don't close the enclosing stream instead */
#define PHP_STREAM_FREE_CLOSE (PHP_STREAM_FREE_CALL_DTOR | PHP_STREAM_FREE_RELEASE_STREAM)
#define PHP_STREAM_FREE_CLOSE_CASTED (PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_PRESERVE_HANDLE)
#define PHP_STREAM_FREE_CLOSE_PERSISTENT (PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_PERSISTENT)
@@ -429,7 +438,7 @@ BEGIN_EXTERN_C()
ZEND_ATTRIBUTE_DEPRECATED
PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen STREAMS_DC TSRMLS_DC);
#define php_stream_copy_to_stream(src, dest, maxlen) _php_stream_copy_to_stream((src), (dest), (maxlen) STREAMS_CC TSRMLS_CC)
-PHPAPI size_t _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC);
+PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC);
#define php_stream_copy_to_stream_ex(src, dest, maxlen, len) _php_stream_copy_to_stream_ex((src), (dest), (maxlen), (len) STREAMS_CC TSRMLS_CC)
@@ -484,8 +493,8 @@ END_EXTERN_C()
#define IGNORE_PATH 0x00000000
#define USE_PATH 0x00000001
#define IGNORE_URL 0x00000002
-#define ENFORCE_SAFE_MODE 0x00000004
#define REPORT_ERRORS 0x00000008
+#define ENFORCE_SAFE_MODE 0 /* for BC only */
/* If you don't need to write to the stream, but really need to
* be able to seek, use this flag in your options. */
@@ -583,6 +592,15 @@ END_EXTERN_C()
/* Definitions for user streams */
#define PHP_STREAM_IS_URL 1
+
+/* Stream metadata definitions */
+/* Create if referred resource does not exist */
+#define PHP_STREAM_META_TOUCH 1
+#define PHP_STREAM_META_OWNER_NAME 2
+#define PHP_STREAM_META_OWNER 3
+#define PHP_STREAM_META_GROUP_NAME 4
+#define PHP_STREAM_META_GROUP 5
+#define PHP_STREAM_META_ACCESS 6
/*
* Local variables:
* tab-width: 4
diff --git a/main/php_variables.c b/main/php_variables.c
index 4b97cbd85f..427966170c 100644
--- a/main/php_variables.c
+++ b/main/php_variables.c
@@ -47,11 +47,7 @@ PHPAPI void php_register_variable_safe(char *var, char *strval, int str_len, zva
/* Prepare value */
Z_STRLEN(new_entry) = str_len;
- if (PG(magic_quotes_gpc)) {
- Z_STRVAL(new_entry) = php_addslashes(strval, Z_STRLEN(new_entry), &Z_STRLEN(new_entry), 0 TSRMLS_CC);
- } else {
- Z_STRVAL(new_entry) = estrndup(strval, Z_STRLEN(new_entry));
- }
+ Z_STRVAL(new_entry) = estrndup(strval, Z_STRLEN(new_entry));
Z_TYPE(new_entry) = IS_STRING;
php_register_variable_ex(var, &new_entry, track_vars_array TSRMLS_CC);
@@ -61,39 +57,38 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
{
char *p = NULL;
char *ip; /* index pointer */
- char *index, *escaped_index = NULL;
+ char *index;
char *var, *var_orig;
int var_len, index_len;
zval *gpc_element, **gpc_element_p;
zend_bool is_array = 0;
HashTable *symtable1 = NULL;
+ ALLOCA_FLAG(use_heap)
assert(var_name != NULL);
if (track_vars_array) {
symtable1 = Z_ARRVAL_P(track_vars_array);
- } else if (PG(register_globals)) {
- if (!EG(active_symbol_table)) {
- zend_rebuild_symbol_table(TSRMLS_C);
- }
- symtable1 = EG(active_symbol_table);
}
+
if (!symtable1) {
/* Nothing to do */
zval_dtor(val);
return;
}
- /*
- * Prepare variable name
- */
- var_orig = estrdup(var_name);
- var = var_orig;
/* ignore leading spaces in the variable name */
- while (*var && *var==' ') {
- var++;
+ while (*var_name && *var_name==' ') {
+ var_name++;
}
+
+ /*
+ * Prepare variable name
+ */
+ var_len = strlen(var_name);
+ var = var_orig = do_alloca(var_len + 1, use_heap);
+ memcpy(var_orig, var_name, var_len + 1);
/* ensure that we don't have spaces or dots in the variable name (not binary safe) */
for (p = var; *p; p++) {
@@ -110,7 +105,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
if (var_len==0) { /* empty variable name, or variable name with a space in it */
zval_dtor(val);
- efree(var_orig);
+ free_alloca(var_orig, use_heap);
return;
}
@@ -119,7 +114,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
var_len == sizeof("GLOBALS")-1 &&
!memcmp(var, "GLOBALS", sizeof("GLOBALS")-1)) {
zval_dtor(val);
- efree(var_orig);
+ free_alloca(var_orig, use_heap);
return;
}
@@ -139,9 +134,6 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
if (track_vars_array) {
ht = Z_ARRVAL_P(track_vars_array);
zend_symtable_del(ht, var, var_len + 1);
- } else if (PG(register_globals)) {
- ht = EG(active_symbol_table);
- zend_symtable_del(ht, var, var_len + 1);
}
zval_dtor(val);
@@ -151,7 +143,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
if (!PG(display_errors)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variable nesting level exceeded %ld. To increase the limit change max_input_nesting_level in php.ini.", PG(max_input_nesting_level));
}
- efree(var_orig);
+ free_alloca(var_orig, use_heap);
return;
}
@@ -185,23 +177,15 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
if (zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p) == FAILURE) {
zval_ptr_dtor(&gpc_element);
zval_dtor(val);
- efree(var_orig);
+ free_alloca(var_orig, use_heap);
return;
}
} else {
- if (PG(magic_quotes_gpc)) {
- escaped_index = php_addslashes(index, index_len, &index_len, 0 TSRMLS_CC);
- } else {
- escaped_index = index;
- }
- if (zend_symtable_find(symtable1, escaped_index, index_len + 1, (void **) &gpc_element_p) == FAILURE
+ if (zend_symtable_find(symtable1, index, index_len + 1, (void **) &gpc_element_p) == FAILURE
|| Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
MAKE_STD_ZVAL(gpc_element);
array_init(gpc_element);
- zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
- }
- if (index != escaped_index) {
- efree(escaped_index);
+ zend_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
}
}
symtable1 = Z_ARRVAL_PP(gpc_element_p);
@@ -227,11 +211,6 @@ plain_var:
zval_ptr_dtor(&gpc_element);
}
} else {
- if (PG(magic_quotes_gpc)) {
- escaped_index = php_addslashes(index, index_len, &index_len, 0 TSRMLS_CC);
- } else {
- escaped_index = index;
- }
/*
* According to rfc2965, more specific paths are listed above the less specific ones.
* If we encounter a duplicate cookie name, we should skip it, since it is not possible
@@ -240,17 +219,14 @@ plain_var:
*/
if (PG(http_globals)[TRACK_VARS_COOKIE] &&
symtable1 == Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) &&
- zend_symtable_exists(symtable1, escaped_index, index_len + 1)) {
+ zend_symtable_exists(symtable1, index, index_len + 1)) {
zval_ptr_dtor(&gpc_element);
} else {
- zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
- }
- if (escaped_index != index) {
- efree(escaped_index);
+ zend_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
}
}
}
- efree(var_orig);
+ free_alloca(var_orig, use_heap);
}
SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler)
@@ -447,13 +423,6 @@ void _php_import_environment_variables(zval *array_ptr TSRMLS_DC)
size_t alloc_size = sizeof(buf);
unsigned long nlen; /* ptrdiff_t is not portable */
- /* turn off magic_quotes while importing environment variables */
- int magic_quotes_gpc = PG(magic_quotes_gpc);
-
- if (magic_quotes_gpc) {
- zend_alter_ini_entry_ex("magic_quotes_gpc", sizeof("magic_quotes_gpc"), "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_ACTIVATE, 1 TSRMLS_CC);
- }
-
for (env = environ; env != NULL && *env != NULL; env++) {
p = strchr(*env, '=');
if (!p) { /* malformed entry? */
@@ -471,10 +440,6 @@ void _php_import_environment_variables(zval *array_ptr TSRMLS_DC)
if (t != buf && t != NULL) {
efree(t);
}
-
- if (magic_quotes_gpc) {
- zend_alter_ini_entry_ex("magic_quotes_gpc", sizeof("magic_quotes_gpc"), "1", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_ACTIVATE, 1 TSRMLS_CC);
- }
}
zend_bool php_std_auto_global_callback(char *name, uint name_len TSRMLS_DC)
@@ -491,7 +456,7 @@ static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC)
int count = 0;
char *ss, *space;
- if (!(PG(register_globals) || SG(request_info).argc || track_vars_array)) {
+ if (!(SG(request_info).argc || track_vars_array)) {
return;
}
@@ -550,7 +515,7 @@ static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC)
}
Z_TYPE_P(argc) = IS_LONG;
- if (PG(register_globals) || SG(request_info).argc) {
+ if (SG(request_info).argc) {
Z_ADDREF_P(arr);
Z_ADDREF_P(argc);
zend_hash_update(&EG(symbol_table), "argv", sizeof("argv"), &arr, sizeof(zval *), NULL);
@@ -588,8 +553,6 @@ PHPAPI int php_handle_special_queries(TSRMLS_D)
static inline void php_register_server_variables(TSRMLS_D)
{
zval *array_ptr = NULL;
- /* turn off magic_quotes while importing server variables */
- int magic_quotes_gpc = PG(magic_quotes_gpc);
ALLOC_ZVAL(array_ptr);
array_init(array_ptr);
@@ -598,9 +561,6 @@ static inline void php_register_server_variables(TSRMLS_D)
zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_SERVER]);
}
PG(http_globals)[TRACK_VARS_SERVER] = array_ptr;
- if (magic_quotes_gpc) {
- zend_alter_ini_entry_ex("magic_quotes_gpc", sizeof("magic_quotes_gpc"), "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_ACTIVATE, 1 TSRMLS_CC);
- }
/* Server variables */
if (sapi_module.register_server_variables) {
@@ -619,15 +579,15 @@ static inline void php_register_server_variables(TSRMLS_D)
}
/* store request init time */
{
- zval new_entry;
- Z_TYPE(new_entry) = IS_LONG;
- Z_LVAL(new_entry) = sapi_get_request_time(TSRMLS_C);
- php_register_variable_ex("REQUEST_TIME", &new_entry, array_ptr TSRMLS_CC);
+ zval request_time_float, request_time_long;
+ Z_TYPE(request_time_float) = IS_DOUBLE;
+ Z_DVAL(request_time_float) = sapi_get_request_time(TSRMLS_C);
+ php_register_variable_ex("REQUEST_TIME_FLOAT", &request_time_float, array_ptr TSRMLS_CC);
+ Z_TYPE(request_time_long) = IS_LONG;
+ Z_LVAL(request_time_long) = zend_dval_to_lval(Z_DVAL(request_time_float));
+ php_register_variable_ex("REQUEST_TIME", &request_time_long, array_ptr TSRMLS_CC);
}
- if (magic_quotes_gpc) {
- zend_alter_ini_entry_ex("magic_quotes_gpc", sizeof("magic_quotes_gpc"), "1", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_ACTIVATE, 1 TSRMLS_CC);
- }
}
/* }}} */
@@ -641,7 +601,7 @@ static void php_autoglobal_merge(HashTable *dest, HashTable *src TSRMLS_DC)
ulong num_key;
HashPosition pos;
int key_type;
- int globals_check = (PG(register_globals) && (dest == (&EG(symbol_table))));
+ int globals_check = (dest == (&EG(symbol_table)));
zend_hash_internal_pointer_reset_ex(src, &pos);
while (zend_hash_get_current_data_ex(src, (void **)&src_entry, &pos) == SUCCESS) {
@@ -650,10 +610,9 @@ static void php_autoglobal_merge(HashTable *dest, HashTable *src TSRMLS_DC)
|| (key_type == HASH_KEY_IS_STRING && zend_hash_find(dest, string_key, string_key_len, (void **) &dest_entry) != SUCCESS)
|| (key_type == HASH_KEY_IS_LONG && zend_hash_index_find(dest, num_key, (void **)&dest_entry) != SUCCESS)
|| Z_TYPE_PP(dest_entry) != IS_ARRAY
- ) {
+ ) {
Z_ADDREF_PP(src_entry);
if (key_type == HASH_KEY_IS_STRING) {
- /* if register_globals is on and working with main symbol table, prevent overwriting of GLOBALS */
if (!globals_check || string_key_len != sizeof("GLOBALS") || memcmp(string_key, "GLOBALS", sizeof("GLOBALS") - 1)) {
zend_hash_update(dest, string_key, string_key_len, src_entry, sizeof(zval *), NULL);
} else {
@@ -671,130 +630,116 @@ static void php_autoglobal_merge(HashTable *dest, HashTable *src TSRMLS_DC)
}
/* }}} */
-static zend_bool php_auto_globals_create_server(char *name, uint name_len TSRMLS_DC);
-static zend_bool php_auto_globals_create_env(char *name, uint name_len TSRMLS_DC);
-static zend_bool php_auto_globals_create_request(char *name, uint name_len TSRMLS_DC);
+static zend_bool php_auto_globals_create_server(const char *name, uint name_len TSRMLS_DC);
+static zend_bool php_auto_globals_create_env(const char *name, uint name_len TSRMLS_DC);
+static zend_bool php_auto_globals_create_request(const char *name, uint name_len TSRMLS_DC);
/* {{{ php_hash_environment
*/
int php_hash_environment(TSRMLS_D)
{
- char *p;
- unsigned char _gpc_flags[5] = {0, 0, 0, 0, 0};
- zend_bool jit_initialization = (PG(auto_globals_jit) && !PG(register_globals) && !PG(register_long_arrays));
- struct auto_global_record {
- char *name;
- uint name_len;
- char *long_name;
- uint long_name_len;
- zend_bool jit_initialization;
- } auto_global_records[] = {
- { "_POST", sizeof("_POST"), "HTTP_POST_VARS", sizeof("HTTP_POST_VARS"), 0 },
- { "_GET", sizeof("_GET"), "HTTP_GET_VARS", sizeof("HTTP_GET_VARS"), 0 },
- { "_COOKIE", sizeof("_COOKIE"), "HTTP_COOKIE_VARS", sizeof("HTTP_COOKIE_VARS"), 0 },
- { "_SERVER", sizeof("_SERVER"), "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), 1 },
- { "_ENV", sizeof("_ENV"), "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS"), 1 },
- { "_FILES", sizeof("_FILES"), "HTTP_POST_FILES", sizeof("HTTP_POST_FILES"), 0 },
- };
- size_t num_track_vars = sizeof(auto_global_records)/sizeof(struct auto_global_record);
- size_t i;
-
- /* jit_initialization = 0; */
- for (i=0; i<num_track_vars; i++) {
- PG(http_globals)[i] = NULL;
- }
-
- for (p=PG(variables_order); p && *p; p++) {
- switch(*p) {
- case 'p':
- case 'P':
- if (!_gpc_flags[0] && !SG(headers_sent) && SG(request_info).request_method && !strcasecmp(SG(request_info).request_method, "POST")) {
- sapi_module.treat_data(PARSE_POST, NULL, NULL TSRMLS_CC); /* POST Data */
- _gpc_flags[0] = 1;
- if (PG(register_globals)) {
- php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST]) TSRMLS_CC);
- }
- }
- break;
- case 'c':
- case 'C':
- if (!_gpc_flags[1]) {
- sapi_module.treat_data(PARSE_COOKIE, NULL, NULL TSRMLS_CC); /* Cookie Data */
- _gpc_flags[1] = 1;
- if (PG(register_globals)) {
- php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) TSRMLS_CC);
- }
- }
- break;
- case 'g':
- case 'G':
- if (!_gpc_flags[2]) {
- sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC); /* GET Data */
- _gpc_flags[2] = 1;
- if (PG(register_globals)) {
- php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC);
- }
- }
- break;
- case 'e':
- case 'E':
- if (!jit_initialization && !_gpc_flags[3]) {
- zend_auto_global_disable_jit("_ENV", sizeof("_ENV")-1 TSRMLS_CC);
- php_auto_globals_create_env("_ENV", sizeof("_ENV")-1 TSRMLS_CC);
- _gpc_flags[3] = 1;
- if (PG(register_globals)) {
- php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV]) TSRMLS_CC);
- }
- }
- break;
- case 's':
- case 'S':
- if (!jit_initialization && !_gpc_flags[4]) {
- zend_auto_global_disable_jit("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
- php_register_server_variables(TSRMLS_C);
- _gpc_flags[4] = 1;
- if (PG(register_globals)) {
- php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]) TSRMLS_CC);
- }
- }
- break;
- }
- }
-
- /* argv/argc support */
+ memset(PG(http_globals), 0, sizeof(PG(http_globals)));
+ zend_activate_auto_globals(TSRMLS_C);
if (PG(register_argc_argv)) {
php_build_argv(SG(request_info).query_string, PG(http_globals)[TRACK_VARS_SERVER] TSRMLS_CC);
}
+ return SUCCESS;
+}
+/* }}} */
- for (i=0; i<num_track_vars; i++) {
- if (jit_initialization && auto_global_records[i].jit_initialization) {
- continue;
+static zend_bool php_auto_globals_create_get(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *vars;
+
+ if (PG(variables_order) && (strchr(PG(variables_order),'G') || strchr(PG(variables_order),'g'))) {
+ sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
+ vars = PG(http_globals)[TRACK_VARS_GET];
+ } else {
+ ALLOC_ZVAL(vars);
+ array_init(vars);
+ INIT_PZVAL(vars);
+ if (PG(http_globals)[TRACK_VARS_GET]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_GET]);
}
- if (!PG(http_globals)[i]) {
- ALLOC_ZVAL(PG(http_globals)[i]);
- array_init(PG(http_globals)[i]);
- INIT_PZVAL(PG(http_globals)[i]);
+ PG(http_globals)[TRACK_VARS_GET] = vars;
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
+ Z_ADDREF_P(vars);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_post(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *vars;
+
+ if (PG(variables_order) &&
+ (strchr(PG(variables_order),'P') || strchr(PG(variables_order),'p')) &&
+ !SG(headers_sent) &&
+ SG(request_info).request_method &&
+ !strcasecmp(SG(request_info).request_method, "POST")) {
+ sapi_module.treat_data(PARSE_POST, NULL, NULL TSRMLS_CC);
+ vars = PG(http_globals)[TRACK_VARS_POST];
+ } else {
+ ALLOC_ZVAL(vars);
+ array_init(vars);
+ INIT_PZVAL(vars);
+ if (PG(http_globals)[TRACK_VARS_POST]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_POST]);
}
+ PG(http_globals)[TRACK_VARS_POST] = vars;
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
+ Z_ADDREF_P(vars);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_cookie(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *vars;
- Z_ADDREF_P(PG(http_globals)[i]);
- zend_hash_update(&EG(symbol_table), auto_global_records[i].name, auto_global_records[i].name_len, &PG(http_globals)[i], sizeof(zval *), NULL);
- if (PG(register_long_arrays)) {
- zend_hash_update(&EG(symbol_table), auto_global_records[i].long_name, auto_global_records[i].long_name_len, &PG(http_globals)[i], sizeof(zval *), NULL);
- Z_ADDREF_P(PG(http_globals)[i]);
+ if (PG(variables_order) && (strchr(PG(variables_order),'C') || strchr(PG(variables_order),'c'))) {
+ sapi_module.treat_data(PARSE_COOKIE, NULL, NULL TSRMLS_CC);
+ vars = PG(http_globals)[TRACK_VARS_COOKIE];
+ } else {
+ ALLOC_ZVAL(vars);
+ array_init(vars);
+ INIT_PZVAL(vars);
+ if (PG(http_globals)[TRACK_VARS_COOKIE]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_COOKIE]);
}
+ PG(http_globals)[TRACK_VARS_COOKIE] = vars;
}
- /* Create _REQUEST */
- if (!jit_initialization) {
- zend_auto_global_disable_jit("_REQUEST", sizeof("_REQUEST")-1 TSRMLS_CC);
- php_auto_globals_create_request("_REQUEST", sizeof("_REQUEST")-1 TSRMLS_CC);
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
+ Z_ADDREF_P(vars);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_files(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *vars;
+
+ if (PG(http_globals)[TRACK_VARS_FILES]) {
+ vars = PG(http_globals)[TRACK_VARS_FILES];
+ } else {
+ ALLOC_ZVAL(vars);
+ array_init(vars);
+ INIT_PZVAL(vars);
+ PG(http_globals)[TRACK_VARS_FILES] = vars;
}
- return SUCCESS;
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
+ Z_ADDREF_P(vars);
+
+ return 0; /* don't rearm */
}
-/* }}} */
-static zend_bool php_auto_globals_create_server(char *name, uint name_len TSRMLS_DC)
+static zend_bool php_auto_globals_create_server(const char *name, uint name_len TSRMLS_DC)
{
if (PG(variables_order) && (strchr(PG(variables_order),'S') || strchr(PG(variables_order),'s'))) {
php_register_server_variables(TSRMLS_C);
@@ -804,7 +749,7 @@ static zend_bool php_auto_globals_create_server(char *name, uint name_len TSRMLS
zval **argc, **argv;
if (zend_hash_find(&EG(symbol_table), "argc", sizeof("argc"), (void**)&argc) == SUCCESS &&
- zend_hash_find(&EG(symbol_table), "argv", sizeof("argv"), (void**)&argv) == SUCCESS) {
+ zend_hash_find(&EG(symbol_table), "argv", sizeof("argv"), (void**)&argv) == SUCCESS) {
Z_ADDREF_PP(argc);
Z_ADDREF_PP(argv);
zend_hash_update(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "argv", sizeof("argv"), argv, sizeof(zval *), NULL);
@@ -828,16 +773,11 @@ static zend_bool php_auto_globals_create_server(char *name, uint name_len TSRMLS
zend_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_SERVER], sizeof(zval *), NULL);
Z_ADDREF_P(PG(http_globals)[TRACK_VARS_SERVER]);
-
- if (PG(register_long_arrays)) {
- zend_hash_update(&EG(symbol_table), "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), &PG(http_globals)[TRACK_VARS_SERVER], sizeof(zval *), NULL);
- Z_ADDREF_P(PG(http_globals)[TRACK_VARS_SERVER]);
- }
return 0; /* don't rearm */
}
-static zend_bool php_auto_globals_create_env(char *name, uint name_len TSRMLS_DC)
+static zend_bool php_auto_globals_create_env(const char *name, uint name_len TSRMLS_DC)
{
zval *env_vars = NULL;
ALLOC_ZVAL(env_vars);
@@ -855,15 +795,10 @@ static zend_bool php_auto_globals_create_env(char *name, uint name_len TSRMLS_DC
zend_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_ENV], sizeof(zval *), NULL);
Z_ADDREF_P(PG(http_globals)[TRACK_VARS_ENV]);
- if (PG(register_long_arrays)) {
- zend_hash_update(&EG(symbol_table), "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS"), &PG(http_globals)[TRACK_VARS_ENV], sizeof(zval *), NULL);
- Z_ADDREF_P(PG(http_globals)[TRACK_VARS_ENV]);
- }
-
return 0; /* don't rearm */
}
-static zend_bool php_auto_globals_create_request(char *name, uint name_len TSRMLS_DC)
+static zend_bool php_auto_globals_create_request(const char *name, uint name_len TSRMLS_DC)
{
zval *form_variables;
unsigned char _gpc_flags[3] = {0, 0, 0};
@@ -873,7 +808,7 @@ static zend_bool php_auto_globals_create_request(char *name, uint name_len TSRML
array_init(form_variables);
INIT_PZVAL(form_variables);
- if(PG(request_order) != NULL) {
+ if (PG(request_order) != NULL) {
p = PG(request_order);
} else {
p = PG(variables_order);
@@ -905,19 +840,19 @@ static zend_bool php_auto_globals_create_request(char *name, uint name_len TSRML
}
}
- zend_hash_update(&EG(symbol_table), "_REQUEST", sizeof("_REQUEST"), &form_variables, sizeof(zval *), NULL);
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &form_variables, sizeof(zval *), NULL);
return 0;
}
void php_startup_auto_globals(TSRMLS_D)
{
- zend_register_auto_global("_GET", sizeof("_GET")-1, NULL TSRMLS_CC);
- zend_register_auto_global("_POST", sizeof("_POST")-1, NULL TSRMLS_CC);
- zend_register_auto_global("_COOKIE", sizeof("_COOKIE")-1, NULL TSRMLS_CC);
- zend_register_auto_global("_SERVER", sizeof("_SERVER")-1, php_auto_globals_create_server TSRMLS_CC);
- zend_register_auto_global("_ENV", sizeof("_ENV")-1, php_auto_globals_create_env TSRMLS_CC);
- zend_register_auto_global("_REQUEST", sizeof("_REQUEST")-1, php_auto_globals_create_request TSRMLS_CC);
- zend_register_auto_global("_FILES", sizeof("_FILES")-1, NULL TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_GET"), 0, php_auto_globals_create_get TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_POST"), 0, php_auto_globals_create_post TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_COOKIE"), 0, php_auto_globals_create_cookie TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_SERVER"), PG(auto_globals_jit), php_auto_globals_create_server TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_ENV"), PG(auto_globals_jit), php_auto_globals_create_env TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_REQUEST"), PG(auto_globals_jit), php_auto_globals_create_request TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_FILES"), 0, php_auto_globals_create_files TSRMLS_CC);
}
/*
diff --git a/main/php_version.h b/main/php_version.h
index e4ba15eba9..8dfe49630f 100644
--- a/main/php_version.h
+++ b/main/php_version.h
@@ -1,8 +1,8 @@
/* automatically generated by configure */
/* edit configure.in to change version number */
#define PHP_MAJOR_VERSION 5
-#define PHP_MINOR_VERSION 3
-#define PHP_RELEASE_VERSION 19
+#define PHP_MINOR_VERSION 4
+#define PHP_RELEASE_VERSION 9
#define PHP_EXTRA_VERSION "-dev"
-#define PHP_VERSION "5.3.19-dev"
-#define PHP_VERSION_ID 50319
+#define PHP_VERSION "5.4.9-dev"
+#define PHP_VERSION_ID 50409
diff --git a/main/rfc1867.c b/main/rfc1867.c
index 31605cfc17..5da3a99355 100644
--- a/main/rfc1867.c
+++ b/main/rfc1867.c
@@ -36,92 +36,24 @@
#define DEBUG_FILE_UPLOAD ZEND_DEBUG
-PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC) = NULL;
-
-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
-#include "ext/mbstring/mbstring.h"
-
-static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
-
-#define SAFE_RETURN { \
- php_mb_flush_gpc_variables(num_vars, val_list, len_list, array_ptr TSRMLS_CC); \
- if (lbuf) efree(lbuf); \
- if (abuf) efree(abuf); \
- if (array_index) efree(array_index); \
- zend_hash_destroy(&PG(rfc1867_protected_variables)); \
- zend_llist_destroy(&header); \
- if (mbuff->boundary_next) efree(mbuff->boundary_next); \
- if (mbuff->boundary) efree(mbuff->boundary); \
- if (mbuff->buffer) efree(mbuff->buffer); \
- if (mbuff) efree(mbuff); \
- return; }
-
-void php_mb_flush_gpc_variables(int num_vars, char **val_list, int *len_list, zval *array_ptr TSRMLS_DC) /* {{{ */
+static int dummy_encoding_translation(TSRMLS_D)
{
- int i;
- if (php_mb_encoding_translation(TSRMLS_C)) {
- if (num_vars > 0 &&
- php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
- php_mb_gpc_encoding_converter(val_list, len_list, num_vars, NULL, NULL TSRMLS_CC);
- }
- for (i = 0; i<num_vars; i += 2) {
- safe_php_register_variable(val_list[i], val_list[i+1], len_list[i+1], array_ptr, 0 TSRMLS_CC);
- efree(val_list[i]);
- efree(val_list[i+1]);
- }
- efree(val_list);
- efree(len_list);
- }
-}
-/* }}} */
-
-void php_mb_gpc_realloc_buffer(char ***pval_list, int **plen_list, int *num_vars_max, int inc TSRMLS_DC) /* {{{ */
-{
- /* allow only even increments */
- if (inc & 1) {
- inc++;
- }
- (*num_vars_max) += inc;
- *pval_list = (char **)erealloc(*pval_list, (*num_vars_max+2)*sizeof(char *));
- *plen_list = (int *)erealloc(*plen_list, (*num_vars_max+2)*sizeof(int));
+ return 0;
}
-/* }}} */
-void php_mb_gpc_stack_variable(char *param, char *value, char ***pval_list, int **plen_list, int *num_vars, int *num_vars_max TSRMLS_DC) /* {{{ */
-{
- char **val_list = *pval_list;
- int *len_list = *plen_list;
-
- if (*num_vars >= *num_vars_max) {
- php_mb_gpc_realloc_buffer(pval_list, plen_list, num_vars_max, 16 TSRMLS_CC);
- /* in case realloc relocated the buffer */
- val_list = *pval_list;
- len_list = *plen_list;
- }
+static char *php_ap_getword(const zend_encoding *encoding, char **line, char stop TSRMLS_DC);
+static char *php_ap_getword_conf(const zend_encoding *encoding, char *str TSRMLS_DC);
- val_list[*num_vars] = (char *)estrdup(param);
- len_list[*num_vars] = strlen(param);
- (*num_vars)++;
- val_list[*num_vars] = (char *)estrdup(value);
- len_list[*num_vars] = strlen(value);
- (*num_vars)++;
-}
-/* }}} */
+static php_rfc1867_encoding_translation_t php_rfc1867_encoding_translation = dummy_encoding_translation;
+static php_rfc1867_get_detect_order_t php_rfc1867_get_detect_order = NULL;
+static php_rfc1867_set_input_encoding_t php_rfc1867_set_input_encoding = NULL;
+static php_rfc1867_getword_t php_rfc1867_getword = php_ap_getword;
+static php_rfc1867_getword_conf_t php_rfc1867_getword_conf = php_ap_getword_conf;
+static php_rfc1867_basename_t php_rfc1867_basename = NULL;
-#else
+PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC) = NULL;
-#define SAFE_RETURN { \
- if (lbuf) efree(lbuf); \
- if (abuf) efree(abuf); \
- if (array_index) efree(array_index); \
- zend_hash_destroy(&PG(rfc1867_protected_variables)); \
- zend_llist_destroy(&header); \
- if (mbuff->boundary_next) efree(mbuff->boundary_next); \
- if (mbuff->boundary) efree(mbuff->boundary); \
- if (mbuff->buffer) efree(mbuff->buffer); \
- if (mbuff) efree(mbuff); \
- return; }
-#endif
+static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
/* The longest property name we use in an uploaded file array */
#define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
@@ -139,7 +71,7 @@ void php_mb_gpc_stack_variable(char *param, char *value, char ***pval_list, int
#define UPLOAD_ERROR_F 7 /* Failed to write file to disk */
#define UPLOAD_ERROR_X 8 /* File upload stopped by extension */
-void php_rfc1867_register_constants(TSRMLS_D) /* {{{ */
+void php_rfc1867_register_constants(TSRMLS_D) /* {{{ */
{
REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK", UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT);
REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE", UPLOAD_ERROR_A, CONST_CS | CONST_PERSISTENT);
@@ -208,16 +140,16 @@ static void normalize_protected_variable(char *varname TSRMLS_DC) /* {{{ */
}
*s = '\0';
}
-/* }}} */
+/* }}} */
-static void add_protected_variable(char *varname TSRMLS_DC) /* {{{ */
+static void add_protected_variable(char *varname TSRMLS_DC) /* {{{ */
{
int dummy = 1;
normalize_protected_variable(varname TSRMLS_CC);
zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL);
}
-/* }}} */
+/* }}} */
static zend_bool is_protected_variable(char *varname TSRMLS_DC) /* {{{ */
{
@@ -226,41 +158,33 @@ static zend_bool is_protected_variable(char *varname TSRMLS_DC) /* {{{ */
}
/* }}} */
-static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
+static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
{
if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
php_register_variable_safe(var, strval, val_len, track_vars_array TSRMLS_CC);
}
}
-/* }}} */
+/* }}} */
-static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
+static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
{
if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
php_register_variable_ex(var, val, track_vars_array TSRMLS_CC);
}
}
-/* }}} */
+/* }}} */
-static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
+static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
{
- int register_globals = PG(register_globals);
-
- PG(register_globals) = 0;
safe_php_register_variable(strvar, val, strlen(val), http_post_files, override_protection TSRMLS_CC);
- PG(register_globals) = register_globals;
}
-/* }}} */
+/* }}} */
static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
{
- int register_globals = PG(register_globals);
-
- PG(register_globals) = 0;
safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC);
- PG(register_globals) = register_globals;
}
-/* }}} */
+/* }}} */
static int unlink_filename(char **filename TSRMLS_DC) /* {{{ */
{
@@ -277,7 +201,7 @@ void destroy_uploaded_files_hash(TSRMLS_D) /* {{{ */
}
/* }}} */
-/* {{{ Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. */
+/* {{{ Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. */
#define FILLUNIT (1024 * 5)
@@ -294,6 +218,9 @@ typedef struct {
char *boundary_next;
int boundary_next_len;
+ const zend_encoding *input_encoding;
+ const zend_encoding **detect_order;
+ size_t detect_order_size;
} multipart_buffer;
typedef struct {
@@ -351,7 +278,7 @@ static int multipart_buffer_eof(multipart_buffer *self TSRMLS_DC)
}
/* create new multipart_buffer structure */
-static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len)
+static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len TSRMLS_DC)
{
multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer));
@@ -368,6 +295,15 @@ static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len)
self->buf_begin = self->buffer;
self->bytes_in_buffer = 0;
+ if (php_rfc1867_encoding_translation(TSRMLS_C)) {
+ php_rfc1867_get_detect_order(&self->detect_order, &self->detect_order_size TSRMLS_CC);
+ } else {
+ self->detect_order = NULL;
+ self->detect_order_size = 0;
+ }
+
+ self->input_encoding = NULL;
+
return self;
}
@@ -478,6 +414,10 @@ static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header T
char *key = line;
char *value = NULL;
+ if (php_rfc1867_encoding_translation(TSRMLS_C)) {
+ self->input_encoding = zend_multibyte_encoding_detector(line, strlen(line), self->detect_order, self->detect_order_size TSRMLS_CC);
+ }
+
/* space in the beginning means same header */
if (!isspace(line[0])) {
value = strchr(line, ':');
@@ -533,7 +473,7 @@ static char *php_mime_get_hdr_value(zend_llist header, char *key)
return NULL;
}
-static char *php_ap_getword(char **line, char stop)
+static char *php_ap_getword(const zend_encoding *encoding, char **line, char stop TSRMLS_DC)
{
char *pos = *line, quote;
char *res;
@@ -569,29 +509,17 @@ static char *php_ap_getword(char **line, char stop)
return res;
}
-static char *substring_conf(char *start, int len, char quote TSRMLS_DC)
+static char *substring_conf(char *start, int len, char quote)
{
- char *result = emalloc(len + 2);
+ char *result = emalloc(len + 1);
char *resp = result;
int i;
- for (i = 0; i < len; ++i) {
+ for (i = 0; i < len && start[i] != quote; ++i) {
if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) {
*resp++ = start[++i];
} else {
-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
- if (php_mb_encoding_translation(TSRMLS_C)) {
- size_t j = php_mb_gpc_mbchar_bytes(start+i TSRMLS_CC);
- while (j-- > 0 && i < len) {
- *resp++ = start[i++];
- }
- --i;
- } else {
- *resp++ = start[i];
- }
-#else
*resp++ = start[i];
-#endif
}
}
@@ -599,65 +527,49 @@ static char *substring_conf(char *start, int len, char quote TSRMLS_DC)
return result;
}
-static char *php_ap_getword_conf(char **line TSRMLS_DC)
+static char *php_ap_getword_conf(const zend_encoding *encoding, char *str TSRMLS_DC)
{
- char *str = *line, *strend, *res, quote;
-
-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
- if (php_mb_encoding_translation(TSRMLS_C)) {
- int len=strlen(str);
- php_mb_gpc_encoding_detector(&str, &len, 1, NULL TSRMLS_CC);
- }
-#endif
-
while (*str && isspace(*str)) {
++str;
}
if (!*str) {
- *line = str;
return estrdup("");
}
- if ((quote = *str) == '"' || quote == '\'') {
- strend = str + 1;
-look_for_quote:
- while (*strend && *strend != quote) {
- if (*strend == '\\' && strend[1] && strend[1] == quote) {
- strend += 2;
- } else {
- ++strend;
- }
- }
- if (*strend && *strend == quote) {
- char p = *(strend + 1);
- if (p != '\r' && p != '\n' && p != '\0') {
- strend++;
- goto look_for_quote;
- }
- }
-
- res = substring_conf(str + 1, strend - str - 1, quote TSRMLS_CC);
-
- if (*strend == quote) {
- ++strend;
- }
+ if (*str == '"' || *str == '\'') {
+ char quote = *str;
+ str++;
+ return substring_conf(str, strlen(str), quote);
} else {
+ char *strend = str;
- strend = str;
while (*strend && !isspace(*strend)) {
++strend;
}
- res = substring_conf(str, strend - str, 0 TSRMLS_CC);
+ return substring_conf(str, strend - str, 0);
}
+}
- while (*strend && isspace(*strend)) {
- ++strend;
- }
+static char *php_ap_basename(const zend_encoding *encoding, char *path TSRMLS_DC)
+{
+ char *s = strrchr(path, '\\');
+ char *s2 = strrchr(path, '/');
- *line = strend;
- return res;
+ if (s && s2) {
+ if (s > s2) {
+ ++s;
+ } else {
+ s = ++s2;
+ }
+ return s;
+ } else if (s) {
+ return ++s;
+ } else if (s2) {
+ return ++s2;
+ }
+ return path;
}
/*
@@ -760,7 +672,7 @@ static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *le
*
*/
-SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
{
char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL;
char *temp_filename = NULL, *lbuf = NULL, *abuf = NULL;
@@ -768,19 +680,29 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
int max_file_size = 0, skip_upload = 0, anonindex = 0, is_anonymous;
zval *http_post_files = NULL;
HashTable *uploaded_files = NULL;
-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
- int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL;
- char **val_list = NULL;
-#endif
multipart_buffer *mbuff;
zval *array_ptr = (zval *) arg;
int fd = -1;
zend_llist header;
void *event_extra_data = NULL;
- int llen = 0;
+ unsigned int llen = 0;
int upload_cnt = INI_INT("max_file_uploads");
+ const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C);
+ php_rfc1867_getword_t getword;
+ php_rfc1867_getword_conf_t getword_conf;
+ php_rfc1867_basename_t _basename;
long count = 0;
+ if (php_rfc1867_encoding_translation(TSRMLS_C) && internal_encoding) {
+ getword = php_rfc1867_getword;
+ getword_conf = php_rfc1867_getword_conf;
+ _basename = php_rfc1867_basename;
+ } else {
+ getword = php_ap_getword;
+ getword_conf = php_ap_getword_conf;
+ _basename = php_ap_basename;
+ }
+
if (SG(post_max_size) > 0 && SG(request_info).content_length > SG(post_max_size)) {
sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size));
return;
@@ -825,7 +747,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
}
/* Initialize the buffer */
- if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) {
+ if (!(mbuff = multipart_buffer_new(boundary, boundary_len TSRMLS_CC))) {
sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
return;
}
@@ -842,12 +764,6 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
INIT_PZVAL(http_post_files);
PG(http_globals)[TRACK_VARS_FILES] = http_post_files;
-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
- if (php_mb_encoding_translation(TSRMLS_C)) {
- val_list = (char **)ecalloc(num_vars_max+2, sizeof(char *));
- len_list = (int *)ecalloc(num_vars_max+2, sizeof(int));
- }
-#endif
zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
if (php_rfc1867_callback != NULL) {
@@ -880,7 +796,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
++cd;
}
- while (*cd && (pair = php_ap_getword(&cd, ';')))
+ while (*cd && (pair = getword(mbuff->input_encoding, &cd, ';' TSRMLS_CC)))
{
char *key = NULL, *word = pair;
@@ -889,18 +805,34 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
}
if (strchr(pair, '=')) {
- key = php_ap_getword(&pair, '=');
+ key = getword(mbuff->input_encoding, &pair, '=' TSRMLS_CC);
if (!strcasecmp(key, "name")) {
if (param) {
efree(param);
}
- param = php_ap_getword_conf(&pair TSRMLS_CC);
+ param = getword_conf(mbuff->input_encoding, pair TSRMLS_CC);
+ if (mbuff->input_encoding && internal_encoding) {
+ unsigned char *new_param;
+ size_t new_param_len;
+ if ((size_t)-1 != zend_multibyte_encoding_converter(&new_param, &new_param_len, (unsigned char *)param, strlen(param), internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
+ efree(param);
+ param = (char *)new_param;
+ }
+ }
} else if (!strcasecmp(key, "filename")) {
if (filename) {
efree(filename);
}
- filename = php_ap_getword_conf(&pair TSRMLS_CC);
+ filename = getword_conf(mbuff->input_encoding, pair TSRMLS_CC);
+ if (mbuff->input_encoding && internal_encoding) {
+ unsigned char *new_filename;
+ size_t new_filename_len;
+ if ((size_t)-1 != zend_multibyte_encoding_converter(&new_filename, &new_filename_len, (unsigned char *)filename, strlen(filename), internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
+ efree(filename);
+ filename = (char *)new_filename;
+ }
+ }
}
}
if (key) {
@@ -917,6 +849,17 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
if (!value) {
value = estrdup("");
+ value_len = 0;
+ }
+
+ if (mbuff->input_encoding && internal_encoding) {
+ unsigned char *new_value;
+ size_t new_value_len;
+ if ((size_t)-1 != zend_multibyte_encoding_converter(&new_value, &new_value_len, (unsigned char *)value, value_len, internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
+ efree(value);
+ value = (char *)new_value;
+ value_len = new_value_len;
+ }
}
if (++count <= PG(max_input_vars) && sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC)) {
@@ -936,21 +879,12 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
}
new_val_len = newlength;
}
-
-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
- if (php_mb_encoding_translation(TSRMLS_C)) {
- php_mb_gpc_stack_variable(param, value, &val_list, &len_list, &num_vars, &num_vars_max TSRMLS_CC);
- } else {
- safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
- }
-#else
safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
-#endif
} else {
if (count == PG(max_input_vars) + 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
}
-
+
if (php_rfc1867_callback != NULL) {
multipart_event_formdata event_formdata;
@@ -1054,7 +988,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
offset = 0;
end = 0;
-
+
if (!cancel_upload) {
/* only bother to open temp file if we have data */
blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
@@ -1089,12 +1023,12 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
}
}
- if (PG(upload_max_filesize) > 0 && (total_bytes+blen) > PG(upload_max_filesize)) {
+ if (PG(upload_max_filesize) > 0 && (long)(total_bytes+blen) > PG(upload_max_filesize)) {
#if DEBUG_FILE_UPLOAD
sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
#endif
cancel_upload = UPLOAD_ERROR_A;
- } else if (max_file_size && ((total_bytes+blen) > max_file_size)) {
+ } else if (max_file_size && ((long)(total_bytes+blen) > max_file_size)) {
#if DEBUG_FILE_UPLOAD
sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
#endif
@@ -1190,56 +1124,18 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
snprintf(lbuf, llen, "%s_name", param);
}
-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
- if (php_mb_encoding_translation(TSRMLS_C)) {
- if (num_vars >= num_vars_max) {
- php_mb_gpc_realloc_buffer(&val_list, &len_list, &num_vars_max, 1 TSRMLS_CC);
- }
- val_list[num_vars] = filename;
- len_list[num_vars] = strlen(filename);
- num_vars++;
- if (php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
- str_len = strlen(filename);
- php_mb_gpc_encoding_converter(&filename, &str_len, 1, NULL, NULL TSRMLS_CC);
- }
- s = php_mb_strrchr(filename, '\\' TSRMLS_CC);
- if ((tmp = php_mb_strrchr(filename, '/' TSRMLS_CC)) > s) {
- s = tmp;
- }
- num_vars--;
- goto filedone;
- }
-#endif
/* The \ check should technically be needed for win32 systems only where
* it is a valid path separator. However, IE in all it's wisdom always sends
* the full path of the file on the user's filesystem, which means that unless
* the user does basename() they get a bogus file name. Until IE's user base drops
* to nill or problem is fixed this code must remain enabled for all systems. */
- s = strrchr(filename, '\\');
- if ((tmp = strrchr(filename, '/')) > s) {
- s = tmp;
- }
-#ifdef PHP_WIN32
- if (PG(magic_quotes_gpc)) {
- if ((tmp = strrchr(s ? s : filename, '\'')) > s) {
- s = tmp;
- }
- if ((tmp = strrchr(s ? s : filename, '"')) > s) {
- s = tmp;
- }
+ s = _basename(internal_encoding, filename TSRMLS_CC);
+ if (!s) {
+ s = filename;
}
-#endif
-
-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
-filedone:
-#endif
if (!is_anonymous) {
- if (s && s >= filename) {
- safe_php_register_variable(lbuf, s+1, strlen(s+1), NULL, 0 TSRMLS_CC);
- } else {
- safe_php_register_variable(lbuf, filename, strlen(filename), NULL, 0 TSRMLS_CC);
- }
+ safe_php_register_variable(lbuf, s, strlen(s), NULL, 0 TSRMLS_CC);
}
/* Add $foo[name] */
@@ -1248,11 +1144,7 @@ filedone:
} else {
snprintf(lbuf, llen, "%s[name]", param);
}
- if (s && s >= filename) {
- register_http_post_files_variable(lbuf, s+1, http_post_files, 0 TSRMLS_CC);
- } else {
- register_http_post_files_variable(lbuf, filename, http_post_files, 0 TSRMLS_CC);
- }
+ register_http_post_files_variable(lbuf, s, http_post_files, 0 TSRMLS_CC);
efree(filename);
s = NULL;
@@ -1292,7 +1184,7 @@ filedone:
s = "";
{
- /* store temp_filename as-is (without magic_quotes_gpc-ing it, in case upload_tmp_dir
+ /* store temp_filename as-is (in case upload_tmp_dir
* contains escapeable characters. escape only the variable name.) */
zval zfilename;
@@ -1368,7 +1260,32 @@ fileupload_done:
php_rfc1867_callback(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC);
}
- SAFE_RETURN;
+ if (lbuf) efree(lbuf);
+ if (abuf) efree(abuf);
+ if (array_index) efree(array_index);
+ zend_hash_destroy(&PG(rfc1867_protected_variables));
+ zend_llist_destroy(&header);
+ if (mbuff->boundary_next) efree(mbuff->boundary_next);
+ if (mbuff->boundary) efree(mbuff->boundary);
+ if (mbuff->buffer) efree(mbuff->buffer);
+ if (mbuff) efree(mbuff);
+}
+/* }}} */
+
+SAPI_API void php_rfc1867_set_multibyte_callbacks(
+ php_rfc1867_encoding_translation_t encoding_translation,
+ php_rfc1867_get_detect_order_t get_detect_order,
+ php_rfc1867_set_input_encoding_t set_input_encoding,
+ php_rfc1867_getword_t getword,
+ php_rfc1867_getword_conf_t getword_conf,
+ php_rfc1867_basename_t basename) /* {{{ */
+{
+ php_rfc1867_encoding_translation = encoding_translation;
+ php_rfc1867_get_detect_order = get_detect_order;
+ php_rfc1867_set_input_encoding = set_input_encoding;
+ php_rfc1867_getword = getword;
+ php_rfc1867_getword_conf = getword_conf;
+ php_rfc1867_basename = basename;
}
/* }}} */
diff --git a/main/rfc1867.h b/main/rfc1867.h
index 7f6c48905c..618458be34 100644
--- a/main/rfc1867.h
+++ b/main/rfc1867.h
@@ -67,10 +67,25 @@ typedef struct _multipart_event_end {
size_t post_bytes_processed;
} multipart_event_end;
+typedef int (*php_rfc1867_encoding_translation_t)(TSRMLS_D);
+typedef void (*php_rfc1867_get_detect_order_t)(const zend_encoding ***list, size_t *list_size TSRMLS_DC);
+typedef void (*php_rfc1867_set_input_encoding_t)(const zend_encoding *encoding TSRMLS_DC);
+typedef char* (*php_rfc1867_getword_t)(const zend_encoding *encoding, char **line, char stop TSRMLS_DC);
+typedef char* (*php_rfc1867_getword_conf_t)(const zend_encoding *encoding, char *str TSRMLS_DC);
+typedef char* (*php_rfc1867_basename_t)(const zend_encoding *encoding, char *str TSRMLS_DC);
+
SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler);
void destroy_uploaded_files_hash(TSRMLS_D);
void php_rfc1867_register_constants(TSRMLS_D);
extern PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC);
+SAPI_API void php_rfc1867_set_multibyte_callbacks(
+ php_rfc1867_encoding_translation_t encoding_translation,
+ php_rfc1867_get_detect_order_t get_detect_order,
+ php_rfc1867_set_input_encoding_t set_input_encoding,
+ php_rfc1867_getword_t getword,
+ php_rfc1867_getword_conf_t getword_conf,
+ php_rfc1867_basename_t basename);
+
#endif /* RFC1867_H */
diff --git a/main/safe_mode.c b/main/safe_mode.c
deleted file mode 100644
index 889becb853..0000000000
--- a/main/safe_mode.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2012 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
- +----------------------------------------------------------------------+
- */
-
-/* $Id$ */
-
-#include "php.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <sys/stat.h>
-#include "ext/standard/pageinfo.h"
-#include "safe_mode.h"
-#include "SAPI.h"
-#include "php_globals.h"
-
-/*
- * php_checkuid
- *
- * This function has six modes:
- *
- * 0 - return invalid (0) if file does not exist
- * 1 - return valid (1) if file does not exist
- * 2 - if file does not exist, check directory
- * 3 - only check directory (needed for mkdir)
- * 4 - check mode and param
- * 5 - only check file
- */
-
-PHPAPI int php_checkuid_ex(const char *filename, const char *fopen_mode, int mode, int flags)
-{
- struct stat sb;
- int ret, nofile=0;
- long uid=0L, gid=0L, duid=0L, dgid=0L;
- char path[MAXPATHLEN];
- char *s, filenamecopy[MAXPATHLEN];
- TSRMLS_FETCH();
-
- path[0] = '\0';
-
- if (!filename) {
- return 0; /* path must be provided */
- }
-
- if (strlcpy(filenamecopy, filename, MAXPATHLEN)>=MAXPATHLEN) {
- return 0;
- }
- filename=(char *)&filenamecopy;
-
- if (fopen_mode) {
- if (fopen_mode[0] == 'r') {
- mode = CHECKUID_DISALLOW_FILE_NOT_EXISTS;
- } else {
- mode = CHECKUID_CHECK_FILE_AND_DIR;
- }
- }
-
- /* First we see if the file is owned by the same user...
- * If that fails, passthrough and check directory...
- */
- if (mode != CHECKUID_ALLOW_ONLY_DIR) {
-#if HAVE_BROKEN_GETCWD
- char ftest[MAXPATHLEN];
-
- strcpy(ftest, filename);
- if (VCWD_GETCWD(ftest, sizeof(ftest)) == NULL) {
- strcpy(path, filename);
- } else
-#endif
- expand_filepath(filename, path TSRMLS_CC);
-
- ret = VCWD_STAT(path, &sb);
- if (ret < 0) {
- if (mode == CHECKUID_DISALLOW_FILE_NOT_EXISTS) {
- if ((flags & CHECKUID_NO_ERRORS) == 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
- }
- return 0;
- } else if (mode == CHECKUID_ALLOW_FILE_NOT_EXISTS) {
- if ((flags & CHECKUID_NO_ERRORS) == 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
- }
- return 1;
- }
- nofile = 1;
- } else {
- uid = sb.st_uid;
- gid = sb.st_gid;
- if (uid == php_getuid()) {
- return 1;
- } else if (PG(safe_mode_gid) && gid == php_getgid()) {
- return 1;
- }
- }
-
- /* Trim off filename */
- if ((s = strrchr(path, DEFAULT_SLASH))) {
- if (*(s + 1) == '\0' && s != path) { /* make sure that the / is not the last character */
- *s = '\0';
- s = strrchr(path, DEFAULT_SLASH);
- }
- if (s) {
- if (s == path) {
- path[1] = '\0';
- } else {
- *s = '\0';
- }
- }
- }
- } else { /* CHECKUID_ALLOW_ONLY_DIR */
- s = strrchr(filename, DEFAULT_SLASH);
-
- if (s == filename) {
- /* root dir */
- path[0] = DEFAULT_SLASH;
- path[1] = '\0';
- } else if (s && *(s + 1) != '\0') { /* make sure that the / is not the last character */
- *s = '\0';
- VCWD_REALPATH(filename, path);
- *s = DEFAULT_SLASH;
- } else {
- /* Under Solaris, getcwd() can fail if there are no
- * read permissions on a component of the path, even
- * though it has the required x permissions */
- path[0] = '.';
- path[1] = '\0';
- VCWD_GETCWD(path, sizeof(path));
- }
- } /* end CHECKUID_ALLOW_ONLY_DIR */
-
- if (mode != CHECKUID_ALLOW_ONLY_FILE) {
- /* check directory */
- ret = VCWD_STAT(path, &sb);
- if (ret < 0) {
- if ((flags & CHECKUID_NO_ERRORS) == 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
- }
- return 0;
- }
- duid = sb.st_uid;
- dgid = sb.st_gid;
- if (duid == php_getuid()) {
- return 1;
- } else if (PG(safe_mode_gid) && dgid == php_getgid()) {
- return 1;
- } else {
- if (SG(rfc1867_uploaded_files)) {
- if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) {
- return 1;
- }
- }
- }
- }
-
- if (mode == CHECKUID_ALLOW_ONLY_DIR) {
- uid = duid;
- gid = dgid;
- if (s) {
- *s = 0;
- }
- }
-
- if (nofile) {
- uid = duid;
- gid = dgid;
- filename = path;
- }
-
- if ((flags & CHECKUID_NO_ERRORS) == 0) {
- if (PG(safe_mode_gid)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "SAFE MODE Restriction in effect. The script whose uid/gid is %ld/%ld is not allowed to access %s owned by uid/gid %ld/%ld", php_getuid(), php_getgid(), filename, uid, gid);
- } else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "SAFE MODE Restriction in effect. The script whose uid is %ld is not allowed to access %s owned by uid %ld", php_getuid(), filename, uid);
- }
- }
-
- return 0;
-}
-
-PHPAPI int php_checkuid(const char *filename, const char *fopen_mode, int mode)
-{
-#ifdef NETWARE
-/* NetWare don't have uid*/
- return 1;
-#else
- return php_checkuid_ex(filename, fopen_mode, mode, 0);
-#endif
-}
-
-PHPAPI char *php_get_current_user(void)
-{
- struct stat *pstat;
- TSRMLS_FETCH();
-
- if (SG(request_info).current_user) {
- return SG(request_info).current_user;
- }
-
- /* FIXME: I need to have this somehow handled if
- USE_SAPI is defined, because cgi will also be
- interfaced in USE_SAPI */
-
- pstat = sapi_get_stat(TSRMLS_C);
-
- if (!pstat) {
- return "";
- } else {
-#ifdef PHP_WIN32
- char name[256];
- DWORD len = sizeof(name)-1;
-
- if (!GetUserName(name, &len)) {
- return "";
- }
- name[len] = '\0';
- SG(request_info).current_user_length = len;
- SG(request_info).current_user = estrndup(name, len);
- return SG(request_info).current_user;
-#else
- struct passwd *pwd;
-#if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
- struct passwd _pw;
- struct passwd *retpwptr = NULL;
- int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
- char *pwbuf;
-
- if (pwbuflen < 1) {
- return "";
- }
- pwbuf = emalloc(pwbuflen);
- if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) {
- efree(pwbuf);
- return "";
- }
- pwd = &_pw;
-#else
- if ((pwd=getpwuid(pstat->st_uid))==NULL) {
- return "";
- }
-#endif
- SG(request_info).current_user_length = strlen(pwd->pw_name);
- SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length);
-#if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
- efree(pwbuf);
-#endif
- return SG(request_info).current_user;
-#endif
- }
-}
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */
diff --git a/main/safe_mode.h b/main/safe_mode.h
deleted file mode 100644
index 2b21960c4a..0000000000
--- a/main/safe_mode.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2012 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id$ */
-
-#ifndef SAFE_MODE_H
-#define SAFE_MODE_H
-
-/* mode's for php_checkuid() */
-#define CHECKUID_DISALLOW_FILE_NOT_EXISTS 0
-#define CHECKUID_ALLOW_FILE_NOT_EXISTS 1
-#define CHECKUID_CHECK_FILE_AND_DIR 2
-#define CHECKUID_ALLOW_ONLY_DIR 3
-#define CHECKUID_CHECK_MODE_PARAM 4
-#define CHECKUID_ALLOW_ONLY_FILE 5
-
-/* flags for php_checkuid_ex() */
-#define CHECKUID_NO_ERRORS 0x01
-
-BEGIN_EXTERN_C()
-PHPAPI int php_checkuid(const char *filename, const char *fopen_mode, int mode);
-PHPAPI int php_checkuid_ex(const char *filename, const char *fopen_mode, int mode, int flags);
-PHPAPI char *php_get_current_user(void);
-END_EXTERN_C()
-
-#endif
diff --git a/main/snprintf.c b/main/snprintf.c
index 1e0e45510d..bda110d339 100644
--- a/main/snprintf.c
+++ b/main/snprintf.c
@@ -18,7 +18,7 @@
/* $Id$ */
-
+#define _GNU_SOURCE
#include "php.h"
#include <zend_strtod.h>
@@ -1222,7 +1222,7 @@ static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_
PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{ */
{
- int cc;
+ unsigned int cc;
va_list ap;
va_start(ap, format);
@@ -1238,7 +1238,7 @@ PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{
PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
{
- int cc;
+ unsigned int cc;
strx_printv(&cc, buf, len, format, ap);
if (cc >= len) {
diff --git a/main/spprintf.c b/main/spprintf.c
index e3c18abe4a..ef51cc5f41 100644
--- a/main/spprintf.c
+++ b/main/spprintf.c
@@ -123,7 +123,7 @@
* NDIG = 320
* NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
*/
-#define NUM_BUF_SIZE 2048
+#define NUM_BUF_SIZE 2048
/*
* The INS_CHAR macro inserts a character in the buffer.
diff --git a/main/streams/cast.c b/main/streams/cast.c
index 0dcdddac3c..da56e86679 100644
--- a/main/streams/cast.c
+++ b/main/streams/cast.c
@@ -271,7 +271,7 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show
newstream = php_stream_fopen_tmpfile();
if (newstream) {
- size_t retcopy = php_stream_copy_to_stream_ex(stream, newstream, PHP_STREAM_COPY_ALL, NULL);
+ int retcopy = php_stream_copy_to_stream_ex(stream, newstream, PHP_STREAM_COPY_ALL, NULL);
if (retcopy != SUCCESS) {
php_stream_close(newstream);
diff --git a/main/streams/glob_wrapper.c b/main/streams/glob_wrapper.c
index 4a35153722..7b568501ee 100644
--- a/main/streams/glob_wrapper.c
+++ b/main/streams/glob_wrapper.c
@@ -145,7 +145,7 @@ static size_t php_glob_stream_read(php_stream *stream, char *buf, size_t count T
/* avoid problems if someone mis-uses the stream */
if (count == sizeof(php_stream_dirent) && pglob) {
- if (pglob->index < pglob->glob.gl_pathc) {
+ if (pglob->index < (size_t)pglob->glob.gl_pathc) {
php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[pglob->index++], pglob->flags & GLOB_APPEND, &path TSRMLS_CC);
PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
return sizeof(php_stream_dirent);
diff --git a/main/streams/memory.c b/main/streams/memory.c
index 7a78d55c41..9e0fae6d1e 100644
--- a/main/streams/memory.c
+++ b/main/streams/memory.c
@@ -42,7 +42,6 @@ typedef struct {
size_t fsize;
size_t smax;
int mode;
- php_stream **owner_ptr;
} php_stream_memory_data;
@@ -112,9 +111,6 @@ static int php_stream_memory_close(php_stream *stream, int close_handle TSRMLS_D
if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) {
efree(ms->data);
}
- if (ms->owner_ptr) {
- *ms->owner_ptr = NULL;
- }
efree(ms);
return 0;
}
@@ -301,7 +297,6 @@ PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC)
self->fsize = 0;
self->smax = ~0u;
self->mode = mode;
- self->owner_ptr = NULL;
stream = php_stream_alloc_rel(&php_stream_memory_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b");
stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
@@ -376,8 +371,9 @@ static size_t php_stream_temp_write(php_stream *stream, const char *buf, size_t
if (memsize + count >= ts->smax) {
php_stream *file = php_stream_fopen_tmpfile();
php_stream_write(file, membuf, memsize);
- php_stream_close(ts->innerstream);
+ php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
ts->innerstream = file;
+ php_stream_encloses(stream, ts->innerstream);
}
}
return php_stream_write(ts->innerstream, buf, count);
@@ -415,7 +411,7 @@ static int php_stream_temp_close(php_stream *stream, int close_handle TSRMLS_DC)
assert(ts != NULL);
if (ts->innerstream) {
- ret = php_stream_free(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE));
+ ret = php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE));
} else {
ret = 0;
}
@@ -499,9 +495,10 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret TSRML
file = php_stream_fopen_tmpfile();
php_stream_write(file, membuf, memsize);
pos = php_stream_tell(ts->innerstream);
-
- php_stream_close(ts->innerstream);
+
+ php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
ts->innerstream = file;
+ php_stream_encloses(stream, ts->innerstream);
php_stream_seek(ts->innerstream, pos, SEEK_SET);
return php_stream_cast(ts->innerstream, castas, ret, 1);
@@ -563,8 +560,7 @@ PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STR
stream = php_stream_alloc_rel(&php_stream_temp_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b");
stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
self->innerstream = php_stream_memory_create_rel(mode);
- php_stream_auto_cleanup(self->innerstream); /* do not warn if innerstream is GC'ed before stream */
- ((php_stream_memory_data*)self->innerstream->abstract)->owner_ptr = &self->innerstream;
+ php_stream_encloses(stream, self->innerstream);
return stream;
}
diff --git a/main/streams/php_stream_context.h b/main/streams/php_stream_context.h
index a0500db2bd..5767b74d26 100644
--- a/main/streams/php_stream_context.h
+++ b/main/streams/php_stream_context.h
@@ -33,10 +33,10 @@ typedef void (*php_stream_notification_func)(php_stream_context *context,
If no context was passed, use the default context
The default context has not yet been created, do it now. */
#define php_stream_context_from_zval(zcontext, nocontext) ( \
- (zcontext) ? zend_fetch_resource(&(zcontext) TSRMLS_CC, -1, "Stream-Context", NULL, 1, php_le_stream_context()) : \
+ (zcontext) ? zend_fetch_resource(&(zcontext) TSRMLS_CC, -1, "Stream-Context", NULL, 1, php_le_stream_context(TSRMLS_C)) : \
(nocontext) ? NULL : \
FG(default_context) ? FG(default_context) : \
- (FG(default_context) = php_stream_context_alloc()) )
+ (FG(default_context) = php_stream_context_alloc(TSRMLS_C)) )
#define php_stream_context_to_zval(context, zval) { ZVAL_RESOURCE(zval, (context)->rsrc_id); zend_list_addref((context)->rsrc_id); }
@@ -59,7 +59,7 @@ struct _php_stream_context {
BEGIN_EXTERN_C()
PHPAPI void php_stream_context_free(php_stream_context *context);
-PHPAPI php_stream_context *php_stream_context_alloc(void);
+PHPAPI php_stream_context *php_stream_context_alloc(TSRMLS_D);
PHPAPI int php_stream_context_get_option(php_stream_context *context,
const char *wrappername, const char *optionname, zval ***optionvalue);
PHPAPI int php_stream_context_set_option(php_stream_context *context,
diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c
index cd5f26148b..77e411377e 100644
--- a/main/streams/plain_wrapper.c
+++ b/main/streams/plain_wrapper.c
@@ -48,6 +48,11 @@
#define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC TSRMLS_CC)
#define php_stream_fopen_from_file_int_rel(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_REL_CC TSRMLS_CC)
+#if !defined(WINDOWS) && !defined(NETWARE)
+extern int php_get_uid_by_name(const char *name, uid_t *uid TSRMLS_DC);
+extern int php_get_gid_by_name(const char *name, gid_t *gid TSRMLS_DC);
+#endif
+
/* parse standard "fopen" modes into open() flags */
PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
{
@@ -108,7 +113,7 @@ typedef struct {
unsigned is_pipe:1; /* don't try and seek */
unsigned cached_fstat:1; /* sb is valid */
unsigned _reserved:29;
-
+
int lock_flag; /* stores the lock state */
char *temp_file_name; /* if non-null, this is the path to a temporary file that
* is to be deleted when the stream is closed */
@@ -134,7 +139,7 @@ static int do_fstat(php_stdio_stream_data *d, int force)
if (!d->cached_fstat || force) {
int fd;
int r;
-
+
PHP_STDIOP_GET_FD(fd, d);
r = fstat(fd, &d->sb);
d->cached_fstat = r == 0;
@@ -147,7 +152,7 @@ static int do_fstat(php_stdio_stream_data *d, int force)
static php_stream *_php_stream_fopen_from_fd_int(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC)
{
php_stdio_stream_data *self;
-
+
self = pemalloc_rel_orig(sizeof(*self), persistent_id);
memset(self, 0, sizeof(*self));
self->file = NULL;
@@ -156,14 +161,14 @@ static php_stream *_php_stream_fopen_from_fd_int(int fd, const char *mode, const
self->is_process_pipe = 0;
self->temp_file_name = NULL;
self->fd = fd;
-
+
return php_stream_alloc_rel(&php_stream_stdio_ops, self, persistent_id, mode);
}
static php_stream *_php_stream_fopen_from_file_int(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
{
php_stdio_stream_data *self;
-
+
self = emalloc_rel_orig(sizeof(*self));
memset(self, 0, sizeof(*self));
self->file = file;
@@ -208,7 +213,7 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC)
self->temp_file_name = opened_path;
self->lock_flag = LOCK_UN;
-
+
return stream;
}
close(fd);
@@ -241,7 +246,7 @@ PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const cha
}
}
#endif
-
+
if (self->is_pipe) {
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
} else {
@@ -280,7 +285,7 @@ PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STRE
}
}
#endif
-
+
if (self->is_pipe) {
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
} else {
@@ -349,9 +354,9 @@ static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS
so script can retry if desired */
ret = read(data->fd, buf, count);
}
-
+
stream->eof = (ret == 0 || (ret == (size_t)-1 && errno != EWOULDBLOCK && errno != EINTR && errno != EBADF));
-
+
} else {
#if HAVE_FLUSHIO
if (!data->is_pipe && data->last_op == 'w')
@@ -388,7 +393,7 @@ static int php_stdiop_close(php_stream *stream, int close_handle TSRMLS_DC)
data->file_mapping = NULL;
}
#endif
-
+
if (close_handle) {
if (data->file) {
if (data->is_process_pipe) {
@@ -458,14 +463,14 @@ static int php_stdiop_seek(php_stream *stream, off_t offset, int whence, off_t *
if (data->fd >= 0) {
off_t result;
-
+
result = lseek(data->fd, offset, whence);
if (result == (off_t)-1)
return -1;
*newoffset = result;
return 0;
-
+
} else {
ret = fseek(data->file, offset, whence);
*newoffset = ftell(data->file);
@@ -479,7 +484,7 @@ static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
assert(data != NULL);
-
+
/* as soon as someone touches the stdio layer, buffering may ensue,
* so we need to stop using the fd directly in that case */
@@ -497,7 +502,7 @@ static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
return FAILURE;
}
}
-
+
*(FILE**)ret = data->file;
data->fd = -1;
}
@@ -553,9 +558,9 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void
int flags;
int oldval;
#endif
-
+
PHP_STDIOP_GET_FD(fd, data);
-
+
switch(option) {
case PHP_STREAM_OPTION_BLOCKING:
if (fd == -1)
@@ -567,20 +572,20 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void
flags &= ~O_NONBLOCK;
else
flags |= O_NONBLOCK;
-
+
if (-1 == fcntl(fd, F_SETFL, flags))
return -1;
return oldval;
#else
return -1; /* not yet implemented */
#endif
-
+
case PHP_STREAM_OPTION_WRITE_BUFFER:
if (data->file == NULL) {
return -1;
}
-
+
if (ptrparam)
size = *(size_t *)ptrparam;
else
@@ -588,22 +593,19 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void
switch(value) {
case PHP_STREAM_BUFFER_NONE:
- stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
return setvbuf(data->file, NULL, _IONBF, 0);
-
+
case PHP_STREAM_BUFFER_LINE:
- stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
return setvbuf(data->file, NULL, _IOLBF, size);
-
+
case PHP_STREAM_BUFFER_FULL:
- stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
return setvbuf(data->file, NULL, _IOFBF, size);
default:
return -1;
}
break;
-
+
case PHP_STREAM_OPTION_LOCKING:
if (fd == -1) {
return -1;
@@ -626,7 +628,7 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void
{
php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam;
int prot, flags;
-
+
switch (value) {
case PHP_STREAM_MMAP_SUPPORTED:
return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
@@ -791,7 +793,7 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void
return ftruncate(fd, new_size) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
}
}
-
+
default:
return PHP_STREAM_OPTION_RETURN_NOTIMPL;
}
@@ -864,11 +866,7 @@ static php_stream *php_plain_files_dir_opener(php_stream_wrapper *wrapper, char
if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
return NULL;
}
-
- if (PG(safe_mode) &&(!php_checkuid(path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
- return NULL;
- }
-
+
dir = VCWD_OPENDIR(path);
#ifdef PHP_WIN32
@@ -886,7 +884,7 @@ static php_stream *php_plain_files_dir_opener(php_stream_wrapper *wrapper, char
if (stream == NULL)
closedir(dir);
}
-
+
return stream;
}
/* }}} */
@@ -934,7 +932,7 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, cha
return ret;
}
}
-
+
fd = open(realpath, open_flags, 0666);
if (fd != -1) {
@@ -998,28 +996,14 @@ static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, ch
return NULL;
}
- if ((php_check_safe_mode_include_dir(path TSRMLS_CC)) == 0) {
- return php_stream_fopen_rel(path, mode, opened_path, options);
- }
-
- if ((options & ENFORCE_SAFE_MODE) && PG(safe_mode) && (!php_checkuid(path, mode, CHECKUID_CHECK_MODE_PARAM)))
- return NULL;
-
return php_stream_fopen_rel(path, mode, opened_path, options);
}
static int php_plain_files_url_stater(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
{
- char *p;
- if ((p = strstr(url, "://")) != NULL) {
- if (p < strchr(url, '/')) {
- url = p + 3;
- }
- }
-
- if (PG(safe_mode) &&(!php_checkuid_ex(url, NULL, CHECKUID_CHECK_FILE_AND_DIR, (flags & PHP_STREAM_URL_STAT_QUIET) ? CHECKUID_NO_ERRORS : 0))) {
- return -1;
+ if (strncmp(url, "file://", sizeof("file://") - 1) == 0) {
+ url += sizeof("file://") - 1;
}
if (php_check_open_basedir_ex(url, (flags & PHP_STREAM_URL_STAT_QUIET) ? 0 : 1 TSRMLS_CC)) {
@@ -1048,19 +1032,11 @@ static int php_plain_files_unlink(php_stream_wrapper *wrapper, char *url, int op
int ret;
if ((p = strstr(url, "://")) != NULL) {
- if (p < strchr(url, '/')) {
- url = p + 3;
- }
+ url = p + 3;
}
- if (options & ENFORCE_SAFE_MODE) {
- if (PG(safe_mode) && !php_checkuid(url, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
- return 0;
- }
-
- if (php_check_open_basedir(url TSRMLS_CC)) {
- return 0;
- }
+ if (php_check_open_basedir(url TSRMLS_CC)) {
+ return 0;
}
ret = VCWD_UNLINK(url);
@@ -1098,20 +1074,11 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, char *url_from, c
#endif
if ((p = strstr(url_from, "://")) != NULL) {
- if (p < strchr(url_from, '/')) {
- url_from = p + 3;
- }
+ url_from = p + 3;
}
if ((p = strstr(url_to, "://")) != NULL) {
- if (p < strchr(url_to, '/')) {
- url_to = p + 3;
- }
- }
-
- if (PG(safe_mode) && (!php_checkuid(url_from, NULL, CHECKUID_CHECK_FILE_AND_DIR) ||
- !php_checkuid(url_to, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
- return 0;
+ url_to = p + 3;
}
if (php_check_open_basedir(url_from TSRMLS_CC) || php_check_open_basedir(url_to TSRMLS_CC)) {
@@ -1177,40 +1144,32 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, char *dir, int mod
char *p;
if ((p = strstr(dir, "://")) != NULL) {
- if (p < strchr(dir, '/')) {
- dir = p + 3;
- }
+ dir = p + 3;
}
if (!recursive) {
ret = php_mkdir(dir, mode TSRMLS_CC);
} else {
/* we look for directory separator from the end of string, thus hopefuly reducing our work load */
- char *e, *buf;
+ char *e;
struct stat sb;
int dir_len = strlen(dir);
int offset = 0;
+ char buf[MAXPATHLEN];
- buf = estrndup(dir, dir_len);
-
-#ifdef PHP_WIN32
- e = buf;
- while (*e) {
- if (*e == '/') {
- *e = DEFAULT_SLASH;
- }
- e++;
+ if (!expand_filepath_with_mode(dir, buf, NULL, 0, CWD_EXPAND TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path");
+ return 0;
}
-#else
- e = buf + dir_len;
-#endif
+
+ e = buf + strlen(buf);
if ((p = memchr(buf, DEFAULT_SLASH, dir_len))) {
offset = p - buf + 1;
}
if (p && dir_len == 1) {
- /* buf == "DEFAULT_SLASH" */
+ /* buf == "DEFAULT_SLASH" */
}
else {
/* find a top level directory we need to create */
@@ -1255,7 +1214,6 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, char *dir, int mod
}
}
}
- efree(buf);
}
if (ret < 0) {
/* Failure */
@@ -1271,10 +1229,6 @@ static int php_plain_files_rmdir(php_stream_wrapper *wrapper, char *url, int opt
#if PHP_WIN32
int url_len = strlen(url);
#endif
- if (PG(safe_mode) &&(!php_checkuid(url, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
- return 0;
- }
-
if (php_check_open_basedir(url TSRMLS_CC)) {
return 0;
}
@@ -1297,6 +1251,92 @@ static int php_plain_files_rmdir(php_stream_wrapper *wrapper, char *url, int opt
return 1;
}
+static int php_plain_files_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC)
+{
+ struct utimbuf *newtime;
+ char *p;
+#if !defined(WINDOWS) && !defined(NETWARE)
+ uid_t uid;
+ gid_t gid;
+#endif
+ mode_t mode;
+ int ret = 0;
+#if PHP_WIN32
+ int url_len = strlen(url);
+#endif
+
+#if PHP_WIN32
+ if (!php_win32_check_trailing_space(url, url_len)) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(ENOENT));
+ return 0;
+ }
+#endif
+
+ if ((p = strstr(url, "://")) != NULL) {
+ url = p + 3;
+ }
+
+ if (php_check_open_basedir(url TSRMLS_CC)) {
+ return 0;
+ }
+
+ switch(option) {
+ case PHP_STREAM_META_TOUCH:
+ newtime = (struct utimbuf *)value;
+ if (VCWD_ACCESS(url, F_OK) != 0) {
+ FILE *file = VCWD_FOPEN(url, "w");
+ if (file == NULL) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to create file %s because %s", url, strerror(errno));
+ return 0;
+ }
+ fclose(file);
+ }
+
+ ret = VCWD_UTIME(url, newtime);
+ break;
+#if !defined(WINDOWS) && !defined(NETWARE)
+ case PHP_STREAM_META_OWNER_NAME:
+ case PHP_STREAM_META_OWNER:
+ if(option == PHP_STREAM_META_OWNER_NAME) {
+ if(php_get_uid_by_name((char *)value, &uid TSRMLS_CC) != SUCCESS) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to find uid for %s", (char *)value);
+ return 0;
+ }
+ } else {
+ uid = (uid_t)*(long *)value;
+ }
+ ret = VCWD_CHOWN(url, uid, -1);
+ break;
+ case PHP_STREAM_META_GROUP:
+ case PHP_STREAM_META_GROUP_NAME:
+ if(option == PHP_STREAM_META_OWNER_NAME) {
+ if(php_get_gid_by_name((char *)value, &gid TSRMLS_CC) != SUCCESS) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to find gid for %s", (char *)value);
+ return 0;
+ }
+ } else {
+ gid = (gid_t)*(long *)value;
+ }
+ ret = VCWD_CHOWN(url, -1, gid);
+ break;
+#endif
+ case PHP_STREAM_META_ACCESS:
+ mode = (mode_t)*(long *)value;
+ ret = VCWD_CHMOD(url, mode);
+ break;
+ default:
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unknown option %d for stream_metadata", option);
+ return 0;
+ }
+ if (ret == -1) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Operation failed: %s", strerror(errno));
+ return 0;
+ }
+ php_clear_stat_cache(0, NULL, 0 TSRMLS_CC);
+ return 1;
+}
+
+
static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
php_plain_files_stream_opener,
NULL,
@@ -1307,7 +1347,8 @@ static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
php_plain_files_unlink,
php_plain_files_rename,
php_plain_files_mkdir,
- php_plain_files_rmdir
+ php_plain_files_rmdir,
+ php_plain_files_metadata
};
php_stream_wrapper php_plain_files_wrapper = {
@@ -1321,7 +1362,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char
{
/* code ripped off from fopen_wrappers.c */
char *pathbuf, *ptr, *end;
- char *exec_fname;
+ const char *exec_fname;
char trypath[MAXPATHLEN];
php_stream *stream;
int path_length;
@@ -1354,17 +1395,9 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char
return NULL;
}
- if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
- return NULL;
- }
return php_stream_fopen_rel(filename, mode, opened_path, options);
}
- /*
- * files in safe_mode_include_dir (or subdir) are excluded from
- * safe mode GID/UID checks
- */
-
not_relative_path:
/* Absolute path open */
@@ -1374,16 +1407,9 @@ not_relative_path:
return NULL;
}
- if ((php_check_safe_mode_include_dir(filename TSRMLS_CC)) == 0)
- /* filename is in safe_mode_include_dir (or subdir) */
- return php_stream_fopen_rel(filename, mode, opened_path, options);
-
- if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM)))
- return NULL;
-
return php_stream_fopen_rel(filename, mode, opened_path, options);
}
-
+
#ifdef PHP_WIN32
if (IS_SLASH(filename[0])) {
size_t cwd_len;
@@ -1391,31 +1417,22 @@ not_relative_path:
cwd = virtual_getcwd_ex(&cwd_len TSRMLS_CC);
/* getcwd() will return always return [DRIVE_LETTER]:/) on windows. */
*(cwd+3) = '\0';
-
+
if (snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename) >= MAXPATHLEN) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN);
}
-
+
free(cwd);
-
+
if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(trypath TSRMLS_CC)) {
return NULL;
}
- if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC)) == 0) {
- return php_stream_fopen_rel(trypath, mode, opened_path, options);
- }
- if (PG(safe_mode) && (!php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM))) {
- return NULL;
- }
-
+
return php_stream_fopen_rel(trypath, mode, opened_path, options);
}
#endif
if (!path || (path && !*path)) {
- if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) {
- return NULL;
- }
return php_stream_fopen_rel(filename, mode, opened_path, options);
}
@@ -1462,24 +1479,9 @@ not_relative_path:
if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir_ex(trypath, 0 TSRMLS_CC)) {
goto stream_skip;
}
-
- if (PG(safe_mode)) {
- struct stat sb;
- if (VCWD_STAT(trypath, &sb) == 0) {
- /* file exists ... check permission */
- if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC) == 0) ||
- php_checkuid_ex(trypath, mode, CHECKUID_CHECK_MODE_PARAM, CHECKUID_NO_ERRORS)) {
- /* UID ok, or trypath is in safe_mode_include_dir */
- stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
- goto stream_done;
- }
- }
- goto stream_skip;
- }
stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
if (stream) {
-stream_done:
efree(pathbuf);
return stream;
}
diff --git a/main/streams/streams.c b/main/streams/streams.c
index dfd60940fc..e9c2e07320 100644
--- a/main/streams/streams.c
+++ b/main/streams/streams.c
@@ -105,6 +105,15 @@ PHP_RSHUTDOWN_FUNCTION(streams)
return SUCCESS;
}
+PHPAPI php_stream *php_stream_encloses(php_stream *enclosing, php_stream *enclosed)
+{
+ php_stream *orig = enclosed->enclosing_stream;
+
+ php_stream_auto_cleanup(enclosed);
+ enclosed->enclosing_stream = enclosing;
+ return orig;
+}
+
PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC)
{
zend_rsrc_list_entry *le;
@@ -324,19 +333,56 @@ fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persiste
ret->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, ret, persistent_id ? le_pstream : le_stream);
strlcpy(ret->mode, mode, sizeof(ret->mode));
+ ret->wrapper = NULL;
+ ret->wrapperthis = NULL;
+ ret->wrapperdata = NULL;
+ ret->stdiocast = NULL;
+ ret->orig_path = NULL;
+ ret->context = NULL;
+ ret->readbuf = NULL;
+ ret->enclosing_stream = NULL;
+
return ret;
}
/* }}} */
+PHPAPI int _php_stream_free_enclosed(php_stream *stream_enclosed, int close_options TSRMLS_DC) /* {{{ */
+{
+ return _php_stream_free(stream_enclosed,
+ close_options | PHP_STREAM_FREE_IGNORE_ENCLOSING TSRMLS_CC);
+}
+/* }}} */
+
+#if STREAM_DEBUG
+static const char *_php_stream_pretty_free_options(int close_options, char *out)
+{
+ if (close_options & PHP_STREAM_FREE_CALL_DTOR)
+ strcat(out, "CALL_DTOR, ");
+ if (close_options & PHP_STREAM_FREE_RELEASE_STREAM)
+ strcat(out, "RELEASE_STREAM, ");
+ if (close_options & PHP_STREAM_FREE_PRESERVE_HANDLE)
+ strcat(out, "PREVERSE_HANDLE, ");
+ if (close_options & PHP_STREAM_FREE_RSRC_DTOR)
+ strcat(out, "RSRC_DTOR, ");
+ if (close_options & PHP_STREAM_FREE_PERSISTENT)
+ strcat(out, "PERSISTENT, ");
+ if (close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING)
+ strcat(out, "IGNORE_ENCLOSING, ");
+ if (out[0] != '\0')
+ out[strlen(out) - 2] = '\0';
+ return out;
+}
+#endif
+
static int _php_stream_free_persistent(zend_rsrc_list_entry *le, void *pStream TSRMLS_DC)
{
return le->ptr == pStream;
}
+
PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* {{{ */
{
int ret = 1;
- int remove_rsrc = 1;
int preserve_handle = close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 1 : 0;
int release_cast = 1;
php_stream_context *context = NULL;
@@ -353,16 +399,40 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /*
}
#if STREAM_DEBUG
-fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%08x\n", stream->ops->label, stream, stream->orig_path, stream->in_free, close_options);
+ {
+ char out[200] = "";
+ fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%s\n",
+ stream->ops->label, stream, stream->orig_path, stream->in_free, _php_stream_pretty_free_options(close_options, out));
+ }
+
#endif
- /* recursion protection */
if (stream->in_free) {
- return 1;
+ /* hopefully called recursively from the enclosing stream; the pointer was NULLed below */
+ if ((stream->in_free == 1) && (close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) && (stream->enclosing_stream == NULL)) {
+ close_options |= PHP_STREAM_FREE_RSRC_DTOR; /* restore flag */
+ } else {
+ return 1; /* recursion protection */
+ }
}
stream->in_free++;
+ /* force correct order on enclosing/enclosed stream destruction (only from resource
+ * destructor as in when reverse destroying the resource list) */
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) &&
+ !(close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) &&
+ (close_options & (PHP_STREAM_FREE_CALL_DTOR | PHP_STREAM_FREE_RELEASE_STREAM)) && /* always? */
+ (stream->enclosing_stream != NULL)) {
+ php_stream *enclosing_stream = stream->enclosing_stream;
+ stream->enclosing_stream = NULL;
+ /* we force PHP_STREAM_CALL_DTOR because that's from where the
+ * enclosing stream can free this stream. We remove rsrc_dtor because
+ * we want the enclosing stream to be deleted from the resource list */
+ return _php_stream_free(enclosing_stream,
+ (close_options | PHP_STREAM_FREE_CALL_DTOR) & ~PHP_STREAM_FREE_RSRC_DTOR TSRMLS_CC);
+ }
+
/* if we are releasing the stream only (and preserving the underlying handle),
* we need to do things a little differently.
* We are only ever called like this when the stream is cast to a FILE*
@@ -383,14 +453,15 @@ fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%08x\n", stream->ops->la
#if STREAM_DEBUG
fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remove_rsrc=%d\n",
- stream->ops->label, stream, stream->orig_path, preserve_handle, release_cast, remove_rsrc);
+ stream->ops->label, stream, stream->orig_path, preserve_handle, release_cast,
+ (close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0);
#endif
/* make sure everything is saved */
_php_stream_flush(stream, 1 TSRMLS_CC);
/* If not called from the resource dtor, remove the stream from the resource list. */
- if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0 && remove_rsrc) {
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0) {
/* zend_list_delete actually only decreases the refcount; if we're
* releasing the stream, we want to actually delete the resource from
* the resource list, otherwise the resource will point to invalid memory.
@@ -1410,7 +1481,7 @@ PHPAPI size_t _php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen
}
/* Returns SUCCESS/FAILURE and sets *len to the number of bytes moved */
-PHPAPI size_t _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC)
+PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC)
{
char buf[CHUNK_SIZE];
size_t readchunk;
@@ -1811,7 +1882,7 @@ PHPAPI int _php_stream_mkdir(char *path, int mode, int options, php_stream_conte
{
php_stream_wrapper *wrapper = NULL;
- wrapper = php_stream_locate_url_wrapper(path, NULL, ENFORCE_SAFE_MODE TSRMLS_CC);
+ wrapper = php_stream_locate_url_wrapper(path, NULL, 0 TSRMLS_CC);
if (!wrapper || !wrapper->wops || !wrapper->wops->stream_mkdir) {
return 0;
}
@@ -1826,7 +1897,7 @@ PHPAPI int _php_stream_rmdir(char *path, int options, php_stream_context *contex
{
php_stream_wrapper *wrapper = NULL;
- wrapper = php_stream_locate_url_wrapper(path, NULL, ENFORCE_SAFE_MODE TSRMLS_CC);
+ wrapper = php_stream_locate_url_wrapper(path, NULL, 0 TSRMLS_CC);
if (!wrapper || !wrapper->wops || !wrapper->wops->stream_rmdir) {
return 0;
}
@@ -1855,7 +1926,7 @@ PHPAPI int _php_stream_stat_path(char *path, int flags, php_stream_statbuf *ssb,
}
}
- wrapper = php_stream_locate_url_wrapper(path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC);
+ wrapper = php_stream_locate_url_wrapper(path, &path_to_open, 0 TSRMLS_CC);
if (wrapper && wrapper->wops->url_stat) {
ret = wrapper->wops->url_stat(wrapper, path_to_open, flags, ssb, context TSRMLS_CC);
if (ret == 0) {
@@ -1940,7 +2011,6 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int optio
char *resolved_path = NULL;
char *copy_of_path = NULL;
-
if (opened_path) {
*opened_path = NULL;
}
@@ -2117,7 +2187,7 @@ PHPAPI void php_stream_context_free(php_stream_context *context)
efree(context);
}
-PHPAPI php_stream_context *php_stream_context_alloc(void)
+PHPAPI php_stream_context *php_stream_context_alloc(TSRMLS_D)
{
php_stream_context *context;
@@ -2126,7 +2196,7 @@ PHPAPI php_stream_context *php_stream_context_alloc(void)
MAKE_STD_ZVAL(context->options);
array_init(context->options);
- context->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, context, php_le_stream_context());
+ context->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, context, php_le_stream_context(TSRMLS_C));
return context;
}
@@ -2269,7 +2339,7 @@ PHPAPI int _php_stream_scandir(char *dirname, char **namelist[], int flags, php_
return FAILURE;
}
- stream = php_stream_opendir(dirname, ENFORCE_SAFE_MODE | REPORT_ERRORS, context);
+ stream = php_stream_opendir(dirname, REPORT_ERRORS, context);
if (!stream) {
return FAILURE;
}
@@ -2292,6 +2362,11 @@ PHPAPI int _php_stream_scandir(char *dirname, char **namelist[], int flags, php_
vector[nfiles] = estrdup(sdp.d_name);
nfiles++;
+ if(vector_size < 10 || nfiles == 0) {
+ /* overflow */
+ efree(vector);
+ return FAILURE;
+ }
}
php_stream_closedir(stream);
diff --git a/main/streams/userspace.c b/main/streams/userspace.c
index 8299cba43a..3b277160d6 100644
--- a/main/streams/userspace.c
+++ b/main/streams/userspace.c
@@ -26,6 +26,15 @@
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
+#include <stddef.h>
+
+#if HAVE_UTIME
+# ifdef PHP_WIN32
+# include <sys/utime.h>
+# else
+# include <utime.h>
+# endif
+#endif
static int le_protocols;
@@ -42,6 +51,7 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC);
static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC);
static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+static int user_wrapper_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC);
static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filename, char *mode,
int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
@@ -55,7 +65,8 @@ static php_stream_wrapper_ops user_stream_wops = {
user_wrapper_unlink,
user_wrapper_rename,
user_wrapper_mkdir,
- user_wrapper_rmdir
+ user_wrapper_rmdir,
+ user_wrapper_metadata
};
@@ -77,7 +88,6 @@ PHP_MINIT_FUNCTION(user_streams)
REGISTER_LONG_CONSTANT("STREAM_USE_PATH", USE_PATH, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("STREAM_IGNORE_URL", IGNORE_URL, CONST_CS|CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("STREAM_ENFORCE_SAFE_MODE", ENFORCE_SAFE_MODE, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("STREAM_REPORT_ERRORS", REPORT_ERRORS, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("STREAM_MUST_SEEK", STREAM_MUST_SEEK, CONST_CS|CONST_PERSISTENT);
@@ -99,6 +109,12 @@ PHP_MINIT_FUNCTION(user_streams)
REGISTER_LONG_CONSTANT("STREAM_CAST_AS_STREAM", PHP_STREAM_AS_STDIO, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("STREAM_CAST_FOR_SELECT", PHP_STREAM_AS_FD_FOR_SELECT, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_TOUCH", PHP_STREAM_META_TOUCH, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_OWNER", PHP_STREAM_META_OWNER, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_OWNER_NAME", PHP_STREAM_META_OWNER_NAME, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_GROUP", PHP_STREAM_META_GROUP, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_GROUP_NAME", PHP_STREAM_META_GROUP_NAME, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_ACCESS", PHP_STREAM_META_ACCESS, CONST_CS|CONST_PERSISTENT);
return SUCCESS;
}
@@ -130,35 +146,37 @@ typedef struct _php_userstream_data php_userstream_data_t;
#define USERSTREAM_LOCK "stream_lock"
#define USERSTREAM_CAST "stream_cast"
#define USERSTREAM_SET_OPTION "stream_set_option"
+#define USERSTREAM_TRUNCATE "stream_truncate"
+#define USERSTREAM_METADATA "stream_metadata"
/* {{{ class should have methods like these:
-
+
function stream_open($path, $mode, $options, &$opened_path)
{
return true/false;
}
-
+
function stream_read($count)
{
return false on error;
else return string;
}
-
+
function stream_write($data)
{
return false on error;
else return count written;
}
-
+
function stream_close()
{
}
-
+
function stream_flush()
{
return true/false;
}
-
+
function stream_seek($offset, $whence)
{
return true/false;
@@ -255,74 +273,55 @@ typedef struct _php_userstream_data php_userstream_data_t;
{
return true / false;
}
-
+
+ function stream_truncate($new_size)
+ {
+ return true / false;
+ }
+
}}} **/
-static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+static zval *user_stream_create_object(struct php_user_stream_wrapper *uwrap, php_stream_context *context TSRMLS_DC)
{
- struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
- php_userstream_data_t *us;
- zval *zfilename, *zmode, *zopened, *zoptions, *zretval = NULL, *zfuncname;
- zval **args[4];
- int call_result;
- php_stream *stream = NULL;
- zend_bool old_in_user_include;
+ zval *object;
+ /* create an instance of our class */
+ ALLOC_ZVAL(object);
+ object_init_ex(object, uwrap->ce);
+ Z_SET_REFCOUNT_P(object, 1);
+ Z_SET_ISREF_P(object);
- /* Try to catch bad usage without preventing flexibility */
- if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) {
- php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "infinite recursion prevented");
- return NULL;
- }
- FG(user_stream_current_filename) = filename;
-
- /* if the user stream was registered as local and we are in include context,
- we add allow_url_include restrictions to allow_url_fopen ones */
- /* we need only is_url == 0 here since if is_url == 1 and remote wrappers
- were restricted we wouldn't get here */
- old_in_user_include = PG(in_user_include);
- if(uwrap->wrapper.is_url == 0 &&
- (options & STREAM_OPEN_FOR_INCLUDE) &&
- !PG(allow_url_include)) {
- PG(in_user_include) = 1;
+ if (context) {
+ add_property_resource(object, "context", context->rsrc_id);
+ zend_list_addref(context->rsrc_id);
+ } else {
+ add_property_null(object, "context");
}
- us = emalloc(sizeof(*us));
- us->wrapper = uwrap;
-
- /* create an instance of our class */
- ALLOC_ZVAL(us->object);
- object_init_ex(us->object, uwrap->ce);
- Z_SET_REFCOUNT_P(us->object, 1);
- Z_SET_ISREF_P(us->object);
-
if (uwrap->ce->constructor) {
zend_fcall_info fci;
zend_fcall_info_cache fcc;
zval *retval_ptr;
-
+
fci.size = sizeof(fci);
fci.function_table = &uwrap->ce->function_table;
fci.function_name = NULL;
fci.symbol_table = NULL;
- fci.object_ptr = us->object;
+ fci.object_ptr = object;
fci.retval_ptr_ptr = &retval_ptr;
fci.param_count = 0;
fci.params = NULL;
fci.no_separation = 1;
-
+
fcc.initialized = 1;
fcc.function_handler = uwrap->ce->constructor;
fcc.calling_scope = EG(scope);
- fcc.called_scope = Z_OBJCE_P(us->object);
- fcc.object_ptr = us->object;
+ fcc.called_scope = Z_OBJCE_P(object);
+ fcc.object_ptr = object;
if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute %s::%s()", uwrap->ce->name, uwrap->ce->constructor->common.function_name);
- zval_dtor(us->object);
- FREE_ZVAL(us->object);
- efree(us);
- FG(user_stream_current_filename) = NULL;
- PG(in_user_include) = old_in_user_include;
+ zval_dtor(object);
+ FREE_ZVAL(object);
return NULL;
} else {
if (retval_ptr) {
@@ -330,14 +329,48 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
}
}
}
+ return object;
+}
- if (context) {
- add_property_resource(us->object, "context", context->rsrc_id);
- zend_list_addref(context->rsrc_id);
- } else {
- add_property_null(us->object, "context");
+static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ php_userstream_data_t *us;
+ zval *zfilename, *zmode, *zopened, *zoptions, *zretval = NULL, *zfuncname;
+ zval **args[4];
+ int call_result;
+ php_stream *stream = NULL;
+ zend_bool old_in_user_include;
+
+ /* Try to catch bad usage without preventing flexibility */
+ if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "infinite recursion prevented");
+ return NULL;
+ }
+ FG(user_stream_current_filename) = filename;
+
+ /* if the user stream was registered as local and we are in include context,
+ we add allow_url_include restrictions to allow_url_fopen ones */
+ /* we need only is_url == 0 here since if is_url == 1 and remote wrappers
+ were restricted we wouldn't get here */
+ old_in_user_include = PG(in_user_include);
+ if(uwrap->wrapper.is_url == 0 &&
+ (options & STREAM_OPEN_FOR_INCLUDE) &&
+ !PG(allow_url_include)) {
+ PG(in_user_include) = 1;
+ }
+
+ us = emalloc(sizeof(*us));
+ us->wrapper = uwrap;
+
+ us->object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(us->object == NULL) {
+ FG(user_stream_current_filename) = NULL;
+ PG(in_user_include) = old_in_user_include;
+ efree(us);
+ return NULL;
}
-
+
/* call it's stream_open method - set up params first */
MAKE_STD_ZVAL(zfilename);
ZVAL_STRING(zfilename, filename, 1);
@@ -359,14 +392,14 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_OPEN, 1);
-
+
call_result = call_user_function_ex(NULL,
&us->object,
zfuncname,
&zretval,
4, args,
0, NULL TSRMLS_CC);
-
+
if (call_result == SUCCESS && zretval != NULL && zval_is_true(zretval)) {
/* the stream is now open! */
stream = php_stream_alloc_rel(&php_stream_userspace_ops, us, 0, mode);
@@ -383,7 +416,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "\"%s::" USERSTREAM_OPEN "\" call failed",
us->wrapper->classname);
}
-
+
/* destroy everything else */
if (stream == NULL) {
zval_ptr_dtor(&us->object);
@@ -391,7 +424,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
}
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zopened);
zval_ptr_dtor(&zoptions);
@@ -399,7 +432,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena
zval_ptr_dtor(&zfilename);
FG(user_stream_current_filename) = NULL;
-
+
PG(in_user_include) = old_in_user_include;
return stream;
}
@@ -410,7 +443,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
php_userstream_data_t *us;
zval *zfilename, *zoptions, *zretval = NULL, *zfuncname;
- zval **args[2];
+ zval **args[2];
int call_result;
php_stream *stream = NULL;
@@ -420,23 +453,17 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
return NULL;
}
FG(user_stream_current_filename) = filename;
-
- us = emalloc(sizeof(*us));
- us->wrapper = uwrap;
- /* create an instance of our class */
- ALLOC_ZVAL(us->object);
- object_init_ex(us->object, uwrap->ce);
- Z_SET_REFCOUNT_P(us->object, 1);
- Z_SET_ISREF_P(us->object);
+ us = emalloc(sizeof(*us));
+ us->wrapper = uwrap;
- if (context) {
- add_property_resource(us->object, "context", context->rsrc_id);
- zend_list_addref(context->rsrc_id);
- } else {
- add_property_null(us->object, "context");
+ us->object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(us == NULL) {
+ FG(user_stream_current_filename) = NULL;
+ efree(us);
+ return NULL;
}
-
+
/* call it's dir_open method - set up params first */
MAKE_STD_ZVAL(zfilename);
ZVAL_STRING(zfilename, filename, 1);
@@ -448,14 +475,14 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_DIR_OPEN, 1);
-
+
call_result = call_user_function_ex(NULL,
&us->object,
zfuncname,
&zretval,
2, args,
0, NULL TSRMLS_CC);
-
+
if (call_result == SUCCESS && zretval != NULL && zval_is_true(zretval)) {
/* the stream is now open! */
stream = php_stream_alloc_rel(&php_stream_userspace_dir_ops, us, 0, mode);
@@ -467,7 +494,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed",
us->wrapper->classname);
}
-
+
/* destroy everything else */
if (stream == NULL) {
zval_ptr_dtor(&us->object);
@@ -475,13 +502,13 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filen
}
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zoptions);
zval_ptr_dtor(&zfilename);
FG(user_stream_current_filename) = NULL;
-
+
return stream;
}
@@ -495,11 +522,11 @@ PHP_FUNCTION(stream_wrapper_register)
struct php_user_stream_wrapper * uwrap;
int rsrc_id;
long flags = 0;
-
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &protocol, &protocol_len, &classname, &classname_len, &flags) == FAILURE) {
RETURN_FALSE;
}
-
+
uwrap = (struct php_user_stream_wrapper *)ecalloc(1, sizeof(*uwrap));
uwrap->protoname = estrndup(protocol, protocol_len);
uwrap->classname = estrndup(classname, classname_len);
@@ -585,7 +612,7 @@ PHP_FUNCTION(stream_wrapper_restore)
if (php_register_url_stream_wrapper_volatile(protocol, wrapper TSRMLS_CC) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to restore original %s:// wrapper", protocol);
RETURN_FALSE;
- }
+ }
RETURN_TRUE;
}
@@ -633,10 +660,10 @@ static size_t php_userstreamop_write(php_stream *stream, const char *buf, size_t
(long)(didwrite - count), (long)didwrite, (long)count);
didwrite = count;
}
-
+
if (retval)
zval_ptr_dtor(&retval);
-
+
return didwrite;
}
@@ -721,9 +748,9 @@ static int php_userstreamop_close(php_stream *stream, int close_handle TSRMLS_DC
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
assert(us != NULL);
-
+
ZVAL_STRINGL(&func_name, USERSTREAM_CLOSE, sizeof(USERSTREAM_CLOSE)-1, 0);
-
+
call_user_function_ex(NULL,
&us->object,
&func_name,
@@ -732,11 +759,11 @@ static int php_userstreamop_close(php_stream *stream, int close_handle TSRMLS_DC
if (retval)
zval_ptr_dtor(&retval);
-
+
zval_ptr_dtor(&us->object);
efree(us);
-
+
return 0;
}
@@ -750,7 +777,7 @@ static int php_userstreamop_flush(php_stream *stream TSRMLS_DC)
assert(us != NULL);
ZVAL_STRINGL(&func_name, USERSTREAM_FLUSH, sizeof(USERSTREAM_FLUSH)-1, 0);
-
+
call_result = call_user_function_ex(NULL,
&us->object,
&func_name,
@@ -761,10 +788,10 @@ static int php_userstreamop_flush(php_stream *stream TSRMLS_DC)
call_result = 0;
else
call_result = -1;
-
+
if (retval)
zval_ptr_dtor(&retval);
-
+
return call_result;
}
@@ -803,10 +830,10 @@ static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence, o
/* stream_seek is not implemented, so disable seeks for this stream */
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
/* there should be no retval to clean up */
-
- if (retval)
+
+ if (retval)
zval_ptr_dtor(&retval);
-
+
return -1;
} else if (call_result == SUCCESS && retval != NULL && zval_is_true(retval)) {
ret = 0;
@@ -890,8 +917,8 @@ static int statbuf_from_array(zval *array, php_stream_statbuf *ssb TSRMLS_DC)
STAT_PROP_ENTRY(blocks);
#endif
-#undef STAT_PROP_ENTRY
-#undef STAT_PROP_ENTRY_EX
+#undef STAT_PROP_ENTRY
+#undef STAT_PROP_ENTRY_EX
return SUCCESS;
}
@@ -921,9 +948,9 @@ static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb TSR
}
}
- if (retval)
+ if (retval)
zval_ptr_dtor(&retval);
-
+
return ret;
}
@@ -933,7 +960,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
zval *retval = NULL;
int call_result;
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
- int ret = -1;
+ int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL;
zval *zvalue = NULL;
zval **args[3];
@@ -971,37 +998,83 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
}
args[0] = &zvalue;
-
+
/* TODO wouldblock */
ZVAL_STRINGL(&func_name, USERSTREAM_LOCK, sizeof(USERSTREAM_LOCK)-1, 0);
-
+
call_result = call_user_function_ex(NULL,
&us->object,
&func_name,
&retval,
1, args, 0, NULL TSRMLS_CC);
-
+
if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_BOOL) {
ret = !Z_LVAL_P(retval);
} else if (call_result == FAILURE) {
- if (value == 0) {
+ if (value == 0) {
/* lock support test (TODO: more check) */
- ret = 0;
+ ret = PHP_STREAM_OPTION_RETURN_OK;
} else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_LOCK " is not implemented!",
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_LOCK " is not implemented!",
us->wrapper->classname);
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
}
}
break;
-
+
+ case PHP_STREAM_OPTION_TRUNCATE_API:
+ ZVAL_STRINGL(&func_name, USERSTREAM_TRUNCATE, sizeof(USERSTREAM_TRUNCATE)-1, 0);
+
+ switch (value) {
+ case PHP_STREAM_TRUNCATE_SUPPORTED:
+ if (zend_is_callable_ex(&func_name, us->object, IS_CALLABLE_CHECK_SILENT,
+ NULL, NULL, NULL, NULL TSRMLS_CC))
+ ret = PHP_STREAM_OPTION_RETURN_OK;
+ else
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ break;
+
+ case PHP_STREAM_TRUNCATE_SET_SIZE: {
+ ptrdiff_t new_size = *(ptrdiff_t*) ptrparam;
+ if (new_size >= 0 && new_size <= (ptrdiff_t)LONG_MAX) {
+ MAKE_STD_ZVAL(zvalue);
+ ZVAL_LONG(zvalue, (long)new_size);
+ args[0] = &zvalue;
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 1, args, 0, NULL TSRMLS_CC);
+ if (call_result == SUCCESS && retval != NULL) {
+ if (Z_TYPE_P(retval) == IS_BOOL) {
+ ret = Z_LVAL_P(retval) ? PHP_STREAM_OPTION_RETURN_OK :
+ PHP_STREAM_OPTION_RETURN_ERR;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "%s::" USERSTREAM_TRUNCATE " did not return a boolean!",
+ us->wrapper->classname);
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "%s::" USERSTREAM_TRUNCATE " is not implemented!",
+ us->wrapper->classname);
+ }
+ } else { /* bad new size */
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ break;
+ }
+ }
+ break;
+
case PHP_STREAM_OPTION_READ_BUFFER:
case PHP_STREAM_OPTION_WRITE_BUFFER:
case PHP_STREAM_OPTION_READ_TIMEOUT:
case PHP_STREAM_OPTION_BLOCKING: {
zval *zoption = NULL;
zval *zptrparam = NULL;
-
+
ZVAL_STRINGL(&func_name, USERSTREAM_SET_OPTION, sizeof(USERSTREAM_SET_OPTION)-1, 0);
ALLOC_INIT_ZVAL(zoption);
@@ -1042,17 +1115,16 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
&func_name,
&retval,
3, args, 0, NULL TSRMLS_CC);
-
- do {
- if (call_result == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_SET_OPTION " is not implemented!",
- us->wrapper->classname);
- break;
- }
- if (retval && zend_is_true(retval)) {
- ret = PHP_STREAM_OPTION_RETURN_OK;
- }
- } while (0);
+
+ if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_SET_OPTION " is not implemented!",
+ us->wrapper->classname);
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ } else if (retval && zend_is_true(retval)) {
+ ret = PHP_STREAM_OPTION_RETURN_OK;
+ } else {
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ }
if (zoption) {
zval_ptr_dtor(&zoption);
@@ -1069,7 +1141,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value
if (retval) {
zval_ptr_dtor(&retval);
}
-
+
if (zvalue) {
zval_ptr_dtor(&zvalue);
@@ -1089,16 +1161,9 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
int ret = 0;
/* create an instance of our class */
- ALLOC_ZVAL(object);
- object_init_ex(object, uwrap->ce);
- Z_SET_REFCOUNT_P(object, 1);
- Z_SET_ISREF_P(object);
-
- if (context) {
- add_property_resource(object, "context", context->rsrc_id);
- zend_list_addref(context->rsrc_id);
- } else {
- add_property_null(object, "context");
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
}
/* call the unlink method */
@@ -1108,7 +1173,7 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_UNLINK, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
@@ -1126,7 +1191,7 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio
zval_ptr_dtor(&object);
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zfilename);
@@ -1143,16 +1208,9 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
int ret = 0;
/* create an instance of our class */
- ALLOC_ZVAL(object);
- object_init_ex(object, uwrap->ce);
- Z_SET_REFCOUNT_P(object, 1);
- Z_SET_ISREF_P(object);
-
- if (context) {
- add_property_resource(object, "context", context->rsrc_id);
- zend_list_addref(context->rsrc_id);
- } else {
- add_property_null(object, "context");
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
}
/* call the rename method */
@@ -1166,7 +1224,7 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_RENAME, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
@@ -1184,7 +1242,7 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
zval_ptr_dtor(&object);
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zold_name);
zval_ptr_dtor(&znew_name);
@@ -1202,16 +1260,9 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode,
int ret = 0;
/* create an instance of our class */
- ALLOC_ZVAL(object);
- object_init_ex(object, uwrap->ce);
- Z_SET_REFCOUNT_P(object, 1);
- Z_SET_ISREF_P(object);
-
- if (context) {
- add_property_resource(object, "context", context->rsrc_id);
- zend_list_addref(context->rsrc_id);
- } else {
- add_property_null(object, "context");
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
}
/* call the mkdir method */
@@ -1229,7 +1280,7 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode,
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_MKDIR, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
@@ -1248,7 +1299,7 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode,
if (zretval) {
zval_ptr_dtor(&zretval);
}
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zfilename);
zval_ptr_dtor(&zmode);
@@ -1267,16 +1318,9 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int option
int ret = 0;
/* create an instance of our class */
- ALLOC_ZVAL(object);
- object_init_ex(object, uwrap->ce);
- Z_SET_REFCOUNT_P(object, 1);
- Z_SET_ISREF_P(object);
-
- if (context) {
- add_property_resource(object, "context", context->rsrc_id);
- zend_list_addref(context->rsrc_id);
- } else {
- add_property_null(object, "context");
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
}
/* call the rmdir method */
@@ -1290,7 +1334,7 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int option
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_RMDIR, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
@@ -1309,7 +1353,7 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int option
if (zretval) {
zval_ptr_dtor(&zretval);
}
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zfilename);
zval_ptr_dtor(&zoptions);
@@ -1317,26 +1361,102 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int option
return ret;
}
+static int user_wrapper_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ zval *zfilename, *zoption, *zvalue, *zfuncname, *zretval;
+ zval **args[3];
+ int call_result;
+ zval *object;
+ int ret = 0;
+
+ MAKE_STD_ZVAL(zvalue);
+ switch(option) {
+ case PHP_STREAM_META_TOUCH:
+ array_init(zvalue);
+ if(value) {
+ struct utimbuf *newtime = (struct utimbuf *)value;
+ add_index_long(zvalue, 0, newtime->modtime);
+ add_index_long(zvalue, 1, newtime->actime);
+ }
+ break;
+ case PHP_STREAM_META_GROUP:
+ case PHP_STREAM_META_OWNER:
+ case PHP_STREAM_META_ACCESS:
+ ZVAL_LONG(zvalue, *(long *)value);
+ break;
+ case PHP_STREAM_META_GROUP_NAME:
+ case PHP_STREAM_META_OWNER_NAME:
+ ZVAL_STRING(zvalue, value, 1);
+ break;
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option %d for " USERSTREAM_METADATA, option);
+ zval_ptr_dtor(&zvalue);
+ return ret;
+ }
+
+ /* create an instance of our class */
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ zval_ptr_dtor(&zvalue);
+ return ret;
+ }
+
+ /* call the mkdir method */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, url, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zoption);
+ ZVAL_LONG(zoption, option);
+ args[1] = &zoption;
+
+ args[2] = &zvalue;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_METADATA, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ zfuncname,
+ &zretval,
+ 3, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
+ ret = Z_LVAL_P(zretval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_METADATA " is not implemented!", uwrap->classname);
+ }
+
+ /* clean up */
+ zval_ptr_dtor(&object);
+ if (zretval) {
+ zval_ptr_dtor(&zretval);
+ }
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zfilename);
+ zval_ptr_dtor(&zoption);
+ zval_ptr_dtor(&zvalue);
+
+ return ret;
+}
+
+
static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
{
struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
zval *zfilename, *zfuncname, *zretval, *zflags;
- zval **args[2];
+ zval **args[2];
int call_result;
zval *object;
int ret = -1;
/* create an instance of our class */
- ALLOC_ZVAL(object);
- object_init_ex(object, uwrap->ce);
- Z_SET_REFCOUNT_P(object, 1);
- Z_SET_ISREF_P(object);
-
- if (context) {
- add_property_resource(object, "context", context->rsrc_id);
- zend_list_addref(context->rsrc_id);
- } else {
- add_property_null(object, "context");
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
}
/* call it's stat_url method - set up params first */
@@ -1350,14 +1470,14 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int fla
MAKE_STD_ZVAL(zfuncname);
ZVAL_STRING(zfuncname, USERSTREAM_STATURL, 1);
-
+
call_result = call_user_function_ex(NULL,
&object,
zfuncname,
&zretval,
2, args,
0, NULL TSRMLS_CC);
-
+
if (call_result == SUCCESS && zretval != NULL && Z_TYPE_P(zretval) == IS_ARRAY) {
/* We got the info we needed */
if (SUCCESS == statbuf_from_array(zretval, ssb TSRMLS_CC))
@@ -1368,16 +1488,16 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int fla
uwrap->classname);
}
}
-
+
/* clean up */
zval_ptr_dtor(&object);
if (zretval)
zval_ptr_dtor(&zretval);
-
+
zval_ptr_dtor(&zfuncname);
zval_ptr_dtor(&zfilename);
zval_ptr_dtor(&zflags);
-
+
return ret;
}
@@ -1427,9 +1547,9 @@ static int php_userstreamop_closedir(php_stream *stream, int close_handle TSRMLS
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
assert(us != NULL);
-
+
ZVAL_STRINGL(&func_name, USERSTREAM_DIR_CLOSE, sizeof(USERSTREAM_DIR_CLOSE)-1, 0);
-
+
call_user_function_ex(NULL,
&us->object,
&func_name,
@@ -1438,11 +1558,11 @@ static int php_userstreamop_closedir(php_stream *stream, int close_handle TSRMLS
if (retval)
zval_ptr_dtor(&retval);
-
+
zval_ptr_dtor(&us->object);
efree(us);
-
+
return 0;
}
@@ -1453,7 +1573,7 @@ static int php_userstreamop_rewinddir(php_stream *stream, off_t offset, int when
php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
ZVAL_STRINGL(&func_name, USERSTREAM_DIR_REWIND, sizeof(USERSTREAM_DIR_REWIND)-1, 0);
-
+
call_user_function_ex(NULL,
&us->object,
&func_name,
@@ -1462,7 +1582,7 @@ static int php_userstreamop_rewinddir(php_stream *stream, off_t offset, int when
if (retval)
zval_ptr_dtor(&retval);
-
+
return 0;
}
@@ -1537,7 +1657,7 @@ php_stream_ops php_stream_userspace_ops = {
"user-space",
php_userstreamop_seek,
php_userstreamop_cast,
- php_userstreamop_stat,
+ php_userstreamop_stat,
php_userstreamop_set_option,
};
diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c
index 64555ca1df..7c3a553102 100644
--- a/main/streams/xp_socket.c
+++ b/main/streams/xp_socket.c
@@ -400,10 +400,6 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void
}
#endif
- case PHP_STREAM_OPTION_WRITE_BUFFER:
- php_stream_set_chunk_size(stream, (ptrparam ? *(size_t *)ptrparam : PHP_SOCK_CHUNK_SIZE));
- return PHP_STREAM_OPTION_RETURN_OK;
-
default:
return PHP_STREAM_OPTION_RETURN_NOTIMPL;
}