summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2002-04-10 22:42:32 +0000
committerWez Furlong <wez@php.net>2002-04-10 22:42:32 +0000
commite1d0a147901d27bb01b0ccda315a9fdd3474e1ee (patch)
tree693eee9be6ba188c62f1223eb2c96f70f23256dd
parent3eafd2207ccb313cff264c2e5baaa26b707fbe4f (diff)
downloadphp-git-e1d0a147901d27bb01b0ccda315a9fdd3474e1ee.tar.gz
Implement stream context and status notification system.
Bump the BC for zlib notice to a warning # See my RFC to php-dev a few days ago
-rw-r--r--ext/standard/Makefile.frag1
-rw-r--r--ext/standard/basic_functions.c2
-rw-r--r--ext/standard/file.c159
-rw-r--r--ext/standard/file.h2
-rw-r--r--ext/standard/ftp_fopen_wrapper.c76
-rw-r--r--ext/standard/http_fopen_wrapper.c57
-rw-r--r--ext/standard/php_fopen_wrapper.c2
-rw-r--r--ext/standard/php_fopen_wrappers.h4
-rw-r--r--ext/zlib/php_zlib.h2
-rw-r--r--ext/zlib/zlib.c6
-rw-r--r--ext/zlib/zlib_fopen_wrapper.c3
-rw-r--r--main/main.c9
-rw-r--r--main/network.c18
-rwxr-xr-xmain/php_streams.h101
-rwxr-xr-xmain/streams.c49
-rw-r--r--main/user_streams.c4
16 files changed, 406 insertions, 89 deletions
diff --git a/ext/standard/Makefile.frag b/ext/standard/Makefile.frag
index 934f501e6c..d48cf2fd18 100644
--- a/ext/standard/Makefile.frag
+++ b/ext/standard/Makefile.frag
@@ -6,3 +6,4 @@ $(srcdir)/var_unserializer.c: $(srcdir)/var_unserializer.re
$(srcdir)/url_scanner_ex.c: $(srcdir)/url_scanner_ex.re
re2c -b $(srcdir)/url_scanner_ex.re > $@
+
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index 28b2357c93..3a10750302 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -595,6 +595,8 @@ function_entry basic_functions[] = {
PHP_STATIC_FE("tmpfile", php_if_tmpfile, NULL)
PHP_FE(file, NULL)
PHP_FE(file_get_contents, NULL)
+ PHP_FE(file_context_create, NULL)
+ PHP_FE(file_context_set_params, NULL)
PHP_FE(fgetcsv, NULL)
PHP_FE(flock, NULL)
PHP_FE(get_meta_tags, NULL)
diff --git a/ext/standard/file.c b/ext/standard/file.c
index 616dba829e..f5f33e61c8 100644
--- a/ext/standard/file.c
+++ b/ext/standard/file.c
@@ -109,10 +109,16 @@ php_file_globals file_globals;
/* sharing globals is *evil* */
static int le_stream = FAILURE;
+static int le_stream_context = FAILURE;
/* }}} */
/* {{{ Module-Stuff */
+static ZEND_RSRC_DTOR_FUNC(file_context_dtor)
+{
+ php_stream_context_free((php_stream_context*)rsrc->ptr);
+}
+
static void _file_stream_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
php_stream *stream = (php_stream*)rsrc->ptr;
@@ -142,6 +148,7 @@ static void file_globals_dtor(php_file_globals *file_globals_p TSRMLS_DC)
PHP_MINIT_FUNCTION(file)
{
le_stream = zend_register_list_destructors_ex(_file_stream_dtor, NULL, "stream", module_number);
+ le_stream_context = zend_register_list_destructors_ex(file_context_dtor, NULL, "stream-context", module_number);
#ifdef ZTS
ts_allocate_id(&file_globals_id, sizeof(php_file_globals), (ts_allocate_ctor) file_globals_ctor, (ts_allocate_dtor) file_globals_dtor);
@@ -157,6 +164,19 @@ PHP_MINIT_FUNCTION(file)
REGISTER_LONG_CONSTANT("LOCK_UN", 3, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LOCK_NB", 4, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_CONNECT", PHP_STREAM_NOTIFY_CONNECT, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_AUTH_REQUIRED", PHP_STREAM_NOTIFY_AUTH_REQUIRED, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_AUTH_RESULT", PHP_STREAM_NOTIFY_AUTH_RESULT, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_MIME_TYPE_IS", PHP_STREAM_NOTIFY_MIME_TYPE_IS, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_FILE_SIZE_IS", PHP_STREAM_NOTIFY_FILE_SIZE_IS, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_REDIRECTED", PHP_STREAM_NOTIFY_REDIRECTED, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_PROGRESS", PHP_STREAM_NOTIFY_PROGRESS, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_FAILURE", PHP_STREAM_NOTIFY_FAILURE, CONST_CS | CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_SEVERITY_INFO", PHP_STREAM_NOTIFY_SEVERITY_INFO, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_SEVERITY_WARN", PHP_STREAM_NOTIFY_SEVERITY_WARN, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_NOTIFY_SEVERITY_ERR", PHP_STREAM_NOTIFY_SEVERITY_ERR, CONST_CS | CONST_PERSISTENT);
+
return SUCCESS;
}
@@ -562,36 +582,126 @@ PHP_FUNCTION(file_get_wrapper_data)
}
/* }}} */
-/* {{{ proto resource fopen(string filename, string mode [, bool use_include_path])
- Open a file or a URL and return a file pointer */
-PHP_NAMED_FUNCTION(php_if_fopen)
+/* {{{ file_context related functions */
+static void user_space_stream_notifier(php_stream_context *context, int notifycode, int severity,
+ char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC)
{
- zval **arg1, **arg2, **arg3;
- int use_include_path = 0;
- php_stream *stream;
+ zval *callback = (zval*)context->notifier->ptr;
+ zval *retval = NULL;
+ zval zcode, zseverity, zmsg, zxcode, zsofar, zmax;
+ zval *ptrs[6] = {&zcode, &zseverity, &zmsg, &zxcode, &zsofar, &zmax};
+ zval **args[6] = {&ptrs[0], &ptrs[1], &ptrs[2], &ptrs[3], &ptrs[4], &ptrs[5]};
- switch(ZEND_NUM_ARGS()) {
- case 2:
- if (zend_get_parameters_ex(2, &arg1, &arg2) == FAILURE) {
- WRONG_PARAM_COUNT;
- }
- break;
- case 3:
- if (zend_get_parameters_ex(3, &arg1, &arg2, &arg3) == FAILURE) {
- WRONG_PARAM_COUNT;
+ INIT_ZVAL(zcode);
+ INIT_ZVAL(zseverity);
+ INIT_ZVAL(zmsg);
+ INIT_ZVAL(zxcode);
+ INIT_ZVAL(zsofar);
+ INIT_ZVAL(zmax);
+
+ ZVAL_LONG(&zcode, notifycode);
+ ZVAL_LONG(&zseverity, severity);
+ ZVAL_LONG(&zxcode, xcode);
+ ZVAL_LONG(&zsofar, bytes_sofar);
+ ZVAL_LONG(&zmax, bytes_max);
+
+ if (xmsg) {
+ ZVAL_STRING(&zmsg, xmsg, 0);
+ } else {
+ ZVAL_NULL(&zmsg);
+ }
+
+ if (FAILURE == call_user_function_ex(EG(function_table), NULL, callback, &retval, 6, args, 0, NULL TSRMLS_CC)) {
+ zend_error(E_WARNING, "failed to call user notifier");
+ }
+ if (retval)
+ zval_ptr_dtor(&retval);
+}
+
+static int parse_context_options(php_stream_context *context, zval *params)
+{
+ int ret = SUCCESS;
+ zval **tmp;
+
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_P(params), "notification", sizeof("notification"), (void**)&tmp)) {
+
+ if (context->notifier) {
+ php_stream_notification_free(context->notifier);
+ context->notifier = NULL;
}
- convert_to_long_ex(arg3);
- use_include_path = Z_LVAL_PP(arg3);
- break;
- default:
- WRONG_PARAM_COUNT;
+
+ context->notifier = php_stream_notification_alloc();
+ context->notifier->func = user_space_stream_notifier;
+ context->notifier->ptr = *tmp;
+ ZVAL_ADDREF(*tmp);
}
- convert_to_string_ex(arg1);
- convert_to_string_ex(arg2);
+
+ return ret;
+}
+/* }}} */
+
+/* {{{ proto bool file_context_set_params(resource context, array options)
+ Set parameters for a file context */
+PHP_FUNCTION(file_context_set_params)
+{
+ zval *params, *zcontext;
+ php_stream_context *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &zcontext, &params) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ context = (php_stream_context*)zend_fetch_resource(&zcontext TSRMLS_CC, -1, "Stream-Context", NULL, 1, le_stream_context);
+ ZEND_VERIFY_RESOURCE(context);
+
+ RETVAL_BOOL(parse_context_options(context, params) == SUCCESS);
+}
+/* }}} */
+
+/* {{{ proto resource file_context_create([array options])
+ Create a file context and optionally set parameters */
+PHP_FUNCTION(file_context_create)
+{
+ zval *params = NULL;
+ php_stream_context *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &params) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ context = php_stream_context_alloc();
+
+ if (params)
+ parse_context_options(context, params);
+
+ ZEND_REGISTER_RESOURCE(return_value, context, le_stream_context);
+}
+/* }}} */
- stream = php_stream_open_wrapper(Z_STRVAL_PP(arg1), Z_STRVAL_PP(arg2),
+/* {{{ proto resource fopen(string filename, string mode [, bool use_include_path [, resource context]])
+ Open a file or a URL and return a file pointer */
+PHP_NAMED_FUNCTION(php_if_fopen)
+{
+ char *filename, *mode;
+ int filename_len, mode_len;
+ zend_bool use_include_path = 0;
+ zval *zcontext = NULL;
+ php_stream *stream;
+ php_stream_context *context = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|br", &filename, &filename_len,
+ &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) {
+ RETURN_FALSE;
+ }
+ if (zcontext) {
+ context = (php_stream_context*)zend_fetch_resource(&zcontext TSRMLS_CC, -1, "Stream-Context", NULL, 1, le_stream_context);
+ ZEND_VERIFY_RESOURCE(context);
+ }
+
+ stream = php_stream_open_wrapper_ex(filename, mode,
use_include_path | ENFORCE_SAFE_MODE | REPORT_ERRORS,
- NULL);
+ NULL, context);
+
if (stream == NULL) {
RETURN_FALSE;
}
@@ -622,6 +732,7 @@ PHPAPI PHP_FUNCTION(fclose)
}
/* }}} */
+
/* {{{ proto resource popen(string command, string mode)
Execute a command and open either a read or a write pipe to it */
diff --git a/ext/standard/file.h b/ext/standard/file.h
index 6d08e31ad9..3261aaba08 100644
--- a/ext/standard/file.h
+++ b/ext/standard/file.h
@@ -73,6 +73,8 @@ PHP_NAMED_FUNCTION(php_if_fstat);
PHP_FUNCTION(file_get_wrapper_data);
PHP_FUNCTION(file_register_wrapper);
+PHP_FUNCTION(file_context_create);
+PHP_FUNCTION(file_context_set_params);
PHP_MINIT_FUNCTION(user_streams);
PHPAPI int php_set_sock_blocking(int socketd, int block);
diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c
index e7f6eef638..2f3db50593 100644
--- a/ext/standard/ftp_fopen_wrapper.c
+++ b/ext/standard/ftp_fopen_wrapper.c
@@ -66,16 +66,16 @@
#include "php_fopen_wrappers.h"
-static int php_get_ftp_result(php_stream *stream TSRMLS_DC)
-{
- char tmp_line[513];
- while (php_stream_gets(stream, tmp_line, sizeof(tmp_line)-1) &&
- !(isdigit((int) tmp_line[0]) && isdigit((int) tmp_line[1]) &&
- isdigit((int) tmp_line[2]) && tmp_line[3] == ' '));
+static inline int get_ftp_result(php_stream *stream, char *buffer, size_t buffer_size TSRMLS_DC)
+{
+ while (php_stream_gets(stream, buffer, buffer_size-1) &&
+ !(isdigit((int) buffer[0]) && isdigit((int) buffer[1]) &&
+ isdigit((int) buffer[2]) && buffer[3] == ' '));
- return strtol(tmp_line, NULL, 10);
+ return strtol(buffer, NULL, 10);
}
+#define GET_FTP_RESULT(stream) get_ftp_result((stream), tmp_line, sizeof(tmp_line) TSRMLS_CC)
static int php_stream_ftp_stream_stat(php_stream_wrapper *wrapper,
php_stream *stream,
@@ -103,7 +103,7 @@ php_stream_wrapper php_stream_ftp_wrapper = {
/* {{{ php_fopen_url_wrap_ftp
*/
-php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
+php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
{
php_stream *stream=NULL;
php_url *resource=NULL;
@@ -113,6 +113,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, ch
int result;
int i;
char *tpath, *ttpath;
+ size_t file_size = 0;
resource = php_url_parse((char *) path);
if (resource == NULL || resource->path == NULL)
@@ -126,10 +127,15 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, ch
if (stream == NULL)
goto errexit;
+ php_stream_context_set(stream, context);
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);
+
/* Start talking to ftp server */
- result = php_get_ftp_result(stream TSRMLS_CC);
- if (result > 299 || result < 200)
+ result = GET_FTP_RESULT(stream);
+ if (result > 299 || result < 200) {
+ php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
goto errexit;
+ }
/* send the user name */
php_stream_write_string(stream, "USER ");
@@ -142,10 +148,12 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, ch
php_stream_write_string(stream, "\r\n");
/* get the response */
- result = php_get_ftp_result(stream TSRMLS_CC);
+ result = GET_FTP_RESULT(stream);
/* if a password is required, send it */
if (result >= 300 && result <= 399) {
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, tmp_line, 0);
+
php_stream_write_string(stream, "PASS ");
if (resource->pass != NULL) {
php_raw_url_decode(resource->pass, strlen(resource->pass));
@@ -162,14 +170,20 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, ch
php_stream_write_string(stream, "\r\n");
/* read the response */
- result = php_get_ftp_result(stream TSRMLS_CC);
+ result = GET_FTP_RESULT(stream);
+
+ if (result > 299 || result < 200) {
+ php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, result);
+ } else {
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, result);
+ }
}
if (result > 299 || result < 200)
goto errexit;
/* set the connection to be binary */
php_stream_write_string(stream, "TYPE I\r\n");
- result = php_get_ftp_result(stream TSRMLS_CC);
+ result = GET_FTP_RESULT(stream);
if (result > 299 || result < 200)
goto errexit;
@@ -179,13 +193,22 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, ch
php_stream_write_string(stream, "\r\n");
/* read the response */
- result = php_get_ftp_result(stream TSRMLS_CC);
+ result = GET_FTP_RESULT(stream);
if (mode[0] == 'r') {
+ char *sizestr;
+
/* when reading file, it must exist */
if (result > 299 || result < 200) {
errno = ENOENT;
goto errexit;
}
+
+ sizestr = strchr(tmp_line, ' ');
+ if (sizestr) {
+ sizestr++;
+ file_size = atoi(sizestr);
+ php_stream_notify_file_size(context, file_size, tmp_line, result);
+ }
} else {
/* when writing file, it must NOT exist */
if (result <= 299 && result >= 200) {
@@ -193,25 +216,23 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, ch
goto errexit;
}
}
-
+
/* set up the passive connection */
/* We try EPSV first, needed for IPv6 and works on some IPv4 servers */
php_stream_write_string(stream, "EPSV\r\n");
- while (php_stream_gets(stream, tmp_line, sizeof(tmp_line)-1) &&
- !(isdigit((int) tmp_line[0]) && isdigit((int) tmp_line[1]) &&
- isdigit((int) tmp_line[2]) && tmp_line[3] == ' '));
+ result = GET_FTP_RESULT(stream);
/* check if we got a 229 response */
- if (strncmp(tmp_line, "229", 3)) {
+ if (result != 229) {
/* EPSV failed, let's try PASV */
php_stream_write_string(stream, "PASV\r\n");
- while (php_stream_gets(stream, tmp_line, sizeof(tmp_line)-1) &&
- !(isdigit((int) tmp_line[0]) && isdigit((int) tmp_line[1]) &&
- isdigit((int) tmp_line[2]) && tmp_line[3] == ' '));
+ result = GET_FTP_RESULT(stream);
+
/* make sure we got a 227 response */
- if (strncmp(tmp_line, "227", 3))
+ if (result != 227)
goto errexit;
+
/* parse pasv command (129, 80, 95, 25, 13, 221) */
tpath = tmp_line;
/* skip over the "227 Some message " part */
@@ -279,13 +300,20 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, ch
if (stream == NULL)
goto errexit;
+ php_stream_context_set(stream, context);
+ php_stream_notify_progress_init(context, 0, file_size);
+
php_url_free(resource);
return stream;
errexit:
php_url_free(resource);
- if (stream)
+ if (stream) {
+ php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
php_stream_close(stream);
+ }
+ if (tmp_line[0] != '\0')
+ zend_error(E_WARNING, "FTP server reports %s", tmp_line);
return NULL;
}
/* }}} */
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
index c96f43ddff..994e60d719 100644
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -70,7 +70,7 @@
#define HTTP_HEADER_BLOCK_SIZE 1024
-php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
+php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
{
php_stream *stream = NULL;
php_url *resource = NULL;
@@ -84,6 +84,8 @@ php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, ch
int reqok = 0;
char *http_header_line = NULL;
char tmp_line[128];
+ size_t chunk_size, file_size = 0;
+ int redirected = 0;
resource = php_url_parse(path);
if (resource == NULL)
@@ -101,6 +103,13 @@ php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, ch
if (stream == NULL)
goto out;
+ /* avoid buffering issues while reading header */
+ chunk_size = php_stream_sock_set_chunk_size(stream, 1 TSRMLS_CC);
+
+ php_stream_context_set(stream, context);
+
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);
+
#if HAVE_OPENSSL_EXT
if (use_ssl) {
if (php_stream_sock_ssl_activate(stream, 1) == FAILURE) {
@@ -146,8 +155,10 @@ php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, ch
tmp = php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL);
- if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0)
+ if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) {
php_stream_write(stream, scratch, strlen(scratch));
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0);
+ }
efree(tmp);
tmp = NULL;
@@ -179,10 +190,22 @@ php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, ch
if (php_stream_gets(stream, tmp_line, sizeof(tmp_line)-1) != NULL) {
zval *http_response;
+ int response_code;
MAKE_STD_ZVAL(http_response);
- if (strncmp(tmp_line + 8, " 200 ", 5) == 0)
+ response_code = atoi(tmp_line + 9);
+ if (response_code == 200) {
reqok = 1;
+ } else {
+ switch(response_code) {
+ case 403:
+ php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, response_code);
+ break;
+ default:
+ php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, response_code);
+ }
+ }
+
Z_STRLEN_P(http_response) = strlen(tmp_line);
Z_STRVAL_P(http_response) = estrndup(tmp_line, Z_STRLEN_P(http_response));
if (Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=='\n') {
@@ -223,8 +246,15 @@ php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, ch
}
http_header_line_length = p-http_header_line+1;
- if (!strncasecmp(http_header_line, "Location: ", 10))
+ if (!strncasecmp(http_header_line, "Location: ", 10)) {
strlcpy(location, http_header_line + 10, sizeof(location));
+ } else if (!strncasecmp(http_header_line, "Content-Type: ", 14)) {
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_line + 14, 0);
+ } else if (!strncasecmp(http_header_line, "Content-Length: ", 16)) {
+ file_size = atoi(http_header_line + 16);
+ php_stream_notify_file_size(context, file_size, http_header_line, 0);
+ }
+
if (http_header_line[0] == '\0')
body = 1;
@@ -243,6 +273,10 @@ php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, ch
}
if (!reqok) {
+
+ if (location[0] != '\0')
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0);
+
php_stream_close(stream);
stream = NULL;
@@ -267,8 +301,9 @@ php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, ch
else {
strlcpy(new_path, location, sizeof(new_path));
}
- stream = php_stream_url_wrap_http(NULL, new_path, mode, options, opened_path STREAMS_CC TSRMLS_CC);
- if (stream->wrapperdata) {
+ redirected = 1;
+ stream = php_stream_url_wrap_http(NULL, new_path, mode, options, opened_path, context STREAMS_CC TSRMLS_CC);
+ if (stream && stream->wrapperdata) {
entryp = &entry;
MAKE_STD_ZVAL(entry);
ZVAL_EMPTY_STRING(entry);
@@ -282,9 +317,10 @@ php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, ch
zval_dtor(stream->wrapperdata);
FREE_ZVAL(stream->wrapperdata);
}
+ } else {
+ if (options & REPORT_ERRORS)
+ zend_error(E_WARNING, "HTTP request failed! %s", tmp_line);
}
- else if (options & REPORT_ERRORS)
- zend_error(E_WARNING, "HTTP request failed! %s", tmp_line);
}
out:
if (http_header_line)
@@ -293,8 +329,11 @@ out:
efree(scratch);
php_url_free(resource);
- if (stream)
+ if (stream) {
stream->wrapperdata = response_header;
+ php_stream_notify_progress_init(context, 0, file_size);
+ php_stream_sock_set_chunk_size(stream, chunk_size TSRMLS_CC);
+ }
if (response_header) {
zval *sym;
diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c
index e7f07a9e9b..fcca4fce2d 100644
--- a/ext/standard/php_fopen_wrapper.c
+++ b/ext/standard/php_fopen_wrapper.c
@@ -30,7 +30,7 @@
#include "php_standard.h"
#include "php_fopen_wrappers.h"
-php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
+php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_wrapper_options *exoptions STREAMS_DC TSRMLS_DC)
{
FILE * fp = NULL;
php_stream * stream = NULL;
diff --git a/ext/standard/php_fopen_wrappers.h b/ext/standard/php_fopen_wrappers.h
index 7c82937d05..392b88d063 100644
--- a/ext/standard/php_fopen_wrappers.h
+++ b/ext/standard/php_fopen_wrappers.h
@@ -23,8 +23,8 @@
#ifndef PHP_FOPEN_WRAPPERS_H
#define PHP_FOPEN_WRAPPERS_H
-php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
-php_stream *php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
+php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+php_stream *php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
php_stream_wrapper php_stream_http_wrapper;
php_stream_wrapper php_stream_ftp_wrapper;
php_stream_wrapper php_stream_php_wrapper;
diff --git a/ext/zlib/php_zlib.h b/ext/zlib/php_zlib.h
index b33d57c06e..333eb1224b 100644
--- a/ext/zlib/php_zlib.h
+++ b/ext/zlib/php_zlib.h
@@ -54,7 +54,7 @@ PHP_FUNCTION(ob_gzhandler);
int php_enable_output_compression(int buffer_size TSRMLS_DC);
-php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
+php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
extern php_stream_ops php_stream_gzio_ops;
extern php_stream_wrapper php_stream_gzip_wrapper;
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index ea935d7917..7031efa23b 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -285,7 +285,7 @@ PHP_FUNCTION(gzfile)
convert_to_string_ex(filename);
/* using a stream here is a bit more efficient (resource wise) than php_gzopen_wrapper */
- stream = php_stream_gzopen(NULL, Z_STRVAL_PP(filename), "rb", use_include_path|ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL STREAMS_CC TSRMLS_CC);
+ stream = php_stream_gzopen(NULL, Z_STRVAL_PP(filename), "rb", use_include_path|ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL, NULL STREAMS_CC TSRMLS_CC);
if (stream == NULL) {
php_error(E_WARNING,"gzFile(\"%s\") - %s",Z_STRVAL_PP(filename),strerror(errno));
RETURN_FALSE;
@@ -341,7 +341,7 @@ PHP_FUNCTION(gzopen)
convert_to_string_ex(arg2);
p = estrndup(Z_STRVAL_PP(arg2),Z_STRLEN_PP(arg2));
- stream = php_stream_gzopen(NULL, Z_STRVAL_PP(arg1), p, use_include_path|ENFORCE_SAFE_MODE, NULL STREAMS_CC TSRMLS_CC);
+ stream = php_stream_gzopen(NULL, Z_STRVAL_PP(arg1), p, use_include_path|ENFORCE_SAFE_MODE, NULL, NULL STREAMS_CC TSRMLS_CC);
if (!stream) {
RETURN_FALSE;
}
@@ -382,7 +382,7 @@ PHP_FUNCTION(readgzfile)
}
convert_to_string_ex(arg1);
- stream = php_stream_gzopen(NULL, Z_STRVAL_PP(arg1), "rb", use_include_path|ENFORCE_SAFE_MODE, NULL STREAMS_CC TSRMLS_CC);
+ stream = php_stream_gzopen(NULL, Z_STRVAL_PP(arg1), "rb", use_include_path|ENFORCE_SAFE_MODE, NULL, NULL STREAMS_CC TSRMLS_CC);
if (!stream) {
RETURN_FALSE;
}
diff --git a/ext/zlib/zlib_fopen_wrapper.c b/ext/zlib/zlib_fopen_wrapper.c
index 2ed6d3b01a..bdc2b5a882 100644
--- a/ext/zlib/zlib_fopen_wrapper.c
+++ b/ext/zlib/zlib_fopen_wrapper.c
@@ -93,7 +93,8 @@ php_stream_ops php_stream_gzio_ops = {
NULL, NULL
};
-php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
+php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, char *path, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
{
struct php_gz_stream_data_t *self;
php_stream *stream = NULL;
diff --git a/main/main.c b/main/main.c
index 01d16f2c84..737507ac1d 100644
--- a/main/main.c
+++ b/main/main.c
@@ -594,16 +594,9 @@ PHP_FUNCTION(set_time_limit)
*/
static FILE *php_fopen_wrapper_for_zend(const char *filename, char **opened_path)
{
- FILE *retval = NULL;
- size_t old_chunk_size;
TSRMLS_FETCH();
- old_chunk_size = FG(def_chunk_size);
- FG(def_chunk_size) = 1;
- retval = php_stream_open_wrapper_as_file((char *)filename, "rb", USE_PATH|IGNORE_URL_WIN|REPORT_ERRORS, opened_path);
- FG(def_chunk_size) = old_chunk_size;
-
- return retval;
+ return php_stream_open_wrapper_as_file((char *)filename, "rb", USE_PATH|IGNORE_URL_WIN|REPORT_ERRORS, opened_path);
}
/* }}} */
diff --git a/main/network.c b/main/network.c
index 7ed301a654..f2fcfa1948 100644
--- a/main/network.c
+++ b/main/network.c
@@ -574,11 +574,18 @@ PHPAPI size_t php_stream_sock_set_chunk_size(php_stream *stream, size_t size TSR
static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
{
php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+ size_t didwrite;
+
#if HAVE_OPENSSL_EXT
if (sock->ssl_active)
- return SSL_write(sock->ssl_handle, buf, count);
+ didwrite = SSL_write(sock->ssl_handle, buf, count);
+ else
#endif
- return send(sock->socket, buf, count, 0);
+ didwrite = send(sock->socket, buf, count, 0);
+
+ php_stream_notify_progress_increment(stream->context, didwrite, 0);
+
+ return didwrite;
}
static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock TSRMLS_DC)
{
@@ -638,6 +645,8 @@ static size_t php_sock_stream_read_internal(php_stream *stream, php_netstream_da
nr_bytes = recv(sock->socket, buf, sock->chunk_size, 0);
if(nr_bytes > 0) {
+ php_stream_notify_progress_increment(stream->context, nr_bytes, 0);
+
/* try to avoid ever expanding buffer */
if (sock->readpos > 0) {
memmove(sock->readbuf, READPTR(sock), sock->readbuflen - sock->readpos);
@@ -669,7 +678,10 @@ static size_t php_sock_stream_read(php_stream *stream, php_netstream_data_t *soc
for(i = 0; !sock->eof && i < MAX_CHUNKS_PER_READ; i++) {
nr_bytes = php_sock_stream_read_internal(stream, sock TSRMLS_CC);
- if(nr_bytes == 0) break;
+ if(nr_bytes == 0)
+ break;
+
+
nr_read += nr_bytes;
}
diff --git a/main/php_streams.h b/main/php_streams.h
index 2243f07de4..c5ef2acfdc 100755
--- a/main/php_streams.h
+++ b/main/php_streams.h
@@ -69,7 +69,8 @@
#define php_stream_fopen_temporary_file_rel(dir, pfx, opened_path) _php_stream_fopen_temporary_file((dir), (pfx), (opened_path) STREAMS_REL_CC TSRMLS_CC)
-#define php_stream_open_wrapper_rel(path, mode, options, opened) _php_stream_open_wrapper((path), (mode), (options), (opened) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_open_wrapper_rel(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_open_wrapper_ex_rel(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_REL_CC TSRMLS_CC)
#define php_stream_make_seekable_rel(origstream, newstream, flags) _php_stream_make_seekable((origstream), (newstream), (flags) STREAMS_REL_CC TSRMLS_CC)
@@ -85,16 +86,48 @@
* the php_stream->abstract pointer to hold their context, and streams
* opened via stream_open_wrappers can use the zval ptr in
* php_stream->wrapperdata to hold meta data for php scripts to
- * retrieve using fgetwrapperdata(). */
+ * retrieve using file_get_wrapper_data(). */
typedef struct _php_stream php_stream;
typedef struct _php_stream_wrapper php_stream_wrapper;
+typedef struct _php_stream_context php_stream_context;
+
+/* callback for status notifications */
+typedef void (*php_stream_notification_func)(php_stream_context *context,
+ int notifycode, int severity,
+ char *xmsg, int xcode,
+ size_t bytes_sofar, size_t bytes_max,
+ void * ptr TSRMLS_DC);
typedef struct _php_stream_statbuf {
struct stat sb; /* regular info */
/* extended info to go here some day */
} php_stream_statbuf;
+#define PHP_STREAM_NOTIFIER_PROGRESS 1
+
+typedef struct _php_stream_notifier {
+ php_stream_notification_func func;
+ void *ptr;
+ int mask;
+ size_t progress, progress_max; /* position for progress notification */
+} php_stream_notifier;
+
+struct _php_stream_context {
+ php_stream_notifier *notifier;
+
+};
+
+typedef struct _php_stream_wrapper_options {
+ int valid_options; /* PHP_STREAM_WRAPPER_OPT_XXX */
+
+ php_stream_notification_func notifier;
+ void *notifier_ptr;
+
+ /* other info like user-agent, SSL cert and cookie information
+ * to go here some day */
+} php_stream_wrapper_options;
+
typedef struct _php_stream_ops {
/* stdio like functions - these are mandatory! */
size_t (*write)(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
@@ -114,7 +147,7 @@ typedef struct _php_stream_ops {
typedef struct _php_stream_wrapper_ops {
/* open/create a wrapped stream */
php_stream *(*opener)(php_stream_wrapper *wrapper, char *filename, char *mode,
- int options, char **opened_path STREAMS_DC TSRMLS_DC);
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
/* close/destroy a wrapped stream */
int (*closer)(php_stream_wrapper *wrapper, php_stream *stream TSRMLS_DC);
/* stat a wrapped stream */
@@ -128,6 +161,7 @@ struct _php_stream_wrapper {
void *abstract; /* context for the wrapper */
};
+
struct _php_stream {
php_stream_ops *ops;
void *abstract; /* convenience pointer for abstraction */
@@ -148,6 +182,9 @@ struct _php_stream {
#if ZEND_DEBUG
int __exposed; /* non-zero if exposed as a zval somewhere */
#endif
+
+ php_stream_context *context;
+
}; /* php_stream */
/* state definitions when closing down; these are private to streams.c */
#define PHP_STREAM_FCLOSE_NONE 0
@@ -305,8 +342,10 @@ int php_init_stream_wrappers(TSRMLS_D);
int php_shutdown_stream_wrappers(TSRMLS_D);
PHPAPI int php_register_url_stream_wrapper(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC);
PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC);
-PHPAPI php_stream *_php_stream_open_wrapper(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
-#define php_stream_open_wrapper(path, mode, options, opened) _php_stream_open_wrapper((path), (mode), (options), (opened) STREAMS_CC TSRMLS_CC)
+PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+
+#define php_stream_open_wrapper(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC)
+#define php_stream_open_wrapper_ex(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_CC TSRMLS_CC)
#define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */
#define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */
@@ -328,6 +367,58 @@ PHPAPI FILE * _php_stream_open_wrapper_as_file(char * path, char * mode, int opt
extern php_stream_ops php_stream_userspace_ops;
#define PHP_STREAM_IS_USERSPACE &php_stream_userspace_ops
+PHPAPI void php_stream_context_free(php_stream_context *context);
+PHPAPI php_stream_context *php_stream_context_alloc(void);
+
+PHPAPI php_stream_notifier *php_stream_notification_alloc(void);
+PHPAPI void php_stream_notification_free(php_stream_notifier *notifier);
+
+#define PHP_STREAM_NOTIFY_RESOLVE 1
+#define PHP_STREAM_NOTIFY_CONNECT 2
+#define PHP_STREAM_NOTIFY_AUTH_REQUIRED 3
+#define PHP_STREAM_NOTIFY_MIME_TYPE_IS 4
+#define PHP_STREAM_NOTIFY_FILE_SIZE_IS 5
+#define PHP_STREAM_NOTIFY_REDIRECTED 6
+#define PHP_STREAM_NOTIFY_PROGRESS 7
+#define PHP_STREAM_NOTIFY_COMPLETED 8
+#define PHP_STREAM_NOTIFY_FAILURE 9
+#define PHP_STREAM_NOTIFY_AUTH_RESULT 10
+
+#define PHP_STREAM_NOTIFY_SEVERITY_INFO 0
+#define PHP_STREAM_NOTIFY_SEVERITY_WARN 1
+#define PHP_STREAM_NOTIFY_SEVERITY_ERR 2
+
+PHPAPI void php_stream_notification_notify(php_stream_context *context, int notifycode, int severity,
+ char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC);
+PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context);
+
+#define php_stream_notify_info(context, code, xmsg, xcode) do { if ((context) && (context)->notifier) { \
+ php_stream_notification_notify((context), (code), PHP_STREAM_NOTIFY_SEVERITY_INFO, \
+ (xmsg), (xcode), 0, 0, NULL TSRMLS_CC); } } while (0)
+
+#define php_stream_notify_progress(context, bsofar, bmax) do { if ((context) && (context)->notifier) { \
+ php_stream_notification_notify((context), PHP_STREAM_NOTIFY_PROGRESS, PHP_STREAM_NOTIFY_SEVERITY_INFO, \
+ NULL, 0, (bsofar), (bmax), NULL TSRMLS_CC); } } while(0)
+
+#define php_stream_notify_progress_init(context, sofar, bmax) do { if ((context)->notifier) { \
+ (context)->notifier->progress = (sofar); \
+ (context)->notifier->progress_max = (bmax); \
+ (context)->notifier->mask |= PHP_STREAM_NOTIFIER_PROGRESS; \
+ php_stream_notify_progress((context), (sofar), (bmax)); } } while (0)
+
+#define php_stream_notify_progress_increment(context, dsofar, dmax) do { if ((context) && (context)->notifier && (context)->notifier->mask & PHP_STREAM_NOTIFIER_PROGRESS) { \
+ (context)->notifier->progress += (dsofar); \
+ (context)->notifier->progress_max += (dmax); \
+ php_stream_notify_progress((context), (context)->notifier->progress, (context)->notifier->progress_max); } } while (0)
+
+#define php_stream_notify_file_size(context, file_size, xmsg, xcode) do { if ((context) && (context)->notifier) { \
+ php_stream_notification_notify((context), PHP_STREAM_NOTIFY_FILE_SIZE_IS, PHP_STREAM_NOTIFY_SEVERITY_INFO, \
+ (xmsg), (xcode), 0, (file_size), NULL TSRMLS_CC); } } while(0)
+
+#define php_stream_notify_error(context, code, xmsg, xcode) do { if ((context) && (context)->notifier) {\
+ php_stream_notification_notify((context), (code), PHP_STREAM_NOTIFY_SEVERITY_ERR, \
+ (xmsg), (xcode), 0, 0, NULL TSRMLS_CC); } } while(0)
+
#endif
/*
diff --git a/main/streams.c b/main/streams.c
index cc8c8789da..3d4c18988d 100755
--- a/main/streams.c
+++ b/main/streams.c
@@ -1069,7 +1069,8 @@ PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC)
/* }}} */
/* {{{ php_stream_open_url */
-static php_stream *php_stream_open_url(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
+static php_stream *php_stream_open_url(char *path, char *mode, int options,
+ char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
{
php_stream_wrapper *wrapper;
const char *p, *protocol = NULL;
@@ -1085,7 +1086,7 @@ static php_stream *php_stream_open_url(char *path, char *mode, int options, char
/* BC with older php scripts and zlib wrapper */
protocol = path;
n = 4;
- zend_error(E_NOTICE, "Use of \"zlib:\" wrapper is deprecated; please use \"zlib://\" instead.");
+ zend_error(E_WARNING, "Use of \"zlib:\" wrapper is deprecated; please use \"zlib://\" instead.");
}
if (protocol) {
@@ -1103,7 +1104,7 @@ static php_stream *php_stream_open_url(char *path, char *mode, int options, char
protocol = NULL;
}
if (wrapper) {
- php_stream *stream = wrapper->wops->opener(wrapper, path, mode, options, opened_path STREAMS_REL_CC TSRMLS_CC);
+ php_stream *stream = wrapper->wops->opener(wrapper, path, mode, options, opened_path, context STREAMS_REL_CC TSRMLS_CC);
if (stream)
stream->wrapper = wrapper;
return stream;
@@ -1126,8 +1127,9 @@ static php_stream *php_stream_open_url(char *path, char *mode, int options, char
}
/* }}} */
-/* {{{ php_stream_open_wrapper */
-PHPAPI php_stream *_php_stream_open_wrapper(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
+/* {{{ php_stream_open_wrapper_ex */
+PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options,
+ char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
{
php_stream *stream = NULL;
@@ -1138,7 +1140,7 @@ PHPAPI php_stream *_php_stream_open_wrapper(char *path, char *mode, int options,
return NULL;
if (PG(allow_url_fopen) && !(options & IGNORE_URL)) {
- stream = php_stream_open_url(path, mode, options, opened_path STREAMS_REL_CC TSRMLS_CC);
+ stream = php_stream_open_url(path, mode, options, opened_path, context STREAMS_REL_CC TSRMLS_CC);
goto out;
}
@@ -1243,6 +1245,41 @@ PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstr
}
/* }}} */
+PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context)
+{
+ php_stream_context *oldcontext = stream->context;
+ stream->context = context;
+ return oldcontext;
+}
+
+PHPAPI void php_stream_notification_notify(php_stream_context *context, int notifycode, int severity,
+ char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC)
+{
+ if (context && context->notifier)
+ context->notifier->func(context, notifycode, severity, xmsg, xcode, bytes_sofar, bytes_max, ptr TSRMLS_CC);
+}
+
+PHPAPI void php_stream_context_free(php_stream_context *context)
+{
+ efree(context);
+}
+
+PHPAPI php_stream_context *php_stream_context_alloc(void)
+{
+ return ecalloc(1, sizeof(php_stream_context));
+}
+
+PHPAPI php_stream_notifier *php_stream_notification_alloc(void)
+{
+ return ecalloc(1, sizeof(php_stream_notifier));
+}
+
+PHPAPI void php_stream_notification_free(php_stream_notifier *notifier)
+{
+ efree(notifier);
+}
+
+
/*
* Local variables:
* tab-width: 4
diff --git a/main/user_streams.c b/main/user_streams.c
index 4aed5d99ac..7f9a2c2701 100644
--- a/main/user_streams.c
+++ b/main/user_streams.c
@@ -29,7 +29,7 @@ struct php_user_stream_wrapper {
php_stream_wrapper wrapper;
};
-static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
+static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_wrapper_options *exoptions STREAMS_DC TSRMLS_DC);
static php_stream_wrapper_ops user_stream_wops = {
user_wrapper_opener,
@@ -115,7 +115,7 @@ function stream_open($path, $mode, $options, &$opened_path)
* */
-static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
+static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_wrapper_options *exoptions STREAMS_DC TSRMLS_DC)
{
struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
php_userstream_data_t *us;