谈谈你的理解ZendSAPIs(ZendSAPI内部)

SAPI:服务器抽象API,学生谁研究了PHP架构,应该知道这个东东的重要性。它提供了一个接口,使PHP与其他应用程序进行交互。本文将不详细介绍每个PHP SAPI,但只有最简单的CGI SAPI说明SAPI的机制。

首先,让我们看看PHP的体系结构图:

图1 PHP体系结构

SAPI提供与外部通信接口。对于php5.2,它提供了许多种类的SAPI默认情况下,普通mod_php5 Apache,IIS的ISAPI CGI,壳CLI。本文从CGI CGI,并介绍了它的机理。虽然CGI是简单的,但不要担心,它包含了大部分的内容,足以给你的SAPI的工作原理有深刻的理解。



定义一个SAPI,先定义一个sapi_module_struct看看php-src / / / cgi_main CGI SAPI。C:


* /
静态sapi_module_struct cgi_sapi_module = { {
如果php_fastcgi #
cgi-fcgi
CGI/FastCGI
其他#
CGI
CGI
# endif

php_cgi_startup,启动 / * * /
php_module_shutdown_wrapper,关机 / * * /

空,激活
sapi_cgi_deactivate,停用 / * * /

sapi_cgibin_ub_write,缓冲写 / * * /
sapi_cgibin_flush,冲洗 / * * /
零,得到UID / * * /
sapi_cgibin_getenv,getenv / * * /

php_error,错误处理程序 / * * /

空头处理程序
sapi_cgi_send_headers,送头处理 / * * /
空,发送头处理程序

sapi_cgi_read_post,读取数据后 / * * /
sapi_cgi_read_cookies,读取cookie / * * /

sapi_cgi_register_variables,登记服务器变量 / * * /
sapi_cgi_log_message,日志消息 / * * /
NULL,获取请求时间

standard_sapi_module_properties
};


这个结构包含一些常量,如姓名,可我们打电话的时候,php_info()。一些初始化,结束功能,和一些函数指针告诉Zend如何获得,输出数据。

1。php_cgi_startup,当应用程序调用PHP函数调用。对于CGI,它只调用PHP的初始化函数:




静态变量php_cgi_startup(sapi_module_struct * sapi_module)
{
如果(php_module_startup(sapi_module,null,0)= =失败){
返回失败;
}
返回成功;
}




2。php_module_shutdown_wrapper,用于PHP的简单封装的封闭功能,只是一个简单的电话php_module_shutdown;

三.PHP将每个请求处理的初始化和配置资源的交易。这一部分是通过激活域定义,并从上面的结构中我们可以看到,它不提供CGI的初始化处理,mod_php,那是不同的。他希望在Apache池中注册资源析构函数、应用空间、初始化环境变量,等等。

4。sapi_cgi_deactivate,这是相应的激活作用。顾名思义,它将提供一个处理终结工作的处理程序。CGI,它只是刷新缓冲区以保证用户在Zend关闭所有输出数据。


静态变量sapi_cgi_deactivate(tsrmls_d)
{
只有当SAPI开始冲洗。/ The reasons are:
1。SAPI停用从两个地方称之为:模块的初始化要求停机
2。当第一个调用发生时,请求没有设置
FastCGI。
* /
如果(SG(sapi_started)){
sapi_cgibin_flush(SG(server_context));
}
返回成功;
}


5。sapi_cgibin_ub_write,这hanlder告诉Zend如何输出数据。对于mod_php,这个功能提供写入响应数据的接口,和CGI,它只是写入标准输出:




静态内联size_t sapi_cgibin_single_write(const char* str,单位str_length tsrmls_dc)
{
# ifdef php_write_stdout
长RET;
其他#
size_t RET;
# endif
如果php_fastcgi #
如果(fcgi_is_fastcgi()){
fcgi_request *要求=(fcgi_request *)SG(server_context);
长fcgi_write ret =(请求,fcgi_stdout,STR,str_length);
如果(RET < = 0){
返回0;
}
返回页首;
}
# endif
# ifdef php_write_stdout
ret =写(stdout_fileno,STR,str_length);
如果(RET 0)返回0;
返回页首;
其他#
ret = fwrite(STR,1 min(str_length,16384)、标准输出);
返回页首;
# endif
}
静态变量sapi_cgibin_ub_write(const char* str,单位str_length tsrmls_dc)
{
const char* ptr = str;
单位剩余= str_length;
size_t RET;
当(剩余> 0){
ret = sapi_cgibin_single_write(PTR,剩下的tsrmls_cc);
如果(!RET){
php_handle_aborted_connection();
str_length剩余收益;
}
ptr = ret;
剩余的= RET;
}
返回str_length;
}


真正的写作逻辑是剥离出一个简单的方法来写FastCGI兼容。

6。sapi_cgibin_flush,这是函数句柄提供刷新CGI Zend,缓存,它只是一个简单的调用系统提供的函数;

7.null,这部分是用来启用Zend验证状态执行脚本文件,以确定文件是否有执行权限等。CGI不提供。

8。sapi_cgibin_getenv为Zend基于环境变量的名字找到一个接口。对于mod_php5,我们调用getenv脚本时,我们会间接调用这个句柄,CGI,因为他的运行机制是CLI非常相似,给家长直接电话外壳,因此它只是调用系统提供的genenv。


sapi_cgibin_getenv静态字符串(char *的名字,size_t name_len tsrmls_dc)
{
如果php_fastcgi #
当PHP的/ mod_fastcgi没有定期的环境开始
提供给PHP。它总是发送到PHP的
请求。所以我们必须自己查找
变量。这可能会更快一些。
如果(fcgi_is_fastcgi()){
fcgi_request *要求=(fcgi_request *)SG(server_context);
返回fcgi_getenv(要求名字,name_len);
}
# endif
如果或者FastCGI和 / CGI环境不好
检查常规环境。
返回getenv(名字);
}


9。php_error,在这里治疗,误差函数,说句题外话,我最后一次看到PHP的邮件列表中提到的错误处理PHP面向对象机制,即,重写这个函数处理,所以当错误发生时,投掷是一个例外,就是简单的调用PHP的CGI提供的错误处理功能。

10。当我们调用PHP的头()函数时,这个函数将被调用,这是不为CGI提供的。

11。sapi_cgi_send_headers,这个函数将被调用的时候,头真是送的,一般来说,在任何输出被发送:


静态变量sapi_cgi_send_headers(sapi_headers_struct * sapi_headers tsrmls_dc)
{
sapi_cgi_max_header_length中字符{ };
sapi_header_struct×h;
zend_llist_position POS;
如果(SG(request_info)。no_headers = = 1){
返回sapi_header_sent_successfully;
}
如果(cgi_nph | | SG(sapi_headers http_response_code)!= 200)
{
Int len;
如果(rfc2616_headers SG(sapi_headers)。http_status_line){
len = snprintf(buf,sapi_cgi_max_header_length,

如果(Len > sapi_cgi_max_header_length){
sapi_cgi_max_header_length len =;
}
{人}
len = sprintf(buf,状态:%d R
}
phpwrite_h(buf,Len);
}
H =(sapi_header_struct *)zend_llist_get_first_ex(sapi_headers ->页眉,POS);
当(h){
防止crlfcrlf / * * /
如果(H - > header_len){
phpwrite_h(H ->页眉、H > header_len);
phpwrite_h( R
}
H =(sapi_header_struct *)zend_llist_get_next_ex(sapi_headers ->页眉,POS);
}
phpwrite_h( R
返回sapi_header_sent_successfully;
}


12。NULL,用于分别发送每个头,CGI不提供

13。sapi_cgi_read_post,这表明如何得到处理后的数据。如果我们做了CGI编程,我们知道CGI从stdin读取数据后。


静态变量sapi_cgi_read_post(char *缓冲单元count_bytes tsrmls_dc)
{
单位read_bytes = 0,tmp_read_bytes;
如果php_fastcgi #
char =缓冲区;
# endif
count_bytes = min(count_bytes(单元),SG(request_info)。content_length - SG(read_post_bytes));
而(read_bytes < count_bytes){
如果php_fastcgi #
如果(fcgi_is_fastcgi()){
fcgi_request *要求=(fcgi_request *)SG(server_context);
tmp_read_bytes = fcgi_read(请求,POS机,count_bytes - read_bytes);
POS = tmp_read_bytes;
{人}
tmp_read_bytes =阅读(0,缓冲+ read_bytes,count_bytes - read_bytes);
}
其他#
tmp_read_bytes =阅读(0,缓冲+ read_bytes,count_bytes - read_bytes);
# endif
如果(tmp_read_bytes <= 0){
打破;
}
read_bytes = tmp_read_bytes;
}
返回read_bytes;
}


14。sapi_cgi_read_cookies,这是上面的功能一样,只是为了得到cookie的值:


静态字符串sapi_cgi_read_cookies(tsrmls_d)
{
返回sapi_cgibin_getenv((char *)http_cookie
}




15。sapi_cgi_register_variables, this function gives an interface to add variables to $_SERVER variables. CGI,它注册一个php_self,所以我们可以进入美元_server { 'php_self}在脚本获取。

这一次request_uri:


静态sapi_cgi_register_variables(zval * track_vars_array tsrmls_dc)
{
在CGI中,我们认为环境是服务器的一部分。
*变量
* /
php_import_environment_variables(track_vars_array tsrmls_cc);
* CGI版* 建立特殊情况php_self变量/
php_register_variable(php_self
}


16。sapi_cgi_log_message,用来输出错误信息,CGI,简单地输出到stderr:


静态sapi_cgi_log_message(char *消息)
{
如果php_fastcgi #
如果(fcgi_is_fastcgi fcgi_logging()){
fcgi_request *要求;
tsrmls_fetch();
请求=(fcgi_request *)SG(server_context);
如果(请求){
int len = strlen(消息);
char * buf = malloc(len + 2);
Memcpy(buf,消息,Len);
Memcpy(BUF + Len,
fcgi_write(请求,fcgi_stderr,buf,len + 1);
免费(BUF);
{人}
Fprintf(stderr,%s
}
忽略返回代码
别的}
如果# php_fastcgi / * * /
Fprintf(stderr,%s
}


经过分析,我们已经知道,一个SAPI实现。在分析了CGI,我们可以想象mod_php实施机制,嵌入等SAPI。:)

怎么了,这篇文章不是很详细,希望大家喜欢。