Return to user_filters.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
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: */