├── Makefile ├── README.md ├── helloworld ├── index.php ├── ydb.c └── ydb.h /Makefile: -------------------------------------------------------------------------------- 1 | PHP_SRC=/usr/local/php/include/php #php源代码目录 2 | 3 | PHP_EXT_HOME=/usr/local/php/extensions #扩展部署目录 4 | 5 | INCLUDE=-I$(PHP_SRC) -I$(PHP_SRC)/main -I$(PHP_SRC)/TSRM -I$(PHP_SRC)/Zend -I$(PHP_SRC)/SAPI 6 | CC=gcc 7 | 8 | ydb.so: ydb.o 9 | $(CC) -shared -rdynamic -o ydb.so ydb.o 10 | ydb.o: ydb.c 11 | $(CC) -g -fpic $(INCLUDE) -c ydb.c 12 | 13 | clean: 14 | rm -fr *.so *.o 15 | 16 | install: ydb.so 17 | sudo cp -fp ydb.so $(PHP_EXT_HOME) 18 | 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ydb 2 | === 3 | 4 | 5 | a debug tool for php like gdb, a php zend extension. you can view the variable value of running script, and it can profile your web script, it's better than the other tools like xdebug or xhprof 6 | 7 | ydb 是像gdb一样的php调试工具,用扩展实现,可以在运行过程中查看变量值,也可以进行性能测试,而不用对源代码进行任何更改,就像xdebug和xhprof 中提供的功能,但使用更方便,ydb目前有如下几大功能: 8 | 9 | 10 | 1. 查看任意变量值 11 | 2. 查看函数执行耗时及排行 12 | 3. 更改运行时变量值,可作为一种强大的单元测试工具 13 | 4. 跨网络调试,对远程调用的模块进行分析 14 | 5. 网络请求调用性能分析 15 | 6. dump代码到页面 16 | 17 | 18 | 19 | 所有信息查看都在url中输入参数进行,而不用更改源代码,更详细的文档包括使用方法介绍见 http://blog.csdn.net/micweaver/article/details/17891163 20 | 21 | 22 | 23 | 24 | 1. view the variable value 25 | 26 | we can input the url in browser like this: 27 | 28 | "wenda.so.com/?c=IndexController&f=indexAction&v= guinness_qa" 29 | 30 | the c,v,v is your debug parameter, 31 | the ydb will dump the value of guinness_qa which's in the indexAction function of class IndexController on your webpage and 32 | stop the script,of course you can input the 'l' parameter to dump the variable value to a log file 33 | 34 | c: the class name; 35 | 36 | f: the functions name; 37 | 38 | v: the variable name,or if you do not provide this parameter,the ydb will dump all of the variable in the function 39 | 40 | 41 | 2. profile your script 42 | 43 | we can input the url in browser like this: 44 | 45 | "wenda.so.com/?c=IndexController&f=indexAction&t= 1" 46 | 47 | the parameter t stand for profiling your script,the ydb will display a time cost rank for all the function in the indexAction function of class IndexController on your webpage and 48 | stop the script desc descending order. 49 | 50 | ydb未来将提供的功能: 51 | 52 | 1. 查看变量中间值 53 | 2. 多层次函数调用性能观察 54 | 3. 查看函数调用栈 55 | 4. 进行安全编码方面的检测调试 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /helloworld: -------------------------------------------------------------------------------- 1 | print "hello,world" 2 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | add(3,4); 22 | 23 | $arr = array(4,5,6); 24 | return $fd; 25 | } 26 | 27 | function look_cost(){ 28 | $this->fun1(); 29 | $this->fun2(); 30 | $this->fun3(); 31 | usleep(300000); 32 | 33 | } 34 | 35 | function fun1(){ 36 | usleep(100000); 37 | return; 38 | } 39 | function fun2(){ 40 | usleep(200000); 41 | return; 42 | } 43 | 44 | function fun3(){ 45 | usleep(500000); 46 | return; 47 | } 48 | } 49 | 50 | 51 | $objAt = new CA(); 52 | $res = $objAt->look_value(1, 2); 53 | 54 | $res = $objAt->look_cost(); 55 | 56 | echo "should not be here"; 57 | 58 | 59 | -------------------------------------------------------------------------------- /ydb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ydb.h" 5 | 6 | void store_function_variable (); 7 | void destroy_str (char *str); 8 | 9 | static int replace_curl_fun (); 10 | static int recover_curl_fun (); 11 | static int dump_code (); 12 | 13 | void ydb_curl_init (INTERNAL_FUNCTION_PARAMETERS); 14 | void ydb_curl_setopt (INTERNAL_FUNCTION_PARAMETERS); 15 | void ydb_curl_exec (INTERNAL_FUNCTION_PARAMETERS); 16 | 17 | #define TEST_LOG_FILE "ydbtest.log" 18 | 19 | #define YDB_LOG(fmt,arg...) do {\ 20 | FILE* fh = fopen(TEST_LOG_FILE,"a");\ 21 | if(fh != NULL) {\ 22 | fprintf(fh,"[%s:%d]" fmt "\n",__FILE__,__LINE__,##arg);\ 23 | fclose(fh);\ 24 | }\ 25 | } while(0) 26 | 27 | #define INFO_USER(fmt,arg...) do {\ 28 | if(YG(depth) <= 1) {\ 29 | zend_printf(fmt,##arg);\ 30 | }\ 31 | } while(0) 32 | 33 | ZEND_DLEXPORT int ydb_zend_startup (zend_extension * extension) 34 | { 35 | 36 | #if(PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3) 37 | CG (compiler_options) |= ZEND_COMPILE_EXTENDED_INFO; 38 | #else 39 | CG (extended_info) = 1; 40 | #endif 41 | 42 | return SUCCESS; 43 | } 44 | 45 | ZEND_DLEXPORT void ydb_zend_shutdown (zend_extension * extension) 46 | { 47 | /* Do nothing. */ 48 | } 49 | 50 | static void init_curl () 51 | { 52 | 53 | YG (old_curl_url) = NULL; 54 | YG (new_curl_url)[0] = 0; 55 | 56 | YG (is_replace_new_fun) = false; 57 | YG (is_get_remote_res) = false; 58 | 59 | YG (is_send_header) = false; 60 | YG (is_net_timer) = false; 61 | 62 | YG (orig_curl_init) = NULL; 63 | YG (orig_curl_setopt) = NULL; 64 | YG (orig_curl_exec) = NULL; 65 | } 66 | 67 | static void init_dump_code () 68 | { 69 | 70 | YG (is_dump_code) = false; 71 | YG (is_get_code_info) = false; 72 | YG (file_name) = NULL; 73 | YG (line_start) = 0; 74 | YG (line_end) = 0; 75 | 76 | } 77 | 78 | ZEND_DLEXPORT void ydb_zend_activate (void) 79 | { 80 | 81 | YG (is_look_variable) = false; 82 | YG (is_timer) = false; 83 | YG (is_get_debug_params) = false; 84 | YG (is_sum_time_begin) = false; 85 | 86 | YG (dst_symbol_table) = NULL; 87 | 88 | YG (input_classname) = NULL; 89 | YG (input_funname) = NULL; 90 | YG (input_varname) = NULL; 91 | 92 | YG (input_post_classname)[0] = 0; 93 | YG (input_post_funname)[0] = 0; 94 | YG (input_post_varname)[0] = 0; 95 | 96 | YG (ydb_shouldreturn) = false; 97 | YG (ydb_cur_op_array) = NULL; 98 | YG (ydb_dst_op_array) = NULL; 99 | 100 | YG (is_post) = false; 101 | 102 | YG (parent_classname) = NULL; 103 | YG (parent_funname) = NULL; 104 | 105 | YG (usetimer) = false; 106 | 107 | YG (ydb_cur_classname) = NULL; 108 | YG (ydb_cur_funname) = NULL; 109 | YG (timer_op_array) = NULL; 110 | YG (timer_fun) = NULL; 111 | YG (ydb_varn) = NULL; 112 | 113 | YG (uselog) = false; 114 | 115 | YG (is_set_new_var) = false; 116 | 117 | YG (depth) = 1; 118 | 119 | init_curl (); 120 | init_dump_code (); 121 | 122 | // zend_printf("%s\n","ydb activate"); 123 | 124 | ALLOC_HASHTABLE (YG (ydb_varn)); 125 | zend_hash_init (YG (ydb_varn), INIT_HASH_SIZE, NULL, ZVAL_PTR_DTOR, 0); 126 | 127 | ALLOC_HASHTABLE (YG (timer_fun)); 128 | zend_hash_init (YG (timer_fun), INIT_HASH_SIZE, NULL, NULL, 0); 129 | 130 | ALLOC_HASHTABLE (YG (input_vars)); 131 | zend_hash_init (YG (input_vars), INIT_HASH_SIZE, NULL, NULL, 0); 132 | 133 | ALLOC_HASHTABLE (YG (key_count)); 134 | zend_hash_init (YG (key_count), INIT_HASH_SIZE, NULL, NULL, 0); 135 | 136 | replace_curl_fun (); 137 | 138 | } 139 | 140 | void destroy_str (char *str) 141 | { 142 | 143 | // if(str) efree(str); 144 | } 145 | 146 | static void my_print_hash (HashTable * ht, int type) 147 | { 148 | 149 | zval l_res; 150 | INIT_ZVAL (l_res); 151 | l_res.value.ht = ht; 152 | Z_TYPE (l_res) = IS_ARRAY; 153 | 154 | if (type) { 155 | zval *tmp = &l_res; 156 | php_var_dump (&tmp, 1); 157 | } 158 | else { 159 | zend_print_zval_r (&l_res, 0); 160 | } 161 | } 162 | 163 | static void my_print_zval (zval * zv) 164 | { 165 | zend_print_zval_r (zv, 0); 166 | } 167 | 168 | static int ydb_timer_compare (const void *a, const void *b) 169 | { 170 | 171 | Bucket *f = *((Bucket **) a); 172 | Bucket *s = *((Bucket **) b); 173 | 174 | int *ia = (int *) f->pData; 175 | int *ib = (int *) s->pData; 176 | 177 | if (*ia > *ib) 178 | return -1; 179 | else if (*ia < *ib) 180 | return 1; 181 | else 182 | return 0; 183 | } 184 | 185 | static int start_ydb () 186 | { 187 | 188 | return YG (is_look_variable) || YG (is_timer) || YG (is_net_timer); 189 | } 190 | 191 | static int add_ydb_header () 192 | { 193 | 194 | int status; 195 | zval function_name, retval; 196 | INIT_ZVAL (function_name); 197 | INIT_ZVAL (retval); 198 | 199 | zval param; 200 | zval *params = ¶m; 201 | INIT_PZVAL (params); 202 | 203 | ZVAL_STRING (params, CURL_RES_FLAG_HEADER, 0); 204 | ZVAL_STRING (&function_name, "header", 0); 205 | 206 | status = call_user_function (CG (function_table), NULL, &function_name, &retval, 1, ¶ms); 207 | 208 | if (status != SUCCESS) { 209 | 210 | } 211 | 212 | } 213 | 214 | static void request_end () 215 | { 216 | 217 | zend_hash_destroy (YG (ydb_varn)); 218 | zend_hash_destroy (YG (timer_fun)); 219 | zend_hash_destroy (YG (input_vars)); 220 | zend_hash_destroy (YG (key_count)); 221 | FREE_HASHTABLE (YG (ydb_varn)); 222 | FREE_HASHTABLE (YG (timer_fun)); 223 | FREE_HASHTABLE (YG (input_vars)); 224 | FREE_HASHTABLE (YG (key_count)); 225 | 226 | recover_curl_fun (); 227 | 228 | } 229 | 230 | ZEND_DLEXPORT void ydb_zend_deactivate (void) 231 | { 232 | 233 | if (!start_ydb () || YG (is_get_remote_res)) { 234 | request_end (); 235 | return; 236 | } 237 | 238 | php_end_ob_buffer (0, 0 TSRMLS_CC); 239 | 240 | int i; 241 | char *skey; 242 | ulong ikey; 243 | 244 | char cwdydb[DIR_MAX_LEN] = { 0 }; 245 | zval *message; 246 | php_stream *stream = NULL; 247 | 248 | if (YG (uselog)) { 249 | getcwd (cwdydb, sizeof (cwdydb)); 250 | strcat (cwdydb, YDB_LOG_FILE); 251 | stream = php_stream_open_wrapper (cwdydb, "a", IGNORE_URL_WIN | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL); 252 | // zend_printf("cwd:%s\n",cwdydb); 253 | ALLOC_ZVAL (message); 254 | php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC); 255 | } 256 | 257 | if (YG (is_look_variable) && YG (ydb_varn)) { //打印变量值 258 | 259 | zval **data; 260 | zend_hash_internal_pointer_reset (YG (ydb_varn)); 261 | int count = zend_hash_num_elements (YG (ydb_varn)); 262 | 263 | if (count <= 0) { 264 | if (YG (input_varname)) { 265 | INFO_USER ("variable value %s::%s::%s not exist, you may supply the wrong param", YG (input_classname), YG (input_funname), YG (input_varname)); 266 | goto EXIT; 267 | } 268 | else { 269 | INFO_USER ("variable value in %s::%s not exist,you may supply the wrong param", YG (input_classname), YG (input_funname)); 270 | goto EXIT; 271 | } 272 | } 273 | 274 | zend_printf ("=========the variable list================\n"); 275 | 276 | for (i = 0; i < count; i++) { 277 | zend_hash_get_current_data (YG (ydb_varn), (void **) &data); 278 | zend_hash_get_current_key (YG (ydb_varn), &skey, &ikey, 0); 279 | zend_hash_move_forward (YG (ydb_varn)); 280 | zend_printf ("$%s:", skey); 281 | zend_print_zval_r (*data, 0); 282 | zend_printf ("\n"); 283 | } 284 | 285 | if (YG (is_dump_code)) { 286 | dump_code (); 287 | } 288 | 289 | if (YG (uselog)) { 290 | php_ob_get_buffer (message TSRMLS_CC); 291 | if (stream != NULL) { 292 | php_stream_write (stream, Z_STRVAL_P (message), Z_STRLEN_P (message)); 293 | } 294 | } 295 | 296 | if (!YG (uselog)) { 297 | goto EXIT; 298 | } 299 | 300 | } 301 | else if (YG (is_timer) && YG (timer_fun)) { //打印耗时排行 302 | skey = 0; 303 | int *data; 304 | zend_hash_internal_pointer_reset (YG (timer_fun)); 305 | int count = zend_hash_num_elements (YG (timer_fun)); 306 | 307 | if (count <= 0) { 308 | INFO_USER ("no function time in %s::%s, you may supply the wrong param", YG (input_classname), YG (input_funname)); 309 | goto EXIT; 310 | } 311 | if (count > 0) { 312 | zend_hash_sort (YG (timer_fun), zend_qsort, ydb_timer_compare, 0 TSRMLS_CC); 313 | for (i = 0; i < count; i++) { 314 | zend_hash_get_current_data (YG (timer_fun), (void **) &data); 315 | zend_hash_get_current_key (YG (timer_fun), &skey, &ikey, 0); 316 | zend_hash_move_forward (YG (timer_fun)); 317 | zend_printf ("%s=>", skey); 318 | zend_printf ("%.3f ms", (float) (*data) / 1000); 319 | zend_printf ("\n"); 320 | 321 | } 322 | 323 | if (YG (is_dump_code)) { 324 | dump_code (); 325 | } 326 | 327 | if (YG (uselog)) { 328 | php_ob_get_buffer (message TSRMLS_CC); 329 | if (stream != NULL) { 330 | php_stream_write (stream, Z_STRVAL_P (message), Z_STRLEN_P (message)); 331 | } 332 | } 333 | } 334 | if (!YG (uselog)) { 335 | goto EXIT; 336 | } 337 | } 338 | else if (YG (is_net_timer) && YG (timer_fun)) { //打印网络请求耗时排行 339 | 340 | zend_printf ("=========the num of call times===============\n"); 341 | 342 | skey = 0; 343 | int *data; 344 | zend_hash_internal_pointer_reset (YG (key_count)); 345 | int count = zend_hash_num_elements (YG (key_count)); 346 | 347 | if (count <= 0) { 348 | zend_printf ("no net request\n"); 349 | goto EXIT; 350 | } 351 | if (count > 0) { 352 | zend_hash_sort (YG (key_count), zend_qsort, ydb_timer_compare, 0 TSRMLS_CC); 353 | for (i = 0; i < count; i++) { 354 | zend_hash_get_current_data (YG (key_count), (void **) &data); 355 | zend_hash_get_current_key (YG (key_count), &skey, &ikey, 0); 356 | zend_hash_move_forward (YG (key_count)); 357 | zend_printf ("%s:%d\n", skey, *data); 358 | } 359 | 360 | } 361 | 362 | zend_printf ("=========the cost time rank list=============\n"); 363 | 364 | zend_hash_internal_pointer_reset (YG (timer_fun)); 365 | count = zend_hash_num_elements (YG (timer_fun)); 366 | 367 | if (count <= 0) { 368 | zend_printf ("no net request\n"); 369 | goto EXIT; 370 | } 371 | if (count > 0) { 372 | zend_hash_sort (YG (timer_fun), zend_qsort, ydb_timer_compare, 0 TSRMLS_CC); 373 | for (i = 0; i < count; i++) { 374 | zend_hash_get_current_data (YG (timer_fun), (void **) &data); 375 | zend_hash_get_current_key (YG (timer_fun), &skey, &ikey, 0); 376 | zend_hash_move_forward (YG (timer_fun)); 377 | zend_printf ("%s=>", skey); 378 | zend_printf ("%.3f ms", (float) (*data) / 1000); 379 | zend_printf ("\n"); 380 | 381 | } 382 | if (YG (uselog)) { 383 | php_ob_get_buffer (message TSRMLS_CC); 384 | if (stream != NULL) { 385 | php_stream_write (stream, Z_STRVAL_P (message), Z_STRLEN_P (message)); 386 | } 387 | } 388 | } 389 | 390 | } 391 | 392 | if (YG (uselog)) { 393 | if (stream != NULL) { 394 | php_stream_close (stream); 395 | } 396 | php_end_ob_buffer (0, 0 TSRMLS_CC); 397 | } 398 | 399 | EXIT: 400 | 401 | request_end (); 402 | 403 | } 404 | 405 | static int dump_code () 406 | { 407 | 408 | if (!YG (is_dump_code) || !YG (file_name)) 409 | return -1; 410 | 411 | zend_printf ("=========the code block of %s::%s=============\n", YG (input_classname), YG (input_funname)); 412 | 413 | #define LINE_LEN 3 414 | 415 | int cur_lineno = 0; 416 | char line_buf[LINE_LEN] = { 0 }; 417 | 418 | FILE *fh = fopen (YG (file_name), "r"); 419 | 420 | if (fh == NULL) 421 | return -1; 422 | 423 | int len; 424 | while (fgets (line_buf, LINE_LEN, fh) != NULL) { 425 | 426 | if (cur_lineno + 1 >= YG (line_start) && cur_lineno + 1 <= YG (line_end)) { 427 | zend_printf ("%s", line_buf); 428 | } 429 | 430 | if (cur_lineno + 1 > YG (line_end)) 431 | break; 432 | 433 | len = strlen (line_buf); 434 | if (line_buf[len - 1] == '\n') 435 | cur_lineno++; 436 | } 437 | 438 | fclose (fh); 439 | efree (YG (file_name)); 440 | return 0; 441 | 442 | } 443 | 444 | static int parse_new_var () 445 | { 446 | 447 | char *new_vars_str = estrdup (YG (input_new_var)); 448 | char *src_str = new_vars_str; 449 | 450 | // zend_printf("new_vars_str:%s\n",new_vars_str); 451 | 452 | int len = strlen (new_vars_str); 453 | 454 | if (new_vars_str[0] == '{' && new_vars_str[len - 1] == '}') { 455 | new_vars_str[len - 1] = 0; 456 | new_vars_str++; 457 | 458 | int status; 459 | zval function_name, retval; 460 | 461 | INIT_ZVAL (function_name); 462 | INIT_ZVAL (retval); 463 | 464 | zval param1, param2; 465 | zval *params[2]; 466 | 467 | params[0] = ¶m1; 468 | INIT_PZVAL (params[0]); 469 | params[1] = ¶m2; 470 | INIT_PZVAL (params[1]); 471 | 472 | ZVAL_STRING (params[0], ":", 0); 473 | ZVAL_STRING (params[1], new_vars_str, 0); 474 | 475 | ZVAL_STRING (&function_name, "explode", 0); 476 | status = call_user_function (CG (function_table), NULL, &function_name, &retval, 2, params); 477 | 478 | if (status != SUCCESS && Z_TYPE (retval) != IS_ARRAY) { 479 | zend_printf ("call explode fail"); 480 | return -1; 481 | } 482 | 483 | // my_print_hash(Z_ARRVAL(retval), 1); 484 | 485 | HashTable *h_vars = Z_ARRVAL (retval); 486 | zval **v_item; 487 | zval v_retval; 488 | INIT_ZVAL (v_retval); 489 | 490 | ZVAL_STRING (params[0], "=", 0); 491 | 492 | zend_hash_internal_pointer_reset (h_vars); 493 | while (zend_hash_has_more_elements (h_vars) == SUCCESS) { 494 | 495 | zend_hash_get_current_data (h_vars, (void **) &v_item); 496 | // zend_printf("v_item:%s\n",Z_STRVAL_PP(v_item)); 497 | ZVAL_STRING (params[1], Z_STRVAL_PP (v_item), 0); 498 | status = call_user_function (CG (function_table), NULL, &function_name, &v_retval, 2, params); 499 | 500 | if (status != SUCCESS || Z_TYPE (v_retval) != IS_ARRAY) { 501 | zend_printf ("new variable \"%s\" parse fail\n", Z_STRVAL_PP (v_item)); 502 | zend_hash_move_forward (h_vars); 503 | continue; 504 | } 505 | if (zend_hash_num_elements (Z_ARRVAL (v_retval)) != 2) { //有些变态的数组以"="作为键,这样也解释为无效 506 | zend_printf ("new variable \"%s\" invalid\n", Z_STRVAL_PP (v_item)); 507 | zend_hash_move_forward (h_vars); 508 | continue; 509 | } 510 | 511 | zval **s_key; 512 | zval **s_val; 513 | zend_hash_index_find (Z_ARRVAL (v_retval), 0, (void **) &s_key); 514 | zend_hash_index_find (Z_ARRVAL (v_retval), 1, (void **) &s_val); 515 | 516 | zend_hash_add (YG (input_vars), Z_STRVAL_PP (s_key), strlen (Z_STRVAL_PP (s_key)) + 1, s_val, sizeof (zval *), NULL); //5.3 下 key = arr[cc] 时会崩溃,待查原因 517 | zend_hash_move_forward (h_vars); 518 | 519 | } 520 | 521 | } 522 | 523 | else { 524 | return -1; 525 | } 526 | 527 | // zend_printf("input_vars:\n"); 528 | // my_print_hash(YG(input_vars),1); 529 | efree (src_str); 530 | return 0; 531 | 532 | } 533 | 534 | static int is_num (char *s) 535 | { 536 | while (*s) { 537 | if (!isdigit (*s)) 538 | return 0; 539 | s++; 540 | } 541 | return 1; 542 | } 543 | 544 | static void get_debug_params () 545 | { 546 | 547 | zval *arrParam; 548 | zval **pvalue; 549 | 550 | char *refer; 551 | int i; 552 | HashTable *ht; 553 | 554 | char *ckey = "c", //类名 555 | *fkey = "f", //函数名 556 | *vkey = "v", //变量名 557 | *okey = "o", //标示post请求 558 | *tkey = "t", //标示进行计时操作 559 | *lkey = "l", //标示将结果打印进日志 560 | *akey = "a", //新的变量值 561 | *rkey = "r", //网络请求耗时排行 562 | *skey = "s", //打印源代码 563 | *dkey = "d"; //表示远程调用深度 564 | 565 | arrParam = PG (http_globals)[TRACK_VARS_GET]; 566 | if (zend_hash_find (Z_ARRVAL_P (arrParam), okey, strlen (okey) + 1, (void **) &pvalue) == SUCCESS) { 567 | YG (is_post) = true; 568 | } 569 | 570 | if (!YG (is_post)) { // get 参数 571 | if (zend_hash_find (Z_ARRVAL_P (arrParam), ckey, strlen (ckey) + 1, (void **) &pvalue) == SUCCESS) { 572 | YG (input_classname) = Z_STRVAL_PP (pvalue); 573 | } 574 | else { 575 | YG (input_classname) = NULL; 576 | } 577 | 578 | if (zend_hash_find (Z_ARRVAL_P (arrParam), fkey, strlen (fkey) + 1, (void **) &pvalue) == SUCCESS) { 579 | YG (input_funname) = Z_STRVAL_PP (pvalue); 580 | } 581 | else { 582 | YG (input_funname) = NULL; 583 | } 584 | 585 | if (zend_hash_find (Z_ARRVAL_P (arrParam), vkey, strlen (vkey) + 1, (void **) &pvalue) == SUCCESS) { 586 | YG (input_varname) = Z_STRVAL_PP (pvalue); 587 | } 588 | else { 589 | YG (input_varname) = NULL; 590 | } 591 | 592 | if (zend_hash_find (Z_ARRVAL_P (arrParam), akey, strlen (akey) + 1, (void **) &pvalue) == SUCCESS) { 593 | YG (input_new_var) = Z_STRVAL_PP (pvalue); 594 | parse_new_var (); 595 | } 596 | else { 597 | YG (input_new_var) = NULL; 598 | } 599 | 600 | if (zend_hash_find (Z_ARRVAL_P (arrParam), dkey, strlen (dkey) + 1, (void **) &pvalue) == SUCCESS) { 601 | 602 | char *dep = Z_STRVAL_PP (pvalue); 603 | if (dep && is_num (dep)) { 604 | YG (depth) = atoi (dep); 605 | YDB_LOG ("depth:%d", YG (depth)); 606 | } 607 | } 608 | 609 | } 610 | 611 | //if(!YG(input_classname) || !YG(input_funname)){ // 这样前一个请求可能影响后一个 612 | if (YG (is_post)) { // post 参数 613 | 614 | zend_is_auto_global ("_SERVER", sizeof ("_SERVER") - 1 TSRMLS_CC); 615 | if (PG (http_globals)[TRACK_VARS_SERVER]) { 616 | ht = Z_ARRVAL_P (PG (http_globals)[TRACK_VARS_SERVER]); 617 | if (zend_hash_find (ht, "HTTP_REFERER", sizeof ("HTTP_REFERER"), (void **) & pvalue) == SUCCESS) { 618 | 619 | refer = Z_STRVAL_PP (pvalue); 620 | // zend_printf("refer:%s\n",refer); 621 | int cur = 0; 622 | int j = 0; 623 | int k = 0; 624 | while (refer[j]) { 625 | 626 | if (cur != 6) { 627 | 628 | switch (refer[j]) { 629 | case 'c': //class name 630 | if (refer[j + 1] == '=') { 631 | j += 2; 632 | cur = 1; 633 | } 634 | break; 635 | case 'f': // function name 636 | if (refer[j + 1] == '=') { 637 | j += 2; 638 | cur = 2; 639 | } 640 | break; 641 | case 'v': // variable name 642 | if (refer[j + 1] == '=') { 643 | j += 2; 644 | cur = 3; 645 | } 646 | break; 647 | case 'l': // use log? 648 | if (refer[j + 1] == '=') { 649 | j += 2; 650 | cur = 4; 651 | YG (uselog) = true; 652 | } 653 | break; 654 | case 't': // use timer? 655 | if (refer[j + 1] == '=') { 656 | j += 2; 657 | cur = 5; 658 | YG (is_timer) = true; 659 | } 660 | break; 661 | case 'a': // new var 662 | if (refer[j + 1] == '=' && refer[j + 2] == '{') { 663 | j += 2; 664 | cur = 6; 665 | } 666 | break; 667 | case 'r': // time rank list 668 | if (refer[j + 1] == '=') { 669 | j += 2; 670 | cur = 7; 671 | YG (is_net_timer) = true; 672 | } 673 | break; 674 | case '&': 675 | case '=': 676 | cur = 0; 677 | k = 0; 678 | break; 679 | 680 | } 681 | } 682 | 683 | if (cur == 1) { 684 | YG (input_post_classname)[k++] = refer[j]; 685 | if (refer[j + 1] == '&' || refer[j + 1] == 0) { 686 | YG (input_post_classname)[k] = 0; 687 | } 688 | } 689 | else if (cur == 2) { 690 | YG (input_post_funname)[k++] = refer[j]; 691 | if (refer[j + 1] == '&' || refer[j + 1] == 0) { 692 | YG (input_post_funname)[k] = 0; 693 | } 694 | } 695 | else if (cur == 3) { 696 | YG (input_post_varname)[k++] = refer[j]; 697 | if (refer[j + 1] == '&' || refer[j + 1] == 0) { 698 | YG (input_post_varname)[k] = 0; 699 | } 700 | } 701 | else if (cur == 6) { 702 | YG (input_post_newvar)[k++] = refer[j]; 703 | if (refer[j + 1] == '&' || refer[j + 1] == 0) { 704 | YG (input_post_newvar)[k] = 0; 705 | } 706 | 707 | if (refer[j] == '}') 708 | cur = 0; 709 | 710 | } 711 | j++; 712 | } 713 | 714 | } 715 | 716 | if (YG (input_post_classname)[0]) { 717 | YG (input_classname) = YG (input_post_classname); 718 | } 719 | 720 | if (YG (input_post_funname)[0]) { 721 | YG (input_funname) = YG (input_post_funname); 722 | } 723 | 724 | if (YG (input_post_varname)[0]) { 725 | YG (input_varname) = YG (input_post_varname); 726 | } 727 | 728 | if (YG (input_post_newvar)[0]) { 729 | YG (input_new_var) = YG (input_post_newvar); 730 | parse_new_var (); 731 | } 732 | 733 | // zend_printf("pc:%s,pf:%s,pv:%s,pnv:%s,pr:%d\n",YG(input_classname), YG(input_funname),YG(input_varname),YG(input_new_var),YG(is_net_timer)); 734 | 735 | } 736 | } 737 | 738 | if (zend_hash_find (Z_ARRVAL_P (arrParam), rkey, strlen (rkey) + 1, (void **) &pvalue) == SUCCESS) { 739 | YG (is_net_timer) = true; 740 | YG (is_timer) = false; 741 | YG (is_look_variable) = false; 742 | YG (ydb_shouldreturn) = true; 743 | goto EXIT; 744 | } 745 | 746 | if (!YG (input_classname) || !YG (input_funname)) { 747 | YG (is_timer) = false; 748 | YG (is_look_variable) = false; 749 | return; 750 | } 751 | 752 | if (zend_hash_find (Z_ARRVAL_P (arrParam), skey, strlen (skey) + 1, (void **) &pvalue) == SUCCESS) { 753 | YG (is_dump_code) = true; 754 | } 755 | 756 | php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC); 757 | if (zend_hash_find (Z_ARRVAL_P (arrParam), tkey, strlen (tkey) + 1, (void **) &pvalue) == SUCCESS) { 758 | YG (is_timer) = true; 759 | 760 | } 761 | else { 762 | YG (is_look_variable) = true; 763 | } 764 | 765 | EXIT: 766 | 767 | if (start_ydb () && zend_hash_find (Z_ARRVAL_P (arrParam), lkey, strlen (lkey) + 1, (void **) &pvalue) == SUCCESS) { 768 | YG (uselog) = true; 769 | } 770 | 771 | } 772 | 773 | ZEND_DLEXPORT void ydb_zend_fcall_begin (zend_op_array * op_array) 774 | { 775 | if (!start_ydb ()) 776 | return; 777 | if (YG (ydb_shouldreturn)) 778 | return; 779 | 780 | YG (ydb_cur_op_array) = op_array; 781 | 782 | if (!YG (is_sum_time_begin)) { 783 | gettimeofday (&YG (start_sum), NULL); 784 | } 785 | 786 | if (YG (is_timer) && YG (timer_op_array) && op_array && op_array == YG (timer_op_array)) { 787 | gettimeofday (&YG (start), NULL); 788 | } 789 | } 790 | 791 | ZEND_DLEXPORT void ydb_zend_fcall_end (zend_op_array * op_array) 792 | { 793 | 794 | if (!start_ydb ()) 795 | return; 796 | if (YG (ydb_shouldreturn)) 797 | return; 798 | 799 | if (YG (is_look_variable) && YG (ydb_varn)) { 800 | int count = zend_hash_num_elements (YG (ydb_varn)); 801 | if (count > 0 && op_array && YG (ydb_dst_op_array) && op_array == YG (ydb_dst_op_array)) { 802 | if (!YG (uselog)) { 803 | zend_bailout (); 804 | } 805 | } 806 | } 807 | int time_use = 0; 808 | char timer_key[100] = { 0 }; 809 | if (YG (is_timer) && YG (timer_op_array) && op_array && op_array == YG (timer_op_array) && YG (ydb_cur_classname) && YG (ydb_cur_funname) && (strcmp (YG (ydb_cur_classname), YG (input_classname)) || strcmp (YG (ydb_cur_funname), YG (input_funname)))) { // why? 810 | 811 | int *data; 812 | gettimeofday (&YG (end), NULL); 813 | time_use = (YG (end).tv_sec - YG (start).tv_sec) * 1000000 + (YG (end).tv_usec - YG (start).tv_usec); 814 | sprintf (timer_key, "%s::%s", YG (ydb_cur_classname), YG (ydb_cur_funname)); 815 | //zend_printf("key:%s,timeuse:%d\n",timer_key,time_use); 816 | if (zend_hash_find (YG (timer_fun), timer_key, strlen (timer_key) + 1, (void **) &data) == SUCCESS) { 817 | if (*data < time_use) { 818 | zend_hash_update (YG (timer_fun), timer_key, strlen (timer_key) + 1, &time_use, sizeof (int), NULL); 819 | } 820 | 821 | } 822 | else { 823 | zend_hash_update (YG (timer_fun), timer_key, strlen (timer_key) + 1, &time_use, sizeof (int), NULL); 824 | } 825 | 826 | } 827 | 828 | if (YG (is_timer)) { 829 | 830 | if (op_array && YG (ydb_dst_op_array) && op_array == YG (ydb_dst_op_array)) { 831 | 832 | gettimeofday (&YG (end_sum), NULL); 833 | time_use = (YG (end_sum).tv_sec - YG (start_sum).tv_sec) * 1000000 + (YG (end_sum).tv_usec - YG (start_sum).tv_usec); 834 | sprintf (timer_key, "sum_cost_time: %s::%s ", YG (input_classname), YG (input_funname)); 835 | zend_hash_update (YG (timer_fun), timer_key, strlen (timer_key) + 1, &time_use, sizeof (int), NULL); 836 | if (!YG (uselog)) { 837 | zend_bailout (); 838 | } 839 | } 840 | } 841 | } 842 | 843 | void store_function_variable () 844 | { 845 | 846 | HashTable *ht; 847 | //HashTable *test1,*test2; 848 | zval **data; 849 | zval *tmp; 850 | char *skey; 851 | ulong ikey; 852 | int i; 853 | ht = YG (dst_symbol_table); 854 | //test1= &EG(symbol_table); 855 | //test2= EG(active_symbol_table); 856 | 857 | if (!ht) 858 | return; 859 | 860 | if (YG (input_varname)) { 861 | if (zend_hash_find (ht, YG (input_varname), strlen (YG (input_varname)) + 1, (void **) &data) == SUCCESS) { 862 | ALLOC_ZVAL (tmp); 863 | MAKE_COPY_ZVAL (data, tmp); 864 | if (YG (ydb_varn)) { 865 | zend_hash_update (YG (ydb_varn), YG (input_varname), strlen (YG (input_varname)) + 1, &tmp, sizeof (zval *), NULL); 866 | } 867 | } 868 | return; 869 | } 870 | else { 871 | 872 | zend_hash_internal_pointer_reset (ht); 873 | int count = zend_hash_num_elements (ht); 874 | for (i = 0; i < count; i++) { 875 | zend_hash_get_current_data (ht, (void **) &data); 876 | zend_hash_get_current_key (ht, &skey, &ikey, 0); 877 | zend_hash_move_forward (ht); 878 | if (YG (ydb_varn)) { 879 | ALLOC_ZVAL (tmp); 880 | MAKE_COPY_ZVAL (data, tmp); 881 | zend_hash_update (YG (ydb_varn), skey, strlen (skey) + 1, &tmp, sizeof (zval *), NULL); 882 | } 883 | } 884 | 885 | } 886 | 887 | } 888 | 889 | static int cur_pos = 0; 890 | // 0 1[2key3][key] 891 | static int get_next_key (char *arglist, char *key) 892 | { 893 | 894 | int status = 0; 895 | 896 | int ki = 0; 897 | 898 | while (arglist[cur_pos]) { 899 | 900 | if (arglist[cur_pos] == '[') { 901 | if (status == 0) { 902 | status = 1; 903 | } 904 | else { 905 | goto fail; 906 | } 907 | } 908 | else if (arglist[cur_pos] == ']') { 909 | 910 | if (status == 2) { 911 | status = 3; 912 | cur_pos++; 913 | break; 914 | } 915 | else { 916 | goto fail; 917 | } 918 | } 919 | else { 920 | 921 | if (status == 1 || status == 2) { 922 | if (ki >= MAX_KEY_LEN) { 923 | goto fail; 924 | } 925 | status = 2; 926 | key[ki++] = arglist[cur_pos]; 927 | } 928 | else { 929 | goto fail; 930 | } 931 | } 932 | cur_pos++; 933 | } 934 | 935 | if (status != 3) { 936 | goto fail; 937 | } 938 | 939 | key[ki] = 0; 940 | 941 | if (arglist[cur_pos] == 0) 942 | return 0; 943 | 944 | return 1; 945 | 946 | fail: 947 | return -1; 948 | 949 | } 950 | 951 | static int replace_new_variable () 952 | { 953 | 954 | HashTable *h_vars = YG (input_vars); 955 | // zend_printf("in replace_new_variable\n"); 956 | // my_print_hash(h_vars, 1); 957 | 958 | zval **z_val; 959 | char *s_var; 960 | char *skey; 961 | ulong ikey; 962 | 963 | // my_print_hash(EG(active_symbol_table), 1); 964 | 965 | int count = zend_hash_num_elements (h_vars); 966 | if (count <= 0) 967 | return -1; 968 | 969 | zend_printf ("=======the replace variable list==========\n"); 970 | zend_hash_internal_pointer_reset (h_vars); 971 | while (zend_hash_has_more_elements (h_vars) == SUCCESS) { 972 | zend_hash_get_current_data (h_vars, (void **) &z_val); 973 | zend_hash_get_current_key (h_vars, &skey, &ikey, 0); 974 | 975 | s_var = Z_STRVAL_PP (z_val); 976 | // zend_printf("key:%s,val:%s\n",skey,s_var); 977 | 978 | if (strstr (skey, "[") && strstr (skey, "]")) { 979 | 980 | cur_pos = 0; 981 | 982 | char cur_key[MAX_KEY_LEN] = { 0 }; 983 | char first_key[MAX_KEY_LEN] = { 0 }; 984 | zval **cur_zv = NULL; 985 | zval **next_zv = NULL; 986 | zval *n_var; 987 | int i = 0; 988 | while (*skey != '[') { 989 | cur_key[i++] = *skey++; 990 | } 991 | 992 | strcpy (first_key, cur_key); 993 | // zend_printf("first key:%s\n",cur_key); 994 | cur_key[i] = 0; 995 | int ret; 996 | 997 | if (zend_hash_find (EG (active_symbol_table), cur_key, strlen (cur_key) + 1, (void **) &cur_zv) == SUCCESS) { 998 | 999 | zend_printf ("$%s:\n", cur_key); 1000 | my_print_zval (*cur_zv); 1001 | zend_printf ("=>"); 1002 | 1003 | if (Z_TYPE_PP (cur_zv) != IS_ARRAY) { 1004 | 1005 | MAKE_STD_ZVAL (n_var); 1006 | array_init (n_var); 1007 | zend_hash_update (EG (active_symbol_table), cur_key, strlen (cur_key) + 1, &n_var, sizeof (zval *), (void **) &cur_zv); 1008 | } 1009 | 1010 | while (1) { 1011 | ret = get_next_key (skey, cur_key); 1012 | 1013 | // zend_printf("arr key:%s, ret:%d\n",cur_key,ret); 1014 | 1015 | if (ret == 0) { 1016 | if (Z_TYPE_PP (cur_zv) == IS_ARRAY) { // may replace the array value with string 1017 | 1018 | MAKE_STD_ZVAL (n_var); 1019 | ZVAL_STRING (n_var, s_var, 1); // all new var type is string 1020 | zend_hash_update (Z_ARRVAL_PP (cur_zv), cur_key, strlen (cur_key) + 1, &n_var, sizeof (zval *), NULL); 1021 | } 1022 | break; 1023 | } 1024 | else if (ret == 1) { 1025 | 1026 | if (zend_hash_find (Z_ARRVAL_PP (cur_zv), cur_key, strlen (cur_key) + 1, (void **) &next_zv) == FAILURE) { 1027 | 1028 | MAKE_STD_ZVAL (n_var); 1029 | array_init (n_var); 1030 | zend_hash_update (Z_ARRVAL_PP (cur_zv), cur_key, strlen (cur_key) + 1, &n_var, sizeof (zval *), (void **) &next_zv); 1031 | // fix me,need efree it 1032 | } 1033 | else if ((Z_TYPE_PP (next_zv) != IS_ARRAY)) { // may replace the string with array 1034 | 1035 | MAKE_STD_ZVAL (n_var); 1036 | array_init (n_var); 1037 | zend_hash_update (Z_ARRVAL_PP (cur_zv), cur_key, strlen (cur_key) + 1, &n_var, sizeof (zval *), (void **) &next_zv); 1038 | } 1039 | cur_zv = next_zv; 1040 | } 1041 | else { 1042 | break; 1043 | } 1044 | } 1045 | 1046 | if (zend_hash_find (EG (active_symbol_table), first_key, strlen (first_key) + 1, (void **) &cur_zv) == SUCCESS) { 1047 | my_print_zval (*cur_zv); 1048 | } 1049 | 1050 | // my_print_hash(EG(active_symbol_table), 1); 1051 | 1052 | } 1053 | else { 1054 | 1055 | zend_printf ("\"$%s\" not exist\n", cur_key); 1056 | } 1057 | 1058 | } 1059 | else { 1060 | 1061 | zval **old_val; 1062 | if (zend_hash_find (EG (active_symbol_table), skey, strlen (skey) + 1, (void **) &old_val) == SUCCESS) { //目前都是覆盖为字符串类型,未来考虑保持原类型 1063 | 1064 | zend_printf ("$%s:\n", skey); 1065 | my_print_zval (*old_val); 1066 | 1067 | zval *n_var; 1068 | MAKE_STD_ZVAL (n_var); 1069 | ZVAL_STRING (n_var, s_var, 1); // all new var type is string 1070 | ZEND_SET_SYMBOL (EG (active_symbol_table), skey, n_var); 1071 | 1072 | zend_printf ("=>"); 1073 | my_print_zval (n_var); 1074 | zend_printf ("\n"); 1075 | } 1076 | else { 1077 | zend_printf ("\"$%s\" not exist\n", skey); 1078 | } 1079 | // my_print_hash(EG(active_symbol_table), 1); 1080 | } 1081 | 1082 | zend_hash_move_forward (h_vars); 1083 | } 1084 | 1085 | return 0; 1086 | } 1087 | 1088 | static int replace_curl_fun () 1089 | { 1090 | 1091 | if (YG (is_replace_new_fun)) 1092 | return 0; 1093 | 1094 | zend_function *orig; 1095 | 1096 | zend_hash_find (EG (function_table), "curl_init", sizeof ("curl_init"), (void **) & orig); 1097 | if (!YG (orig_curl_init)) { 1098 | YG (orig_curl_init) = orig->internal_function.handler; 1099 | } 1100 | 1101 | /* if(YG(orig_curl_init) == ydb_curl_init) { // 完善这个地方 1102 | zend_printf("some big error\n"); 1103 | zend_bailout(); 1104 | } */ 1105 | 1106 | orig->internal_function.handler = ydb_curl_init; 1107 | 1108 | zend_hash_find (EG (function_table), "curl_setopt", sizeof ("curl_setopt"), (void **) & orig); 1109 | if (!YG (orig_curl_setopt)) { 1110 | YG (orig_curl_setopt) = orig->internal_function.handler; 1111 | } 1112 | orig->internal_function.handler = ydb_curl_setopt; 1113 | 1114 | zend_hash_find (EG (function_table), "curl_exec", sizeof ("curl_exec"), (void **) & orig); 1115 | if (!YG (orig_curl_exec)) { 1116 | YG (orig_curl_exec) = orig->internal_function.handler; 1117 | } 1118 | orig->internal_function.handler = ydb_curl_exec; 1119 | 1120 | YG (is_replace_new_fun) = true; 1121 | 1122 | return 0; 1123 | 1124 | } 1125 | 1126 | static int recover_curl_fun () 1127 | { 1128 | 1129 | if (!YG (is_replace_new_fun)) 1130 | return 0; 1131 | 1132 | zend_function *orig; 1133 | 1134 | zend_hash_find (EG (function_table), "curl_init", sizeof ("curl_init"), (void **) & orig); 1135 | orig->internal_function.handler = YG (orig_curl_init); 1136 | 1137 | zend_hash_find (EG (function_table), "curl_setopt", sizeof ("curl_setopt"), (void **) & orig); 1138 | orig->internal_function.handler = YG (orig_curl_setopt); 1139 | 1140 | zend_hash_find (EG (function_table), "curl_exec", sizeof ("curl_exec"), (void **) & orig); 1141 | orig->internal_function.handler = YG (orig_curl_exec); 1142 | 1143 | YG (is_replace_new_fun) = false; 1144 | 1145 | return 0; 1146 | 1147 | } 1148 | 1149 | static int replace_new_mysql_fun () 1150 | { // todo 1151 | 1152 | } 1153 | 1154 | static int is_cross_app () 1155 | { // will do is_net_timer in the future 1156 | 1157 | return YG (is_look_variable) || YG (is_timer); 1158 | 1159 | } 1160 | 1161 | static int is_need_curl_url () 1162 | { 1163 | 1164 | return YG (is_net_timer); 1165 | 1166 | } 1167 | 1168 | void ydb_curl_init (INTERNAL_FUNCTION_PARAMETERS) 1169 | { 1170 | 1171 | if (is_cross_app () || is_need_curl_url ()) { 1172 | char *url = NULL; 1173 | int url_len = 0; 1174 | if (zend_parse_parameters (ZEND_NUM_ARGS ()TSRMLS_CC, "|s", &url, &url_len) == FAILURE) { 1175 | return; 1176 | } 1177 | if (url) { 1178 | YG (old_curl_url) = estrdup (url); 1179 | //YDB_LOG("init set url:%s", YG(old_curl_url)); 1180 | } 1181 | } 1182 | 1183 | YG (orig_curl_init) (INTERNAL_FUNCTION_PARAM_PASSTHRU); 1184 | 1185 | } 1186 | 1187 | void ydb_curl_setopt (INTERNAL_FUNCTION_PARAMETERS) 1188 | { 1189 | 1190 | if (is_cross_app () || is_need_curl_url ()) { 1191 | zval *zid, **zvalue; 1192 | long options; 1193 | 1194 | if (zend_parse_parameters (ZEND_NUM_ARGS ()TSRMLS_CC, "rlZ", &zid, &options, &zvalue) == FAILURE) { 1195 | return; 1196 | } 1197 | zval curl_const; 1198 | zend_get_constant ("CURLOPT_URL", strlen ("CURLOPT_URL"), &curl_const); 1199 | if (Z_LVAL (curl_const) == options && zvalue && Z_TYPE_PP (zvalue) == IS_STRING) { 1200 | YG (old_curl_url) = estrdup (Z_STRVAL_PP (zvalue)); 1201 | //YDB_LOG("setopt set url:%s", YG(old_curl_url)); 1202 | if (is_cross_app ()) { 1203 | RETURN_TRUE; //注意返回值 1204 | } 1205 | } 1206 | YG (orig_curl_setopt) (INTERNAL_FUNCTION_PARAM_PASSTHRU); 1207 | } 1208 | else { 1209 | YG (orig_curl_setopt) (INTERNAL_FUNCTION_PARAM_PASSTHRU); 1210 | } 1211 | 1212 | } 1213 | 1214 | /* 1215 | * 1216 | * 有类似如下的返回头 1217 | HTTP/1.1 100 Continue 1218 | 1219 | HTTP/1.1 200 OK 1220 | Server: 360Server 1221 | Date: Mon, 14 Apr 2014 13:32:21 GMT 1222 | 1223 | */ 1224 | int split_curl_res (char **source_res) 1225 | { // no len? 1226 | 1227 | int res = 0; 1228 | char *source = *source_res; 1229 | if (!source || strncmp (source, CURL_RES_FIRST_LINE, strlen (CURL_RES_FIRST_LINE))) { 1230 | while (*source) { 1231 | 1232 | if (source[0] == '\r' && source[1] == '\n', source[2] == '\r' && source[3] == '\n') { 1233 | source += 4; 1234 | if (strncmp (source, CURL_RES_FIRST_LINE, strlen (CURL_RES_FIRST_LINE))) { 1235 | break; 1236 | } 1237 | else 1238 | return 1; 1239 | } 1240 | source++; 1241 | } 1242 | 1243 | } 1244 | 1245 | char res_line[MAX_HEAD_LINE_LEN] = { 0 }; 1246 | int i = 0; 1247 | while (*source) { 1248 | 1249 | if (source[0] == '\r' && source[1] == '\n') { 1250 | 1251 | res_line[i] = 0; 1252 | if (strcmp (res_line, CURL_RES_FLAG_HEADER) == 0) 1253 | res = 1; 1254 | 1255 | if (source[2] == '\r' && source[3] == '\n') { 1256 | source += 4; 1257 | *source_res = source; 1258 | return res; 1259 | } 1260 | 1261 | i = 0; 1262 | source += 2; 1263 | } 1264 | res_line[i++] = *source++; 1265 | } 1266 | 1267 | *source_res = source; 1268 | return res; 1269 | 1270 | } 1271 | 1272 | static char *get_new_url () 1273 | { 1274 | 1275 | YG (new_curl_url)[0] = 0; 1276 | 1277 | char *n_url = YG (new_curl_url); 1278 | strcat (n_url, YG (old_curl_url)); 1279 | 1280 | if (strstr (n_url, "=")) { 1281 | strcat (n_url, "&d=2"); //表示远程访问深度,后续升级 1282 | } 1283 | else { 1284 | strcat (n_url, "?d=2"); 1285 | } 1286 | 1287 | if (YG (input_classname)) { 1288 | strcat (n_url, "&c="); 1289 | strcat (n_url, YG (input_classname)); 1290 | } 1291 | 1292 | if (YG (input_funname)) { 1293 | strcat (n_url, "&f="); 1294 | strcat (n_url, YG (input_funname)); 1295 | } 1296 | 1297 | if (YG (input_varname)) { 1298 | strcat (n_url, "&v="); 1299 | strcat (n_url, YG (input_varname)); 1300 | } 1301 | 1302 | if (YG (input_new_var)) { 1303 | strcat (n_url, "&a="); 1304 | strcat (n_url, YG (input_new_var)); 1305 | } 1306 | 1307 | if (YG (is_timer)) { 1308 | strcat (n_url, "&t=1"); 1309 | } 1310 | 1311 | if (YG (uselog)) { 1312 | strcat (n_url, "&l=1"); 1313 | } 1314 | 1315 | if (YG (is_dump_code)) { 1316 | strcat (n_url, "&s=1"); 1317 | } 1318 | 1319 | YDB_LOG ("old_url:%s,new_url:%s\n", YG (old_curl_url), YG (new_curl_url)); 1320 | 1321 | efree (YG (old_curl_url)); 1322 | 1323 | return n_url; 1324 | 1325 | } 1326 | 1327 | void ydb_curl_exec (INTERNAL_FUNCTION_PARAMETERS) 1328 | { 1329 | 1330 | zval function_name, retval; 1331 | INIT_ZVAL (function_name); 1332 | INIT_ZVAL (retval); 1333 | zval *zid; 1334 | 1335 | int status; 1336 | 1337 | if (zend_parse_parameters (ZEND_NUM_ARGS ()TSRMLS_CC, "r", &zid) == FAILURE) { 1338 | return; 1339 | } 1340 | 1341 | recover_curl_fun (); 1342 | 1343 | if (is_cross_app ()) { 1344 | 1345 | get_new_url (); 1346 | 1347 | char *n_url = YG (new_curl_url); 1348 | 1349 | zval param2, param3; 1350 | zval *params[3]; 1351 | 1352 | params[0] = zid; 1353 | 1354 | params[1] = ¶m2; 1355 | INIT_PZVAL (params[1]); 1356 | 1357 | params[2] = ¶m3; 1358 | INIT_PZVAL (params[2]); 1359 | 1360 | zval curl_const; 1361 | zend_get_constant ("CURLOPT_URL", strlen ("CURLOPT_URL"), &curl_const); 1362 | 1363 | ZVAL_LONG (params[1], Z_LVAL (curl_const)); 1364 | ZVAL_STRING (params[2], n_url, 0); 1365 | 1366 | ZVAL_STRING (&function_name, "curl_setopt", 0); 1367 | status = call_user_function (CG (function_table), NULL, &function_name, &retval, 3, params); 1368 | 1369 | if (status != SUCCESS) { 1370 | 1371 | } 1372 | 1373 | zend_get_constant ("CURLOPT_HEADER", strlen ("CURLOPT_HEADER"), &curl_const); 1374 | ZVAL_LONG (params[1], Z_LVAL (curl_const)); 1375 | ZVAL_BOOL (params[2], 1); 1376 | 1377 | status = call_user_function (CG (function_table), NULL, &function_name, &retval, 3, params); 1378 | 1379 | if (status != SUCCESS) { 1380 | 1381 | } 1382 | 1383 | } 1384 | 1385 | if (YG (is_net_timer)) { 1386 | gettimeofday (&YG (start), NULL); 1387 | } 1388 | 1389 | ZVAL_STRING (&function_name, "curl_exec", 0); // 调用方需要设置CURLOPT_RETURNTRANSFER,这里需要加上判断有没有设置 fixme 1390 | status = call_user_function (CG (function_table), NULL, &function_name, &retval, 1, &zid); 1391 | 1392 | YDB_LOG ("status:%d", status); 1393 | if (status != SUCCESS) { 1394 | YDB_LOG ("status:%d,curl_exec fail", status); 1395 | } 1396 | 1397 | if (YG (is_net_timer)) { 1398 | int time_use = 0; 1399 | int *data; 1400 | gettimeofday (&YG (end), NULL); 1401 | time_use = (YG (end).tv_sec - YG (start).tv_sec) * 1000000 + (YG (end).tv_usec - YG (start).tv_usec); 1402 | 1403 | char *key = YG (old_curl_url); 1404 | // zend_printf("key:%s,timeuse:%d\n",key,time_use); 1405 | 1406 | int *kcnt; 1407 | 1408 | char new_key[MAX_URL_LEN + 10] = { 0 }; 1409 | strcpy (new_key, key); 1410 | 1411 | int cnt = 1; 1412 | if (zend_hash_find (YG (key_count), key, strlen (key) + 1, (void **) &kcnt) == SUCCESS) { 1413 | cnt = *kcnt + 1; 1414 | } 1415 | 1416 | sprintf (new_key, "%s_%d", key, cnt); 1417 | zend_hash_update (YG (key_count), key, strlen (key) + 1, &cnt, sizeof (int), NULL); 1418 | 1419 | if (zend_hash_find (YG (timer_fun), new_key, strlen (new_key) + 1, (void **) &data) == SUCCESS) { 1420 | if (*data < time_use) { 1421 | zend_hash_update (YG (timer_fun), new_key, strlen (new_key) + 1, &time_use, sizeof (int), NULL); 1422 | } 1423 | 1424 | } 1425 | else { 1426 | zend_hash_update (YG (timer_fun), new_key, strlen (new_key) + 1, &time_use, sizeof (int), NULL); 1427 | } 1428 | 1429 | } 1430 | 1431 | if (!Z_STRVAL (retval)) { //结果可能为空 1432 | YDB_LOG ("res is empty"); 1433 | replace_curl_fun (); 1434 | RETURN_STRING ("", 1); 1435 | } 1436 | 1437 | if (is_cross_app ()) { 1438 | YG (curl_res) = Z_STRVAL (retval); 1439 | char *src_res = YG (curl_res); 1440 | // zend_printf("\nresstr:\n%s =========end\n",Z_STRVAL(retval)); 1441 | //YDB_LOG("full res===:\n%s", src_res); 1442 | 1443 | if (split_curl_res (&src_res)) { 1444 | zend_printf ("%s", src_res); 1445 | YG (is_get_remote_res) = true; 1446 | zend_bailout (); //need do some efree work 1447 | } 1448 | else { 1449 | //YDB_LOG("res===:\n%s", src_res); 1450 | replace_curl_fun (); 1451 | RETURN_STRING (src_res, 1); 1452 | } 1453 | 1454 | } 1455 | else { 1456 | // zend_printf("resstr:%s\n",Z_STRVAL(retval)); 1457 | replace_curl_fun (); 1458 | RETURN_STRING (Z_STRVAL (retval), 1); 1459 | } 1460 | 1461 | } 1462 | 1463 | ZEND_DLEXPORT void ydb_statement_call (zend_op_array * op_array) 1464 | { 1465 | 1466 | if (!YG (is_get_debug_params)) { 1467 | get_debug_params (); 1468 | YG (is_get_debug_params) = true; 1469 | } 1470 | 1471 | if (!start_ydb ()) 1472 | return; 1473 | if (YG (ydb_shouldreturn)) 1474 | return; 1475 | 1476 | zend_class_entry *scope; 1477 | scope = EG (scope); 1478 | if (scope) { 1479 | YG (ydb_cur_classname) = scope->name; 1480 | } 1481 | else { 1482 | YG (ydb_cur_classname) = NULL; 1483 | } 1484 | 1485 | zend_op_array *op; 1486 | 1487 | op = EG (active_op_array); 1488 | if (op && op->function_name) { 1489 | YG (ydb_cur_funname) = op->function_name; 1490 | } 1491 | else { 1492 | YG (ydb_cur_funname) = NULL; 1493 | } 1494 | 1495 | // zend_printf("sclass:%s\n",class_name); 1496 | // zend_printf("sfunc:%s\n",fun_name); 1497 | 1498 | if (!YG (ydb_cur_classname) || !YG (ydb_cur_funname)) { 1499 | return; 1500 | } 1501 | 1502 | if (strcmp (YG (input_classname), YG (ydb_cur_classname))) { 1503 | return; 1504 | } 1505 | if (strcmp (YG (input_funname), YG (ydb_cur_funname))) { 1506 | return; 1507 | } 1508 | 1509 | if (YG (is_dump_code) && !YG (is_get_code_info) && op->filename) { 1510 | 1511 | YG (file_name) = estrdup (op->filename); 1512 | YG (line_start) = op->line_start; 1513 | YG (line_end) = op->line_end; 1514 | YG (is_get_code_info) = true; 1515 | } 1516 | 1517 | if (!YG (is_send_header) && !YG (uselog)) { 1518 | add_ydb_header (); 1519 | YG (is_send_header) = true; 1520 | } 1521 | 1522 | if (!YG (ydb_dst_op_array)) 1523 | YG (ydb_dst_op_array) = YG (ydb_cur_op_array); 1524 | 1525 | if (YG (is_timer)) { 1526 | if (op_array && !YG (timer_op_array)) 1527 | YG (timer_op_array) = op_array; 1528 | YG (is_sum_time_begin) = true; 1529 | } 1530 | 1531 | if (YG (is_timer)) 1532 | return; 1533 | 1534 | if (!EG (active_symbol_table)) { 1535 | zend_rebuild_symbol_table (TSRMLS_C); 1536 | } 1537 | 1538 | if (EG (active_symbol_table)) { 1539 | YG (dst_symbol_table) = EG (active_symbol_table); 1540 | } 1541 | 1542 | store_function_variable (); 1543 | if (EG (active_symbol_table) && !YG (is_set_new_var)) { //只在函数入口处进行一次变量覆盖 1544 | replace_new_variable (); 1545 | YG (is_set_new_var) = true; 1546 | } 1547 | 1548 | } 1549 | 1550 | ZEND_DLEXPORT void ydb_oparray_init (zend_op_array * op_array) 1551 | { 1552 | 1553 | } 1554 | 1555 | #ifndef ZEND_EXT_API 1556 | #define ZEND_EXT_API ZEND_DLEXPORT 1557 | #endif 1558 | 1559 | ZEND_EXTENSION (); 1560 | 1561 | ZEND_DLEXPORT zend_extension zend_extension_entry = { 1562 | YDB_NAME, 1563 | YDB_VERSION, 1564 | YDB_AUTHOR, 1565 | YDB_URL_FAQ, 1566 | YDB_COPYRIGHT_SHORT, 1567 | ydb_zend_startup, 1568 | ydb_zend_shutdown, 1569 | ydb_zend_activate, /* activate_func_t */ 1570 | ydb_zend_deactivate, /* deactivate_func_t */ 1571 | NULL, /* message_handler_func_t */ 1572 | NULL, /* op_array_handler_func_t */// we may use it 1573 | ydb_statement_call, /* statement_handler_func_t */ 1574 | ydb_zend_fcall_begin, /* fcall_begin_handler_func_t */ 1575 | ydb_zend_fcall_end, /* fcall_end_handler_func_t */ 1576 | ydb_oparray_init, /* op_array_ctor_func_t */ 1577 | NULL, /* op_array_dtor_func_t */ 1578 | STANDARD_ZEND_EXTENSION_PROPERTIES 1579 | }; 1580 | -------------------------------------------------------------------------------- /ydb.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micweaver/ydb/0808e7498156094a43f69cebfb1bdb610ac4e434/ydb.h --------------------------------------------------------------------------------