我们知道定义sapi之前,首先要定义sapi_module_struct这个结构,相看源码:/soft/php-5.2.9/sapi/apache2handler/sapi_apache2.c,可以看到定义该结构,我直接复制过来:
[cpp]
static sapi_module_struct apache2_sapi_module = {
apache2handler,
apache 2.0 handler,
php_apache2_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */
null, /* activate */
null, /* deactivate */
php_apache_sapi_ub_write, /* unbuffered write */
php_apache_sapi_flush, /* flush */
php_apache_sapi_get_stat, /* get uid */
php_apache_sapi_getenv, /* getenv */
php_error, /* error handler */
php_apache_sapi_header_handler, /* header handler */
php_apache_sapi_send_headers, /* send headers handler */
null, /* send header handler */
php_apache_sapi_read_post, /* read post data */
php_apache_sapi_read_cookies, /* read cookies */
php_apache_sapi_register_variables,
php_apache_sapi_log_message, /* log message */
php_apache_sapi_get_request_time, /* request time */
standard_sapi_module_properties
};
1,php_apache2_startup:当通过apache调用php时,这个函数会被调用。该函数定义如下,主要是对php进行初始化。
[cpp]
static int php_apache2_startup(sapi_module_struct *sapi_module)
{
if (php_module_startup(sapi_module, &php_apache_module, 1)==failure) {
return failure;
}
return success;
}
2,php_module_shutdown_wrapper :php的关闭函数。
3,php会在每个request的时候,处理一些初始化,资源分配的事务。这部分就是activate字段要定义的。
4,与activate的函数,就是deactiveate,它会提供一个handler, 用来处理收尾工作。
5,php_apache_sapi_ub_write:提供一个向response数据写的接口。
[cpp]
static int
php_apache_sapi_ub_write(const char *str, uint str_length tsrmls_dc)
{
request_rec *r;
php_struct *ctx;
ctx = sg(server_context);
r = ctx->r;
if (ap_rwrite(str, str_length, r) php_handle_aborted_connection();
}
return str_length; /* we always consume all the data passed to us. */
}
6,php_apache_sapi_flush:提供给zend刷新缓存的句柄。
[cpp]
static void
php_apache_sapi_flush(void *server_context)
{
php_struct *ctx;
request_rec *r;
tsrmls_fetch();
ctx = server_context;
/* if we haven't registered a server_context yet,
* then don't bother flushing. */
if (!server_context) {
return;
}
r = ctx->r;
sapi_send_headers(tsrmls_c);
r->status = sg(sapi_headers).http_response_code;
sg(headers_sent) = 1;
if (ap_rflush(r) connection->aborted) {
php_handle_aborted_connection();
}
}
7,php_apache_sapi_get_stat:这部分用来让zend可以验证一个要执行脚本文件的state,从而判断文件是否据有执行权限等等。
[cpp]
static struct stat*
php_apache_sapi_get_stat(tsrmls_d)
{
php_struct *ctx = sg(server_context);
ctx->finfo.st_uid = ctx->r->finfo.user;
ctx->finfo.st_gid = ctx->r->finfo.group;
ctx->finfo.st_dev = ctx->r->finfo.device;
ctx->finfo.st_ino = ctx->r->finfo.inode;
#if defined(netware) && defined(clib_stat_patch)
ctx->finfo.st_atime.tv_sec = apr_time_sec(ctx->r->finfo.atime);
ctx->finfo.st_mtime.tv_sec = apr_time_sec(ctx->r->finfo.mtime);
ctx->finfo.st_ctime.tv_sec = apr_time_sec(ctx->r->finfo.ctime);
#else
ctx->finfo.st_atime = apr_time_sec(ctx->r->finfo.atime);
ctx->finfo.st_mtime = apr_time_sec(ctx->r->finfo.mtime);
ctx->finfo.st_ctime = apr_time_sec(ctx->r->finfo.ctime);
#endif
ctx->finfo.st_size = ctx->r->finfo.size;
ctx->finfo.st_nlink = ctx->r->finfo.nlink;
return &ctx->finfo;
}
8,php_apache_sapi_getenv:为zend提供了一个根据name来查找环境变量的接口,当我们在脚本中调用getenv的时候,就会间接的调用这个句柄。
[cpp]
static char *
php_apache_sapi_getenv(char *name, size_t name_len tsrmls_dc)
{
php_struct *ctx = sg(server_context);
const char *env_var;
env_var = apr_table_get(ctx->r->subprocess_env, name);
return (char *) env_var;
}
9,php_error:错误处理函数,直接调用php错误处理函数。
10,php_apache_sapi_header_handler:在调用php的header()函数时,会调用这个函数。
[cpp]
static int
php_apache_sapi_header_handler(sapi_header_struct *sapi_header,sapi_headers_struct *sapi_headers tsrmls_dc)
{
php_struct *ctx;
char *val, *ptr;
ctx = sg(server_context);
val = strchr(sapi_header->header, ':');
if (!val) {
sapi_free_header(sapi_header);
return 0;
}
ptr = val;
*val = '\0';
do {
val++;
} while (*val == ' ');
if (!strcasecmp(sapi_header->header, content-type)) {
if (ctx->content_type) {
efree(ctx->content_type);
}
ctx->content_type = estrdup(val);
} else if (sapi_header->replace) {
apr_table_set(ctx->r->headers_out, sapi_header->header, val);
} else {
apr_table_add(ctx->r->headers_out, sapi_header->header, val);
}
*ptr = ':';
return sapi_header_add;
}
11,php_apache_sapi_send_headers:当要真正发送header的时候,这个函数会被调用。
[cpp]
static int
php_apache_sapi_send_headers(sapi_headers_struct *sapi_headers tsrmls_dc)
{
php_struct *ctx = sg(server_context);
const char *sline = sg(sapi_headers).http_status_line;
ctx->r->status = sg(sapi_headers).http_response_code;
/* httpd requires that r->status_line is set to the first digit of
* the status-code: */
if (sline && strlen(sline) > 12 && strncmp(sline, http/1., 7) == 0 && sline[8] == ' ') {
ctx->r->status_line = apr_pstrdup(ctx->r->pool, sline + 9);
ctx->r->proto_num = 1000 + (sline[7]-'0');
if ((sline[7]-'0') == 0) {
apr_table_set(ctx->r->subprocess_env, force-response-1.0, true);
}
}
/* call ap_set_content_type only once, else each time we call it,
configured output filters for that content type will be added */
if (!ctx->content_type) {
ctx->content_type = sapi_get_default_content_type(tsrmls_c);
}
ap_set_content_type(ctx->r, apr_pstrdup(ctx->r->pool, ctx->content_type));
efree(ctx->content_type);
ctx->content_type = null;
return sapi_header_sent_successfully;
}
12,在php_apache_sapi_send_headers指针下面有一个域,用来指明发送每一个单独的header时调用。
13,php_apache_sapi_read_post:表示如何读取post数据。
[cpp]
static int
php_apache_sapi_read_post(char *buf, uint count_bytes tsrmls_dc)
{
apr_size_t len, tlen=0;
php_struct *ctx = sg(server_context);
request_rec *r;
apr_bucket_brigade *brigade;
r = ctx->r;
brigade = ctx->brigade;
len = count_bytes;
/*
* this loop is needed because ap_get_brigade() can return us partial data
* which would cause premature termination of request read. therefor we
* need to make sure that if data is available we fill the buffer completely.
*/
while (ap_get_brigade(r->input_filters, brigade, ap_mode_readbytes, apr_block_read, len) == apr_success) {
apr_brigade_flatten(brigade, buf, &len);
apr_brigade_cleanup(brigade);
tlen += len;
if (tlen == count_bytes || !len) {
break;
}
buf += len;
len = count_bytes - tlen;
}
return tlen;
}
14,php_apache_sapi_read_cookie:如何读取cookie。
[cpp]
static char *
php_apache_sapi_read_cookies(tsrmls_d)
{
php_struct *ctx = sg(server_context);
const char *http_cookie;
http_cookie = apr_table_get(ctx->r->headers_in, cookie);
/* the sapi interface should use 'const char *' */
return (char *) http_cookie;
}
15,php_apache_sapi_register_variables:提供接口,用于给$_server[]数组提供变量。
[cpp]
static void
php_apache_sapi_register_variables(zval *track_vars_array tsrmls_dc)
{
php_struct *ctx = sg(server_context);
const apr_array_header_t *arr = apr_table_elts(ctx->r->subprocess_env);
char *key, *val;
int new_val_len;
apr_array_foreach_open(arr, key, val)
if (!val) {
val = ;
}
if (sapi_module.input_filter(parse_server, key, &val, strlen(val), &new_val_len tsrmls_cc)) {
php_register_variable_safe(key, val, new_val_len, track_vars_array tsrmls_cc);
}
apr_array_foreach_close()
if (sapi_module.input_filter(parse_server, php_self, &ctx->r->uri, strlen(ctx->r->uri), &new_val_len tsrmls_cc)) {
php_register_variable_safe(php_self, ctx->r->uri, new_val_len, track_vars_array tsrmls_cc);
}
}
16,php_apache_sapi_log_message:输出错误信息。
[cpp]
static void php_apache_sapi_log_message(char *msg)
{
php_struct *ctx;
tsrmls_fetch();
ctx = sg(server_context);
if (ctx == null) { /* we haven't initialized our ctx yet, oh well */
ap_log_error(aplog_mark, aplog_err | aplog_startup, 0, null, %s, msg);
} else {
ap_log_rerror(aplog_mark, aplog_err, 0, ctx->r, %s, msg);
}
}
17,php_apache_sapi_get_request_time:获取请求时间。
[cpp]
static time_t php_apache_sapi_get_request_time(tsrmls_d) {
php_struct *ctx = sg(server_context);
return apr_time_sec(ctx->r->request_time);
}
这就完成了apache的sapi定义。之后,就是当用户用url请求apache服务,这些函数指针就会在适当的时候,发挥作用了(被调用)。
http://www.bkjia.com/phpjc/477971.htmlwww.bkjia.comtruehttp://www.bkjia.com/phpjc/477971.htmltecharticle我们知道定义sapi之前,首先要定义sapi_module_struct这个结构,相看源码:/soft/php-5.2.9/sapi/apache2handler/sapi_apache2.c,可以看到定义该结构,我直...