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