File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / apache / mod_php5.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:04:02 2014 UTC (10 years ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 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@php.net>                             |
   16:    | (with helpful hints from Dean Gaudet <dgaudet@arctic.org>            |
   17:    | PHP 4.0 patches by Zeev Suraski <zeev@zend.com>                      |
   18:    +----------------------------------------------------------------------+
   19:  */
   20: /* $Id: mod_php5.c,v 1.1.1.4 2014/06/15 20:04:02 misho Exp $ */
   21: 
   22: #include "php_apache_http.h"
   23: #include "http_conf_globals.h"
   24: 
   25: #ifdef NETWARE
   26: #define SIGPIPE SIGINT
   27: #endif
   28: 
   29: #undef shutdown
   30: 
   31: /* {{{ Prototypes
   32:  */
   33: int apache_php_module_main(request_rec *r, int display_source_mode TSRMLS_DC);
   34: static void php_save_umask(void);
   35: static void php_restore_umask(void);
   36: static int sapi_apache_read_post(char *buffer, uint count_bytes TSRMLS_DC);
   37: static char *sapi_apache_read_cookies(TSRMLS_D);
   38: static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
   39: static int sapi_apache_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC);
   40: static int send_php(request_rec *r, int display_source_mode, char *filename);
   41: static int send_parsed_php(request_rec * r);
   42: static int send_parsed_php_source(request_rec * r);
   43: static int php_xbithack_handler(request_rec * r);
   44: static void php_init_handler(server_rec *s, pool *p);
   45: /* }}} */
   46: 
   47: #if MODULE_MAGIC_NUMBER >= 19970728
   48: static void php_child_exit_handler(server_rec *s, pool *p);
   49: #endif
   50: 
   51: #if MODULE_MAGIC_NUMBER > 19961007
   52: #define CONST_PREFIX const
   53: #else
   54: #define CONST_PREFIX
   55: #endif
   56: static CONST_PREFIX char *php_apache_value_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode);
   57: static CONST_PREFIX char *php_apache_value_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2);
   58: static CONST_PREFIX char *php_apache_admin_value_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2);
   59: static CONST_PREFIX char *php_apache_flag_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2);
   60: static CONST_PREFIX char *php_apache_flag_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode);
   61: static CONST_PREFIX char *php_apache_admin_flag_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2);
   62: 
   63: /* ### these should be defined in mod_php5.h or somewhere else */
   64: #define USE_PATH 1
   65: #define IGNORE_URL 2
   66: #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST POSSIBLE STATUS DESCRIPTION")
   67: 
   68: module MODULE_VAR_EXPORT php5_module;
   69: 
   70: int saved_umask;
   71: static unsigned char apache_php_initialized;
   72: 
   73: typedef struct _php_per_dir_entry {
   74: 	char *key;
   75: 	char *value;
   76: 	uint key_length;
   77: 	uint value_length;
   78: 	int type;
   79: 	char htaccess;
   80: } php_per_dir_entry;
   81: 
   82: /* some systems are missing these from their header files */
   83: 
   84: /* {{{ php_save_umask
   85:  */
   86: static void php_save_umask(void)
   87: {
   88: 	saved_umask = umask(077);
   89: 	umask(saved_umask);
   90: }
   91: /* }}} */
   92: 
   93: /* {{{ sapi_apache_ub_write
   94:  */
   95: static int sapi_apache_ub_write(const char *str, uint str_length TSRMLS_DC)
   96: {
   97: 	int ret=0;
   98: 		
   99: 	if (SG(server_context)) {
  100: 		ret = rwrite(str, str_length, (request_rec *) SG(server_context));
  101: 	}
  102: 	if (ret != str_length) {
  103: 		php_handle_aborted_connection();
  104: 	}
  105: 	return ret;
  106: }
  107: /* }}} */
  108: 
  109: /* {{{ sapi_apache_flush
  110:  */
  111: static void sapi_apache_flush(void *server_context)
  112: {
  113: 	if (server_context) {
  114: #if MODULE_MAGIC_NUMBER > 19970110
  115: 		rflush((request_rec *) server_context);
  116: #else
  117: 		bflush((request_rec *) server_context->connection->client);
  118: #endif
  119: 	}
  120: }
  121: /* }}} */
  122: 
  123: /* {{{ sapi_apache_read_post
  124:  */
  125: static int sapi_apache_read_post(char *buffer, uint count_bytes TSRMLS_DC)
  126: {
  127: 	int total_read_bytes=0, read_bytes;
  128: 	request_rec *r = (request_rec *) SG(server_context);
  129: 	void (*handler)(int);
  130: 
  131: 	/*
  132: 	 * This handles the situation where the browser sends a Expect: 100-continue header
  133: 	 * and needs to receive confirmation from the server on whether or not it can send
  134: 	 * the rest of the request. RFC 2616
  135: 	 *
  136: 	 */
  137: 	if (!SG(read_post_bytes) && !ap_should_client_block(r)) {
  138: 		return total_read_bytes;
  139: 	}
  140:  
  141: 	handler = signal(SIGPIPE, SIG_IGN);
  142: 	while (total_read_bytes<count_bytes) {
  143: 		hard_timeout("Read POST information", r); /* start timeout timer */
  144: 		read_bytes = get_client_block(r, buffer+total_read_bytes, count_bytes-total_read_bytes);
  145: 		reset_timeout(r);
  146: 		if (read_bytes<=0) {
  147: 			break;
  148: 		}
  149: 		total_read_bytes += read_bytes;
  150: 	}
  151: 	signal(SIGPIPE, handler);	
  152: 	return total_read_bytes;
  153: }
  154: /* }}} */
  155: 
  156: /* {{{ sapi_apache_read_cookies
  157:  */
  158: static char *sapi_apache_read_cookies(TSRMLS_D)
  159: {
  160: 	return (char *) table_get(((request_rec *) SG(server_context))->subprocess_env, "HTTP_COOKIE");
  161: }
  162: /* }}} */
  163: 
  164: /* {{{ sapi_apache_header_handler
  165:  */
  166: static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
  167: {
  168: 	char *header_name, *header_content, *p;
  169: 	request_rec *r = (request_rec *) SG(server_context);
  170: 	if(!r) {
  171: 		return 0;
  172: 	}
  173: 
  174: 	switch(op) {
  175: 		case SAPI_HEADER_DELETE_ALL:
  176: 			clear_table(r->headers_out);
  177: 			return 0;
  178: 
  179: 		case SAPI_HEADER_DELETE:
  180: 			table_unset(r->headers_out, sapi_header->header);
  181: 			return 0;
  182: 
  183: 		case SAPI_HEADER_ADD:
  184: 		case SAPI_HEADER_REPLACE:
  185: 			header_name = sapi_header->header;
  186: 
  187: 			header_content = p = strchr(header_name, ':');
  188: 			if (!p) {
  189: 				return 0;
  190: 			}
  191: 
  192: 			*p = 0;
  193: 			do {
  194: 				header_content++;
  195: 			} while (*header_content==' ');
  196: 
  197: 			if (!strcasecmp(header_name, "Content-Type")) {
  198: 				r->content_type = pstrdup(r->pool, header_content);
  199:                        } else if (!strcasecmp(header_name, "Content-Length")) {
  200:                                ap_set_content_length(r, strtol(header_content, (char **)NULL, 10));
  201: 			} else if (!strcasecmp(header_name, "Set-Cookie")) {
  202: 				table_add(r->headers_out, header_name, header_content);
  203: 			} else if (op == SAPI_HEADER_REPLACE) {
  204: 				table_set(r->headers_out, header_name, header_content);
  205: 			} else {
  206: 				table_add(r->headers_out, header_name, header_content);
  207: 			}
  208: 
  209: 			*p = ':';  /* a well behaved header handler shouldn't change its original arguments */
  210: 
  211: 			return SAPI_HEADER_ADD;
  212: 
  213: 		default:
  214: 			return 0;
  215: 	}
  216: }
  217: /* }}} */
  218: 
  219: /* {{{ sapi_apache_send_headers
  220:  */
  221: static int sapi_apache_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
  222: {
  223: 	request_rec *r = SG(server_context);
  224: 	const char *sline = SG(sapi_headers).http_status_line;
  225: 	int sline_len;
  226: 
  227: 	if(r == NULL) { /* server_context is not here anymore */
  228: 		return SAPI_HEADER_SEND_FAILED;
  229: 	}
  230: 
  231: 	r->status = SG(sapi_headers).http_response_code;
  232: 
  233: 	/* httpd requires that r->status_line is set to the first digit of
  234: 	 * the status-code: */
  235: 	if (sline && ((sline_len = strlen(sline)) > 12) && strncmp(sline, "HTTP/1.", 7) == 0 && sline[8] == ' ' && sline[12] == ' ') {
  236: 		if ((sline_len - 9) > MAX_STATUS_LENGTH) {
  237: 			r->status_line = ap_pstrndup(r->pool, sline + 9, MAX_STATUS_LENGTH);
  238: 		} else {
  239: 			r->status_line = ap_pstrndup(r->pool, sline + 9, sline_len - 9);
  240: 		}
  241: 	}
  242: 
  243: 	if(r->status==304) {
  244: 		send_error_response(r,0);
  245: 	} else {
  246: 		send_http_header(r);
  247: 	}
  248: 	return SAPI_HEADER_SENT_SUCCESSFULLY;
  249: }
  250: /* }}} */
  251: 
  252: /* {{{ sapi_apache_register_server_variables
  253:  */
  254: static void sapi_apache_register_server_variables(zval *track_vars_array TSRMLS_DC)
  255: {
  256: 	register int i;
  257: 	array_header *arr = table_elts(((request_rec *) SG(server_context))->subprocess_env);
  258: 	table_entry *elts = (table_entry *) arr->elts;
  259: 	zval **path_translated;
  260: 	HashTable *symbol_table;
  261: 	unsigned int new_val_len;
  262: 
  263: 	for (i = 0; i < arr->nelts; i++) {
  264: 		char *val;
  265: 		int val_len;
  266: 
  267: 		if (elts[i].val) {
  268: 			val = elts[i].val;
  269: 		} else {
  270: 			val = "";
  271: 		}
  272: 		val_len = strlen(val);
  273: 		if (sapi_module.input_filter(PARSE_SERVER, elts[i].key, &val, val_len, &new_val_len TSRMLS_CC)) {
  274: 			php_register_variable_safe(elts[i].key, val, new_val_len, track_vars_array TSRMLS_CC);
  275: 		}
  276: 	}
  277: 
  278: 	/* If PATH_TRANSLATED doesn't exist, copy it from SCRIPT_FILENAME */
  279: 	if (track_vars_array) {
  280: 		symbol_table = track_vars_array->value.ht;
  281: 	} else {
  282: 		symbol_table = NULL;
  283: 	}
  284: 	if (symbol_table
  285: 		&& !zend_hash_exists(symbol_table, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"))
  286: 		&& zend_hash_find(symbol_table, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &path_translated)==SUCCESS) {
  287: 		php_register_variable("PATH_TRANSLATED", Z_STRVAL_PP(path_translated), track_vars_array TSRMLS_CC);
  288: 	}
  289: 
  290: 	if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &((request_rec *) SG(server_context))->uri, strlen(((request_rec *) SG(server_context))->uri), &new_val_len TSRMLS_CC)) {
  291: 		php_register_variable("PHP_SELF", ((request_rec *) SG(server_context))->uri, track_vars_array TSRMLS_CC);
  292: 	}
  293: }
  294: /* }}} */
  295: 
  296: /* {{{ php_apache_startup
  297:  */
  298: static int php_apache_startup(sapi_module_struct *sapi_module)
  299: {
  300: 	if (php_module_startup(sapi_module, &apache_module_entry, 1) == FAILURE) {
  301: 		return FAILURE;
  302: 	} else {
  303: 		return SUCCESS;
  304: 	}
  305: }
  306: /* }}} */
  307: 
  308: /* {{{ php_apache_log_message
  309:  */
  310: static void php_apache_log_message(char *message TSRMLS_DC)
  311: {
  312: 	if (SG(server_context)) {
  313: #if MODULE_MAGIC_NUMBER >= 19970831
  314: 		aplog_error(NULL, 0, APLOG_ERR | APLOG_NOERRNO, ((request_rec *) SG(server_context))->server, "%s", message);
  315: #else
  316: 		log_error(message, ((request_rec *) SG(server_context))->server);
  317: #endif
  318: 	} else {
  319: 		fprintf(stderr, "%s\n", message);
  320: 	}
  321: }
  322: /* }}} */
  323: 
  324: /* {{{ php_apache_request_shutdown
  325:  */
  326: static void php_apache_request_shutdown(void *dummy)
  327: {
  328: 	TSRMLS_FETCH();
  329: 
  330: 	php_output_set_status(PHP_OUTPUT_DISABLED TSRMLS_CC);
  331: 	if (AP(in_request)) {
  332: 		AP(in_request) = 0;
  333: 		php_request_shutdown(dummy);
  334: 	}
  335: 	SG(server_context) = NULL; 
  336: 	/* 
  337: 	* The server context (request) is NOT invalid by the time 
  338: 	* run_cleanups() is called 
  339: 	*/
  340: }
  341: /* }}} */
  342: 
  343: /* {{{ php_apache_sapi_activate
  344:  */
  345: static int php_apache_sapi_activate(TSRMLS_D)
  346: {
  347: 	request_rec *r = (request_rec *) SG(server_context); 
  348: 
  349: 	/*
  350: 	 * For the Apache module version, this bit of code registers a cleanup
  351: 	 * function that gets triggered when our request pool is destroyed.
  352: 	 * We need this because at any point in our code we can be interrupted
  353: 	 * and that may happen before we have had time to free our memory.
  354: 	 * The php_request_shutdown function needs to free all outstanding allocated
  355: 	 * memory.  
  356: 	 */
  357: 	block_alarms();
  358: 	register_cleanup(r->pool, NULL, php_apache_request_shutdown, php_request_shutdown_for_exec);
  359: 	AP(in_request)=1;
  360: 	unblock_alarms();
  361: 
  362: 	/* Override the default headers_only value - sometimes "GET" requests should actually only
  363: 	 * send headers.
  364: 	 */
  365: 	SG(request_info).headers_only = r->header_only;
  366: 	return SUCCESS;
  367: }
  368: /* }}} */
  369: 
  370: /* {{{ php_apache_get_stat
  371:  */
  372: static struct stat *php_apache_get_stat(TSRMLS_D)
  373: {
  374: 	return &((request_rec *) SG(server_context))->finfo;
  375: }
  376: /* }}} */
  377: 
  378: /* {{{ php_apache_getenv
  379:  */
  380: static char *php_apache_getenv(char *name, size_t name_len TSRMLS_DC)
  381: {
  382: 	if (SG(server_context) == NULL) {
  383: 		return NULL;
  384: 	}
  385: 
  386: 	return (char *) table_get(((request_rec *) SG(server_context))->subprocess_env, name);
  387: }
  388: /* }}} */
  389: 
  390: /* {{{ sapi_apache_get_fd
  391:  */
  392: static int sapi_apache_get_fd(int *nfd TSRMLS_DC)
  393: {
  394: #if PHP_APACHE_HAVE_CLIENT_FD
  395: 	request_rec *r = SG(server_context);
  396: 	int fd;
  397: 
  398: 	fd = r->connection->client->fd;
  399: 	
  400: 	if (fd >= 0) {
  401: 		if (nfd) *nfd = fd;
  402: 		return SUCCESS;
  403: 	}
  404: #endif
  405: 	return FAILURE;
  406: }
  407: /* }}} */
  408: 
  409: /* {{{ sapi_apache_force_http_10
  410:  */
  411: static int sapi_apache_force_http_10(TSRMLS_D)
  412: {
  413: 	request_rec *r = SG(server_context);
  414: 	
  415: 	r->proto_num = HTTP_VERSION(1,0);
  416: 	
  417: 	return SUCCESS;
  418: }
  419: /* }}} */
  420: 
  421: /* {{{ sapi_apache_get_target_uid
  422:  */
  423: static int sapi_apache_get_target_uid(uid_t *obj TSRMLS_DC)
  424: {
  425: 	*obj = ap_user_id;
  426: 	return SUCCESS;
  427: }
  428: /* }}} */
  429: 
  430: /* {{{ sapi_apache_get_target_gid
  431:  */
  432: static int sapi_apache_get_target_gid(gid_t *obj TSRMLS_DC)
  433: {
  434: 	*obj = ap_group_id;
  435: 	return SUCCESS;
  436: }
  437: /* }}} */
  438: 
  439: /* {{{ php_apache_get_request_time
  440:  */
  441: static double php_apache_get_request_time(TSRMLS_D)
  442: {
  443: 	return (double) ((request_rec *)SG(server_context))->request_time;
  444: }
  445: /* }}} */
  446: 
  447: /* {{{ sapi_apache_child_terminate
  448:  */
  449: static void sapi_apache_child_terminate(TSRMLS_D)
  450: {
  451: #ifndef MULTITHREAD
  452: 	ap_child_terminate((request_rec *)SG(server_context));
  453: #endif
  454: }
  455: /* }}} */
  456: 
  457: /* {{{ sapi_module_struct apache_sapi_module
  458:  */
  459: static sapi_module_struct apache_sapi_module = {
  460: 	"apache",						/* name */
  461: 	"Apache",						/* pretty name */
  462: 									
  463: 	php_apache_startup,				/* startup */
  464: 	php_module_shutdown_wrapper,	/* shutdown */
  465: 
  466: 	php_apache_sapi_activate,		/* activate */
  467: 	NULL,							/* deactivate */
  468: 
  469: 	sapi_apache_ub_write,			/* unbuffered write */
  470: 	sapi_apache_flush,				/* flush */
  471: 	php_apache_get_stat,			/* get uid */
  472: 	php_apache_getenv,				/* getenv */
  473: 
  474: 	php_error,						/* error handler */
  475: 
  476: 	sapi_apache_header_handler,		/* header handler */
  477: 	sapi_apache_send_headers,		/* send headers handler */
  478: 	NULL,							/* send header handler */
  479: 
  480: 	sapi_apache_read_post,			/* read POST data */
  481: 	sapi_apache_read_cookies,		/* read Cookies */
  482: 
  483: 	sapi_apache_register_server_variables,		/* register server variables */
  484: 	php_apache_log_message,			/* Log message */
  485: 	php_apache_get_request_time,	/* Get request time */
  486: 	sapi_apache_child_terminate,
  487: 
  488: 	NULL,							/* php.ini path override */
  489: 
  490: #ifdef PHP_WIN32
  491: 	NULL,
  492: 	NULL,
  493: #else
  494: 	block_alarms,					/* Block interruptions */
  495: 	unblock_alarms,					/* Unblock interruptions */
  496: #endif
  497: 
  498: 	NULL,							/* default post reader */
  499: 	NULL,							/* treat data */
  500: 	NULL,							/* exe location */
  501: 	0,								/* ini ignore */
  502: 	0,								/* ini ignore cwd */
  503: 	sapi_apache_get_fd,
  504: 	sapi_apache_force_http_10,
  505: 	sapi_apache_get_target_uid,
  506: 	sapi_apache_get_target_gid
  507: };
  508: /* }}} */
  509: 
  510: /* {{{ php_restore_umask
  511:  */
  512: static void php_restore_umask(void)
  513: {
  514: 	umask(saved_umask);
  515: }
  516: /* }}} */
  517: 
  518: /* {{{ init_request_info
  519:  */
  520: static void init_request_info(TSRMLS_D)
  521: {
  522: 	request_rec *r = ((request_rec *) SG(server_context));
  523: 	char *content_length = (char *) table_get(r->subprocess_env, "CONTENT_LENGTH");
  524: 	const char *authorization=NULL;
  525: 	char *tmp, *tmp_user;
  526: 
  527: 	SG(request_info).query_string = r->args;
  528: 	SG(request_info).path_translated = r->filename;
  529: 	SG(request_info).request_uri = r->uri;
  530: 	SG(request_info).request_method = (char *)r->method;
  531: 	SG(request_info).content_type = (char *) table_get(r->subprocess_env, "CONTENT_TYPE");
  532: 	SG(request_info).content_length = (content_length ? atol(content_length) : 0);
  533: 	SG(sapi_headers).http_response_code = r->status;
  534: 	SG(request_info).proto_num = r->proto_num;
  535: 
  536: 	if (r->headers_in) {
  537: 		authorization = table_get(r->headers_in, "Authorization");
  538: 	}
  539: 
  540: 	SG(request_info).auth_user = NULL;
  541: 	SG(request_info).auth_password = NULL;
  542: 	SG(request_info).auth_digest = NULL;
  543: 
  544: 	if (authorization) {
  545: 		char *p = getword(r->pool, &authorization, ' ');
  546: 		if (!strcasecmp(p, "Basic")) {
  547: 			tmp = uudecode(r->pool, authorization);
  548: 			tmp_user = getword_nulls_nc(r->pool, &tmp, ':');
  549: 			if (tmp_user) {
  550: 				r->connection->user = pstrdup(r->connection->pool, tmp_user);
  551: 				r->connection->ap_auth_type = "Basic";
  552: 				SG(request_info).auth_user = estrdup(tmp_user);
  553: 			}
  554: 			if (tmp) {
  555: 				SG(request_info).auth_password = estrdup(tmp);
  556: 			}
  557: 		} else if (!strcasecmp(p, "Digest")) {
  558: 			r->connection->ap_auth_type = "Digest";
  559: 			SG(request_info).auth_digest = estrdup(authorization);
  560: 		}
  561: 	}
  562: }
  563: /* }}} */
  564: 
  565: /* {{{ php_apache_alter_ini_entries
  566:  */
  567: static int php_apache_alter_ini_entries(php_per_dir_entry *per_dir_entry TSRMLS_DC)
  568: {
  569: 	zend_alter_ini_entry(per_dir_entry->key, per_dir_entry->key_length+1, per_dir_entry->value, per_dir_entry->value_length, per_dir_entry->type, per_dir_entry->htaccess?PHP_INI_STAGE_HTACCESS:PHP_INI_STAGE_ACTIVATE);
  570: 	return 0;
  571: }
  572: /* }}} */
  573: 
  574: /* {{{ php_apache_get_default_mimetype
  575:  */
  576: static char *php_apache_get_default_mimetype(request_rec *r TSRMLS_DC)
  577: {
  578: 	
  579: 	char *mimetype;
  580: 	if (SG(default_mimetype) || SG(default_charset)) {
  581: 		/* Assume output will be of the default MIME type.  Individual
  582: 		   scripts may change this later. */
  583: 		char *tmpmimetype;
  584: 		tmpmimetype = sapi_get_default_content_type(TSRMLS_C);
  585: 		mimetype = pstrdup(r->pool, tmpmimetype);
  586: 		efree(tmpmimetype);
  587: 	} else {
  588: 		mimetype = SAPI_DEFAULT_MIMETYPE "; charset=" SAPI_DEFAULT_CHARSET;
  589: 	}
  590: 	return mimetype;
  591: }
  592: /* }}} */
  593: 
  594: /* {{{ send_php
  595:  */
  596: static int send_php(request_rec *r, int display_source_mode, char *filename)
  597: {
  598: 	int retval;
  599: 	HashTable *per_dir_conf;
  600: 	TSRMLS_FETCH();
  601: 
  602: 	if (AP(in_request)) {
  603: 		zend_file_handle fh;
  604: 
  605: 		fh.filename = r->filename;
  606: 		fh.opened_path = NULL;
  607: 		fh.free_filename = 0;
  608: 		fh.type = ZEND_HANDLE_FILENAME;
  609: 
  610: 		zend_execute_scripts(ZEND_INCLUDE TSRMLS_CC, NULL, 1, &fh);
  611: 		return OK;
  612: 	}
  613: 
  614: 	SG(server_context) = r;
  615: 
  616: 	zend_first_try {
  617: 
  618: 		/* Make sure file exists */
  619: 		if (filename == NULL && r->finfo.st_mode == 0) {
  620: 			return DECLINED;
  621: 		}
  622: 
  623: 		per_dir_conf = (HashTable *) get_module_config(r->per_dir_config, &php5_module);
  624: 		if (per_dir_conf) {
  625: 			zend_hash_apply((HashTable *) per_dir_conf, (apply_func_t) php_apache_alter_ini_entries TSRMLS_CC);
  626: 		}
  627: 		
  628: 		/* If PHP parser engine has been turned off with an "engine off"
  629: 		 * directive, then decline to handle this request
  630: 		 */
  631: 		if (!AP(engine)) {
  632: 			r->content_type = php_apache_get_default_mimetype(r TSRMLS_CC);
  633: 			zend_try {
  634: 				zend_ini_deactivate(TSRMLS_C);
  635: 			} zend_end_try();
  636: 			return DECLINED;
  637: 		}
  638: 		if (filename == NULL) {
  639: 			filename = r->filename;
  640: 		}
  641: 
  642: 		/* Apache 1.2 has a more complex mechanism for reading POST data */
  643: #if MODULE_MAGIC_NUMBER > 19961007
  644: 		if ((retval = setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) {
  645: 			zend_try {
  646: 				zend_ini_deactivate(TSRMLS_C);
  647: 			} zend_end_try();
  648: 			return retval;
  649: 		}
  650: #endif
  651: 
  652: 		if (AP(last_modified)) {
  653: #if MODULE_MAGIC_NUMBER < 19970912
  654: 			if ((retval = set_last_modified(r, r->finfo.st_mtime))) {
  655: 				zend_try {
  656: 					zend_ini_deactivate(TSRMLS_C);
  657: 				} zend_end_try();
  658: 				return retval;
  659: 			}
  660: #else
  661: 			update_mtime (r, r->finfo.st_mtime);
  662: 			set_last_modified(r);
  663: 			set_etag(r);
  664: #endif
  665: 		}
  666: 		/* Assume output will be of the default MIME type.  Individual
  667: 		   scripts may change this later in the request. */
  668: 		r->content_type = php_apache_get_default_mimetype(r TSRMLS_CC);
  669: 
  670: 		/* Init timeout */
  671: 		hard_timeout("send", r);
  672: 
  673: 		php_save_umask();
  674: 		add_common_vars(r);
  675: 		add_cgi_vars(r);
  676: 
  677: 		init_request_info(TSRMLS_C);
  678: 		apache_php_module_main(r, display_source_mode TSRMLS_CC);
  679: 
  680: 		/* Done, restore umask, turn off timeout, close file and return */
  681: 		php_restore_umask();
  682: 		kill_timeout(r);
  683: 	} zend_end_try();
  684: 
  685: 	return OK;
  686: }
  687: /* }}} */
  688: 
  689: /* {{{ send_parsed_php
  690:  */
  691: static int send_parsed_php(request_rec * r)
  692: {
  693: 	int result = send_php(r, 0, NULL);
  694: 	TSRMLS_FETCH();
  695:  
  696: 	ap_table_setn(r->notes, "mod_php_memory_usage",
  697: 		ap_psprintf(r->pool, "%lu", zend_memory_peak_usage(1 TSRMLS_CC)));
  698: 
  699: 	return result;
  700: }
  701: /* }}} */
  702: 
  703: /* {{{ send_parsed_php_source
  704:  */
  705: static int send_parsed_php_source(request_rec * r)
  706: {
  707: 	return send_php(r, 1, NULL);
  708: }
  709: /* }}} */
  710: 
  711: /* {{{ destroy_per_dir_entry
  712:  */
  713: static void destroy_per_dir_entry(php_per_dir_entry *per_dir_entry)
  714: {
  715: 	free(per_dir_entry->key);
  716: 	free(per_dir_entry->value);
  717: }
  718: /* }}} */
  719: 
  720: /* {{{ copy_per_dir_entry
  721:  */
  722: static void copy_per_dir_entry(php_per_dir_entry *per_dir_entry)
  723: {
  724: 	php_per_dir_entry tmp = *per_dir_entry;
  725: 
  726: 	per_dir_entry->key = (char *) malloc(tmp.key_length+1);
  727: 	memcpy(per_dir_entry->key, tmp.key, tmp.key_length);
  728: 	per_dir_entry->key[per_dir_entry->key_length] = 0;
  729: 
  730: 	per_dir_entry->value = (char *) malloc(tmp.value_length+1);
  731: 	memcpy(per_dir_entry->value, tmp.value, tmp.value_length);
  732: 	per_dir_entry->value[per_dir_entry->value_length] = 0;
  733: }
  734: /* }}} */
  735: 
  736: /* {{{ should_overwrite_per_dir_entry
  737:  */
  738: static zend_bool should_overwrite_per_dir_entry(HashTable *target_ht, php_per_dir_entry *new_per_dir_entry, zend_hash_key *hash_key, void *pData)
  739: {
  740: 	php_per_dir_entry *orig_per_dir_entry;
  741: 
  742: 	if (zend_hash_find(target_ht, hash_key->arKey, hash_key->nKeyLength, (void **) &orig_per_dir_entry)==FAILURE) {
  743: 		return 1; /* does not exist in dest, copy from source */
  744: 	}
  745: 
  746: 	if (orig_per_dir_entry->type==PHP_INI_SYSTEM
  747: 		&& new_per_dir_entry->type!=PHP_INI_SYSTEM) {
  748: 		return 0;
  749: 	} else {
  750: 		return 1;
  751: 	}
  752: }
  753: /* }}} */
  754: 
  755: /* {{{ php_destroy_per_dir_info
  756:  */
  757: static void php_destroy_per_dir_info(HashTable *per_dir_info)
  758: {
  759: 	zend_hash_destroy(per_dir_info);
  760: 	free(per_dir_info);
  761: }
  762: /* }}} */
  763: 
  764: /* {{{ php_create_dir
  765:  */
  766: static void *php_create_dir(pool *p, char *dummy)
  767: {
  768: 	HashTable *per_dir_info;
  769: 
  770: 	per_dir_info = (HashTable *) malloc(sizeof(HashTable));
  771: 	zend_hash_init_ex(per_dir_info, 5, NULL, (void (*)(void *)) destroy_per_dir_entry, 1, 0);
  772: 	register_cleanup(p, (void *) per_dir_info, (void (*)(void *)) php_destroy_per_dir_info, (void (*)(void *)) zend_hash_destroy);
  773: 
  774: 	return per_dir_info;
  775: }
  776: /* }}} */
  777: 
  778: /* {{{ php_merge_dir
  779:  */
  780: static void *php_merge_dir(pool *p, void *basev, void *addv)
  781: {
  782: 	/* This function *must* not modify addv or basev */
  783: 	HashTable *new;
  784: 
  785: 	/* need a copy of addv to merge */
  786: 	new = php_create_dir(p, "php_merge_dir");
  787: 	zend_hash_copy(new, (HashTable *) basev, (copy_ctor_func_t) copy_per_dir_entry, NULL, sizeof(php_per_dir_entry));
  788: 
  789: 	zend_hash_merge_ex(new, (HashTable *) addv, (copy_ctor_func_t) copy_per_dir_entry, sizeof(php_per_dir_entry), (merge_checker_func_t) should_overwrite_per_dir_entry, NULL);
  790: 	return new;
  791: }
  792: /* }}} */
  793: 
  794: /* {{{ php_apache_value_handler_ex
  795:  */
  796: static CONST_PREFIX char *php_apache_value_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode)
  797: {
  798: 	php_per_dir_entry per_dir_entry;
  799: 
  800: 	if (!apache_php_initialized) {
  801: 		apache_php_initialized = 1;
  802: #ifdef ZTS
  803: 		tsrm_startup(1, 1, 0, NULL);
  804: #endif
  805: 		sapi_startup(&apache_sapi_module);
  806: 		php_apache_startup(&apache_sapi_module);
  807: 	}
  808: 	per_dir_entry.type = mode;
  809: 	per_dir_entry.htaccess = ((cmd->override & (RSRC_CONF|ACCESS_CONF)) == 0);
  810: 
  811: 	if (strcasecmp(arg2, "none") == 0) {
  812: 		arg2 = "";
  813: 	}
  814: 
  815: 	per_dir_entry.key_length = strlen(arg1);
  816: 	per_dir_entry.value_length = strlen(arg2);
  817: 
  818: 	per_dir_entry.key = (char *) malloc(per_dir_entry.key_length+1);
  819: 	memcpy(per_dir_entry.key, arg1, per_dir_entry.key_length);
  820: 	per_dir_entry.key[per_dir_entry.key_length] = 0;
  821: 
  822: 	per_dir_entry.value = (char *) malloc(per_dir_entry.value_length+1);
  823: 	memcpy(per_dir_entry.value, arg2, per_dir_entry.value_length);
  824: 	per_dir_entry.value[per_dir_entry.value_length] = 0;
  825: 
  826: 	zend_hash_update(conf, per_dir_entry.key, per_dir_entry.key_length, &per_dir_entry, sizeof(php_per_dir_entry), NULL);
  827: 	return NULL;
  828: }
  829: /* }}} */
  830: 
  831: /* {{{ php_apache_value_handler
  832:  */
  833: static CONST_PREFIX char *php_apache_value_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2)
  834: {
  835: 	return php_apache_value_handler_ex(cmd, conf, arg1, arg2, PHP_INI_PERDIR);
  836: }
  837: /* }}} */
  838: 
  839: /* {{{ php_apache_admin_value_handler
  840:  */
  841: static CONST_PREFIX char *php_apache_admin_value_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2)
  842: {
  843: 	return php_apache_value_handler_ex(cmd, conf, arg1, arg2, PHP_INI_SYSTEM);
  844: }
  845: /* }}} */
  846: 
  847: /* {{{ php_apache_flag_handler_ex
  848:  */
  849: static CONST_PREFIX char *php_apache_flag_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode)
  850: {
  851: 	char bool_val[2];
  852: 
  853: 	if (!strcasecmp(arg2, "On") || (arg2[0] == '1' && arg2[1] == '\0')) {
  854: 		bool_val[0] = '1';
  855: 	} else {
  856: 		bool_val[0] = '0';
  857: 	}
  858: 	bool_val[1] = 0;
  859: 	
  860: 	return php_apache_value_handler_ex(cmd, conf, arg1, bool_val, mode);
  861: }
  862: /* }}} */
  863: 
  864: /* {{{ php_apache_flag_handler
  865:  */
  866: static CONST_PREFIX char *php_apache_flag_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2)
  867: {
  868: 	return php_apache_flag_handler_ex(cmd, conf, arg1, arg2, PHP_INI_PERDIR);
  869: }
  870: /* }}} */
  871: 
  872: /* {{{ php_apache_admin_flag_handler
  873:  */
  874: static CONST_PREFIX char *php_apache_admin_flag_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2)
  875: {
  876: 	return php_apache_flag_handler_ex(cmd, conf, arg1, arg2, PHP_INI_SYSTEM);
  877: }
  878: /* }}} */
  879: 
  880: /* {{{ php_apache_phpini_set
  881:  */
  882: static CONST_PREFIX char *php_apache_phpini_set(cmd_parms *cmd, HashTable *conf, char *arg)
  883: {
  884: 	if (apache_sapi_module.php_ini_path_override) {
  885: 		return "Only first PHPINIDir directive honored per configuration tree - subsequent ones ignored";
  886: 	}
  887: 	apache_sapi_module.php_ini_path_override = ap_server_root_relative(cmd->pool, arg);
  888: 	return NULL;
  889: }
  890: /* }}} */
  891: 
  892: /* {{{ int php_xbithack_handler(request_rec * r)
  893:  */
  894: static int php_xbithack_handler(request_rec * r)
  895: {
  896: 	HashTable *per_dir_conf;
  897: 	TSRMLS_FETCH();
  898: 
  899: 	if (!(r->finfo.st_mode & S_IXUSR)) {
  900: 		return DECLINED;
  901: 	}
  902: 	per_dir_conf = (HashTable *) get_module_config(r->per_dir_config, &php5_module);
  903: 	if (per_dir_conf) {
  904: 		zend_hash_apply((HashTable *) per_dir_conf, (apply_func_t) php_apache_alter_ini_entries TSRMLS_CC);
  905: 	}
  906: 	if(!AP(xbithack)) {
  907: 		zend_try {
  908: 			zend_ini_deactivate(TSRMLS_C);
  909: 		} zend_end_try();
  910: 		return DECLINED;
  911: 	}
  912: 	return send_parsed_php(r);
  913: }
  914: /* }}} */
  915: 
  916: /* {{{ apache_php_module_shutdown_wrapper
  917:  */
  918: static void apache_php_module_shutdown_wrapper(void)
  919: {
  920: 	apache_php_initialized = 0;
  921: 	apache_sapi_module.shutdown(&apache_sapi_module);
  922: 
  923: #if MODULE_MAGIC_NUMBER >= 19970728
  924: 	/* This function is only called on server exit if the apache API
  925: 	 * child_exit handler exists, so shutdown globally 
  926: 	 */
  927: 	sapi_shutdown();
  928: #endif
  929: 
  930: #ifdef ZTS
  931: 	tsrm_shutdown();
  932: #endif
  933: }
  934: /* }}} */
  935: 
  936: #if MODULE_MAGIC_NUMBER >= 19970728
  937: /* {{{ php_child_exit_handler
  938:  */
  939: static void php_child_exit_handler(server_rec *s, pool *p)
  940: {
  941: /*	apache_php_initialized = 0; */
  942: 	apache_sapi_module.shutdown(&apache_sapi_module);
  943: 
  944: #ifdef ZTS
  945: 	tsrm_shutdown();
  946: #endif
  947: }
  948: /* }}} */
  949: #endif
  950: 
  951: /* {{{ void php_init_handler(server_rec *s, pool *p)
  952:  */
  953: static void php_init_handler(server_rec *s, pool *p)
  954: {
  955: 	register_cleanup(p, NULL, (void (*)(void *))apache_php_module_shutdown_wrapper, (void (*)(void *))php_module_shutdown_for_exec);
  956: 	if (!apache_php_initialized) {
  957: 		apache_php_initialized = 1;
  958: #ifdef ZTS
  959: 		tsrm_startup(1, 1, 0, NULL);
  960: #endif
  961: 		sapi_startup(&apache_sapi_module);
  962: 		php_apache_startup(&apache_sapi_module);
  963: 	}
  964: #if MODULE_MAGIC_NUMBER >= 19980527
  965: 	{
  966: 		TSRMLS_FETCH();
  967: 		if (PG(expose_php)) {
  968: 			ap_add_version_component("PHP/" PHP_VERSION);
  969: 		}
  970: 	}
  971: #endif
  972: }
  973: /* }}} */
  974: 
  975: /* {{{ handler_rec php_handlers[]
  976:  */
  977: handler_rec php_handlers[] =
  978: {
  979: 	{"application/x-httpd-php", send_parsed_php},
  980: 	{"application/x-httpd-php-source", send_parsed_php_source},
  981: 	{"text/html", php_xbithack_handler},
  982: 	{NULL}
  983: };
  984: /* }}} */
  985: 
  986: /* {{{ command_rec php_commands[]
  987:  */
  988: command_rec php_commands[] =
  989: {
  990: 	{"php_value",		php_apache_value_handler, NULL, OR_OPTIONS, TAKE2, "PHP Value Modifier"},
  991: 	{"php_flag",		php_apache_flag_handler, NULL, OR_OPTIONS, TAKE2, "PHP Flag Modifier"},
  992: 	{"php_admin_value",	php_apache_admin_value_handler, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, "PHP Value Modifier (Admin)"},
  993: 	{"php_admin_flag",	php_apache_admin_flag_handler, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, "PHP Flag Modifier (Admin)"},
  994: 	{"PHPINIDir",		php_apache_phpini_set, NULL, RSRC_CONF, TAKE1, "Directory containing the php.ini file"},
  995: 	{NULL}
  996: };
  997: /* }}} */
  998: 
  999: /* {{{ odule MODULE_VAR_EXPORT php5_module
 1000:  */
 1001: module MODULE_VAR_EXPORT php5_module =
 1002: {
 1003: 	STANDARD_MODULE_STUFF,
 1004: 	php_init_handler,			/* initializer */
 1005: 	php_create_dir,				/* per-directory config creator */
 1006: 	php_merge_dir,				/* dir merger */
 1007: 	NULL,						/* per-server config creator */
 1008: 	NULL, 						/* merge server config */
 1009: 	php_commands,				/* command table */
 1010: 	php_handlers,				/* handlers */
 1011: 	NULL,						/* filename translation */
 1012: 	NULL,						/* check_user_id */
 1013: 	NULL,						/* check auth */
 1014: 	NULL,						/* check access */
 1015: 	NULL,						/* type_checker */
 1016: 	NULL,						/* fixups */
 1017: 	NULL						/* logger */
 1018: #if MODULE_MAGIC_NUMBER >= 19970103
 1019: 	, NULL						/* header parser */
 1020: #endif
 1021: #if MODULE_MAGIC_NUMBER >= 19970719
 1022: 	, NULL						/* child_init */
 1023: #endif
 1024: #if MODULE_MAGIC_NUMBER >= 19970728
 1025: 	, php_child_exit_handler		/* child_exit */
 1026: #endif
 1027: #if MODULE_MAGIC_NUMBER >= 19970902
 1028: 	, NULL						/* post read-request */
 1029: #endif
 1030: };
 1031: /* }}} */
 1032: 
 1033: /*
 1034:  * Local variables:
 1035:  * tab-width: 4
 1036:  * c-basic-offset: 4
 1037:  * End:
 1038:  * vim600: sw=4 ts=4 fdm=marker
 1039:  * vim<600: sw=4 ts=4
 1040:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>