Back to index

php5  5.3.10
Classes | Defines | Functions | Variables
user_filters.c File Reference
#include "php.h"
#include "php_globals.h"
#include "ext/standard/basic_functions.h"
#include "ext/standard/file.h"

Go to the source code of this file.

Classes

struct  php_user_filter_data

Defines

#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"
#define GET_FILTER_FROM_OBJ()

Functions

 PHP_FUNCTION (user_filter_nop)
static ZEND_RSRC_DTOR_FUNC (php_bucket_dtor)
 PHP_MINIT_FUNCTION (user_filters)
 PHP_RSHUTDOWN_FUNCTION (user_filters)
static void userfilter_dtor (php_stream_filter *thisfilter TSRMLS_DC)
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)
static php_stream_filter * user_filter_factory_create (const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
static void filter_item_dtor (struct php_user_filter_data *fdat)
 PHP_FUNCTION (stream_bucket_make_writeable)
static void php_stream_bucket_attach (int append, INTERNAL_FUNCTION_PARAMETERS)
 PHP_FUNCTION (stream_bucket_prepend)
 PHP_FUNCTION (stream_bucket_append)
 PHP_FUNCTION (stream_bucket_new)
 PHP_FUNCTION (stream_get_filters)
 PHP_FUNCTION (stream_filter_register)

Variables

static int le_userfilters
static int le_bucket_brigade
static int le_bucket
static const zend_function_entry user_filter_class_funcs []
static zend_class_entry user_filter_class_entry
static php_stream_filter_ops userfilter_ops
static php_stream_filter_factory user_filter_factory

Class Documentation

struct php_user_filter_data

Definition at line 32 of file user_filters.c.

Class Members
zend_class_entry * ce
char classname

Define Documentation

#define GET_FILTER_FROM_OBJ ( )
Value:
{ \
       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); \
}

Definition at line 43 of file user_filters.c.

#define PHP_STREAM_BRIGADE_RES_NAME   "userfilter.bucket brigade"

Definition at line 28 of file user_filters.c.

#define PHP_STREAM_BUCKET_RES_NAME   "userfilter.bucket"

Definition at line 29 of file user_filters.c.

#define PHP_STREAM_FILTER_RES_NAME   "userfilter.filter"

Definition at line 30 of file user_filters.c.


Function Documentation

static void filter_item_dtor ( struct php_user_filter_data fdat) [static]

Definition at line 408 of file user_filters.c.

{
}

Here is the caller graph for this function:

PHP_FUNCTION ( user_filter_nop  )

Definition at line 54 of file user_filters.c.

{
}
PHP_FUNCTION ( stream_bucket_make_writeable  )

Definition at line 414 of file user_filters.c.

{
       zval *zbrigade, *zbucket;
       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))) {
              ALLOC_INIT_ZVAL(zbucket);
              ZEND_REGISTER_RESOURCE(zbucket, bucket, le_bucket);
              object_init(return_value);
              add_property_zval(return_value, "bucket", zbucket);
              /* add_property_zval increments the refcount which is unwanted here */
              zval_ptr_dtor(&zbucket);
              add_property_stringl(return_value, "data", bucket->buf, bucket->buflen, 1);
              add_property_long(return_value, "datalen", bucket->buflen);
       }
}

Here is the call graph for this function:

PHP_FUNCTION ( stream_bucket_prepend  )

Definition at line 488 of file user_filters.c.

Here is the call graph for this function:

PHP_FUNCTION ( stream_bucket_append  )

Definition at line 496 of file user_filters.c.

Here is the call graph for this function:

PHP_FUNCTION ( stream_bucket_new  )

Definition at line 504 of file user_filters.c.

{
       zval *zstream, *zbucket;
       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;
       }

       php_stream_from_zval(stream, &zstream);

       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);
       
       if (bucket == NULL) {
              RETURN_FALSE;
       }

       ALLOC_INIT_ZVAL(zbucket);
       ZEND_REGISTER_RESOURCE(zbucket, bucket, le_bucket);
       object_init(return_value);
       add_property_zval(return_value, "bucket", zbucket);
       /* add_property_zval increments the refcount which is unwanted here */
       zval_ptr_dtor(&zbucket);
       add_property_stringl(return_value, "data", bucket->buf, bucket->buflen, 1);
       add_property_long(return_value, "datalen", bucket->buflen);
}

Here is the call graph for this function:

PHP_FUNCTION ( stream_get_filters  )

Definition at line 544 of file user_filters.c.

{
       char *filter_name;
       int key_flags, filter_name_len = 0;
       HashTable *filters_hash;
       ulong num_key;

       if (zend_parse_parameters_none() == FAILURE) {
              return;
       }

       array_init(return_value);

       filters_hash = php_get_stream_filters_hash();

       if (filters_hash) {
              for(zend_hash_internal_pointer_reset(filters_hash);
                     (key_flags = zend_hash_get_current_key_ex(filters_hash, &filter_name, &filter_name_len, &num_key, 0, NULL)) != HASH_KEY_NON_EXISTANT;
                     zend_hash_move_forward(filters_hash))
                            if (key_flags == HASH_KEY_IS_STRING) {
                                   add_next_index_stringl(return_value, filter_name, filter_name_len - 1, 1);
                            }
       }
       /* It's okay to return an empty array if no filters are registered */
}

