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