/** * This is a function to call PHP functions in a old-style secure way */ static inline int phalcon_call_func_normal(zval *return_value, char *func_name, int func_length, int noreturn TSRMLS_DC){ zval *fn = NULL; int status = FAILURE; if (!noreturn) { ALLOC_INIT_ZVAL(return_value); } PHALCON_ALLOC_ZVAL(fn); ZVAL_STRINGL(fn, func_name, func_length, 0); status = phalcon_call_user_function(CG(function_table), NULL, fn, return_value, 0, NULL TSRMLS_CC); if (status == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to undefined function %s()", func_name); } ZVAL_NULL(fn); zval_ptr_dtor(&fn); if (!noreturn) { zval_ptr_dtor(&return_value); } if (EG(exception)) { status = FAILURE; } if (status == FAILURE) { phalcon_memory_restore_stack(TSRMLS_C); } return status; }
void test_phalcon_alloc_zval(void) { startup_php(__func__); zend_first_try { zval* x; PHALCON_MM_GROW(); PHALCON_ALLOC_ZVAL(x); CU_ASSERT_EQUAL(Z_REFCOUNT_P(x), 1); CU_ASSERT_EQUAL(Z_ISREF_P(x), 0); CU_ASSERT_EQUAL(Z_TYPE_P(x), IS_NULL); PHALCON_MM_RESTORE(); /* zvals allocated by PHALCON_ALLOC_ZVAL() should not be affected by PHALCON_MM_RESTORE() */ CU_ASSERT_EQUAL(_mem_block_check(x, 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC), 1); CU_ASSERT_EQUAL(Z_REFCOUNT_P(x), 1); zval_ptr_dtor(&x); } zend_catch { CU_ASSERT(0); } zend_end_try(); shutdown_php(); CU_ASSERT_EQUAL(leaks, 0); }
/** * This function implements a secure old-style way to call functions */ static inline int phalcon_call_method_normal(zval *return_value, zval *object, char *method_name, int method_len, int check, int noreturn TSRMLS_DC){ zval *fn = NULL; int status = FAILURE; zend_class_entry *ce, *active_scope = NULL; if (Z_TYPE_P(object) != IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to method %s() on a non object", method_name); phalcon_memory_restore_stack(TSRMLS_C); return FAILURE; } ce = Z_OBJCE_P(object); if (check) { if (!zend_hash_exists(&ce->function_table, method_name, method_len+1)) { return SUCCESS; } } if (!noreturn) { ALLOC_INIT_ZVAL(return_value); } PHALCON_ALLOC_ZVAL(fn); ZVAL_STRINGL(fn, method_name, method_len, 0); active_scope = EG(scope); /* Find class_entry scope */ if (ce->parent) { phalcon_find_scope(ce, method_name, method_len TSRMLS_CC); } else { EG(scope) = ce; } status = phalcon_call_user_function(&ce->function_table, &object, fn, return_value, 0, NULL TSRMLS_CC); if (status == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to undefined method %s()", method_name); } EG(scope) = active_scope; ZVAL_NULL(fn); zval_ptr_dtor(&fn); if (!noreturn) { zval_ptr_dtor(&return_value); } if (EG(exception)) { status = FAILURE; } if (status == FAILURE) { phalcon_memory_restore_stack(TSRMLS_C); } return status; }
/** * Call methods that require parameters in a old-style secure way */ inline int phalcon_call_method_params_normal(zval *return_value, zval *object, char *method_name, int method_len, zend_uint param_count, zval *params[], int check, int noreturn TSRMLS_DC){ zval *fn = NULL; int status = FAILURE; zend_class_entry *ce, *active_scope = NULL; if (check) { if (!zend_hash_exists(&Z_OBJCE_P(object)->function_table, method_name, method_len+1)) { return SUCCESS; } } if (!noreturn) { ALLOC_INIT_ZVAL(return_value); } PHALCON_ALLOC_ZVAL(fn); ZVAL_STRINGL(fn, method_name, method_len, 1); if (Z_TYPE_P(object) == IS_OBJECT) { active_scope = EG(scope); ce = Z_OBJCE_P(object); phalcon_find_scope(ce, method_name, method_len TSRMLS_CC); status = PHALCON_CALL_USER_FUNCTION(&ce->function_table, &object, fn, return_value, param_count, params TSRMLS_CC); if (status == FAILURE) { EG(scope) = active_scope; php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to undefined method %s() on class %s", Z_STRVAL_P(fn), Z_OBJCE_P(object)->name); status = FAILURE; } EG(scope) = active_scope; } else { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to method %s() on a non object", Z_STRVAL_P(fn)); status = FAILURE; } zval_ptr_dtor(&fn); if (!noreturn) { zval_ptr_dtor(&return_value); return_value = NULL; } if (EG(exception)){ status = FAILURE; } if (status == FAILURE) { phalcon_memory_restore_stack(TSRMLS_C); } return status; }
/** * Call single function which requires arbitrary number of parameters */ int phalcon_call_func_params(zval *return_value, char *func_name, int func_length, zend_uint param_count, zval *params[], int noreturn, int fcache_pointer TSRMLS_DC){ zval *fn = NULL; int status = FAILURE; //zval ***params_array; zval *local_retval_ptr = NULL; //int i; if (!noreturn) { ALLOC_INIT_ZVAL(return_value); } PHALCON_ALLOC_ZVAL(fn); ZVAL_STRINGL(fn, func_name, func_length, 1); /*status = phalcon_cache_lookup_function(fn, fcache_pointer); if (status == FAILURE) { return FAILURE; }*/ /*if(param_count){ params_array = (zval ***) emalloc(sizeof(zval **)*param_count); for (i=0; i<param_count; i++) { params_array[i] = ¶ms[i]; } } else { params_array = NULL; }*/ status = call_user_function(CG(function_table), NULL, fn, return_value, param_count, params TSRMLS_CC); //status = phalcon_call_user_function_ex(CG(function_table), NULL, fn, &local_retval_ptr, param_count, params_array, 1, NULL, phalcon_fcall_cache[fcache_pointer] TSRMLS_CC); if (status == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to undefined function %s()", func_name); return FAILURE; } zval_ptr_dtor(&fn); if (local_retval_ptr) { COPY_PZVAL_TO_ZVAL(*return_value, local_retval_ptr); } if (!noreturn) { zval_ptr_dtor(&return_value); } /*if (params_array) { efree(params_array); }*/ return status; }
/** * Call method on an object which not requires parameters * */ int phalcon_call_method(zval *return_value, zval *object, char *method_name, int method_len, int check, int noreturn TSRMLS_DC){ zval *fn = NULL; int status = FAILURE; zend_class_entry *active_scope = NULL; if (check) { if (!zend_hash_exists(&Z_OBJCE_P(object)->function_table, method_name, strlen(method_name)+1)) { return FAILURE; } } if(!noreturn){ ALLOC_INIT_ZVAL(return_value); } PHALCON_ALLOC_ZVAL(fn); ZVAL_STRINGL(fn, method_name, method_len, 1); if (Z_TYPE_P(object) == IS_OBJECT) { active_scope = EG(scope); phalcon_find_scope(Z_OBJCE_P(object), method_name, method_len TSRMLS_CC); status = call_user_function(&Z_OBJCE_P(object)->function_table, &object, fn, return_value, 0, NULL TSRMLS_CC); if (status == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to undefined method %s()", Z_STRVAL_P(fn)); return FAILURE; } EG(scope) = active_scope; } else { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to method %s() on a non object", Z_STRVAL_P(fn)); return FAILURE; } zval_ptr_dtor(&fn); if (!noreturn) { zval_ptr_dtor(&return_value); } return status; }
/** * This is a function to call PHP functions in a old-style secure way */ inline int phalcon_call_func_normal(zval *return_value, char *func_name, int func_length, int noreturn TSRMLS_DC){ zval *fn = NULL; int status = FAILURE; zval *local_retval_ptr = NULL; if (!noreturn) { ALLOC_INIT_ZVAL(return_value); } PHALCON_ALLOC_ZVAL(fn); ZVAL_STRINGL(fn, func_name, func_length, 1); status = PHALCON_CALL_USER_FUNCTION(CG(function_table), NULL, fn, return_value, 0, NULL TSRMLS_CC); if (status == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to undefined function %s()", func_name); } zval_ptr_dtor(&fn); if (local_retval_ptr) { COPY_PZVAL_TO_ZVAL(*return_value, local_retval_ptr); } if (!noreturn) { zval_ptr_dtor(&return_value); } if (EG(exception)){ status = FAILURE; } if (status == FAILURE) { phalcon_memory_restore_stack(TSRMLS_C); } return status; }
/** * Call single function which not requires parameters */ int phalcon_call_func(zval *return_value, char *func_name, int func_length, int noreturn, int fcache_pointer TSRMLS_DC){ zval *fn = NULL; int status = FAILURE; zval *local_retval_ptr = NULL; if (!noreturn) { ALLOC_INIT_ZVAL(return_value); } PHALCON_ALLOC_ZVAL(fn); ZVAL_STRINGL(fn, func_name, func_length, 1); /*status = phalcon_cache_lookup_function(fn, fcache_pointer); if (status == FAILURE) { return FAILURE; }*/ status = call_user_function(CG(function_table), NULL, fn, return_value, 0, NULL TSRMLS_CC); //status = phalcon_call_user_function_ex(CG(function_table), NULL, fn, &local_retval_ptr, 0, NULL, 1, NULL, phalcon_fcall_cache[fcache_pointer] TSRMLS_CC); if (status == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Call to undefined function %s()", func_name); return FAILURE; } zval_ptr_dtor(&fn); if (local_retval_ptr) { COPY_PZVAL_TO_ZVAL(*return_value, local_retval_ptr); } if (!noreturn) { zval_ptr_dtor(&return_value); } return status; }
/** * Applies a format to a message before sending it to the log * * @param string $message * @param int $type * @param int $timestamp * @return string */ PHP_METHOD(Phalcon_Logger_Formatter_Firephp, format) { zval *message, *type, *type_str = NULL, *timestamp; zval *payload, *body, *backtrace, *meta, *encoded; zval *show_backtrace; smart_str result = { NULL, 0, 0 }; int i; Bucket *p; phalcon_fetch_params(0, 3, 0, &message, &type, ×tamp); /** * We intentionally do not use Phalcon's MM for better performance. * All variables allocated with PHALCON_ALLOC_ZVAL() will have * their reference count set to 1 and therefore they can be nicely * put into the result array; when that array will be destroyed, * all inserted variables will be automatically destroyed, too * and we will just save some time by not using Z_ADDREF_P and Z_DELREF_P */ PHALCON_ALLOC_ZVAL(type_str); phalcon_call_method_p1(type_str, this_ptr, "gettypestring", type); phalcon_read_property_this(&show_backtrace, getThis(), SL("_showBacktrace"), PH_NOISY TSRMLS_CC); Z_DELREF_P(show_backtrace); /** * Get the backtrace. This differs for differemt PHP versions. * 5.3.6+ allows us to skip the function arguments which will save some memory * For 5.4+ there is an extra argument. */ PHALCON_ALLOC_ZVAL(backtrace); if (zend_is_true(show_backtrace)) { #if PHP_VERSION_ID < 50306 zend_fetch_debug_backtrace(backtrace, 1, 0 TSRMLS_CC); #elif PHP_VERSION_ID < 50400 zend_fetch_debug_backtrace(backtrace, 1, DEBUG_BACKTRACE_IGNORE_ARGS TSRMLS_CC); #else zend_fetch_debug_backtrace(backtrace, 1, DEBUG_BACKTRACE_IGNORE_ARGS, 0 TSRMLS_CC); #endif if (Z_TYPE_P(backtrace) == IS_ARRAY) { HashPosition pos; HashTable *ht = Z_ARRVAL_P(backtrace); zval **ppzval; int found = 0; ulong idx; char *key; uint key_len; /** * At this point we know that the backtrace is the array. * Again, we intentionally do not use Phalcon's API because we know * that we are working with the array / hash table and thus we can * save some time by omitting Z_TYPE_P(x) == IS_ARRAY checks */ for ( zend_hash_internal_pointer_reset_ex(ht, &pos); zend_hash_has_more_elements_ex(ht, &pos) == SUCCESS; ) { zend_hash_get_current_data_ex(ht, (void**)&ppzval, &pos); zend_hash_get_current_key_ex(ht, &key, &key_len, &idx, 0, &pos); zend_hash_move_forward_ex(ht, &pos); if (Z_TYPE_PP(ppzval) == IS_ARRAY) { /** * Here we need to skip the latest calls into Phalcon's core. * Calls to Zend internal functions will have "file" index not set. * We remove these entries from the array. */ if (!found && !zend_hash_exists(Z_ARRVAL_PP(ppzval), SS("file"))) { zend_hash_index_del(ht, idx); } else { /** * Remove args and object indices. They usually give * too much information; this is not suitable to send * in the HTTP headers */ zend_hash_del(Z_ARRVAL_PP(ppzval), "args", sizeof("args")); zend_hash_del(Z_ARRVAL_PP(ppzval), "object", sizeof("object")); found = 1; } } } /** * Now we need to renumber the hash table because we removed several * heading elements. If we don't do this, json_encode() will convert * this array to a JavaScript object which is an unwanted side effect */ p = ht->pListHead; i = 0; while (p != NULL) { p->nKeyLength = 0; p->h = i++; p = p->pListNext; } ht->nNextFreeElement = i; zend_hash_rehash(ht); } } /** * The result will looks like this: * * array( * array('Type' => 'message type', 'Label' => 'message'), * array('backtrace' => array(backtrace goes here) * ) */ MAKE_STD_ZVAL(payload); array_init_size(payload, 2); PHALCON_ALLOC_ZVAL(meta); array_init_size(meta, 4); add_assoc_zval_ex(meta, SS("Type"), type_str); Z_ADDREF_P(message); add_assoc_zval_ex(meta, SS("Label"), message); if (Z_TYPE_P(backtrace) == IS_ARRAY) { zval **ppzval; if (likely(SUCCESS == zend_hash_index_find(Z_ARRVAL_P(backtrace), 0, (void**)&ppzval)) && likely(Z_TYPE_PP(ppzval) == IS_ARRAY)) { zval **file = NULL, **line = NULL; zend_hash_quick_find(Z_ARRVAL_PP(ppzval), SS("file"), zend_inline_hash_func(SS("file")), (void**)&file); zend_hash_quick_find(Z_ARRVAL_PP(ppzval), SS("line"), zend_inline_hash_func(SS("line")), (void**)&line); if (likely(file != NULL)) { Z_ADDREF_PP(file); add_assoc_zval_ex(meta, SS("File"), *file); } if (likely(line != NULL)) { Z_ADDREF_PP(line); add_assoc_zval_ex(meta, SS("Line"), *line); } } } MAKE_STD_ZVAL(body); array_init_size(body, 1); if (zend_is_true(show_backtrace)) { add_assoc_zval_ex(body, SS("backtrace"), backtrace); } else { zval_ptr_dtor(&backtrace); } add_next_index_zval(payload, meta); add_next_index_zval(payload, body); /** * Convert everything to JSON */ ALLOC_INIT_ZVAL(encoded); phalcon_json_encode(encoded, payload, 0 TSRMLS_CC); /** * As promised, kill the payload and all associated elements */ zval_ptr_dtor(&payload); /** * We don't want to use Phalcon's concatenation API because it * requires the memory manager. Therefore we fall back to using smart strings. * smart_str_alloc4() will allocate all required memory amount (plus some more) * in one go and this allows us to avoid performance penalties due to * memory reallocations. */ smart_str_alloc4(&result, Z_STRLEN_P(encoded) + 2 + 5, 0, i); /** * The format is: * * <size>|[meta,body]| * * Meta and body are contained in encoded inside the array, as required * by the protocol specification * @see http://www.firephp.org/Wiki/Reference/Protocol */ smart_str_append_long(&result, Z_STRLEN_P(encoded)); smart_str_appendc(&result, '|'); smart_str_appendl(&result, Z_STRVAL_P(encoded), Z_STRLEN_P(encoded)); smart_str_appendc(&result, '|'); smart_str_0(&result); /* We don't need the JSON message anymore */ zval_ptr_dtor(&encoded); /* Do not free the samrt string because we steal its data for zval */ RETURN_STRINGL(result.c, result.len, 0); }