In-depth understanding of PHP kernel (III) Overview-SAPI overview, deep understanding-sapi_PHP tutorial

Source: Internet
Author: User
Tags sapi website server
Deep understanding of PHP kernel (3) Overview-SAPI overview, deep understanding-sapi. In-depth understanding of PHP kernel (3) Overview-SAPI overview, deep understanding-sapi this article link: www. orlion. ml2341. in various stages of the PHP lifecycle, some service-related operations are implemented through a thorough understanding of the PHP kernel (III) Overview-SAPI overview, in-depth understanding-sapi


1. in various stages of the PHP lifecycle, some service-related operations are implemented through the SAPI interface. These built-in implementations are physically located in the SAPI Directory of the PHP source code. This directory stores PHP code on the abstraction layer of each server, such as the implementation of the command line program, the mod_php module of Apache, and the fastcgi implementation.

The server abstraction layer follows the same conventions. here we call it the SAPI interface. Each SAPI implementation is a _ sapi_module_struct struct variable. (SAPI ). In the source code of PHP, when server-related information needs to be called, all methods are called through the corresponding method in the SAPI interface, and these methods are implemented at each server abstraction layer. Because of the versatility of many operations, a large part of interface methods use the default method. Simple for SPAI

Take cgi mode and apache2 server as an example. their startup methods are as follows:

Cgi_sapi_module.startup (& cgi_sapi_module) // cgi/cgi_main.c file restart (& apache_sapi_module); // apache server apache2handler/sapi_apache2.c file

Here the cgi_sapi_module is the static variable of the sapi_module_struct struct. Its startup method points to the php_cgi_startup function pointer. In this struct, apart from the startup function pointer, there are many other methods or fields which are defined in the server interface implementation.

The entire SAPI is similar to an application of the template method mode in object-oriented mode. Some functions contained in SAPI. c and SAPI. h files are abstract templates in the template method mode. the definitions and implementations of sapi_module by each server are specific templates.

2. Apache Module

(1) When PHP needs to run on an Apache server, it can be integrated in the form of the mod_php5 module. at this time, the mod_php5 module is used to receive PHP file requests transmitted by Aapche, and process these requests, and then return the processed results to Apache. If the PHP module is configured in the configuration file before Apache is started, the PHP module registers the ap_hook_post_config hook of apache2 and starts this module at Apache startup to receive requests from the PHP file.

In addition to this loading method at startup, Apache modules can be dynamically loaded during running, which means that the server can be extended without re-compiling the source code, you do not even need to restart the server. All we need to do is send a signal HUP or AP_SIG_GEACEFUL to the server to notify the server to reload the module. However, before dynamic loading, we need to compile the module into a dynamic link library. In this case, dynamic loading is to load the dynamic link library. In Apache, the processing of the dynamic link library is done through the module mod_so. Therefore, the mod_so module cannot be dynamically loaded. it can only be compiled locally into the core of Apache. This means that it is started with Apache.

How does Apache load modules? Take mod_php5 as an example. add a line in httpd. conf:

LoadModule php5_module modules/

After the commands shown in the configuration file are added, Apache finds and loads the module based on the module name when loading the module. Every module of Apache exists in the form of a module structure. the name attribute of the module structure is embodied in _ FILE _ at the end of the macro STANDARD20_MODULE_STUFF. After finding the relevant dynamic link library file through the path specified in the previous command, Apache obtains the content in the dynamic link library through internal functions, load the module content to the specified variable in the memory.

Before activating a module, Apache checks whether all loaded modules are real Apache modules. Finally, Apache will call related functions (ap_add_loaded_module) to activate the module. the activation here is to put the module into the corresponding linked list (ap_top_modules linked list)

Apache loads the PHP module. how can this module be implemented? The mod_php5 module of Apache2 contains two directories: sapi/apache2handler and sapi/apache2filter. in the apache2_handle/mod_php5.c file, the code defined by the module is as follows:

AP_MODULE_DECLARE_DATA module php5_module = {STANDARD20_MODULE_STUFF,/* macro, including version, minor version, module index, module name, next module pointer, and other information, the module name is represented by _ FILE _ */create_php_config,/* create per-directory config structure */merge_php_config,/* merge per-directory config structures */NULL, /* create per-server config structure */NULL,/* merge per-server config structures */php_dir_cmds,/* all commands defined by the module */php_ap2_register_hook/* register the hook, this function registers a hook for a specified step during a processing using a function starting with ap_hoo */};

It corresponds to the module structure of Apache. the module structure is defined as follows:

typedef struct module_struct module;struct module_struct {    int version;    int minor_version;    int module_index;    const char *name;    void *dynamic_load_handle;    struct module_struct *next;    unsigned long magic;    void (*rewrite_args) (process_rec *process);    void *(*create_dir_config) (apr_pool_t *p, char *dir);    void *(*merge_dir_config) (apr_pool_t *p, void *base_conf, void *new_conf);    void *(*create_server_config) (apr_pool_t *p, server_rec *s);    void *(*merge_server_config) (apr_pool_t *p, void *base_conf, void *new_conf);    const command_rec *cmds;    void (*register_hooks) (apr_pool_t *p);}

