php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
user_filters.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: |
14 | Wez Furlong (wez@thebrainroom.com) |
15 | Sara Golemon (pollita@php.net) |
16 +----------------------------------------------------------------------+
17*/
18
19#include "php.h"
20#include "php_globals.h"
22#include "ext/standard/file.h"
24
25#define PHP_STREAM_BRIGADE_RES_NAME "userfilter.bucket brigade"
26#define PHP_STREAM_BUCKET_RES_NAME "userfilter.bucket"
27
30 /* variable length; this *must* be last in the structure */
32};
33
34/* to provide context for calling into the next filter from user-space */
35static int le_bucket_brigade;
36static int le_bucket;
37
38/* define the base filter class */
39
41{
42 zval *in, *out, *consumed;
43 bool closing;
44 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrzb", &in, &out, &consumed, &closing) == FAILURE) {
46 }
47
49}
50
57
62
63static zend_class_entry *user_filter_class_entry;
64static zend_class_entry *stream_bucket_class_entry;
65
66static ZEND_RSRC_DTOR_FUNC(php_bucket_dtor)
67{
68 php_stream_bucket *bucket = (php_stream_bucket *)res->ptr;
69 if (bucket) {
71 bucket = NULL;
72 }
73}
74
75PHP_MINIT_FUNCTION(user_filters)
76{
77 /* init the filter class ancestor */
78 user_filter_class_entry = register_class_php_user_filter();
79 stream_bucket_class_entry = register_class_StreamBucket();
80
81 /* Filters will dispose of their brigades */
82 le_bucket_brigade = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_BRIGADE_RES_NAME, module_number);
83 /* Brigades will dispose of their buckets */
84 le_bucket = zend_register_list_destructors_ex(php_bucket_dtor, NULL, PHP_STREAM_BUCKET_RES_NAME, module_number);
85
86 if (le_bucket_brigade == FAILURE) {
87 return FAILURE;
88 }
89
90 register_user_filters_symbols(module_number);
91
92 return SUCCESS;
93}
94
96{
97 if (BG(user_filter_map)) {
98 zend_hash_destroy(BG(user_filter_map));
99 efree(BG(user_filter_map));
100 BG(user_filter_map) = NULL;
101 }
102
103 return SUCCESS;
104}
105
106static void userfilter_dtor(php_stream_filter *thisfilter)
107{
108 zval *obj = &thisfilter->abstract;
109 zval retval;
110
111 if (Z_ISUNDEF_P(obj)) {
112 /* If there's no object associated then there's nothing to dispose of */
113 return;
114 }
115
116 zend_string *func_name = ZSTR_INIT_LITERAL("onclose", 0);
118 zend_string_release(func_name);
119
121
122 /* kill the object */
123 zval_ptr_dtor(obj);
124}
125
126static php_stream_filter_status_t userfilter_filter(
127 php_stream *stream,
128 php_stream_filter *thisfilter,
129 php_stream_bucket_brigade *buckets_in,
130 php_stream_bucket_brigade *buckets_out,
131 size_t *bytes_consumed,
132 int flags
133 )
134{
135 int ret = PSFS_ERR_FATAL;
136 zval *obj = &thisfilter->abstract;
138 zval retval;
139 zval args[4];
140 int call_result;
141
142 /* the userfilter object probably doesn't exist anymore */
143 if (CG(unclean_shutdown)) {
144 return ret;
145 }
146
147 /* Make sure the stream is not closed while the filter callback executes. */
148 uint32_t orig_no_fclose = stream->flags & PHP_STREAM_FLAG_NO_FCLOSE;
150
151 zval *stream_prop = zend_hash_str_find_ind(Z_OBJPROP_P(obj), "stream", sizeof("stream")-1);
152 if (stream_prop) {
153 /* Give the userfilter class a hook back to the stream */
154 zval_ptr_dtor(stream_prop);
155 php_stream_to_zval(stream, stream_prop);
156 Z_ADDREF_P(stream_prop);
157 }
158
159 ZVAL_STRINGL(&func_name, "filter", sizeof("filter")-1);
160
161 /* Setup calling arguments */
162 ZVAL_RES(&args[0], zend_register_resource(buckets_in, le_bucket_brigade));
163 ZVAL_RES(&args[1], zend_register_resource(buckets_out, le_bucket_brigade));
164
165 if (bytes_consumed) {
166 ZVAL_LONG(&args[2], *bytes_consumed);
167 } else {
168 ZVAL_NULL(&args[2]);
169 }
170 ZVAL_MAKE_REF(&args[2]);
171
173
174 call_result = call_user_function(NULL,
175 obj,
176 &func_name,
177 &retval,
178 4, args);
179
181
182 if (call_result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
184 ret = (int)Z_LVAL(retval);
185 } else if (call_result == FAILURE) {
186 php_error_docref(NULL, E_WARNING, "Failed to call filter function");
187 }
188
189 if (bytes_consumed) {
190 *bytes_consumed = zval_get_long(&args[2]);
191 }
192
193 if (buckets_in->head) {
194 php_error_docref(NULL, E_WARNING, "Unprocessed filter buckets remaining on input brigade");
195 }
196
197 /* filter resources are cleaned up by the stream destructor,
198 * keeping a reference to the stream resource here would prevent it
199 * from being destroyed properly */
200 if (stream_prop) {
201 convert_to_null(stream_prop);
202 }
203
204 zval_ptr_dtor(&args[3]);
205 zval_ptr_dtor(&args[2]);
206 zval_ptr_dtor(&args[1]);
207 zval_ptr_dtor(&args[0]);
208
210 stream->flags |= orig_no_fclose;
211
212 return ret;
213}
214
215static const php_stream_filter_ops userfilter_ops = {
216 userfilter_filter,
217 userfilter_dtor,
218 "user-filter"
219};
220
221static php_stream_filter *user_filter_factory_create(const char *filtername,
222 zval *filterparams, uint8_t persistent)
223{
224 struct php_user_filter_data *fdat = NULL;
225 php_stream_filter *filter;
226 zval obj;
227 zval retval;
228 size_t len;
229
230 /* some sanity checks */
231 if (persistent) {
233 "Cannot use a user-space filter with a persistent stream");
234 return NULL;
235 }
236
237 len = strlen(filtername);
238
239 /* determine the classname/class entry */
240 if (NULL == (fdat = zend_hash_str_find_ptr(BG(user_filter_map), (char*)filtername, len))) {
241 char *period;
242
243 /* Userspace Filters using ambiguous wildcards could cause problems.
244 i.e.: myfilter.foo.bar will always call into myfilter.foo.*
245 never seeing myfilter.*
246 TODO: Allow failed userfilter creations to continue
247 scanning through the list */
248 if ((period = strrchr(filtername, '.'))) {
249 char *wildcard = safe_emalloc(len, 1, 3);
250
251 /* Search for wildcard matches instead */
252 memcpy(wildcard, filtername, len + 1); /* copy \0 */
253 period = wildcard + (period - filtername);
254 while (period) {
255 ZEND_ASSERT(period[0] == '.');
256 period[1] = '*';
257 period[2] = '\0';
258 if (NULL != (fdat = zend_hash_str_find_ptr(BG(user_filter_map), wildcard, strlen(wildcard)))) {
259 period = NULL;
260 } else {
261 *period = '\0';
262 period = strrchr(wildcard, '.');
263 }
264 }
265 efree(wildcard);
266 }
267 ZEND_ASSERT(fdat);
268 }
269
270 /* bind the classname to the actual class */
271 if (fdat->ce == NULL) {
272 if (NULL == (fdat->ce = zend_lookup_class(fdat->classname))) {
274 "User-filter \"%s\" requires class \"%s\", but that class is not defined",
275 filtername, ZSTR_VAL(fdat->classname));
276 return NULL;
277 }
278 }
279
280 /* create the object */
281 if (object_init_ex(&obj, fdat->ce) == FAILURE) {
282 return NULL;
283 }
284
285 filter = php_stream_filter_alloc(&userfilter_ops, NULL, 0);
286 if (filter == NULL) {
287 zval_ptr_dtor(&obj);
288 return NULL;
289 }
290
291 /* filtername */
292 add_property_string(&obj, "filtername", (char*)filtername);
293
294 /* and the parameters, if any */
295 if (filterparams) {
296 add_property_zval(&obj, "params", filterparams);
297 } else {
298 add_property_null(&obj, "params");
299 }
300
301 /* invoke the constructor */
302 zend_string *func_name = ZSTR_INIT_LITERAL("oncreate", 0);
304 zend_string_release(func_name);
305
306 if (Z_TYPE(retval) != IS_UNDEF) {
307 if (Z_TYPE(retval) == IS_FALSE) {
308 /* User reported filter creation error "return false;" */
310
311 /* Kill the filter (safely) */
312 ZVAL_UNDEF(&filter->abstract);
314
315 /* Kill the object */
316 zval_ptr_dtor(&obj);
317
318 /* Report failure to filter_alloc */
319 return NULL;
320 }
322 }
323
324 ZVAL_OBJ(&filter->abstract, Z_OBJ(obj));
325
326 return filter;
327}
328
329static const php_stream_filter_factory user_filter_factory = {
330 user_filter_factory_create
331};
332
333static void filter_item_dtor(zval *zv)
334{
335 struct php_user_filter_data *fdat = Z_PTR_P(zv);
337 efree(fdat);
338}
339
340/* {{{ Return a bucket object from the brigade for operating on */
342{
343 zval *zbrigade, zbucket;
345 php_stream_bucket *bucket;
346
348 Z_PARAM_RESOURCE(zbrigade)
350
352 Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
354 }
355
356 if (brigade->head && (bucket = php_stream_bucket_make_writeable(brigade->head))) {
357 ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
358 object_init_ex(return_value, stream_bucket_class_entry);
360 /* add_property_zval increments the refcount which is unwanted here */
361 zval_ptr_dtor(&zbucket);
365 } else {
367 }
368}
369/* }}} */
370
371/* {{{ php_stream_bucket_attach */
372static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
373{
374 zval *zbrigade, *zobject;
375 zval *pzbucket, *pzdata, rv;
377 php_stream_bucket *bucket;
378
380 Z_PARAM_RESOURCE(zbrigade)
381 Z_PARAM_OBJECT_OF_CLASS(zobject, stream_bucket_class_entry)
383
385 Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
387 }
388
389 if (NULL == (pzbucket = zend_read_property(NULL, Z_OBJ_P(zobject), "bucket", sizeof("bucket")-1, false, &rv))) {
390 zend_argument_value_error(2, "must be an object that has a \"bucket\" property");
392 }
393 ZVAL_DEREF(pzbucket);
394
395 if ((bucket = (php_stream_bucket *)zend_fetch_resource_ex(pzbucket, PHP_STREAM_BUCKET_RES_NAME, le_bucket)) == NULL) {
397 }
398
399 if (NULL != (pzdata = zend_read_property(NULL, Z_OBJ_P(zobject), "data", sizeof("data")-1, false, &rv))) {
400 ZVAL_DEREF(pzdata);
401 if (!bucket->own_buf) {
402 bucket = php_stream_bucket_make_writeable(bucket);
403 }
404 if (bucket->buflen != Z_STRLEN_P(pzdata)) {
405 bucket->buf = perealloc(bucket->buf, MAX(Z_STRLEN_P(pzdata), 1), bucket->is_persistent);
406 bucket->buflen = Z_STRLEN_P(pzdata);
407 }
408 memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);
409 }
410
411 if (append) {
412 php_stream_bucket_append(brigade, bucket);
413 } else {
414 php_stream_bucket_prepend(brigade, bucket);
415 }
416 /* This is a hack necessary to accommodate situations where bucket is appended to the stream
417 * multiple times. See bug35916.phpt for reference.
418 */
419 if (bucket->refcount == 1) {
420 bucket->refcount++;
421 }
422}
423/* }}} */
424
425/* {{{ Prepend bucket to brigade */
427{
428 php_stream_bucket_attach(0, INTERNAL_FUNCTION_PARAM_PASSTHRU);
429}
430/* }}} */
431
432/* {{{ Append bucket to brigade */
434{
435 php_stream_bucket_attach(1, INTERNAL_FUNCTION_PARAM_PASSTHRU);
436}
437/* }}} */
438
439/* {{{ Create a new bucket for use on the current stream */
441{
442 zval *zstream, zbucket;
443 php_stream *stream;
444 char *buffer;
445 char *pbuffer;
446 size_t buffer_len;
447 php_stream_bucket *bucket;
448
450 Z_PARAM_ZVAL(zstream)
451 Z_PARAM_STRING(buffer, buffer_len)
453
454 php_stream_from_zval(stream, zstream);
455 pbuffer = pemalloc(buffer_len, php_stream_is_persistent(stream));
456
457 memcpy(pbuffer, buffer, buffer_len);
458
459 bucket = php_stream_bucket_new(stream, pbuffer, buffer_len, 1, php_stream_is_persistent(stream));
460
461 ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
462 object_init_ex(return_value, stream_bucket_class_entry);
464 /* add_property_zval increments the refcount which is unwanted here */
465 zval_ptr_dtor(&zbucket);
469}
470/* }}} */
471
472/* {{{ Returns a list of registered filters */
474{
475 zend_string *filter_name;
476 HashTable *filters_hash;
477
479
481
482 filters_hash = php_get_stream_filters_hash();
483
484 if (filters_hash && !HT_IS_PACKED(filters_hash)) {
485 ZEND_HASH_MAP_FOREACH_STR_KEY(filters_hash, filter_name) {
486 if (filter_name) {
487 add_next_index_str(return_value, zend_string_copy(filter_name));
488 }
490 }
491 /* It's okay to return an empty array if no filters are registered */
492}
493/* }}} */
494
495/* {{{ Registers a custom filter handler class */
497{
498 zend_string *filtername, *classname;
499 struct php_user_filter_data *fdat;
500
502 Z_PARAM_STR(filtername)
505
506 if (!ZSTR_LEN(filtername)) {
507 zend_argument_value_error(1, "must be a non-empty string");
509 }
510
511 if (!ZSTR_LEN(classname)) {
512 zend_argument_value_error(2, "must be a non-empty string");
514 }
515
516 if (!BG(user_filter_map)) {
517 BG(user_filter_map) = (HashTable*) emalloc(sizeof(HashTable));
518 zend_hash_init(BG(user_filter_map), 8, NULL, (dtor_func_t) filter_item_dtor, 0);
519 }
520
521 fdat = ecalloc(1, sizeof(struct php_user_filter_data));
522 fdat->classname = zend_string_copy(classname);
523
524 if (zend_hash_add_ptr(BG(user_filter_map), filtername, fdat) != NULL) {
525 if (php_stream_filter_register_factory_volatile(filtername, &user_filter_factory) == SUCCESS) {
527 }
528
529 zend_hash_del(BG(user_filter_map), filtername);
530 } else {
532 efree(fdat);
533 }
534
536}
537/* }}} */
size_t len
Definition apprentice.c:174
#define BG(v)
stream_bucket_append($brigade, StreamBucket $bucket)
strrchr(string $haystack, string $needle, bool $before_needle=false)
stream_bucket_make_writeable($brigade)
stream_bucket_prepend($brigade, StreamBucket $bucket)
stream_filter_register(string $filter_name, string $class)
stream_bucket_new($stream, string $buffer)
zval * zv
Definition ffi.c:3975
zend_string * res
Definition ffi.c:4692
memcpy(ptr1, ptr2, size)
ffi persistent
Definition ffi.c:3633
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
PHPAPI php_stream_bucket * php_stream_bucket_new(php_stream *stream, char *buf, size_t buflen, uint8_t own_buf, uint8_t buf_persistent)
Definition filter.c:71
PHPAPI php_stream_bucket * php_stream_bucket_make_writeable(php_stream_bucket *bucket)
Definition filter.c:104
PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket)
Definition filter.c:174
PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket)
Definition filter.c:150
PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket)
Definition filter.c:160
PHPAPI int php_stream_filter_register_factory_volatile(zend_string *filterpattern, const php_stream_filter_factory *factory)
Definition filter.c:58
PHPAPI void php_stream_filter_free(php_stream_filter *filter)
Definition filter.c:278
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define PHP_FUNCTION
Definition php.h:364
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define PHP_RSHUTDOWN_FUNCTION
Definition php.h:403
#define PHP_METHOD
Definition php.h:365
#define php_stream_filter_alloc(fops, thisptr, persistent)
#define PSFS_FLAG_FLUSH_CLOSE
struct _php_stream_filter_ops php_stream_filter_ops
php_stream_filter_status_t
@ PSFS_ERR_FATAL
struct _php_stream_filter_factory php_stream_filter_factory
struct _php_stream_bucket php_stream_bucket
struct _php_stream_bucket_brigade php_stream_bucket_brigade
struct _php_stream php_stream
Definition php_streams.h:96
#define php_stream_from_zval(xstr, pzval)
struct _php_stream_filter php_stream_filter
Definition php_streams.h:99
#define php_stream_to_zval(stream, zval)
#define php_get_stream_filters_hash()
#define php_stream_is_persistent(stream)
#define PHP_STREAM_FLAG_NO_FCLOSE
const char * func_name
zval rv
Definition session.c:1024
uint32_t flags
Definition file.h:177
zend_class_entry * ce
zend_string * classname
#define PHP_STREAM_BUCKET_RES_NAME
#define PHP_STREAM_BRIGADE_RES_NAME
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
#define INTERNAL_FUNCTION_PARAM_PASSTHRU
Definition zend.h:50
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
Definition zend_API.c:1849
ZEND_API zval * zend_read_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, bool silent, zval *rv)
Definition zend_API.c:5201
ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, const char *value, size_t value_len)
Definition zend_API.c:5076
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API void zend_update_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zval *value)
Definition zend_API.c:4991
ZEND_API void zend_update_property_long(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zend_long value)
Definition zend_API.c:5039
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
ZEND_API zend_result add_next_index_str(zval *arg, zend_string *str)
Definition zend_API.c:2177
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define Z_PARAM_RESOURCE(dest)
Definition zend_API.h:2056
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
ZEND_API zend_result zend_call_method_if_exists(zend_object *object, zend_string *method_name, zval *retval, uint32_t param_count, zval *params)
#define Z_PARAM_STRING(dest, dest_len)
Definition zend_API.h:2071
#define Z_PARAM_STR(dest)
Definition zend_API.h:2086
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_THROWS()
Definition zend_API.h:1060
#define call_user_function(function_table, object, function_name, retval_ptr, param_count, params)
Definition zend_API.h:687
#define Z_PARAM_OBJECT_OF_CLASS(dest, _ce)
Definition zend_API.h:1976
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define ZVAL_STRINGL(z, s, l)
Definition zend_API.h:952
#define RETURN_TRUE
Definition zend_API.h:1059
#define array_init(arg)
Definition zend_API.h:537
#define perealloc(ptr, size, persistent)
Definition zend_alloc.h:201
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define efree(ptr)
Definition zend_alloc.h:155
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
zend_string_release_ex(func->internal_function.function_name, 0)
zval * args
#define E_WARNING
Definition zend_errors.h:24
ZEND_API zend_class_entry * zend_lookup_class(zend_string *name)
#define CG(v)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
Definition zend_hash.c:1534
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define HT_IS_PACKED(ht)
Definition zend_hash.h:59
#define ZEND_HASH_MAP_FOREACH_STR_KEY(ht, _key)
Definition zend_hash.h:1346
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
ZEND_API void * zend_fetch_resource(zend_resource *res, const char *resource_type_name, int resource_type)
Definition zend_list.c:117
ZEND_API zend_resource * zend_register_resource(void *rsrc_pointer, int rsrc_type)
Definition zend_list.c:87
ZEND_API void * zend_fetch_resource_ex(zval *res, const char *resource_type_name, int resource_type)
Definition zend_list.c:132
ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, const char *type_name, int module_number)
Definition zend_list.c:265
#define ZEND_RSRC_DTOR_FUNC(name)
Definition zend_list.h:29
struct _zend_string zend_string
ZEND_API void ZEND_FASTCALL convert_to_null(zval *op)
ZEND_API void ZEND_FASTCALL convert_to_long(zval *op)
#define ZEND_ASSERT(c)
#define ZEND_STRL(str)
#define MAX(a, b)
struct _zend_class_entry zend_class_entry
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_INIT_LITERAL(s, persistent)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define ZVAL_UNDEF(z)
#define IS_FALSE
Definition zend_types.h:602
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define Z_ISUNDEF_P(zval_p)
Definition zend_types.h:957
#define ZVAL_NULL(z)
#define ZVAL_DEREF(z)
#define ZVAL_LONG(z, l)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define Z_PTR_P(zval_p)
void(* dtor_func_t)(zval *pDest)
Definition zend_types.h:107
#define Z_ADDREF_P(pz)
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define ZVAL_RES(z, r)
#define Z_OBJCE_P(zval_p)
#define ZVAL_OBJ(z, o)
@ FAILURE
Definition zend_types.h:61
#define ZVAL_MAKE_REF(zv)
#define Z_OBJPROP_P(zval_p)
#define Z_RES_P(zval_p)
#define Z_TYPE(zval)
Definition zend_types.h:659
#define ZVAL_BOOL(z, b)
#define Z_LVAL(zval)
Definition zend_types.h:965
#define Z_OBJ(zval)
Definition zend_types.h:989
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval retval
zval * return_value
zval * ret
out($f, $s)