1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> | 16 | Stig S�ther Bakken <ssb@php.net> | 17 | David Sklar <sklar@student.net> | 18 +----------------------------------------------------------------------+ 19 */ 20/* $Id$ */ 21 22#include "php_apache_http.h" 23 24#if defined(PHP_WIN32) || defined(NETWARE) 25#include "zend.h" 26#include "ap_compat.h" 27#endif 28 29#ifdef ZTS 30int php_apache_info_id; 31#else 32php_apache_info_struct php_apache_info; 33#endif 34 35#define SECTION(name) PUTS("<h2>" name "</h2>\n") 36 37#ifndef PHP_WIN32 38extern module *top_module; 39extern module **ap_loaded_modules; 40#else 41extern __declspec(dllimport) module *top_module; 42extern __declspec(dllimport) module **ap_loaded_modules; 43#endif 44 45PHP_FUNCTION(virtual); 46PHP_FUNCTION(apache_request_headers); 47PHP_FUNCTION(apache_response_headers); 48PHP_FUNCTION(apachelog); 49PHP_FUNCTION(apache_note); 50PHP_FUNCTION(apache_lookup_uri); 51PHP_FUNCTION(apache_child_terminate); 52PHP_FUNCTION(apache_setenv); 53PHP_FUNCTION(apache_get_version); 54PHP_FUNCTION(apache_get_modules); 55PHP_FUNCTION(apache_reset_timeout); 56 57PHP_MINFO_FUNCTION(apache); 58 59ZEND_BEGIN_ARG_INFO(arginfo_apache_child_terminate, 0) 60ZEND_END_ARG_INFO() 61 62ZEND_BEGIN_ARG_INFO_EX(arginfo_apache_note, 0, 0, 1) 63 ZEND_ARG_INFO(0, note_name) 64 ZEND_ARG_INFO(0, note_value) 65ZEND_END_ARG_INFO() 66 67ZEND_BEGIN_ARG_INFO_EX(arginfo_apache_virtual, 0, 0, 1) 68 ZEND_ARG_INFO(0, filename) 69ZEND_END_ARG_INFO() 70 71ZEND_BEGIN_ARG_INFO(arginfo_apache_request_headers, 0) 72ZEND_END_ARG_INFO() 73 74ZEND_BEGIN_ARG_INFO(arginfo_apache_response_headers, 0) 75ZEND_END_ARG_INFO() 76 77ZEND_BEGIN_ARG_INFO_EX(arginfo_apache_setenv, 0, 0, 2) 78 ZEND_ARG_INFO(0, variable) 79 ZEND_ARG_INFO(0, value) 80 ZEND_ARG_INFO(0, walk_to_top) 81ZEND_END_ARG_INFO() 82 83ZEND_BEGIN_ARG_INFO_EX(arginfo_apache_lookup_uri, 0, 0, 1) 84 ZEND_ARG_INFO(0, uri) 85ZEND_END_ARG_INFO() 86 87ZEND_BEGIN_ARG_INFO(arginfo_apache_get_version, 0) 88ZEND_END_ARG_INFO() 89 90ZEND_BEGIN_ARG_INFO(arginfo_apache_get_modules, 0) 91ZEND_END_ARG_INFO() 92 93ZEND_BEGIN_ARG_INFO(arginfo_apache_reset_timeout, 0) 94ZEND_END_ARG_INFO() 95 96 97 98const zend_function_entry apache_functions[] = { 99 PHP_FE(virtual, arginfo_apache_virtual) 100 PHP_FE(apache_request_headers, arginfo_apache_request_headers) 101 PHP_FE(apache_note, arginfo_apache_note) 102 PHP_FE(apache_lookup_uri, arginfo_apache_lookup_uri) 103 PHP_FE(apache_child_terminate, arginfo_apache_child_terminate) 104 PHP_FE(apache_setenv, arginfo_apache_setenv) 105 PHP_FE(apache_response_headers, arginfo_apache_response_headers) 106 PHP_FE(apache_get_version, arginfo_apache_get_version) 107 PHP_FE(apache_get_modules, arginfo_apache_get_modules) 108 PHP_FE(apache_reset_timeout, arginfo_apache_reset_timeout) 109 PHP_FALIAS(getallheaders, apache_request_headers, arginfo_apache_request_headers) 110 {NULL, NULL, NULL} 111}; 112 113 114PHP_INI_BEGIN() 115 STD_PHP_INI_ENTRY("xbithack", "0", PHP_INI_ALL, OnUpdateLong, xbithack, php_apache_info_struct, php_apache_info) 116 STD_PHP_INI_ENTRY("engine", "1", PHP_INI_ALL, OnUpdateLong, engine, php_apache_info_struct, php_apache_info) 117 STD_PHP_INI_ENTRY("last_modified", "0", PHP_INI_ALL, OnUpdateLong, last_modified, php_apache_info_struct, php_apache_info) 118 STD_PHP_INI_ENTRY("child_terminate", "0", PHP_INI_ALL, OnUpdateLong, terminate_child, php_apache_info_struct, php_apache_info) 119PHP_INI_END() 120 121 122 123static void php_apache_globals_ctor(php_apache_info_struct *apache_globals TSRMLS_DC) 124{ 125 apache_globals->in_request = 0; 126} 127 128 129static PHP_MINIT_FUNCTION(apache) 130{ 131#ifdef ZTS 132 ts_allocate_id(&php_apache_info_id, sizeof(php_apache_info_struct), (ts_allocate_ctor) php_apache_globals_ctor, NULL); 133#else 134 php_apache_globals_ctor(&php_apache_info TSRMLS_CC); 135#endif 136 REGISTER_INI_ENTRIES(); 137 return SUCCESS; 138} 139 140 141static PHP_MSHUTDOWN_FUNCTION(apache) 142{ 143 UNREGISTER_INI_ENTRIES(); 144 return SUCCESS; 145} 146 147zend_module_entry apache_module_entry = { 148 STANDARD_MODULE_HEADER, 149 "apache", 150 apache_functions, 151 PHP_MINIT(apache), 152 PHP_MSHUTDOWN(apache), 153 NULL, 154 NULL, 155 PHP_MINFO(apache), 156 NO_VERSION_YET, 157 STANDARD_MODULE_PROPERTIES 158}; 159 160/* {{{ PHP_MINFO_FUNCTION 161 */ 162PHP_MINFO_FUNCTION(apache) 163{ 164 char *apv = (char *) ap_get_server_version(); 165 module *modp = NULL; 166 char output_buf[128]; 167#if !defined(WIN32) && !defined(WINNT) 168 char name[64]; 169 char modulenames[1024]; 170 char *p; 171#endif 172 server_rec *serv; 173 extern char server_root[MAX_STRING_LEN]; 174 extern uid_t user_id; 175 extern char *user_name; 176 extern gid_t group_id; 177 extern int max_requests_per_child; 178 179 serv = ((request_rec *) SG(server_context))->server; 180 181 182 php_info_print_table_start(); 183 184#ifdef PHP_WIN32 185 php_info_print_table_row(1, "Apache for Windows 95/NT"); 186 php_info_print_table_end(); 187 php_info_print_table_start(); 188#elif defined(NETWARE) 189 php_info_print_table_row(1, "Apache for NetWare"); 190 php_info_print_table_end(); 191 php_info_print_table_start(); 192#else 193 php_info_print_table_row(2, "APACHE_INCLUDE", PHP_APACHE_INCLUDE); 194 php_info_print_table_row(2, "APACHE_TARGET", PHP_APACHE_TARGET); 195#endif 196 197 if (apv && *apv) { 198 php_info_print_table_row(2, "Apache Version", apv); 199 } 200 201#ifdef APACHE_RELEASE 202 snprintf(output_buf, sizeof(output_buf), "%d", APACHE_RELEASE); 203 php_info_print_table_row(2, "Apache Release", output_buf); 204#endif 205 snprintf(output_buf, sizeof(output_buf), "%d", MODULE_MAGIC_NUMBER); 206 php_info_print_table_row(2, "Apache API Version", output_buf); 207 snprintf(output_buf, sizeof(output_buf), "%s:%u", serv->server_hostname, serv->port); 208 php_info_print_table_row(2, "Hostname:Port", output_buf); 209#if !defined(WIN32) && !defined(WINNT) 210 snprintf(output_buf, sizeof(output_buf), "%s(%d)/%d", user_name, (int)user_id, (int)group_id); 211 php_info_print_table_row(2, "User/Group", output_buf); 212 snprintf(output_buf, sizeof(output_buf), "Per Child: %d - Keep Alive: %s - Max Per Connection: %d", max_requests_per_child, serv->keep_alive ? "on":"off", serv->keep_alive_max); 213 php_info_print_table_row(2, "Max Requests", output_buf); 214#endif 215 snprintf(output_buf, sizeof(output_buf), "Connection: %d - Keep-Alive: %d", serv->timeout, serv->keep_alive_timeout); 216 php_info_print_table_row(2, "Timeouts", output_buf); 217#if !defined(WIN32) && !defined(WINNT) 218/* 219 This block seems to be working on NetWare; But it seems to be showing 220 all modules instead of just the loaded ones 221*/ 222 php_info_print_table_row(2, "Server Root", server_root); 223 224 strcpy(modulenames, ""); 225 for(modp = top_module; modp; modp = modp->next) { 226 strlcpy(name, modp->name, sizeof(name)); 227 if ((p = strrchr(name, '.'))) { 228 *p='\0'; /* Cut off ugly .c extensions on module names */ 229 } 230 strlcat(modulenames, name, sizeof(modulenames)); 231 if (modp->next) { 232 strlcat(modulenames, ", ", sizeof(modulenames)); 233 } 234 } 235 php_info_print_table_row(2, "Loaded Modules", modulenames); 236#endif 237 238 php_info_print_table_end(); 239 240 DISPLAY_INI_ENTRIES(); 241 242 { 243 register int i; 244 array_header *arr; 245 table_entry *elts; 246 request_rec *r; 247 248 r = ((request_rec *) SG(server_context)); 249 arr = table_elts(r->subprocess_env); 250 elts = (table_entry *)arr->elts; 251 252 SECTION("Apache Environment"); 253 php_info_print_table_start(); 254 php_info_print_table_header(2, "Variable", "Value"); 255 for (i=0; i < arr->nelts; i++) { 256 php_info_print_table_row(2, elts[i].key, elts[i].val); 257 } 258 php_info_print_table_end(); 259 } 260 261 { 262 array_header *env_arr; 263 table_entry *env; 264 int i; 265 request_rec *r; 266 267 r = ((request_rec *) SG(server_context)); 268 SECTION("HTTP Headers Information"); 269 php_info_print_table_start(); 270 php_info_print_table_colspan_header(2, "HTTP Request Headers"); 271 php_info_print_table_row(2, "HTTP Request", r->the_request); 272 env_arr = table_elts(r->headers_in); 273 env = (table_entry *)env_arr->elts; 274 for (i = 0; i < env_arr->nelts; ++i) { 275 if (env[i].key && (!PG(safe_mode) || (PG(safe_mode) && strncasecmp(env[i].key, "authorization", 13)))) { 276 php_info_print_table_row(2, env[i].key, env[i].val); 277 } 278 } 279 php_info_print_table_colspan_header(2, "HTTP Response Headers"); 280 env_arr = table_elts(r->headers_out); 281 env = (table_entry *)env_arr->elts; 282 for(i = 0; i < env_arr->nelts; ++i) { 283 if (env[i].key) { 284 php_info_print_table_row(2, env[i].key, env[i].val); 285 } 286 } 287 php_info_print_table_end(); 288 } 289} 290/* }}} */ 291 292/* {{{ proto bool apache_child_terminate(void) 293 Terminate apache process after this request */ 294PHP_FUNCTION(apache_child_terminate) 295{ 296#ifndef MULTITHREAD 297 if (AP(terminate_child)) { 298 ap_child_terminate( ((request_rec *)SG(server_context)) ); 299 RETURN_TRUE; 300 } else { /* tell them to get lost! */ 301 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This function is disabled"); 302 RETURN_FALSE; 303 } 304#else 305 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This function is not supported in this build"); 306 RETURN_FALSE; 307#endif 308} 309/* }}} */ 310 311/* {{{ proto string apache_note(string note_name [, string note_value]) 312 Get and set Apache request notes */ 313PHP_FUNCTION(apache_note) 314{ 315 char *note_name, *note_val = NULL; 316 int note_name_len, note_val_len; 317 char *old_val; 318 319 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", ¬e_name, ¬e_name_len, ¬e_val, ¬e_val_len) == FAILURE) { 320 return; 321 } 322 323 old_val = (char *) table_get(((request_rec *)SG(server_context))->notes, note_name); 324 325 if (note_val) { 326 table_set(((request_rec *)SG(server_context))->notes, note_name, note_val); 327 } 328 329 if (old_val) { 330 RETURN_STRING(old_val, 1); 331 } 332 333 RETURN_FALSE; 334} 335/* }}} */ 336 337/* {{{ proto bool virtual(string filename) 338 Perform an Apache sub-request */ 339/* This function is equivalent to <!--#include virtual...--> 340 * in mod_include. It does an Apache sub-request. It is useful 341 * for including CGI scripts or .shtml files, or anything else 342 * that you'd parse through Apache (for .phtml files, you'd probably 343 * want to use <?Include>. This only works when PHP is compiled 344 * as an Apache module, since it uses the Apache API for doing 345 * sub requests. 346 */ 347PHP_FUNCTION(virtual) 348{ 349 char *filename; 350 int filename_len; 351 request_rec *rr = NULL; 352 353 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { 354 return; 355 } 356 357 if (!(rr = sub_req_lookup_uri (filename, ((request_rec *) SG(server_context))))) { 358 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include '%s' - URI lookup failed", filename); 359 if (rr) 360 destroy_sub_req (rr); 361 RETURN_FALSE; 362 } 363 364 if (rr->status != 200) { 365 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include '%s' - error finding URI", filename); 366 if (rr) 367 destroy_sub_req (rr); 368 RETURN_FALSE; 369 } 370 371 php_end_ob_buffers(1 TSRMLS_CC); 372 php_header(TSRMLS_C); 373 374 if (run_sub_req(rr)) { 375 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include '%s' - request execution failed", filename); 376 if (rr) 377 destroy_sub_req (rr); 378 RETURN_FALSE; 379 } 380 381 if (rr) 382 destroy_sub_req (rr); 383 384 RETURN_TRUE; 385} 386/* }}} */ 387 388/* {{{ proto array getallheaders(void) 389 Alias for apache_request_headers() */ 390/* }}} */ 391 392/* {{{ proto array apache_request_headers(void) 393 Fetch all HTTP request headers */ 394PHP_FUNCTION(apache_request_headers) 395{ 396 array_header *env_arr; 397 table_entry *tenv; 398 int i; 399 400 array_init(return_value); 401 env_arr = table_elts(((request_rec *) SG(server_context))->headers_in); 402 tenv = (table_entry *)env_arr->elts; 403 for (i = 0; i < env_arr->nelts; ++i) { 404 if (!tenv[i].key || 405 (PG(safe_mode) && 406 !strncasecmp(tenv[i].key, "authorization", 13))) { 407 continue; 408 } 409 if (add_assoc_string(return_value, tenv[i].key, (tenv[i].val==NULL) ? "" : tenv[i].val, 1)==FAILURE) { 410 RETURN_FALSE; 411 } 412 } 413} 414/* }}} */ 415 416/* {{{ proto array apache_response_headers(void) 417 Fetch all HTTP response headers */ 418PHP_FUNCTION(apache_response_headers) 419{ 420 array_header *env_arr; 421 table_entry *tenv; 422 int i; 423 424 array_init(return_value); 425 env_arr = table_elts(((request_rec *) SG(server_context))->headers_out); 426 tenv = (table_entry *)env_arr->elts; 427 for (i = 0; i < env_arr->nelts; ++i) { 428 if (!tenv[i].key) continue; 429 if (add_assoc_string(return_value, tenv[i].key, (tenv[i].val==NULL) ? "" : tenv[i].val, 1)==FAILURE) { 430 RETURN_FALSE; 431 } 432 } 433} 434/* }}} */ 435 436/* {{{ proto bool apache_setenv(string variable, string value [, bool walk_to_top]) 437 Set an Apache subprocess_env variable */ 438PHP_FUNCTION(apache_setenv) 439{ 440 int var_len, val_len; 441 zend_bool top=0; 442 char *var = NULL, *val = NULL; 443 request_rec *r = (request_rec *) SG(server_context); 444 445 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &var, &var_len, &val, &val_len, &top) == FAILURE) { 446 return; 447 } 448 449 while(top) { 450 if(r->prev) r = r->prev; 451 else break; 452 } 453 454 ap_table_setn(r->subprocess_env, ap_pstrndup(r->pool, var, var_len), ap_pstrndup(r->pool, val, val_len)); 455 RETURN_TRUE; 456} 457/* }}} */ 458 459/* {{{ proto object apache_lookup_uri(string URI) 460 Perform a partial request of the given URI to obtain information about it */ 461PHP_FUNCTION(apache_lookup_uri) 462{ 463 char *filename; 464 int filename_len; 465 request_rec *rr=NULL; 466 467 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { 468 return; 469 } 470 471 if (!(rr = sub_req_lookup_uri(filename, ((request_rec *) SG(server_context))))) { 472 php_error_docref(NULL TSRMLS_CC, E_WARNING, "URI lookup failed '%s'", filename); 473 RETURN_FALSE; 474 } 475 476 object_init(return_value); 477 add_property_long(return_value,"status", rr->status); 478 479 if (rr->the_request) { 480 add_property_string(return_value,"the_request", rr->the_request, 1); 481 } 482 if (rr->status_line) { 483 add_property_string(return_value,"status_line", (char *)rr->status_line, 1); 484 } 485 if (rr->method) { 486 add_property_string(return_value,"method", (char *)rr->method, 1); 487 } 488 if (rr->content_type) { 489 add_property_string(return_value,"content_type", (char *)rr->content_type, 1); 490 } 491 if (rr->handler) { 492 add_property_string(return_value,"handler", (char *)rr->handler, 1); 493 } 494 if (rr->uri) { 495 add_property_string(return_value,"uri", rr->uri, 1); 496 } 497 if (rr->filename) { 498 add_property_string(return_value,"filename", rr->filename, 1); 499 } 500 if (rr->path_info) { 501 add_property_string(return_value,"path_info", rr->path_info, 1); 502 } 503 if (rr->args) { 504 add_property_string(return_value,"args", rr->args, 1); 505 } 506 if (rr->boundary) { 507 add_property_string(return_value,"boundary", rr->boundary, 1); 508 } 509 510 add_property_long(return_value,"no_cache", rr->no_cache); 511 add_property_long(return_value,"no_local_copy", rr->no_local_copy); 512 add_property_long(return_value,"allowed", rr->allowed); 513 add_property_long(return_value,"sent_bodyct", rr->sent_bodyct); 514 add_property_long(return_value,"bytes_sent", rr->bytes_sent); 515 add_property_long(return_value,"byterange", rr->byterange); 516 add_property_long(return_value,"clength", rr->clength); 517 518#if MODULE_MAGIC_NUMBER >= 19980324 519 if (rr->unparsed_uri) { 520 add_property_string(return_value,"unparsed_uri", rr->unparsed_uri, 1); 521 } 522 if(rr->mtime) { 523 add_property_long(return_value,"mtime", rr->mtime); 524 } 525#endif 526 if(rr->request_time) { 527 add_property_long(return_value,"request_time", rr->request_time); 528 } 529 530 destroy_sub_req(rr); 531} 532/* }}} */ 533 534 535#if 0 536This function is most likely a bad idea. Just playing with it for now. 537 538PHP_FUNCTION(apache_exec_uri) 539{ 540 char *filename; 541 int filename_len; 542 request_rec *rr=NULL; 543 TSRMLS_FETCH(); 544 545 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { 546 return; 547 } 548 549 if(!(rr = ap_sub_req_lookup_uri(filename, ((request_rec *) SG(server_context))))) { 550 php_error_docref(NULL TSRMLS_CC, E_WARNING, "URI lookup failed", filename); 551 RETURN_FALSE; 552 } 553 554 RETVAL_LONG(ap_run_sub_req(rr)); 555 ap_destroy_sub_req(rr); 556} 557#endif 558 559/* {{{ proto string apache_get_version(void) 560 Fetch Apache version */ 561PHP_FUNCTION(apache_get_version) 562{ 563 char *apv = (char *) ap_get_server_version(); 564 565 if (apv && *apv) { 566 RETURN_STRING(apv, 1); 567 } 568 569 RETURN_FALSE; 570} 571/* }}} */ 572 573/* {{{ proto array apache_get_modules(void) 574 Get a list of loaded Apache modules */ 575PHP_FUNCTION(apache_get_modules) 576{ 577 int n; 578 char *p; 579 580 array_init(return_value); 581 582 for (n = 0; ap_loaded_modules[n]; ++n) { 583 char *s = (char *) ap_loaded_modules[n]->name; 584 if ((p = strchr(s, '.'))) { 585 add_next_index_stringl(return_value, s, (p - s), 1); 586 } else { 587 add_next_index_string(return_value, s, 1); 588 } 589 } 590} 591/* }}} */ 592 593/* {{{ proto bool apache_reset_timeout(void) 594 Reset the Apache write timer */ 595PHP_FUNCTION(apache_reset_timeout) 596{ 597 if (PG(safe_mode)) { 598 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot reset the Apache timeout in safe mode"); 599 RETURN_FALSE; 600 } 601 602 ap_reset_timeout((request_rec *)SG(server_context)); 603 RETURN_TRUE; 604} 605/* }}} */ 606 607/* 608 * Local variables: 609 * tab-width: 4 610 * c-basic-offset: 4 611 * End: 612 * vim600: sw=4 ts=4 fdm=marker 613 * vim<600: sw=4 ts=4 614 */ 615