The structure of the above module is a little different from the structure we see in mod_php5.c. this is because of STANDARD20_MODULE_STUFF. this macro contains the definition of the previous eight fields. The STANDARD20_MODULE_STUFF macro is defined as follows:

/** Use this in all standard modules */#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \                MODULE_MAGIC_NUMBER_MINOR, \                -1, \                __FILE__, \                NULL, \                NULL, \                MODULE_MAGIC_COOKIE, \                                NULL      /* rewrite args spot */

In the structure defined by php5_module, php_dir_cmds is a set of all commands defined by the module. The definition is as follows:

const command_rec php_dir_cmds[] ={    AP_INIT_TAKE2("php_value", php_apache_value_handler, NULL,        OR_OPTIONS, "PHP Value Modifier"),    AP_INIT_TAKE2("php_flag", php_apache_flag_handler, NULL,        OR_OPTIONS, "PHP Flag Modifier"),    AP_INIT_TAKE2("php_admin_value", php_apache_admin_value_handler,        NULL, ACCESS_CONF|RSRC_CONF, "PHP Value Modifier (Admin)"),    AP_INIT_TAKE2("php_admin_flag", php_apache_admin_flag_handler,        NULL, ACCESS_CONF|RSRC_CONF, "PHP Flag Modifier (Admin)"),    AP_INIT_TAKE1("PHPINIDir", php_apache_phpini_set, NULL,        RSRC_CONF, "Directory containing the php.ini file"),    {NULL}};

This is the instruction table defined by the mod_php5 module. It is actually an array of commond_rec structures. When Apache encounters commands, it will traverse the command tables in each module one by one to find whether the module can process the commands. if it finds the commands, it will call the response processing function, if all the modules in the instruction table cannot process this command, an error is reported. as shown above, the mod_php5 module only provides five commands, such as php_value.

The php_ap2_register_hook function is defined as follows:

void php_ap2_register_hook(apr_pool_t *p){    ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);    ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);    ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE);    ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE);}

The above code declares the pre_config, post_config, handler and child_init4 hooks and corresponding processing functions. Pre_config, post_config, and child_init are startup hooks, which are called at Server startup. A handler hook is a request hook called when the server processes the request. Start php in the post_config hook. It is implemented through the compile function. the php_apache_server_startup function calls sapi_startup to start sapi, calls php_apache2_startup to register the sapi module struct, and finally calls php_module_startup to initialize php. the Zend Engine is initialized, and fill in the treat_data member in zend_module_struct (via php_startup_sapi_content_types.

At this point, we know the whole process of loading the mod_php5 module from Apache, but what is the relationship between this process and our Ele. me SAPI? Mod_php5 also defines the sapi_module_struct structure of Apache:

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 */NULL,                       /* Child Terminate */ STANDARD_SAPI_MODULE_PROPERTIES};

These methods belong to the Apache server. taking cookie reading as an example, when we call and read cookies in PHP in the Apache server environment, the final data obtained is obtained when SAPI is activated, it calls read_cookie.

SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);

When loading each server, we specify sapi_module, while Apache's sapi_module is apache2_sapi_module. The method corresponding to read_cookie is the php_apache_sapi_read_cookie function. This is also the reason for defining the SAPI structure: unified interface, interface-oriented programming, with better scalability and adaptability.

(2) Apache running process

Apache is running in the startup and running phases. Apache is started as root in the startup phase. the whole process is in a single-process, single-thread environment, this phase includes parsing configuration files, loading modules, and initializing system resources (such as log files, shared memory segments, and database connections.

In the running stage, Apache processes user service requests. Apache runs as a common user at this stage. Apache requests for HTTP can be divided into three major stages: connection, processing, and disconnection.

2. FastCGI

(1) cgi is a Common Gateway Interface (Intedface) that allows a client to request data from a Web browser to programs executed on the Web server. CGI describes the standard for data transmission between the client and the program. One purpose of CGI is to be independent from any language, so CGI can be written in any language as long as it has standard input, output, and environment variables. Such as PHP, perl, and tcl.

FastCGI is a protocol for communication between Web servers and processing programs. it is an improvement solution of CGI. FastCGI is like a resident CGI and can be executed continuously, when a request arrives, it does not take time to fork a process for processing (this is the fork-and-execute mode that is criticized by CGI ). Because it is only a communication protocol, it also supports distributed computing, that is, the FastCGI program can be executed on a host other than the website server and receive requests from other website servers.

The entire FastCGI process is as follows:

Step 1: load the FastCGI Process Manager (iis isapi or Apache Module) when the Web Server starts)

Step 2: FastCGI Process Manager initializes itself, starts multiple CGI interpreter processes (multiple php-cgi are visible), and waits for a connection from the web server

