diff options
author | Anatol Belski <ab@php.net> | 2014-10-24 22:28:32 +0200 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2014-10-24 22:28:32 +0200 |
commit | c51a42076c0f92988115a25068b8ab01dfb8a6ff (patch) | |
tree | 87e1a4f1eec114067ca1d66beb02fb7ddd477cd6 /sapi/phpdbg/phpdbg_wait.c | |
parent | 9cbdf3e66a76895861b6f39e1b1ef5cc46d76654 (diff) | |
parent | 1b4fd5825a820873e4ed0f326bcb890e660dc39c (diff) | |
download | php-git-c51a42076c0f92988115a25068b8ab01dfb8a6ff.tar.gz |
Merge remote-tracking branch 'origin/master' into native-tls
* origin/master: (214 commits)
fix datatype mismatch warnings
fix datatype mismatches
fix datatype mismatches
fix datatype mismatches
fix datatype mismatch warnings
fix datatype mismatch warnings
fix datatype mismatch warnings
fix datatype mismatch warning
fix datatype mismatches
fix datatype mismatch warnings
Re-add phpdbg to travis
Added some NEWS
Make xml valid (missing space between attrs)
Fix info classes file name in xml
Add note about <eval> tag for errors in xml.md
Name the tag <eval> if the error id during ev cmd
Do not print out xml as PHP print...
Fix output to wrong function
Fixed parameter order on %.*s
Too much copypaste...
...
Diffstat (limited to 'sapi/phpdbg/phpdbg_wait.c')
-rw-r--r-- | sapi/phpdbg/phpdbg_wait.c | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/sapi/phpdbg/phpdbg_wait.c b/sapi/phpdbg/phpdbg_wait.c new file mode 100644 index 0000000000..9051ca379f --- /dev/null +++ b/sapi/phpdbg/phpdbg_wait.c @@ -0,0 +1,400 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg_wait.h" +#include "phpdbg_prompt.h" +#include "ext/json/JSON_parser.h" +#include "ext/standard/basic_functions.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +ZEND_EXTERN_MODULE_GLOBALS(json); + +static void phpdbg_rebuild_http_globals_array(int type, const char *name TSRMLS_DC) { + zval *zvp; + if (Z_TYPE(PG(http_globals)[type]) != IS_UNDEF) { + zval_dtor(&PG(http_globals)[type]); + } + if ((zvp = zend_hash_str_find(&EG(symbol_table).ht, name, strlen(name)))) { + Z_ADDREF_P(zvp); + PG(http_globals)[type] = *zvp; + } +} + + +static int phpdbg_dearm_autoglobals(zend_auto_global *auto_global TSRMLS_DC) { + if (auto_global->name->len != sizeof("GLOBALS") - 1 || memcmp(auto_global->name->val, "GLOBALS", sizeof("GLOBALS") - 1)) { + auto_global->armed = 0; + } + + return ZEND_HASH_APPLY_KEEP; +} + +typedef struct { + HashTable *ht[2]; + HashPosition pos[2]; +} phpdbg_intersect_ptr; + +static int phpdbg_array_data_compare(const void *a, const void *b TSRMLS_DC) { + Bucket *f, *s; + zval result; + zval *first, *second; + + f = *((Bucket **) a); + s = *((Bucket **) b); + + first = &f->val; + second = &s->val; + + if (string_compare_function(&result, first, second TSRMLS_CC) == FAILURE) { + return 0; + } + + if (Z_LVAL(result) < 0) { + return -1; + } else if (Z_LVAL(result) > 0) { + return 1; + } + + return 0; +} + +static void phpdbg_array_intersect_init(phpdbg_intersect_ptr *info, HashTable *ht1, HashTable *ht2 TSRMLS_DC) { + info->ht[0] = ht1; + info->ht[1] = ht2; + + zend_hash_sort(info->ht[0], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC); + zend_hash_sort(info->ht[1], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC); + + zend_hash_internal_pointer_reset_ex(info->ht[0], &info->pos[0]); + zend_hash_internal_pointer_reset_ex(info->ht[1], &info->pos[1]); +} + +/* -1 => first array, 0 => both arrays equal, 1 => second array */ +static int phpdbg_array_intersect(phpdbg_intersect_ptr *info, zval **ptr) { + int ret; + zval *zvp[2]; + int invalid = !info->ht[0] + !info->ht[1]; + + if (invalid > 0) { + invalid = !info->ht[0]; + + if (!(*ptr = zend_hash_get_current_data_ex(info->ht[invalid], &info->pos[invalid]))) { + return 0; + } + + zend_hash_move_forward_ex(info->ht[invalid], &info->pos[invalid]); + + return invalid ? 1 : -1; + } + + if (!(zvp[0] = zend_hash_get_current_data_ex(info->ht[0], &info->pos[0]))) { + info->ht[0] = NULL; + return phpdbg_array_intersect(info, ptr); + } + if (!(zvp[1] = zend_hash_get_current_data_ex(info->ht[1], &info->pos[1]))) { + info->ht[1] = NULL; + return phpdbg_array_intersect(info, ptr); + } + + ret = zend_binary_zval_strcmp(zvp[0], zvp[1]); + + if (ret <= 0) { + *ptr = zvp[0]; + zend_hash_move_forward_ex(info->ht[0], &info->pos[0]); + } + if (ret >= 0) { + *ptr = zvp[1]; + zend_hash_move_forward_ex(info->ht[1], &info->pos[1]); + } + + return ret; +} + +void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC) { +#ifdef HAVE_JSON + zval *free_zv = NULL; + zval zv, *zvp; + HashTable *ht; + php_json_decode(&zv, msg, len, 1, 1000 /* enough */ TSRMLS_CC); + + if (JSON_G(error_code) != PHP_JSON_ERROR_NONE) { + phpdbg_error("wait", "type=\"invaliddata\" import=\"fail\"", "Malformed JSON was sent to this socket, arborting"); + return; + } + + ht = Z_ARRVAL(zv); + + /* Reapply symbol table */ + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("GLOBALS"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + { + zval *srv; + if ((srv = zend_hash_str_find(Z_ARRVAL_P(zvp), ZEND_STRL("_SERVER"))) && Z_TYPE_P(srv) == IS_ARRAY) { + zval *script; + if ((script = zend_hash_str_find(Z_ARRVAL_P(srv), ZEND_STRL("SCRIPT_FILENAME"))) && Z_TYPE_P(script) == IS_STRING) { + phpdbg_param_t param; + param.str = Z_STRVAL_P(script); + PHPDBG_COMMAND_HANDLER(exec)(¶m TSRMLS_CC); + } + } + } + + PG(auto_globals_jit) = 0; + zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_dearm_autoglobals TSRMLS_CC); + + zend_hash_clean(&EG(symbol_table).ht); + EG(symbol_table) = *Z_ARR_P(zvp); + + /* Rebuild cookies, env vars etc. from GLOBALS (PG(http_globals)) */ + phpdbg_rebuild_http_globals_array(TRACK_VARS_POST, "_POST" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_GET, "_GET" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_COOKIE, "_COOKIE" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_SERVER, "_SERVER" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_ENV, "_ENV" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_FILES, "_FILES" TSRMLS_CC); + + Z_ADDREF_P(zvp); + free_zv = zvp; + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("input"))) && Z_TYPE_P(zvp) == IS_STRING) { + if (SG(request_info).request_body) { + php_stream_close(SG(request_info).request_body); + } + SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir)); + php_stream_truncate_set_size(SG(request_info).request_body, 0); + php_stream_write(SG(request_info).request_body, Z_STRVAL_P(zvp), Z_STRLEN_P(zvp)); + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("cwd"))) && Z_TYPE_P(zvp) == IS_STRING) { + if (VCWD_CHDIR(Z_STRVAL_P(zvp)) == SUCCESS) { + if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) { + efree(BG(CurrentStatFile)); + BG(CurrentStatFile) = NULL; + } + if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) { + efree(BG(CurrentLStatFile)); + BG(CurrentLStatFile) = NULL; + } + } + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("sapi_name"))) && (Z_TYPE_P(zvp) == IS_STRING || Z_TYPE_P(zvp) == IS_NULL)) { + if (PHPDBG_G(sapi_name_ptr)) { + free(PHPDBG_G(sapi_name_ptr)); + } + if (Z_TYPE_P(zvp) == IS_STRING) { + PHPDBG_G(sapi_name_ptr) = sapi_module.name = strdup(Z_STRVAL_P(zvp)); + } else { + PHPDBG_G(sapi_name_ptr) = sapi_module.name = NULL; + } + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("modules"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + phpdbg_intersect_ptr pos; + zval *module; + zend_module_entry *mod; + HashTable zv_registry; + + /* intersect modules, unregister modules loaded "too much", announce not yet registered modules (phpdbg_notice) */ + + zend_hash_init(&zv_registry, zend_hash_num_elements(&module_registry), 0, ZVAL_PTR_DTOR, 0); + ZEND_HASH_FOREACH_PTR(&module_registry, mod) { + if (mod->name) { + zval value; + ZVAL_NEW_STR(&value, zend_string_init(mod->name, strlen(mod->name), 0)); + zend_hash_next_index_insert(&zv_registry, &value); + } + } ZEND_HASH_FOREACH_END(); + + phpdbg_array_intersect_init(&pos, &zv_registry, Z_ARRVAL_P(zvp) TSRMLS_CC); + do { + int mode = phpdbg_array_intersect(&pos, &module); + if (mode < 0) { + // loaded module, but not needed + if (strcmp(PHPDBG_NAME, Z_STRVAL_P(module))) { + zend_hash_del(&module_registry, Z_STR_P(module)); + } + } else if (mode > 0) { + // not loaded module + if (!sapi_module.name || strcmp(sapi_module.name, Z_STRVAL_P(module))) { + phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", Z_STRLEN_P(module), Z_STRVAL_P(module), Z_STRLEN_P(module), Z_STRVAL_P(module)); + } + } + } while (module); + + zend_hash_clean(&zv_registry); + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("extensions"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + zend_extension *extension; + zend_llist_position pos; + zval *name = NULL; + zend_string *strkey; + + extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos); + while (extension) { + extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos); + + /* php_serach_array() body should be in some ZEND_API function... */ + ZEND_HASH_FOREACH_STR_KEY_PTR(Z_ARRVAL_P(zvp), strkey, name) { + if (Z_TYPE_P(name) == IS_STRING && !zend_binary_strcmp(extension->name, strlen(extension->name), Z_STRVAL_P(name), Z_STRLEN_P(name))) { + break; + } + name = NULL; + } ZEND_HASH_FOREACH_END(); + + if (name) { + /* sigh, breaking the encapsulation, there aren't any functions manipulating the llist at the place of the zend_llist_position */ + zend_llist_element *elm = pos; + if (elm->prev) { + elm->prev->next = elm->next; + } else { + zend_extensions.head = elm->next; + } + if (elm->next) { + elm->next->prev = elm->prev; + } else { + zend_extensions.tail = elm->prev; + } +#if ZEND_EXTENSIONS_SUPPORT + if (extension->shutdown) { + extension->shutdown(extension); + } +#endif + if (zend_extensions.dtor) { + zend_extensions.dtor(elm->data); + } + pefree(elm, zend_extensions.persistent); + zend_extensions.count--; + } else { +/* zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &hpos); + if (Z_TYPE(key) == IS_LONG) { + zend_hash_index_del(Z_ARRVAL_PP(zvpp), Z_LVAL(key)); + } +*/ + zend_hash_del(Z_ARRVAL_P(zvp), strkey); + } + } + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zvp), name) { + if (Z_TYPE_P(name) == IS_STRING) { + phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", Z_STRLEN_P(name), Z_STRVAL_P(name)); + } + } ZEND_HASH_FOREACH_END(); + } + + zend_ini_deactivate(TSRMLS_C); + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("systemini"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + zval *ini_entry; + zend_ini_entry *original_ini; + zend_string *key; + + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) { + if (key && Z_TYPE_P(ini_entry) == IS_STRING) { + if ((original_ini = zend_hash_find_ptr(EG(ini_directives), key))) { + if (!original_ini->on_modify || original_ini->on_modify(original_ini, Z_STR_P(ini_entry), original_ini->mh_arg1, original_ini->mh_arg2, original_ini->mh_arg3, ZEND_INI_STAGE_ACTIVATE TSRMLS_CC) == SUCCESS) { + if (original_ini->modified && original_ini->orig_value != original_ini->value) { + efree(original_ini->value); + } + original_ini->value = Z_STR_P(ini_entry); + Z_ADDREF_P(ini_entry); /* don't free the string */ + } + } + } + } ZEND_HASH_FOREACH_END(); + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("userini"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + zval *ini_entry; + zend_string *key; + + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) { + if (key && Z_TYPE_P(ini_entry) == IS_STRING) { + zend_alter_ini_entry_ex(key, Z_STR_P(ini_entry), ZEND_INI_PERDIR, ZEND_INI_STAGE_HTACCESS, 1 TSRMLS_CC); + } + } ZEND_HASH_FOREACH_END(); + } + + zval_dtor(&zv); + if (free_zv) { + /* separate freeing to not dtor the symtable too, just the container zval... */ + efree(free_zv); + } + + /* Reapply raw input */ + /* ??? */ +#endif +} + +PHPDBG_COMMAND(wait) /* {{{ */ +{ +#ifdef HAVE_JSON + struct sockaddr_un local, remote; + int rlen, sr, sl; + unlink(PHPDBG_G(socket_path)); + if (PHPDBG_G(socket_server_fd) == -1) { + int len; + PHPDBG_G(socket_server_fd) = sl = socket(AF_UNIX, SOCK_STREAM, 0); + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, PHPDBG_G(socket_path)); + len = strlen(local.sun_path) + sizeof(local.sun_family); + if (bind(sl, (struct sockaddr *)&local, len) == -1) { + phpdbg_error("wait", "type=\"nosocket\" import=\"fail\"", "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting", PHPDBG_G(socket_path)); + return FAILURE; + } + + chmod(PHPDBG_G(socket_path), 0666); + + listen(sl, 2); + } else { + sl = PHPDBG_G(socket_server_fd); + } + + rlen = sizeof(remote); + sr = accept(sl, (struct sockaddr *) &remote, (socklen_t *) &rlen); + + char msglen[5]; + int recvd = 4; + + do { + recvd -= recv(sr, &(msglen[4 - recvd]), recvd, 0); + } while (recvd > 0); + + recvd = *(size_t *) msglen; + char *data = emalloc(recvd); + + do { + recvd -= recv(sr, &(data[(*(int *) msglen) - recvd]), recvd, 0); + } while (recvd > 0); + + phpdbg_webdata_decompress(data, *(int *) msglen TSRMLS_CC); + + if (PHPDBG_G(socket_fd) != -1) { + close(PHPDBG_G(socket_fd)); + } + PHPDBG_G(socket_fd) = sr; + + efree(data); + + phpdbg_notice("wait", "import=\"success\"", "Successfully imported request data, stopped before executing"); + + return SUCCESS; +#endif +} /* }}} */ |