1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 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    | Author: Sascha Schumann <sascha@schumann.cx>                         |
16    +----------------------------------------------------------------------+
17  */
18 
19 /* $Id$ */
20 
21 
22 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
23 
24 #include "php.h"
25 #include "ext/standard/php_smart_str.h"
26 #include "ext/standard/info.h"
27 #include "SAPI.h"
28 
29 #define CORE_PRIVATE
30 #include "apr_strings.h"
31 #include "apr_time.h"
32 #include "ap_config.h"
33 #include "util_filter.h"
34 #include "httpd.h"
35 #include "http_config.h"
36 #include "http_request.h"
37 #include "http_core.h"
38 #include "http_protocol.h"
39 #include "http_log.h"
40 #include "http_main.h"
41 #include "util_script.h"
42 #include "http_core.h"
43 
44 #include "php_apache.h"
45 
php_apache_lookup_uri(char * filename TSRMLS_DC)46 static request_rec *php_apache_lookup_uri(char *filename TSRMLS_DC)
47 {
48 	php_struct *ctx;
49 
50 	if (!filename) {
51 		return NULL;
52 	}
53 
54 	ctx = SG(server_context);
55 	return ap_sub_req_lookup_uri(filename, ctx->f->r, ctx->f->next);
56 }
57 
58 /* {{{ proto bool virtual(string uri)
59  Perform an apache sub-request */
PHP_FUNCTION(virtual)60 PHP_FUNCTION(virtual)
61 {
62 	char *filename;
63 	int filename_len;
64 	request_rec *rr;
65 
66 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) {
67 		return;
68 	}
69 
70 	if (!(rr = php_apache_lookup_uri(filename TSRMLS_CC))) {
71 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include '%s' - URI lookup failed", filename);
72 		RETURN_FALSE;
73 	}
74 
75 	if (rr->status == HTTP_OK) {
76 		if (ap_run_sub_req(rr)) {
77 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include '%s' - request execution failed", filename);
78 			ap_destroy_sub_req(rr);
79 			RETURN_FALSE;
80 		}
81 		ap_destroy_sub_req(rr);
82 		RETURN_TRUE;
83 	}
84 
85 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include '%s' - error finding URI", filename);
86 	ap_destroy_sub_req(rr);
87 	RETURN_FALSE;
88 }
89 /* }}} */
90 
91 #define ADD_LONG(name) \
92 		add_property_long(return_value, #name, rr->name)
93 #define ADD_TIME(name) \
94 		add_property_long(return_value, #name, apr_time_sec(rr->name));
95 #define ADD_STRING(name) \
96 		if (rr->name) add_property_string(return_value, #name, (char *) rr->name, 1)
97 
PHP_FUNCTION(apache_lookup_uri)98 PHP_FUNCTION(apache_lookup_uri)
99 {
100 	request_rec *rr;
101 	char *filename;
102 	int filename_len;
103 
104 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) {
105 		return;
106 	}
107 
108 	if (!(rr = php_apache_lookup_uri(filename TSRMLS_CC))) {
109 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include '%s' - URI lookup failed", filename);
110 		RETURN_FALSE;
111 	}
112 
113 	if (rr->status == HTTP_OK) {
114 		object_init(return_value);
115 
116 		ADD_LONG(status);
117 		ADD_STRING(the_request);
118 		ADD_STRING(status_line);
119 		ADD_STRING(method);
120 		ADD_TIME(mtime);
121 		ADD_LONG(clength);
122 #if MODULE_MAGIC_NUMBER < 20020506
123 		ADD_STRING(boundary);
124 #endif
125 		ADD_STRING(range);
126 		ADD_LONG(chunked);
127 		ADD_STRING(content_type);
128 		ADD_STRING(handler);
129 		ADD_LONG(no_cache);
130 		ADD_LONG(no_local_copy);
131 		ADD_STRING(unparsed_uri);
132 		ADD_STRING(uri);
133 		ADD_STRING(filename);
134 		ADD_STRING(path_info);
135 		ADD_STRING(args);
136 		ADD_LONG(allowed);
137 		ADD_LONG(sent_bodyct);
138 		ADD_LONG(bytes_sent);
139 		ADD_LONG(mtime);
140 		ADD_TIME(request_time);
141 
142 		ap_destroy_sub_req(rr);
143 		return;
144 	}
145 
146 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to include '%s' - error finding URI", filename);
147 	ap_destroy_sub_req(rr);
148 	RETURN_FALSE;
149 }
150 
151 /* {{{ proto array getallheaders(void)
152    Fetch all HTTP request headers */
PHP_FUNCTION(apache_request_headers)153 PHP_FUNCTION(apache_request_headers)
154 {
155 	php_struct *ctx;
156 	const apr_array_header_t *arr;
157 	char *key, *val;
158 
159 	array_init(return_value);
160 
161 	ctx = SG(server_context);
162 	arr = apr_table_elts(ctx->f->r->headers_in);
163 
164 	APR_ARRAY_FOREACH_OPEN(arr, key, val)
165 		if (!val) val = "";
166 		add_assoc_string(return_value, key, val, 1);
167 	APR_ARRAY_FOREACH_CLOSE()
168 }
169 /* }}} */
170 
171 /* {{{ proto array apache_response_headers(void)
172    Fetch all HTTP response headers */
PHP_FUNCTION(apache_response_headers)173 PHP_FUNCTION(apache_response_headers)
174 {
175 	php_struct *ctx;
176 	const apr_array_header_t *arr;
177 	char *key, *val;
178 
179 	array_init(return_value);
180 
181 	ctx = SG(server_context);
182 	arr = apr_table_elts(ctx->f->r->headers_out);
183 
184 	APR_ARRAY_FOREACH_OPEN(arr, key, val)
185 		if (!val) val = "";
186 		add_assoc_string(return_value, key, val, 1);
187 	APR_ARRAY_FOREACH_CLOSE()
188 }
189 /* }}} */
190 
191 /* {{{ proto string apache_note(string note_name [, string note_value])
192    Get and set Apache request notes */
PHP_FUNCTION(apache_note)193 PHP_FUNCTION(apache_note)
194 {
195 	php_struct *ctx;
196 	char *note_name, *note_val = NULL;
197 	int note_name_len, note_val_len;
198 	char *old_note_val=NULL;
199 
200 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &note_name, &note_name_len, &note_val, &note_val_len) == FAILURE) {
201 		return;
202 	}
203 
204 	ctx = SG(server_context);
205 
206 	old_note_val = (char *) apr_table_get(ctx->r->notes, note_name);
207 
208 	if (note_val) {
209 		apr_table_set(ctx->r->notes, note_name, note_val);
210 	}
211 
212 	if (old_note_val) {
213 		RETURN_STRING(old_note_val, 1);
214 	}
215 
216 	RETURN_FALSE;
217 }
218 /* }}} */
219 
220 
221 /* {{{ proto bool apache_setenv(string variable, string value [, bool walk_to_top])
222    Set an Apache subprocess_env variable */
PHP_FUNCTION(apache_setenv)223 PHP_FUNCTION(apache_setenv)
224 {
225 	php_struct *ctx;
226 	char *variable=NULL, *string_val=NULL;
227 	int variable_len, string_val_len;
228 	zend_bool walk_to_top = 0;
229 	int arg_count = ZEND_NUM_ARGS();
230 
231 	if (zend_parse_parameters(arg_count TSRMLS_CC, "ss|b", &variable, &variable_len, &string_val, &string_val_len, &walk_to_top) == FAILURE) {
232 		return;
233 	}
234 
235 	ctx = SG(server_context);
236 
237 	if (arg_count == 3 && walk_to_top) {
238 		while(ctx->f->r->prev) {
239 			ctx->f->r = ctx->f->r->prev;
240 		}
241 	}
242 
243 	apr_table_set(ctx->r->subprocess_env, variable, string_val);
244 
245 	RETURN_TRUE;
246 }
247 /* }}} */
248 
249 /* {{{ proto bool apache_getenv(string variable [, bool walk_to_top])
250    Get an Apache subprocess_env variable */
PHP_FUNCTION(apache_getenv)251 PHP_FUNCTION(apache_getenv)
252 {
253 	php_struct *ctx;
254 	char *variable=NULL;
255 	int variable_len;
256 	zend_bool walk_to_top = 0;
257 	int arg_count = ZEND_NUM_ARGS();
258 	char *env_val=NULL;
259 
260 	if (zend_parse_parameters(arg_count TSRMLS_CC, "s|b", &variable, &variable_len, &walk_to_top) == FAILURE) {
261 		return;
262 	}
263 
264 	ctx = SG(server_context);
265 
266 	if (arg_count == 2 && walk_to_top) {
267 		while(ctx->f->r->prev) {
268 			ctx->f->r = ctx->f->r->prev;
269 		}
270 	}
271 
272 	env_val = (char*) apr_table_get(ctx->r->subprocess_env, variable);
273 	if (env_val != NULL) {
274 		RETURN_STRING(env_val, 1);
275 	}
276 
277 	RETURN_FALSE;
278 }
279 /* }}} */
280 
php_apache_get_version()281 static char *php_apache_get_version()
282 {
283 #if MODULE_MAGIC_NUMBER_MAJOR >= 20060905
284 	return (char *) ap_get_server_banner();
285 #else
286 	return (char *) ap_get_server_version();
287 #endif
288 }
289 
290 /* {{{ proto string apache_get_version(void)
291    Fetch Apache version */
PHP_FUNCTION(apache_get_version)292 PHP_FUNCTION(apache_get_version)
293 {
294 	char *apv = php_apache_get_version();
295 
296 	if (apv && *apv) {
297 		RETURN_STRING(apv, 1);
298 	} else {
299 		RETURN_FALSE;
300 	}
301 }
302 /* }}} */
303 
304 /* {{{ proto array apache_get_modules(void)
305    Get a list of loaded Apache modules */
PHP_FUNCTION(apache_get_modules)306 PHP_FUNCTION(apache_get_modules)
307 {
308 	int n;
309 	char *p;
310 
311 	array_init(return_value);
312 
313 	for (n = 0; ap_loaded_modules[n]; ++n) {
314 		char *s = (char *) ap_loaded_modules[n]->name;
315 		if ((p = strchr(s, '.'))) {
316 			add_next_index_stringl(return_value, s, (p - s), 1);
317 		} else {
318 			add_next_index_string(return_value, s, 1);
319 		}
320 	}
321 }
322 /* }}} */
323 
PHP_MINFO_FUNCTION(apache)324 PHP_MINFO_FUNCTION(apache)
325 {
326 	char *apv = php_apache_get_version();
327 	smart_str tmp1 = {0};
328 	int n;
329 	char *p;
330 
331 	for (n = 0; ap_loaded_modules[n]; ++n) {
332 		char *s = (char *) ap_loaded_modules[n]->name;
333 		if ((p = strchr(s, '.'))) {
334 			smart_str_appendl(&tmp1, s, (p - s));
335 		} else {
336 			smart_str_appends(&tmp1, s);
337 		}
338 		smart_str_appendc(&tmp1, ' ');
339 	}
340 	if ((tmp1.len - 1) >= 0) {
341 		tmp1.c[tmp1.len - 1] = '\0';
342 	}
343 
344 	php_info_print_table_start();
345 	if (apv && *apv) {
346 		php_info_print_table_row(2, "Apache Version", apv);
347 	}
348 	php_info_print_table_row(2, "Loaded Modules", tmp1.c);
349 	smart_str_free(&tmp1);
350 	php_info_print_table_end();
351 }
352 
353 /* {{{ arginfo */
354 ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_lookup_uri, 0, 0, 1)
355 	ZEND_ARG_INFO(0, filename)
356 ZEND_END_ARG_INFO()
357 
358 ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_virtual, 0, 0, 1)
359 	ZEND_ARG_INFO(0, uri)
360 ZEND_END_ARG_INFO()
361 
362 ZEND_BEGIN_ARG_INFO(arginfo_apache2filter_getallheaders, 0)
363 ZEND_END_ARG_INFO()
364 
365 ZEND_BEGIN_ARG_INFO(arginfo_apache2filter_response_headers, 0)
366 ZEND_END_ARG_INFO()
367 
368 ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_note, 0, 0, 1)
369 	ZEND_ARG_INFO(0, note_name)
370 	ZEND_ARG_INFO(0, note_value)
371 ZEND_END_ARG_INFO()
372 
373 ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_setenv, 0, 0, 2)
374 	ZEND_ARG_INFO(0, variable)
375 	ZEND_ARG_INFO(0, value)
376 	ZEND_ARG_INFO(0, walk_to_top)
377 ZEND_END_ARG_INFO()
378 
379 ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_getenv, 0, 0, 1)
380 	ZEND_ARG_INFO(0, variable)
381 	ZEND_ARG_INFO(0, walk_to_top)
382 ZEND_END_ARG_INFO()
383 
384 ZEND_BEGIN_ARG_INFO(arginfo_apache2filter_get_version, 0)
385 ZEND_END_ARG_INFO()
386 
387 ZEND_BEGIN_ARG_INFO(arginfo_apache2filter_get_modules, 0)
388 ZEND_END_ARG_INFO()
389 /* }}} */
390 
391 static const zend_function_entry apache_functions[] = {
392 	PHP_FE(apache_lookup_uri, 		arginfo_apache2filter_lookup_uri)
393 	PHP_FE(virtual, 				arginfo_apache2filter_virtual)
394 	PHP_FE(apache_request_headers, 	arginfo_apache2filter_getallheaders)
395 	PHP_FE(apache_response_headers, arginfo_apache2filter_response_headers)
396 	PHP_FE(apache_setenv, 			arginfo_apache2filter_setenv)
397 	PHP_FE(apache_getenv, 			arginfo_apache2filter_getenv)
398 	PHP_FE(apache_note, 			arginfo_apache2filter_note)
399 	PHP_FE(apache_get_version, 		arginfo_apache2filter_get_version)
400 	PHP_FE(apache_get_modules, 		arginfo_apache2filter_get_modules)
401 	PHP_FALIAS(getallheaders, 		apache_request_headers, arginfo_apache2filter_getallheaders)
402 	{NULL, NULL, NULL}
403 };
404 
405 zend_module_entry php_apache_module = {
406 	STANDARD_MODULE_HEADER,
407 	"apache2filter",
408 	apache_functions,
409 	NULL,
410 	NULL,
411 	NULL,
412 	NULL,
413 	PHP_MINFO(apache),
414 	NULL,
415 	STANDARD_MODULE_PROPERTIES
416 };
417 
418 /*
419  * Local variables:
420  * tab-width: 4
421  * c-basic-offset: 4
422  * End:
423  * vim600: sw=4 ts=4 fdm=marker
424  * vim<600: sw=4 ts=4
425  */
426