# SAPI講解
**什么是SAPI:Server Application Programming Interface,它是PHP提供的一個接口機制,使得PHP可以和其他應用進行交互數據/協作;**
## PHP架構圖

## 舉例

## sapi模塊結構體
```c
struct _sapi_module_struct {
char *name;
char *pretty_name;
int (*startup)(struct _sapi_module_struct *sapi_module);//PHP被調用的時候,這個函數會被調用執行
int (*shutdown)(struct _sapi_module_struct *sapi_module);//PHP調用結束的時候,這個函數會被調用執行
int (*activate)(void);//每個request開始時會執行,進行一些初始化,資源分配的事務
int (*deactivate)(void);//每個request結束時會執行
size_t (*ub_write)(const char *str, size_t str_length);//這個hanlder告訴了Zend,如何輸出數據,對于mod_php來說,這個函數提供了一個向response數據寫的接口,而CLI只是簡單的寫到stdout
void (*flush)(void *server_context);//這個是提供給zend的刷新緩存的函數句柄,對于CLI來說,只是簡單的調用系統提供的fflush;
zend_stat_t *(*get_stat)(void);//這部分用來讓Zend可以驗證一個要執行腳本文件的state,從而判斷文件是否據有執行權限等等.
char *(*getenv)(char *name, size_t name_len);//為Zend提供了一個根據name來查找環境變量的接口,對于mod_php5來說,當我們在腳本中調用getenv的時候,就會間接的調用這個句柄.CLI和CGI很類似,直接調用父級是Shell, 所以,只是簡單的調用了系統提供的genenv:
void (*sapi_error)(int type, const char *error_msg, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);//錯誤處理函數
int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers);//這個函數會在我們調用PHP的header()函數的時候被調用.
int (*send_headers)(sapi_headers_struct *sapi_headers);//這個函數會在要真正發送header的時候被調用,一般來說,就是當有任何的輸出要發送之前:
void (*send_header)(sapi_header_struct *sapi_header, void *server_context);//這個用來單獨發送每一個header
size_t (*read_post)(char *buffer, size_t count_bytes);//這個句柄指明了如何獲取POST的數據,CLI是從stdin中讀取POST DATA的,
char *(*read_cookies)(void);//這個句柄指明了如何獲取cookies的數據
void (*register_server_variables)(zval *track_vars_array);//這個函數用以給$_SERVER變量中添加變量,CLI在此函數中注冊了PHP_SELF,SCRIPT_FILENAME等server變量:
void (*log_message)(char *message, int syslog_type_int);//用來輸出錯誤信息,對于CLI來說,只是簡單的輸出到stderr
double (*get_request_time)(void);//獲取請求時間,只有apach2自定義了,默認為獲取當前時間
void (*terminate_process)(void);//沒有任何SAPI用到,無用代碼
//STANDARD_SAPI_MODULE_PROPERTIES
char *php_ini_path_override;
void (*default_post_reader)(void);
void (*treat_data)(int arg, char *str, zval *destArray);
char *executable_location;
int php_ini_ignore;
int php_ini_ignore_cwd;
int (*get_fd)(int *fd);
int (*force_http_10)(void);
int (*get_target_uid)(uid_t *);
int (*get_target_gid)(gid_t *);
unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len);
void (*ini_defaults)(HashTable *configuration_hash);
int phpinfo_as_text;
char *ini_entries;
const zend_function_entry *additional_functions;
unsigned int (*input_filter_init)(void);
};```
---
## cli_sapi_module 的定義
```c
static sapi_module_struct cli_sapi_module = {
"cli", /* name */
"Command Line Interface", /* pretty name */
php_cli_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */
NULL, /* activate */
sapi_cli_deactivate, /* deactivate */
sapi_cli_ub_write, /* unbuffered write */
sapi_cli_flush, /* flush */
NULL, /* get uid */
NULL, /* getenv */
php_error, /* error handler */
sapi_cli_header_handler, /* header handler */
sapi_cli_send_headers, /* send headers handler */
sapi_cli_send_header, /* send header handler */
NULL, /* read POST data */
sapi_cli_read_cookies, /* read Cookies */
sapi_cli_register_variables, /* register server variables */
sapi_cli_log_message, /* Log message */
NULL, /* Get request time */
NULL, /* Child terminate */
STANDARD_SAPI_MODULE_PROPERTIES
};
```
## 在代碼中下斷點定位一下調用過程