1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Sascha Schumann <sascha@schumann.cx> |
14 +----------------------------------------------------------------------+
15 */
16
17 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
18
19 #include "php.h"
20 #ifdef strcasecmp
21 # undef strcasecmp
22 #endif
23 #ifdef strncasecmp
24 # undef strncasecmp
25 #endif
26 #include "zend_smart_str.h"
27 #include "ext/standard/info.h"
28 #include "ext/standard/head.h"
29 #include "php_ini.h"
30 #include "SAPI.h"
31
32 #include "apr_strings.h"
33 #include "apr_time.h"
34 #include "ap_config.h"
35 #include "util_filter.h"
36 #include "httpd.h"
37 #include "http_config.h"
38 #include "http_request.h"
39 #include "http_core.h"
40 #include "http_protocol.h"
41 #include "http_log.h"
42 #include "http_main.h"
43 #include "util_script.h"
44 #include "http_core.h"
45 #include "ap_mpm.h"
46 #ifndef PHP_WIN32
47 #include "unixd.h"
48 #endif
49
50 #include "php_apache.h"
51 #include "php_functions_arginfo.h"
52
53 #ifdef ZTS
54 int php_apache2_info_id;
55 #else
56 php_apache2_info_struct php_apache2_info;
57 #endif
58
59 #define SECTION(name) PUTS("<h2>" name "</h2>\n")
60
php_apache_lookup_uri(char * filename)61 static request_rec *php_apache_lookup_uri(char *filename)
62 {
63 php_struct *ctx = SG(server_context);
64
65 if (!filename || !ctx || !ctx->r) {
66 return NULL;
67 }
68
69 return ap_sub_req_lookup_uri(filename, ctx->r, ctx->r->output_filters);
70 }
71
72 /* {{{ Perform an apache sub-request */
PHP_FUNCTION(virtual)73 PHP_FUNCTION(virtual)
74 {
75 char *filename;
76 size_t filename_len;
77 request_rec *rr;
78
79 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &filename, &filename_len) == FAILURE) {
80 RETURN_THROWS();
81 }
82
83 if (!(rr = php_apache_lookup_uri(filename))) {
84 php_error_docref(NULL, E_WARNING, "Unable to include '%s' - URI lookup failed", filename);
85 RETURN_FALSE;
86 }
87
88 if (rr->status != HTTP_OK) {
89 php_error_docref(NULL, E_WARNING, "Unable to include '%s' - error finding URI", filename);
90 ap_destroy_sub_req(rr);
91 RETURN_FALSE;
92 }
93
94 /* Flush everything. */
95 php_output_end_all();
96 php_header();
97
98 /* Ensure that the ap_r* layer for the main request is flushed, to
99 * work around http://issues.apache.org/bugzilla/show_bug.cgi?id=17629 */
100 ap_rflush(rr->main);
101
102 if (ap_run_sub_req(rr)) {
103 php_error_docref(NULL, E_WARNING, "Unable to include '%s' - request execution failed", filename);
104 ap_destroy_sub_req(rr);
105 RETURN_FALSE;
106 }
107 ap_destroy_sub_req(rr);
108 RETURN_TRUE;
109 }
110 /* }}} */
111
112 #define ADD_LONG(name) \
113 add_property_long(return_value, #name, rr->name)
114 #define ADD_TIME(name) \
115 add_property_long(return_value, #name, apr_time_sec(rr->name));
116 #define ADD_STRING(name) \
117 if (rr->name) add_property_string(return_value, #name, (char *) rr->name)
118
PHP_FUNCTION(apache_lookup_uri)119 PHP_FUNCTION(apache_lookup_uri)
120 {
121 request_rec *rr;
122 char *filename;
123 size_t filename_len;
124
125 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &filename, &filename_len) == FAILURE) {
126 RETURN_THROWS();
127 }
128
129 if (!(rr = php_apache_lookup_uri(filename))) {
130 php_error_docref(NULL, E_WARNING, "Unable to include '%s' - URI lookup failed", filename);
131 RETURN_FALSE;
132 }
133
134 if (rr->status == HTTP_OK) {
135 object_init(return_value);
136
137 ADD_LONG(status);
138 ADD_STRING(the_request);
139 ADD_STRING(status_line);
140 ADD_STRING(method);
141 ADD_TIME(mtime);
142 ADD_LONG(clength);
143 ADD_STRING(range);
144 ADD_LONG(chunked);
145 ADD_STRING(content_type);
146 ADD_STRING(handler);
147 ADD_LONG(no_cache);
148 ADD_LONG(no_local_copy);
149 ADD_STRING(unparsed_uri);
150 ADD_STRING(uri);
151 ADD_STRING(filename);
152 ADD_STRING(path_info);
153 ADD_STRING(args);
154 ADD_LONG(allowed);
155 ADD_LONG(sent_bodyct);
156 ADD_LONG(bytes_sent);
157 ADD_LONG(mtime);
158 ADD_TIME(request_time);
159
160 ap_destroy_sub_req(rr);
161 return;
162 }
163
164 php_error_docref(NULL, E_WARNING, "Unable to include '%s' - error finding URI", filename);
165 ap_destroy_sub_req(rr);
166 RETURN_FALSE;
167 }
168
169 /* {{{ Fetch all HTTP request headers */
PHP_FUNCTION(apache_request_headers)170 PHP_FUNCTION(apache_request_headers)
171 {
172 php_struct *ctx;
173 const apr_array_header_t *arr;
174 char *key, *val;
175
176 if (zend_parse_parameters_none() == FAILURE) {
177 RETURN_THROWS();
178 }
179
180 array_init(return_value);
181
182 ctx = SG(server_context);
183 arr = apr_table_elts(ctx->r->headers_in);
184
185 APR_ARRAY_FOREACH_OPEN(arr, key, val)
186 if (!val) val = "";
187 add_assoc_string(return_value, key, val);
188 APR_ARRAY_FOREACH_CLOSE()
189 }
190 /* }}} */
191
192 /* {{{ Fetch all HTTP response headers */
PHP_FUNCTION(apache_response_headers)193 PHP_FUNCTION(apache_response_headers)
194 {
195 php_struct *ctx;
196 const apr_array_header_t *arr;
197 char *key, *val;
198
199 if (zend_parse_parameters_none() == FAILURE) {
200 RETURN_THROWS();
201 }
202
203 array_init(return_value);
204
205 ctx = SG(server_context);
206 arr = apr_table_elts(ctx->r->headers_out);
207
208 APR_ARRAY_FOREACH_OPEN(arr, key, val)
209 if (!val) val = "";
210 add_assoc_string(return_value, key, val);
211 APR_ARRAY_FOREACH_CLOSE()
212 }
213 /* }}} */
214
215 /* {{{ Get and set Apache request notes */
PHP_FUNCTION(apache_note)216 PHP_FUNCTION(apache_note)
217 {
218 php_struct *ctx;
219 char *note_name, *note_val = NULL;
220 size_t note_name_len, note_val_len;
221 char *old_note_val=NULL;
222
223 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", ¬e_name, ¬e_name_len, ¬e_val, ¬e_val_len) == FAILURE) {
224 RETURN_THROWS();
225 }
226
227 ctx = SG(server_context);
228
229 old_note_val = (char *) apr_table_get(ctx->r->notes, note_name);
230
231 if (note_val) {
232 apr_table_set(ctx->r->notes, note_name, note_val);
233 }
234
235 if (old_note_val) {
236 RETURN_STRING(old_note_val);
237 }
238
239 RETURN_FALSE;
240 }
241 /* }}} */
242
243
244 /* {{{ Set an Apache subprocess_env variable */
245 /*
246 * XXX this doesn't look right. shouldn't it be the parent ?*/
PHP_FUNCTION(apache_setenv)247 PHP_FUNCTION(apache_setenv)
248 {
249 php_struct *ctx;
250 char *variable=NULL, *string_val=NULL;
251 size_t variable_len, string_val_len;
252 bool walk_to_top = false;
253 request_rec *r;
254
255 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|b", &variable, &variable_len, &string_val, &string_val_len, &walk_to_top) == FAILURE) {
256 RETURN_THROWS();
257 }
258
259 ctx = SG(server_context);
260
261 r = ctx->r;
262 if (walk_to_top) {
263 while(r->prev) {
264 r = r->prev;
265 }
266 }
267
268 apr_table_set(r->subprocess_env, variable, string_val);
269
270 RETURN_TRUE;
271 }
272 /* }}} */
273
274 /* {{{ Get an Apache subprocess_env variable */
275 /*
276 * XXX: shouldn't this be the parent not the 'prev'
277 */
PHP_FUNCTION(apache_getenv)278 PHP_FUNCTION(apache_getenv)
279 {
280 php_struct *ctx;
281 char *variable;
282 size_t variable_len;
283 bool walk_to_top = 0;
284 char *env_val=NULL;
285 request_rec *r;
286
287 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &variable, &variable_len, &walk_to_top) == FAILURE) {
288 RETURN_THROWS();
289 }
290
291 ctx = SG(server_context);
292
293 r = ctx->r;
294 if (walk_to_top) {
295 while(r->prev) {
296 r = r->prev;
297 }
298 }
299
300 env_val = (char*) apr_table_get(r->subprocess_env, variable);
301
302 if (env_val != NULL) {
303 RETURN_STRING(env_val);
304 }
305
306 RETURN_FALSE;
307 }
308 /* }}} */
309
php_apache_get_version(void)310 static const char *php_apache_get_version(void)
311 {
312 return ap_get_server_banner();
313 }
314
315 /* {{{ Fetch Apache version */
PHP_FUNCTION(apache_get_version)316 PHP_FUNCTION(apache_get_version)
317 {
318 const char *apv = php_apache_get_version();
319
320 if (apv && *apv) {
321 RETURN_STRING(apv);
322 } else {
323 RETURN_FALSE;
324 }
325 }
326 /* }}} */
327
328 /* {{{ Get a list of loaded Apache modules */
PHP_FUNCTION(apache_get_modules)329 PHP_FUNCTION(apache_get_modules)
330 {
331 int n;
332 char *p;
333
334 array_init(return_value);
335
336 for (n = 0; ap_loaded_modules[n]; ++n) {
337 const char *s = ap_loaded_modules[n]->name;
338 if ((p = strchr(s, '.'))) {
339 add_next_index_stringl(return_value, s, (p - s));
340 } else {
341 add_next_index_string(return_value, s);
342 }
343 }
344 }
345 /* }}} */
346
PHP_MINFO_FUNCTION(apache)347 PHP_MINFO_FUNCTION(apache)
348 {
349 const char *apv = php_apache_get_version();
350 smart_str tmp1 = {0};
351 char tmp[1024];
352 int n, max_requests;
353 char *p;
354 server_rec *serv = ((php_struct *) SG(server_context))->r->server;
355 #ifndef PHP_WIN32
356 AP_DECLARE_DATA extern unixd_config_rec ap_unixd_config;
357 #endif
358
359 for (n = 0; ap_loaded_modules[n]; ++n) {
360 const char *s = ap_loaded_modules[n]->name;
361 if (n > 0) {
362 smart_str_appendc(&tmp1, ' ');
363 }
364 if ((p = strchr(s, '.'))) {
365 smart_str_appendl(&tmp1, s, (p - s));
366 } else {
367 smart_str_appends(&tmp1, s);
368 }
369 }
370 if (!tmp1.s) {
371 smart_str_appendc(&tmp1, '/');
372 }
373 smart_str_0(&tmp1);
374
375 php_info_print_table_start();
376 if (apv && *apv) {
377 php_info_print_table_row(2, "Apache Version", apv);
378 }
379 snprintf(tmp, sizeof(tmp), "%d", MODULE_MAGIC_NUMBER_MAJOR);
380 php_info_print_table_row(2, "Apache API Version", tmp);
381
382 if (serv->server_admin && *(serv->server_admin)) {
383 php_info_print_table_row(2, "Server Administrator", serv->server_admin);
384 }
385
386 snprintf(tmp, sizeof(tmp), "%s:%u", serv->server_hostname, serv->port);
387 php_info_print_table_row(2, "Hostname:Port", tmp);
388
389 #ifndef PHP_WIN32
390 snprintf(tmp, sizeof(tmp), "%s(%d)/%d", ap_unixd_config.user_name, ap_unixd_config.user_id, ap_unixd_config.group_id);
391 php_info_print_table_row(2, "User/Group", tmp);
392 #endif
393
394 ap_mpm_query(AP_MPMQ_MAX_REQUESTS_DAEMON, &max_requests);
395 snprintf(tmp, sizeof(tmp), "Per Child: %d - Keep Alive: %s - Max Per Connection: %d", max_requests, (serv->keep_alive ? "on":"off"), serv->keep_alive_max);
396 php_info_print_table_row(2, "Max Requests", tmp);
397
398 apr_snprintf(tmp, sizeof tmp,
399 "Connection: %" APR_TIME_T_FMT " - Keep-Alive: %" APR_TIME_T_FMT,
400 apr_time_sec(serv->timeout), apr_time_sec(serv->keep_alive_timeout));
401 php_info_print_table_row(2, "Timeouts", tmp);
402
403 php_info_print_table_row(2, "Virtual Server", (serv->is_virtual ? "Yes" : "No"));
404 php_info_print_table_row(2, "Server Root", ap_server_root);
405 php_info_print_table_row(2, "Loaded Modules", ZSTR_VAL(tmp1.s));
406
407 smart_str_free(&tmp1);
408 php_info_print_table_end();
409
410 DISPLAY_INI_ENTRIES();
411
412 {
413 const apr_array_header_t *arr = apr_table_elts(((php_struct *) SG(server_context))->r->subprocess_env);
414 char *key, *val;
415
416 SECTION("Apache Environment");
417 php_info_print_table_start();
418 php_info_print_table_header(2, "Variable", "Value");
419 APR_ARRAY_FOREACH_OPEN(arr, key, val)
420 if (!val) {
421 val = "";
422 }
423 php_info_print_table_row(2, key, val);
424 APR_ARRAY_FOREACH_CLOSE()
425
426 php_info_print_table_end();
427
428 SECTION("HTTP Headers Information");
429 php_info_print_table_start();
430 php_info_print_table_colspan_header(2, "HTTP Request Headers");
431 php_info_print_table_row(2, "HTTP Request", ((php_struct *) SG(server_context))->r->the_request);
432
433 arr = apr_table_elts(((php_struct *) SG(server_context))->r->headers_in);
434 APR_ARRAY_FOREACH_OPEN(arr, key, val)
435 if (!val) {
436 val = "";
437 }
438 php_info_print_table_row(2, key, val);
439 APR_ARRAY_FOREACH_CLOSE()
440
441 php_info_print_table_colspan_header(2, "HTTP Response Headers");
442 arr = apr_table_elts(((php_struct *) SG(server_context))->r->headers_out);
443 APR_ARRAY_FOREACH_OPEN(arr, key, val)
444 if (!val) {
445 val = "";
446 }
447 php_info_print_table_row(2, key, val);
448 APR_ARRAY_FOREACH_CLOSE()
449
450 php_info_print_table_end();
451 }
452 }
453
454 PHP_INI_BEGIN()
455 STD_PHP_INI_BOOLEAN("xbithack", "0", PHP_INI_ALL, OnUpdateBool, xbithack, php_apache2_info_struct, php_apache2_info)
456 STD_PHP_INI_BOOLEAN("engine", "1", PHP_INI_ALL, OnUpdateBool, engine, php_apache2_info_struct, php_apache2_info)
457 STD_PHP_INI_BOOLEAN("last_modified", "0", PHP_INI_ALL, OnUpdateBool, last_modified, php_apache2_info_struct, php_apache2_info)
PHP_INI_END()458 PHP_INI_END()
459
460 static PHP_MINIT_FUNCTION(apache)
461 {
462 #ifdef ZTS
463 ts_allocate_id(&php_apache2_info_id, sizeof(php_apache2_info_struct), (ts_allocate_ctor) NULL, NULL);
464 #endif
465 REGISTER_INI_ENTRIES();
466 return SUCCESS;
467 }
468
PHP_MSHUTDOWN_FUNCTION(apache)469 static PHP_MSHUTDOWN_FUNCTION(apache)
470 {
471 UNREGISTER_INI_ENTRIES();
472 return SUCCESS;
473 }
474
475 zend_module_entry php_apache_module = {
476 STANDARD_MODULE_HEADER,
477 "apache2handler",
478 ext_functions,
479 PHP_MINIT(apache),
480 PHP_MSHUTDOWN(apache),
481 NULL,
482 NULL,
483 PHP_MINFO(apache),
484 PHP_VERSION,
485 STANDARD_MODULE_PROPERTIES
486 };
487