Step 3: When a client request arrives at the Web Server, the FastCGI process manager selects and connects to a CGI interpreter. The Web Server sends CGI environment variables and standard input to the FastCGI sub-process php-cgi

Step 4: After the FastCGI sub-process completes processing, the standard output and the new error words are returned from the same connection to the Web Server. when the FastCGI sub-process closes the connection, the request ends. The FastCGI sub-process then waits for and processes the next connection from the FastCGI Process Manager (running on the Web Server. In CGI mode, php-cgi exits here.

(2) CGI implementation in php

Php cgi implements the Fastcgi protocol. A TCP or UDP server receives requests from the Web server. when the server is started, it creates a socket listener for the TCP/UDP protocol server, and accepts and processes the requests. Then the lifecycle of PHP is entered: module initialization, sapi initialization, PHP request processing, module shutdown, and sapi shutdown constitute the entire CGI lifecycle.

Taking TCP as an example, the following steps are generally performed on the TCP server:

1. call the socket function to create a streaming socket for TCP;

2. call the bind function to bind the local address of the server to the socket created earlier;

3. call the listen function to use the newly created socket as the listener. wait for the connection initiated by the client. when the client has multiple connections connected to the socket, it may need to be queued for processing;

4. the server process calls the accept function and becomes congested until a client process calls the connect function to establish a connection;

5. after creating a connection with the client, the server calls the read_stream function to read the client's request;

6. after the data is processed, the server calls the write function to send a response to the client.

Time sequence of client-server transaction on TCP:

The CGI implementation of php starts from the main function of the cgi_main.c file. The main function calls functions such as initialization and listening defined in the fastcgi. c file. Compared with the TCP process, we can see the implementation of the TCP protocol in php. Although php itself implements these procedures, some processes in the main function are encapsulated into a function implementation. For the TCP operation process, PHP first creates a socket, binds the socket, and creates a listener:

if (bindpath) {    fcgi_fd = fcgi_listen(bindpath, 128);   //  socket˥˦2sfcgi_initɩ    Ȑ    ...}

In the fastcgi. c file, the fcig_listen function is mainly used to create, bind a socket, and start listening. it completes the first three stages of the TCP process listed above,

 if ((listen_socket = socket(, SOCK_STREAM, 0)) < 0 ||        ...        bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||        listen(listen_socket, backlog) < 0) {        ...    }

After the initialization is complete on the server side, the process calls the accept function to enter the blocking state. in the main function, we can see the following code:

  while (parent) {        do {            pid = fork();   //  oÒȨėJ            switch (pid) {            case 0: //  ȨėJ                parent = 0;                 /* don't catch our signals */                sigaction(SIGTERM, &old_term, 0);   //  ľâ¯ķ                sigaction(SIGQUIT, &old_quit, 0);   //  ľĿɰ£ƺ                sigaction(SIGINT,  &old_int,  0);   //  ľĿKȠƺ                break;                ...                default:                /* Fine */                running++;                break;        } while (parent && (running < children));     ...        while (!fastcgi || fcgi_accept_request(&request) >= 0) {        SG(server_context) = (void *) &request;        init_request_info(TSRMLS_C);        CG(interactive) = 0;                    ...            }

The above code is a sub-process generated and waiting for user requests. In the fcgi_accept_request function, the program calls the accept function to block the newly created thread. When a user's request arrives, the fcgi_accept_request function determines whether to process the user's request. the fcgi_accept_request function filters some connection requests and ignores the requests of restricted customers. if the program accepts the user's request, it will analyze the request information and write the relevant variables into the corresponding variables. The safe_read method is called when the request content is read. As shown in the following figure: main ()-> fcgi_accept_request ()-> fcgi_read_request ()-> safe_read ()

Static inline ssize_t safe_read (fcgi_request * req, const void * buf, size_t count) {size_t n = 0; do {... // omitting the win32 processing ret = read (req-> fd, (char *) buf) + n, count-n ); // non-win version read operation D... // omitted} while (n! = Count );}

As shown above, the server reads the user's request data.

After the request initialization is complete and the read request is complete, it is time to process the php file of the request. If the request is PHP_MODE_STANDARD, php_execute_script is called to execute the php file. In this function, it first initializes some content related to this file, and then calls the zend_execute_scripts function to perform lexical analysis and syntax analysis on the php file, generate intermediate code, and execute the zend_execute function, to execute the intermediate code.

After processing the user's request, the server returns the information to the client. in this case, fcgi_finish_request (& request, 1) is called in the main function. the fcgi_finish_request function is defined in fasftcgi. c file.

After the server sends a response to the request, the server executes the close operation, which is limited to the shutdown of CGI itself. The program executes the fcgi_close function.

Summary (3) Overview-SAPI overview, deep understanding-sapi this article link: 1, in the PHP lifecycle of each stage, some services related operations are through...

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.