Here is the call graph for this function:

PHP_FUNCTION ( stream_filter_register  )

Definition at line 573 of file user_filters.c.

{
       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;

       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;
       }

       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(struct php_user_filter_data) + classname_len);
       memcpy(fdat->classname, classname, classname_len);

       if (zend_hash_add(BG(user_filter_map), filtername, filtername_len + 1, (void*)fdat,
                            sizeof(*fdat) + classname_len, NULL) == SUCCESS &&
                     php_stream_filter_register_factory_volatile(filtername, &user_filter_factory TSRMLS_CC) == SUCCESS) {
              RETVAL_TRUE;
       }

       efree(fdat);
}

Here is the call graph for this function:

PHP_MINIT_FUNCTION ( user_filters  )

Definition at line 88 of file user_filters.c.

{
       zend_class_entry *php_user_filter;
       /* init the filter class ancestor */
       INIT_CLASS_ENTRY(user_filter_class_entry, "php_user_filter", user_filter_class_funcs);
       if ((php_user_filter = zend_register_internal_class(&user_filter_class_entry TSRMLS_CC)) == NULL) {
              return FAILURE;
       }
       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);

       /* init the filter resource; it has no dtor, as streams will always clean it up
        * at the correct time */
       le_userfilters = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_FILTER_RES_NAME, 0);

       if (le_userfilters == FAILURE) {
              return FAILURE;
       }

       /* Filters will dispose of their brigades */
       le_bucket_brigade = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_BRIGADE_RES_NAME, module_number);
       /* Brigades will dispose of their buckets */
       le_bucket = zend_register_list_destructors_ex(php_bucket_dtor, NULL, PHP_STREAM_BUCKET_RES_NAME, module_number);
       
       if (le_bucket_brigade == FAILURE) {
              return FAILURE;
       }

       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);
       
       return SUCCESS;
}

Here is the call graph for this function:

PHP_RSHUTDOWN_FUNCTION ( user_filters  )

Definition at line 127 of file user_filters.c.

{
       if (BG(user_filter_map)) {
              zend_hash_destroy(BG(user_filter_map));
              efree(BG(user_filter_map));
              BG(user_filter_map) = NULL;
       }

       return SUCCESS;
}

Here is the call graph for this function:

static void php_stream_bucket_attach ( int  append,
INTERNAL_FUNCTION_PARAMETERS   
) [static]

Definition at line 442 of file user_filters.c.

{
       zval *zbrigade, *zobject;
       zval **pzbucket, **pzdata;
       php_stream_bucket_brigade *brigade;
       php_stream_bucket *bucket;

       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");
              RETURN_FALSE;
       }

       ZEND_FETCH_RESOURCE(brigade, php_stream_bucket_brigade *, &zbrigade, -1, PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade);
       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);
              }
              if ((int)bucket->buflen != Z_STRLEN_PP(pzdata)) {
                     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);
       }

       if (append) {
              php_stream_bucket_append(brigade, bucket TSRMLS_CC);
       } else {
              php_stream_bucket_prepend(brigade, bucket TSRMLS_CC);
       }
       /* 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++;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static php_stream_filter* user_filter_factory_create ( const char *  filtername,
zval *  filterparams,
int persistent  TSRMLS_DC 
) [static]

Definition at line 278 of file user_filters.c.

{
       struct php_user_filter_data *fdat = NULL;
       php_stream_filter *filter;
       zval *obj, *zfilter;
       zval func_name;
       zval *retval = NULL;
       int len;
       
       /* 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;
       }

       len = strlen(filtername);

       /* determine the classname/class entry */
       if (FAILURE == zend_hash_find(BG(user_filter_map), (char*)filtername, len + 1, (void**)&fdat)) {
              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 = emalloc(len + 3);

                     /* Search for wildcard matches instead */
                     memcpy(wildcard, filtername, len + 1); /* copy \0 */
                     period = wildcard + (period - filtername);
                     while (period) {
                            *period = '\0';
                            strncat(wildcard, ".*", 2);
                            if (SUCCESS == zend_hash_find(BG(user_filter_map), wildcard, strlen(wildcard) + 1, (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;
              }
       }

       /* bind the classname to the actual class */
       if (fdat->ce == NULL) {
              if (FAILURE == zend_lookup_class(fdat->classname, strlen(fdat->classname),
                                   (zend_class_entry ***)&fdat->ce TSRMLS_CC)) {
                     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);
       Z_SET_REFCOUNT_P(obj, 1);
       Z_SET_ISREF_P(obj);

       /* filtername */
       add_property_string(obj, "filtername", (char*)filtername, 1);
       
       /* and the parameters, if any */
       if (filterparams) {
              add_property_zval(obj, "params", filterparams);
       } 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);

       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;
              }                    
              zval_ptr_dtor(&retval);
       }

       /* 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);
       /* add_property_zval increments the refcount which is unwanted here */
       zval_ptr_dtor(&zfilter);

       return filter;
}

