Annotation of embedaddon/php/ext/standard/user_filters.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 The PHP Group |
! 6: +----------------------------------------------------------------------+
! 7: | This source file is subject to version 3.01 of the PHP license, |
! 8: | that is bundled with this package in the file LICENSE, and is |
! 9: | available through the world-wide-web at the following url: |
! 10: | http://www.php.net/license/3_01.txt |
! 11: | If you did not receive a copy of the PHP license and are unable to |
! 12: | obtain it through the world-wide-web, please send a note to |
! 13: | license@php.net so we can mail you a copy immediately. |
! 14: +----------------------------------------------------------------------+
! 15: | Authors: |
! 16: | Wez Furlong (wez@thebrainroom.com) |
! 17: | Sara Golemon (pollita@php.net) |
! 18: +----------------------------------------------------------------------+
! 19: */
! 20:
! 21: /* $Id: user_filters.c 321634 2012-01-01 13:15:04Z felipe $ */
! 22:
! 23: #include "php.h"
! 24: #include "php_globals.h"
! 25: #include "ext/standard/basic_functions.h"
! 26: #include "ext/standard/file.h"
! 27:
! 28: #define PHP_STREAM_BRIGADE_RES_NAME "userfilter.bucket brigade"
! 29: #define PHP_STREAM_BUCKET_RES_NAME "userfilter.bucket"
! 30: #define PHP_STREAM_FILTER_RES_NAME "userfilter.filter"
! 31:
! 32: struct php_user_filter_data {
! 33: zend_class_entry *ce;
! 34: /* variable length; this *must* be last in the structure */
! 35: char classname[1];
! 36: };
! 37:
! 38: /* to provide context for calling into the next filter from user-space */
! 39: static int le_userfilters;
! 40: static int le_bucket_brigade;
! 41: static int le_bucket;
! 42:
! 43: #define GET_FILTER_FROM_OBJ() { \
! 44: zval **tmp; \
! 45: if (FAILURE == zend_hash_index_find(Z_OBJPROP_P(this_ptr), 0, (void**)&tmp)) { \
! 46: php_error_docref(NULL TSRMLS_CC, E_WARNING, "filter property vanished"); \
! 47: RETURN_FALSE; \
! 48: } \
! 49: ZEND_FETCH_RESOURCE(filter, php_stream_filter*, tmp, -1, "filter", le_userfilters); \
! 50: }
! 51:
! 52: /* define the base filter class */
! 53:
! 54: PHP_FUNCTION(user_filter_nop)
! 55: {
! 56: }
! 57: ZEND_BEGIN_ARG_INFO(arginfo_php_user_filter_filter, 0)
! 58: ZEND_ARG_INFO(0, in)
! 59: ZEND_ARG_INFO(0, out)
! 60: ZEND_ARG_INFO(1, consumed)
! 61: ZEND_ARG_INFO(0, closing)
! 62: ZEND_END_ARG_INFO()
! 63:
! 64: ZEND_BEGIN_ARG_INFO(arginfo_php_user_filter_onCreate, 0)
! 65: ZEND_END_ARG_INFO()
! 66:
! 67: ZEND_BEGIN_ARG_INFO(arginfo_php_user_filter_onClose, 0)
! 68: ZEND_END_ARG_INFO()
! 69:
! 70: static const zend_function_entry user_filter_class_funcs[] = {
! 71: PHP_NAMED_FE(filter, PHP_FN(user_filter_nop), arginfo_php_user_filter_filter)
! 72: PHP_NAMED_FE(onCreate, PHP_FN(user_filter_nop), arginfo_php_user_filter_onCreate)
! 73: PHP_NAMED_FE(onClose, PHP_FN(user_filter_nop), arginfo_php_user_filter_onClose)
! 74: PHP_FE_END
! 75: };
! 76:
! 77: static zend_class_entry user_filter_class_entry;
! 78:
! 79: static ZEND_RSRC_DTOR_FUNC(php_bucket_dtor)
! 80: {
! 81: php_stream_bucket *bucket = (php_stream_bucket *)rsrc->ptr;
! 82: if (bucket) {
! 83: php_stream_bucket_delref(bucket TSRMLS_CC);
! 84: bucket = NULL;
! 85: }
! 86: }
! 87:
! 88: PHP_MINIT_FUNCTION(user_filters)
! 89: {
! 90: zend_class_entry *php_user_filter;
! 91: /* init the filter class ancestor */
! 92: INIT_CLASS_ENTRY(user_filter_class_entry, "php_user_filter", user_filter_class_funcs);
! 93: if ((php_user_filter = zend_register_internal_class(&user_filter_class_entry TSRMLS_CC)) == NULL) {
! 94: return FAILURE;
! 95: }
! 96: zend_declare_property_string(php_user_filter, "filtername", sizeof("filtername")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC);
! 97: zend_declare_property_string(php_user_filter, "params", sizeof("params")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC);
! 98:
! 99: /* init the filter resource; it has no dtor, as streams will always clean it up
! 100: * at the correct time */
! 101: le_userfilters = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_FILTER_RES_NAME, 0);
! 102:
! 103: if (le_userfilters == FAILURE) {
! 104: return FAILURE;
! 105: }
! 106:
! 107: /* Filters will dispose of their brigades */
! 108: le_bucket_brigade = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_BRIGADE_RES_NAME, module_number);
! 109: /* Brigades will dispose of their buckets */
! 110: le_bucket = zend_register_list_destructors_ex(php_bucket_dtor, NULL, PHP_STREAM_BUCKET_RES_NAME, module_number);
! 111:
! 112: if (le_bucket_brigade == FAILURE) {
! 113: return FAILURE;
! 114: }
! 115:
! 116: REGISTER_LONG_CONSTANT("PSFS_PASS_ON", PSFS_PASS_ON, CONST_CS | CONST_PERSISTENT);
! 117: REGISTER_LONG_CONSTANT("PSFS_FEED_ME", PSFS_FEED_ME, CONST_CS | CONST_PERSISTENT);
! 118: REGISTER_LONG_CONSTANT("PSFS_ERR_FATAL", PSFS_ERR_FATAL, CONST_CS | CONST_PERSISTENT);
! 119:
! 120: REGISTER_LONG_CONSTANT("PSFS_FLAG_NORMAL", PSFS_FLAG_NORMAL, CONST_CS | CONST_PERSISTENT);
! 121: REGISTER_LONG_CONSTANT("PSFS_FLAG_FLUSH_INC", PSFS_FLAG_FLUSH_INC, CONST_CS | CONST_PERSISTENT);
! 122: REGISTER_LONG_CONSTANT("PSFS_FLAG_FLUSH_CLOSE", PSFS_FLAG_FLUSH_CLOSE, CONST_CS | CONST_PERSISTENT);
! 123:
! 124: return SUCCESS;
! 125: }
! 126:
! 127: PHP_RSHUTDOWN_FUNCTION(user_filters)
! 128: {
! 129: if (BG(user_filter_map)) {
! 130: zend_hash_destroy(BG(user_filter_map));
! 131: efree(BG(user_filter_map));
! 132: BG(user_filter_map) = NULL;
! 133: }
! 134:
! 135: return SUCCESS;
! 136: }
! 137:
! 138: static void userfilter_dtor(php_stream_filter *thisfilter TSRMLS_DC)
! 139: {
! 140: zval *obj = (zval*)thisfilter->abstract;
! 141: zval func_name;
! 142: zval *retval = NULL;
! 143:
! 144: if (obj == NULL) {
! 145: /* If there's no object associated then there's nothing to dispose of */
! 146: return;
! 147: }
! 148:
! 149: ZVAL_STRINGL(&func_name, "onclose", sizeof("onclose")-1, 0);
! 150:
! 151: call_user_function_ex(NULL,
! 152: &obj,
! 153: &func_name,
! 154: &retval,
! 155: 0, NULL,
! 156: 0, NULL TSRMLS_CC);
! 157:
! 158: if (retval)
! 159: zval_ptr_dtor(&retval);
! 160:
! 161: /* kill the object */
! 162: zval_ptr_dtor(&obj);
! 163: }
! 164:
! 165: php_stream_filter_status_t userfilter_filter(
! 166: php_stream *stream,
! 167: php_stream_filter *thisfilter,
! 168: php_stream_bucket_brigade *buckets_in,
! 169: php_stream_bucket_brigade *buckets_out,
! 170: size_t *bytes_consumed,
! 171: int flags
! 172: TSRMLS_DC)
! 173: {
! 174: int ret = PSFS_ERR_FATAL;
! 175: zval *obj = (zval*)thisfilter->abstract;
! 176: zval func_name;
! 177: zval *retval = NULL;
! 178: zval **args[4];
! 179: zval *zclosing, *zconsumed, *zin, *zout, *zstream;
! 180: zval zpropname;
! 181: int call_result;
! 182:
! 183: if (FAILURE == zend_hash_find(Z_OBJPROP_P(obj), "stream", sizeof("stream"), (void**)&zstream)) {
! 184: /* Give the userfilter class a hook back to the stream */
! 185: ALLOC_INIT_ZVAL(zstream);
! 186: php_stream_to_zval(stream, zstream);
! 187: zval_copy_ctor(zstream);
! 188: add_property_zval(obj, "stream", zstream);
! 189: /* add_property_zval increments the refcount which is unwanted here */
! 190: zval_ptr_dtor(&zstream);
! 191: }
! 192:
! 193: ZVAL_STRINGL(&func_name, "filter", sizeof("filter")-1, 0);
! 194:
! 195: /* Setup calling arguments */
! 196: ALLOC_INIT_ZVAL(zin);
! 197: ZEND_REGISTER_RESOURCE(zin, buckets_in, le_bucket_brigade);
! 198: args[0] = &zin;
! 199:
! 200: ALLOC_INIT_ZVAL(zout);
! 201: ZEND_REGISTER_RESOURCE(zout, buckets_out, le_bucket_brigade);
! 202: args[1] = &zout;
! 203:
! 204: ALLOC_INIT_ZVAL(zconsumed);
! 205: if (bytes_consumed) {
! 206: ZVAL_LONG(zconsumed, *bytes_consumed);
! 207: } else {
! 208: ZVAL_NULL(zconsumed);
! 209: }
! 210: args[2] = &zconsumed;
! 211:
! 212: ALLOC_INIT_ZVAL(zclosing);
! 213: ZVAL_BOOL(zclosing, flags & PSFS_FLAG_FLUSH_CLOSE);
! 214: args[3] = &zclosing;
! 215:
! 216: call_result = call_user_function_ex(NULL,
! 217: &obj,
! 218: &func_name,
! 219: &retval,
! 220: 4, args,
! 221: 0, NULL TSRMLS_CC);
! 222:
! 223: if (call_result == SUCCESS && retval != NULL) {
! 224: convert_to_long(retval);
! 225: ret = Z_LVAL_P(retval);
! 226: } else if (call_result == FAILURE) {
! 227: php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to call filter function");
! 228: }
! 229:
! 230: if (bytes_consumed) {
! 231: *bytes_consumed = Z_LVAL_P(zconsumed);
! 232: }
! 233:
! 234: if (retval) {
! 235: zval_ptr_dtor(&retval);
! 236: }
! 237:
! 238: if (buckets_in->head) {
! 239: php_stream_bucket *bucket = buckets_in->head;
! 240:
! 241: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unprocessed filter buckets remaining on input brigade");
! 242: while ((bucket = buckets_in->head)) {
! 243: /* Remove unconsumed buckets from the brigade */
! 244: php_stream_bucket_unlink(bucket TSRMLS_CC);
! 245: php_stream_bucket_delref(bucket TSRMLS_CC);
! 246: }
! 247: }
! 248: if (ret != PSFS_PASS_ON) {
! 249: php_stream_bucket *bucket = buckets_out->head;
! 250: while (bucket != NULL) {
! 251: php_stream_bucket_unlink(bucket TSRMLS_CC);
! 252: php_stream_bucket_delref(bucket TSRMLS_CC);
! 253: bucket = buckets_out->head;
! 254: }
! 255: }
! 256:
! 257: /* filter resources are cleaned up by the stream destructor,
! 258: * keeping a reference to the stream resource here would prevent it
! 259: * from being destroyed properly */
! 260: INIT_ZVAL(zpropname);
! 261: ZVAL_STRINGL(&zpropname, "stream", sizeof("stream")-1, 0);
! 262: Z_OBJ_HANDLER_P(obj, unset_property)(obj, &zpropname TSRMLS_CC);
! 263:
! 264: zval_ptr_dtor(&zclosing);
! 265: zval_ptr_dtor(&zconsumed);
! 266: zval_ptr_dtor(&zout);
! 267: zval_ptr_dtor(&zin);
! 268:
! 269: return ret;
! 270: }
! 271:
! 272: static php_stream_filter_ops userfilter_ops = {
! 273: userfilter_filter,
! 274: userfilter_dtor,
! 275: "user-filter"
! 276: };
! 277:
! 278: static php_stream_filter *user_filter_factory_create(const char *filtername,
! 279: zval *filterparams, int persistent TSRMLS_DC)
! 280: {
! 281: struct php_user_filter_data *fdat = NULL;
! 282: php_stream_filter *filter;
! 283: zval *obj, *zfilter;
! 284: zval func_name;
! 285: zval *retval = NULL;
! 286: int len;
! 287:
! 288: /* some sanity checks */
! 289: if (persistent) {
! 290: php_error_docref(NULL TSRMLS_CC, E_WARNING,
! 291: "cannot use a user-space filter with a persistent stream");
! 292: return NULL;
! 293: }
! 294:
! 295: len = strlen(filtername);
! 296:
! 297: /* determine the classname/class entry */
! 298: if (FAILURE == zend_hash_find(BG(user_filter_map), (char*)filtername, len + 1, (void**)&fdat)) {
! 299: char *period;
! 300:
! 301: /* Userspace Filters using ambiguous wildcards could cause problems.
! 302: i.e.: myfilter.foo.bar will always call into myfilter.foo.*
! 303: never seeing myfilter.*
! 304: TODO: Allow failed userfilter creations to continue
! 305: scanning through the list */
! 306: if ((period = strrchr(filtername, '.'))) {
! 307: char *wildcard = emalloc(len + 3);
! 308:
! 309: /* Search for wildcard matches instead */
! 310: memcpy(wildcard, filtername, len + 1); /* copy \0 */
! 311: period = wildcard + (period - filtername);
! 312: while (period) {
! 313: *period = '\0';
! 314: strncat(wildcard, ".*", 2);
! 315: if (SUCCESS == zend_hash_find(BG(user_filter_map), wildcard, strlen(wildcard) + 1, (void**)&fdat)) {
! 316: period = NULL;
! 317: } else {
! 318: *period = '\0';
! 319: period = strrchr(wildcard, '.');
! 320: }
! 321: }
! 322: efree(wildcard);
! 323: }
! 324: if (fdat == NULL) {
! 325: php_error_docref(NULL TSRMLS_CC, E_WARNING,
! 326: "Err, filter \"%s\" is not in the user-filter map, but somehow the user-filter-factory was invoked for it!?", filtername);
! 327: return NULL;
! 328: }
! 329: }
! 330:
! 331: /* bind the classname to the actual class */
! 332: if (fdat->ce == NULL) {
! 333: if (FAILURE == zend_lookup_class(fdat->classname, strlen(fdat->classname),
! 334: (zend_class_entry ***)&fdat->ce TSRMLS_CC)) {
! 335: php_error_docref(NULL TSRMLS_CC, E_WARNING,
! 336: "user-filter \"%s\" requires class \"%s\", but that class is not defined",
! 337: filtername, fdat->classname);
! 338: return NULL;
! 339: }
! 340: fdat->ce = *(zend_class_entry**)fdat->ce;
! 341:
! 342: }
! 343:
! 344: filter = php_stream_filter_alloc(&userfilter_ops, NULL, 0);
! 345: if (filter == NULL) {
! 346: return NULL;
! 347: }
! 348:
! 349: /* create the object */
! 350: ALLOC_ZVAL(obj);
! 351: object_init_ex(obj, fdat->ce);
! 352: Z_SET_REFCOUNT_P(obj, 1);
! 353: Z_SET_ISREF_P(obj);
! 354:
! 355: /* filtername */
! 356: add_property_string(obj, "filtername", (char*)filtername, 1);
! 357:
! 358: /* and the parameters, if any */
! 359: if (filterparams) {
! 360: add_property_zval(obj, "params", filterparams);
! 361: } else {
! 362: add_property_null(obj, "params");
! 363: }
! 364:
! 365: /* invoke the constructor */
! 366: ZVAL_STRINGL(&func_name, "oncreate", sizeof("oncreate")-1, 0);
! 367:
! 368: call_user_function_ex(NULL,
! 369: &obj,
! 370: &func_name,
! 371: &retval,
! 372: 0, NULL,
! 373: 0, NULL TSRMLS_CC);
! 374:
! 375: if (retval) {
! 376: if (Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval) == 0) {
! 377: /* User reported filter creation error "return false;" */
! 378: zval_ptr_dtor(&retval);
! 379:
! 380: /* Kill the filter (safely) */
! 381: filter->abstract = NULL;
! 382: php_stream_filter_free(filter TSRMLS_CC);
! 383:
! 384: /* Kill the object */
! 385: zval_ptr_dtor(&obj);
! 386:
! 387: /* Report failure to filter_alloc */
! 388: return NULL;
! 389: }
! 390: zval_ptr_dtor(&retval);
! 391: }
! 392:
! 393: /* set the filter property, this will be used during cleanup */
! 394: ALLOC_INIT_ZVAL(zfilter);
! 395: ZEND_REGISTER_RESOURCE(zfilter, filter, le_userfilters);
! 396: filter->abstract = obj;
! 397: add_property_zval(obj, "filter", zfilter);
! 398: /* add_property_zval increments the refcount which is unwanted here */
! 399: zval_ptr_dtor(&zfilter);
! 400:
! 401: return filter;
! 402: }
! 403:
! 404: static php_stream_filter_factory user_filter_factory = {
! 405: user_filter_factory_create
! 406: };
! 407:
! 408: static void filter_item_dtor(struct php_user_filter_data *fdat)
! 409: {
! 410: }
! 411:
! 412: /* {{{ proto object stream_bucket_make_writeable(resource brigade)
! 413: Return a bucket object from the brigade for operating on */
! 414: PHP_FUNCTION(stream_bucket_make_writeable)
! 415: {
! 416: zval *zbrigade, *zbucket;
! 417: php_stream_bucket_brigade *brigade;
! 418: php_stream_bucket *bucket;
! 419:
! 420: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zbrigade) == FAILURE) {
! 421: RETURN_FALSE;
! 422: }
! 423:
! 424: ZEND_FETCH_RESOURCE(brigade, php_stream_bucket_brigade *, &zbrigade, -1, PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade);
! 425:
! 426: ZVAL_NULL(return_value);
! 427:
! 428: if (brigade->head && (bucket = php_stream_bucket_make_writeable(brigade->head TSRMLS_CC))) {
! 429: ALLOC_INIT_ZVAL(zbucket);
! 430: ZEND_REGISTER_RESOURCE(zbucket, bucket, le_bucket);
! 431: object_init(return_value);
! 432: add_property_zval(return_value, "bucket", zbucket);
! 433: /* add_property_zval increments the refcount which is unwanted here */
! 434: zval_ptr_dtor(&zbucket);
! 435: add_property_stringl(return_value, "data", bucket->buf, bucket->buflen, 1);
! 436: add_property_long(return_value, "datalen", bucket->buflen);
! 437: }
! 438: }
! 439: /* }}} */
! 440:
! 441: /* {{{ php_stream_bucket_attach */
! 442: static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
! 443: {
! 444: zval *zbrigade, *zobject;
! 445: zval **pzbucket, **pzdata;
! 446: php_stream_bucket_brigade *brigade;
! 447: php_stream_bucket *bucket;
! 448:
! 449: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zo", &zbrigade, &zobject) == FAILURE) {
! 450: RETURN_FALSE;
! 451: }
! 452:
! 453: if (FAILURE == zend_hash_find(Z_OBJPROP_P(zobject), "bucket", 7, (void**)&pzbucket)) {
! 454: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Object has no bucket property");
! 455: RETURN_FALSE;
! 456: }
! 457:
! 458: ZEND_FETCH_RESOURCE(brigade, php_stream_bucket_brigade *, &zbrigade, -1, PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade);
! 459: ZEND_FETCH_RESOURCE(bucket, php_stream_bucket *, pzbucket, -1, PHP_STREAM_BUCKET_RES_NAME, le_bucket);
! 460:
! 461: if (SUCCESS == zend_hash_find(Z_OBJPROP_P(zobject), "data", 5, (void**)&pzdata) && (*pzdata)->type == IS_STRING) {
! 462: if (!bucket->own_buf) {
! 463: bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC);
! 464: }
! 465: if ((int)bucket->buflen != Z_STRLEN_PP(pzdata)) {
! 466: bucket->buf = perealloc(bucket->buf, Z_STRLEN_PP(pzdata), bucket->is_persistent);
! 467: bucket->buflen = Z_STRLEN_PP(pzdata);
! 468: }
! 469: memcpy(bucket->buf, Z_STRVAL_PP(pzdata), bucket->buflen);
! 470: }
! 471:
! 472: if (append) {
! 473: php_stream_bucket_append(brigade, bucket TSRMLS_CC);
! 474: } else {
! 475: php_stream_bucket_prepend(brigade, bucket TSRMLS_CC);
! 476: }
! 477: /* This is a hack necessary to accomodate situations where bucket is appended to the stream
! 478: * multiple times. See bug35916.phpt for reference.
! 479: */
! 480: if (bucket->refcount == 1) {
! 481: bucket->refcount++;
! 482: }
! 483: }
! 484: /* }}} */
! 485:
! 486: /* {{{ proto void stream_bucket_prepend(resource brigade, resource bucket)
! 487: Prepend bucket to brigade */
! 488: PHP_FUNCTION(stream_bucket_prepend)
! 489: {
! 490: php_stream_bucket_attach(0, INTERNAL_FUNCTION_PARAM_PASSTHRU);
! 491: }
! 492: /* }}} */
! 493:
! 494: /* {{{ proto void stream_bucket_append(resource brigade, resource bucket)
! 495: Append bucket to brigade */
! 496: PHP_FUNCTION(stream_bucket_append)
! 497: {
! 498: php_stream_bucket_attach(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
! 499: }
! 500: /* }}} */
! 501:
! 502: /* {{{ proto resource stream_bucket_new(resource stream, string buffer)
! 503: Create a new bucket for use on the current stream */
! 504: PHP_FUNCTION(stream_bucket_new)
! 505: {
! 506: zval *zstream, *zbucket;
! 507: php_stream *stream;
! 508: char *buffer;
! 509: char *pbuffer;
! 510: int buffer_len;
! 511: php_stream_bucket *bucket;
! 512:
! 513: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &zstream, &buffer, &buffer_len) == FAILURE) {
! 514: RETURN_FALSE;
! 515: }
! 516:
! 517: php_stream_from_zval(stream, &zstream);
! 518:
! 519: if (!(pbuffer = pemalloc(buffer_len, php_stream_is_persistent(stream)))) {
! 520: RETURN_FALSE;
! 521: }
! 522:
! 523: memcpy(pbuffer, buffer, buffer_len);
! 524:
! 525: bucket = php_stream_bucket_new(stream, pbuffer, buffer_len, 1, php_stream_is_persistent(stream) TSRMLS_CC);
! 526:
! 527: if (bucket == NULL) {
! 528: RETURN_FALSE;
! 529: }
! 530:
! 531: ALLOC_INIT_ZVAL(zbucket);
! 532: ZEND_REGISTER_RESOURCE(zbucket, bucket, le_bucket);
! 533: object_init(return_value);
! 534: add_property_zval(return_value, "bucket", zbucket);
! 535: /* add_property_zval increments the refcount which is unwanted here */
! 536: zval_ptr_dtor(&zbucket);
! 537: add_property_stringl(return_value, "data", bucket->buf, bucket->buflen, 1);
! 538: add_property_long(return_value, "datalen", bucket->buflen);
! 539: }
! 540: /* }}} */
! 541:
! 542: /* {{{ proto array stream_get_filters(void)
! 543: Returns a list of registered filters */
! 544: PHP_FUNCTION(stream_get_filters)
! 545: {
! 546: char *filter_name;
! 547: int key_flags, filter_name_len = 0;
! 548: HashTable *filters_hash;
! 549: ulong num_key;
! 550:
! 551: if (zend_parse_parameters_none() == FAILURE) {
! 552: return;
! 553: }
! 554:
! 555: array_init(return_value);
! 556:
! 557: filters_hash = php_get_stream_filters_hash();
! 558:
! 559: if (filters_hash) {
! 560: for(zend_hash_internal_pointer_reset(filters_hash);
! 561: (key_flags = zend_hash_get_current_key_ex(filters_hash, &filter_name, &filter_name_len, &num_key, 0, NULL)) != HASH_KEY_NON_EXISTANT;
! 562: zend_hash_move_forward(filters_hash))
! 563: if (key_flags == HASH_KEY_IS_STRING) {
! 564: add_next_index_stringl(return_value, filter_name, filter_name_len - 1, 1);
! 565: }
! 566: }
! 567: /* It's okay to return an empty array if no filters are registered */
! 568: }
! 569: /* }}} */
! 570:
! 571: /* {{{ proto bool stream_filter_register(string filtername, string classname)
! 572: Registers a custom filter handler class */
! 573: PHP_FUNCTION(stream_filter_register)
! 574: {
! 575: char *filtername, *classname;
! 576: int filtername_len, classname_len;
! 577: struct php_user_filter_data *fdat;
! 578:
! 579: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &filtername, &filtername_len,
! 580: &classname, &classname_len) == FAILURE) {
! 581: RETURN_FALSE;
! 582: }
! 583:
! 584: RETVAL_FALSE;
! 585:
! 586: if (!filtername_len) {
! 587: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter name cannot be empty");
! 588: return;
! 589: }
! 590:
! 591: if (!classname_len) {
! 592: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class name cannot be empty");
! 593: return;
! 594: }
! 595:
! 596: if (!BG(user_filter_map)) {
! 597: BG(user_filter_map) = (HashTable*) emalloc(sizeof(HashTable));
! 598: zend_hash_init(BG(user_filter_map), 5, NULL, (dtor_func_t) filter_item_dtor, 0);
! 599: }
! 600:
! 601: fdat = ecalloc(1, sizeof(struct php_user_filter_data) + classname_len);
! 602: memcpy(fdat->classname, classname, classname_len);
! 603:
! 604: if (zend_hash_add(BG(user_filter_map), filtername, filtername_len + 1, (void*)fdat,
! 605: sizeof(*fdat) + classname_len, NULL) == SUCCESS &&
! 606: php_stream_filter_register_factory_volatile(filtername, &user_filter_factory TSRMLS_CC) == SUCCESS) {
! 607: RETVAL_TRUE;
! 608: }
! 609:
! 610: efree(fdat);
! 611: }
! 612: /* }}} */
! 613:
! 614:
! 615: /*
! 616: * Local variables:
! 617: * tab-width: 4
! 618: * c-basic-offset: 4
! 619: * End:
! 620: * vim600: sw=4 ts=4 fdm=marker
! 621: * vim<600: sw=4 ts=4
! 622: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>