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   | 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
46static 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 */
60PHP_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, "s", &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
98PHP_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, "s", &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 */
153PHP_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 */
173PHP_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 */
193PHP_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 */
223PHP_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 */
251PHP_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
281static 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 */
292PHP_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 */
306PHP_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
324PHP_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 */
354ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_lookup_uri, 0, 0, 1)
355    ZEND_ARG_INFO(0, filename)
356ZEND_END_ARG_INFO()
357
358ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_virtual, 0, 0, 1)
359    ZEND_ARG_INFO(0, uri)
360ZEND_END_ARG_INFO()
361
362ZEND_BEGIN_ARG_INFO(arginfo_apache2filter_getallheaders, 0)
363ZEND_END_ARG_INFO()
364
365ZEND_BEGIN_ARG_INFO(arginfo_apache2filter_response_headers, 0)
366ZEND_END_ARG_INFO()
367
368ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_note, 0, 0, 1)
369    ZEND_ARG_INFO(0, note_name)
370    ZEND_ARG_INFO(0, note_value)
371ZEND_END_ARG_INFO()
372
373ZEND_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)
377ZEND_END_ARG_INFO()
378
379ZEND_BEGIN_ARG_INFO_EX(arginfo_apache2filter_getenv, 0, 0, 1)
380    ZEND_ARG_INFO(0, variable)
381    ZEND_ARG_INFO(0, walk_to_top)
382ZEND_END_ARG_INFO()
383
384ZEND_BEGIN_ARG_INFO(arginfo_apache2filter_get_version, 0)
385ZEND_END_ARG_INFO()
386
387ZEND_BEGIN_ARG_INFO(arginfo_apache2filter_get_modules, 0)
388ZEND_END_ARG_INFO()
389/* }}} */
390
391static 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
405zend_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