PHP_FE(stream_context_set_params, NULL)
PHP_FE(stream_context_set_option, NULL)
PHP_FE(stream_context_get_options, NULL)
+ PHP_FE(stream_filter_prepend, NULL)
+ PHP_FE(stream_filter_append, NULL)
PHP_FE(fgetcsv, NULL)
PHP_FE(flock, NULL)
PHP_FE(get_meta_tags, NULL)
PHP_MINIT(file) (INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(pack) (INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(browscap) (INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(string_filters) (INIT_FUNC_ARGS_PASSTHRU);
#if defined(HAVE_LOCALECONV) && defined(ZTS)
PHP_MINIT(localeconv) (INIT_FUNC_ARGS_PASSTHRU);
PHP_MSHUTDOWN(assert) (SHUTDOWN_FUNC_ARGS_PASSTHRU);
PHP_MSHUTDOWN(url_scanner_ex) (SHUTDOWN_FUNC_ARGS_PASSTHRU);
PHP_MSHUTDOWN(file) (SHUTDOWN_FUNC_ARGS_PASSTHRU);
+ PHP_MSHUTDOWN(string_filters) (SHUTDOWN_FUNC_ARGS_PASSTHRU);
#if defined(HAVE_LOCALECONV) && defined(ZTS)
PHP_MSHUTDOWN(localeconv) (SHUTDOWN_FUNC_ARGS_PASSTHRU);
#endif
zval *options = NULL, *zcontext = NULL, *zvalue = NULL;
php_stream_context *context;
char *wrappername, *optionname;
- long wrapperlen, optionlen;
+ int wrapperlen, optionlen;
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
"rssz", &zcontext, &wrappername, &wrapperlen,
}
/* }}} */
+static void apply_filter_to_stream(int append, INTERNAL_FUNCTION_PARAMETERS)
+{
+ zval *zstream;
+ php_stream *stream;
+ char *filtername, *filterparams = NULL;
+ int filternamelen, filterparamslen = 0;
+ php_stream_filter *filter;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|s", &zstream,
+ &filtername, &filternamelen, &filterparams, &filterparamslen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ ZEND_FETCH_RESOURCE(stream, php_stream*, &zstream, -1, "stream", le_stream);
+
+ filter = php_stream_filter_create(filtername, filterparams, filterparamslen, php_stream_is_persistent(stream) TSRMLS_CC);
+ if (filter == NULL)
+ RETURN_FALSE;
+
+ if (append)
+ php_stream_filter_append(stream, filter);
+ else
+ php_stream_filter_prepend(stream, filter);
+
+ RETURN_TRUE;
+}
+
+/* {{{ proto bool stream_filter_prepend(resource stream, string filtername[, string filterparams])
+ Prepend a filter to a stream */
+PHP_FUNCTION(stream_filter_prepend)
+{
+ apply_filter_to_stream(0, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto bool stream_filter_append(resource stream, string filtername[, string filterparams])
+ Append a filter to a stream */
+PHP_FUNCTION(stream_filter_append)
+{
+ apply_filter_to_stream(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
/* {{{ 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)
PHP_FUNCTION(stream_context_set_params);
PHP_FUNCTION(stream_context_set_option);
PHP_FUNCTION(stream_context_get_options);
+PHP_FUNCTION(stream_filter_prepend);
+PHP_FUNCTION(stream_filter_append);
PHP_MINIT_FUNCTION(user_streams);
PHPAPI int php_set_sock_blocking(int socketd, int block TSRMLS_DC);
PHP_FUNCTION(money_format);
#endif
+PHP_MINIT_FUNCTION(string_filters);
+PHP_MSHUTDOWN_FUNCTION(string_filters);
+
#if defined(HAVE_LOCALECONV) && defined(ZTS)
PHP_MINIT_FUNCTION(localeconv);
PHP_MSHUTDOWN_FUNCTION(localeconv);
}
/* }}} */
+static char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
+
/* {{{ proto string str_rot13(string str)
Perform the rot13 transform on a string */
PHP_FUNCTION(str_rot13)
{
zval **arg;
- static char xfrom[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
- static char xto[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
-
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg)) {
WRONG_PARAM_COUNT;
}
*return_value = **arg;
zval_copy_ctor(return_value);
- php_strtr(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), xfrom, xto, 52);
+ php_strtr(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), rot13_from, rot13_to, 52);
}
/* }}} */
/* }}} */
#endif
+/* {{{ rot13 stream filter implementation */
+static size_t strfilter_rot13_write(php_stream *stream, php_stream_filter *thisfilter,
+ const char *buf, size_t count TSRMLS_DC)
+{
+ char rotbuf[1024];
+ size_t chunk;
+ size_t wrote = 0;
+
+ while (count > 0) {
+ chunk = count;
+ if (chunk > sizeof(rotbuf))
+ chunk = sizeof(rotbuf);
+
+ PHP_STRLCPY(rotbuf, buf, sizeof(rotbuf), chunk);
+ buf += chunk;
+ count -= chunk;
+
+ php_strtr(rotbuf, chunk, rot13_from, rot13_to, 52);
+ wrote += php_stream_filter_write_next(stream, thisfilter, rotbuf, chunk);
+ }
+
+ return wrote;
+}
+
+static size_t strfilter_rot13_read(php_stream *stream, php_stream_filter *thisfilter,
+ char *buf, size_t count TSRMLS_DC)
+{
+ size_t read;
+
+ read = php_stream_filter_read_next(stream, thisfilter, buf, count);
+ php_strtr(buf, read, rot13_from, rot13_to, 52);
+
+ return read;
+}
+
+static int strfilter_rot13_flush(php_stream *stream, php_stream_filter *thisfilter TSRMLS_DC)
+{
+ return php_stream_filter_flush_next(stream, thisfilter);
+}
+
+static int strfilter_rot13_eof(php_stream *stream, php_stream_filter *thisfilter TSRMLS_DC)
+{
+ return php_stream_filter_eof_next(stream, thisfilter);
+}
+
+
+static php_stream_filter_ops strfilter_rot13_ops = {
+ strfilter_rot13_write,
+ strfilter_rot13_read,
+ strfilter_rot13_flush,
+ strfilter_rot13_eof,
+ NULL,
+ "string.rot13"
+};
+
+static php_stream_filter *strfilter_rot13_create(const char *filtername, const char *filterparams,
+ int filterparamslen, int persistent TSRMLS_DC)
+{
+ return php_stream_filter_alloc(&strfilter_rot13_ops, NULL, persistent);
+}
+
+static php_stream_filter_factory strfilter_rot13_factory = {
+ strfilter_rot13_create
+};
+
+PHP_MINIT_FUNCTION(string_filters)
+{
+ return php_stream_filter_register_factory("string.rot13", &strfilter_rot13_factory);
+}
+
+PHP_MSHUTDOWN_FUNCTION(string_filters)
+{
+ return php_stream_filter_unregister_factory("string.rot13");
+}
+/* }}} */
+
/*
* Local variables:
* tab-width: 4
typedef struct _php_stream php_stream;
typedef struct _php_stream_wrapper php_stream_wrapper;
typedef struct _php_stream_context php_stream_context;
+typedef struct _php_stream_filter php_stream_filter;
/* callback for status notifications */
typedef void (*php_stream_notification_func)(php_stream_context *context,
char **err_stack;
};
-/* pushes an error message onto the stack for a wrapper instance */
-PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...);
+typedef struct _php_stream_filter_ops {
+ size_t (*write)(php_stream *stream, php_stream_filter *thisfilter,
+ const char *buf, size_t count TSRMLS_DC);
+ size_t (*read)(php_stream *stream, php_stream_filter *thisfilter,
+ char *buf, size_t count TSRMLS_DC);
+ int (*flush)(php_stream *stream, php_stream_filter *thisfilter TSRMLS_DC);
+ int (*eof)(php_stream *stream, php_stream_filter *thisfilter TSRMLS_DC);
+ void (*dtor)(php_stream_filter *thisfilter TSRMLS_DC);
+ const char *label;
+} php_stream_filter_ops;
+
+struct _php_stream_filter {
+ php_stream_filter_ops *fops;
+ void *abstract; /* for use by filter implementation */
+ php_stream_filter *next;
+ php_stream_filter *prev;
+ int is_persistent;
+ php_stream *stream;
+};
+
+#define php_stream_filter_write_next(stream, thisfilter, buf, size) \
+ (thisfilter)->next ? (thisfilter)->next->fops->write((stream), (thisfilter)->next, (buf), (size) TSRMLS_CC) \
+ : (stream)->ops->write((stream), (buf), (size) TSRMLS_CC)
+
+#define php_stream_filter_read_next(stream, thisfilter, buf, size) \
+ (thisfilter)->next ? (thisfilter)->next->fops->read((stream), (thisfilter)->next, (buf), (size) TSRMLS_CC) \
+ : (stream)->ops->read((stream), (buf), (size) TSRMLS_CC)
+#define php_stream_filter_flush_next(stream, thisfilter) \
+ (thisfilter)->next ? (thisfilter)->next->fops->flush((stream), (thisfilter) TSRMLS_CC) \
+ : (stream)->ops->flush((stream) TSRMLS_CC)
+
+#define php_stream_filter_eof_next(stream, thisfilter) \
+ (thisfilter)->next ? (thisfilter)->next->fops->eof((stream), (thisfilter) TSRMLS_CC) \
+ : (stream)->ops->read((stream), NULL, 0 TSRMLS_CC) == EOF ? 1 : 0
+
+
+
struct _php_stream {
php_stream_ops *ops;
void *abstract; /* convenience pointer for abstraction */
+ php_stream_filter *filterhead;
+ php_stream_filter *filtertail;
+
php_stream_wrapper *wrapper; /* which wrapper was used to open the stream */
void *wrapperthis; /* convenience pointer for a instance of a wrapper */
zval *wrapperdata; /* fgetwrapperdata retrieves this */
FILE *stdiocast; /* cache this, otherwise we might leak! */
#if ZEND_DEBUG
int __exposed; /* non-zero if exposed as a zval somewhere */
+ char *__orig_path; /* it really helps when debugging "unclosed" streams */
#endif
php_stream_context *context;
int persistent, const char *mode STREAMS_DC TSRMLS_DC);
#define php_stream_alloc(ops, thisptr, persistent, mode) _php_stream_alloc((ops), (thisptr), (persistent), (mode) STREAMS_CC TSRMLS_CC)
-#define php_stream_get_resource_id(stream) (stream)->rsrc_id
+/* stack filter onto a stream */
+PHPAPI void php_stream_filter_prepend(php_stream *stream, php_stream_filter *filter);
+PHPAPI void php_stream_filter_append(php_stream *stream, php_stream_filter *filter);
+PHPAPI php_stream_filter *php_stream_filter_remove(php_stream *stream, php_stream_filter *filter, int call_dtor TSRMLS_DC);
+PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC);
+PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC);
+#define php_stream_filter_alloc(fops, thisptr, persistent) _php_stream_filter_alloc((fops), (thisptr), (persistent) STREAMS_CC TSRMLS_CC)
+#define php_stream_filter_alloc_rel(fops, thisptr, persistent) _php_stream_filter_alloc((fops), (thisptr), (persistent) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_filter_remove_head(stream, call_dtor) php_stream_filter_remove((stream), (stream)->filterhead, (call_dtor) TSRMLS_CC)
+#define php_stream_filter_remove_tail(stream, call_dtor) php_stream_filter_remove((stream), (stream)->filtertail, (call_dtor) TSRMLS_CC)
+
+typedef struct _php_stream_filter_factory {
+ php_stream_filter *(*create_filter)(const char *filtername, const char *filterparams, int filterparamslen, int persistent TSRMLS_DC);
+} php_stream_filter_factory;
+
+PHPAPI int php_stream_filter_register_factory(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC);
+PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern TSRMLS_DC);
+PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, const char *filterparams, int filterparamslen, int persistent TSRMLS_DC);
+
+
+#define php_stream_get_resource_id(stream) (stream)->rsrc_id
#if ZEND_DEBUG
/* use this to tell the stream that it is OK if we don't explicitly close it */
# define php_stream_auto_cleanup(stream) { (stream)->__exposed++; }
#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)
+/* pushes an error message onto the stack for a wrapper instance */
+PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...);
+
+
#define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */
#define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */
#define PHP_STREAM_FAILED 2 /* an error occurred while attempting conversion */
#define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */
-/* DO NOT call this on streams that are referenced by resources! */
#define PHP_STREAM_NO_PREFERENCE 0
#define PHP_STREAM_PREFER_STDIO 1
+/* DO NOT call this on streams that are referenced by resources! */
PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC);
#define php_stream_make_seekable(origstream, newstream, flags) _php_stream_make_seekable((origstream), (newstream), (flags) STREAMS_CC TSRMLS_CC)
stream->in_free++;
+ php_stream_flush(stream);
+
if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0) {
/* Remove entry from the resource list */
zend_list_delete(stream->rsrc_id);
}
if (close_options & PHP_STREAM_FREE_RELEASE_STREAM) {
+
+ while (stream->filterhead) {
+ php_stream_filter_remove_head(stream, 1);
+ }
if (stream->wrapper && stream->wrapper->wops && stream->wrapper->wops->stream_closer) {
stream->wrapper->wops->stream_closer(stream->wrapper, stream TSRMLS_CC);
* as leaked; it will log a warning, but lets help it out and display what kind
* of stream it was. */
char leakbuf[512];
- snprintf(leakbuf, sizeof(leakbuf), __FILE__ "(%d) : Stream of type '%s' 0x%08X was not closed\n", __LINE__, stream->ops->label, (unsigned int)stream);
+ snprintf(leakbuf, sizeof(leakbuf), __FILE__ "(%d) : Stream of type '%s' 0x%08X (path:%s) was not closed\n", __LINE__, stream->ops->label, (unsigned int)stream, stream->__orig_path);
# if defined(PHP_WIN32)
OutputDebugString(leakbuf);
# else
}
/* }}} */
+static HashTable stream_filters_hash;
+
+PHPAPI int php_stream_filter_register_factory(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC)
+{
+ return zend_hash_add(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern), factory, sizeof(*factory), NULL);
+}
+
+PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern TSRMLS_DC)
+{
+ return zend_hash_del(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern));
+}
+
+/* We allow very simple pattern matching for filter factories:
+ * if "charset.utf-8/sjis" is requested, we search first for an exact
+ * match. If that fails, we try "charset.*".
+ * This means that we don't need to clog up the hashtable with a zillion
+ * charsets (for example) but still be able to provide them all as filters */
+PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, const char *filterparams, int filterparamslen, int persistent TSRMLS_DC)
+{
+ php_stream_filter_factory *factory;
+ php_stream_filter *filter = NULL;
+ int n;
+ char *period;
+
+ n = strlen(filtername);
+
+ if (SUCCESS == zend_hash_find(&stream_filters_hash, (char*)filtername, n, (void**)&factory)) {
+ filter = factory->create_filter(filtername, filterparams, filterparamslen, persistent TSRMLS_CC);
+ } else if ((period = strchr(filtername, '.'))) {
+ /* try a wildcard */
+ char wildname[128];
+
+ PHP_STRLCPY(wildname, filtername, sizeof(wildname) - 1, period-filtername + 1);
+ strcat(wildname, "*");
+
+ if (SUCCESS == zend_hash_find(&stream_filters_hash, wildname, strlen(wildname), (void**)&factory)) {
+ filter = factory->create_filter(filtername, filterparams, filterparamslen, persistent TSRMLS_CC);
+ }
+ }
+
+ if (filter == NULL) {
+ /* TODO: these need correct docrefs */
+ if (factory == NULL)
+ php_error_docref(NULL, E_WARNING TSRMLS_CC, "unable to locate filter \"%s\"", filtername);
+ else
+ php_error_docref(NULL, E_WARNING TSRMLS_CC, "unable to create or locate filter \"%s\"", filtername);
+ }
+
+ return filter;
+}
+
+PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC)
+{
+ php_stream_filter *filter;
+
+ filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent);
+ memset(filter, 0, sizeof(php_stream_filter));
+
+ filter->fops = fops;
+ filter->abstract = abstract;
+ filter->is_persistent = persistent;
+
+ return filter;
+}
+
+PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC)
+{
+ if (filter->fops->dtor)
+ filter->fops->dtor(filter TSRMLS_CC);
+ pefree(filter, filter->is_persistent);
+}
+
+PHPAPI void php_stream_filter_prepend(php_stream *stream, php_stream_filter *filter)
+{
+ filter->next = stream->filterhead;
+ filter->prev = NULL;
+
+ if (stream->filterhead) {
+ stream->filterhead->prev = filter;
+ } else {
+ stream->filtertail = filter;
+ }
+ stream->filterhead = filter;
+ filter->stream = stream;
+}
+
+PHPAPI void php_stream_filter_append(php_stream *stream, php_stream_filter *filter)
+{
+ filter->prev = stream->filtertail;
+ filter->next = NULL;
+ if (stream->filtertail) {
+ stream->filtertail->next = filter;
+ } else {
+ stream->filterhead = filter;
+ }
+ stream->filtertail = filter;
+ filter->stream = stream;
+}
+
+PHPAPI php_stream_filter *php_stream_filter_remove(php_stream *stream, php_stream_filter *filter, int call_dtor TSRMLS_DC)
+{
+ assert(stream == filter->stream);
+
+ if (filter->prev) {
+ filter->prev->next = filter->next;
+ } else {
+ stream->filterhead = filter->next;
+ }
+ if (filter->next) {
+ filter->next->prev = filter->prev;
+ } else {
+ stream->filtertail = filter->prev;
+ }
+ if (call_dtor) {
+ php_stream_filter_free(filter TSRMLS_CC);
+ return NULL;
+ }
+ return filter;
+}
+
/* {{{ generic stream operations */
PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC)
{
- return stream->ops->read == NULL ? 0 : stream->ops->read(stream, buf, size TSRMLS_CC);
+ if (stream->filterhead)
+ return stream->filterhead->fops->read(stream, stream->filterhead, buf, size TSRMLS_CC);
+
+ return stream->ops->read(stream, buf, size TSRMLS_CC);
}
PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC)
/* we define our stream reading function so that it
must return EOF when an EOF condition occurs, when
working in unbuffered mode and called with these args */
- return stream->ops->read == NULL ? -1 : stream->ops->read(stream, NULL, 0 TSRMLS_CC) == EOF ? 1 : 0;
+
+ if (stream->filterhead)
+ return stream->filterhead->fops->eof(stream, stream->filterhead TSRMLS_CC);
+
+ return stream->ops->read(stream, NULL, 0 TSRMLS_CC) == EOF ? 1 : 0;
}
PHPAPI int _php_stream_putc(php_stream *stream, int c TSRMLS_DC)
PHPAPI char *_php_stream_gets(php_stream *stream, char *buf, size_t maxlen TSRMLS_DC)
{
-
- if (maxlen == 0) {
- buf[0] = 0;
- return buf;
- }
-
- if (stream->ops->gets) {
- return stream->ops->gets(stream, buf, maxlen TSRMLS_CC);
- } else if (stream->ops->read == NULL) {
+ if (maxlen == 0)
return NULL;
- } else {
- /* unbuffered fgets - poor performance ! */
+
+ if (stream->filterhead || stream->ops->gets == NULL) {
+ /* unbuffered fgets - performance not so good! */
char *c = buf;
/* TODO: look at error returns? */
- while (--maxlen > 0 && stream->ops->read(stream, buf, 1 TSRMLS_CC) == 1 && *buf++ != '\n');
+ while (--maxlen > 0 && php_stream_read(stream, buf, 1 TSRMLS_CC) == 1 && *buf++ != '\n')
+ ;
*buf = '\0';
+
return c == buf && maxlen > 0 ? NULL : c;
+
+ } else if (stream->ops->gets) {
+ return stream->ops->gets(stream, buf, maxlen TSRMLS_CC);
}
+ /* should not happen */
+ return NULL;
}
PHPAPI int _php_stream_flush(php_stream *stream TSRMLS_DC)
{
+ if (stream->filterhead)
+ stream->filterhead->fops->flush(stream, stream->filterhead TSRMLS_CC);
+
if (stream->ops->flush) {
return stream->ops->flush(stream TSRMLS_CC);
}
assert(stream);
if (buf == NULL || count == 0 || stream->ops->write == NULL)
return 0;
- return stream->ops->write(stream, buf, count TSRMLS_CC);
+
+ if (stream->filterhead) {
+ return stream->filterhead->fops->write(stream, stream->filterhead, buf, count TSRMLS_CC);
+ } else {
+ return stream->ops->write(stream, buf, count TSRMLS_CC);
+ }
}
PHPAPI off_t _php_stream_tell(php_stream *stream TSRMLS_DC)
PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC)
{
if (stream->ops->seek) {
+
+ if (stream->filterhead)
+ stream->filterhead->fops->flush(stream, stream->filterhead TSRMLS_CC);
+
return stream->ops->seek(stream, offset, whence TSRMLS_CC);
}
#ifdef HAVE_MMAP
if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET)
+ && stream->filterhead == NULL
&& SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)&fd, 0))
{
struct stat sbuf;
* buffering layer.
* */
if ( php_stream_is(src, PHP_STREAM_IS_STDIO) &&
+ src->filterhead == NULL &&
php_stream_tell(src) == 0 &&
SUCCESS == php_stream_cast(src, PHP_STREAM_AS_FD, (void**)&srcfd, 0))
{
* buffering layer.
* */
if ( php_stream_is(src, PHP_STREAM_IS_STDIO) &&
+ src->filterhead == NULL &&
php_stream_tell(src) == 0 &&
SUCCESS == php_stream_cast(src, PHP_STREAM_AS_FD, (void**)&srcfd, 0))
{
int flags = castas & PHP_STREAM_CAST_MASK;
castas &= ~PHP_STREAM_CAST_MASK;
+ /* filtered streams can only be cast as stdio, and only when fopencookie is present */
+
if (castas == PHP_STREAM_AS_STDIO) {
if (stream->stdiocast) {
if (ret) {
* first, to avoid doubling up the layers of stdio with an fopencookie */
if (php_stream_is(stream, PHP_STREAM_IS_STDIO) &&
stream->ops->cast &&
+ stream->filterhead == NULL &&
stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS)
{
goto exit_success;
#endif
}
+
+ if (stream->filterhead) {
+ php_error_docref(NULL, E_WARNING TSRMLS_CC, "cannot cast a filtered stream on this system");
+ return FAILURE;
+ }
+
if (stream->ops->cast && stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS)
goto exit_success;
/* {{{ wrapper init and registration */
int php_init_stream_wrappers(TSRMLS_D)
{
- return zend_hash_init(&url_stream_wrappers_hash, 0, NULL, NULL, 1);
+ return zend_hash_init(&url_stream_wrappers_hash, 0, NULL, NULL, 1) == SUCCESS && zend_hash_init(&stream_filters_hash, 0, NULL, NULL, 1) == SUCCESS ? SUCCESS : FAILURE;
}
int php_shutdown_stream_wrappers(TSRMLS_D)
{
zend_hash_destroy(&url_stream_wrappers_hash);
+ zend_hash_destroy(&stream_filters_hash);
return SUCCESS;
}
php_stream *stream = NULL;
php_stream_wrapper *wrapper = NULL;
char *path_to_open;
+#if ZEND_DEBUG
+ char *copy_of_path = NULL;
+#endif
+
if (opened_path)
*opened_path = NULL;
stream->wrapper = wrapper;
}
+#if ZEND_DEBUG
+ if (stream) {
+ copy_of_path = estrdup(path);
+ stream->__orig_path = copy_of_path;
+ }
+#endif
+
if (stream != NULL && (options & STREAM_MUST_SEEK)) {
php_stream *newstream;
case PHP_STREAM_UNCHANGED:
return stream;
case PHP_STREAM_RELEASED:
+#if ZEND_DEBUG
+ newstream->__orig_path = copy_of_path;
+#endif
return newstream;
default:
php_stream_close(stream);
efree(wrapper->err_stack);
wrapper->err_stack = NULL;
}
+#if ZEND_DEBUG
+ if (stream == NULL && copy_of_path != NULL)
+ efree(copy_of_path);
+#endif
return stream;
}
/* }}} */
if (stream == NULL)
return NULL;
-
+
if (php_stream_cast(stream, PHP_STREAM_AS_STDIO|PHP_STREAM_CAST_TRY_HARD|PHP_STREAM_CAST_RELEASE,
(void**)&fp, REPORT_ERRORS) == FAILURE)
{