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