From 77312522be5d5818b87a93a535b83afbe01f2a26 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 4 Nov 2024 16:35:33 +0100 Subject: [PATCH 1/4] Limit the number of filters Chaining filters is becoming an increasingly popular primitive to exploit PHP applications. Limiting the usage of only a few of them at the time should, if not close entirely, make it significantly less attractive. This should close #10453 --- ext/standard/php_fopen_wrapper.c | 10 ++++++++++ tests/security/bug10453.phpt | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/security/bug10453.phpt diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index 89c2d9c49b0c..02d73c036dcc 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -26,6 +26,7 @@ #include "php_memory_streams.h" #include "php_fopen_wrappers.h" #include "SAPI.h" +#include "zend_exceptions.h" static ssize_t php_stream_output_write(php_stream *stream, const char *buf, size_t count) /* {{{ */ { @@ -144,13 +145,22 @@ static const php_stream_ops php_stream_input_ops = { NULL /* set_option */ }; +static const char max_stream_filters = 5; + static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain) /* {{{ */ { char *p, *token = NULL; php_stream_filter *temp_filter; + char nb_filters = 0; p = php_strtok_r(filterlist, "|", &token); while (p) { + if (nb_filters >= max_stream_filters) { + zend_throw_exception_ex(NULL, 0, "Unable to apply filter, maximum number (%d) reached", max_stream_filters); + return; + } + nb_filters++; + php_url_decode(p, strlen(p)); if (read_chain) { if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) { diff --git a/tests/security/bug10453.phpt b/tests/security/bug10453.phpt new file mode 100644 index 000000000000..c83294eaae19 --- /dev/null +++ b/tests/security/bug10453.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #10453 (using a high amount of filters for nefarious purposes) +--FILE-- + +--EXPECTF-- +This is a test. + +Fatal error: Uncaught Exception: Unable to apply filter, maximum number (5) reached in %s +Stack trace: +#0 %s: fopen('php://filter/wr...', 'w') +#1 {main} + thrown in %s From a3159004d31b84b164bd956a591f45768a9f98ae Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Tue, 5 May 2026 18:15:56 +0000 Subject: [PATCH 2/4] Count number of filters, raise deprecation warning Limit number of filters that can be chained in a php://filter URL. Count number of filters already on the stream, instead of counting iterations on the loop. When filters are separated by slash instead of pipe, php_stream_apply_filter_list is called muliple times, so counting iterations won't work. Instead, count numbers of filters already on the chain. Add more elaborate test that tests: - file read - file include - no warning on stream_filter_append Related to: https://github.com/php/php-src/issues/10453 https://github.com/php/php-src/pull/16699 --- ext/standard/php_fopen_wrapper.c | 16 ++-- .../tests/filters/max_filter_chain.phpt | 85 +++++++++++++++++++ main/streams/filter.c | 14 +++ main/streams/php_stream_filter_api.h | 1 + tests/security/bug10453.phpt | 20 ----- 5 files changed, 107 insertions(+), 29 deletions(-) create mode 100644 ext/standard/tests/filters/max_filter_chain.phpt delete mode 100644 tests/security/bug10453.phpt diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index 02d73c036dcc..112e0e90794d 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -26,7 +26,6 @@ #include "php_memory_streams.h" #include "php_fopen_wrappers.h" #include "SAPI.h" -#include "zend_exceptions.h" static ssize_t php_stream_output_write(php_stream *stream, const char *buf, size_t count) /* {{{ */ { @@ -145,24 +144,20 @@ static const php_stream_ops php_stream_input_ops = { NULL /* set_option */ }; -static const char max_stream_filters = 5; +static const int max_stream_filters = 16; static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain) /* {{{ */ { char *p, *token = NULL; php_stream_filter *temp_filter; - char nb_filters = 0; p = php_strtok_r(filterlist, "|", &token); while (p) { - if (nb_filters >= max_stream_filters) { - zend_throw_exception_ex(NULL, 0, "Unable to apply filter, maximum number (%d) reached", max_stream_filters); - return; - } - nb_filters++; - php_url_decode(p, strlen(p)); if (read_chain) { + if (php_stream_filter_count(&stream->readfilters) == max_stream_filters) { + zend_error(E_DEPRECATED, "Using more than %d filters in a php://filter URL is deprecated, use stream_filter_append to chain more than %d filters", max_stream_filters, max_stream_filters); + } if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) { php_stream_filter_append(&stream->readfilters, temp_filter); } else { @@ -170,6 +165,9 @@ static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, i } } if (write_chain) { + if (php_stream_filter_count(&stream->writefilters) == max_stream_filters) { + zend_error(E_DEPRECATED, "Using more than %d filters in a php://filter URL is deprecated, use stream_filter_append to chain more than %d filters", max_stream_filters, max_stream_filters); + } if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) { php_stream_filter_append(&stream->writefilters, temp_filter); } else { diff --git a/ext/standard/tests/filters/max_filter_chain.phpt b/ext/standard/tests/filters/max_filter_chain.phpt new file mode 100644 index 000000000000..33ce0f8fe0f6 --- /dev/null +++ b/ext/standard/tests/filters/max_filter_chain.phpt @@ -0,0 +1,85 @@ +--TEST-- +At most 16 filters can be chained in one stream +--EXTENSIONS-- +filter +--FILE-- + +--EXPECTF-- +string(7) "SIXTEEN" +string(7) "SIXTEEN" +string(7) "SIXTEEN" +int(1) +int(1) +int(1) + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +string(9) "SEVENTEEN" + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +string(9) "SEVENTEEN" + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +string(9) "SEVENTEEN" + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +int(1) + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +int(1) + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +int(1) + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +string(8) "EIGHTEEN" + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +string(8) "EIGHTEEN" + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +string(8) "EIGHTEEN" +string(20) "STREAM_FILTER_APPEND" diff --git a/main/streams/filter.c b/main/streams/filter.c index 3a19f5ce918a..58449c8c8530 100644 --- a/main/streams/filter.c +++ b/main/streams/filter.c @@ -447,6 +447,20 @@ PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream } } +PHPAPI int php_stream_filter_count(php_stream_filter_chain *chain) { + if (chain->head == NULL) { + return 0; + } + + int count = 1; + php_stream_filter *node = chain->head; + while (node != chain->tail) { + count += 1; + node = node->next; + } + return count; +} + PHPAPI zend_result _php_stream_filter_flush(php_stream_filter *filter, bool finish) { php_stream_bucket_brigade brig_a = { NULL, NULL }, brig_b = { NULL, NULL }, *inp = &brig_a, *outp = &brig_b, *brig_temp; diff --git a/main/streams/php_stream_filter_api.h b/main/streams/php_stream_filter_api.h index 111127a8ad1a..e31ef2182dbe 100644 --- a/main/streams/php_stream_filter_api.h +++ b/main/streams/php_stream_filter_api.h @@ -138,6 +138,7 @@ PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_strea PHPAPI void php_stream_filter_prepend_ex(php_stream_filter_chain *chain, php_stream_filter *filter); PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter); PHPAPI zend_result php_stream_filter_append_ex(php_stream_filter_chain *chain, php_stream_filter *filter); +PHPAPI int php_stream_filter_count(php_stream_filter_chain *chain); PHPAPI zend_result _php_stream_filter_flush(php_stream_filter *filter, bool finish); PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, bool call_dtor); PHPAPI void php_stream_filter_free(php_stream_filter *filter); diff --git a/tests/security/bug10453.phpt b/tests/security/bug10453.phpt deleted file mode 100644 index c83294eaae19..000000000000 --- a/tests/security/bug10453.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Bug #10453 (using a high amount of filters for nefarious purposes) ---FILE-- - ---EXPECTF-- -This is a test. - -Fatal error: Uncaught Exception: Unable to apply filter, maximum number (5) reached in %s -Stack trace: -#0 %s: fopen('php://filter/wr...', 'w') -#1 {main} - thrown in %s From af279cb089939038d9e65e5a5e6249d5b10c7960 Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Fri, 22 May 2026 07:35:48 +0000 Subject: [PATCH 3/4] Error when max_filter_count is set and exceeded Read the maximum number of filters from context stream. If it is set, it doesn't make sense to raise a deprecation warning, because this stream context option didn't exist earlier. We raise an error consistent with current stream handling, as long as rfc/stream_errors has not landed. If it is not set, we give a deprecation warning when the 17th filter is added. This is unfortunately done in another place; to prevent showing warnings multiple times, the counting is done within the loop and not at the end. --- ext/standard/php_fopen_wrapper.c | 54 +++++++++++++++---- .../tests/filters/max_filter_chain.phpt | 42 +++++++++++---- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index 112e0e90794d..a0fa9f052be0 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -144,20 +144,47 @@ static const php_stream_ops php_stream_input_ops = { NULL /* set_option */ }; -static const int max_stream_filters = 16; +static const int max_filter_count_default = 16; + +static int php_get_max_filter_count(php_stream_context *context) { + if (context != NULL) { + zval *option_val = php_stream_context_get_option(context, "filter", "max_filter_count"); + if (option_val) { + zend_long custom_limit = zval_get_long(option_val); + if (custom_limit >= 0) { + return (int)custom_limit; + } + } + } + return -1; +} + +static bool php_stream_has_too_many_filters(php_stream *stream, php_stream_context *context) { + int max_filter_count = php_get_max_filter_count(context); + if (max_filter_count == -1) { + // If not explicitly configured we don't throw an error yet. + return false; + } -static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain) /* {{{ */ + int count = MAX(php_stream_filter_count(&stream->readfilters), php_stream_filter_count(&stream->writefilters)); + return count > max_filter_count; +} + +static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain, bool warn_filter_count) /* {{{ */ { char *p, *token = NULL; php_stream_filter *temp_filter; p = php_strtok_r(filterlist, "|", &token); while (p) { + int count = read_chain ? php_stream_filter_count(&stream->readfilters) : write_chain ? php_stream_filter_count(&stream->writefilters) : 0; + if (warn_filter_count && count == max_filter_count_default) { + zend_error(E_DEPRECATED, "Using more than %d filters in a php://filter URL is deprecated, " + "set this limit using the stream context option max_filter_count, or use stream_filter_append", max_filter_count_default); + } + php_url_decode(p, strlen(p)); if (read_chain) { - if (php_stream_filter_count(&stream->readfilters) == max_stream_filters) { - zend_error(E_DEPRECATED, "Using more than %d filters in a php://filter URL is deprecated, use stream_filter_append to chain more than %d filters", max_stream_filters, max_stream_filters); - } if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) { php_stream_filter_append(&stream->readfilters, temp_filter); } else { @@ -165,9 +192,6 @@ static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, i } } if (write_chain) { - if (php_stream_filter_count(&stream->writefilters) == max_stream_filters) { - zend_error(E_DEPRECATED, "Using more than %d filters in a php://filter URL is deprecated, use stream_filter_append to chain more than %d filters", max_stream_filters, max_stream_filters); - } if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) { php_stream_filter_append(&stream->writefilters, temp_filter); } else { @@ -363,16 +387,18 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c return NULL; } + bool max_filter_count_not_set = php_get_max_filter_count(context) == -1; + *p = '\0'; p = php_strtok_r(pathdup + 1, "/", &token); while (p) { if (!strncasecmp(p, "read=", 5)) { - php_stream_apply_filter_list(stream, p + 5, 1, 0); + php_stream_apply_filter_list(stream, p + 5, 1, 0, max_filter_count_not_set); } else if (!strncasecmp(p, "write=", 6)) { - php_stream_apply_filter_list(stream, p + 6, 0, 1); + php_stream_apply_filter_list(stream, p + 6, 0, 1, max_filter_count_not_set); } else { - php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE); + php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE, max_filter_count_not_set); } p = php_strtok_r(NULL, "/", &token); } @@ -383,6 +409,12 @@ static php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const c return NULL; } + if (php_stream_has_too_many_filters(stream, context)) { + php_stream_wrapper_log_error(wrapper, options, "too many filters"); + php_stream_close(stream); + return NULL; + } + return stream; } else { /* invalid php://thingy */ diff --git a/ext/standard/tests/filters/max_filter_chain.phpt b/ext/standard/tests/filters/max_filter_chain.phpt index 33ce0f8fe0f6..520c84b167be 100644 --- a/ext/standard/tests/filters/max_filter_chain.phpt +++ b/ext/standard/tests/filters/max_filter_chain.phpt @@ -33,6 +33,18 @@ foreach ($blocked_include as $chain) { var_dump(include $chain); } +$ctx = stream_context_create(['filter' => ['max_filter_count' => 2]]); +$blocked_read = createFilterChains(3, 'data:text/plain,three'); +foreach ($blocked_read as $chain) { + var_dump(file_get_contents($chain, false, $ctx)); +} + +$ctx = stream_context_create(['filter' => ['max_filter_count' => 20]]); +$allowed_read = createFilterChains(19, 'data:text/plain,nineteen'); +foreach ($allowed_read as $chain) { + var_dump(file_get_contents($chain, false, $ctx)); +} + // Test that the warning is only given once, even when we add two filters over the limit. $blocked_read = createFilterChains(18, 'data:text/plain,eighteen'); foreach ($blocked_read as $chain) { @@ -56,30 +68,42 @@ int(1) int(1) int(1) -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d string(9) "SEVENTEEN" -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d string(9) "SEVENTEEN" -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d string(9) "SEVENTEEN" -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d int(1) -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d int(1) -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d int(1) -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Warning: file_get_contents(php://filter/string.toupper|string.toupper|string.toupper/resource=data:text/plain,three): Failed to open stream: too many filters in %s on line %d +bool(false) + +Warning: file_get_contents(php://filter/string.toupper/string.toupper/string.toupper/resource=data:text/plain,three): Failed to open stream: too many filters in %s on line %d +bool(false) + +Warning: file_get_contents(php://filter/string.toupper/resource=php://filter/string.toupper/resource=php://filter/string.toupper/resource=data:text/plain,three): Failed to open stream: too many filters in %s on line %d +bool(false) +string(8) "NINETEEN" +string(8) "NINETEEN" +string(8) "NINETEEN" + +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d string(8) "EIGHTEEN" -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d string(8) "EIGHTEEN" -Deprecated: Using more than 16 filters in a php://filter URL is deprecated, use stream_filter_append to chain more than 16 filters in %smax_filter_chain.php on line %d +Deprecated: Using more than 16 filters in a php://filter URL is deprecated, set this limit using the stream context option max_filter_count, or use stream_filter_append in %smax_filter_chain.php on line %d string(8) "EIGHTEEN" string(20) "STREAM_FILTER_APPEND" From 6da0c2fcf39c484a4a4a2eb7de6de3099e1cb879 Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Fri, 22 May 2026 11:45:17 +0000 Subject: [PATCH 4/4] Use zend_long consistently for filter count We get a zend_long from the stream context, so it makes sense to consistently use it for all counts of filters. --- ext/standard/php_fopen_wrapper.c | 12 ++++++------ main/streams/filter.c | 2 +- main/streams/php_stream_filter_api.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index a0fa9f052be0..b53a7d80f42d 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -144,15 +144,15 @@ static const php_stream_ops php_stream_input_ops = { NULL /* set_option */ }; -static const int max_filter_count_default = 16; +static const zend_long max_filter_count_default = 16; -static int php_get_max_filter_count(php_stream_context *context) { +static zend_long php_get_max_filter_count(php_stream_context *context) { if (context != NULL) { zval *option_val = php_stream_context_get_option(context, "filter", "max_filter_count"); if (option_val) { zend_long custom_limit = zval_get_long(option_val); if (custom_limit >= 0) { - return (int)custom_limit; + return custom_limit; } } } @@ -160,13 +160,13 @@ static int php_get_max_filter_count(php_stream_context *context) { } static bool php_stream_has_too_many_filters(php_stream *stream, php_stream_context *context) { - int max_filter_count = php_get_max_filter_count(context); + zend_long max_filter_count = php_get_max_filter_count(context); if (max_filter_count == -1) { // If not explicitly configured we don't throw an error yet. return false; } - int count = MAX(php_stream_filter_count(&stream->readfilters), php_stream_filter_count(&stream->writefilters)); + zend_long count = MAX(php_stream_filter_count(&stream->readfilters), php_stream_filter_count(&stream->writefilters)); return count > max_filter_count; } @@ -177,7 +177,7 @@ static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, i p = php_strtok_r(filterlist, "|", &token); while (p) { - int count = read_chain ? php_stream_filter_count(&stream->readfilters) : write_chain ? php_stream_filter_count(&stream->writefilters) : 0; + zend_long count = read_chain ? php_stream_filter_count(&stream->readfilters) : write_chain ? php_stream_filter_count(&stream->writefilters) : 0; if (warn_filter_count && count == max_filter_count_default) { zend_error(E_DEPRECATED, "Using more than %d filters in a php://filter URL is deprecated, " "set this limit using the stream context option max_filter_count, or use stream_filter_append", max_filter_count_default); diff --git a/main/streams/filter.c b/main/streams/filter.c index 58449c8c8530..265b21be27e8 100644 --- a/main/streams/filter.c +++ b/main/streams/filter.c @@ -447,7 +447,7 @@ PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream } } -PHPAPI int php_stream_filter_count(php_stream_filter_chain *chain) { +PHPAPI zend_long php_stream_filter_count(php_stream_filter_chain *chain) { if (chain->head == NULL) { return 0; } diff --git a/main/streams/php_stream_filter_api.h b/main/streams/php_stream_filter_api.h index e31ef2182dbe..612c71330051 100644 --- a/main/streams/php_stream_filter_api.h +++ b/main/streams/php_stream_filter_api.h @@ -138,7 +138,7 @@ PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_strea PHPAPI void php_stream_filter_prepend_ex(php_stream_filter_chain *chain, php_stream_filter *filter); PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter); PHPAPI zend_result php_stream_filter_append_ex(php_stream_filter_chain *chain, php_stream_filter *filter); -PHPAPI int php_stream_filter_count(php_stream_filter_chain *chain); +PHPAPI zend_long php_stream_filter_count(php_stream_filter_chain *chain); PHPAPI zend_result _php_stream_filter_flush(php_stream_filter *filter, bool finish); PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, bool call_dtor); PHPAPI void php_stream_filter_free(php_stream_filter *filter);