cgi程序的入口函数在/sapi/cgi/cgi_main.c中,同样透过源码来看看CGI程序是如何启动的.
首先CGI跟CLI程序的运行做一个大概的对比一下,个人总结,有错误请指正:
1、CLI启动是在终端执行,其参数通过终端指定
2、CGI启动是通过web服务器执行,当WEB服务器接受到HTTP请求以后,调用(应该类似exec)入口方法,参数的传递通过环境变量指定,具体哪些参数可以查看CGI协议的规定。
那么PHP CGI模式的运行是如何运行的呢? 因为FASTCGI和CGI是在同一文件里面做了判断,这里直接去掉FASTCGI的代码,省略部分代码作出说明:
1、定义了一些常量
int
free_query_string = 0;
int
exit_status = SUCCESS;
int
cgi = 0, c, i, len;
zend_file_handle file_handle;
char
*s;
/* temporary locals */
int
behavior = PHP_MODE_STANDARD;
int
no_headers = 0;
int
orig_optind = php_optind;
char
*orig_optarg = php_optarg;
char
*script_file = NULL;
int
ini_entries_len = 0;
/* end of temporary locals */
int max_requests = 500;
int requests = 0;
int fastcgi;
char *bindpath = NULL;
int fcgi_fd = 0;
fcgi_request *request = NULL;
int repeats = 1;
int benchmark = 0;
signal(SIGPIPE, SIG_IGN); /* 信号量设置*/
sapi_startup(&cgi_sapi_module); //设置一些全局常量,比如SG,设置php.ini的设置选项
//.........读取参数,设置一些全局变量
//请求初始化操作。请求初始化操作,除了图中显示的调用每个模块的请求初始化函数外,
//
激活Zend引擎,激活SAPI,环境初始化,包括了$_GET,$_POST等
if (php_request_startup(TSRMLS_C) == FAILURE) {
if (fastcgi) {
fcgi_finish_request(request, 1);
}
SG(server_context) = NULL;
php_module_shutdown(TSRMLS_C);
return FAILURE;
}
switch
(behavior) {
case
PHP_MODE_STANDARD:
php_execute_script(&file_handle TSRMLS_CC);
break
;
case
PHP_MODE_LINT:
PG(during_request_startup) = 0;
exit_status = php_lint_script(&file_handle TSRMLS_CC);
if
(exit_status == SUCCESS) {
zend_printf(
"No syntax errors detected in %s\n"
, file_handle.filename);
}
else
{
zend_printf(
"Errors parsing %s\n"
, file_handle.filename);
}
break
;
case
PHP_MODE_STRIP:
if
(open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
zend_strip(TSRMLS_C);
zend_file_handle_dtor(&file_handle TSRMLS_CC);
php_output_teardown();
}
return
SUCCESS;
break
;
case
PHP_MODE_HIGHLIGHT:
{
zend_syntax_highlighter_ini syntax_highlighter_ini;
if
(open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
php_get_highlight_struct(&syntax_highlighter_ini);
zend_highlight(&syntax_highlighter_ini TSRMLS_CC);
if
(fastcgi) {
goto
fastcgi_request_done;
}
zend_file_handle_dtor(&file_handle TSRMLS_CC);
php_output_teardown();
}
return
SUCCESS;
}
break
;
behavior是由之前的代码决定的,我们看到标准的就可以了
php_execute_script函数包含了运行PHP脚本的全部过程。
具体来看下php_request_start函数的执行,就跟CLI模式下的do_cli一样。
int
php_request_startup(TSRMLS_D)
{
int
retval = SUCCESS;
#if PHP_SIGCHILD
signal
(SIGCHLD, sigchld_handler);
#endif
if
(php_start_sapi() == FAILURE) {
return
FAILURE;
}
php_output_activate(TSRMLS_C);
sapi_activate(TSRMLS_C);
php_hash_environment(TSRMLS_C);
zend_try {
PG(during_request_startup) = 1;
if
(PG(expose_php)) {
sapi_add_header(SAPI_PHP_VERSION_HEADER,
sizeof
(SAPI_PHP_VERSION_HEADER)-1, 1);
}
} zend_catch {
retval = FAILURE;
} zend_end_try();
return
retval;
}
来看几个简化以后的主要函数:
zend_activate(TSRMLS_C); //激活zend引擎
zend_activate_modules(TSRMLS_C); //激活所有模块,使用for循环回调每个模块的 INIT_FUNC
php_output_activate(TSRMLS_C); //激活输出的堆栈结构, 就是声明了一个结构体,分配了空间
sapi_activate(TSRMLS_C); //激活当前这个sapi,主要是初始化一些常量,比如$_COOKIE
php_hash_environment(TSRMLS_C); //应该是hash存储的一些变量,没具体看
其实除了获取一些命令参数是从环境变量获取之外, 它的运行过程和CLI模式差不多,