Here is the call graph for this function:

static void userfilter_dtor ( php_stream_filter *thisfilter  TSRMLS_DC) [static]

Definition at line 138 of file user_filters.c.

{
       zval *obj = (zval*)thisfilter->abstract;
       zval func_name;
       zval *retval = NULL;

       if (obj == NULL) {
              /* If there's no object associated then there's nothing to dispose of */
              return;
       }

       ZVAL_STRINGL(&func_name, "onclose", sizeof("onclose")-1, 0);

       call_user_function_ex(NULL,
                     &obj,
                     &func_name,
                     &retval,
                     0, NULL,
                     0, NULL TSRMLS_CC);

       if (retval)
              zval_ptr_dtor(&retval);

       /* kill the object */
       zval_ptr_dtor(&obj);
}

Here is the call graph for this function:

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 
)

Definition at line 165 of file user_filters.c.

{
       int ret = PSFS_ERR_FATAL;
       zval *obj = (zval*)thisfilter->abstract;
       zval func_name;
       zval *retval = NULL;
       zval **args[4];
       zval *zclosing, *zconsumed, *zin, *zout, *zstream;
       zval zpropname;
       int call_result;

       if (FAILURE == zend_hash_find(Z_OBJPROP_P(obj), "stream", sizeof("stream"), (void**)&zstream)) {
              /* Give the userfilter class a hook back to the stream */
              ALLOC_INIT_ZVAL(zstream);
              php_stream_to_zval(stream, zstream);
              zval_copy_ctor(zstream);
              add_property_zval(obj, "stream", zstream);
              /* add_property_zval increments the refcount which is unwanted here */
              zval_ptr_dtor(&zstream);
       }

       ZVAL_STRINGL(&func_name, "filter", sizeof("filter")-1, 0);

       /* Setup calling arguments */
       ALLOC_INIT_ZVAL(zin);
       ZEND_REGISTER_RESOURCE(zin, buckets_in, le_bucket_brigade);
       args[0] = &zin;

       ALLOC_INIT_ZVAL(zout);
       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;

       call_result = call_user_function_ex(NULL,
                     &obj,
                     &func_name,
                     &retval,
                     4, args,
                     0, NULL TSRMLS_CC);

       if (call_result == SUCCESS && retval != NULL) {
              convert_to_long(retval);
              ret = Z_LVAL_P(retval);
       } else if (call_result == FAILURE) {
              php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to call filter function");
       }

       if (bytes_consumed) {
              *bytes_consumed = Z_LVAL_P(zconsumed);
       }

       if (retval) {
              zval_ptr_dtor(&retval);
       }

       if (buckets_in->head) {
              php_stream_bucket *bucket = buckets_in->head;

              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unprocessed filter buckets remaining on input brigade");
              while ((bucket = buckets_in->head)) {
                     /* Remove unconsumed buckets from the brigade */
                     php_stream_bucket_unlink(bucket TSRMLS_CC);
                     php_stream_bucket_delref(bucket TSRMLS_CC);
              }
       }
       if (ret != PSFS_PASS_ON) {
              php_stream_bucket *bucket = buckets_out->head;
              while (bucket != NULL) {
                     php_stream_bucket_unlink(bucket TSRMLS_CC);
                     php_stream_bucket_delref(bucket TSRMLS_CC);
                     bucket = buckets_out->head;
              }
       }

       /* filter resources are cleaned up by the stream destructor,
        * keeping a reference to the stream resource here would prevent it
        * from being destroyed properly */
       INIT_ZVAL(zpropname);
       ZVAL_STRINGL(&zpropname, "stream", sizeof("stream")-1, 0);
       Z_OBJ_HANDLER_P(obj, unset_property)(obj, &zpropname TSRMLS_CC);

       zval_ptr_dtor(&zclosing);
       zval_ptr_dtor(&zconsumed);
       zval_ptr_dtor(&zout);
       zval_ptr_dtor(&zin);

       return ret;
}

Here is the call graph for this function:

static ZEND_RSRC_DTOR_FUNC ( php_bucket_dtor  ) [static]

Definition at line 79 of file user_filters.c.

{
       php_stream_bucket *bucket = (php_stream_bucket *)rsrc->ptr;
       if (bucket) {
              php_stream_bucket_delref(bucket TSRMLS_CC);
              bucket = NULL;
       }
}

Here is the call graph for this function:


Variable Documentation

int le_bucket [static]

Definition at line 41 of file user_filters.c.

Definition at line 40 of file user_filters.c.

int le_userfilters [static]

Definition at line 39 of file user_filters.c.

zend_class_entry user_filter_class_entry [static]

Definition at line 77 of file user_filters.c.

Initial value:

Definition at line 70 of file user_filters.c.

Initial value:

Definition at line 404 of file user_filters.c.

Initial value:
 {
       userfilter_filter,
       userfilter_dtor,
       "user-filter"
}

Definition at line 272 of file user_filters.c.