diff options
author | Wez Furlong <wez@php.net> | 2002-04-10 22:42:32 +0000 |
---|---|---|
committer | Wez Furlong <wez@php.net> | 2002-04-10 22:42:32 +0000 |
commit | e1d0a147901d27bb01b0ccda315a9fdd3474e1ee (patch) | |
tree | 693eee9be6ba188c62f1223eb2c96f70f23256dd | |
parent | 3eafd2207ccb313cff264c2e5baaa26b707fbe4f (diff) | |
download | php-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.frag | 1 | ||||
-rw-r--r-- | ext/standard/basic_functions.c | 2 | ||||
-rw-r--r-- | ext/standard/file.c | 159 | ||||
-rw-r--r-- | ext/standard/file.h | 2 | ||||
-rw-r--r-- | ext/standard/ftp_fopen_wrapper.c | 76 | ||||
-rw-r--r-- | ext/standard/http_fopen_wrapper.c | 57 | ||||
-rw-r--r-- | ext/standard/php_fopen_wrapper.c | 2 | ||||
-rw-r--r-- | ext/standard/php_fopen_wrappers.h | 4 | ||||
-rw-r--r-- | ext/zlib/php_zlib.h | 2 | ||||
-rw-r--r-- | ext/zlib/zlib.c | 6 | ||||
-rw-r--r-- | ext/zlib/zlib_fopen_wrapper.c | 3 | ||||
-rw-r--r-- | main/main.c | 9 | ||||
-rw-r--r-- | main/network.c | 18 | ||||
-rwxr-xr-x | main/php_streams.h | 101 | ||||
-rwxr-xr-x | main/streams.c | 49 | ||||
-rw-r--r-- | main/user_streams.c | 4 |
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, ¶ms) == 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", ¶ms) == 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; |