2002-12-31 18:39:36 +00:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
2004-01-08 08:18:22 +00:00
|
|
|
| PHP Version 5 |
|
2002-12-31 18:39:36 +00:00
|
|
|
+----------------------------------------------------------------------+
|
2006-01-01 12:51:34 +00:00
|
|
|
| Copyright (c) 1997-2006 The PHP Group |
|
2002-12-31 18:39:36 +00:00
|
|
|
+----------------------------------------------------------------------+
|
2006-01-01 12:51:34 +00:00
|
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
2002-12-31 18:39:36 +00:00
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
2003-06-10 20:04:29 +00:00
|
|
|
| available through the world-wide-web at the following url: |
|
2006-01-01 12:51:34 +00:00
|
|
|
| http://www.php.net/license/3_01.txt |
|
2002-12-31 18:39:36 +00:00
|
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Authors: |
|
|
|
|
| Wez Furlong (wez@thebrainroom.com) |
|
2003-02-24 21:56:19 +00:00
|
|
|
| Sara Golemon (pollita@php.net) |
|
2002-12-31 18:39:36 +00:00
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
#include "php.h"
|
|
|
|
#include "php_globals.h"
|
|
|
|
#include "ext/standard/basic_functions.h"
|
|
|
|
#include "ext/standard/file.h"
|
|
|
|
|
2003-02-24 21:56:19 +00:00
|
|
|
#define PHP_STREAM_BRIGADE_RES_NAME "userfilter.bucket brigade"
|
|
|
|
#define PHP_STREAM_BUCKET_RES_NAME "userfilter.bucket"
|
|
|
|
#define PHP_STREAM_FILTER_RES_NAME "userfilter.filter"
|
|
|
|
|
2002-12-31 18:39:36 +00:00
|
|
|
struct php_user_filter_data {
|
|
|
|
zend_class_entry *ce;
|
|
|
|
/* variable length; this *must* be last in the structure */
|
|
|
|
char classname[1];
|
|
|
|
};
|
|
|
|
|
|
|
|
/* to provide context for calling into the next filter from user-space */
|
|
|
|
static int le_userfilters;
|
2003-02-24 21:56:19 +00:00
|
|
|
static int le_bucket_brigade;
|
|
|
|
static int le_bucket;
|
2002-12-31 18:39:36 +00:00
|
|
|
|
|
|
|
#define GET_FILTER_FROM_OBJ() { \
|
|
|
|
zval **tmp; \
|
|
|
|
if (FAILURE == zend_hash_index_find(Z_OBJPROP_P(this_ptr), 0, (void**)&tmp)) { \
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "filter property vanished"); \
|
|
|
|
RETURN_FALSE; \
|
|
|
|
} \
|
|
|
|
ZEND_FETCH_RESOURCE(filter, php_stream_filter*, tmp, -1, "filter", le_userfilters); \
|
|
|
|
}
|
|
|
|
|
|
|
|
/* define the base filter class */
|
|
|
|
|
|
|
|
PHP_FUNCTION(user_filter_nop)
|
|
|
|
{
|
|
|
|
}
|
2006-06-26 17:23:39 +00:00
|
|
|
static
|
|
|
|
ZEND_BEGIN_ARG_INFO(arginfo_php_user_filter_filter, 0)
|
|
|
|
ZEND_ARG_INFO(0, in)
|
|
|
|
ZEND_ARG_INFO(0, out)
|
|
|
|
ZEND_ARG_INFO(1, consumed)
|
|
|
|
ZEND_ARG_INFO(0, closing)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
|
|
static
|
|
|
|
ZEND_BEGIN_ARG_INFO(arginfo_php_user_filter_onCreate, 0)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
|
|
static
|
|
|
|
ZEND_BEGIN_ARG_INFO(arginfo_php_user_filter_onClose, 0)
|
|
|
|
ZEND_END_ARG_INFO()
|
2002-12-31 18:39:36 +00:00
|
|
|
|
|
|
|
static zend_function_entry user_filter_class_funcs[] = {
|
2006-06-26 17:23:39 +00:00
|
|
|
PHP_NAMED_FE(filter, PHP_FN(user_filter_nop), arginfo_php_user_filter_filter)
|
|
|
|
PHP_NAMED_FE(onCreate, PHP_FN(user_filter_nop), arginfo_php_user_filter_onCreate)
|
|
|
|
PHP_NAMED_FE(onClose, PHP_FN(user_filter_nop), arginfo_php_user_filter_onClose)
|
2002-12-31 18:39:36 +00:00
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static zend_class_entry user_filter_class_entry;
|
|
|
|
|
2006-03-28 16:01:04 +00:00
|
|
|
static ZEND_RSRC_DTOR_FUNC(php_bucket_dtor)
|
|
|
|
{
|
2006-03-30 21:10:23 +00:00
|
|
|
php_stream_bucket *bucket = (php_stream_bucket *)rsrc->ptr;
|
2006-03-28 16:01:04 +00:00
|
|
|
if (bucket) {
|
|
|
|
php_stream_bucket_delref(bucket TSRMLS_CC);
|
|
|
|
bucket = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-31 18:39:36 +00:00
|
|
|
PHP_MINIT_FUNCTION(user_filters)
|
|
|
|
{
|
2006-06-26 17:23:39 +00:00
|
|
|
zend_class_entry *php_user_filter;
|
2002-12-31 18:39:36 +00:00
|
|
|
/* init the filter class ancestor */
|
|
|
|
INIT_CLASS_ENTRY(user_filter_class_entry, "php_user_filter", user_filter_class_funcs);
|
2006-06-26 17:23:39 +00:00
|
|
|
if ((php_user_filter = zend_register_internal_class(&user_filter_class_entry TSRMLS_CC)) == NULL) {
|
2002-12-31 18:39:36 +00:00
|
|
|
return FAILURE;
|
|
|
|
}
|
2006-06-26 17:23:39 +00:00
|
|
|
zend_declare_property_string(php_user_filter, "filtername", sizeof("filtername")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC);
|
|
|
|
zend_declare_property_string(php_user_filter, "params", sizeof("params")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC);
|
2002-12-31 18:39:36 +00:00
|
|
|
|
|
|
|
/* init the filter resource; it has no dtor, as streams will always clean it up
|
|
|
|
* at the correct time */
|
2003-02-24 21:56:19 +00:00
|
|
|
le_userfilters = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_FILTER_RES_NAME, 0);
|
|
|
|
|
|
|
|
if (le_userfilters == FAILURE) {
|
|
|
|
return FAILURE;
|
|
|
|
}
|
2002-12-31 18:39:36 +00:00
|
|
|
|
2003-06-13 22:25:29 +00:00
|
|
|
/* Filters will dispose of their brigades */
|
2003-02-24 21:56:19 +00:00
|
|
|
le_bucket_brigade = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_BRIGADE_RES_NAME, module_number);
|
2003-06-13 22:25:29 +00:00
|
|
|
/* Brigades will dispose of their buckets */
|
2006-03-28 16:01:04 +00:00
|
|
|
le_bucket = zend_register_list_destructors_ex(php_bucket_dtor, NULL, PHP_STREAM_BUCKET_RES_NAME, module_number);
|
2003-02-24 21:56:19 +00:00
|
|
|
|
|
|
|
if (le_bucket_brigade == FAILURE) {
|
2002-12-31 18:39:36 +00:00
|
|
|
return FAILURE;
|
2003-02-24 21:56:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
REGISTER_LONG_CONSTANT("PSFS_PASS_ON", PSFS_PASS_ON, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("PSFS_FEED_ME", PSFS_FEED_ME, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("PSFS_ERR_FATAL", PSFS_ERR_FATAL, CONST_CS | CONST_PERSISTENT);
|
|
|
|
|
|
|
|
REGISTER_LONG_CONSTANT("PSFS_FLAG_NORMAL", PSFS_FLAG_NORMAL, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("PSFS_FLAG_FLUSH_INC", PSFS_FLAG_FLUSH_INC, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("PSFS_FLAG_FLUSH_CLOSE", PSFS_FLAG_FLUSH_CLOSE, CONST_CS | CONST_PERSISTENT);
|
2002-12-31 18:39:36 +00:00
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-08-07 19:53:31 +00:00
|
|
|
PHP_RSHUTDOWN_FUNCTION(user_filters)
|
|
|
|
{
|
|
|
|
if (BG(user_filter_map)) {
|
|
|
|
zend_hash_destroy(BG(user_filter_map));
|
|
|
|
efree(BG(user_filter_map));
|
|
|
|
BG(user_filter_map) = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
static void userfilter_dtor(php_stream_filter *thisfilter TSRMLS_DC)
|
2002-12-31 18:39:36 +00:00
|
|
|
{
|
|
|
|
zval *obj = (zval*)thisfilter->abstract;
|
|
|
|
zval func_name;
|
|
|
|
zval *retval = NULL;
|
|
|
|
|
2003-10-28 23:56:57 +00:00
|
|
|
if (obj == NULL) {
|
|
|
|
/* If there's no object associated then there's nothing to dispose of */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
ZVAL_STRINGL(&func_name, "onclose", sizeof("onclose")-1, 0);
|
2002-12-31 18:39:36 +00:00
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
call_user_function_ex(NULL,
|
2002-12-31 18:39:36 +00:00
|
|
|
&obj,
|
|
|
|
&func_name,
|
|
|
|
&retval,
|
2003-02-18 01:22:21 +00:00
|
|
|
0, NULL,
|
2002-12-31 18:39:36 +00:00
|
|
|
0, NULL TSRMLS_CC);
|
|
|
|
|
|
|
|
if (retval)
|
|
|
|
zval_ptr_dtor(&retval);
|
2003-01-07 08:57:27 +00:00
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
/* kill the object */
|
|
|
|
zval_ptr_dtor(&obj);
|
2002-12-31 18:39:36 +00:00
|
|
|
}
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
php_stream_filter_status_t userfilter_filter(
|
|
|
|
php_stream *stream,
|
|
|
|
php_stream_filter *thisfilter,
|
|
|
|
php_stream_bucket_brigade *buckets_in,
|
|
|
|
php_stream_bucket_brigade *buckets_out,
|
|
|
|
size_t *bytes_consumed,
|
|
|
|
int flags
|
|
|
|
TSRMLS_DC)
|
2002-12-31 18:39:36 +00:00
|
|
|
{
|
2003-02-24 21:56:19 +00:00
|
|
|
int ret = PSFS_ERR_FATAL;
|
2002-12-31 18:39:36 +00:00
|
|
|
zval *obj = (zval*)thisfilter->abstract;
|
|
|
|
zval func_name;
|
|
|
|
zval *retval = NULL;
|
2003-02-24 21:56:19 +00:00
|
|
|
zval **args[4];
|
|
|
|
zval *zclosing, *zconsumed, *zin, *zout, *zstream;
|
2002-12-31 18:39:36 +00:00
|
|
|
int call_result;
|
|
|
|
|
2003-04-21 18:43:36 +00:00
|
|
|
if (FAILURE == zend_hash_find(Z_OBJPROP_P(obj), "stream", sizeof("stream"), (void**)&zstream)) {
|
2003-02-24 21:56:19 +00:00
|
|
|
/* Give the userfilter class a hook back to the stream */
|
2003-04-21 18:43:36 +00:00
|
|
|
ALLOC_INIT_ZVAL(zstream);
|
2003-06-13 22:25:29 +00:00
|
|
|
php_stream_to_zval(stream, zstream);
|
2003-02-24 21:56:19 +00:00
|
|
|
add_property_zval(obj, "stream", zstream);
|
2003-04-21 18:43:36 +00:00
|
|
|
/* add_property_zval increments the refcount which is unwanted here */
|
|
|
|
zval_ptr_dtor(&zstream);
|
2003-02-24 21:56:19 +00:00
|
|
|
}
|
|
|
|
|
2003-02-18 01:22:21 +00:00
|
|
|
ZVAL_STRINGL(&func_name, "filter", sizeof("filter")-1, 0);
|
2002-12-31 18:39:36 +00:00
|
|
|
|
2003-02-24 21:56:19 +00:00
|
|
|
/* Setup calling arguments */
|
2003-04-21 18:43:36 +00:00
|
|
|
ALLOC_INIT_ZVAL(zin);
|
2003-02-24 21:56:19 +00:00
|
|
|
ZEND_REGISTER_RESOURCE(zin, buckets_in, le_bucket_brigade);
|
|
|
|
args[0] = &zin;
|
|
|
|
|
2003-04-21 18:43:36 +00:00
|
|
|
ALLOC_INIT_ZVAL(zout);
|
2003-02-24 21:56:19 +00:00
|
|
|
ZEND_REGISTER_RESOURCE(zout, buckets_out, le_bucket_brigade);
|
|
|
|
args[1] = &zout;
|
|
|
|
|
|
|
|
ALLOC_INIT_ZVAL(zconsumed);
|
|
|
|
if (bytes_consumed) {
|
|
|
|
ZVAL_LONG(zconsumed, *bytes_consumed);
|
|
|
|
} else {
|
|
|
|
ZVAL_NULL(zconsumed);
|
|
|
|
}
|
|
|
|
args[2] = &zconsumed;
|
|
|
|
|
|
|
|
ALLOC_INIT_ZVAL(zclosing);
|
|
|
|
ZVAL_BOOL(zclosing, flags & PSFS_FLAG_FLUSH_CLOSE);
|
|
|
|
args[3] = &zclosing;
|
2002-12-31 18:39:36 +00:00
|
|
|
|
|
|
|
call_result = call_user_function_ex(NULL,
|
|
|
|
&obj,
|
|
|
|
&func_name,
|
|
|
|
&retval,
|
2003-02-24 21:56:19 +00:00
|
|
|
4, args,
|
2002-12-31 18:39:36 +00:00
|
|
|
0, NULL TSRMLS_CC);
|
|
|
|
|
|
|
|
if (call_result == SUCCESS && retval != NULL) {
|
|
|
|
convert_to_long(retval);
|
|
|
|
ret = Z_LVAL_P(retval);
|
|
|
|
} else if (call_result == FAILURE) {
|
2003-02-18 01:22:21 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to call filter function");
|
2002-12-31 18:39:36 +00:00
|
|
|
}
|
|
|
|
|
2003-02-24 21:56:19 +00:00
|
|
|
if (bytes_consumed) {
|
|
|
|
*bytes_consumed = Z_LVAL_P(zconsumed);
|
|
|
|
}
|
|
|
|
|
2002-12-31 18:39:36 +00:00
|
|
|
if (retval)
|
|
|
|
zval_ptr_dtor(&retval);
|
2003-02-24 21:56:19 +00:00
|
|
|
zval_ptr_dtor(&zclosing);
|
|
|
|
zval_ptr_dtor(&zconsumed);
|
|
|
|
zval_ptr_dtor(&zout);
|
|
|
|
zval_ptr_dtor(&zin);
|
2002-12-31 18:39:36 +00:00
|
|
|
|
2003-02-24 21:56:19 +00:00
|
|
|
return ret;
|
2002-12-31 18:39:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static php_stream_filter_ops userfilter_ops = {
|
2003-02-18 01:22:21 +00:00
|
|
|
userfilter_filter,
|
2002-12-31 18:39:36 +00:00
|
|
|
userfilter_dtor,
|
|
|
|
"user-filter"
|
|
|
|
};
|
|
|
|
|
|
|
|
static php_stream_filter *user_filter_factory_create(const char *filtername,
|
2003-04-17 23:59:28 +00:00
|
|
|
zval *filterparams, int persistent TSRMLS_DC)
|
2002-12-31 18:39:36 +00:00
|
|
|
{
|
|
|
|
struct php_user_filter_data *fdat = NULL;
|
|
|
|
php_stream_filter *filter;
|
|
|
|
zval *obj, *zfilter;
|
|
|
|
zval func_name;
|
|
|
|
zval *retval = NULL;
|
|
|
|
|
|
|
|
/* some sanity checks */
|
|
|
|
if (persistent) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
|
|
|
"cannot use a user-space filter with a persistent stream");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* determine the classname/class entry */
|
|
|
|
if (FAILURE == zend_hash_find(BG(user_filter_map), (char*)filtername,
|
|
|
|
strlen(filtername), (void**)&fdat)) {
|
2003-10-29 00:19:57 +00:00
|
|
|
char *period;
|
|
|
|
|
|
|
|
/* Userspace Filters using ambiguous wildcards could cause problems.
|
|
|
|
i.e.: myfilter.foo.bar will always call into myfilter.foo.*
|
|
|
|
never seeing myfilter.*
|
|
|
|
TODO: Allow failed userfilter creations to continue
|
|
|
|
scanning through the list */
|
|
|
|
if ((period = strrchr(filtername, '.'))) {
|
|
|
|
char *wildcard;
|
|
|
|
|
|
|
|
/* Search for wildcard matches instead */
|
|
|
|
wildcard = estrdup(filtername);
|
|
|
|
period = wildcard + (period - filtername);
|
|
|
|
while (period) {
|
|
|
|
*period = '\0';
|
|
|
|
strcat(wildcard, ".*");
|
|
|
|
if (SUCCESS == zend_hash_find(BG(user_filter_map), wildcard, strlen(wildcard), (void**)&fdat)) {
|
|
|
|
period = NULL;
|
|
|
|
} else {
|
|
|
|
*period = '\0';
|
|
|
|
period = strrchr(wildcard, '.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
efree(wildcard);
|
|
|
|
}
|
|
|
|
if (fdat == NULL) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
|
|
|
"Err, filter \"%s\" is not in the user-filter map, but somehow the user-filter-factory was invoked for it!?", filtername);
|
|
|
|
return NULL;
|
|
|
|
}
|
2002-12-31 18:39:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* bind the classname to the actual class */
|
|
|
|
if (fdat->ce == NULL) {
|
2004-05-05 18:18:57 +00:00
|
|
|
if (FAILURE == zend_lookup_class(fdat->classname, strlen(fdat->classname),
|
|
|
|
(zend_class_entry ***)&fdat->ce TSRMLS_CC)) {
|
2002-12-31 18:39:36 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
|
|
|
"user-filter \"%s\" requires class \"%s\", but that class is not defined",
|
|
|
|
filtername, fdat->classname);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
fdat->ce = *(zend_class_entry**)fdat->ce;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
filter = php_stream_filter_alloc(&userfilter_ops, NULL, 0);
|
|
|
|
if (filter == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create the object */
|
|
|
|
ALLOC_ZVAL(obj);
|
|
|
|
object_init_ex(obj, fdat->ce);
|
|
|
|
ZVAL_REFCOUNT(obj) = 1;
|
|
|
|
PZVAL_IS_REF(obj) = 1;
|
|
|
|
|
|
|
|
/* filtername */
|
|
|
|
add_property_string(obj, "filtername", (char*)filtername, 1);
|
|
|
|
|
|
|
|
/* and the parameters, if any */
|
|
|
|
if (filterparams) {
|
2003-04-17 23:59:28 +00:00
|
|
|
add_property_zval(obj, "params", filterparams);
|
2002-12-31 18:39:36 +00:00
|
|
|
} else {
|
|
|
|
add_property_null(obj, "params");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* invoke the constructor */
|
|
|
|
ZVAL_STRINGL(&func_name, "oncreate", sizeof("oncreate")-1, 0);
|
|
|
|
|
|
|
|
call_user_function_ex(NULL,
|
|
|
|
&obj,
|
|
|
|
&func_name,
|
|
|
|
&retval,
|
|
|
|
0, NULL,
|
|
|
|
0, NULL TSRMLS_CC);
|
|
|
|
|
2003-10-28 23:56:57 +00:00
|
|
|
if (retval) {
|
|
|
|
if (Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval) == 0) {
|
|
|
|
/* User reported filter creation error "return false;" */
|
|
|
|
zval_ptr_dtor(&retval);
|
|
|
|
|
|
|
|
/* Kill the filter (safely) */
|
|
|
|
filter->abstract = NULL;
|
|
|
|
php_stream_filter_free(filter TSRMLS_CC);
|
|
|
|
|
|
|
|
/* Kill the object */
|
|
|
|
zval_ptr_dtor(&obj);
|
|
|
|
|
|
|
|
/* Report failure to filter_alloc */
|
|
|
|
return NULL;
|
|
|
|
}
|
2002-12-31 18:39:36 +00:00
|
|
|
zval_ptr_dtor(&retval);
|
2003-10-28 23:56:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set the filter property, this will be used during cleanup */
|
|
|
|
ALLOC_INIT_ZVAL(zfilter);
|
|
|
|
ZEND_REGISTER_RESOURCE(zfilter, filter, le_userfilters);
|
|
|
|
filter->abstract = obj;
|
|
|
|
add_property_zval(obj, "filter", zfilter);
|
2005-06-09 08:19:30 +00:00
|
|
|
/* add_property_zval increments the refcount which is unwanted here */
|
|
|
|
zval_ptr_dtor(&zfilter);
|
2003-10-28 23:56:57 +00:00
|
|
|
|
2002-12-31 18:39:36 +00:00
|
|
|
return filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
static php_stream_filter_factory user_filter_factory = {
|
|
|
|
user_filter_factory_create
|
|
|
|
};
|
|
|
|
|
|
|
|
static void filter_item_dtor(struct php_user_filter_data *fdat)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2003-03-09 23:12:31 +00:00
|
|
|
/* {{{ proto object stream_bucket_make_writeable(resource brigade)
|
|
|
|
Return a bucket object from the brigade for operating on */
|
2003-02-24 21:56:19 +00:00
|
|
|
PHP_FUNCTION(stream_bucket_make_writeable)
|
|
|
|
{
|
2003-03-09 23:12:31 +00:00
|
|
|
zval *zbrigade, *zbucket;
|
2003-02-24 21:56:19 +00:00
|
|
|
php_stream_bucket_brigade *brigade;
|
|
|
|
php_stream_bucket *bucket;
|
|
|
|
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zbrigade) == FAILURE) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZEND_FETCH_RESOURCE(brigade, php_stream_bucket_brigade *, &zbrigade, -1, PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade);
|
|
|
|
|
|
|
|
ZVAL_NULL(return_value);
|
|
|
|
|
|
|
|
if (brigade->head && (bucket = php_stream_bucket_make_writeable(brigade->head TSRMLS_CC))) {
|
2003-03-09 23:12:31 +00:00
|
|
|
ALLOC_INIT_ZVAL(zbucket);
|
|
|
|
ZEND_REGISTER_RESOURCE(zbucket, bucket, le_bucket);
|
|
|
|
object_init(return_value);
|
|
|
|
add_property_zval(return_value, "bucket", zbucket);
|
2003-04-21 18:43:36 +00:00
|
|
|
/* add_property_zval increments the refcount which is unwanted here */
|
|
|
|
zval_ptr_dtor(&zbucket);
|
2003-03-09 23:12:31 +00:00
|
|
|
add_property_stringl(return_value, "data", bucket->buf, bucket->buflen, 1);
|
|
|
|
add_property_long(return_value, "datalen", bucket->buflen);
|
2003-02-24 21:56:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ php_stream_bucket_attach */
|
|
|
|
static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
|
|
|
|
{
|
2003-03-09 23:12:31 +00:00
|
|
|
zval *zbrigade, *zobject;
|
|
|
|
zval **pzbucket, **pzdata;
|
2003-02-24 21:56:19 +00:00
|
|
|
php_stream_bucket_brigade *brigade;
|
|
|
|
php_stream_bucket *bucket;
|
|
|
|
|
2003-03-09 23:12:31 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zo", &zbrigade, &zobject) == FAILURE) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FAILURE == zend_hash_find(Z_OBJPROP_P(zobject), "bucket", 7, (void**)&pzbucket)) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Object has no bucket property");
|
2003-02-24 21:56:19 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZEND_FETCH_RESOURCE(brigade, php_stream_bucket_brigade *, &zbrigade, -1, PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade);
|
2003-03-09 23:12:31 +00:00
|
|
|
ZEND_FETCH_RESOURCE(bucket, php_stream_bucket *, pzbucket, -1, PHP_STREAM_BUCKET_RES_NAME, le_bucket);
|
|
|
|
|
|
|
|
if (SUCCESS == zend_hash_find(Z_OBJPROP_P(zobject), "data", 5, (void**)&pzdata) && (*pzdata)->type == IS_STRING) {
|
|
|
|
if (!bucket->own_buf) {
|
|
|
|
bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC);
|
|
|
|
}
|
2006-02-26 10:57:00 +00:00
|
|
|
if ((int)bucket->buflen != Z_STRLEN_PP(pzdata)) {
|
2003-03-09 23:12:31 +00:00
|
|
|
bucket->buf = perealloc(bucket->buf, Z_STRLEN_PP(pzdata), bucket->is_persistent);
|
|
|
|
bucket->buflen = Z_STRLEN_PP(pzdata);
|
|
|
|
}
|
|
|
|
memcpy(bucket->buf, Z_STRVAL_PP(pzdata), bucket->buflen);
|
|
|
|
}
|
2003-02-24 21:56:19 +00:00
|
|
|
|
|
|
|
if (append) {
|
|
|
|
php_stream_bucket_append(brigade, bucket TSRMLS_CC);
|
|
|
|
} else {
|
|
|
|
php_stream_bucket_prepend(brigade, bucket TSRMLS_CC);
|
|
|
|
}
|
2006-03-28 16:01:04 +00:00
|
|
|
/* This is a hack necessary to accomodate situations where bucket is appended to the stream
|
|
|
|
* multiple times. See bug35916.phpt for reference.
|
|
|
|
*/
|
|
|
|
if (bucket->refcount == 1) {
|
|
|
|
bucket->refcount++;
|
|
|
|
}
|
2003-02-24 21:56:19 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto void stream_bucket_prepend(resource brigade, resource bucket)
|
|
|
|
Prepend bucket to brigade */
|
|
|
|
PHP_FUNCTION(stream_bucket_prepend)
|
|
|
|
{
|
|
|
|
php_stream_bucket_attach(0, INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto void stream_bucket_append(resource brigade, resource bucket)
|
|
|
|
Append bucket to brigade */
|
|
|
|
PHP_FUNCTION(stream_bucket_append)
|
|
|
|
{
|
|
|
|
php_stream_bucket_attach(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource stream_bucket_new(resource stream, string buffer)
|
|
|
|
Create a new bucket for use on the current stream */
|
|
|
|
PHP_FUNCTION(stream_bucket_new)
|
|
|
|
{
|
2003-03-09 23:12:31 +00:00
|
|
|
zval *zstream, *zbucket;
|
2003-02-24 21:56:19 +00:00
|
|
|
php_stream *stream;
|
|
|
|
char *buffer;
|
|
|
|
char *pbuffer;
|
|
|
|
int buffer_len;
|
|
|
|
php_stream_bucket *bucket;
|
|
|
|
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &zstream, &buffer, &buffer_len) == FAILURE) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2003-06-13 22:25:29 +00:00
|
|
|
php_stream_from_zval(stream, &zstream);
|
2003-02-24 21:56:19 +00:00
|
|
|
|
|
|
|
if (!(pbuffer = pemalloc(buffer_len, php_stream_is_persistent(stream)))) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(pbuffer, buffer, buffer_len);
|
|
|
|
|
|
|
|
bucket = php_stream_bucket_new(stream, pbuffer, buffer_len, 1, php_stream_is_persistent(stream) TSRMLS_CC);
|
|
|
|
|
2003-03-09 23:12:31 +00:00
|
|
|
ALLOC_INIT_ZVAL(zbucket);
|
|
|
|
ZEND_REGISTER_RESOURCE(zbucket, bucket, le_bucket);
|
|
|
|
object_init(return_value);
|
|
|
|
add_property_zval(return_value, "bucket", zbucket);
|
2005-06-09 08:19:30 +00:00
|
|
|
/* add_property_zval increments the refcount which is unwanted here */
|
|
|
|
zval_ptr_dtor(&zbucket);
|
2003-03-09 23:12:31 +00:00
|
|
|
add_property_stringl(return_value, "data", bucket->buf, bucket->buflen, 1);
|
|
|
|
add_property_long(return_value, "datalen", bucket->buflen);
|
2003-02-24 21:56:19 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2003-01-07 16:43:26 +00:00
|
|
|
/* {{{ proto array stream_get_filters(void)
|
2003-01-05 03:24:38 +00:00
|
|
|
Returns a list of registered filters */
|
|
|
|
PHP_FUNCTION(stream_get_filters)
|
|
|
|
{
|
|
|
|
char *filter_name;
|
2003-01-05 22:24:49 +00:00
|
|
|
int key_flags, filter_name_len = 0;
|
2003-01-06 04:06:40 +00:00
|
|
|
HashTable *filters_hash;
|
2003-06-19 16:10:54 +00:00
|
|
|
ulong num_key;
|
2003-01-05 22:24:49 +00:00
|
|
|
|
2003-01-07 16:43:26 +00:00
|
|
|
if (ZEND_NUM_ARGS() != 0) {
|
|
|
|
WRONG_PARAM_COUNT;
|
2003-01-05 22:24:49 +00:00
|
|
|
}
|
2003-01-05 03:24:38 +00:00
|
|
|
|
|
|
|
array_init(return_value);
|
|
|
|
|
2003-01-07 16:43:26 +00:00
|
|
|
filters_hash = php_get_stream_filters_hash();
|
2003-01-06 04:06:40 +00:00
|
|
|
|
|
|
|
if (filters_hash) {
|
|
|
|
for(zend_hash_internal_pointer_reset(filters_hash);
|
2003-06-19 16:10:54 +00:00
|
|
|
(key_flags = zend_hash_get_current_key_ex(filters_hash, &filter_name, &filter_name_len, &num_key, 0, NULL)) != HASH_KEY_NON_EXISTANT;
|
2003-01-06 04:06:40 +00:00
|
|
|
zend_hash_move_forward(filters_hash))
|
2003-01-05 22:24:49 +00:00
|
|
|
if (key_flags == HASH_KEY_IS_STRING)
|
|
|
|
add_next_index_stringl(return_value, filter_name, filter_name_len, 1);
|
2003-01-05 03:24:38 +00:00
|
|
|
}
|
2003-01-05 22:24:49 +00:00
|
|
|
/* It's okay to return an empty array if no filters are registered */
|
2003-01-05 03:24:38 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2003-05-19 15:35:06 +00:00
|
|
|
/* {{{ proto bool stream_filter_register(string filtername, string classname)
|
2002-12-31 18:39:36 +00:00
|
|
|
Registers a custom filter handler class */
|
2003-05-19 15:35:06 +00:00
|
|
|
PHP_FUNCTION(stream_filter_register)
|
2002-12-31 18:39:36 +00:00
|
|
|
{
|
|
|
|
char *filtername, *classname;
|
|
|
|
int filtername_len, classname_len;
|
|
|
|
struct php_user_filter_data *fdat;
|
|
|
|
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &filtername, &filtername_len,
|
|
|
|
&classname, &classname_len) == FAILURE) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
RETVAL_FALSE;
|
|
|
|
|
2006-10-11 14:46:40 +00:00
|
|
|
if (!filtername_len) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter name cannot be empty");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!classname_len) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class name cannot be empty");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-12-31 18:39:36 +00:00
|
|
|
if (!BG(user_filter_map)) {
|
|
|
|
BG(user_filter_map) = (HashTable*) emalloc(sizeof(HashTable));
|
|
|
|
zend_hash_init(BG(user_filter_map), 5, NULL, (dtor_func_t) filter_item_dtor, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
fdat = ecalloc(1, sizeof(*fdat) + classname_len);
|
|
|
|
memcpy(fdat->classname, classname, classname_len);
|
|
|
|
|
|
|
|
if (zend_hash_add(BG(user_filter_map), filtername, filtername_len, (void*)fdat,
|
|
|
|
sizeof(*fdat) + classname_len, NULL) == SUCCESS &&
|
2004-06-21 21:08:05 +00:00
|
|
|
php_stream_filter_register_factory_volatile(filtername, &user_filter_factory TSRMLS_CC) == SUCCESS) {
|
2002-12-31 18:39:36 +00:00
|
|
|
RETVAL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
efree(fdat);
|
|
|
|
}
|
|
|
|
/* }}} */
|
2003-01-01 11:04:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* tab-width: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
|
|
|
* vim600: sw=4 ts=4 fdm=marker
|
|
|
|
* vim<600: sw=4 ts=4
|
|
|
|
*/
|